@sasjs/adapter 4.9.0 → 4.9.2

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.
@@ -1,5 +1,5 @@
1
1
  /// <reference types="node" />
2
- import { AxiosInstance, AxiosResponse } from 'axios';
2
+ import { AxiosError, AxiosInstance, AxiosResponse } from 'axios';
3
3
  import * as https from 'https';
4
4
  import { CsrfToken } from '..';
5
5
  import { SASjsRequest, HttpClient, VerboseMode } from '../types';
@@ -90,7 +90,7 @@ export declare class RequestClient implements HttpClient {
90
90
  * @param successCallBack - function that should be triggered on every HTTP response with the status 2**.
91
91
  * @param errorCallBack - function that should be triggered on every HTTP response with the status different from 2**.
92
92
  */
93
- enableVerboseMode: (successCallBack?: (response: AxiosResponse) => AxiosResponse<any, any>, errorCallBack?: (response: AxiosResponse) => AxiosResponse<any, any>) => void;
93
+ enableVerboseMode: (successCallBack?: (axiosResponse: AxiosResponse | AxiosError) => AxiosResponse<any, any> | AxiosError<unknown, any>, errorCallBack?: (axiosResponse: AxiosResponse | AxiosError) => AxiosResponse<any, any> | AxiosError<unknown, any>) => void;
94
94
  /**
95
95
  * Turns off verbose mode to log every HTTP response.
96
96
  */
package/package.json CHANGED
@@ -84,5 +84,5 @@
84
84
  "https": "1.0.0",
85
85
  "tough-cookie": "4.1.3"
86
86
  },
87
- "version": "4.9.0"
87
+ "version": "4.9.2"
88
88
  }
@@ -1,5 +1,5 @@
1
1
  /// <reference types="node" />
2
- import { AxiosInstance, AxiosResponse } from 'axios';
2
+ import { AxiosError, AxiosInstance, AxiosResponse } from 'axios';
3
3
  import * as https from 'https';
4
4
  import { CsrfToken } from '..';
5
5
  import { SASjsRequest, HttpClient, VerboseMode } from '../types';
@@ -90,7 +90,7 @@ export declare class RequestClient implements HttpClient {
90
90
  * @param successCallBack - function that should be triggered on every HTTP response with the status 2**.
91
91
  * @param errorCallBack - function that should be triggered on every HTTP response with the status different from 2**.
92
92
  */
93
- enableVerboseMode: (successCallBack?: (response: AxiosResponse) => AxiosResponse<any, any>, errorCallBack?: (response: AxiosResponse) => AxiosResponse<any, any>) => void;
93
+ enableVerboseMode: (successCallBack?: (axiosResponse: AxiosResponse | AxiosError) => AxiosResponse<any, any> | AxiosError<unknown, any>, errorCallBack?: (axiosResponse: AxiosResponse | AxiosError) => AxiosResponse<any, any> | AxiosError<unknown, any>) => void;
94
94
  /**
95
95
  * Turns off verbose mode to log every HTTP response.
96
96
  */
@@ -25,7 +25,7 @@ import { prefixMessage } from '@sasjs/utils/error'
25
25
  import { pollJobState } from './api/viya/pollJobState'
26
26
  import { getTokens } from './auth/getTokens'
27
27
  import { uploadTables } from './api/viya/uploadTables'
28
- import { executeScript } from './api/viya/executeScript'
28
+ import { executeOnComputeApi } from './api/viya/executeOnComputeApi'
29
29
  import { getAccessTokenForViya } from './auth/getAccessTokenForViya'
30
30
  import { refreshTokensForViya } from './auth/refreshTokensForViya'
31
31
 
@@ -293,7 +293,7 @@ export class SASViyaApiClient {
293
293
  printPid = false,
294
294
  variables?: MacroVar
295
295
  ): Promise<any> {
296
- return executeScript(
296
+ return executeOnComputeApi(
297
297
  this.requestClient,
298
298
  this.sessionManager,
299
299
  this.rootFolderName,
package/src/SASjs.ts CHANGED
@@ -34,7 +34,7 @@ import {
34
34
  Sas9JobExecutor,
35
35
  FileUploader
36
36
  } from './job-execution'
37
- import { AxiosResponse } from 'axios'
37
+ import { AxiosResponse, AxiosError } from 'axios'
38
38
 
39
39
  interface ExecuteScriptParams {
40
40
  linesOfCode: string[]
@@ -1170,8 +1170,8 @@ export default class SASjs {
1170
1170
  * @param errorCallBack - function that should be triggered on every HTTP response with the status different from 2**.
1171
1171
  */
1172
1172
  public enableVerboseMode(
1173
- successCallBack?: (response: AxiosResponse) => AxiosResponse,
1174
- errorCallBack?: (response: AxiosResponse) => AxiosResponse
1173
+ successCallBack?: (response: AxiosResponse | AxiosError) => AxiosResponse,
1174
+ errorCallBack?: (response: AxiosResponse | AxiosError) => AxiosResponse
1175
1175
  ) {
1176
1176
  this.requestClient?.enableVerboseMode(successCallBack, errorCallBack)
1177
1177
  }
@@ -15,8 +15,12 @@ import { formatDataForRequest } from '../../utils/formatDataForRequest'
15
15
  import { pollJobState, JobState } from './pollJobState'
16
16
  import { uploadTables } from './uploadTables'
17
17
 
18
+ interface JobRequestBody {
19
+ [key: string]: number | string | string[]
20
+ }
21
+
18
22
  /**
19
- * Executes code on the current SAS Viya server.
23
+ * Executes SAS program on the current SAS Viya server using Compute API.
20
24
  * @param jobPath - the path to the file being submitted for execution.
21
25
  * @param linesOfCode - an array of code lines to execute.
22
26
  * @param contextName - the context to execute the code in.
@@ -29,7 +33,7 @@ import { uploadTables } from './uploadTables'
29
33
  * @param printPid - a boolean that indicates whether the function should print (PID) of the started job.
30
34
  * @param variables - an object that represents macro variables.
31
35
  */
32
- export async function executeScript(
36
+ export async function executeOnComputeApi(
33
37
  requestClient: RequestClient,
34
38
  sessionManager: SessionManager,
35
39
  rootFolderName: string,
@@ -46,6 +50,7 @@ export async function executeScript(
46
50
  variables?: MacroVar
47
51
  ): Promise<any> {
48
52
  let access_token = (authConfig || {}).access_token
53
+
49
54
  if (authConfig) {
50
55
  ;({ access_token } = await getTokens(requestClient, authConfig))
51
56
  }
@@ -78,27 +83,13 @@ export async function executeScript(
78
83
  const logger = process.logger || console
79
84
 
80
85
  logger.info(
81
- `Triggered '${relativeJobPath}' with PID ${
86
+ `Triggering '${relativeJobPath}' with PID ${
82
87
  jobIdVariable.value
83
88
  } at ${timestampToYYYYMMDDHHMMSS()}`
84
89
  )
85
90
  }
86
91
  }
87
92
 
88
- const jobArguments: { [key: string]: any } = {
89
- _contextName: contextName,
90
- _OMITJSONLISTING: true,
91
- _OMITJSONLOG: true,
92
- _OMITSESSIONRESULTS: true,
93
- _OMITTEXTLISTING: true,
94
- _OMITTEXTLOG: true
95
- }
96
-
97
- if (debug) {
98
- jobArguments['_OMITTEXTLOG'] = false
99
- jobArguments['_OMITSESSIONRESULTS'] = false
100
- }
101
-
102
93
  let fileName
103
94
 
104
95
  if (isRelativePath(jobPath)) {
@@ -107,6 +98,7 @@ export async function executeScript(
107
98
  }`
108
99
  } else {
109
100
  const jobPathParts = jobPath.split('/')
101
+
110
102
  fileName = jobPathParts.pop()
111
103
  }
112
104
 
@@ -118,7 +110,6 @@ export async function executeScript(
118
110
  }
119
111
 
120
112
  if (variables) jobVariables = { ...jobVariables, ...variables }
121
-
122
113
  if (debug) jobVariables = { ...jobVariables, _DEBUG: 131 }
123
114
 
124
115
  let files: any[] = []
@@ -145,12 +136,12 @@ export async function executeScript(
145
136
  }
146
137
 
147
138
  // Execute job in session
148
- const jobRequestBody = {
149
- name: fileName,
139
+ const jobRequestBody: JobRequestBody = {
140
+ name: fileName || 'Default Job Name',
150
141
  description: 'Powered by SASjs',
151
142
  code: linesOfCode,
152
143
  variables: jobVariables,
153
- arguments: jobArguments
144
+ version: 2
154
145
  }
155
146
 
156
147
  const { result: postedJob, etag } = await requestClient
@@ -279,7 +270,7 @@ export async function executeScript(
279
270
  const error = e as HttpError
280
271
 
281
272
  if (error.status === 404) {
282
- return executeScript(
273
+ return executeOnComputeApi(
283
274
  requestClient,
284
275
  sessionManager,
285
276
  rootFolderName,
@@ -1,4 +1,10 @@
1
- import { AxiosInstance, AxiosRequestConfig, AxiosResponse } from 'axios'
1
+ import {
2
+ AxiosError,
3
+ AxiosInstance,
4
+ AxiosRequestConfig,
5
+ AxiosResponse
6
+ } from 'axios'
7
+ import axios from 'axios'
2
8
  import * as https from 'https'
3
9
  import { CsrfToken } from '..'
4
10
  import { isAuthorizeFormRequired, isLogInRequired } from '../auth'
@@ -65,6 +71,7 @@ export class RequestClient implements HttpClient {
65
71
  this.csrfToken = { headerName: '', value: '' }
66
72
  this.fileUploadCsrfToken = { headerName: '', value: '' }
67
73
  }
74
+
68
75
  public clearLocalStorageTokens() {
69
76
  localStorage.setItem('accessToken', '')
70
77
  localStorage.setItem('refreshToken', '')
@@ -406,10 +413,73 @@ export class RequestClient implements HttpClient {
406
413
  return bodyLines.join('\n')
407
414
  }
408
415
 
409
- private defaultInterceptionCallBack = (response: AxiosResponse) => {
410
- const { status, config, request, data: resData } = response
416
+ private defaultInterceptionCallBack = (
417
+ axiosResponse: AxiosResponse | AxiosError
418
+ ) => {
419
+ // Message indicating absent value.
420
+ const noValueMessage = 'Not provided'
421
+
422
+ // Fallback request object that can be safely used to form request summary.
423
+ type FallbackRequest = { _header?: string; res: { rawHeaders: string[] } }
424
+ // _header is not present in responses with status 1**
425
+ // rawHeaders are not present in responses with status 1**
426
+ let fallbackRequest: FallbackRequest = {
427
+ _header: `${noValueMessage}\n`,
428
+ res: { rawHeaders: [noValueMessage] }
429
+ }
430
+
431
+ // Fallback response object that can be safely used to form response summary.
432
+ type FallbackResponse = {
433
+ status?: number | string
434
+ request?: FallbackRequest
435
+ config: { data?: string }
436
+ data?: unknown
437
+ }
438
+ let fallbackResponse: FallbackResponse = axiosResponse
439
+
440
+ if (axios.isAxiosError(axiosResponse)) {
441
+ const { response, request, config } = axiosResponse
442
+
443
+ // Try to use axiosResponse.response to form response summary.
444
+ if (response) {
445
+ fallbackResponse = response
446
+ } else {
447
+ // Try to use axiosResponse.request to form request summary.
448
+ if (request) {
449
+ const { _header, _currentRequest } = request
450
+
451
+ // Try to use axiosResponse.request._header to form request summary.
452
+ if (_header) {
453
+ fallbackRequest._header = _header
454
+ }
455
+ // Try to use axiosResponse.request._currentRequest._header to form request summary.
456
+ else if (_currentRequest && _currentRequest._header) {
457
+ fallbackRequest._header = _currentRequest._header
458
+ }
459
+
460
+ const { res } = request
461
+
462
+ // Try to use axiosResponse.request.res.rawHeaders to form request summary.
463
+ if (res && res.rawHeaders) {
464
+ fallbackRequest.res.rawHeaders = res.rawHeaders
465
+ }
466
+ }
467
+
468
+ // Fallback config that can be safely used to form response summary.
469
+ const fallbackConfig = { data: noValueMessage }
470
+
471
+ fallbackResponse = {
472
+ status: noValueMessage,
473
+ request: fallbackRequest,
474
+ config: config || fallbackConfig,
475
+ data: noValueMessage
476
+ }
477
+ }
478
+ }
479
+
480
+ const { status, config, request, data: resData } = fallbackResponse
411
481
  const { data: reqData } = config
412
- const { _header: reqHeaders, res } = request
482
+ const { _header: reqHeaders, res } = request || fallbackRequest
413
483
  const { rawHeaders } = res
414
484
 
415
485
  // Converts an array of strings into a single string with the following format:
@@ -439,7 +509,7 @@ HTTP Response (first 50 lines):
439
509
  ${resHeaders}${parsedResBody ? `\n\n${parsedResBody}` : ''}
440
510
  `)
441
511
 
442
- return response
512
+ return axiosResponse
443
513
  }
444
514
 
445
515
  /**