@sasjs/adapter 4.19.0 → 4.19.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/.git-hooks/commit-msg +26 -5
- package/.pre-commit-config.yaml +25 -0
- package/index-dev.js +957 -227
- package/index.js +957 -227
- package/job-execution/spec/ComputeJobExecutor.spec.d.ts +1 -0
- package/job-execution/spec/JesJobExecutor.spec.d.ts +1 -0
- package/job-execution/spec/Sas9JobExecutor.spec.d.ts +1 -0
- package/job-execution/spec/SasjsJobExecutor.spec.d.ts +1 -0
- package/job-execution/spec/WebJobExecutor.debug.spec.d.ts +1 -0
- package/job-execution/spec/WebJobExecutor.spec.d.ts +1 -0
- package/minified_sas9.js +940 -2289
- package/node/index.js +1122 -262
- package/node/request/RequestClient.d.ts +1 -1
- package/node/utils/extractWeboutBlob.d.ts +13 -0
- package/node/utils/index.d.ts +1 -0
- package/node/utils/parseViyaLogDebugResponse.d.ts +4 -6
- package/package.json +2 -2
- package/request/RequestClient.d.ts +1 -1
- package/src/job-execution/WebJobExecutor.ts +19 -15
- package/src/utils/extractWeboutBlob.ts +36 -0
- package/src/utils/index.ts +1 -0
- package/src/utils/parseViyaDebugResponse.ts +16 -5
- package/src/utils/parseViyaLogDebugResponse.ts +8 -18
- package/utils/extractWeboutBlob.d.ts +13 -0
- package/utils/index.d.ts +1 -0
- package/utils/parseViyaLogDebugResponse.d.ts +4 -6
|
@@ -104,7 +104,7 @@ export declare class RequestClient implements HttpClient {
|
|
|
104
104
|
* @param successCallBack - function that should be triggered on every HTTP response with the status 2**.
|
|
105
105
|
* @param errorCallBack - function that should be triggered on every HTTP response with the status different from 2**.
|
|
106
106
|
*/
|
|
107
|
-
enableVerboseMode: (successCallBack?: (response: AxiosResponse) => AxiosResponse<any, any, {}>, errorCallBack?: (error: AxiosError) => AxiosError<unknown, any>) => void;
|
|
107
|
+
enableVerboseMode: (successCallBack?: (response: AxiosResponse) => AxiosResponse<any, any, {}, any>, errorCallBack?: (error: AxiosError) => AxiosError<unknown, any, any>) => void;
|
|
108
108
|
/**
|
|
109
109
|
* Turns off verbose mode to log every HTTP response.
|
|
110
110
|
*/
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* True when the response inlines the webout in a script-constructed Blob,
|
|
3
|
+
* which is the shape the compute task debug path returns. The iframe file URL
|
|
4
|
+
* path does not, so callers use this to pick the matching parser.
|
|
5
|
+
*/
|
|
6
|
+
export declare const hasWeboutBlob: (response: string) => boolean;
|
|
7
|
+
/**
|
|
8
|
+
* Extracts and parses the webout JSON from a JES web app debug response that
|
|
9
|
+
* inlines it via a script-constructed Blob - see blobPattern for the shapes
|
|
10
|
+
* handled. Returns null (rather than throwing) if no such blob is present, so
|
|
11
|
+
* callers can fall back to another extraction strategy first.
|
|
12
|
+
*/
|
|
13
|
+
export declare const extractWeboutBlob: (response: string) => object | null;
|
package/node/utils/index.d.ts
CHANGED
|
@@ -4,6 +4,7 @@ export * from './compareTimestamps';
|
|
|
4
4
|
export * from './convertToCsv';
|
|
5
5
|
export * from './createAxiosInstance';
|
|
6
6
|
export * from './delay';
|
|
7
|
+
export * from './extractWeboutBlob';
|
|
7
8
|
export * from './fetchLogByChunks';
|
|
8
9
|
export * from './getValidJson';
|
|
9
10
|
export * from './isNode';
|
|
@@ -1,10 +1,8 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* When querying a Viya job using the Web approach with _DEBUG=128 (used when
|
|
3
|
-
* runAsTask is true), the webout JSON is inlined into the response via
|
|
4
|
-
*
|
|
5
|
-
*
|
|
6
|
-
*
|
|
7
|
-
* var blob = new Blob([`>>weboutBEGIN<<\n{...}\n>>weboutEND<<\n`], {type: 'text/plain'});
|
|
8
|
-
* No follow-up request is needed — extract and parse the JSON directly.
|
|
3
|
+
* runAsTask is true), the webout JSON is inlined into the response via a
|
|
4
|
+
* script-constructed Blob - see extractWeboutBlob for the exact shapes
|
|
5
|
+
* handled. No follow-up request is needed — extract and parse the JSON
|
|
6
|
+
* directly.
|
|
9
7
|
*/
|
|
10
8
|
export declare const parseSasViyaLogDebugResponse: (response: any) => Promise<any>;
|
package/package.json
CHANGED
|
@@ -93,11 +93,11 @@
|
|
|
93
93
|
"main": "index.js",
|
|
94
94
|
"dependencies": {
|
|
95
95
|
"@sasjs/utils": "^3.6.0",
|
|
96
|
-
"axios": "1.
|
|
96
|
+
"axios": "1.20.0",
|
|
97
97
|
"axios-cookiejar-support": "5.0.5",
|
|
98
98
|
"form-data": "4.0.6",
|
|
99
99
|
"https": "1.0.0",
|
|
100
100
|
"tough-cookie": "4.1.3"
|
|
101
101
|
},
|
|
102
|
-
"version": "4.19.
|
|
102
|
+
"version": "4.19.1"
|
|
103
103
|
}
|
|
@@ -104,7 +104,7 @@ export declare class RequestClient implements HttpClient {
|
|
|
104
104
|
* @param successCallBack - function that should be triggered on every HTTP response with the status 2**.
|
|
105
105
|
* @param errorCallBack - function that should be triggered on every HTTP response with the status different from 2**.
|
|
106
106
|
*/
|
|
107
|
-
enableVerboseMode: (successCallBack?: (response: AxiosResponse) => AxiosResponse<any, any, {}>, errorCallBack?: (error: AxiosError) => AxiosError<unknown, any>) => void;
|
|
107
|
+
enableVerboseMode: (successCallBack?: (response: AxiosResponse) => AxiosResponse<any, any, {}, any>, errorCallBack?: (error: AxiosError) => AxiosError<unknown, any, any>) => void;
|
|
108
108
|
/**
|
|
109
109
|
* Turns off verbose mode to log every HTTP response.
|
|
110
110
|
*/
|
|
@@ -20,6 +20,7 @@ import {
|
|
|
20
20
|
appendExtraResponseAttributes,
|
|
21
21
|
parseWeboutResponse,
|
|
22
22
|
getFormData,
|
|
23
|
+
hasWeboutBlob,
|
|
23
24
|
isNode
|
|
24
25
|
} from '../utils'
|
|
25
26
|
import { BaseJobExecutor } from './JobExecutor'
|
|
@@ -59,7 +60,7 @@ export class WebJobExecutor extends BaseJobExecutor {
|
|
|
59
60
|
if (config.serverType === ServerType.SasViya) {
|
|
60
61
|
let jobUri
|
|
61
62
|
try {
|
|
62
|
-
jobUri = await this.getJobUri(
|
|
63
|
+
jobUri = await this.getJobUri(program)
|
|
63
64
|
} catch (e: any) {
|
|
64
65
|
return new Promise(async (resolve, reject) => {
|
|
65
66
|
if (e instanceof LoginRequiredError) {
|
|
@@ -88,8 +89,6 @@ export class WebJobExecutor extends BaseJobExecutor {
|
|
|
88
89
|
})
|
|
89
90
|
}
|
|
90
91
|
|
|
91
|
-
apiUrl += jobUri.length > 0 ? '&_job=' + jobUri : ''
|
|
92
|
-
|
|
93
92
|
if (jobUri.length > 0) {
|
|
94
93
|
apiUrl += '&_job=' + jobUri
|
|
95
94
|
/**
|
|
@@ -205,8 +204,17 @@ export class WebJobExecutor extends BaseJobExecutor {
|
|
|
205
204
|
if (config.debug) {
|
|
206
205
|
switch (this.serverType) {
|
|
207
206
|
case ServerType.SasViya:
|
|
207
|
+
// Route on the shape of the response itself. The JES web app
|
|
208
|
+
// returns the webout inline in a script-constructed Blob when
|
|
209
|
+
// it runs the job as a compute task, and as an iframe file URL
|
|
210
|
+
// otherwise - but the _debug value sent does not determine
|
|
211
|
+
// which: a _debug=128 request without _EXECUTIONTASKS gets the
|
|
212
|
+
// iframe form back. A result that is already an object has
|
|
213
|
+
// been parsed upstream, and parseSasViyaDebugResponse also
|
|
214
|
+
// falls back to blob extraction, so either parser copes with
|
|
215
|
+
// a response that mixes the two.
|
|
208
216
|
jsonResponse =
|
|
209
|
-
|
|
217
|
+
typeof res.result !== 'string' || hasWeboutBlob(res.result)
|
|
210
218
|
? await parseSasViyaLogDebugResponse(res.result)
|
|
211
219
|
: await parseSasViyaDebugResponse(
|
|
212
220
|
res.result,
|
|
@@ -292,17 +300,13 @@ export class WebJobExecutor extends BaseJobExecutor {
|
|
|
292
300
|
if (!this.sasViyaApiClient) return ''
|
|
293
301
|
let uri = ''
|
|
294
302
|
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
const folderPathParts = sasJob.split('/')
|
|
303
|
-
jobName = folderPathParts.pop() || ''
|
|
304
|
-
folderPath = folderPathParts.join('/')
|
|
305
|
-
}
|
|
303
|
+
// sasJob arrives with the appLoc already applied, so the folder is
|
|
304
|
+
// everything before the last segment. Reading the first two segments only
|
|
305
|
+
// would look up folder 'services' and job 'common' for a job like
|
|
306
|
+
// services/common/configure.
|
|
307
|
+
const folderPathParts = sasJob.split('/')
|
|
308
|
+
const jobName = folderPathParts.pop() || ''
|
|
309
|
+
const folderPath = folderPathParts.join('/')
|
|
306
310
|
|
|
307
311
|
if (!jobName) {
|
|
308
312
|
throw new Error('Job name is empty, null or undefined.')
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import { getValidJson } from './getValidJson'
|
|
2
|
+
import { parseWeboutResponse } from './parseWeboutResponse'
|
|
3
|
+
|
|
4
|
+
// Matches the script-constructed Blob that the JES web app uses to inline the
|
|
5
|
+
// webout: `new Blob([`{...}`], {type: 'application/json'})`. The type is
|
|
6
|
+
// text/plain on abort and error paths, where the JSON is wrapped in
|
|
7
|
+
// weboutBEGIN/END markers. Quote style and whitespace vary between Viya
|
|
8
|
+
// releases, so both are tolerated here rather than in a second pattern.
|
|
9
|
+
const blobPattern =
|
|
10
|
+
/new Blob\(\[`([\s\S]*?)`\],\s*\{\s*type:\s*['"](?:application\/json|text\/plain)['"]\s*\}/
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* True when the response inlines the webout in a script-constructed Blob,
|
|
14
|
+
* which is the shape the compute task debug path returns. The iframe file URL
|
|
15
|
+
* path does not, so callers use this to pick the matching parser.
|
|
16
|
+
*/
|
|
17
|
+
export const hasWeboutBlob = (response: string): boolean =>
|
|
18
|
+
blobPattern.test(response)
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* Extracts and parses the webout JSON from a JES web app debug response that
|
|
22
|
+
* inlines it via a script-constructed Blob - see blobPattern for the shapes
|
|
23
|
+
* handled. Returns null (rather than throwing) if no such blob is present, so
|
|
24
|
+
* callers can fall back to another extraction strategy first.
|
|
25
|
+
*/
|
|
26
|
+
export const extractWeboutBlob = (response: string): object | null => {
|
|
27
|
+
const blobMatch = response.match(blobPattern)
|
|
28
|
+
if (!blobMatch) return null
|
|
29
|
+
|
|
30
|
+
const blobContent = blobMatch[1]
|
|
31
|
+
const stripped = blobContent.includes('>>weboutBEGIN<<')
|
|
32
|
+
? parseWeboutResponse(blobContent)
|
|
33
|
+
: blobContent
|
|
34
|
+
|
|
35
|
+
return getValidJson(stripped)
|
|
36
|
+
}
|
package/src/utils/index.ts
CHANGED
|
@@ -4,6 +4,7 @@ export * from './compareTimestamps'
|
|
|
4
4
|
export * from './convertToCsv'
|
|
5
5
|
export * from './createAxiosInstance'
|
|
6
6
|
export * from './delay'
|
|
7
|
+
export * from './extractWeboutBlob'
|
|
7
8
|
export * from './fetchLogByChunks'
|
|
8
9
|
export * from './getValidJson'
|
|
9
10
|
export * from './isNode'
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { RequestClient } from '../request/RequestClient'
|
|
2
2
|
import { getValidJson } from '../utils'
|
|
3
|
+
import { extractWeboutBlob } from './extractWeboutBlob'
|
|
3
4
|
|
|
4
5
|
/**
|
|
5
6
|
* When querying a Viya job using the Web approach (as opposed to using the APIs) with _DEBUG enabled,
|
|
@@ -25,11 +26,21 @@ export const parseSasViyaDebugResponse = async (
|
|
|
25
26
|
const jsonUrl = iframeStart
|
|
26
27
|
? iframeStart.split(/"><\/iframe>|><\/iframe>/)[0]
|
|
27
28
|
: null
|
|
28
|
-
|
|
29
|
-
|
|
29
|
+
|
|
30
|
+
if (jsonUrl) {
|
|
31
|
+
return requestClient
|
|
32
|
+
.get(serverUrl + jsonUrl, undefined, 'text/plain')
|
|
33
|
+
.then((res: any) => getValidJson(res.result))
|
|
30
34
|
}
|
|
31
35
|
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
36
|
+
// Fallback: some Viya configurations inline the webout via a
|
|
37
|
+
// script-constructed Blob instead of an iframe src URL, e.g. when the
|
|
38
|
+
// _debug=128 format is served on a path expecting the older _debug=131
|
|
39
|
+
// iframe-URL format.
|
|
40
|
+
const blobResult = extractWeboutBlob(response)
|
|
41
|
+
if (blobResult !== null) return blobResult
|
|
42
|
+
|
|
43
|
+
throw new Error(
|
|
44
|
+
'Unable to find webout content - no iframe URL and no inline blob.'
|
|
45
|
+
)
|
|
35
46
|
}
|
|
@@ -1,14 +1,11 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { parseWeboutResponse } from './parseWeboutResponse'
|
|
1
|
+
import { extractWeboutBlob } from './extractWeboutBlob'
|
|
3
2
|
|
|
4
3
|
/**
|
|
5
4
|
* When querying a Viya job using the Web approach with _DEBUG=128 (used when
|
|
6
|
-
* runAsTask is true), the webout JSON is inlined into the response via
|
|
7
|
-
*
|
|
8
|
-
*
|
|
9
|
-
*
|
|
10
|
-
* var blob = new Blob([`>>weboutBEGIN<<\n{...}\n>>weboutEND<<\n`], {type: 'text/plain'});
|
|
11
|
-
* No follow-up request is needed — extract and parse the JSON directly.
|
|
5
|
+
* runAsTask is true), the webout JSON is inlined into the response via a
|
|
6
|
+
* script-constructed Blob - see extractWeboutBlob for the exact shapes
|
|
7
|
+
* handled. No follow-up request is needed — extract and parse the JSON
|
|
8
|
+
* directly.
|
|
12
9
|
*/
|
|
13
10
|
export const parseSasViyaLogDebugResponse = async (response: any) => {
|
|
14
11
|
// If upstream already parsed the response as JSON (object), pass through.
|
|
@@ -16,17 +13,10 @@ export const parseSasViyaLogDebugResponse = async (response: any) => {
|
|
|
16
13
|
return response
|
|
17
14
|
}
|
|
18
15
|
|
|
19
|
-
const
|
|
20
|
-
|
|
21
|
-
)
|
|
22
|
-
if (!blobMatch) {
|
|
16
|
+
const result = extractWeboutBlob(response)
|
|
17
|
+
if (result === null) {
|
|
23
18
|
throw new Error('Unable to find webout blob in debug log response.')
|
|
24
19
|
}
|
|
25
20
|
|
|
26
|
-
|
|
27
|
-
const stripped = blobContent.includes('>>weboutBEGIN<<')
|
|
28
|
-
? parseWeboutResponse(blobContent)
|
|
29
|
-
: blobContent
|
|
30
|
-
|
|
31
|
-
return getValidJson(stripped)
|
|
21
|
+
return result
|
|
32
22
|
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* True when the response inlines the webout in a script-constructed Blob,
|
|
3
|
+
* which is the shape the compute task debug path returns. The iframe file URL
|
|
4
|
+
* path does not, so callers use this to pick the matching parser.
|
|
5
|
+
*/
|
|
6
|
+
export declare const hasWeboutBlob: (response: string) => boolean;
|
|
7
|
+
/**
|
|
8
|
+
* Extracts and parses the webout JSON from a JES web app debug response that
|
|
9
|
+
* inlines it via a script-constructed Blob - see blobPattern for the shapes
|
|
10
|
+
* handled. Returns null (rather than throwing) if no such blob is present, so
|
|
11
|
+
* callers can fall back to another extraction strategy first.
|
|
12
|
+
*/
|
|
13
|
+
export declare const extractWeboutBlob: (response: string) => object | null;
|
package/utils/index.d.ts
CHANGED
|
@@ -4,6 +4,7 @@ export * from './compareTimestamps';
|
|
|
4
4
|
export * from './convertToCsv';
|
|
5
5
|
export * from './createAxiosInstance';
|
|
6
6
|
export * from './delay';
|
|
7
|
+
export * from './extractWeboutBlob';
|
|
7
8
|
export * from './fetchLogByChunks';
|
|
8
9
|
export * from './getValidJson';
|
|
9
10
|
export * from './isNode';
|
|
@@ -1,10 +1,8 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* When querying a Viya job using the Web approach with _DEBUG=128 (used when
|
|
3
|
-
* runAsTask is true), the webout JSON is inlined into the response via
|
|
4
|
-
*
|
|
5
|
-
*
|
|
6
|
-
*
|
|
7
|
-
* var blob = new Blob([`>>weboutBEGIN<<\n{...}\n>>weboutEND<<\n`], {type: 'text/plain'});
|
|
8
|
-
* No follow-up request is needed — extract and parse the JSON directly.
|
|
3
|
+
* runAsTask is true), the webout JSON is inlined into the response via a
|
|
4
|
+
* script-constructed Blob - see extractWeboutBlob for the exact shapes
|
|
5
|
+
* handled. No follow-up request is needed — extract and parse the JSON
|
|
6
|
+
* directly.
|
|
9
7
|
*/
|
|
10
8
|
export declare const parseSasViyaLogDebugResponse: (response: any) => Promise<any>;
|