1
0
mirror of https://github.com/sasjs/adapter.git synced 2026-01-16 08:30:07 +00:00

Merge branch 'master' into releaseScript

This commit is contained in:
Yury Shkoda
2021-02-06 09:31:21 +03:00
committed by GitHub
35 changed files with 1118 additions and 3071 deletions

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

3772
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@@ -37,30 +37,31 @@
"license": "ISC", "license": "ISC",
"devDependencies": { "devDependencies": {
"@types/isomorphic-fetch": "0.0.35", "@types/isomorphic-fetch": "0.0.35",
"@types/jest": "^26.0.15", "@types/jest": "^26.0.20",
"cp": "^0.2.0", "cp": "^0.2.0",
"dotenv": "^8.2.0", "dotenv": "^8.2.0",
"jest": "^25.5.4", "jest": "^25.5.4",
"path": "^0.12.7", "path": "^0.12.7",
"rimraf": "^3.0.2", "rimraf": "^3.0.2",
"semantic-release": "^17.3.0", "semantic-release": "^17.3.1",
"terser-webpack-plugin": "^4.2.3", "terser-webpack-plugin": "^4.2.3",
"ts-jest": "^25.5.1", "ts-jest": "^25.5.1",
"ts-loader": "^8.0.11", "ts-loader": "^8.0.14",
"tslint": "^6.1.3", "tslint": "^6.1.3",
"tslint-config-prettier": "^1.18.0", "tslint-config-prettier": "^1.18.0",
"typedoc": "^0.17.8", "typedoc": "^0.19.2",
"typedoc-neo-theme": "^1.0.10", "typedoc-neo-theme": "^1.0.10",
"typedoc-plugin-external-module-name": "^4.0.3", "typedoc-plugin-external-module-name": "^4.0.6",
"typescript": "^3.9.7", "typescript": "^3.9.7",
"webpack": "^4.44.2", "webpack": "^5.13.0",
"webpack-cli": "^4.2.0" "webpack-cli": "^4.3.1"
}, },
"main": "index.js", "main": "index.js",
"dependencies": { "dependencies": {
"@sasjs/utils": "^1.5.0", "@sasjs/utils": "^2.0.2",
"es6-promise": "^4.2.8", "es6-promise": "^4.2.8",
"form-data": "^3.0.0", "form-data": "^3.0.0",
"https": "^1.0.0",
"isomorphic-fetch": "^2.2.1" "isomorphic-fetch": "^2.2.1"
} }
} }

View File

@@ -701,11 +701,13 @@ export class SASViyaApiClient {
* @param clientId - the client ID to authenticate with. * @param clientId - the client ID to authenticate with.
* @param clientSecret - the client secret to authenticate with. * @param clientSecret - the client secret to authenticate with.
* @param authCode - the auth code received from the server. * @param authCode - the auth code received from the server.
* @param insecure - this boolean tells adapter to ignore SSL errors. [Not Recommended]
*/ */
public async getAccessToken( public async getAccessToken(
clientId: string, clientId: string,
clientSecret: string, clientSecret: string,
authCode: string authCode: string,
insecure: boolean = false
) { ) {
const url = this.serverUrl + '/SASLogon/oauth/token' const url = this.serverUrl + '/SASLogon/oauth/token'
let token let token
@@ -729,12 +731,23 @@ export class SASViyaApiClient {
formData.append('code', authCode) formData.append('code', authCode)
} }
let moreOptions = {}
if (insecure) {
const https = require('https')
moreOptions = {
agent: new https.Agent({
rejectUnauthorized: false
})
}
}
const authResponse = await fetch(url, { const authResponse = await fetch(url, {
method: 'POST', method: 'POST',
credentials: 'include', credentials: 'include',
headers, headers,
body: formData as any, body: formData as any,
referrerPolicy: 'same-origin' referrerPolicy: 'same-origin',
...moreOptions
}).then((res) => res.json()) }).then((res) => res.json())
return authResponse return authResponse
@@ -833,23 +846,20 @@ export class SASViyaApiClient {
) )
} }
if (isRelativePath(sasJob)) { const folderPathParts = sasJob.split('/')
const folderName = sasJob.split('/')[0] const jobName = folderPathParts.pop()
await this.populateFolderMap( const folderPath = folderPathParts.join('/')
`${this.rootFolderName}/${folderName}`, const fullFolderPath = isRelativePath(sasJob)
accessToken ? `${this.rootFolderName}/${folderPath}`
) : folderPath
if (!this.folderMap.get(`${this.rootFolderName}/${folderName}`)) { await this.populateFolderMap(fullFolderPath, accessToken)
throw new Error(
`The folder '${folderName}' was not found at '${this.serverUrl}/${this.rootFolderName}'` const jobFolder = this.folderMap.get(fullFolderPath)
) if (!jobFolder) {
} throw new Error(
} else { `The folder '${fullFolderPath}' was not found on '${this.serverUrl}'`
const folderPathParts = sasJob.split('/') )
folderPathParts.pop()
const folderPath = folderPathParts.join('/')
await this.populateFolderMap(folderPath, accessToken)
} }
const headers: any = { 'Content-Type': 'application/json' } const headers: any = { 'Content-Type': 'application/json' }
@@ -857,21 +867,7 @@ export class SASViyaApiClient {
headers.Authorization = `Bearer ${accessToken}` headers.Authorization = `Bearer ${accessToken}`
} }
let jobToExecute const jobToExecute = jobFolder?.find((item) => item.name === jobName)
if (isRelativePath(sasJob)) {
const folderName = sasJob.split('/')[0]
const jobName = sasJob.split('/')[1]
const jobFolder = this.folderMap.get(
`${this.rootFolderName}/${folderName}`
)
jobToExecute = jobFolder?.find((item) => item.name === jobName)
} else {
const folderPathParts = sasJob.split('/')
const jobName = folderPathParts.pop()
const folderPath = folderPathParts.join('/')
const jobFolder = this.folderMap.get(folderPath)
jobToExecute = jobFolder?.find((item) => item.name === jobName)
}
if (!jobToExecute) { if (!jobToExecute) {
throw new Error(`Job was not found.`) throw new Error(`Job was not found.`)
@@ -937,52 +933,28 @@ export class SASViyaApiClient {
) )
} }
if (isRelativePath(sasJob)) { const folderPathParts = sasJob.split('/')
const folderName = sasJob.split('/')[0] const jobName = folderPathParts.pop()
await this.populateFolderMap( const folderPath = folderPathParts.join('/')
`${this.rootFolderName}/${folderName}`, const fullFolderPath = isRelativePath(sasJob)
accessToken ? `${this.rootFolderName}/${folderPath}`
) : folderPath
await this.populateFolderMap(fullFolderPath, accessToken)
if (!this.folderMap.get(`${this.rootFolderName}/${folderName}`)) { const jobFolder = this.folderMap.get(fullFolderPath)
throw new Error( if (!jobFolder) {
`The folder '${folderName}' was not found at '${this.serverUrl}/${this.rootFolderName}'.` throw new Error(
) `The folder '${fullFolderPath}' was not found on '${this.serverUrl}'.`
} )
} else {
const folderPathParts = sasJob.split('/')
folderPathParts.pop()
const folderPath = folderPathParts.join('/')
await this.populateFolderMap(folderPath, accessToken)
if (!this.folderMap.get(folderPath)) {
throw new Error(
`The folder '${folderPath}' was not found at '${this.serverUrl}'.`
)
}
} }
const jobToExecute = jobFolder?.find((item) => item.name === jobName)
let files: any[] = [] let files: any[] = []
if (data && Object.keys(data).length) { if (data && Object.keys(data).length) {
files = await this.uploadTables(data, accessToken) files = await this.uploadTables(data, accessToken)
} }
let jobToExecute: Job | undefined
let jobName: string | undefined
let jobPath: string | undefined
if (isRelativePath(sasJob)) {
const folderName = sasJob.split('/')[0]
jobName = sasJob.split('/')[1]
jobPath = `${this.rootFolderName}/${folderName}`
const jobFolder = this.folderMap.get(jobPath)
jobToExecute = jobFolder?.find((item) => item.name === jobName)
} else {
const folderPathParts = sasJob.split('/')
jobName = folderPathParts.pop()
jobPath = folderPathParts.join('/')
const jobFolder = this.folderMap.get(jobPath)
jobToExecute = jobFolder?.find((item) => item.name === jobName)
}
if (!jobToExecute) { if (!jobToExecute) {
throw new Error(`Job was not found.`) throw new Error(`Job was not found.`)
} }
@@ -1007,7 +979,7 @@ export class SASViyaApiClient {
const jobArguments: { [key: string]: any } = { const jobArguments: { [key: string]: any } = {
_contextName: contextName, _contextName: contextName,
_program: `${jobPath}/${jobName}`, _program: `${fullFolderPath}/${jobName}`,
_webin_file_count: files.length, _webin_file_count: files.length,
_OMITJSONLISTING: true, _OMITJSONLISTING: true,
_OMITJSONLOG: true, _OMITJSONLOG: true,
@@ -1148,6 +1120,8 @@ export class SASViyaApiClient {
} }
return new Promise(async (resolve, _) => { return new Promise(async (resolve, _) => {
let printedState = ''
const interval = setInterval(async () => { const interval = setInterval(async () => {
if ( if (
postedJobState === 'running' || postedJobState === 'running' ||
@@ -1155,9 +1129,6 @@ export class SASViyaApiClient {
postedJobState === 'pending' postedJobState === 'pending'
) { ) {
if (stateLink) { if (stateLink) {
if (this.debug) {
console.log('Polling job status... \n')
}
const { result: jobState } = await this.request<string>( const { result: jobState } = await this.request<string>(
`${this.serverUrl}${stateLink.href}?_action=wait&wait=30`, `${this.serverUrl}${stateLink.href}?_action=wait&wait=30`,
{ {
@@ -1167,10 +1138,16 @@ export class SASViyaApiClient {
) )
postedJobState = jobState.trim() postedJobState = jobState.trim()
if (this.debug) {
console.log(`Current state: ${postedJobState}\n`) if (this.debug && printedState !== postedJobState) {
console.log('Polling job status...')
console.log(`Current job state: ${postedJobState}`)
printedState = postedJobState
} }
pollCount++ pollCount++
if (pollCount >= MAX_POLL_COUNT) { if (pollCount >= MAX_POLL_COUNT) {
resolve(postedJobState) resolve(postedJobState)
} }

View File

@@ -386,17 +386,26 @@ export default class SASjs {
return await this.sasViyaApiClient!.getAuthCode(clientId) return await this.sasViyaApiClient!.getAuthCode(clientId)
} }
/**
* Exchanges the auth code for an access token for the given client.
* @param clientId - the client ID to authenticate with.
* @param clientSecret - the client secret to authenticate with.
* @param authCode - the auth code received from the server.
* @param insecure - this boolean tells adapter to ignore SSL errors. [Not Recommended]
*/
public async getAccessToken( public async getAccessToken(
clientId: string, clientId: string,
clientSecret: string, clientSecret: string,
authCode: string authCode: string,
insecure: boolean = false
) { ) {
this.isMethodSupported('getAccessToken', ServerType.SASViya) this.isMethodSupported('getAccessToken', ServerType.SASViya)
return await this.sasViyaApiClient!.getAccessToken( return await this.sasViyaApiClient!.getAccessToken(
clientId, clientId,
clientSecret, clientSecret,
authCode authCode,
insecure
) )
} }
@@ -747,10 +756,7 @@ export default class SASjs {
) )
} }
const members = const members = serviceJson.members
serviceJson.members[0].name === 'services'
? serviceJson.members[0].members
: serviceJson.members
await this.createFoldersAndServices( await this.createFoldersAndServices(
appLoc, appLoc,

View File

@@ -23,6 +23,10 @@ export class SessionManager {
private currentContext: Context | null = null private currentContext: Context | null = null
private csrfToken: CsrfToken | null = null private csrfToken: CsrfToken | null = null
private _debug: boolean = false private _debug: boolean = false
private printedSessionState = {
printed: false,
state: ''
}
public get debug() { public get debug() {
return this._debug return this._debug
@@ -175,8 +179,10 @@ export class SessionManager {
sessionState === '' sessionState === ''
) { ) {
if (stateLink) { if (stateLink) {
if (this.debug) { if (this.debug && !this.printedSessionState.printed) {
console.log('Polling session status... \n') console.log('Polling session status...')
this.printedSessionState.printed = true
} }
const { result: state } = await this.requestSessionStatus<string>( const { result: state } = await this.requestSessionStatus<string>(
@@ -191,8 +197,11 @@ export class SessionManager {
sessionState = state.trim() sessionState = state.trim()
if (this.debug) { if (this.debug && this.printedSessionState.state !== sessionState) {
console.log(`Current state is '${sessionState}'\n`) console.log(`Current session state is '${sessionState}'`)
this.printedSessionState.state = sessionState
this.printedSessionState.printed = false
} }
// There is an internal error present in SAS Viya 3.5 // There is an internal error present in SAS Viya 3.5

View File

@@ -26,7 +26,8 @@ const browserConfig = {
] ]
}, },
resolve: { resolve: {
extensions: ['.ts', '.js'] extensions: ['.ts', '.js'],
fallback: { https: false }
}, },
output: { output: {
filename: 'index.js', filename: 'index.js',