mirror of
https://github.com/sasjs/adapter.git
synced 2026-01-07 04:20:05 +00:00
Compare commits
40 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
85a530ae5a | ||
|
|
1fc6db114d | ||
|
|
8d203b8df4 | ||
|
|
39924ff078 | ||
|
|
de25f106ec | ||
|
|
c0b82c5125 | ||
|
|
1c1b5baefe | ||
|
|
8b17aeaea2 | ||
|
|
cb0d03c965 | ||
|
|
9e77f3d64e | ||
|
|
25f61815dc | ||
|
|
3a2252e69c | ||
|
|
8a08980e6a | ||
|
|
d0f31771ad | ||
|
|
e9e2c9372d | ||
|
|
70c4a095a0 | ||
|
|
82e2fc4445 | ||
|
|
6661d81fdf | ||
|
|
e76abaafa8 | ||
|
|
fbfc1c05d6 | ||
|
|
839c211c64 | ||
|
|
f3ff82143a | ||
|
|
0dd0abae87 | ||
|
|
13781c993e | ||
|
|
7616cacbec | ||
|
|
cab7d3c012 | ||
|
|
dfce676fdf | ||
|
|
1890cab623 | ||
|
|
4307d8fe43 | ||
|
|
8df6fdbee6 | ||
|
|
ac5c2a3088 | ||
|
|
0212b677ae | ||
|
|
1a0d62d8f3 | ||
|
|
8f4d1c7aea | ||
|
|
2a4735c6f2 | ||
|
|
5a2ee88cbc | ||
|
|
b23f199334 | ||
|
|
ed5dabee9f | ||
|
|
0c88c5a522 | ||
|
|
640e7015c8 |
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
3772
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
17
package.json
17
package.json
@@ -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"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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)
|
||||||
}
|
}
|
||||||
|
|||||||
18
src/SASjs.ts
18
src/SASjs.ts
@@ -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,
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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',
|
||||||
|
|||||||
Reference in New Issue
Block a user