@sasjs/adapter 4.11.3 → 4.12.1
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 +25 -8
- package/SASjs.d.ts +19 -1
- package/index-dev.js +109 -12
- package/index.js +109 -12
- package/minified_sas9.js +2 -2
- package/node/SASViyaApiClient.d.ts +25 -8
- package/node/SASjs.d.ts +19 -1
- package/node/index.js +109 -12
- package/node/types/FileResource.d.ts +32 -0
- package/package.json +1 -1
- package/src/SASViyaApiClient.ts +125 -7
- package/src/SASjs.ts +52 -2
- package/src/job-execution/JobExecutor.ts +1 -1
- package/src/types/FileResource.ts +33 -0
- package/types/FileResource.d.ts +32 -0
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
export interface FileResource {
|
|
2
|
+
creationTimeStamp: string;
|
|
3
|
+
modifiedTimeStamp: string;
|
|
4
|
+
createdBy: string;
|
|
5
|
+
modifiedBy: string;
|
|
6
|
+
id: string;
|
|
7
|
+
properties: Properties;
|
|
8
|
+
contentDisposition: string;
|
|
9
|
+
contentType: string;
|
|
10
|
+
encoding: string;
|
|
11
|
+
links: Link[];
|
|
12
|
+
name: string;
|
|
13
|
+
size: number;
|
|
14
|
+
searchable: boolean;
|
|
15
|
+
fileStatus: string;
|
|
16
|
+
fileVersion: number;
|
|
17
|
+
typeDefName: string;
|
|
18
|
+
version: number;
|
|
19
|
+
virusDetected: boolean;
|
|
20
|
+
urlDetected: boolean;
|
|
21
|
+
quarantine: boolean;
|
|
22
|
+
}
|
|
23
|
+
export interface Link {
|
|
24
|
+
method: string;
|
|
25
|
+
rel: string;
|
|
26
|
+
href: string;
|
|
27
|
+
uri: string;
|
|
28
|
+
type?: string;
|
|
29
|
+
responseType?: string;
|
|
30
|
+
}
|
|
31
|
+
export interface Properties {
|
|
32
|
+
}
|
package/package.json
CHANGED
package/src/SASViyaApiClient.ts
CHANGED
|
@@ -28,6 +28,7 @@ import { uploadTables } from './api/viya/uploadTables'
|
|
|
28
28
|
import { executeOnComputeApi } from './api/viya/executeOnComputeApi'
|
|
29
29
|
import { getAccessTokenForViya } from './auth/getAccessTokenForViya'
|
|
30
30
|
import { refreshTokensForViya } from './auth/refreshTokensForViya'
|
|
31
|
+
import { FileResource } from './types/FileResource'
|
|
31
32
|
|
|
32
33
|
interface JobExecutionResult {
|
|
33
34
|
result?: { result: object }
|
|
@@ -311,6 +312,84 @@ export class SASViyaApiClient {
|
|
|
311
312
|
)
|
|
312
313
|
}
|
|
313
314
|
|
|
315
|
+
/**
|
|
316
|
+
* Fetches the file content for a file in the specified folder.
|
|
317
|
+
*
|
|
318
|
+
* @param folderPath - the full path to the folder containing the file. eg: /Public/folder1/folder2
|
|
319
|
+
* @param fileName - the name of the file in the `folderPath`
|
|
320
|
+
* @param accessToken - an access token for authorizing the request
|
|
321
|
+
*/
|
|
322
|
+
public async getFileContent(
|
|
323
|
+
folderPath: string,
|
|
324
|
+
fileName: string,
|
|
325
|
+
accessToken?: string
|
|
326
|
+
) {
|
|
327
|
+
const fileUri = await this.getFileUri(
|
|
328
|
+
folderPath,
|
|
329
|
+
fileName,
|
|
330
|
+
accessToken
|
|
331
|
+
).catch((err) => {
|
|
332
|
+
throw prefixMessage(
|
|
333
|
+
err,
|
|
334
|
+
`Error while getting file URI for: ${fileName} in folder: ${folderPath}. `
|
|
335
|
+
)
|
|
336
|
+
})
|
|
337
|
+
|
|
338
|
+
return await this.requestClient
|
|
339
|
+
.get<string>(`${this.serverUrl}${fileUri}/content`, accessToken)
|
|
340
|
+
.then((res) => res.result)
|
|
341
|
+
}
|
|
342
|
+
|
|
343
|
+
/**
|
|
344
|
+
* Updates the file content for a file in the specified folder.
|
|
345
|
+
*
|
|
346
|
+
* @param folderPath - the full path to the folder containing the file. eg: /Public/folder1/folder2
|
|
347
|
+
* @param fileName - the name of the file in the `folderPath`
|
|
348
|
+
* @param content - the new content to be written to the file
|
|
349
|
+
* @param accessToken - an access token for authorizing the request
|
|
350
|
+
*/
|
|
351
|
+
public async updateFileContent(
|
|
352
|
+
folderPath: string,
|
|
353
|
+
fileName: string,
|
|
354
|
+
content: string,
|
|
355
|
+
accessToken?: string
|
|
356
|
+
) {
|
|
357
|
+
const fileUri = await this.getFileUri(
|
|
358
|
+
folderPath,
|
|
359
|
+
fileName,
|
|
360
|
+
accessToken
|
|
361
|
+
).catch((err) => {
|
|
362
|
+
throw prefixMessage(
|
|
363
|
+
err,
|
|
364
|
+
`Error while getting file URI for: ${fileName} in folder: ${folderPath}. `
|
|
365
|
+
)
|
|
366
|
+
})
|
|
367
|
+
|
|
368
|
+
// Fetch the file resource details to get the Etag and content type
|
|
369
|
+
const { result: originalFileResource, etag } =
|
|
370
|
+
await this.requestClient.get<FileResource>(
|
|
371
|
+
`${this.serverUrl}${fileUri}`,
|
|
372
|
+
accessToken
|
|
373
|
+
)
|
|
374
|
+
|
|
375
|
+
if (!originalFileResource || !etag)
|
|
376
|
+
throw new Error(
|
|
377
|
+
`File ${fileName} does not have an ETag, or request failed.`
|
|
378
|
+
)
|
|
379
|
+
|
|
380
|
+
return await this.requestClient
|
|
381
|
+
.put<FileResource>(
|
|
382
|
+
`${this.serverUrl}${fileUri}/content`,
|
|
383
|
+
content,
|
|
384
|
+
accessToken,
|
|
385
|
+
{
|
|
386
|
+
'If-Match': etag,
|
|
387
|
+
'Content-Type': originalFileResource.contentType
|
|
388
|
+
}
|
|
389
|
+
)
|
|
390
|
+
.then((res) => res.result)
|
|
391
|
+
}
|
|
392
|
+
|
|
314
393
|
/**
|
|
315
394
|
* Fetches a folder. Path to the folder is required.
|
|
316
395
|
* @param folderPath - the absolute path to the folder.
|
|
@@ -791,14 +870,14 @@ export class SASViyaApiClient {
|
|
|
791
870
|
_webin_file_count: files.length,
|
|
792
871
|
_OMITJSONLISTING: true,
|
|
793
872
|
_OMITJSONLOG: true,
|
|
794
|
-
|
|
873
|
+
_omitSessionResults: false,
|
|
795
874
|
_OMITTEXTLISTING: true,
|
|
796
875
|
_OMITTEXTLOG: true
|
|
797
876
|
}
|
|
798
877
|
|
|
799
878
|
if (debug) {
|
|
800
879
|
jobArguments['_OMITTEXTLOG'] = 'false'
|
|
801
|
-
jobArguments['
|
|
880
|
+
jobArguments['_omitSessionResults'] = 'false'
|
|
802
881
|
jobArguments['_DEBUG'] = 131
|
|
803
882
|
}
|
|
804
883
|
|
|
@@ -941,6 +1020,7 @@ export class SASViyaApiClient {
|
|
|
941
1020
|
})
|
|
942
1021
|
|
|
943
1022
|
if (!folder) return undefined
|
|
1023
|
+
|
|
944
1024
|
return folder
|
|
945
1025
|
}
|
|
946
1026
|
|
|
@@ -952,6 +1032,30 @@ export class SASViyaApiClient {
|
|
|
952
1032
|
return `/folders/folders/${folderDetails.id}`
|
|
953
1033
|
}
|
|
954
1034
|
|
|
1035
|
+
private async getFileUri(
|
|
1036
|
+
folderPath: string,
|
|
1037
|
+
fileName: string,
|
|
1038
|
+
accessToken?: string
|
|
1039
|
+
): Promise<string> {
|
|
1040
|
+
const folderMembers = await this.listFolder(folderPath, accessToken, 1000, {
|
|
1041
|
+
returnDetails: true
|
|
1042
|
+
}).catch((err) => {
|
|
1043
|
+
throw prefixMessage(err, `Error while listing folder: ${folderPath}. `)
|
|
1044
|
+
})
|
|
1045
|
+
|
|
1046
|
+
if (!folderMembers || !folderMembers.length)
|
|
1047
|
+
throw new Error(`No members found in folder: ${folderPath}`)
|
|
1048
|
+
|
|
1049
|
+
const fileUri = folderMembers.find(
|
|
1050
|
+
(member) => member.name === fileName
|
|
1051
|
+
)?.uri
|
|
1052
|
+
|
|
1053
|
+
if (!fileUri)
|
|
1054
|
+
throw new Error(`File ${fileName} not found in folder: ${folderPath}`)
|
|
1055
|
+
|
|
1056
|
+
return fileUri
|
|
1057
|
+
}
|
|
1058
|
+
|
|
955
1059
|
private async getRecycleBinUri(accessToken?: string) {
|
|
956
1060
|
const url = '/folders/folders/@myRecycleBin'
|
|
957
1061
|
|
|
@@ -999,14 +1103,19 @@ export class SASViyaApiClient {
|
|
|
999
1103
|
}
|
|
1000
1104
|
|
|
1001
1105
|
/**
|
|
1002
|
-
* Lists children folders for given Viya folder.
|
|
1106
|
+
* Lists children folders/files for given Viya folder.
|
|
1003
1107
|
* @param sourceFolder - the full path (eg `/Public/example/myFolder`) or URI of the source folder listed. Providing URI instead of path will save one extra request.
|
|
1004
1108
|
* @param accessToken - an access token for authorizing the request.
|
|
1109
|
+
* @param {Object} [options] - Additional options.
|
|
1110
|
+
* @param {boolean} [options.returnDetails=false] - when set to true, the function will return an array of objects with member details, otherwise it will return an array of member names.
|
|
1005
1111
|
*/
|
|
1006
1112
|
public async listFolder(
|
|
1007
1113
|
sourceFolder: string,
|
|
1008
1114
|
accessToken?: string,
|
|
1009
|
-
limit: number = 20
|
|
1115
|
+
limit: number = 20,
|
|
1116
|
+
options?: {
|
|
1117
|
+
returnDetails?: boolean
|
|
1118
|
+
}
|
|
1010
1119
|
) {
|
|
1011
1120
|
// checks if 'sourceFolder' is already a URI
|
|
1012
1121
|
const sourceFolderUri = isUri(sourceFolder)
|
|
@@ -1018,11 +1127,20 @@ export class SASViyaApiClient {
|
|
|
1018
1127
|
accessToken
|
|
1019
1128
|
)
|
|
1020
1129
|
|
|
1130
|
+
let membersToReturn = []
|
|
1131
|
+
|
|
1021
1132
|
if (members && members.items) {
|
|
1022
|
-
return
|
|
1023
|
-
|
|
1024
|
-
|
|
1133
|
+
// If returnDetails is true, return full member details
|
|
1134
|
+
if (options?.returnDetails) {
|
|
1135
|
+
membersToReturn = members.items
|
|
1136
|
+
} else {
|
|
1137
|
+
// If returnDetails is false, return only member names
|
|
1138
|
+
membersToReturn = members.items.map((item: any) => item.name)
|
|
1139
|
+
}
|
|
1025
1140
|
}
|
|
1141
|
+
|
|
1142
|
+
// Return members without Etag
|
|
1143
|
+
return membersToReturn
|
|
1026
1144
|
}
|
|
1027
1145
|
|
|
1028
1146
|
/**
|
package/src/SASjs.ts
CHANGED
|
@@ -411,6 +411,51 @@ export default class SASjs {
|
|
|
411
411
|
)
|
|
412
412
|
}
|
|
413
413
|
|
|
414
|
+
/**
|
|
415
|
+
* Fetches the file content for a file in the specified folder.
|
|
416
|
+
*
|
|
417
|
+
* @param folderPath - the full path to the folder containing the file. eg: /Public/folder1/folder2
|
|
418
|
+
* @param fileName - the name of the file in the `folderPath`
|
|
419
|
+
* @param accessToken - an access token for authorizing the request
|
|
420
|
+
*/
|
|
421
|
+
public async getFileContent(
|
|
422
|
+
folderPath: string,
|
|
423
|
+
fileName: string,
|
|
424
|
+
accessToken?: string
|
|
425
|
+
) {
|
|
426
|
+
this.isMethodSupported('getFileContent', [ServerType.SasViya])
|
|
427
|
+
|
|
428
|
+
return await this.sasViyaApiClient!.getFileContent(
|
|
429
|
+
folderPath,
|
|
430
|
+
fileName,
|
|
431
|
+
accessToken
|
|
432
|
+
)
|
|
433
|
+
}
|
|
434
|
+
|
|
435
|
+
/**
|
|
436
|
+
* Updates the file content for a file in the specified folder.
|
|
437
|
+
*
|
|
438
|
+
* @param folderPath - the full path to the folder containing the file. eg: /Public/folder1/folder2
|
|
439
|
+
* @param fileName - the name of the file in the `folderPath`
|
|
440
|
+
* @param content - the new content to be written to the file
|
|
441
|
+
* @param accessToken - an access token for authorizing the request
|
|
442
|
+
*/
|
|
443
|
+
public async updateFileContent(
|
|
444
|
+
folderPath: string,
|
|
445
|
+
fileName: string,
|
|
446
|
+
content: string,
|
|
447
|
+
accessToken?: string
|
|
448
|
+
) {
|
|
449
|
+
this.isMethodSupported('updateFileContent', [ServerType.SasViya])
|
|
450
|
+
|
|
451
|
+
return await this.sasViyaApiClient!.updateFileContent(
|
|
452
|
+
folderPath,
|
|
453
|
+
fileName,
|
|
454
|
+
content,
|
|
455
|
+
accessToken
|
|
456
|
+
)
|
|
457
|
+
}
|
|
458
|
+
|
|
414
459
|
/**
|
|
415
460
|
* Fetches a folder from the SAS file system.
|
|
416
461
|
* @param folderPath - path of the folder to be fetched.
|
|
@@ -436,18 +481,23 @@ export default class SASjs {
|
|
|
436
481
|
* Lists children folders for given Viya folder.
|
|
437
482
|
* @param sourceFolder - the full path (eg `/Public/example/myFolder`) or URI of the source folder listed. Providing URI instead of path will save one extra request.
|
|
438
483
|
* @param accessToken - an access token for authorizing the request.
|
|
484
|
+
* @param returnDetails - when set to true, the function will return an array of objects with member details, otherwise it will return an array of member names.
|
|
439
485
|
*/
|
|
440
486
|
public async listFolder(
|
|
441
487
|
sourceFolder: string,
|
|
442
488
|
accessToken?: string,
|
|
443
|
-
limit?: number
|
|
489
|
+
limit?: number,
|
|
490
|
+
returnDetails = false
|
|
444
491
|
) {
|
|
445
492
|
this.isMethodSupported('listFolder', [ServerType.SasViya])
|
|
446
493
|
|
|
447
494
|
return await this.sasViyaApiClient?.listFolder(
|
|
448
495
|
sourceFolder,
|
|
449
496
|
accessToken,
|
|
450
|
-
limit
|
|
497
|
+
limit,
|
|
498
|
+
{
|
|
499
|
+
returnDetails
|
|
500
|
+
}
|
|
451
501
|
)
|
|
452
502
|
}
|
|
453
503
|
|
|
@@ -51,7 +51,7 @@ export abstract class BaseJobExecutor implements JobExecutor {
|
|
|
51
51
|
|
|
52
52
|
if (config.debug) {
|
|
53
53
|
requestParams['_omittextlog'] = 'false'
|
|
54
|
-
requestParams['
|
|
54
|
+
requestParams['_omitSessionResults'] = 'false'
|
|
55
55
|
|
|
56
56
|
requestParams['_debug'] = 131
|
|
57
57
|
}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
export interface FileResource {
|
|
2
|
+
creationTimeStamp: string
|
|
3
|
+
modifiedTimeStamp: string
|
|
4
|
+
createdBy: string
|
|
5
|
+
modifiedBy: string
|
|
6
|
+
id: string
|
|
7
|
+
properties: Properties
|
|
8
|
+
contentDisposition: string
|
|
9
|
+
contentType: string
|
|
10
|
+
encoding: string
|
|
11
|
+
links: Link[]
|
|
12
|
+
name: string
|
|
13
|
+
size: number
|
|
14
|
+
searchable: boolean
|
|
15
|
+
fileStatus: string
|
|
16
|
+
fileVersion: number
|
|
17
|
+
typeDefName: string
|
|
18
|
+
version: number
|
|
19
|
+
virusDetected: boolean
|
|
20
|
+
urlDetected: boolean
|
|
21
|
+
quarantine: boolean
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
export interface Link {
|
|
25
|
+
method: string
|
|
26
|
+
rel: string
|
|
27
|
+
href: string
|
|
28
|
+
uri: string
|
|
29
|
+
type?: string
|
|
30
|
+
responseType?: string
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
export interface Properties {}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
export interface FileResource {
|
|
2
|
+
creationTimeStamp: string;
|
|
3
|
+
modifiedTimeStamp: string;
|
|
4
|
+
createdBy: string;
|
|
5
|
+
modifiedBy: string;
|
|
6
|
+
id: string;
|
|
7
|
+
properties: Properties;
|
|
8
|
+
contentDisposition: string;
|
|
9
|
+
contentType: string;
|
|
10
|
+
encoding: string;
|
|
11
|
+
links: Link[];
|
|
12
|
+
name: string;
|
|
13
|
+
size: number;
|
|
14
|
+
searchable: boolean;
|
|
15
|
+
fileStatus: string;
|
|
16
|
+
fileVersion: number;
|
|
17
|
+
typeDefName: string;
|
|
18
|
+
version: number;
|
|
19
|
+
virusDetected: boolean;
|
|
20
|
+
urlDetected: boolean;
|
|
21
|
+
quarantine: boolean;
|
|
22
|
+
}
|
|
23
|
+
export interface Link {
|
|
24
|
+
method: string;
|
|
25
|
+
rel: string;
|
|
26
|
+
href: string;
|
|
27
|
+
uri: string;
|
|
28
|
+
type?: string;
|
|
29
|
+
responseType?: string;
|
|
30
|
+
}
|
|
31
|
+
export interface Properties {
|
|
32
|
+
}
|