diff --git a/package-lock.json b/package-lock.json index 9d896d1..f51088d 100644 --- a/package-lock.json +++ b/package-lock.json @@ -8,7 +8,7 @@ "hasInstallScript": true, "license": "ISC", "dependencies": { - "@sasjs/utils": "2.40.1", + "@sasjs/utils": "2.42.0", "axios": "0.26.0", "axios-cookiejar-support": "1.0.1", "form-data": "4.0.0", @@ -1142,9 +1142,9 @@ } }, "node_modules/@sasjs/utils": { - "version": "2.40.1", - "resolved": "https://registry.npmjs.org/@sasjs/utils/-/utils-2.40.1.tgz", - "integrity": "sha512-wWYElDH71bSZTdZ5V38743vAnw2EPDhzH7+1s7zxINHpaQWK/qrDldI0vgVFLeGpxVU0D7WPZ/ltG6MoE2obeg==", + "version": "2.42.0", + "resolved": "https://registry.npmjs.org/@sasjs/utils/-/utils-2.42.0.tgz", + "integrity": "sha512-Y69l89PYNF/h9xvVH72om/39xA+cY80bhiVLzp/fJb3BlvzCf4RNswBBanUOv2I5JNa7gPpJuE7mEiXOlhD3eg==", "hasInstallScript": true, "dependencies": { "@types/fs-extra": "9.0.13", @@ -13870,9 +13870,9 @@ } }, "@sasjs/utils": { - "version": "2.40.1", - "resolved": "https://registry.npmjs.org/@sasjs/utils/-/utils-2.40.1.tgz", - "integrity": "sha512-wWYElDH71bSZTdZ5V38743vAnw2EPDhzH7+1s7zxINHpaQWK/qrDldI0vgVFLeGpxVU0D7WPZ/ltG6MoE2obeg==", + "version": "2.42.0", + "resolved": "https://registry.npmjs.org/@sasjs/utils/-/utils-2.42.0.tgz", + "integrity": "sha512-Y69l89PYNF/h9xvVH72om/39xA+cY80bhiVLzp/fJb3BlvzCf4RNswBBanUOv2I5JNa7gPpJuE7mEiXOlhD3eg==", "requires": { "@types/fs-extra": "9.0.13", "@types/prompts": "2.0.13", diff --git a/package.json b/package.json index f1b8a52..e2e4dc5 100644 --- a/package.json +++ b/package.json @@ -72,7 +72,7 @@ }, "main": "index.js", "dependencies": { - "@sasjs/utils": "2.40.1", + "@sasjs/utils": "2.42.0", "axios": "0.26.0", "axios-cookiejar-support": "1.0.1", "form-data": "4.0.0", diff --git a/src/SASjs.ts b/src/SASjs.ts index 8aed075..2b2fb6d 100644 --- a/src/SASjs.ts +++ b/src/SASjs.ts @@ -5,8 +5,7 @@ import { EditContextInput, PollOptions, LoginMechanism, - ExecutionQuery, - FileTree + ExecutionQuery } from './types' import { SASViyaApiClient } from './SASViyaApiClient' import { SAS9ApiClient } from './SAS9ApiClient' @@ -18,7 +17,7 @@ import { AuthConfig, ExtraResponseAttributes, SasAuthResponse, - StreamConfig + ServicePackSASjs } from '@sasjs/utils/types' import { RequestClient } from './request/RequestClient' import { SasjsRequestClient } from './request/SasjsRequestClient' @@ -889,27 +888,21 @@ export default class SASjs { /** * 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 appLoc - the base folder in which to create the new folders and - * services. If not provided, is taken from SASjsConfig. - * @param streamConfig - optional configuration object of StreamConfig for deploying streaming app. - * @param authConfig - a valid client, secret, refresh and access tokens that are authorised to execute compute jobs. + * @param dataJson - the JSON specifying the folders and files to be created, can also includes + * appLoc, streamServiceName, streamWebFolder, streamLogo + * @param appLoc - (optional) the base folder in which to create the new folders and + * 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( - members: FileTree, + dataJson: ServicePackSASjs, appLoc?: string, - streamConfig?: StreamConfig, authConfig?: AuthConfig ) { if (!appLoc) { appLoc = this.sasjsConfig.appLoc } - return await this.sasJSApiClient?.deploy( - members, - appLoc, - streamConfig, - authConfig - ) + return await this.sasJSApiClient?.deploy(dataJson, appLoc, authConfig) } public async executeJobSASjs(query: ExecutionQuery) { @@ -1102,13 +1095,8 @@ export default class SASjs { } if (this.sasjsConfig.serverType === ServerType.Sasjs) { - if (this.sasJSApiClient) { - this.sasJSApiClient.setConfig(this.sasjsConfig.serverUrl) - } else { - this.sasJSApiClient = new SASjsApiClient( - this.sasjsConfig.serverUrl, - this.requestClient - ) + if (!this.sasJSApiClient) { + this.sasJSApiClient = new SASjsApiClient(this.requestClient) } } diff --git a/src/SASjsApiClient.ts b/src/SASjsApiClient.ts index e4fa737..c0a4268 100644 --- a/src/SASjsApiClient.ts +++ b/src/SASjsApiClient.ts @@ -1,5 +1,5 @@ -import { AuthConfig, ServerType, StreamConfig } from '@sasjs/utils/types' -import { FileTree, ExecutionQuery } from './types' +import { AuthConfig, ServerType, ServicePackSASjs } from '@sasjs/utils/types' +import { ExecutionQuery } from './types' import { RequestClient } from './request/RequestClient' import { getAccessTokenForSasjs } from './auth/getAccessTokenForSasjs' import { refreshTokensForSasjs } from './auth/refreshTokensForSasjs' @@ -8,19 +8,11 @@ import { parseWeboutResponse } from './utils' import { getTokens } from './auth/getTokens' export class SASjsApiClient { - constructor( - private serverUrl: string, - private requestClient: RequestClient - ) {} - - public setConfig(serverUrl: string) { - if (serverUrl) this.serverUrl = serverUrl - } + constructor(private requestClient: RequestClient) {} public async deploy( - members: FileTree, + dataJson: ServicePackSASjs, appLoc: string, - streamConfig?: StreamConfig, authConfig?: AuthConfig ) { let access_token = (authConfig || {}).access_token @@ -31,6 +23,9 @@ export class SASjsApiClient { ServerType.Sasjs )) } + + dataJson.appLoc = dataJson.appLoc || appLoc + const { result } = await this.requestClient.post<{ status: string message: string @@ -38,13 +33,7 @@ export class SASjsApiClient { example?: {} }>( 'SASjsApi/drive/deploy', - { - fileTree: members, - appLoc: appLoc, - streamServiceName: streamConfig?.streamServiceName, - streamWebFolder: streamConfig?.streamWebFolder, - streamLogo: streamConfig?.streamLogo - }, + dataJson, access_token, undefined, {}, diff --git a/src/file/generateFileUploadForm.ts b/src/file/generateFileUploadForm.ts index 04e9c30..d88f13d 100644 --- a/src/file/generateFileUploadForm.ts +++ b/src/file/generateFileUploadForm.ts @@ -26,11 +26,18 @@ export const generateFileUploadForm = ( ) } - const file = new Blob([csv], { - type: 'application/csv' - }) + if (typeof FormData === 'undefined' && formData instanceof NodeFormData) { + 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 diff --git a/src/types/FileTree.ts b/src/types/FileTree.ts deleted file mode 100644 index 548bc5a..0000000 --- a/src/types/FileTree.ts +++ /dev/null @@ -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' diff --git a/src/types/index.ts b/src/types/index.ts index 97f5406..c5994f7 100644 --- a/src/types/index.ts +++ b/src/types/index.ts @@ -12,5 +12,4 @@ export * from './Session' export * from './UploadFile' export * from './PollOptions' export * from './WriteStream' -export * from './FileTree' export * from './ExecuteScript' diff --git a/src/utils/parseViyaDebugResponse.ts b/src/utils/parseViyaDebugResponse.ts index d3d3e6e..f5e4e54 100644 --- a/src/utils/parseViyaDebugResponse.ts +++ b/src/utils/parseViyaDebugResponse.ts @@ -16,10 +16,15 @@ export const parseSasViyaDebugResponse = async ( requestClient: RequestClient, serverUrl: string ) => { + // On viya 3.5, iframe is like + // On viya 4, iframe is like + const iframeStart = response.split( - '')[0] : null + const jsonUrl = iframeStart + ? iframeStart.split(/"><\/iframe>|><\/iframe>/)[0] + : null if (!jsonUrl) { throw new Error('Unable to find webout file URL.') }