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

Compare commits

...

28 Commits

Author SHA1 Message Date
Allan Bowe
9ed64e5a2c Merge pull request #42 from sasjs/issue41
fix: csrfTokenWeb setter callback
2020-08-18 13:22:33 +02:00
Mihajlo Medjedovic
0479a5d651 fix: csrfTokenWeb setter callback 2020-08-18 13:17:29 +02:00
Allan Bowe
005f10bb47 Update CONTRIBUTING.md 2020-08-18 11:24:30 +02:00
Krishna Acondy
8192f69f67 fix(*): do not use polyfill when running on Node.js 2020-08-18 08:25:40 +01:00
Krishna Acondy
a409d8cdb6 Merge pull request #38 from sasjs/brwoserCheckFix
fix: isIEorEdgeOrOldFirefox error
2020-08-14 13:10:44 +01:00
Mihajlo Medjedovic
618a20eaba fix: isIEorEdgeOrOldFirefox error 2020-08-14 14:09:28 +02:00
Krishna Acondy
c9b1273c31 Merge pull request #37 from sasjs/ie-edge-fetch
fix(*): use fetch polyfill in IE, Edge and Firefox <60
2020-08-13 21:56:11 +01:00
Krishna Acondy
59674744be fix(*): use fetch polyfill for Firefox versions older than 60 2020-08-13 21:46:08 +01:00
Krishna Acondy
870cc0055b fix(*): use fetch polyfill in Firefox 60 2020-08-13 21:07:21 +01:00
Krishna Acondy
0ffa62fab4 fix(*): use fetch polyfill in IE and Edge 2020-08-13 20:53:27 +01:00
Allan Bowe
b4c7868fb6 Merge pull request #36 from sasjs/issue34
fix: job definition debug log parse
2020-08-11 18:44:39 +02:00
Mihajlo Medjedovic
2266578013 Merge branch 'master' into issue34 2020-08-11 18:29:41 +02:00
Mihajlo Medjedovic
f2ebe1a5b0 fix: job definition debug log parse 2020-08-10 18:13:11 +02:00
Allan Bowe
6a52bbe560 Merge pull request #35 from sasjs/issue33
fix: makeRequest inconsistent response structure
2020-08-10 17:19:05 +02:00
Mihajlo Medjedovic
a5c725e677 fix: makeRequest incositent response structure 2020-08-10 17:05:10 +02:00
Krishna Acondy
f5e1907e28 feat(clear-requests): add function to clear debug requests 2020-08-08 14:27:40 +01:00
Krishna Acondy
f7a9b0cbb6 fix(compute-api): ignore 404s when requesting webout content 2020-08-08 14:26:09 +01:00
Krishna Acondy
1258a1a180 fix(login-callback): fix request failure when login is required 2020-08-08 12:56:31 +01:00
Krishna Acondy
0bb343a1de chore(deps): bump adapter and test framework 2020-08-08 11:42:16 +01:00
Krishna Acondy
929c89b70f Merge pull request #32 from sasjs/dependabot/npm_and_yarn/types/jest-26.0.9
chore(deps-dev): bump @types/jest from 26.0.8 to 26.0.9
2020-08-08 11:04:25 +01:00
dependabot-preview[bot]
169ca35238 chore(deps-dev): bump @types/jest from 26.0.8 to 26.0.9
Bumps [@types/jest](https://github.com/DefinitelyTyped/DefinitelyTyped/tree/HEAD/types/jest) from 26.0.8 to 26.0.9.
- [Release notes](https://github.com/DefinitelyTyped/DefinitelyTyped/releases)
- [Commits](https://github.com/DefinitelyTyped/DefinitelyTyped/commits/HEAD/types/jest)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>
2020-08-06 12:59:52 +00:00
Allan Bowe
60be28f149 Merge pull request #31 from sasjs/session-cleanup
feat(session-cleanup): delete a session after it has been used
2020-08-05 23:17:42 +02:00
Krishna Acondy
14daa55184 feat(session-cleanup): delete a session after it has been used 2020-08-05 21:52:23 +01:00
Krishna Acondy
f763f05b5e Merge pull request #30 from sasjs/deployFix
fix: makeRequest retry
2020-08-05 20:02:44 +01:00
Mihajlo Medjedovic
b6aced5bad fix: makeRequest retry 2020-08-05 20:58:10 +02:00
Allan Bowe
7bb7db0f27 Merge pull request #24 from sasjs/dependabot/npm_and_yarn/webpack-4.44.1
chore(deps-dev): bump webpack from 4.43.0 to 4.44.1
2020-08-04 20:57:22 +02:00
Allan Bowe
36ea148446 Merge branch 'master' into dependabot/npm_and_yarn/webpack-4.44.1 2020-08-04 20:56:51 +02:00
dependabot-preview[bot]
c1750c014e chore(deps-dev): bump webpack from 4.43.0 to 4.44.1
Bumps [webpack](https://github.com/webpack/webpack) from 4.43.0 to 4.44.1.
- [Release notes](https://github.com/webpack/webpack/releases)
- [Commits](https://github.com/webpack/webpack/compare/v4.43.0...v4.44.1)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>
2020-08-03 20:41:21 +00:00
15 changed files with 742 additions and 948 deletions

View File

@@ -70,6 +70,14 @@ parmcards4;
%webout(CLOSE)
;;;;
%mp_createwebservice(path=/Public/app/common,name=sendArr)
filename ft15f001 temp;
parmcards4;
If you can keep your head when all about you
Are losing theirs and blaming it on you,
If you can trust yourself when all men doubt you,
But make allowance for their doubting too;
;;;;
%mp_createwebservice(path=/Public/app/common,name=makeErr)
```
The above services will return anything you send. To run the tests simply launch `npm run cypress`.

1250
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@@ -37,7 +37,7 @@
"license": "ISC",
"devDependencies": {
"@types/isomorphic-fetch": "0.0.35",
"@types/jest": "^26.0.8",
"@types/jest": "^26.0.9",
"cp": "^0.2.0",
"jest": "^25.5.4",
"path": "^0.12.7",
@@ -53,7 +53,7 @@
"typedoc-plugin-external-module-name": "^4.0.3",
"typescript": "^3.9.7",
"uglifyjs-webpack-plugin": "^2.2.0",
"webpack": "^4.43.0",
"webpack": "^4.44.1",
"webpack-cli": "^3.3.12"
},
"main": "index.js",

View File

@@ -1357,9 +1357,9 @@
"integrity": "sha512-shAmDyaQC4H92APFoIaVDHCx5bStIocgvbwQyxPRrbUY20V1EYTbSDchWbuwlMG3V17cprZhA6+78JfB+3DTPw=="
},
"@sasjs/adapter": {
"version": "1.0.5",
"resolved": "https://registry.npmjs.org/@sasjs/adapter/-/adapter-1.0.5.tgz",
"integrity": "sha512-54gQZD7QdNmQu77axOqr0vMS7hUVXO5hPbUtwXXocMIi3kRQDbROYjC3kuiFM9FrxqiZWbLRcyOqmFv3W/N36w==",
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/@sasjs/adapter/-/adapter-1.2.0.tgz",
"integrity": "sha512-PcQcmb7TsfPJ94tzFnvycm+tMYD3wKx2a6niwHfsV9+g6XHtmwReVV3EPZZ5XB4s565vU6Qc+ZnFbMIAeik8QA==",
"requires": {
"es6-promise": "^4.2.8",
"form-data": "^3.0.0",
@@ -1379,15 +1379,23 @@
}
},
"@sasjs/test-framework": {
"version": "1.3.0",
"resolved": "https://registry.npmjs.org/@sasjs/test-framework/-/test-framework-1.3.0.tgz",
"integrity": "sha512-vrbRFUhNUShLlNFZO+XwVwFLXDLApQG9zOPx00xhQ8IUA0cSDFFmf2mP/KBdFCxa1REaR6GHvMctUj+xRZo9QQ==",
"version": "1.3.3",
"resolved": "https://registry.npmjs.org/@sasjs/test-framework/-/test-framework-1.3.3.tgz",
"integrity": "sha512-Ou4UXlxBAVR8jv7boVvJ/eKLHRTQvDi9LouPAasLCO2EC4AD0wX1hLMwVhmydCvsdgVEeXs6InvX3ROHiKSADg==",
"requires": {
"@types/react-highlight.js": "^1.0.0",
"immer": "^7.0.7",
"moment": "^2.27.0",
"react-highlight.js": "^1.0.7",
"semantic-ui-css": "^2.4.1",
"semantic-ui-react": "^1.0.0"
},
"dependencies": {
"immer": {
"version": "7.0.7",
"resolved": "https://registry.npmjs.org/immer/-/immer-7.0.7.tgz",
"integrity": "sha512-Q8yYwVADJXrNfp1ZUAh4XDHkcoE3wpdpb4mC5abDSajs2EbW8+cGdPyAnglMyLnm7EF6ojD2xBFX7L5i4TIytw=="
}
}
},
"@semantic-ui-react/event-stack": {
@@ -3747,11 +3755,6 @@
}
}
},
"classnames": {
"version": "2.2.6",
"resolved": "https://registry.npmjs.org/classnames/-/classnames-2.2.6.tgz",
"integrity": "sha512-JR/iSQOSt+LQIWwrwEzJ9uk0xfN3mTVYMwt1Ir5mUcSN6pU+V4zQFFaJsclJbPuAUQH+yfWef6tm7l1quW3C8Q=="
},
"clean-css": {
"version": "4.2.3",
"resolved": "https://registry.npmjs.org/clean-css/-/clean-css-4.2.3.tgz",
@@ -3829,6 +3832,11 @@
"shallow-clone": "^0.1.2"
}
},
"clsx": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/clsx/-/clsx-1.1.1.tgz",
"integrity": "sha512-6/bPho624p3S2pMyvP5kKBPXnI3ufHLObBFCfgx+LkeR5lg2XYy2hqZqUf45ypD8COn2bhgGJSUE+l5dhNBieA=="
},
"co": {
"version": "4.6.0",
"resolved": "https://registry.npmjs.org/co/-/co-4.6.0.tgz",
@@ -12226,21 +12234,36 @@
}
},
"semantic-ui-react": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/semantic-ui-react/-/semantic-ui-react-1.0.0.tgz",
"integrity": "sha512-85mYHYuDBNa6la1BgKwuOSD1vcIPsFQEXRxGsZ9pUtE4iHlEcylF+x46NYHIGbBjlys63SpNH3PtK6VyZj9LBw==",
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/semantic-ui-react/-/semantic-ui-react-1.1.1.tgz",
"integrity": "sha512-QtzLNkK4MUe1HQo4S7/tIkSp4NFtxSGDzTMKxmvztMJ6jt+nKGmMyjpyxJsrm3ohU8Z3sTyBUyiBsDYW4jNtjw==",
"requires": {
"@babel/runtime": "^7.1.2",
"@babel/runtime": "^7.10.5",
"@semantic-ui-react/event-stack": "^3.1.0",
"@stardust-ui/react-component-event-listener": "~0.38.0",
"@stardust-ui/react-component-ref": "~0.38.0",
"classnames": "^2.2.6",
"keyboard-key": "^1.0.4",
"lodash": "^4.17.15",
"clsx": "^1.1.1",
"keyboard-key": "^1.1.0",
"lodash": "^4.17.19",
"prop-types": "^15.7.2",
"react-is": "^16.8.6",
"react-popper": "^1.3.4",
"react-popper": "^1.3.7",
"shallowequal": "^1.1.0"
},
"dependencies": {
"@babel/runtime": {
"version": "7.11.2",
"resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.11.2.tgz",
"integrity": "sha512-TeWkU52so0mPtDcaCTxNBI/IHiz0pZgr8VEFqXFtZWpYD08ZB6FaSwVAS8MKRQAP3bYKiVjwysOJgMFY28o6Tw==",
"requires": {
"regenerator-runtime": "^0.13.4"
}
},
"lodash": {
"version": "4.17.19",
"resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.19.tgz",
"integrity": "sha512-JNvd8XER9GQX0v2qJgsaN/mzFCNA5BRe/j8JN9d+tWyGLSodKQHKFicdwNYzWwI3wjRnaKPsGj1XkBjx/F96DQ=="
}
}
},
"semver": {

View File

@@ -4,8 +4,8 @@
"homepage": ".",
"private": true,
"dependencies": {
"@sasjs/adapter": "^1.0.5",
"@sasjs/test-framework": "^1.3.0",
"@sasjs/adapter": "^1.2.0",
"@sasjs/test-framework": "^1.3.3",
"@testing-library/jest-dom": "^4.2.4",
"@testing-library/react": "^9.5.0",
"@testing-library/user-event": "^7.2.1",

View File

@@ -12,7 +12,7 @@ const Login = (): ReactElement<{}> => {
(e) => {
e.preventDefault();
appContext.adapter.logIn(username, password).then((res) => {
appContext.setIsLoggedIn(true);
appContext.setIsLoggedIn(res.isLoggedIn);
});
},
[username, password, appContext]

View File

@@ -9,7 +9,8 @@ export class FileUploader {
private appLoc: string,
private serverUrl: string,
private jobsPath: string,
private csrfToken: CsrfToken | null = null
private setCsrfTokenWeb: any,
private csrfToken: CsrfToken | null = null,
) {}
private retryCount = 0;
@@ -61,6 +62,8 @@ export class FileUploader {
headerName: tokenHeader,
value: token || "",
};
this.setCsrfTokenWeb(this.csrfToken);
}
}
}

View File

@@ -29,7 +29,11 @@ export class SASViyaApiClient {
}
private csrfToken: CsrfToken | null = null;
private rootFolder: Folder | null = null;
private sessionManager = new SessionManager(this.serverUrl, this.contextName, this.setCsrfToken);
private sessionManager = new SessionManager(
this.serverUrl,
this.contextName,
this.setCsrfToken
);
/**
* Returns a map containing the directory structure in the currently set root folder.
@@ -113,9 +117,7 @@ export class SASViyaApiClient {
`test-${context.name}`,
linesOfCode,
context.name,
accessToken,
undefined,
true
accessToken
).catch(() => null);
});
const results = await Promise.all(promises);
@@ -201,17 +203,20 @@ export class SASViyaApiClient {
linesOfCode: string[],
contextName: string,
accessToken?: string,
sessionId = "",
silent = false,
data = null,
debug = false
) {
silent = !debug;
const headers: any = {
"Content-Type": "application/json",
};
if (accessToken) {
headers.Authorization = `Bearer ${accessToken}`;
}
let executionSessionId: string;
const session = await this.sessionManager.getSession(accessToken);
executionSessionId = session!.id;
@@ -239,7 +244,9 @@ export class SASViyaApiClient {
SYS_JES_JOB_URI: "",
_program: this.rootFolderName + "/" + jobName,
};
let files: any[] = [];
if (data) {
if (JSON.stringify(data).includes(";")) {
files = await this.uploadTables(data, accessToken);
@@ -267,10 +274,12 @@ export class SASViyaApiClient {
arguments: jobArguments,
}),
};
const { result: postedJob, etag } = await this.request<Job>(
`${this.serverUrl}/compute/sessions/${executionSessionId}/jobs`,
postJobRequest
);
if (!silent) {
console.log(`Job has been submitted for ${fileName}`);
console.log(
@@ -286,34 +295,41 @@ export class SASViyaApiClient {
accessToken,
silent
);
const { result: currentJob } = await this.request<Job>(
`${this.serverUrl}/compute/sessions/${executionSessionId}/jobs/${postedJob.id}`,
{ headers }
);
let jobResult, log;
if (jobStatus === "failed" || jobStatus === "error") {
return Promise.reject(currentJob.error);
}
const resultLink = `/compute/sessions/${executionSessionId}/filerefs/_webout/content`;
const logLink = currentJob.links.find((l) => l.rel === "log");
if (resultLink) {
jobResult = await this.request<any>(
`${this.serverUrl}${resultLink}`,
{ headers },
"text"
);
).catch((e) => ({
result: JSON.stringify(e),
}));
}
if (true && logLink) {
log = await this.request<any>(
`${this.serverUrl}${logLink.href}/content`,
`${this.serverUrl}${logLink.href}/content?limit=10000`,
{
headers,
}
).then((res: any) => res.result.items.map((i: any) => i.line).join("\n"));
}
await this.sessionManager.clearSession(executionSessionId, accessToken);
return { result: jobResult?.result, log };
// } else {
// console.error(
@@ -623,12 +639,16 @@ export class SASViyaApiClient {
await this.populateRootFolder(accessToken);
}
if (!this.rootFolder) {
console.error("Root folder was not found");
throw new Error("Root folder was not found");
}
if (!this.rootFolderMap.size) {
await this.populateRootFolderMap(accessToken);
}
if (!this.rootFolderMap.size) {
console.error(
`The job ${sasJob} was not found in ${this.rootFolderName}`
);
throw new Error(
`The job ${sasJob} was not found in ${this.rootFolderName}`
);
@@ -647,6 +667,7 @@ export class SASViyaApiClient {
(l) => l.rel === "getResource"
);
if (!jobDefinitionLink) {
console.error("Job definition URI was not found.");
throw new Error("Job definition URI was not found.");
}
const { result: jobDefinition } = await this.request<JobDefinition>(
@@ -661,7 +682,6 @@ export class SASViyaApiClient {
linesToExecute,
contextName,
accessToken,
"",
true,
data,
debug
@@ -698,11 +718,12 @@ export class SASViyaApiClient {
`The job ${sasJob} was not found in ${this.rootFolderName}`
);
}
let files: any[] = [];
if (data && Object.keys(data).length) {
files = await this.uploadTables(data, accessToken);
}
const jobName = path.basename(sasJob);
const jobFolder = sasJob.replace(`/${jobName}`, "");
const allJobsInFolder = this.rootFolderMap.get(jobFolder.replace("/", ""));
@@ -997,12 +1018,12 @@ export class SASViyaApiClient {
headers,
};
const { result: file } = await this.request<any>(
const uploadResponse = await this.request<any>(
`${this.serverUrl}/files/files#rawUpload`,
createFileRequest
);
uploadedFiles.push({ tableName, file });
uploadedFiles.push({ tableName, file: uploadResponse.result });
}
return uploadedFiles;
}
@@ -1019,9 +1040,9 @@ export class SASViyaApiClient {
`${this.serverUrl}${url}`,
requestInfo
).catch((err) => {
return {result: null};
})
return { result: null };
});
if (!folder) return undefined;
return `/folders/folders/${folder.id}`;
}
@@ -1042,6 +1063,11 @@ export class SASViyaApiClient {
[this.csrfToken.headerName]: this.csrfToken.value,
};
}
return await makeRequest<T>(url, options, this.setCsrfTokenLocal, contentType);
return await makeRequest<T>(
url,
options,
this.setCsrfTokenLocal,
contentType
);
}
}

View File

@@ -1,6 +1,13 @@
import "isomorphic-fetch";
import { isIEorEdgeOrOldFirefox } from "./utils/isIeOrEdge";
import * as e6p from "es6-promise";
(e6p as any).polyfill();
if (isIEorEdgeOrOldFirefox()) {
if (window) {
window.fetch = undefined as any; // ensure the polyfill runs
}
}
// tslint:disable-next-line
require("isomorphic-fetch");
import {
convertToCSV,
compareTimestamps,
@@ -12,6 +19,7 @@ import {
isLogInSuccess,
parseSourceCode,
parseGeneratedCode,
parseWeboutResponse,
needsRetry,
asyncForEach,
} from "./utils";
@@ -21,7 +29,7 @@ import {
SASjsWaitingRequest,
ServerType,
CsrfToken,
UploadFile
UploadFile,
} from "./types";
import { SASViyaApiClient } from "./SASViyaApiClient";
import { SAS9ApiClient } from "./SAS9ApiClient";
@@ -122,7 +130,6 @@ export default class SASjs {
linesOfCode,
contextName,
accessToken,
sessionId,
silent
);
}
@@ -392,8 +399,10 @@ export default class SASjs {
this.sasjsConfig.appLoc,
this.sasjsConfig.serverUrl,
this.jobsPath,
this.setCsrfTokenWeb,
this.csrfTokenWeb
);
return fileUploader.uploadFile(sasJob, files, params);
}
@@ -546,52 +555,60 @@ export default class SASjs {
sasjsWaitingRequest.requestPromise.promise = new Promise(
async (resolve, reject) => {
this.sasViyaApiClient
?.executeComputeJob(
sasJob,
config.contextName,
config.debug,
data,
accessToken
)
.then((response) => {
if (!config.debug) {
this.appendSasjsRequest(null, sasJob, null);
?.executeComputeJob(
sasJob,
config.contextName,
config.debug,
data,
accessToken
)
.then((response) => {
if (!config.debug) {
this.appendSasjsRequest(null, sasJob, null);
} else {
this.appendSasjsRequest(response, sasJob, null);
}
let responseJson;
try {
responseJson = JSON.parse(response!.result);
} catch {
responseJson = JSON.parse(parseWeboutResponse(response!.result));
}
resolve(responseJson);
})
.catch(async (e) => {
if (needsRetry(JSON.stringify(e))) {
if (this.retryCountComputeApi < requestRetryLimit) {
let retryResponse = await this.executeJobViaComputeApi(
sasJob,
data,
config,
loginRequiredCallback,
accessToken
);
this.retryCountComputeApi++;
resolve(retryResponse);
} else {
this.appendSasjsRequest(response, sasJob, null);
this.retryCountComputeApi = 0;
reject({ MESSAGE: "Compute API retry requests limit reached" });
}
}
resolve(JSON.parse(response!.result));
})
.catch(async (e) => {
if (needsRetry(JSON.stringify(e))) {
if (this.retryCountComputeApi < requestRetryLimit) {
let retryResponse = await this.executeJobViaComputeApi(
sasJob,
data,
config,
loginRequiredCallback,
accessToken
);
this.retryCountComputeApi++;
resolve(retryResponse);
} else {
this.retryCountComputeApi = 0;
reject({ MESSAGE: "Compute API retry requests limit reached" });
}
}
if (e && e.status === 401) {
if (loginRequiredCallback) loginRequiredCallback(true);
sasjsWaitingRequest.requestPromise.resolve = resolve;
sasjsWaitingRequest.requestPromise.reject = reject;
sasjsWaitingRequest.config = config;
this.sasjsWaitingRequests.push(sasjsWaitingRequest);
} else {
reject({ MESSAGE: e || "Job execution failed" });
}
})
if (e && e.status === 401) {
if (loginRequiredCallback) loginRequiredCallback(true);
sasjsWaitingRequest.requestPromise.resolve = resolve;
sasjsWaitingRequest.requestPromise.reject = reject;
sasjsWaitingRequest.config = config;
this.sasjsWaitingRequests.push(sasjsWaitingRequest);
} else {
reject({ MESSAGE: e || "Job execution failed" });
}
});
}
);
return sasjsWaitingRequest.requestPromise.promise;
@@ -640,7 +657,18 @@ export default class SASjs {
} else {
this.appendSasjsRequest(response, sasJob, null);
}
return JSON.parse(response!.result);
let responseJson;
try {
responseJson = JSON.parse(response!.result);
} catch {
responseJson = JSON.parse(
parseWeboutResponse(response!.result)
);
}
return responseJson;
})
.catch(async (e) => {
if (needsRetry(JSON.stringify(e))) {
@@ -652,9 +680,9 @@ export default class SASjs {
loginRequiredCallback,
accessToken
);
this.retryCountJeseApi++;
resolve(retryResponse);
} else {
this.retryCountJeseApi = 0;
@@ -662,7 +690,7 @@ export default class SASjs {
}
}
reject({ MESSAGE: (e && e.message) || "Job execution failed" })
reject({ MESSAGE: (e && e.message) || "Job execution failed" });
})
);
}
@@ -835,7 +863,7 @@ export default class SASjs {
} else {
if (config.serverType === ServerType.SAS9 && config.debug) {
this.updateUsername(responseText);
const jsonResponseText = this.parseSAS9Response(responseText);
const jsonResponseText = parseWeboutResponse(responseText);
if (jsonResponseText !== "") {
resolve(JSON.parse(jsonResponseText));
@@ -885,6 +913,10 @@ export default class SASjs {
return sasjsWaitingRequest.requestPromise.promise;
}
private setCsrfTokenWeb = (csrfToken: CsrfToken) => {
this.csrfTokenWeb = csrfToken;
};
private setCsrfTokenApi = (csrfToken: CsrfToken) => {
this.csrfTokenApi = csrfToken;
@@ -976,23 +1008,6 @@ export default class SASjs {
return uri;
}
private parseSAS9Response(response: string) {
let sas9Response = "";
if (response.includes(">>weboutBEGIN<<")) {
try {
sas9Response = response
.split(">>weboutBEGIN<<")[1]
.split(">>weboutEND<<")[0];
} catch (e) {
sas9Response = "";
console.error(e);
}
}
return sas9Response;
}
private parseSAS9ErrorResponse(response: string) {
const logLines = response.split("\n");
const parsedLines: string[] = [];
@@ -1050,7 +1065,12 @@ export default class SASjs {
if (response && response.result && response.log) {
sourceCode = parseSourceCode(response.log);
generatedCode = parseGeneratedCode(response.log);
sasWork = JSON.parse(response.result).WORK;
if (this.sasjsConfig.debug) {
sasWork = JSON.parse(parseWeboutResponse(response.result)).WORK;
} else {
sasWork = JSON.parse(response.result).WORK;
}
} else {
if (response) {
sourceCode = parseSourceCode(response);
@@ -1079,7 +1099,7 @@ export default class SASjs {
if (this.sasjsConfig.serverType === ServerType.SAS9) {
try {
jsonResponse = JSON.parse(this.parseSAS9Response(response));
jsonResponse = JSON.parse(parseWeboutResponse(response));
} catch (e) {
console.error(e);
}
@@ -1110,6 +1130,10 @@ export default class SASjs {
return sortedRequests;
}
public clearSasRequests() {
this.sasjsRequests = [];
}
private setupConfiguration() {
if (
this.sasjsConfig.serverUrl === undefined ||
@@ -1159,7 +1183,8 @@ export default class SASjs {
this.fileUploader = new FileUploader(
this.sasjsConfig.appLoc,
this.sasjsConfig.serverUrl,
this.jobsPath
this.jobsPath,
this.setCsrfTokenWeb
);
}

View File

@@ -16,7 +16,21 @@ export class SessionManager {
async getSession(accessToken?: string) {
await this.createSessions(accessToken);
this.createAndWaitForSession(accessToken);
return this.sessions.pop();
const session = this.sessions.pop();
return session;
}
async clearSession(id: string, accessToken?: string) {
const deleteSessionRequest = {
method: "DELETE",
headers: this.getHeaders(accessToken),
};
return await this.request<Session>(
`${this.serverUrl}/compute/sessions/${id}`,
deleteSessionRequest
).then(() => {
this.sessions = this.sessions.filter((s) => s.id !== id);
});
}
private async createSessions(accessToken?: string) {

View File

@@ -12,3 +12,4 @@ export * from "./parseSourceCode";
export * from "./parseSasViyaLog";
export * from "./serialize";
export * from "./splitChunks";
export * from "./parseWeboutResponse";

34
src/utils/isIeOrEdge.ts Normal file
View File

@@ -0,0 +1,34 @@
export function isIEorEdgeOrOldFirefox() {
if (typeof window === "undefined") {
return false;
}
const ua = window.navigator.userAgent;
if (ua.indexOf("Firefox") > 0) {
const version = parseInt(
ua.substring(ua.lastIndexOf("Firefox/") + 8, ua.length),
10
);
return version <= 60;
}
const msie = ua.indexOf("MSIE ");
if (msie > 0) {
// IE 10 or older => return version number
return true;
}
const trident = ua.indexOf("Trident/");
if (trident > 0) {
return true;
}
const edge = ua.indexOf("Edge/");
if (edge > 0) {
// Edge (IE 12+) => return version number
return true;
}
// other browser
return false;
}

View File

@@ -18,6 +18,9 @@ export async function makeRequest<T>(
: (res: Response) => res.text();
let etag = null;
const result = await fetch(url, request).then(async (response) => {
if (response.redirected && response.url.includes("SASLogon/login")) {
return Promise.reject({ status: 401 });
}
if (!response.ok) {
if (response.status === 403) {
const tokenHeader = response.headers.get("X-CSRF-HEADER");
@@ -40,33 +43,59 @@ export async function makeRequest<T>(
}
} else {
const body = await response.text();
if (needsRetry(body)) {
if (retryCount < retryLimit) {
retryCount++;
let retryResponse = await makeRequest(
url,
retryRequest || request,
callback,
contentType
);
retryCount = 0;
etag = retryResponse.etag;
return retryResponse.result;
} else {
retryCount = 0;
throw new Error("Request retry limit exceeded");
}
}
return Promise.reject({ status: response.status, body });
}
} else {
const responseTransformed = responseTransform(response);
let responseText = '';
if (response.status === 204) {
return Promise.resolve();
}
const responseTransformed = await responseTransform(response);
let responseText = "";
if (typeof responseTransformed === 'string') {
if (typeof responseTransformed === "string") {
responseText = responseTransformed;
} else {
responseText = JSON.stringify(responseTransformed);
}
if (response.redirected && response.url.includes("SASLogon/login")) {
return Promise.reject({ status: 401, responseTransformed });
}
if (needsRetry(responseText)) {
if (retryCount < retryLimit) {
retryCount++;
let retryResponse = await makeRequest(url, retryRequest || request, callback, contentType);
const retryResponse = await makeRequest(
url,
retryRequest || request,
callback,
contentType
);
retryCount = 0;
return retryResponse;
etag = retryResponse.etag;
return retryResponse.result;
} else {
retryCount = 0;
throw new Error('Request retry limit exceeded');
throw new Error("Request retry limit exceeded");
}
}

View File

@@ -1,11 +1,14 @@
export const needsRetry = (responseText: string): boolean => {
return (
(responseText.includes('"errorCode":403') &&
!!responseText &&
((responseText.includes('"errorCode":403') &&
responseText.includes("_csrf") &&
responseText.includes("X-CSRF-TOKEN")) ||
(responseText.includes('"status":403') &&
responseText.includes('"error":"Forbidden"')) ||
(responseText.includes('"status":449') &&
responseText.includes("Authentication success, retry original request"))
(responseText.includes('"status":403') &&
responseText.includes('"error":"Forbidden"')) ||
(responseText.includes('"status":449') &&
responseText.includes(
"Authentication success, retry original request"
)))
);
};

View File

@@ -0,0 +1,16 @@
export const parseWeboutResponse = (response: string) => {
let sasResponse = "";
if (response.includes(">>weboutBEGIN<<")) {
try {
sasResponse = response
.split(">>weboutBEGIN<<")[1]
.split(">>weboutEND<<")[0];
} catch (e) {
sasResponse = "";
console.error(e);
}
}
return sasResponse;
}