mirror of
https://github.com/sasjs/adapter.git
synced 2025-12-11 09:24:35 +00:00
Compare commits
74 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
ec77ffdd88 | ||
|
|
9797c1ca84 | ||
|
|
bbe9633dc8 | ||
|
|
e7ba09793c | ||
|
|
c0c0800e61 | ||
|
|
0bd9d8f93f | ||
|
|
214fc2d5cd | ||
|
|
55b0e2f934 | ||
|
|
609cd4ed6d | ||
|
|
2b20bbdcc8 | ||
|
|
946a95bea1 | ||
|
|
7ec1c152e3 | ||
|
|
0cf1110018 | ||
|
|
9c5ada6fa1 | ||
|
|
0f5702e21b | ||
|
|
f10d6ec80a | ||
|
|
490215df90 | ||
|
|
9d27451813 | ||
|
|
a977f59675 | ||
|
|
47be5e77e5 | ||
|
|
d517e79ec0 | ||
|
|
8714ecdde8 | ||
|
|
2cffc57209 | ||
|
|
4e43687de2 | ||
|
|
f8dab83e37 | ||
|
|
655af03cf3 | ||
|
|
0a4dd00edb | ||
|
|
55b4929c54 | ||
|
|
8eb73a6b3c | ||
|
|
0aeb201625 | ||
|
|
e0140a23c2 | ||
|
|
ff6698a9d1 | ||
|
|
843d498b72 | ||
|
|
349612a065 | ||
|
|
e48b22128d | ||
|
|
14dfe4ec51 | ||
|
|
f679b17cbe | ||
|
|
36a0f0e743 | ||
|
|
ad563b9bc8 | ||
|
|
e0051bf276 | ||
|
|
7b72998e1c | ||
|
|
893cce7f21 | ||
|
|
bf7e8fd0e6 | ||
|
|
66d02cf1d1 | ||
|
|
f2c8e40430 | ||
|
|
4b28ee8e73 | ||
|
|
c7e54cfe9f | ||
|
|
50be3acc78 | ||
|
|
66c12a69bb | ||
|
|
e2058f0c71 | ||
|
|
75a74152a5 | ||
|
|
9344c4fd35 | ||
|
|
be0fe00076 | ||
|
|
a2069ee48b | ||
|
|
907885cf85 | ||
|
|
f10ed3236e | ||
|
|
a852a0af7c | ||
|
|
03f3550774 | ||
|
|
2e8d06f9e1 | ||
|
|
7a6e6e8333 | ||
|
|
cc594eca52 | ||
|
|
3fbca2835e | ||
|
|
61ed5c4fa7 | ||
|
|
9b6ba3548f | ||
|
|
efa4c71b8a | ||
|
|
ecfc1a4bf8 | ||
|
|
246b855c76 | ||
|
|
80aa848617 | ||
|
|
acf045965e | ||
|
|
5a7f64dc35 | ||
|
|
de447b0727 | ||
|
|
ace16efd93 | ||
|
|
13ae5ae756 | ||
|
|
f1b035032f |
4
.gitignore
vendored
4
.gitignore
vendored
@@ -3,4 +3,6 @@ build
|
||||
|
||||
.env
|
||||
|
||||
/coverage
|
||||
/coverage
|
||||
|
||||
.DS_Store
|
||||
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
328
docs/classes/auth.authmanager.html
Normal file
328
docs/classes/auth.authmanager.html
Normal file
File diff suppressed because one or more lines are too long
432
docs/classes/job_execution.basejobexecutor.html
Normal file
432
docs/classes/job_execution.basejobexecutor.html
Normal file
File diff suppressed because one or more lines are too long
435
docs/classes/job_execution.computejobexecutor.html
Normal file
435
docs/classes/job_execution.computejobexecutor.html
Normal file
File diff suppressed because one or more lines are too long
435
docs/classes/job_execution.jesjobexecutor.html
Normal file
435
docs/classes/job_execution.jesjobexecutor.html
Normal file
File diff suppressed because one or more lines are too long
441
docs/classes/job_execution.webjobexecutor.html
Normal file
441
docs/classes/job_execution.webjobexecutor.html
Normal file
File diff suppressed because one or more lines are too long
231
docs/classes/reflection-817.reflection-220.fileuploader.html
Normal file
231
docs/classes/reflection-817.reflection-220.fileuploader.html
Normal file
File diff suppressed because one or more lines are too long
312
docs/classes/reflection-817.reflection-220.sas9apiclient.html
Normal file
312
docs/classes/reflection-817.reflection-220.sas9apiclient.html
Normal file
File diff suppressed because one or more lines are too long
1715
docs/classes/reflection-817.reflection-220.sasjs.html
Normal file
1715
docs/classes/reflection-817.reflection-220.sasjs.html
Normal file
File diff suppressed because one or more lines are too long
1516
docs/classes/reflection-817.reflection-220.sasviyaapiclient.html
Normal file
1516
docs/classes/reflection-817.reflection-220.sasviyaapiclient.html
Normal file
File diff suppressed because one or more lines are too long
323
docs/classes/reflection-817.reflection-220.sessionmanager.html
Normal file
323
docs/classes/reflection-817.reflection-220.sessionmanager.html
Normal file
File diff suppressed because one or more lines are too long
231
docs/classes/reflection-830.reflection-222.fileuploader.html
Normal file
231
docs/classes/reflection-830.reflection-222.fileuploader.html
Normal file
File diff suppressed because one or more lines are too long
312
docs/classes/reflection-830.reflection-222.sas9apiclient.html
Normal file
312
docs/classes/reflection-830.reflection-222.sas9apiclient.html
Normal file
File diff suppressed because one or more lines are too long
1721
docs/classes/reflection-830.reflection-222.sasjs.html
Normal file
1721
docs/classes/reflection-830.reflection-222.sasjs.html
Normal file
File diff suppressed because one or more lines are too long
1528
docs/classes/reflection-830.reflection-222.sasviyaapiclient.html
Normal file
1528
docs/classes/reflection-830.reflection-222.sasviyaapiclient.html
Normal file
File diff suppressed because one or more lines are too long
360
docs/classes/reflection-830.reflection-222.sessionmanager.html
Normal file
360
docs/classes/reflection-830.reflection-222.sessionmanager.html
Normal file
File diff suppressed because one or more lines are too long
548
docs/classes/request.requestclient.html
Normal file
548
docs/classes/request.requestclient.html
Normal file
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
328
docs/classes/types.authorizeerror.html
Normal file
328
docs/classes/types.authorizeerror.html
Normal file
File diff suppressed because one or more lines are too long
346
docs/classes/types.computejobexecutionerror.html
Normal file
346
docs/classes/types.computejobexecutionerror.html
Normal file
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
367
docs/classes/types.jobexecutionerror.html
Normal file
367
docs/classes/types.jobexecutionerror.html
Normal file
File diff suppressed because one or more lines are too long
301
docs/classes/types.loginrequirederror.html
Normal file
301
docs/classes/types.loginrequirederror.html
Normal file
File diff suppressed because one or more lines are too long
325
docs/classes/types.notfounderror.html
Normal file
325
docs/classes/types.notfounderror.html
Normal file
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
302
docs/interfaces/job_execution.jobexecutor.html
Normal file
302
docs/interfaces/job_execution.jobexecutor.html
Normal file
File diff suppressed because one or more lines are too long
392
docs/interfaces/request.httpclient.html
Normal file
392
docs/interfaces/request.httpclient.html
Normal file
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
94
docs/modules/__mocks__.html
Normal file
94
docs/modules/__mocks__.html
Normal file
File diff suppressed because one or more lines are too long
179
docs/modules/auth.html
Normal file
179
docs/modules/auth.html
Normal file
File diff suppressed because one or more lines are too long
144
docs/modules/auth_spec.html
Normal file
144
docs/modules/auth_spec.html
Normal file
File diff suppressed because one or more lines are too long
184
docs/modules/file.html
Normal file
184
docs/modules/file.html
Normal file
File diff suppressed because one or more lines are too long
171
docs/modules/job_execution.html
Normal file
171
docs/modules/job_execution.html
Normal file
File diff suppressed because one or more lines are too long
106
docs/modules/reflection-817.html
Normal file
106
docs/modules/reflection-817.html
Normal file
File diff suppressed because one or more lines are too long
128
docs/modules/reflection-817.reflection-220.html
Normal file
128
docs/modules/reflection-817.reflection-220.html
Normal file
File diff suppressed because one or more lines are too long
106
docs/modules/reflection-830.html
Normal file
106
docs/modules/reflection-830.html
Normal file
File diff suppressed because one or more lines are too long
128
docs/modules/reflection-830.reflection-222.html
Normal file
128
docs/modules/reflection-830.reflection-222.html
Normal file
File diff suppressed because one or more lines are too long
118
docs/modules/request.html
Normal file
118
docs/modules/request.html
Normal file
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
17392
package-lock.json
generated
17392
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@@ -43,23 +43,23 @@
|
||||
"jest-extended": "^0.11.5",
|
||||
"path": "^0.12.7",
|
||||
"rimraf": "^3.0.2",
|
||||
"semantic-release": "^17.3.9",
|
||||
"semantic-release": "^17.4.1",
|
||||
"terser-webpack-plugin": "^4.2.3",
|
||||
"ts-jest": "^25.5.1",
|
||||
"ts-loader": "^8.0.17",
|
||||
"tslint": "^6.1.3",
|
||||
"tslint-config-prettier": "^1.18.0",
|
||||
"typedoc": "^0.19.2",
|
||||
"typedoc": "^0.20.30",
|
||||
"typedoc-neo-theme": "^1.1.0",
|
||||
"typedoc-plugin-external-module-name": "^4.0.6",
|
||||
"typescript": "^3.9.9",
|
||||
"webpack": "^5.21.2",
|
||||
"webpack": "^5.24.4",
|
||||
"webpack-cli": "^4.5.0"
|
||||
},
|
||||
"main": "index.js",
|
||||
"dependencies": {
|
||||
"@sasjs/utils": "^2.6.3",
|
||||
"axios": "^0.21.1",
|
||||
"@sasjs/utils": "^2.5.0",
|
||||
"form-data": "^3.0.0",
|
||||
"https": "^1.0.0"
|
||||
}
|
||||
|
||||
88
sasjs-tests/package-lock.json
generated
88
sasjs-tests/package-lock.json
generated
@@ -2004,21 +2004,19 @@
|
||||
}
|
||||
},
|
||||
"@sasjs/adapter": {
|
||||
"version": "2.1.0",
|
||||
"resolved": "https://registry.npmjs.org/@sasjs/adapter/-/adapter-2.1.0.tgz",
|
||||
"integrity": "sha512-FdvxAPzXHHwCurH5B1RxSGeO6h+lVqDGAtrTAQDByT7HhsikAMFi6mW5dJR/1CKcI2rLOdE/479yYqjwfX8nwg==",
|
||||
"version": "file:../build/sasjs-adapter-5.0.0.tgz",
|
||||
"integrity": "sha512-1t+3LIL2BFw8HpZUPI9QM24801+JH4DCAu4eHoLLmytYhN72asMi1aVtgSDb1xiJYgpbTG7EK3qRpHIV8cEN8w==",
|
||||
"requires": {
|
||||
"@sasjs/utils": "^2.0.2",
|
||||
"es6-promise": "^4.2.8",
|
||||
"@sasjs/utils": "^2.5.0",
|
||||
"axios": "^0.21.1",
|
||||
"form-data": "^3.0.0",
|
||||
"https": "^1.0.0",
|
||||
"isomorphic-fetch": "^2.2.1"
|
||||
"https": "^1.0.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"form-data": {
|
||||
"version": "3.0.0",
|
||||
"resolved": "https://registry.npmjs.org/form-data/-/form-data-3.0.0.tgz",
|
||||
"integrity": "sha512-CKMFDglpbMi6PyN+brwB9Q/GOw0eAnsrEZDgcsH5Krhz5Od/haKHAX0NmQfha2zPPz0JpWzA7GJHGSnvCRLWsg==",
|
||||
"version": "3.0.1",
|
||||
"resolved": "https://registry.npmjs.org/form-data/-/form-data-3.0.1.tgz",
|
||||
"integrity": "sha512-RHkBKtLWUVwd7SqRIvCZMEvAMoGUp0XU+seQiZejj0COz3RI3hWP4sCv3gZWWLjJTd7rGwcsF5eKZGii0r/hbg==",
|
||||
"requires": {
|
||||
"asynckit": "^0.4.0",
|
||||
"combined-stream": "^1.0.8",
|
||||
@@ -2048,10 +2046,11 @@
|
||||
}
|
||||
},
|
||||
"@sasjs/utils": {
|
||||
"version": "2.2.0",
|
||||
"resolved": "https://registry.npmjs.org/@sasjs/utils/-/utils-2.2.0.tgz",
|
||||
"integrity": "sha512-T01TYAFU+WQ1uAUaunZXg0MotQe5jn3auVuMPPbY5RU5VhIn4oVhr6qz3EHyNsYYKD1aj5pP7w2elnBzkgWhGw==",
|
||||
"version": "2.5.1",
|
||||
"resolved": "https://registry.npmjs.org/@sasjs/utils/-/utils-2.5.1.tgz",
|
||||
"integrity": "sha512-a3ISiUX8Yz7au4XYxq2KWf9ODT6nsIDbE4FEqS+AQ3McxZkfuAk4v+REXjOmIlcyQd4R4bufEK8XoB6AROn9sA==",
|
||||
"requires": {
|
||||
"@types/prompts": "^2.0.9",
|
||||
"consola": "^2.15.0",
|
||||
"prompts": "^2.4.0",
|
||||
"valid-url": "^1.0.9"
|
||||
@@ -2366,6 +2365,14 @@
|
||||
"resolved": "https://registry.npmjs.org/@types/prettier/-/prettier-2.1.6.tgz",
|
||||
"integrity": "sha512-6gOkRe7OIioWAXfnO/2lFiv+SJichKVSys1mSsgyrYHSEjk8Ctv4tSR/Odvnu+HWlH2C8j53dahU03XmQdd5fA=="
|
||||
},
|
||||
"@types/prompts": {
|
||||
"version": "2.0.9",
|
||||
"resolved": "https://registry.npmjs.org/@types/prompts/-/prompts-2.0.9.tgz",
|
||||
"integrity": "sha512-TORZP+FSjTYMWwKadftmqEn6bziN5RnfygehByGsjxoK5ydnClddtv6GikGWPvCm24oI+YBwck5WDxIIyNxUrA==",
|
||||
"requires": {
|
||||
"@types/node": "*"
|
||||
}
|
||||
},
|
||||
"@types/prop-types": {
|
||||
"version": "15.7.3",
|
||||
"resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.3.tgz",
|
||||
@@ -3396,6 +3403,14 @@
|
||||
"resolved": "https://registry.npmjs.org/axe-core/-/axe-core-4.1.1.tgz",
|
||||
"integrity": "sha512-5Kgy8Cz6LPC9DJcNb3yjAXTu3XihQgEdnIg50c//zOC/MyLP0Clg+Y8Sh9ZjjnvBrDZU4DgXS9C3T9r4/scGZQ=="
|
||||
},
|
||||
"axios": {
|
||||
"version": "0.21.1",
|
||||
"resolved": "https://registry.npmjs.org/axios/-/axios-0.21.1.tgz",
|
||||
"integrity": "sha512-dKQiRHxGD9PPRIUNIWvZhPTPpl1rf/OxTYKsqKUDjBwYylTvV7SjSHJb9ratfyzM6wCdLCOYLzs73qpg5c4iGA==",
|
||||
"requires": {
|
||||
"follow-redirects": "^1.10.0"
|
||||
}
|
||||
},
|
||||
"axobject-query": {
|
||||
"version": "2.2.0",
|
||||
"resolved": "https://registry.npmjs.org/axobject-query/-/axobject-query-2.2.0.tgz",
|
||||
@@ -4677,9 +4692,9 @@
|
||||
"integrity": "sha512-e54B99q/OUoH64zYYRf3HBP5z24G38h5D3qXu23JGRoigpX5Ss4r9ZnDk3g0Z8uQC2x2lPaJ+UlWBc1ZWBWdLg=="
|
||||
},
|
||||
"consola": {
|
||||
"version": "2.15.2",
|
||||
"resolved": "https://registry.npmjs.org/consola/-/consola-2.15.2.tgz",
|
||||
"integrity": "sha512-VxqWw5C8O/mQpZYtfaaSCDJcVK3AxyvQ26rhgvyAI4j/QJISh8DLwFS8GQU+9154u4ngyCsSlnyIAYJme9kQug=="
|
||||
"version": "2.15.3",
|
||||
"resolved": "https://registry.npmjs.org/consola/-/consola-2.15.3.tgz",
|
||||
"integrity": "sha512-9vAdYbHj6x2fLKC4+oPH0kFzY/orMZyG2Aj+kNylHxKGJ/Ed4dpNyAQYwJOdqO4zdM7XpVHmyejQDcQHrnuXbw=="
|
||||
},
|
||||
"console-browserify": {
|
||||
"version": "1.2.0",
|
||||
@@ -5722,24 +5737,6 @@
|
||||
"resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz",
|
||||
"integrity": "sha1-rT/0yG7C0CkyL1oCw6mmBslbP1k="
|
||||
},
|
||||
"encoding": {
|
||||
"version": "0.1.13",
|
||||
"resolved": "https://registry.npmjs.org/encoding/-/encoding-0.1.13.tgz",
|
||||
"integrity": "sha512-ETBauow1T35Y/WZMkio9jiM0Z5xjHHmJ4XmjZOq1l/dXz3lr2sRn87nJy20RupqSh1F2m3HHPSp8ShIPQJrJ3A==",
|
||||
"requires": {
|
||||
"iconv-lite": "^0.6.2"
|
||||
},
|
||||
"dependencies": {
|
||||
"iconv-lite": {
|
||||
"version": "0.6.2",
|
||||
"resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.2.tgz",
|
||||
"integrity": "sha512-2y91h5OpQlolefMPmUlivelittSWy0rP+oYVpn6A7GwVHNE8AWzoYOBNmlwks3LobaJxgHCYZAnyNo2GgpNRNQ==",
|
||||
"requires": {
|
||||
"safer-buffer": ">= 2.1.2 < 3.0.0"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"end-of-stream": {
|
||||
"version": "1.4.4",
|
||||
"resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.4.tgz",
|
||||
@@ -5882,11 +5879,6 @@
|
||||
"es6-symbol": "^3.1.1"
|
||||
}
|
||||
},
|
||||
"es6-promise": {
|
||||
"version": "4.2.8",
|
||||
"resolved": "https://registry.npmjs.org/es6-promise/-/es6-promise-4.2.8.tgz",
|
||||
"integrity": "sha512-HJDGx5daxeIvxdBxvG2cb9g4tEvwIk3i8+nhX0yGrYmZUzbkdg8QbDevheDB8gd0//uPj4c1EQua8Q+MViT0/w=="
|
||||
},
|
||||
"es6-symbol": {
|
||||
"version": "3.1.3",
|
||||
"resolved": "https://registry.npmjs.org/es6-symbol/-/es6-symbol-3.1.3.tgz",
|
||||
@@ -8584,15 +8576,6 @@
|
||||
"resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz",
|
||||
"integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8="
|
||||
},
|
||||
"isomorphic-fetch": {
|
||||
"version": "2.2.1",
|
||||
"resolved": "https://registry.npmjs.org/isomorphic-fetch/-/isomorphic-fetch-2.2.1.tgz",
|
||||
"integrity": "sha1-YRrhrPFPXoH3KVB0coGf6XM1WKk=",
|
||||
"requires": {
|
||||
"node-fetch": "^1.0.1",
|
||||
"whatwg-fetch": ">=0.10.0"
|
||||
}
|
||||
},
|
||||
"isstream": {
|
||||
"version": "0.1.2",
|
||||
"resolved": "https://registry.npmjs.org/isstream/-/isstream-0.1.2.tgz",
|
||||
@@ -11423,15 +11406,6 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"node-fetch": {
|
||||
"version": "1.7.3",
|
||||
"resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-1.7.3.tgz",
|
||||
"integrity": "sha512-NhZ4CsKx7cYm2vSrBAr2PvFOe6sWDf0UYLRqA6svUYg7+/TSfVAu49jYC4BvQ4Sms9SZgdqGBgroqfDhJdTyKQ==",
|
||||
"requires": {
|
||||
"encoding": "^0.1.11",
|
||||
"is-stream": "^1.0.1"
|
||||
}
|
||||
},
|
||||
"node-forge": {
|
||||
"version": "0.10.0",
|
||||
"resolved": "https://registry.npmjs.org/node-forge/-/node-forge-0.10.0.tgz",
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
"homepage": ".",
|
||||
"private": true,
|
||||
"dependencies": {
|
||||
"@sasjs/adapter": "^2.1.0",
|
||||
"@sasjs/adapter": "^2.2.4",
|
||||
"@sasjs/test-framework": "^1.4.0",
|
||||
"@types/jest": "^26.0.20",
|
||||
"@types/node": "^14.14.25",
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
"appLoc": "/Public/app",
|
||||
"serverType": "SASVIYA",
|
||||
"debug": false,
|
||||
"contextName": "SharedCompute",
|
||||
"contextName": "sasjs adapter compute context",
|
||||
"useComputeApi": true
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,6 +2,8 @@ import SASjs, { SASjsConfig } from "@sasjs/adapter";
|
||||
import { TestSuite } from "@sasjs/test-framework";
|
||||
import { ServerType } from "@sasjs/utils/types";
|
||||
|
||||
const stringData: any = { table1: [{ col1: "first col value" }] };
|
||||
|
||||
const defaultConfig: SASjsConfig = {
|
||||
serverUrl: window.location.origin,
|
||||
pathSAS9: "/SASStoredProcess/do",
|
||||
@@ -51,6 +53,36 @@ export const basicTests = (
|
||||
assertion: (response: any) =>
|
||||
response && response.isLoggedIn && response.userName === userName
|
||||
},
|
||||
{
|
||||
title: "Trigger login callback",
|
||||
description:
|
||||
"Should trigger required login callback and after successful login, it should finish the request",
|
||||
test: async () => {
|
||||
await adapter.logOut();
|
||||
|
||||
return await adapter.request("common/sendArr", stringData, null, () => {
|
||||
adapter.logIn(userName, password);
|
||||
});
|
||||
},
|
||||
assertion: (response: any) => {
|
||||
return response.table1[0][0] === stringData.table1[0].col1;
|
||||
}
|
||||
},
|
||||
{
|
||||
title: "Request with debug on",
|
||||
description:
|
||||
"Should complete successful request with debugging switched on",
|
||||
test: async () => {
|
||||
const config = {
|
||||
debug: true
|
||||
}
|
||||
|
||||
return await adapter.request("common/sendArr", stringData, config)
|
||||
},
|
||||
assertion: (response: any) => {
|
||||
return response.table1[0][0] === stringData.table1[0].col1;
|
||||
}
|
||||
},
|
||||
{
|
||||
title: "Default config",
|
||||
description:
|
||||
|
||||
@@ -21,6 +21,7 @@ import { isAuthorizeFormRequired } from './auth/isAuthorizeFormRequired'
|
||||
import { RequestClient } from './request/RequestClient'
|
||||
import { NotFoundError } from './types/NotFoundError'
|
||||
import { SasAuthResponse } from '@sasjs/utils/types'
|
||||
import { prefixMessage } from '@sasjs/utils/error'
|
||||
|
||||
/**
|
||||
* A client for interfacing with the SAS Viya REST API.
|
||||
@@ -280,25 +281,24 @@ export class SASViyaApiClient {
|
||||
'Content-Type': 'application/json'
|
||||
}
|
||||
|
||||
if (accessToken) {
|
||||
headers.Authorization = `Bearer ${accessToken}`
|
||||
}
|
||||
if (accessToken) headers.Authorization = `Bearer ${accessToken}`
|
||||
|
||||
let executionSessionId: string
|
||||
|
||||
const session = await this.sessionManager
|
||||
.getSession(accessToken)
|
||||
.catch((err) => {
|
||||
throw err
|
||||
throw prefixMessage(err, 'Error while getting session. ')
|
||||
})
|
||||
|
||||
executionSessionId = session!.id
|
||||
|
||||
if (printPid) {
|
||||
const { result: jobIdVariable } = await this.sessionManager.getVariable(
|
||||
executionSessionId,
|
||||
'SYSJOBID',
|
||||
accessToken
|
||||
)
|
||||
const { result: jobIdVariable } = await this.sessionManager
|
||||
.getVariable(executionSessionId, 'SYSJOBID', accessToken)
|
||||
.catch((err) => {
|
||||
throw prefixMessage(err, 'Error while getting session variable. ')
|
||||
})
|
||||
|
||||
if (jobIdVariable && jobIdVariable.value) {
|
||||
const relativeJobPath = this.rootFolderName
|
||||
@@ -331,6 +331,7 @@ export class SASViyaApiClient {
|
||||
}
|
||||
|
||||
let fileName
|
||||
|
||||
if (isRelativePath(jobPath)) {
|
||||
fileName = `exec-${
|
||||
jobPath.includes('/') ? jobPath.split('/')[1] : jobPath
|
||||
@@ -352,7 +353,7 @@ export class SASViyaApiClient {
|
||||
if (data) {
|
||||
if (JSON.stringify(data).includes(';')) {
|
||||
files = await this.uploadTables(data, accessToken).catch((err) => {
|
||||
throw err
|
||||
throw prefixMessage(err, 'Error while uploading tables. ')
|
||||
})
|
||||
|
||||
jobVariables['_webin_file_count'] = files.length
|
||||
@@ -376,19 +377,18 @@ export class SASViyaApiClient {
|
||||
variables: jobVariables,
|
||||
arguments: jobArguments
|
||||
}
|
||||
|
||||
const { result: postedJob, etag } = await this.requestClient
|
||||
.post<Job>(
|
||||
`/compute/sessions/${executionSessionId}/jobs`,
|
||||
jobRequestBody,
|
||||
accessToken
|
||||
)
|
||||
.catch((err: any) => {
|
||||
throw err
|
||||
.catch((err) => {
|
||||
throw prefixMessage(err, 'Error while posting job. ')
|
||||
})
|
||||
|
||||
if (!waitForResult) {
|
||||
return session
|
||||
}
|
||||
if (!waitForResult) return session
|
||||
|
||||
if (debug) {
|
||||
console.log(`Job has been submitted for '${fileName}'.`)
|
||||
@@ -404,7 +404,9 @@ export class SASViyaApiClient {
|
||||
etag,
|
||||
accessToken,
|
||||
pollOptions
|
||||
)
|
||||
).catch((err) => {
|
||||
throw prefixMessage(err, 'Error while polling job status. ')
|
||||
})
|
||||
|
||||
const { result: currentJob } = await this.requestClient
|
||||
.get<Job>(
|
||||
@@ -412,7 +414,7 @@ export class SASViyaApiClient {
|
||||
accessToken
|
||||
)
|
||||
.catch((err) => {
|
||||
throw err
|
||||
throw prefixMessage(err, 'Error while getting job. ')
|
||||
})
|
||||
|
||||
let jobResult
|
||||
@@ -427,7 +429,7 @@ export class SASViyaApiClient {
|
||||
res.result.items.map((i: any) => i.line).join('\n')
|
||||
)
|
||||
.catch((err) => {
|
||||
throw err
|
||||
throw prefixMessage(err, 'Error while getting log. ')
|
||||
})
|
||||
}
|
||||
|
||||
@@ -455,7 +457,7 @@ export class SASViyaApiClient {
|
||||
res.result.items.map((i: any) => i.line).join('\n')
|
||||
)
|
||||
.catch((err) => {
|
||||
throw err
|
||||
throw prefixMessage(err, 'Error while getting log. ')
|
||||
})
|
||||
|
||||
return Promise.reject({
|
||||
@@ -464,6 +466,7 @@ export class SASViyaApiClient {
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
result: JSON.stringify(e)
|
||||
}
|
||||
@@ -473,7 +476,7 @@ export class SASViyaApiClient {
|
||||
await this.sessionManager
|
||||
.clearSession(executionSessionId, accessToken)
|
||||
.catch((err) => {
|
||||
throw err
|
||||
throw prefixMessage(err, 'Error while clearing session. ')
|
||||
})
|
||||
|
||||
return { result: jobResult?.result, log }
|
||||
@@ -490,7 +493,7 @@ export class SASViyaApiClient {
|
||||
true
|
||||
)
|
||||
} else {
|
||||
throw e
|
||||
throw prefixMessage(e, 'Error while executing script. ')
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -814,9 +817,12 @@ export class SASViyaApiClient {
|
||||
? `${this.rootFolderName}/${folderPath}`
|
||||
: folderPath
|
||||
|
||||
await this.populateFolderMap(fullFolderPath, accessToken)
|
||||
await this.populateFolderMap(fullFolderPath, accessToken).catch((err) => {
|
||||
throw prefixMessage(err, 'Error while populating folder map. ')
|
||||
})
|
||||
|
||||
const jobFolder = this.folderMap.get(fullFolderPath)
|
||||
|
||||
if (!jobFolder) {
|
||||
throw new Error(
|
||||
`The folder '${fullFolderPath}' was not found on '${this.serverUrl}'`
|
||||
@@ -824,6 +830,7 @@ export class SASViyaApiClient {
|
||||
}
|
||||
|
||||
const headers: any = { 'Content-Type': 'application/json' }
|
||||
|
||||
if (!!accessToken) {
|
||||
headers.Authorization = `Bearer ${accessToken}`
|
||||
}
|
||||
@@ -847,10 +854,14 @@ export class SASViyaApiClient {
|
||||
|
||||
const {
|
||||
result: jobDefinition
|
||||
} = await this.requestClient.get<JobDefinition>(
|
||||
`${this.serverUrl}${jobDefinitionLink.href}`,
|
||||
accessToken
|
||||
)
|
||||
} = await this.requestClient
|
||||
.get<JobDefinition>(
|
||||
`${this.serverUrl}${jobDefinitionLink.href}`,
|
||||
accessToken
|
||||
)
|
||||
.catch((err) => {
|
||||
throw prefixMessage(err, 'Error while getting job definition. ')
|
||||
})
|
||||
|
||||
code = jobDefinition.code
|
||||
|
||||
@@ -861,6 +872,7 @@ export class SASViyaApiClient {
|
||||
if (!code) code = ''
|
||||
|
||||
const linesToExecute = code.replace(/\r\n/g, '\n').split('\n')
|
||||
|
||||
return await this.executeScript(
|
||||
sasJob,
|
||||
linesToExecute,
|
||||
@@ -965,7 +977,13 @@ export class SASViyaApiClient {
|
||||
postJobRequestBody,
|
||||
accessToken
|
||||
)
|
||||
const jobStatus = await this.pollJobState(postedJob, etag, accessToken)
|
||||
const jobStatus = await this.pollJobState(
|
||||
postedJob,
|
||||
etag,
|
||||
accessToken
|
||||
).catch((err) => {
|
||||
throw prefixMessage(err, 'Error while polling job status. ')
|
||||
})
|
||||
const { result: currentJob } = await this.requestClient.get<Job>(
|
||||
`${this.serverUrl}/jobExecution/jobs/${postedJob.id}`,
|
||||
accessToken
|
||||
@@ -1007,19 +1025,27 @@ export class SASViyaApiClient {
|
||||
}
|
||||
|
||||
const url = '/folders/folders/@item?path=' + path
|
||||
const { result: folder } = await this.requestClient.get<Folder>(
|
||||
`${url}`,
|
||||
accessToken
|
||||
)
|
||||
const { result: folder } = await this.requestClient
|
||||
.get<Folder>(`${url}`, accessToken)
|
||||
.catch((err) => {
|
||||
throw prefixMessage(err, 'Error while getting folder. ')
|
||||
})
|
||||
|
||||
if (!folder) {
|
||||
throw new Error(`The path ${path} does not exist on ${this.serverUrl}`)
|
||||
}
|
||||
const { result: members } = await this.requestClient.get<{ items: any[] }>(
|
||||
`/folders/folders/${folder.id}/members?limit=${folder.memberCount}`,
|
||||
accessToken
|
||||
)
|
||||
|
||||
const { result: members } = await this.requestClient
|
||||
.get<{ items: any[] }>(
|
||||
`/folders/folders/${folder.id}/members?limit=${folder.memberCount}`,
|
||||
accessToken
|
||||
)
|
||||
.catch((err) => {
|
||||
throw prefixMessage(err, 'Error while getting members. ')
|
||||
})
|
||||
|
||||
const itemsAtRoot = members.items
|
||||
|
||||
this.folderMap.set(path, itemsAtRoot)
|
||||
}
|
||||
|
||||
@@ -1052,11 +1078,15 @@ export class SASViyaApiClient {
|
||||
Promise.reject(`Job state link was not found.`)
|
||||
}
|
||||
|
||||
const { result: state } = await this.requestClient.get<string>(
|
||||
`${this.serverUrl}${stateLink.href}?_action=wait&wait=30`,
|
||||
accessToken,
|
||||
'text/plain'
|
||||
)
|
||||
const { result: state } = await this.requestClient
|
||||
.get<string>(
|
||||
`${this.serverUrl}${stateLink.href}?_action=wait&wait=30`,
|
||||
accessToken,
|
||||
'text/plain'
|
||||
)
|
||||
.catch((err) => {
|
||||
throw prefixMessage(err, 'Error while getting job state. ')
|
||||
})
|
||||
|
||||
const currentState = state.trim()
|
||||
if (currentState === 'completed') {
|
||||
@@ -1073,11 +1103,18 @@ export class SASViyaApiClient {
|
||||
postedJobState === 'pending'
|
||||
) {
|
||||
if (stateLink) {
|
||||
const { result: jobState } = await this.requestClient.get<string>(
|
||||
`${this.serverUrl}${stateLink.href}?_action=wait&wait=30`,
|
||||
accessToken,
|
||||
'text/plain'
|
||||
)
|
||||
const { result: jobState } = await this.requestClient
|
||||
.get<string>(
|
||||
`${this.serverUrl}${stateLink.href}?_action=wait&wait=30`,
|
||||
accessToken,
|
||||
'text/plain'
|
||||
)
|
||||
.catch((err) => {
|
||||
throw prefixMessage(
|
||||
err,
|
||||
'Error while getting job state after interval. '
|
||||
)
|
||||
})
|
||||
|
||||
postedJobState = jobState.trim()
|
||||
|
||||
@@ -1119,19 +1156,25 @@ export class SASViyaApiClient {
|
||||
)
|
||||
}
|
||||
|
||||
const uploadResponse = await this.requestClient.uploadFile(
|
||||
`${this.serverUrl}/files/files#rawUpload`,
|
||||
csv,
|
||||
accessToken
|
||||
)
|
||||
const uploadResponse = await this.requestClient
|
||||
.uploadFile(`${this.serverUrl}/files/files#rawUpload`, csv, accessToken)
|
||||
.catch((err) => {
|
||||
throw prefixMessage(err, 'Error while uploading file. ')
|
||||
})
|
||||
|
||||
uploadedFiles.push({ tableName, file: uploadResponse.result })
|
||||
}
|
||||
return uploadedFiles
|
||||
}
|
||||
|
||||
private async getFolderUri(folderPath: string, accessToken?: string) {
|
||||
const url = '/folders/folders/@item?path=' + folderPath
|
||||
private async getFolderDetails(
|
||||
folderPath: string,
|
||||
accessToken?: string
|
||||
): Promise<Folder | undefined> {
|
||||
const url = isUri(folderPath)
|
||||
? folderPath
|
||||
: `/folders/folders/@item?path=${folderPath}`
|
||||
|
||||
const { result: folder } = await this.requestClient
|
||||
.get<Folder>(`${this.serverUrl}${url}`, accessToken)
|
||||
.catch(() => {
|
||||
@@ -1139,7 +1182,15 @@ export class SASViyaApiClient {
|
||||
})
|
||||
|
||||
if (!folder) return undefined
|
||||
return `/folders/folders/${folder.id}`
|
||||
return folder
|
||||
}
|
||||
|
||||
private async getFolderUri(folderPath: string, accessToken?: string) {
|
||||
const folderDetails = await this.getFolderDetails(folderPath, accessToken)
|
||||
|
||||
if (!folderDetails) return undefined
|
||||
|
||||
return `/folders/folders/${folderDetails.id}`
|
||||
}
|
||||
|
||||
private async getRecycleBinUri(accessToken: string) {
|
||||
@@ -1188,9 +1239,44 @@ export class SASViyaApiClient {
|
||||
}
|
||||
|
||||
/**
|
||||
* Moves a Viya folder to a new location. The folder may be renamed at the same time.
|
||||
* Lists children folders for given Viya folder.
|
||||
* @param sourceFolder - the full path (eg `/Public/example/myFolder`) or URI of the source folder listed. Providing URI instead of path will save one extra request.
|
||||
* @param accessToken - an access token for authorizing the request.
|
||||
*/
|
||||
public async listFolder(
|
||||
sourceFolder: string,
|
||||
accessToken?: string,
|
||||
limit: number = 20
|
||||
) {
|
||||
// checks if 'sourceFolder' is already a URI
|
||||
const sourceFolderUri = isUri(sourceFolder)
|
||||
? sourceFolder
|
||||
: await this.getFolderUri(sourceFolder, accessToken)
|
||||
|
||||
const requestInfo = {
|
||||
method: 'GET',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
Authorization: 'Bearer ' + accessToken
|
||||
}
|
||||
}
|
||||
|
||||
const { result: members } = await this.requestClient.get<{ items: any[] }>(
|
||||
`${this.serverUrl}${sourceFolderUri}/members?limit=${limit}`,
|
||||
accessToken
|
||||
)
|
||||
|
||||
if (members && members.items) {
|
||||
return members.items.map((item: any) => item.name)
|
||||
} else {
|
||||
return []
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Moves Viya folder to a new location. The folder may be renamed at the same time.
|
||||
* @param sourceFolder - the full path (eg `/Public/example/myFolder`) or URI of the source folder to be moved. Providing URI instead of path will save one extra request.
|
||||
* @param targetParentFolder - the full path or URI of the _parent_ folder to which the `sourceFolder` will be moved (eg `/Public/newDestination`). To move a folder, a user has to have write permissions in targetParentFolder. Providing URI instead of path will save one extra request.
|
||||
* @param targetParentFolder - the full path or URI of the _parent_ folder to which the `sourceFolder` will be moved (eg `/Public/newDestination`). To move a folder, a user has to have write permissions in targetParentFolder. Providing URI instead of the path will save one extra request.
|
||||
* @param targetFolderName - the name of the "moved" folder. If left blank, the original folder name will be used (eg `myFolder` in `/Public/newDestination/myFolder` for the example above). Optional field.
|
||||
* @param accessToken - an access token for authorizing the request.
|
||||
*/
|
||||
@@ -1200,22 +1286,35 @@ export class SASViyaApiClient {
|
||||
targetFolderName: string,
|
||||
accessToken: string
|
||||
) {
|
||||
// checks if 'sourceFolder' is already a URI
|
||||
const sourceFolderUri = isUri(sourceFolder)
|
||||
? sourceFolder
|
||||
: await this.getFolderUri(sourceFolder, accessToken)
|
||||
// If target path is an existing folder, than keep source folder name, othervise rename it with given target folder name
|
||||
const sourceFolderName = sourceFolder.split('/').pop() as string
|
||||
const targetFolderDetails = await this.getFolderDetails(
|
||||
targetParentFolder,
|
||||
accessToken
|
||||
)
|
||||
|
||||
if (!targetFolderDetails) {
|
||||
let targetParentFolderArr = targetParentFolder.split('/')
|
||||
targetParentFolderArr.splice(targetParentFolderArr.length - 1, 1)
|
||||
targetParentFolder = targetParentFolderArr.join('/')
|
||||
} else {
|
||||
targetFolderName = sourceFolderName
|
||||
}
|
||||
|
||||
// checks if 'sourceFolder' is already an URI
|
||||
const sourceFolderUri = await this.getFolderUri(sourceFolder, accessToken)
|
||||
|
||||
// checks if 'targetParentFolder' is already a URI
|
||||
const targetParentFolderUri = isUri(targetParentFolder)
|
||||
? targetParentFolder
|
||||
: await this.getFolderUri(targetParentFolder, accessToken)
|
||||
const targetParentFolderUri = await this.getFolderUri(
|
||||
targetParentFolder,
|
||||
accessToken
|
||||
)
|
||||
|
||||
const sourceFolderId = sourceFolderUri?.split('/').pop()
|
||||
const url = sourceFolderUri
|
||||
|
||||
const { result: folder } = await this.requestClient
|
||||
.patch<Folder>(
|
||||
`${this.serverUrl}${url}`,
|
||||
`${this.serverUrl}${sourceFolderUri}`,
|
||||
{
|
||||
id: sourceFolderId,
|
||||
name: targetFolderName,
|
||||
|
||||
19
src/SASjs.ts
19
src/SASjs.ts
@@ -317,6 +317,25 @@ export default class SASjs {
|
||||
return await this.sasViyaApiClient?.deleteFolder(folderPath, accessToken)
|
||||
}
|
||||
|
||||
/**
|
||||
* Lists children folders for given Viya folder.
|
||||
* @param sourceFolder - the full path (eg `/Public/example/myFolder`) or URI of the source folder listed. Providing URI instead of path will save one extra request.
|
||||
* @param accessToken - an access token for authorizing the request.
|
||||
*/
|
||||
public async listFolder(
|
||||
sourceFolder: string,
|
||||
accessToken?: string,
|
||||
limit?: number
|
||||
) {
|
||||
this.isMethodSupported('listFolder', ServerType.SasViya)
|
||||
|
||||
return await this.sasViyaApiClient?.listFolder(
|
||||
sourceFolder,
|
||||
accessToken,
|
||||
limit
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Moves folder to a new location. The folder may be renamed at the same time.
|
||||
* @param sourceFolder - the full path (eg `/Public/example/myFolder`) or URI of the source folder to be moved. Providing URI instead of path will save one extra request.
|
||||
|
||||
@@ -64,7 +64,7 @@ export class SessionManager {
|
||||
this.sessions = this.sessions.filter((s) => s.id !== id)
|
||||
})
|
||||
.catch((err) => {
|
||||
throw err
|
||||
throw prefixMessage(err, 'Error while deleting session. ')
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
@@ -20,35 +20,52 @@ export class ComputeJobExecutor extends BaseJobExecutor {
|
||||
const waitForResult = true
|
||||
const expectWebout = true
|
||||
|
||||
return this.sasViyaApiClient
|
||||
?.executeComputeJob(
|
||||
sasJob,
|
||||
config.contextName,
|
||||
config.debug,
|
||||
data,
|
||||
accessToken,
|
||||
waitForResult,
|
||||
expectWebout
|
||||
)
|
||||
.then((response) => {
|
||||
this.appendRequest(response, sasJob, config.debug)
|
||||
let responseJson
|
||||
const requestPromise = new Promise((resolve, reject) => {
|
||||
this.sasViyaApiClient
|
||||
?.executeComputeJob(
|
||||
sasJob,
|
||||
config.contextName,
|
||||
config.debug,
|
||||
data,
|
||||
accessToken,
|
||||
waitForResult,
|
||||
expectWebout
|
||||
)
|
||||
.then((response) => {
|
||||
this.appendRequest(response, sasJob, config.debug)
|
||||
|
||||
return response.result
|
||||
resolve(response.result)
|
||||
})
|
||||
.catch(async (e: Error) => {
|
||||
if (e instanceof ComputeJobExecutionError) {
|
||||
this.appendRequest(e, sasJob, config.debug)
|
||||
|
||||
return responseJson
|
||||
})
|
||||
.catch(async (e: Error) => {
|
||||
if (e instanceof ComputeJobExecutionError) {
|
||||
this.appendRequest(e, sasJob, config.debug)
|
||||
}
|
||||
if (e instanceof LoginRequiredError) {
|
||||
await loginCallback()
|
||||
this.appendWaitingRequest(() =>
|
||||
this.execute(sasJob, data, config, loginRequiredCallback)
|
||||
)
|
||||
}
|
||||
return Promise.reject(new ErrorResponse(e?.message, e))
|
||||
})
|
||||
reject(new ErrorResponse(e?.message, e))
|
||||
}
|
||||
|
||||
if (e instanceof LoginRequiredError) {
|
||||
await loginCallback()
|
||||
this.appendWaitingRequest(() => {
|
||||
return this.execute(
|
||||
sasJob,
|
||||
data,
|
||||
config,
|
||||
loginRequiredCallback
|
||||
).then(
|
||||
(res: any) => {
|
||||
resolve(res)
|
||||
},
|
||||
(err: any) => {
|
||||
reject(err)
|
||||
}
|
||||
)
|
||||
})
|
||||
} else {
|
||||
reject(new ErrorResponse(e?.message, e))
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
return requestPromise
|
||||
}
|
||||
}
|
||||
|
||||
@@ -17,24 +17,52 @@ export class JesJobExecutor extends BaseJobExecutor {
|
||||
accessToken?: string
|
||||
) {
|
||||
const loginCallback = loginRequiredCallback || (() => Promise.resolve())
|
||||
return await this.sasViyaApiClient
|
||||
?.executeJob(sasJob, config.contextName, config.debug, data, accessToken)
|
||||
.then((response) => {
|
||||
this.appendRequest(response, sasJob, config.debug)
|
||||
|
||||
return response.result
|
||||
})
|
||||
.catch(async (e: Error) => {
|
||||
if (e instanceof JobExecutionError) {
|
||||
this.appendRequest(e, sasJob, config.debug)
|
||||
}
|
||||
if (e instanceof LoginRequiredError) {
|
||||
await loginCallback()
|
||||
this.appendWaitingRequest(() =>
|
||||
this.execute(sasJob, data, config, loginRequiredCallback)
|
||||
)
|
||||
}
|
||||
return Promise.reject(new ErrorResponse(e?.message, e))
|
||||
})
|
||||
const requestPromise = new Promise((resolve, reject) => {
|
||||
this.sasViyaApiClient
|
||||
?.executeJob(
|
||||
sasJob,
|
||||
config.contextName,
|
||||
config.debug,
|
||||
data,
|
||||
accessToken
|
||||
)
|
||||
.then((response) => {
|
||||
this.appendRequest(response, sasJob, config.debug)
|
||||
|
||||
resolve(response.result)
|
||||
})
|
||||
.catch(async (e: Error) => {
|
||||
if (e instanceof JobExecutionError) {
|
||||
this.appendRequest(e, sasJob, config.debug)
|
||||
|
||||
reject(new ErrorResponse(e?.message, e))
|
||||
}
|
||||
|
||||
if (e instanceof LoginRequiredError) {
|
||||
await loginCallback()
|
||||
|
||||
this.appendWaitingRequest(() => {
|
||||
return this.execute(
|
||||
sasJob,
|
||||
data,
|
||||
config,
|
||||
loginRequiredCallback
|
||||
).then(
|
||||
(res: any) => {
|
||||
resolve(res)
|
||||
},
|
||||
(err: any) => {
|
||||
reject(err)
|
||||
}
|
||||
)
|
||||
})
|
||||
} else {
|
||||
reject(new ErrorResponse(e?.message, e))
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
return requestPromise
|
||||
}
|
||||
}
|
||||
|
||||
@@ -7,6 +7,11 @@ import { SASViyaApiClient } from '../SASViyaApiClient'
|
||||
import { isRelativePath } from '../utils'
|
||||
import { BaseJobExecutor } from './JobExecutor'
|
||||
|
||||
export interface WaitingRequstPromise {
|
||||
promise: Promise<any> | null
|
||||
resolve: any
|
||||
reject: any
|
||||
}
|
||||
export class WebJobExecutor extends BaseJobExecutor {
|
||||
constructor(
|
||||
serverUrl: string,
|
||||
@@ -80,30 +85,51 @@ export class WebJobExecutor extends BaseJobExecutor {
|
||||
}
|
||||
}
|
||||
|
||||
return this.requestClient!.post(apiUrl, formData, undefined)
|
||||
.then(async (res) => {
|
||||
if (this.serverType === ServerType.SasViya && config.debug) {
|
||||
const jsonResponse = await this.parseSasViyaDebugResponse(
|
||||
res.result as string
|
||||
)
|
||||
const requestPromise = new Promise((resolve, reject) => {
|
||||
this.requestClient!.post(apiUrl, formData, undefined)
|
||||
.then(async (res) => {
|
||||
if (this.serverType === ServerType.SasViya && config.debug) {
|
||||
const jsonResponse = await this.parseSasViyaDebugResponse(
|
||||
res.result as string
|
||||
)
|
||||
this.appendRequest(res, sasJob, config.debug)
|
||||
resolve(jsonResponse)
|
||||
}
|
||||
this.appendRequest(res, sasJob, config.debug)
|
||||
return jsonResponse
|
||||
}
|
||||
this.appendRequest(res, sasJob, config.debug)
|
||||
return res.result
|
||||
})
|
||||
.catch(async (e: Error) => {
|
||||
if (e instanceof JobExecutionError) {
|
||||
this.appendRequest(e, sasJob, config.debug)
|
||||
}
|
||||
if (e instanceof LoginRequiredError) {
|
||||
await loginCallback()
|
||||
this.appendWaitingRequest(() =>
|
||||
this.execute(sasJob, data, config, loginRequiredCallback)
|
||||
)
|
||||
}
|
||||
return Promise.reject(new ErrorResponse(e?.message, e))
|
||||
})
|
||||
resolve(res.result)
|
||||
})
|
||||
.catch(async (e: Error) => {
|
||||
if (e instanceof JobExecutionError) {
|
||||
this.appendRequest(e, sasJob, config.debug)
|
||||
|
||||
reject(new ErrorResponse(e?.message, e))
|
||||
}
|
||||
|
||||
if (e instanceof LoginRequiredError) {
|
||||
await loginCallback()
|
||||
|
||||
this.appendWaitingRequest(() => {
|
||||
return this.execute(
|
||||
sasJob,
|
||||
data,
|
||||
config,
|
||||
loginRequiredCallback
|
||||
).then(
|
||||
(res: any) => {
|
||||
resolve(res)
|
||||
},
|
||||
(err: any) => {
|
||||
reject(err)
|
||||
}
|
||||
)
|
||||
})
|
||||
} else {
|
||||
reject(new ErrorResponse(e?.message, e))
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
return requestPromise
|
||||
}
|
||||
|
||||
private parseSasViyaDebugResponse = async (response: string) => {
|
||||
|
||||
@@ -5,6 +5,7 @@ import { LoginRequiredError } from '../types'
|
||||
import { AuthorizeError } from '../types/AuthorizeError'
|
||||
import { NotFoundError } from '../types/NotFoundError'
|
||||
import { parseWeboutResponse } from '../utils/parseWeboutResponse'
|
||||
import { prefixMessage } from '@sasjs/utils/error'
|
||||
|
||||
export interface HttpClient {
|
||||
get<T>(
|
||||
@@ -96,8 +97,18 @@ export class RequestClient implements HttpClient {
|
||||
})
|
||||
.catch(async (e) => {
|
||||
return await this.handleError(e, () =>
|
||||
this.get<T>(url, accessToken, contentType, overrideHeaders)
|
||||
)
|
||||
this.get<T>(url, accessToken, contentType, overrideHeaders).catch(
|
||||
(err) => {
|
||||
throw prefixMessage(
|
||||
err,
|
||||
'Error while executing handle error callback. '
|
||||
)
|
||||
}
|
||||
)
|
||||
).catch((err) => {
|
||||
console.log(`[err]`, err)
|
||||
throw prefixMessage(err, 'Error while handling error. ')
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
@@ -331,35 +342,59 @@ export class RequestClient implements HttpClient {
|
||||
|
||||
private handleError = async (e: any, callback: any) => {
|
||||
const response = e.response as AxiosResponse
|
||||
|
||||
if (e instanceof AuthorizeError) {
|
||||
const res = await this.httpClient.get(e.confirmUrl, {
|
||||
responseType: 'text',
|
||||
headers: { 'Content-Type': 'text/plain', Accept: '*/*' }
|
||||
})
|
||||
const res = await this.httpClient
|
||||
.get(e.confirmUrl, {
|
||||
responseType: 'text',
|
||||
headers: { 'Content-Type': 'text/plain', Accept: '*/*' }
|
||||
})
|
||||
.catch((err) => {
|
||||
throw prefixMessage(err, 'Error while getting error confirmUrl. ')
|
||||
})
|
||||
|
||||
if (isAuthorizeFormRequired(res?.data as string)) {
|
||||
await this.authorize(res.data as string)
|
||||
await this.authorize(res.data as string).catch((err) => {
|
||||
throw prefixMessage(err, 'Error while authorizing request. ')
|
||||
})
|
||||
}
|
||||
return await callback()
|
||||
|
||||
return await callback().catch((err: any) => {
|
||||
throw prefixMessage(
|
||||
err,
|
||||
'Error while executing callback in handleError. '
|
||||
)
|
||||
})
|
||||
}
|
||||
|
||||
if (e instanceof LoginRequiredError) {
|
||||
this.clearCsrfTokens()
|
||||
}
|
||||
|
||||
if (response?.status === 403 || response?.status === 449) {
|
||||
this.parseAndSetCsrfToken(response)
|
||||
|
||||
if (this.csrfToken.headerName && this.csrfToken.value) {
|
||||
return await callback()
|
||||
return await callback().catch((err: any) => {
|
||||
throw prefixMessage(
|
||||
err,
|
||||
'Error while executing callback in handleError. '
|
||||
)
|
||||
})
|
||||
}
|
||||
|
||||
throw e
|
||||
} else if (response?.status === 404) {
|
||||
throw new NotFoundError(response.config.url!)
|
||||
}
|
||||
|
||||
throw e
|
||||
}
|
||||
|
||||
private async parseResponse<T>(response: AxiosResponse<any>) {
|
||||
private parseResponse<T>(response: AxiosResponse<any>) {
|
||||
const etag = response?.headers ? response.headers['etag'] : ''
|
||||
let parsedResponse
|
||||
let includeSAS9Log: boolean = false
|
||||
|
||||
try {
|
||||
if (typeof response.data === 'string') {
|
||||
@@ -373,11 +408,20 @@ export class RequestClient implements HttpClient {
|
||||
} catch {
|
||||
parsedResponse = response.data
|
||||
}
|
||||
|
||||
includeSAS9Log = true
|
||||
}
|
||||
return {
|
||||
|
||||
let responseToReturn: { result: T; etag: any; log?: string } = {
|
||||
result: parsedResponse as T,
|
||||
etag
|
||||
}
|
||||
|
||||
if (includeSAS9Log) {
|
||||
responseToReturn.log = response.data
|
||||
}
|
||||
|
||||
return responseToReturn
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
83
src/test/FolderOperations.spec.ts
Normal file
83
src/test/FolderOperations.spec.ts
Normal file
@@ -0,0 +1,83 @@
|
||||
import { RequestClient } from '../request/RequestClient'
|
||||
import { SASViyaApiClient } from '../SASViyaApiClient'
|
||||
import axios from 'axios'
|
||||
jest.mock('axios')
|
||||
const mockedAxios = axios as jest.Mocked<typeof axios>
|
||||
|
||||
describe('FolderOperations', () => {
|
||||
const sasViyaApiClient = new SASViyaApiClient(
|
||||
'https://sample.server.com',
|
||||
'/Public',
|
||||
'Context',
|
||||
new RequestClient('https://sample.server.com')
|
||||
)
|
||||
|
||||
beforeEach(() => {})
|
||||
|
||||
it('should move and rename folder', async (done) => {
|
||||
mockFetchResponse(false)
|
||||
|
||||
let res: any = await sasViyaApiClient.moveFolder(
|
||||
'/Test/fromFolder/oldName',
|
||||
'/Test/toFolder/newName',
|
||||
'newName',
|
||||
'token'
|
||||
)
|
||||
|
||||
expect(res.folder.name).toEqual('newName')
|
||||
expect(res.folder.parentFolderUri.split('=')[1]).toEqual('/Test/toFolder')
|
||||
|
||||
done()
|
||||
})
|
||||
|
||||
it('should move and keep the name of folder', async (done) => {
|
||||
mockFetchResponse(true)
|
||||
|
||||
let res: any = await sasViyaApiClient.moveFolder(
|
||||
'/Test/fromFolder/oldName',
|
||||
'/Test/toFolder',
|
||||
'toFolder',
|
||||
'token'
|
||||
)
|
||||
|
||||
expect(res.folder.name).toEqual('oldName')
|
||||
expect(res.folder.parentFolderUri.split('=')[1]).toEqual('/Test/toFolder')
|
||||
|
||||
done()
|
||||
})
|
||||
|
||||
it('should only rename folder', async (done) => {
|
||||
mockFetchResponse(false)
|
||||
|
||||
let res: any = await sasViyaApiClient.moveFolder(
|
||||
'/Test/toFolder/oldName',
|
||||
'/Test/toFolder/newName',
|
||||
'newName',
|
||||
'token'
|
||||
)
|
||||
|
||||
expect(res.folder.name).toEqual('newName')
|
||||
expect(res.folder.parentFolderUri.split('=')[1]).toEqual('/Test/toFolder')
|
||||
|
||||
done()
|
||||
})
|
||||
})
|
||||
|
||||
const mockFetchResponse = (targetFolderExists: boolean) => {
|
||||
mockedAxios.patch.mockImplementation((url: any, request: any) => {
|
||||
return Promise.resolve({ status: 200, data: { folder: request } })
|
||||
})
|
||||
|
||||
mockedAxios.get.mockImplementation((url: any, request: any) => {
|
||||
if (!targetFolderExists && url.includes('newName')) {
|
||||
return Promise.resolve(undefined)
|
||||
}
|
||||
|
||||
return Promise.resolve({
|
||||
status: 200,
|
||||
data: {
|
||||
id: url
|
||||
}
|
||||
})
|
||||
})
|
||||
}
|
||||
@@ -29,7 +29,10 @@ describe('SessionManager', () => {
|
||||
Promise.resolve({ data: sampleResponse })
|
||||
)
|
||||
|
||||
const expectedResponse = { etag: '', result: sampleResponse }
|
||||
const expectedResponse = {
|
||||
etag: '',
|
||||
result: sampleResponse
|
||||
}
|
||||
|
||||
await expect(
|
||||
sessionManager.getVariable(
|
||||
|
||||
Reference in New Issue
Block a user