@sasjs/adapter 3.10.10 → 3.10.13
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 +2 -1
- package/SASjs.d.ts +2 -1
- package/SASjsApiClient.d.ts +2 -1
- package/index.js +2 -2
- package/job-execution/JobExecutor.d.ts +1 -0
- package/job-execution/Sas9JobExecutor.d.ts +1 -1
- package/job-execution/SasjsJobExecutor.d.ts +9 -0
- package/job-execution/WebJobExecutor.d.ts +0 -2
- package/job-execution/index.d.ts +1 -0
- package/node/SASjs.d.ts +2 -1
- package/node/SASjsApiClient.d.ts +2 -1
- package/node/index.js +2 -2
- package/node/job-execution/JobExecutor.d.ts +1 -0
- package/node/job-execution/Sas9JobExecutor.d.ts +1 -1
- package/node/job-execution/SasjsJobExecutor.d.ts +9 -0
- package/node/job-execution/WebJobExecutor.d.ts +0 -2
- package/node/job-execution/index.d.ts +1 -0
- package/node/request/SasjsRequestClient.d.ts +7 -0
- package/node/types/errors/InvalidSASjsCsrfError.d.ts +3 -0
- package/node/utils/constants.d.ts +1 -0
- package/node/utils/index.d.ts +1 -0
- package/package.json +1 -1
- package/request/SasjsRequestClient.d.ts +7 -0
- package/src/SASjs.ts +15 -3
- package/src/SASjsApiClient.ts +9 -8
- package/src/auth/AuthManager.ts +10 -2
- package/src/job-execution/FileUploader.ts +3 -15
- package/src/job-execution/JobExecutor.ts +14 -1
- package/src/job-execution/Sas9JobExecutor.ts +1 -1
- package/src/job-execution/SasjsJobExecutor.ts +141 -0
- package/src/job-execution/WebJobExecutor.ts +4 -78
- package/src/job-execution/index.ts +1 -0
- package/src/request/RequestClient.ts +17 -25
- package/src/request/SasjsRequestClient.ts +31 -0
- package/src/types/errors/InvalidSASjsCsrfError.ts +9 -0
- package/src/utils/constants.ts +2 -0
- package/src/utils/index.ts +1 -0
- package/types/errors/InvalidSASjsCsrfError.d.ts +3 -0
- package/utils/constants.d.ts +1 -0
- package/utils/index.d.ts +1 -0
- package/node/types/errors/InvalidCsrfError.d.ts +0 -3
- package/src/types/errors/InvalidCsrfError.ts +0 -9
- package/types/errors/InvalidCsrfError.d.ts +0 -3
|
@@ -13,4 +13,5 @@ export declare abstract class BaseJobExecutor implements JobExecutor {
|
|
|
13
13
|
abstract execute(sasJob: string, data: any, config: any, loginRequiredCallback?: any, authConfig?: AuthConfig | undefined, extraResponseAttributes?: ExtraResponseAttributes[]): Promise<any>;
|
|
14
14
|
resendWaitingRequests: () => Promise<void>;
|
|
15
15
|
protected appendWaitingRequest(request: ExecuteFunction): void;
|
|
16
|
+
protected getRequestParams(config: any): any;
|
|
16
17
|
}
|
|
@@ -15,5 +15,5 @@ export declare class Sas9JobExecutor extends BaseJobExecutor {
|
|
|
15
15
|
private sas9RequestClient;
|
|
16
16
|
constructor(serverUrl: string, serverType: ServerType, jobsPath: string, requestClient: RequestClient, httpsAgentOptions?: https.AgentOptions);
|
|
17
17
|
execute(sasJob: string, data: any, config: any): Promise<unknown>;
|
|
18
|
-
|
|
18
|
+
protected getRequestParams(config: any): any;
|
|
19
19
|
}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { AuthConfig, ExtraResponseAttributes } from '@sasjs/utils/types';
|
|
2
|
+
import { RequestClient } from '../request/RequestClient';
|
|
3
|
+
import { BaseJobExecutor } from './JobExecutor';
|
|
4
|
+
export declare class SasjsJobExecutor extends BaseJobExecutor {
|
|
5
|
+
private jobsPath;
|
|
6
|
+
private requestClient;
|
|
7
|
+
constructor(serverUrl: string, jobsPath: string, requestClient: RequestClient);
|
|
8
|
+
execute(sasJob: string, data: any, config: any, loginRequiredCallback?: any, authConfig?: AuthConfig, extraResponseAttributes?: ExtraResponseAttributes[]): Promise<unknown>;
|
|
9
|
+
}
|
|
@@ -14,6 +14,4 @@ export declare class WebJobExecutor extends BaseJobExecutor {
|
|
|
14
14
|
constructor(serverUrl: string, serverType: ServerType, jobsPath: string, requestClient: RequestClient, sasViyaApiClient: SASViyaApiClient);
|
|
15
15
|
execute(sasJob: string, data: any, config: any, loginRequiredCallback?: any, authConfig?: AuthConfig, extraResponseAttributes?: ExtraResponseAttributes[]): Promise<unknown>;
|
|
16
16
|
private getJobUri;
|
|
17
|
-
private getRequestParams;
|
|
18
|
-
private parseSAS9ErrorResponse;
|
|
19
17
|
}
|
|
@@ -1,8 +1,15 @@
|
|
|
1
1
|
import { RequestClient } from './RequestClient';
|
|
2
|
+
import { AxiosResponse } from 'axios';
|
|
2
3
|
/**
|
|
3
4
|
* Specific request client for SASJS.
|
|
4
5
|
* Append tokens in headers.
|
|
5
6
|
*/
|
|
6
7
|
export declare class SasjsRequestClient extends RequestClient {
|
|
7
8
|
getHeaders: (accessToken: string | undefined, contentType: string) => any;
|
|
9
|
+
protected parseResponse<T>(response: AxiosResponse<any>): {
|
|
10
|
+
result: T;
|
|
11
|
+
log: any;
|
|
12
|
+
etag: string;
|
|
13
|
+
status: number;
|
|
14
|
+
};
|
|
8
15
|
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare const SASJS_LOGS_SEPARATOR = "SASJS_LOGS_SEPARATOR_163ee17b6ff24f028928972d80a26784";
|
package/node/utils/index.d.ts
CHANGED
|
@@ -2,6 +2,7 @@ export * from './appendExtraResponseAttributes';
|
|
|
2
2
|
export * from './asyncForEach';
|
|
3
3
|
export * from './compareTimestamps';
|
|
4
4
|
export * from './convertToCsv';
|
|
5
|
+
export * from './constants';
|
|
5
6
|
export * from './createAxiosInstance';
|
|
6
7
|
export * from './delay';
|
|
7
8
|
export * from './fetchLogByChunks';
|
package/package.json
CHANGED
|
@@ -1,8 +1,15 @@
|
|
|
1
1
|
import { RequestClient } from './RequestClient';
|
|
2
|
+
import { AxiosResponse } from 'axios';
|
|
2
3
|
/**
|
|
3
4
|
* Specific request client for SASJS.
|
|
4
5
|
* Append tokens in headers.
|
|
5
6
|
*/
|
|
6
7
|
export declare class SasjsRequestClient extends RequestClient {
|
|
7
8
|
getHeaders: (accessToken: string | undefined, contentType: string) => any;
|
|
9
|
+
protected parseResponse<T>(response: AxiosResponse<any>): {
|
|
10
|
+
result: T;
|
|
11
|
+
log: any;
|
|
12
|
+
etag: string;
|
|
13
|
+
status: number;
|
|
14
|
+
};
|
|
8
15
|
}
|
package/src/SASjs.ts
CHANGED
|
@@ -24,6 +24,7 @@ import { SasjsRequestClient } from './request/SasjsRequestClient'
|
|
|
24
24
|
import {
|
|
25
25
|
JobExecutor,
|
|
26
26
|
WebJobExecutor,
|
|
27
|
+
SasjsJobExecutor,
|
|
27
28
|
ComputeJobExecutor,
|
|
28
29
|
JesJobExecutor,
|
|
29
30
|
Sas9JobExecutor,
|
|
@@ -59,6 +60,7 @@ export default class SASjs {
|
|
|
59
60
|
private authManager: AuthManager | null = null
|
|
60
61
|
private requestClient: RequestClient | null = null
|
|
61
62
|
private webJobExecutor: JobExecutor | null = null
|
|
63
|
+
private sasjsJobExecutor: JobExecutor | null = null
|
|
62
64
|
private computeJobExecutor: JobExecutor | null = null
|
|
63
65
|
private jesJobExecutor: JobExecutor | null = null
|
|
64
66
|
private sas9JobExecutor: JobExecutor | null = null
|
|
@@ -102,10 +104,14 @@ export default class SASjs {
|
|
|
102
104
|
* @param code - a string of code from the file to run.
|
|
103
105
|
* @param authConfig - (optional) a valid client, secret, refresh and access tokens that are authorised to execute scripts.
|
|
104
106
|
*/
|
|
105
|
-
public async executeScriptSASjs(
|
|
107
|
+
public async executeScriptSASjs(
|
|
108
|
+
code: string,
|
|
109
|
+
runTime?: string,
|
|
110
|
+
authConfig?: AuthConfig
|
|
111
|
+
) {
|
|
106
112
|
this.isMethodSupported('executeScriptSASJS', [ServerType.Sasjs])
|
|
107
113
|
|
|
108
|
-
return await this.sasJSApiClient?.executeScript(code, authConfig)
|
|
114
|
+
return await this.sasJSApiClient?.executeScript(code, runTime, authConfig)
|
|
109
115
|
}
|
|
110
116
|
|
|
111
117
|
/**
|
|
@@ -691,7 +697,7 @@ export default class SASjs {
|
|
|
691
697
|
// status is true if the data passes validation checks above
|
|
692
698
|
if (validationResult.status) {
|
|
693
699
|
if (config.serverType === ServerType.Sasjs) {
|
|
694
|
-
return await this.
|
|
700
|
+
return await this.sasjsJobExecutor!.execute(
|
|
695
701
|
sasJob,
|
|
696
702
|
data,
|
|
697
703
|
config,
|
|
@@ -1049,6 +1055,12 @@ export default class SASjs {
|
|
|
1049
1055
|
this.sasViyaApiClient!
|
|
1050
1056
|
)
|
|
1051
1057
|
|
|
1058
|
+
this.sasjsJobExecutor = new SasjsJobExecutor(
|
|
1059
|
+
this.sasjsConfig.serverUrl,
|
|
1060
|
+
this.jobsPath,
|
|
1061
|
+
this.requestClient
|
|
1062
|
+
)
|
|
1063
|
+
|
|
1052
1064
|
this.sas9JobExecutor = new Sas9JobExecutor(
|
|
1053
1065
|
this.sasjsConfig.serverUrl,
|
|
1054
1066
|
this.sasjsConfig.serverType!,
|
package/src/SASjsApiClient.ts
CHANGED
|
@@ -3,7 +3,7 @@ import { ExecutionQuery } from './types'
|
|
|
3
3
|
import { RequestClient } from './request/RequestClient'
|
|
4
4
|
import { getAccessTokenForSasjs } from './auth/getAccessTokenForSasjs'
|
|
5
5
|
import { refreshTokensForSasjs } from './auth/refreshTokensForSasjs'
|
|
6
|
-
import { parseWeboutResponse } from './utils'
|
|
6
|
+
import { parseWeboutResponse, SASJS_LOGS_SEPARATOR } from './utils'
|
|
7
7
|
import { getTokens } from './auth/getTokens'
|
|
8
8
|
|
|
9
9
|
export class SASjsApiClient {
|
|
@@ -64,9 +64,14 @@ export class SASjsApiClient {
|
|
|
64
64
|
/**
|
|
65
65
|
* Executes code on a SASJS server.
|
|
66
66
|
* @param code - a string of code to execute.
|
|
67
|
+
* @param runTime - a string to representing runTime for code execution
|
|
67
68
|
* @param authConfig - an object for authentication.
|
|
68
69
|
*/
|
|
69
|
-
public async executeScript(
|
|
70
|
+
public async executeScript(
|
|
71
|
+
code: string,
|
|
72
|
+
runTime: string = 'sas',
|
|
73
|
+
authConfig?: AuthConfig
|
|
74
|
+
) {
|
|
70
75
|
let access_token = (authConfig || {}).access_token
|
|
71
76
|
if (authConfig) {
|
|
72
77
|
;({ access_token } = await getTokens(
|
|
@@ -79,13 +84,9 @@ export class SASjsApiClient {
|
|
|
79
84
|
let parsedSasjsServerLog = ''
|
|
80
85
|
|
|
81
86
|
await this.requestClient
|
|
82
|
-
.post('SASjsApi/code/execute', { code }, access_token)
|
|
87
|
+
.post('SASjsApi/code/execute', { code, runTime }, access_token)
|
|
83
88
|
.then((res: any) => {
|
|
84
|
-
if (res.
|
|
85
|
-
parsedSasjsServerLog = res.result.log
|
|
86
|
-
.map((logLine: any) => logLine.line)
|
|
87
|
-
.join('\n')
|
|
88
|
-
}
|
|
89
|
+
if (res.log) parsedSasjsServerLog = res.log
|
|
89
90
|
})
|
|
90
91
|
.catch((err) => {
|
|
91
92
|
parsedSasjsServerLog = err
|
package/src/auth/AuthManager.ts
CHANGED
|
@@ -223,9 +223,17 @@ export class AuthManager {
|
|
|
223
223
|
|
|
224
224
|
private async getNewLoginForm() {
|
|
225
225
|
if (this.serverType === ServerType.Sasjs) {
|
|
226
|
-
// server will be sending CSRF
|
|
226
|
+
// server will be sending CSRF token in response,
|
|
227
|
+
// need to save in cookie so that,
|
|
227
228
|
// http client will use it automatically
|
|
228
|
-
return this.requestClient.get('/', undefined)
|
|
229
|
+
return this.requestClient.get('/', undefined).then(({ result }) => {
|
|
230
|
+
const cookie =
|
|
231
|
+
/<script>document.cookie = '(XSRF-TOKEN=.*; Max-Age=86400; SameSite=Strict; Path=\/;)'<\/script>/.exec(
|
|
232
|
+
result as string
|
|
233
|
+
)?.[1]
|
|
234
|
+
|
|
235
|
+
if (cookie) document.cookie = cookie
|
|
236
|
+
})
|
|
229
237
|
}
|
|
230
238
|
|
|
231
239
|
const { result: formResponse } = await this.requestClient.get<string>(
|
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
import {
|
|
2
2
|
getValidJson,
|
|
3
3
|
parseSasViyaDebugResponse,
|
|
4
|
-
parseWeboutResponse
|
|
4
|
+
parseWeboutResponse,
|
|
5
|
+
SASJS_LOGS_SEPARATOR
|
|
5
6
|
} from '../utils'
|
|
6
7
|
import { UploadFile } from '../types/UploadFile'
|
|
7
8
|
import {
|
|
@@ -99,21 +100,8 @@ export class FileUploader extends BaseJobExecutor {
|
|
|
99
100
|
? parseWeboutResponse(res.result, uploadUrl)
|
|
100
101
|
: res.result
|
|
101
102
|
break
|
|
102
|
-
case ServerType.Sasjs:
|
|
103
|
-
if (typeof res.result._webout === 'object') {
|
|
104
|
-
jsonResponse = res.result._webout
|
|
105
|
-
} else {
|
|
106
|
-
const webout = parseWeboutResponse(
|
|
107
|
-
res.result._webout,
|
|
108
|
-
uploadUrl
|
|
109
|
-
)
|
|
110
|
-
jsonResponse = getValidJson(webout)
|
|
111
|
-
}
|
|
112
|
-
break
|
|
113
103
|
}
|
|
114
|
-
} else if (this.serverType
|
|
115
|
-
jsonResponse = getValidJson(res.result._webout)
|
|
116
|
-
} else {
|
|
104
|
+
} else if (this.serverType !== ServerType.Sasjs) {
|
|
117
105
|
jsonResponse =
|
|
118
106
|
typeof res.result === 'string'
|
|
119
107
|
? getValidJson(res.result)
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { AuthConfig, ServerType } from '@sasjs/utils/types'
|
|
2
2
|
import { ExtraResponseAttributes } from '@sasjs/utils/types'
|
|
3
|
-
import { asyncForEach } from '../utils'
|
|
3
|
+
import { asyncForEach, isRelativePath } from '../utils'
|
|
4
4
|
|
|
5
5
|
export type ExecuteFunction = () => Promise<any>
|
|
6
6
|
|
|
@@ -45,4 +45,17 @@ export abstract class BaseJobExecutor implements JobExecutor {
|
|
|
45
45
|
protected appendWaitingRequest(request: ExecuteFunction) {
|
|
46
46
|
this.waitingRequests.push(request)
|
|
47
47
|
}
|
|
48
|
+
|
|
49
|
+
protected getRequestParams(config: any): any {
|
|
50
|
+
const requestParams: any = {}
|
|
51
|
+
|
|
52
|
+
if (config.debug) {
|
|
53
|
+
requestParams['_omittextlog'] = 'false'
|
|
54
|
+
requestParams['_omitsessionresults'] = 'false'
|
|
55
|
+
|
|
56
|
+
requestParams['_debug'] = 131
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
return requestParams
|
|
60
|
+
}
|
|
48
61
|
}
|
|
@@ -102,7 +102,7 @@ export class Sas9JobExecutor extends BaseJobExecutor {
|
|
|
102
102
|
return requestPromise
|
|
103
103
|
}
|
|
104
104
|
|
|
105
|
-
|
|
105
|
+
protected getRequestParams(config: any): any {
|
|
106
106
|
const requestParams: any = {}
|
|
107
107
|
|
|
108
108
|
if (config.debug) {
|
|
@@ -0,0 +1,141 @@
|
|
|
1
|
+
import * as NodeFormData from 'form-data'
|
|
2
|
+
import {
|
|
3
|
+
AuthConfig,
|
|
4
|
+
ExtraResponseAttributes,
|
|
5
|
+
ServerType
|
|
6
|
+
} from '@sasjs/utils/types'
|
|
7
|
+
import {
|
|
8
|
+
ErrorResponse,
|
|
9
|
+
JobExecutionError,
|
|
10
|
+
LoginRequiredError
|
|
11
|
+
} from '../types/errors'
|
|
12
|
+
import { generateFileUploadForm } from '../file/generateFileUploadForm'
|
|
13
|
+
|
|
14
|
+
import { RequestClient } from '../request/RequestClient'
|
|
15
|
+
|
|
16
|
+
import { isRelativePath, appendExtraResponseAttributes } from '../utils'
|
|
17
|
+
import { BaseJobExecutor } from './JobExecutor'
|
|
18
|
+
|
|
19
|
+
export class SasjsJobExecutor extends BaseJobExecutor {
|
|
20
|
+
constructor(
|
|
21
|
+
serverUrl: string,
|
|
22
|
+
private jobsPath: string,
|
|
23
|
+
private requestClient: RequestClient
|
|
24
|
+
) {
|
|
25
|
+
super(serverUrl, ServerType.Sasjs)
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
async execute(
|
|
29
|
+
sasJob: string,
|
|
30
|
+
data: any,
|
|
31
|
+
config: any,
|
|
32
|
+
loginRequiredCallback?: any,
|
|
33
|
+
authConfig?: AuthConfig,
|
|
34
|
+
extraResponseAttributes: ExtraResponseAttributes[] = []
|
|
35
|
+
) {
|
|
36
|
+
const loginCallback = loginRequiredCallback
|
|
37
|
+
const program =
|
|
38
|
+
isRelativePath(sasJob) && config.appLoc
|
|
39
|
+
? config.appLoc.replace(/\/?$/, '/') + sasJob.replace(/^\//, '')
|
|
40
|
+
: sasJob
|
|
41
|
+
|
|
42
|
+
let apiUrl = `${config.serverUrl}${this.jobsPath}/?${'_program=' + program}`
|
|
43
|
+
|
|
44
|
+
let requestParams = {
|
|
45
|
+
...this.getRequestParams(config)
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
/**
|
|
49
|
+
* Use the available form data object (FormData in Browser, NodeFormData in
|
|
50
|
+
* Node)
|
|
51
|
+
*/
|
|
52
|
+
let formData =
|
|
53
|
+
typeof FormData === 'undefined' ? new NodeFormData() : new FormData()
|
|
54
|
+
|
|
55
|
+
if (data) {
|
|
56
|
+
// file upload approach
|
|
57
|
+
try {
|
|
58
|
+
formData = generateFileUploadForm(formData, data)
|
|
59
|
+
} catch (e: any) {
|
|
60
|
+
return Promise.reject(new ErrorResponse(e?.message, e))
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
for (const key in requestParams) {
|
|
65
|
+
if (requestParams.hasOwnProperty(key)) {
|
|
66
|
+
formData.append(key, requestParams[key])
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
/* The NodeFormData object does not set the request header - so, set it */
|
|
71
|
+
const contentType =
|
|
72
|
+
formData instanceof NodeFormData && typeof FormData === 'undefined'
|
|
73
|
+
? `multipart/form-data; boundary=${formData.getBoundary()}`
|
|
74
|
+
: undefined
|
|
75
|
+
|
|
76
|
+
const requestPromise = new Promise((resolve, reject) => {
|
|
77
|
+
this.requestClient!.post(
|
|
78
|
+
apiUrl,
|
|
79
|
+
formData,
|
|
80
|
+
authConfig?.access_token,
|
|
81
|
+
contentType
|
|
82
|
+
)
|
|
83
|
+
.then(async (res: any) => {
|
|
84
|
+
if (Object.entries(res.result).length < 1) {
|
|
85
|
+
throw new JobExecutionError(
|
|
86
|
+
0,
|
|
87
|
+
`No webout was returned by job ${program}. Please check the SAS log for more info.`,
|
|
88
|
+
res.log
|
|
89
|
+
)
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
this.requestClient!.appendRequest(res, sasJob, config.debug)
|
|
93
|
+
|
|
94
|
+
const responseObject = appendExtraResponseAttributes(
|
|
95
|
+
res,
|
|
96
|
+
extraResponseAttributes
|
|
97
|
+
)
|
|
98
|
+
resolve(responseObject)
|
|
99
|
+
})
|
|
100
|
+
.catch(async (e: Error) => {
|
|
101
|
+
if (e instanceof JobExecutionError) {
|
|
102
|
+
this.requestClient!.appendRequest(e, sasJob, config.debug)
|
|
103
|
+
reject(new ErrorResponse(e?.message, e))
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
if (e instanceof LoginRequiredError) {
|
|
107
|
+
if (!loginRequiredCallback) {
|
|
108
|
+
reject(
|
|
109
|
+
new ErrorResponse(
|
|
110
|
+
'Request is not authenticated. Make sure .env file exists with valid credentials.',
|
|
111
|
+
e
|
|
112
|
+
)
|
|
113
|
+
)
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
this.appendWaitingRequest(() => {
|
|
117
|
+
return this.execute(
|
|
118
|
+
sasJob,
|
|
119
|
+
data,
|
|
120
|
+
config,
|
|
121
|
+
loginRequiredCallback,
|
|
122
|
+
authConfig,
|
|
123
|
+
extraResponseAttributes
|
|
124
|
+
).then(
|
|
125
|
+
(res: any) => {
|
|
126
|
+
resolve(res)
|
|
127
|
+
},
|
|
128
|
+
(err: any) => {
|
|
129
|
+
reject(err)
|
|
130
|
+
}
|
|
131
|
+
)
|
|
132
|
+
})
|
|
133
|
+
|
|
134
|
+
if (loginCallback) await loginCallback()
|
|
135
|
+
} else reject(new ErrorResponse(e?.message, e))
|
|
136
|
+
})
|
|
137
|
+
})
|
|
138
|
+
|
|
139
|
+
return requestPromise
|
|
140
|
+
}
|
|
141
|
+
}
|
|
@@ -16,12 +16,10 @@ import { SASViyaApiClient } from '../SASViyaApiClient'
|
|
|
16
16
|
import {
|
|
17
17
|
isRelativePath,
|
|
18
18
|
parseSasViyaDebugResponse,
|
|
19
|
-
appendExtraResponseAttributes
|
|
20
|
-
getValidJson
|
|
19
|
+
appendExtraResponseAttributes
|
|
21
20
|
} from '../utils'
|
|
22
21
|
import { BaseJobExecutor } from './JobExecutor'
|
|
23
22
|
import { parseWeboutResponse } from '../utils/parseWeboutResponse'
|
|
24
|
-
import { Server } from 'https'
|
|
25
23
|
|
|
26
24
|
export interface WaitingRequstPromise {
|
|
27
25
|
promise: Promise<any> | null
|
|
@@ -121,7 +119,6 @@ export class WebJobExecutor extends BaseJobExecutor {
|
|
|
121
119
|
const stringifiedData = JSON.stringify(data)
|
|
122
120
|
if (
|
|
123
121
|
config.serverType === ServerType.Sas9 ||
|
|
124
|
-
config.serverType === ServerType.Sasjs ||
|
|
125
122
|
stringifiedData.length > 500000 ||
|
|
126
123
|
stringifiedData.includes(';')
|
|
127
124
|
) {
|
|
@@ -164,31 +161,7 @@ export class WebJobExecutor extends BaseJobExecutor {
|
|
|
164
161
|
contentType
|
|
165
162
|
)
|
|
166
163
|
.then(async (res: any) => {
|
|
167
|
-
|
|
168
|
-
this.serverType === ServerType.Sasjs
|
|
169
|
-
? res.result.log.map((logLine: any) => logLine.line).join('\n')
|
|
170
|
-
: res.result.log
|
|
171
|
-
|
|
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
|
-
)
|
|
189
|
-
}
|
|
190
|
-
|
|
191
|
-
this.requestClient!.appendRequest(resObj, sasJob, config.debug)
|
|
164
|
+
this.requestClient!.appendRequest(res, sasJob, config.debug)
|
|
192
165
|
|
|
193
166
|
let jsonResponse = res.result
|
|
194
167
|
|
|
@@ -207,21 +180,11 @@ export class WebJobExecutor extends BaseJobExecutor {
|
|
|
207
180
|
? parseWeboutResponse(res.result, apiUrl)
|
|
208
181
|
: res.result
|
|
209
182
|
break
|
|
210
|
-
case ServerType.Sasjs:
|
|
211
|
-
if (typeof res.result._webout === 'object') {
|
|
212
|
-
jsonResponse = res.result._webout
|
|
213
|
-
} else {
|
|
214
|
-
const webout = parseWeboutResponse(res.result._webout, apiUrl)
|
|
215
|
-
jsonResponse = getValidJson(webout)
|
|
216
|
-
}
|
|
217
|
-
break
|
|
218
183
|
}
|
|
219
|
-
} else if (this.serverType === ServerType.Sasjs) {
|
|
220
|
-
jsonResponse = getValidJson(res.result._webout)
|
|
221
184
|
}
|
|
222
185
|
|
|
223
186
|
const responseObject = appendExtraResponseAttributes(
|
|
224
|
-
{ result: jsonResponse, log:
|
|
187
|
+
{ result: jsonResponse, log: res.log },
|
|
225
188
|
extraResponseAttributes
|
|
226
189
|
)
|
|
227
190
|
resolve(responseObject)
|
|
@@ -261,9 +224,7 @@ export class WebJobExecutor extends BaseJobExecutor {
|
|
|
261
224
|
})
|
|
262
225
|
|
|
263
226
|
if (loginCallback) await loginCallback()
|
|
264
|
-
} else
|
|
265
|
-
reject(new ErrorResponse(e?.message, e))
|
|
266
|
-
}
|
|
227
|
+
} else reject(new ErrorResponse(e?.message, e))
|
|
267
228
|
})
|
|
268
229
|
})
|
|
269
230
|
|
|
@@ -301,39 +262,4 @@ export class WebJobExecutor extends BaseJobExecutor {
|
|
|
301
262
|
}
|
|
302
263
|
return uri
|
|
303
264
|
}
|
|
304
|
-
|
|
305
|
-
private getRequestParams(config: any): any {
|
|
306
|
-
const requestParams: any = {}
|
|
307
|
-
|
|
308
|
-
if (config.debug) {
|
|
309
|
-
requestParams['_omittextlog'] = 'false'
|
|
310
|
-
requestParams['_omitsessionresults'] = 'false'
|
|
311
|
-
|
|
312
|
-
requestParams['_debug'] = 131
|
|
313
|
-
}
|
|
314
|
-
|
|
315
|
-
return requestParams
|
|
316
|
-
}
|
|
317
|
-
|
|
318
|
-
private parseSAS9ErrorResponse(response: string) {
|
|
319
|
-
const logLines = response.split('\n')
|
|
320
|
-
const parsedLines: string[] = []
|
|
321
|
-
let firstErrorLineIndex: number = -1
|
|
322
|
-
|
|
323
|
-
logLines.map((line: string, index: number) => {
|
|
324
|
-
if (
|
|
325
|
-
line.toLowerCase().includes('error') &&
|
|
326
|
-
!line.toLowerCase().includes('this request completed with errors.') &&
|
|
327
|
-
firstErrorLineIndex === -1
|
|
328
|
-
) {
|
|
329
|
-
firstErrorLineIndex = index
|
|
330
|
-
}
|
|
331
|
-
})
|
|
332
|
-
|
|
333
|
-
for (let i = firstErrorLineIndex - 10; i <= firstErrorLineIndex + 10; i++) {
|
|
334
|
-
parsedLines.push(logLines[i])
|
|
335
|
-
}
|
|
336
|
-
|
|
337
|
-
return parsedLines.join(', ')
|
|
338
|
-
}
|
|
339
265
|
}
|
|
@@ -19,7 +19,7 @@ import {
|
|
|
19
19
|
parseSourceCode,
|
|
20
20
|
createAxiosInstance
|
|
21
21
|
} from '../utils'
|
|
22
|
-
import {
|
|
22
|
+
import { InvalidSASjsCsrfError } from '../types/errors/InvalidSASjsCsrfError'
|
|
23
23
|
|
|
24
24
|
export interface HttpClient {
|
|
25
25
|
get<T>(
|
|
@@ -133,29 +133,13 @@ export class RequestClient implements HttpClient {
|
|
|
133
133
|
} else {
|
|
134
134
|
sasWork = response.log
|
|
135
135
|
}
|
|
136
|
-
} else if (response?.result
|
|
137
|
-
//
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
if (typeof log !== 'string') {
|
|
143
|
-
log = response.result.log
|
|
144
|
-
.map((logLine: any) => logLine.line)
|
|
145
|
-
.join('\n')
|
|
136
|
+
} else if (response?.result) {
|
|
137
|
+
// We parse only if it's a string, otherwise it would throw error
|
|
138
|
+
if (typeof response.result === 'string') {
|
|
139
|
+
sourceCode = parseSourceCode(response.result)
|
|
140
|
+
generatedCode = parseGeneratedCode(response.result)
|
|
146
141
|
}
|
|
147
142
|
|
|
148
|
-
sourceCode = parseSourceCode(log)
|
|
149
|
-
generatedCode = parseGeneratedCode(log)
|
|
150
|
-
|
|
151
|
-
if (response?.result?._webout) {
|
|
152
|
-
sasWork = response.result._webout.WORK
|
|
153
|
-
} else {
|
|
154
|
-
sasWork = log
|
|
155
|
-
}
|
|
156
|
-
} else if (response?.result) {
|
|
157
|
-
sourceCode = parseSourceCode(response.result)
|
|
158
|
-
generatedCode = parseGeneratedCode(response.result)
|
|
159
143
|
sasWork = response.result.WORK
|
|
160
144
|
}
|
|
161
145
|
}
|
|
@@ -499,12 +483,20 @@ export class RequestClient implements HttpClient {
|
|
|
499
483
|
throw e
|
|
500
484
|
}
|
|
501
485
|
|
|
502
|
-
if (e instanceof
|
|
503
|
-
// Fetching root
|
|
486
|
+
if (e instanceof InvalidSASjsCsrfError) {
|
|
487
|
+
// Fetching root and creating CSRF cookie
|
|
504
488
|
await this.httpClient
|
|
505
489
|
.get('/', {
|
|
506
490
|
withCredentials: true
|
|
507
491
|
})
|
|
492
|
+
.then((response) => {
|
|
493
|
+
const cookie =
|
|
494
|
+
/<script>document.cookie = '(XSRF-TOKEN=.*; Max-Age=86400; SameSite=Strict; Path=\/;)'<\/script>/.exec(
|
|
495
|
+
response.data
|
|
496
|
+
)?.[1]
|
|
497
|
+
|
|
498
|
+
if (cookie) document.cookie = cookie
|
|
499
|
+
})
|
|
508
500
|
.catch((err) => {
|
|
509
501
|
throw prefixMessage(err, 'Error while re-fetching CSRF token.')
|
|
510
502
|
})
|
|
@@ -615,7 +607,7 @@ export const throwIfError = (response: AxiosResponse) => {
|
|
|
615
607
|
typeof response.data === 'string' &&
|
|
616
608
|
response.data.toLowerCase() === 'invalid csrf token!'
|
|
617
609
|
) {
|
|
618
|
-
throw new
|
|
610
|
+
throw new InvalidSASjsCsrfError()
|
|
619
611
|
}
|
|
620
612
|
break
|
|
621
613
|
case 401:
|