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

Compare commits

...

15 Commits

Author SHA1 Message Date
Allan Bowe
01235616a0 Merge pull request #690 from sasjs/issue-689
fix: update code for extracting JSON URL on viya4 when debug is enabled
2022-03-31 15:54:20 +03:00
Muhammad Saad
10051cb7d1 Merge pull request #692 from sasjs/deploy-to-sasjs-server
fix(deploy): to SASJS with complete JSON object
2022-03-31 17:18:17 +05:00
Saad Jutt
7b0ad2d60d chore: sasjs/utils version bump 2022-03-31 16:39:46 +05:00
Saad Jutt
fc0a450e94 fix(deploy): to SASJS with complete JSON object 2022-03-31 04:20:49 +05:00
6cab245cde fix: update code for extracting json url when debug is enabled 2022-03-30 01:22:03 +05:00
Allan Bowe
ee97e8211e Merge pull request #685 from sasjs/issue-684
fix: blob is not defined
2022-03-28 14:26:58 +03:00
d0eb1a7bfb fix: should not create blob in node 2022-03-24 02:43:14 +05:00
Allan Bowe
256e4ef314 Merge pull request #681 from sasjs/sasjs-deploy-with-streaming-app
feat(deploy): stream app deployment on SASJS server
2022-03-21 23:54:40 +02:00
Saad Jutt
6a6dfc5e9d chore: corrected authorised in SASjs.ts only 2022-03-22 02:49:46 +05:00
Saad Jutt
5140848039 chore: sasjs deploy return template type 2022-03-22 02:38:20 +05:00
Saad Jutt
31baf01d3e feat(deploy): stream app deployment on SASJS server 2022-03-22 01:18:02 +05:00
Allan Bowe
804e78cf0c Merge pull request #678 from sasjs/issue-677
fix: return requestPromise from sas9JobExecutor
2022-03-11 12:54:17 +02:00
f6a621fe46 chore: update comments 2022-03-11 14:22:45 +05:00
c47d0c9789 fix: return requestPromise from sas9JobExecutor #677 2022-03-11 14:16:44 +05:00
Allan Bowe
1ddc71b017 Create CNAME 2022-03-10 12:08:46 +00:00
10 changed files with 84 additions and 120 deletions

1
docs/CNAME Normal file
View File

@@ -0,0 +1 @@
adapter.sasjs.io

14
package-lock.json generated
View File

@@ -8,7 +8,7 @@
"hasInstallScript": true, "hasInstallScript": true,
"license": "ISC", "license": "ISC",
"dependencies": { "dependencies": {
"@sasjs/utils": "2.36.1", "@sasjs/utils": "2.42.0",
"axios": "0.26.0", "axios": "0.26.0",
"axios-cookiejar-support": "1.0.1", "axios-cookiejar-support": "1.0.1",
"form-data": "4.0.0", "form-data": "4.0.0",
@@ -1142,9 +1142,9 @@
} }
}, },
"node_modules/@sasjs/utils": { "node_modules/@sasjs/utils": {
"version": "2.36.1", "version": "2.42.0",
"resolved": "https://registry.npmjs.org/@sasjs/utils/-/utils-2.36.1.tgz", "resolved": "https://registry.npmjs.org/@sasjs/utils/-/utils-2.42.0.tgz",
"integrity": "sha512-JkGUpLOODsvkeU+S25jb9k2WnvzyD2w6cEk7YyQ/byuqKL8xawH91PPWegrVcJlDY8WmqKE4CPcA3d1mM3B3LA==", "integrity": "sha512-Y69l89PYNF/h9xvVH72om/39xA+cY80bhiVLzp/fJb3BlvzCf4RNswBBanUOv2I5JNa7gPpJuE7mEiXOlhD3eg==",
"hasInstallScript": true, "hasInstallScript": true,
"dependencies": { "dependencies": {
"@types/fs-extra": "9.0.13", "@types/fs-extra": "9.0.13",
@@ -13870,9 +13870,9 @@
} }
}, },
"@sasjs/utils": { "@sasjs/utils": {
"version": "2.36.1", "version": "2.42.0",
"resolved": "https://registry.npmjs.org/@sasjs/utils/-/utils-2.36.1.tgz", "resolved": "https://registry.npmjs.org/@sasjs/utils/-/utils-2.42.0.tgz",
"integrity": "sha512-JkGUpLOODsvkeU+S25jb9k2WnvzyD2w6cEk7YyQ/byuqKL8xawH91PPWegrVcJlDY8WmqKE4CPcA3d1mM3B3LA==", "integrity": "sha512-Y69l89PYNF/h9xvVH72om/39xA+cY80bhiVLzp/fJb3BlvzCf4RNswBBanUOv2I5JNa7gPpJuE7mEiXOlhD3eg==",
"requires": { "requires": {
"@types/fs-extra": "9.0.13", "@types/fs-extra": "9.0.13",
"@types/prompts": "2.0.13", "@types/prompts": "2.0.13",

View File

@@ -72,7 +72,7 @@
}, },
"main": "index.js", "main": "index.js",
"dependencies": { "dependencies": {
"@sasjs/utils": "2.36.1", "@sasjs/utils": "2.42.0",
"axios": "0.26.0", "axios": "0.26.0",
"axios-cookiejar-support": "1.0.1", "axios-cookiejar-support": "1.0.1",
"form-data": "4.0.0", "form-data": "4.0.0",

View File

@@ -5,8 +5,7 @@ import {
EditContextInput, EditContextInput,
PollOptions, PollOptions,
LoginMechanism, LoginMechanism,
ExecutionQuery, ExecutionQuery
FileTree
} from './types' } from './types'
import { SASViyaApiClient } from './SASViyaApiClient' import { SASViyaApiClient } from './SASViyaApiClient'
import { SAS9ApiClient } from './SAS9ApiClient' import { SAS9ApiClient } from './SAS9ApiClient'
@@ -17,7 +16,8 @@ import {
MacroVar, MacroVar,
AuthConfig, AuthConfig,
ExtraResponseAttributes, ExtraResponseAttributes,
SasAuthResponse SasAuthResponse,
ServicePackSASjs
} from '@sasjs/utils/types' } from '@sasjs/utils/types'
import { RequestClient } from './request/RequestClient' import { RequestClient } from './request/RequestClient'
import { SasjsRequestClient } from './request/SasjsRequestClient' import { SasjsRequestClient } from './request/SasjsRequestClient'
@@ -134,7 +134,7 @@ export default class SASjs {
/** /**
* Gets compute contexts. * Gets compute contexts.
* @param accessToken - an access token for an authorized user. * @param accessToken - an access token for an authorised user.
*/ */
public async getComputeContexts(accessToken: string) { public async getComputeContexts(accessToken: string) {
this.isMethodSupported('getComputeContexts', [ServerType.SasViya]) this.isMethodSupported('getComputeContexts', [ServerType.SasViya])
@@ -144,7 +144,7 @@ export default class SASjs {
/** /**
* Gets launcher contexts. * Gets launcher contexts.
* @param accessToken - an access token for an authorized user. * @param accessToken - an access token for an authorised user.
*/ */
public async getLauncherContexts(accessToken: string) { public async getLauncherContexts(accessToken: string) {
this.isMethodSupported('getLauncherContexts', [ServerType.SasViya]) this.isMethodSupported('getLauncherContexts', [ServerType.SasViya])
@@ -163,7 +163,7 @@ export default class SASjs {
/** /**
* Gets executable compute contexts. * Gets executable compute contexts.
* @param authConfig - an access token, refresh token, client and secret for an authorized user. * @param authConfig - an access token, refresh token, client and secret for an authorised user.
*/ */
public async getExecutableContexts(authConfig: AuthConfig) { public async getExecutableContexts(authConfig: AuthConfig) {
this.isMethodSupported('getExecutableContexts', [ServerType.SasViya]) this.isMethodSupported('getExecutableContexts', [ServerType.SasViya])
@@ -177,8 +177,8 @@ export default class SASjs {
* @param launchContextName - the name of the launcher context used by the compute service. * @param launchContextName - the name of the launcher context used by the compute service.
* @param sharedAccountId - the ID of the account to run the servers for this context as. * @param sharedAccountId - the ID of the account to run the servers for this context as.
* @param autoExecLines - the lines of code to execute during session initialization. * @param autoExecLines - the lines of code to execute during session initialization.
* @param accessToken - an access token for an authorized user. * @param accessToken - an access token for an authorised user.
* @param authorizedUsers - an optional list of authorized user IDs. * @param authorisedUsers - an optional list of authorised user IDs.
*/ */
public async createComputeContext( public async createComputeContext(
contextName: string, contextName: string,
@@ -186,7 +186,7 @@ export default class SASjs {
sharedAccountId: string, sharedAccountId: string,
autoExecLines: string[], autoExecLines: string[],
accessToken: string, accessToken: string,
authorizedUsers?: string[] authorisedUsers?: string[]
) { ) {
this.isMethodSupported('createComputeContext', [ServerType.SasViya]) this.isMethodSupported('createComputeContext', [ServerType.SasViya])
@@ -196,7 +196,7 @@ export default class SASjs {
sharedAccountId, sharedAccountId,
autoExecLines, autoExecLines,
accessToken, accessToken,
authorizedUsers authorisedUsers
) )
} }
@@ -205,7 +205,7 @@ export default class SASjs {
* @param contextName - the name of the context to be created. * @param contextName - the name of the context to be created.
* @param description - the description of the context to be created. * @param description - the description of the context to be created.
* @param launchType - launch type of the context to be created. * @param launchType - launch type of the context to be created.
* @param accessToken - an access token for an authorized user. * @param accessToken - an access token for an authorised user.
*/ */
public async createLauncherContext( public async createLauncherContext(
contextName: string, contextName: string,
@@ -227,7 +227,7 @@ export default class SASjs {
* Updates a compute context on the given server. * Updates a compute context on the given server.
* @param contextName - the original name of the context to be deleted. * @param contextName - the original name of the context to be deleted.
* @param editedContext - an object with the properties to be updated. * @param editedContext - an object with the properties to be updated.
* @param accessToken - an access token for an authorized user. * @param accessToken - an access token for an authorised user.
*/ */
public async editComputeContext( public async editComputeContext(
contextName: string, contextName: string,
@@ -246,7 +246,7 @@ export default class SASjs {
/** /**
* Deletes a compute context on the given server. * Deletes a compute context on the given server.
* @param contextName - the name of the context to be deleted. * @param contextName - the name of the context to be deleted.
* @param accessToken - an access token for an authorized user. * @param accessToken - an access token for an authorised user.
*/ */
public async deleteComputeContext(contextName: string, accessToken?: string) { public async deleteComputeContext(contextName: string, accessToken?: string) {
this.isMethodSupported('deleteComputeContext', [ServerType.SasViya]) this.isMethodSupported('deleteComputeContext', [ServerType.SasViya])
@@ -261,7 +261,7 @@ export default class SASjs {
* Returns a JSON representation of a compute context. * Returns a JSON representation of a compute context.
* @example: { "createdBy": "admin", "links": [...], "id": "ID", "version": 2, "name": "context1" } * @example: { "createdBy": "admin", "links": [...], "id": "ID", "version": 2, "name": "context1" }
* @param contextName - the name of the context to return. * @param contextName - the name of the context to return.
* @param accessToken - an access token for an authorized user. * @param accessToken - an access token for an authorised user.
*/ */
public async getComputeContextByName( public async getComputeContextByName(
contextName: string, contextName: string,
@@ -278,7 +278,7 @@ export default class SASjs {
/** /**
* Returns a JSON representation of a compute context. * Returns a JSON representation of a compute context.
* @param contextId - an id of the context to return. * @param contextId - an id of the context to return.
* @param accessToken - an access token for an authorized user. * @param accessToken - an access token for an authorised user.
*/ */
public async getComputeContextById(contextId: string, accessToken?: string) { public async getComputeContextById(contextId: string, accessToken?: string) {
this.isMethodSupported('getComputeContextById', [ServerType.SasViya]) this.isMethodSupported('getComputeContextById', [ServerType.SasViya])
@@ -888,20 +888,21 @@ export default class SASjs {
/** /**
* Creates the folders and services at the given location `appLoc` on the given server `serverUrl`. * Creates the folders and services at the given location `appLoc` on the given server `serverUrl`.
* @param members - the JSON specifying the folders and services to be created. * @param dataJson - the JSON specifying the folders and files to be created, can also includes
* @param appLoc - the base folder in which to create the new folders and * appLoc, streamServiceName, streamWebFolder, streamLogo
* services. If not provided, is taken from SASjsConfig. * @param appLoc - (optional) the base folder in which to create the new folders and
* @param authConfig - a valid client, secret, refresh and access tokens that are authorised to execute compute jobs. * services. If not provided, is taken from SASjsConfig. Precedence will be of appLoc present in dataJson.
* @param authConfig - (optional) a valid client, secret, refresh and access tokens that are authorised to execute compute jobs.
*/ */
public async deployToSASjs( public async deployToSASjs(
members: FileTree, dataJson: ServicePackSASjs,
appLoc?: string, appLoc?: string,
authConfig?: AuthConfig authConfig?: AuthConfig
) { ) {
if (!appLoc) { if (!appLoc) {
appLoc = this.sasjsConfig.appLoc appLoc = this.sasjsConfig.appLoc
} }
return await this.sasJSApiClient?.deploy(members, appLoc, authConfig) return await this.sasJSApiClient?.deploy(dataJson, appLoc, authConfig)
} }
public async executeJobSASjs(query: ExecutionQuery) { public async executeJobSASjs(query: ExecutionQuery) {
@@ -972,7 +973,7 @@ export default class SASjs {
/** /**
* Fetches content of the log file * Fetches content of the log file
* @param logUrl - url of the log file. * @param logUrl - url of the log file.
* @param accessToken - an access token for an authorized user. * @param accessToken - an access token for an authorised user.
*/ */
public async fetchLogFileContent(logUrl: string, accessToken?: string) { public async fetchLogFileContent(logUrl: string, accessToken?: string) {
return await this.requestClient!.get(logUrl, accessToken).then((res) => { return await this.requestClient!.get(logUrl, accessToken).then((res) => {
@@ -1094,13 +1095,8 @@ export default class SASjs {
} }
if (this.sasjsConfig.serverType === ServerType.Sasjs) { if (this.sasjsConfig.serverType === ServerType.Sasjs) {
if (this.sasJSApiClient) { if (!this.sasJSApiClient) {
this.sasJSApiClient.setConfig(this.sasjsConfig.serverUrl) this.sasJSApiClient = new SASjsApiClient(this.requestClient)
} else {
this.sasJSApiClient = new SASjsApiClient(
this.sasjsConfig.serverUrl,
this.requestClient
)
} }
} }

View File

@@ -1,5 +1,5 @@
import { AuthConfig, ServerType } from '@sasjs/utils/types' import { AuthConfig, ServerType, ServicePackSASjs } from '@sasjs/utils/types'
import { FileTree, ExecutionQuery } from './types' import { ExecutionQuery } from './types'
import { RequestClient } from './request/RequestClient' import { RequestClient } from './request/RequestClient'
import { getAccessTokenForSasjs } from './auth/getAccessTokenForSasjs' import { getAccessTokenForSasjs } from './auth/getAccessTokenForSasjs'
import { refreshTokensForSasjs } from './auth/refreshTokensForSasjs' import { refreshTokensForSasjs } from './auth/refreshTokensForSasjs'
@@ -8,17 +8,10 @@ import { parseWeboutResponse } from './utils'
import { getTokens } from './auth/getTokens' import { getTokens } from './auth/getTokens'
export class SASjsApiClient { export class SASjsApiClient {
constructor( constructor(private requestClient: RequestClient) {}
private serverUrl: string,
private requestClient: RequestClient
) {}
public setConfig(serverUrl: string) {
if (serverUrl) this.serverUrl = serverUrl
}
public async deploy( public async deploy(
members: FileTree, dataJson: ServicePackSASjs,
appLoc: string, appLoc: string,
authConfig?: AuthConfig authConfig?: AuthConfig
) { ) {
@@ -30,13 +23,17 @@ export class SASjsApiClient {
ServerType.Sasjs ServerType.Sasjs
)) ))
} }
dataJson.appLoc = dataJson.appLoc || appLoc
const { result } = await this.requestClient.post<{ const { result } = await this.requestClient.post<{
status: string status: string
message: string message: string
streamServiceName?: string
example?: {} example?: {}
}>( }>(
'SASjsApi/drive/deploy', 'SASjsApi/drive/deploy',
{ fileTree: members, appLoc: appLoc }, dataJson,
access_token, access_token,
undefined, undefined,
{}, {},

View File

@@ -26,11 +26,18 @@ export const generateFileUploadForm = (
) )
} }
const file = new Blob([csv], { if (typeof FormData === 'undefined' && formData instanceof NodeFormData) {
type: 'application/csv' formData.append(name, csv, {
}) filename: `${name}.csv`,
contentType: 'application/csv'
})
} else {
const file = new Blob([csv], {
type: 'application/csv'
})
formData.append(name, file, `${name}.csv`) formData.append(name, file, `${name}.csv`)
}
} }
return formData return formData

View File

@@ -74,26 +74,32 @@ export class Sas9JobExecutor extends BaseJobExecutor {
? 'multipart/form-data; boundary=' + (formData as any)._boundary ? 'multipart/form-data; boundary=' + (formData as any)._boundary
: 'text/plain' : 'text/plain'
return await this.sas9RequestClient!.post( const requestPromise = new Promise((resolve, reject) =>
apiUrl, this.sas9RequestClient!.post(apiUrl, formData, undefined, contentType, {
formData,
undefined,
contentType,
{
Accept: '*/*', Accept: '*/*',
Connection: 'Keep-Alive' Connection: 'Keep-Alive'
} })
.then((res: any) => {
// appending response to requests array that will be used for requests history reference
this.requestClient!.appendRequest(res, sasJob, config.debug)
resolve(res)
})
.catch((err: any) => {
// by default error string is equal to actual error object
let errString = err
// if error object contains non empty result attribute, set result to errString
if (err.result && err.result !== '') errString = err.result
// if there's no result but error message, set error message to errString
else if (err.message) errString = err.message
// appending error to requests array that will be used for requests history reference
this.requestClient!.appendRequest(errString, sasJob, config.debug)
reject(new ErrorResponse(err?.message, err))
})
) )
.then((res: any) => {
//appending response to requests array that will be used for requests history reference return requestPromise
this.requestClient!.appendRequest(res, sasJob, config.debug)
return res
})
.catch((err: any) => {
//appending error to requests array that will be used for requests history reference
this.requestClient!.appendRequest(err, sasJob, config.debug)
return err
})
} }
private getRequestParams(config: any): any { private getRequestParams(config: any): any {

View File

@@ -1,47 +0,0 @@
export interface FileTree {
members: [FolderMember, ServiceMember]
}
export enum MemberType {
folder = 'folder',
service = 'service'
}
export interface FolderMember {
name: string
type: MemberType.folder
members: [FolderMember, ServiceMember]
}
export interface ServiceMember {
name: string
type: MemberType.service
code: string
}
export const isFileTree = (arg: any): arg is FileTree =>
arg &&
arg.members &&
Array.isArray(arg.members) &&
arg.members.filter(
(member: FolderMember | ServiceMember) =>
!isFolderMember(member) && !isServiceMember(member)
).length === 0
const isFolderMember = (arg: any): arg is FolderMember =>
arg &&
typeof arg.name === 'string' &&
arg.type === MemberType.folder &&
arg.members &&
Array.isArray(arg.members) &&
arg.members.filter(
(member: FolderMember | ServiceMember) =>
!isFolderMember(member) && !isServiceMember(member)
).length === 0
const isServiceMember = (arg: any): arg is ServiceMember =>
arg &&
typeof arg.name === 'string' &&
arg.type === MemberType.service &&
arg.code &&
typeof arg.code === 'string'

View File

@@ -12,5 +12,4 @@ export * from './Session'
export * from './UploadFile' export * from './UploadFile'
export * from './PollOptions' export * from './PollOptions'
export * from './WriteStream' export * from './WriteStream'
export * from './FileTree'
export * from './ExecuteScript' export * from './ExecuteScript'

View File

@@ -16,10 +16,15 @@ export const parseSasViyaDebugResponse = async (
requestClient: RequestClient, requestClient: RequestClient,
serverUrl: string serverUrl: string
) => { ) => {
// On viya 3.5, iframe is like <iframe style="width: 99%; height: 500px" src="..."></iframe>
// On viya 4, iframe is like <iframe style="width: 99%; height: 500px; background-color:Canvas;" src=...></iframe>
const iframeStart = response.split( const iframeStart = response.split(
'<iframe style="width: 99%; height: 500px" src="' /<iframe style="width: 99%; height: 500px" src="|<iframe style="width: 99%; height: 500px; background-color:Canvas;" src=/
)[1] )[1]
const jsonUrl = iframeStart ? iframeStart.split('"></iframe>')[0] : null const jsonUrl = iframeStart
? iframeStart.split(/"><\/iframe>|><\/iframe>/)[0]
: null
if (!jsonUrl) { if (!jsonUrl) {
throw new Error('Unable to find webout file URL.') throw new Error('Unable to find webout file URL.')
} }