@sasjs/adapter 4.3.2 → 4.3.4
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/SASViyaApiClient.d.ts +2 -2
- package/SASjsApiClient.d.ts +10 -5
- package/index-dev.js +2 -2
- package/index.js +1 -1
- package/node/SASViyaApiClient.d.ts +2 -2
- package/node/SASjsApiClient.d.ts +10 -5
- package/node/index.js +1 -1
- package/node/request/SasjsRequestClient.d.ts +9 -6
- package/package.json +2 -2
- package/request/SasjsRequestClient.d.ts +9 -6
- package/src/SASViyaApiClient.ts +35 -6
- package/src/SASjs.ts +11 -8
- package/src/SASjsApiClient.ts +28 -11
- package/src/job-execution/SasjsJobExecutor.ts +9 -1
- package/src/request/SasjsRequestClient.ts +23 -6
- package/src/utils/getValidJson.ts +1 -0
|
@@ -1,15 +1,18 @@
|
|
|
1
1
|
import { RequestClient } from './RequestClient';
|
|
2
2
|
import { AxiosResponse } from 'axios';
|
|
3
|
+
interface SasjsParsedResponse<T> {
|
|
4
|
+
result: T;
|
|
5
|
+
log: string;
|
|
6
|
+
etag: string;
|
|
7
|
+
status: number;
|
|
8
|
+
printOutput?: string;
|
|
9
|
+
}
|
|
3
10
|
/**
|
|
4
11
|
* Specific request client for SASJS.
|
|
5
12
|
* Append tokens in headers.
|
|
6
13
|
*/
|
|
7
14
|
export declare class SasjsRequestClient extends RequestClient {
|
|
8
15
|
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
|
-
};
|
|
16
|
+
protected parseResponse<T>(response: AxiosResponse<any>): SasjsParsedResponse<T>;
|
|
15
17
|
}
|
|
18
|
+
export {};
|
package/package.json
CHANGED
|
@@ -60,7 +60,7 @@
|
|
|
60
60
|
"node-polyfill-webpack-plugin": "1.1.4",
|
|
61
61
|
"path": "0.12.7",
|
|
62
62
|
"pem": "1.14.5",
|
|
63
|
-
"prettier": "2.7
|
|
63
|
+
"prettier": "2.8.7",
|
|
64
64
|
"process": "0.11.10",
|
|
65
65
|
"rimraf": "3.0.2",
|
|
66
66
|
"semantic-release": "19.0.3",
|
|
@@ -84,5 +84,5 @@
|
|
|
84
84
|
"https": "1.0.0",
|
|
85
85
|
"tough-cookie": "4.0.0"
|
|
86
86
|
},
|
|
87
|
-
"version": "4.3.
|
|
87
|
+
"version": "4.3.4"
|
|
88
88
|
}
|
|
@@ -1,15 +1,18 @@
|
|
|
1
1
|
import { RequestClient } from './RequestClient';
|
|
2
2
|
import { AxiosResponse } from 'axios';
|
|
3
|
+
interface SasjsParsedResponse<T> {
|
|
4
|
+
result: T;
|
|
5
|
+
log: string;
|
|
6
|
+
etag: string;
|
|
7
|
+
status: number;
|
|
8
|
+
printOutput?: string;
|
|
9
|
+
}
|
|
3
10
|
/**
|
|
4
11
|
* Specific request client for SASJS.
|
|
5
12
|
* Append tokens in headers.
|
|
6
13
|
*/
|
|
7
14
|
export declare class SasjsRequestClient extends RequestClient {
|
|
8
15
|
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
|
-
};
|
|
16
|
+
protected parseResponse<T>(response: AxiosResponse<any>): SasjsParsedResponse<T>;
|
|
15
17
|
}
|
|
18
|
+
export {};
|
package/src/SASViyaApiClient.ts
CHANGED
|
@@ -378,12 +378,14 @@ export class SASViyaApiClient {
|
|
|
378
378
|
isForced?: boolean
|
|
379
379
|
): Promise<Folder> {
|
|
380
380
|
const logger = process.logger || console
|
|
381
|
+
|
|
381
382
|
if (!parentFolderPath && !parentFolderUri) {
|
|
382
383
|
throw new Error('Path or URI of the parent folder is required.')
|
|
383
384
|
}
|
|
384
385
|
|
|
385
386
|
if (!parentFolderUri && parentFolderPath) {
|
|
386
387
|
parentFolderUri = await this.getFolderUri(parentFolderPath, accessToken)
|
|
388
|
+
|
|
387
389
|
if (!parentFolderUri) {
|
|
388
390
|
logger.info(
|
|
389
391
|
`Parent folder at path '${parentFolderPath}' is not present.`
|
|
@@ -394,6 +396,7 @@ export class SASViyaApiClient {
|
|
|
394
396
|
parentFolderPath.lastIndexOf('/')
|
|
395
397
|
)
|
|
396
398
|
const newFolderName = `${parentFolderPath.split('/').pop()}`
|
|
399
|
+
|
|
397
400
|
if (newParentFolderPath === '') {
|
|
398
401
|
throw new RootFolderNotFoundError(
|
|
399
402
|
parentFolderPath,
|
|
@@ -401,20 +404,24 @@ export class SASViyaApiClient {
|
|
|
401
404
|
accessToken
|
|
402
405
|
)
|
|
403
406
|
}
|
|
407
|
+
|
|
404
408
|
logger.info(
|
|
405
409
|
`Creating parent folder:\n'${newFolderName}' in '${newParentFolderPath}'`
|
|
406
410
|
)
|
|
411
|
+
|
|
407
412
|
const parentFolder = await this.createFolder(
|
|
408
413
|
newFolderName,
|
|
409
414
|
newParentFolderPath,
|
|
410
415
|
undefined,
|
|
411
416
|
accessToken
|
|
412
417
|
)
|
|
418
|
+
|
|
413
419
|
logger.info(
|
|
414
420
|
`Parent folder '${newFolderName}' has been successfully created.`
|
|
415
421
|
)
|
|
422
|
+
|
|
416
423
|
parentFolderUri = `/folders/folders/${parentFolder.id}`
|
|
417
|
-
} else if (isForced
|
|
424
|
+
} else if (isForced) {
|
|
418
425
|
const folderPath = parentFolderPath + '/' + folderName
|
|
419
426
|
const folderUri = await this.getFolderUri(folderPath, accessToken)
|
|
420
427
|
|
|
@@ -427,8 +434,8 @@ export class SASViyaApiClient {
|
|
|
427
434
|
}
|
|
428
435
|
}
|
|
429
436
|
|
|
430
|
-
const { result: createFolderResponse } =
|
|
431
|
-
|
|
437
|
+
const { result: createFolderResponse } = await this.requestClient
|
|
438
|
+
.post<Folder>(
|
|
432
439
|
`/folders/folders?parentFolderUri=${parentFolderUri}`,
|
|
433
440
|
{
|
|
434
441
|
name: folderName,
|
|
@@ -436,12 +443,34 @@ export class SASViyaApiClient {
|
|
|
436
443
|
},
|
|
437
444
|
accessToken
|
|
438
445
|
)
|
|
446
|
+
.catch((err) => {
|
|
447
|
+
const { message, response } = err
|
|
448
|
+
|
|
449
|
+
if (message && response && response.data && response.data.message) {
|
|
450
|
+
const { status } = response
|
|
451
|
+
const { message: responseMessage } = response.data
|
|
452
|
+
const messages = [message, responseMessage].map((mes: string) =>
|
|
453
|
+
/\.$/.test(mes) ? mes : `${mes}.`
|
|
454
|
+
)
|
|
455
|
+
|
|
456
|
+
if (!isForced && status === 409) {
|
|
457
|
+
messages.push(`To override, please set "isForced" to "true".`)
|
|
458
|
+
}
|
|
459
|
+
|
|
460
|
+
const errMessage = messages.join(' ')
|
|
461
|
+
|
|
462
|
+
throw errMessage
|
|
463
|
+
}
|
|
464
|
+
|
|
465
|
+
throw err
|
|
466
|
+
})
|
|
439
467
|
|
|
440
468
|
// update folder map with newly created folder.
|
|
441
469
|
await this.populateFolderMap(
|
|
442
470
|
`${parentFolderPath}/${folderName}`,
|
|
443
471
|
accessToken
|
|
444
472
|
)
|
|
473
|
+
|
|
445
474
|
return createFolderResponse
|
|
446
475
|
}
|
|
447
476
|
|
|
@@ -900,7 +929,7 @@ export class SASViyaApiClient {
|
|
|
900
929
|
return `/folders/folders/${folderDetails.id}`
|
|
901
930
|
}
|
|
902
931
|
|
|
903
|
-
private async getRecycleBinUri(accessToken
|
|
932
|
+
private async getRecycleBinUri(accessToken?: string) {
|
|
904
933
|
const url = '/folders/folders/@myRecycleBin'
|
|
905
934
|
|
|
906
935
|
const { result: folder } = await this.requestClient
|
|
@@ -984,7 +1013,7 @@ export class SASViyaApiClient {
|
|
|
984
1013
|
sourceFolder: string,
|
|
985
1014
|
targetParentFolder: string,
|
|
986
1015
|
targetFolderName: string,
|
|
987
|
-
accessToken
|
|
1016
|
+
accessToken?: string
|
|
988
1017
|
) {
|
|
989
1018
|
// If target path is an existing folder, than keep source folder name, othervise rename it with given target folder name
|
|
990
1019
|
const sourceFolderName = sourceFolder.split('/').pop() as string
|
|
@@ -1051,7 +1080,7 @@ export class SASViyaApiClient {
|
|
|
1051
1080
|
* @param folderPath - the full path (eg `/Public/example/deleteThis`) of the folder to be deleted.
|
|
1052
1081
|
* @param accessToken - an access token for authorizing the request.
|
|
1053
1082
|
*/
|
|
1054
|
-
public async deleteFolder(folderPath: string, accessToken
|
|
1083
|
+
public async deleteFolder(folderPath: string, accessToken?: string) {
|
|
1055
1084
|
const recycleBinUri = await this.getRecycleBinUri(accessToken)
|
|
1056
1085
|
const folderName = folderPath.split('/').pop() || ''
|
|
1057
1086
|
const date = new Date()
|
package/src/SASjs.ts
CHANGED
|
@@ -337,13 +337,16 @@ export default class SASjs {
|
|
|
337
337
|
sasApiClient?: SASViyaApiClient,
|
|
338
338
|
isForced?: boolean
|
|
339
339
|
) {
|
|
340
|
-
if (sasApiClient)
|
|
340
|
+
if (sasApiClient) {
|
|
341
341
|
return await sasApiClient.createFolder(
|
|
342
342
|
folderName,
|
|
343
343
|
parentFolderPath,
|
|
344
344
|
parentFolderUri,
|
|
345
|
-
accessToken
|
|
345
|
+
accessToken,
|
|
346
|
+
isForced
|
|
346
347
|
)
|
|
348
|
+
}
|
|
349
|
+
|
|
347
350
|
return await this.sasViyaApiClient!.createFolder(
|
|
348
351
|
folderName,
|
|
349
352
|
parentFolderPath,
|
|
@@ -783,13 +786,11 @@ export default class SASjs {
|
|
|
783
786
|
this.isMethodSupported('deployServicePack', [ServerType.SasViya])
|
|
784
787
|
|
|
785
788
|
let sasApiClient: any = null
|
|
789
|
+
|
|
786
790
|
if (serverUrl || appLoc) {
|
|
787
|
-
if (!serverUrl)
|
|
788
|
-
|
|
789
|
-
|
|
790
|
-
if (!appLoc) {
|
|
791
|
-
appLoc = this.sasjsConfig.appLoc
|
|
792
|
-
}
|
|
791
|
+
if (!serverUrl) serverUrl = this.sasjsConfig.serverUrl
|
|
792
|
+
if (!appLoc) appLoc = this.sasjsConfig.appLoc
|
|
793
|
+
|
|
793
794
|
if (this.sasjsConfig.serverType === ServerType.SasViya) {
|
|
794
795
|
sasApiClient = new SASViyaApiClient(
|
|
795
796
|
serverUrl,
|
|
@@ -807,11 +808,13 @@ export default class SASjs {
|
|
|
807
808
|
}
|
|
808
809
|
} else {
|
|
809
810
|
let sasClientConfig: any = null
|
|
811
|
+
|
|
810
812
|
if (this.sasjsConfig.serverType === ServerType.SasViya) {
|
|
811
813
|
sasClientConfig = this.sasViyaApiClient!.getConfig()
|
|
812
814
|
} else if (this.sasjsConfig.serverType === ServerType.Sas9) {
|
|
813
815
|
sasClientConfig = this.sas9ApiClient!.getConfig()
|
|
814
816
|
}
|
|
817
|
+
|
|
815
818
|
serverUrl = sasClientConfig.serverUrl
|
|
816
819
|
appLoc = sasClientConfig.rootFolderName as string
|
|
817
820
|
}
|
package/src/SASjsApiClient.ts
CHANGED
|
@@ -1,11 +1,24 @@
|
|
|
1
1
|
import * as NodeFormData from 'form-data'
|
|
2
2
|
import { AuthConfig, ServerType, ServicePackSASjs } from '@sasjs/utils/types'
|
|
3
|
+
import { prefixMessage } from '@sasjs/utils/error'
|
|
3
4
|
import { ExecutionQuery } from './types'
|
|
4
5
|
import { RequestClient } from './request/RequestClient'
|
|
5
6
|
import { getAccessTokenForSasjs } from './auth/getAccessTokenForSasjs'
|
|
6
7
|
import { refreshTokensForSasjs } from './auth/refreshTokensForSasjs'
|
|
7
8
|
import { getTokens } from './auth/getTokens'
|
|
8
9
|
|
|
10
|
+
// TODO: move to sasjs/utils
|
|
11
|
+
export interface SASjsAuthResponse {
|
|
12
|
+
access_token: string
|
|
13
|
+
refresh_token: string
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
export interface ScriptExecutionResult {
|
|
17
|
+
log: string
|
|
18
|
+
webout?: string
|
|
19
|
+
printOutput?: string
|
|
20
|
+
}
|
|
21
|
+
|
|
9
22
|
export class SASjsApiClient {
|
|
10
23
|
constructor(private requestClient: RequestClient) {}
|
|
11
24
|
|
|
@@ -118,18 +131,28 @@ export class SASjsApiClient {
|
|
|
118
131
|
code: string,
|
|
119
132
|
runTime: string = 'sas',
|
|
120
133
|
authConfig?: AuthConfig
|
|
121
|
-
) {
|
|
134
|
+
): Promise<ScriptExecutionResult> {
|
|
122
135
|
const access_token = await this.getAccessTokenForRequest(authConfig)
|
|
123
|
-
|
|
124
|
-
let parsedSasjsServerLog = ''
|
|
136
|
+
const executionResult: ScriptExecutionResult = { log: '' }
|
|
125
137
|
|
|
126
138
|
await this.requestClient
|
|
127
139
|
.post('SASjsApi/code/execute', { code, runTime }, access_token)
|
|
128
140
|
.then((res: any) => {
|
|
129
|
-
|
|
141
|
+
const { log, printOutput, result: webout } = res
|
|
142
|
+
|
|
143
|
+
executionResult.log = log
|
|
144
|
+
|
|
145
|
+
if (printOutput) executionResult.printOutput = printOutput
|
|
146
|
+
if (webout) executionResult.webout = webout
|
|
147
|
+
})
|
|
148
|
+
.catch((err) => {
|
|
149
|
+
throw prefixMessage(
|
|
150
|
+
err,
|
|
151
|
+
'Error while sending POST request to execute code. '
|
|
152
|
+
)
|
|
130
153
|
})
|
|
131
154
|
|
|
132
|
-
return
|
|
155
|
+
return executionResult
|
|
133
156
|
}
|
|
134
157
|
|
|
135
158
|
/**
|
|
@@ -152,9 +175,3 @@ export class SASjsApiClient {
|
|
|
152
175
|
return refreshTokensForSasjs(this.requestClient, refreshToken)
|
|
153
176
|
}
|
|
154
177
|
}
|
|
155
|
-
|
|
156
|
-
// todo move to sasjs/utils
|
|
157
|
-
export interface SASjsAuthResponse {
|
|
158
|
-
access_token: string
|
|
159
|
-
refresh_token: string
|
|
160
|
-
}
|
|
@@ -13,7 +13,11 @@ import { generateFileUploadForm } from '../file/generateFileUploadForm'
|
|
|
13
13
|
|
|
14
14
|
import { RequestClient } from '../request/RequestClient'
|
|
15
15
|
|
|
16
|
-
import {
|
|
16
|
+
import {
|
|
17
|
+
isRelativePath,
|
|
18
|
+
appendExtraResponseAttributes,
|
|
19
|
+
getValidJson
|
|
20
|
+
} from '../utils'
|
|
17
21
|
import { BaseJobExecutor } from './JobExecutor'
|
|
18
22
|
|
|
19
23
|
export class SasjsJobExecutor extends BaseJobExecutor {
|
|
@@ -89,12 +93,16 @@ export class SasjsJobExecutor extends BaseJobExecutor {
|
|
|
89
93
|
)
|
|
90
94
|
}
|
|
91
95
|
|
|
96
|
+
const { result } = res.result
|
|
97
|
+
if (result && result.trim()) res.result = getValidJson(result)
|
|
98
|
+
|
|
92
99
|
this.requestClient!.appendRequest(res, sasJob, config.debug)
|
|
93
100
|
|
|
94
101
|
const responseObject = appendExtraResponseAttributes(
|
|
95
102
|
res,
|
|
96
103
|
extraResponseAttributes
|
|
97
104
|
)
|
|
105
|
+
|
|
98
106
|
resolve(responseObject)
|
|
99
107
|
})
|
|
100
108
|
.catch(async (e: Error) => {
|
|
@@ -1,6 +1,14 @@
|
|
|
1
1
|
import { RequestClient } from './RequestClient'
|
|
2
2
|
import { AxiosResponse } from 'axios'
|
|
3
|
-
import { SASJS_LOGS_SEPARATOR
|
|
3
|
+
import { SASJS_LOGS_SEPARATOR } from '../utils'
|
|
4
|
+
|
|
5
|
+
interface SasjsParsedResponse<T> {
|
|
6
|
+
result: T
|
|
7
|
+
log: string
|
|
8
|
+
etag: string
|
|
9
|
+
status: number
|
|
10
|
+
printOutput?: string
|
|
11
|
+
}
|
|
4
12
|
|
|
5
13
|
/**
|
|
6
14
|
* Specific request client for SASJS.
|
|
@@ -27,7 +35,7 @@ export class SasjsRequestClient extends RequestClient {
|
|
|
27
35
|
protected parseResponse<T>(response: AxiosResponse<any>) {
|
|
28
36
|
const etag = response?.headers ? response.headers['etag'] : ''
|
|
29
37
|
let parsedResponse = {}
|
|
30
|
-
let log
|
|
38
|
+
let webout, log, printOutput
|
|
31
39
|
|
|
32
40
|
try {
|
|
33
41
|
if (typeof response.data === 'string') {
|
|
@@ -38,17 +46,26 @@ export class SasjsRequestClient extends RequestClient {
|
|
|
38
46
|
} catch {
|
|
39
47
|
if (response.data.includes(SASJS_LOGS_SEPARATOR)) {
|
|
40
48
|
const splittedResponse = response.data.split(SASJS_LOGS_SEPARATOR)
|
|
49
|
+
|
|
50
|
+
webout = splittedResponse[0]
|
|
51
|
+
if (webout) parsedResponse = webout
|
|
52
|
+
|
|
41
53
|
log = splittedResponse[1]
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
54
|
+
printOutput = splittedResponse[2]
|
|
55
|
+
} else {
|
|
56
|
+
parsedResponse = response.data
|
|
57
|
+
}
|
|
45
58
|
}
|
|
46
59
|
|
|
47
|
-
|
|
60
|
+
const returnResult: SasjsParsedResponse<T> = {
|
|
48
61
|
result: parsedResponse as T,
|
|
49
62
|
log,
|
|
50
63
|
etag,
|
|
51
64
|
status: response.status
|
|
52
65
|
}
|
|
66
|
+
|
|
67
|
+
if (printOutput) returnResult.printOutput = printOutput
|
|
68
|
+
|
|
69
|
+
return returnResult
|
|
53
70
|
}
|
|
54
71
|
}
|