mirror of
https://github.com/sasjs/adapter.git
synced 2026-01-04 19:20:05 +00:00
Compare commits
70 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
0aa0ae65e0 | ||
|
|
4b0d62d59b | ||
|
|
b3ef50e9eb | ||
|
|
d30a1890a1 | ||
|
|
f1c2569de3 | ||
|
|
4826388cdd | ||
| e88736056a | |||
| 9da2a29a72 | |||
| dce8a08a86 | |||
| 1fabb9e610 | |||
| 23db0ac80d | |||
| 28370341d8 | |||
|
|
a023ffe850 | ||
|
|
a4e77ecf6e | ||
|
|
7efc0a1fb2 | ||
|
|
c3e2b2ce70 | ||
|
|
dde1228b1d | ||
|
|
b3474b6dfb | ||
|
|
179a04ae31 | ||
|
|
2bdcbda54c | ||
|
|
a123392c56 | ||
|
|
719135e366 | ||
|
|
ba619554b7 | ||
|
|
6a3ab7032f | ||
|
|
d818d14cb4 | ||
|
|
599c130395 | ||
|
|
9ef2759e27 | ||
|
|
43355c88d4 | ||
|
|
15e1acaf4f | ||
|
|
ec77ffdd88 | ||
|
|
9797c1ca84 | ||
|
|
bbe9633dc8 | ||
|
|
6f60ac5cc7 | ||
|
|
e7ba09793c | ||
|
|
c0c0800e61 | ||
|
|
0bd9d8f93f | ||
|
|
214fc2d5cd | ||
|
|
55b0e2f934 | ||
|
|
609cd4ed6d | ||
|
|
2b20bbdcc8 | ||
|
|
946a95bea1 | ||
|
|
7ec1c152e3 | ||
|
|
0cf1110018 | ||
|
|
9c5ada6fa1 | ||
|
|
0f5702e21b | ||
|
|
f10d6ec80a | ||
|
|
490215df90 | ||
|
|
9d27451813 | ||
|
|
a977f59675 | ||
|
|
51a09d049c | ||
|
|
47be5e77e5 | ||
|
|
d517e79ec0 | ||
|
|
8714ecdde8 | ||
|
|
2cffc57209 | ||
|
|
4e43687de2 | ||
|
|
f8dab83e37 | ||
|
|
655af03cf3 | ||
|
|
0a4dd00edb | ||
|
|
55b4929c54 | ||
|
|
8eb73a6b3c | ||
|
|
0aeb201625 | ||
|
|
349612a065 | ||
|
|
e48b22128d | ||
|
|
14dfe4ec51 | ||
|
|
e0051bf276 | ||
|
|
7b72998e1c | ||
|
|
66d02cf1d1 | ||
|
|
f2c8e40430 | ||
|
|
4b28ee8e73 | ||
|
|
c7e54cfe9f |
161
README.md
161
README.md
@@ -6,7 +6,7 @@ SASjs is a open-source framework for building Web Apps on SAS® platforms. You c
|
|||||||
|
|
||||||
1 - `npm install @sasjs/adapter` - for use in a node project
|
1 - `npm install @sasjs/adapter` - for use in a node project
|
||||||
|
|
||||||
2 - [Download](https://cdn.jsdelivr.net/npm/@sasjs/adapter@1/index.js) and use a copy of the latest JS file
|
2 - [Download](https://cdn.jsdelivr.net/npm/@sasjs/adapter@2/index.js) and use a copy of the latest JS file
|
||||||
|
|
||||||
3 - Reference directly from the CDN - in which case click [here](https://www.jsdelivr.com/package/npm/@sasjs/adapter?tab=collection) and select "SRI" to get the script tag with the integrity hash.
|
3 - Reference directly from the CDN - in which case click [here](https://www.jsdelivr.com/package/npm/@sasjs/adapter?tab=collection) and select "SRI" to get the script tag with the integrity hash.
|
||||||
|
|
||||||
@@ -41,8 +41,165 @@ parmcards4;
|
|||||||
|
|
||||||
You now have a simple web app with a backend service!
|
You now have a simple web app with a backend service!
|
||||||
|
|
||||||
|
## Detailed Overview
|
||||||
|
|
||||||
|
The SASjs adapter is a JS library and a set of SAS Macros that handle the communication between the frontend app and backend SAS services.
|
||||||
|
|
||||||
|
There are three parts to consider:
|
||||||
|
|
||||||
|
1. JS request / response
|
||||||
|
2. SAS inputs / outputs
|
||||||
|
3. Configuration
|
||||||
|
|
||||||
|
### JS Request / Response
|
||||||
|
|
||||||
|
To install the library you can simply run `npm i @sasjs/adapter` or include a `<script>` tag with a reference to our [CDN](https://www.jsdelivr.com/package/npm/@sasjs/adapter).
|
||||||
|
|
||||||
|
Full technical documentation is available [here](https://adapter.sasjs.io). The main parts are:
|
||||||
|
|
||||||
|
### Instantiation
|
||||||
|
The following code will instantiate an instance of the adapter:
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
let sasJs = new SASjs.default(
|
||||||
|
{
|
||||||
|
appLoc: "/Your/SAS/Folder",
|
||||||
|
serverType:"SAS9"
|
||||||
|
}
|
||||||
|
);
|
||||||
|
```
|
||||||
|
If you've installed it via NPM, you can import it as a default import like so:
|
||||||
|
```
|
||||||
|
import SASjs from '@sasjs/adapter';
|
||||||
|
```
|
||||||
|
You can then instantiate it with:
|
||||||
|
```
|
||||||
|
const sasJs = new SASjs({your config})
|
||||||
|
```
|
||||||
|
|
||||||
|
More on the config later.
|
||||||
|
|
||||||
|
### SAS Logon
|
||||||
|
The login process can be handled directly, as below, or as a callback function to a SAS request.
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
sasJs.logIn('USERNAME','PASSWORD'
|
||||||
|
).then((response) => {
|
||||||
|
if (response.isLoggedIn === true) {
|
||||||
|
console.log('do stuff')
|
||||||
|
} else {
|
||||||
|
console.log('do other stuff')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### Request / Response
|
||||||
|
A simple request can be sent to SAS in the following fashion:
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
sasJs.request("/path/to/my/service", dataObject)
|
||||||
|
.then((response) => {
|
||||||
|
// all tables are in the response object, eg:
|
||||||
|
console.log(response.tablewith2cols1row[0].COL1.value)
|
||||||
|
})
|
||||||
|
```
|
||||||
|
We supply the path to the SAS service, and a data object. The data object can be null (for services with no input), or can contain one or more tables in the following format:
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
let dataObject={
|
||||||
|
"tablewith2cols1row": [{
|
||||||
|
"col1": "val1",
|
||||||
|
"col2": 42
|
||||||
|
}],
|
||||||
|
"tablewith1col2rows": [{
|
||||||
|
"col": "row1"
|
||||||
|
}, {
|
||||||
|
"col": "row2"
|
||||||
|
}]
|
||||||
|
};
|
||||||
|
```
|
||||||
|
|
||||||
|
There are optional parameters such as a config object and a callback login function.
|
||||||
|
|
||||||
|
The response object will contain returned tables and columns. Table names are always lowercase, and column names uppercase.
|
||||||
|
|
||||||
|
The adapter will also cache the logs (if debug enabled) and even the work tables. For performance, it is best to keep debug mode off.
|
||||||
|
|
||||||
|
## SAS Inputs / Outputs
|
||||||
|
|
||||||
|
The SAS side is handled by a number of macros in the [macro core](https://github.com/sasjs/core) library.
|
||||||
|
|
||||||
|
The following snippet shows the process of SAS tables arriving / leaving:
|
||||||
|
```sas
|
||||||
|
/* fetch all input tables sent from frontend - they arrive as work tables */
|
||||||
|
%webout(FETCH)
|
||||||
|
|
||||||
|
/* some sas code */
|
||||||
|
data some sas tables;
|
||||||
|
set from js;
|
||||||
|
run;
|
||||||
|
|
||||||
|
%webout(OPEN) /* open the JSON to be returned */
|
||||||
|
%webout(OBJ,some) /* `some` table is sent in object format */
|
||||||
|
%webout(ARR,sas) /* `sas` table is sent in array format, smaller filesize */
|
||||||
|
%webout(OBJ,tables,fmt=N) /* unformatted (raw) data */
|
||||||
|
%webout(OBJ,tables,label=newtable) /* rename tables on export */
|
||||||
|
%webout(CLOSE) /* close the JSON and send some extra useful variables too */
|
||||||
|
|
||||||
|
```
|
||||||
|
|
||||||
|
## Configuration
|
||||||
|
|
||||||
|
Configuration on the client side involves passing an object on startup, which can also be passed with each request. Technical documentation on the SASjsConfig class is available [here](https://adapter.sasjs.io/classes/types.sasjsconfig.html). The main config items are:
|
||||||
|
|
||||||
|
* `appLoc` - this is the folder under which the SAS services will be created.
|
||||||
|
* `serverType` - either `SAS9` or `SASVIYA`.
|
||||||
|
* `serverUrl` - the location (including http protocol and port) of the SAS Server. Can be omitted, eg if serving directly from the SAS Web Server, or in streaming mode.
|
||||||
|
* `debug` - if `true` then SAS Logs and extra debug information is returned.
|
||||||
|
* `useComputeApi` - if `true` and the serverType is `SASVIYA` then the REST APIs will be called directly (rather than using the JES web service).
|
||||||
|
* `contextName` - if missing or blank, and `useComputeApi` is `true` and `serverType` is `SASVIYA` then the JES API will be used.
|
||||||
|
|
||||||
|
The adapter supports a number of approaches for interfacing with Viya (`serverType` is `SASVIYA`). For maximum performance, be sure to [configure your compute context](https://sasjs.io/guide-viya/#shared-account-and-server-re-use) with `reuseServerProcesses` as `true` and a system account in `runServerAs`. This functionality is available since Viya 3.5. This configuration is supported when [creating contexts using the CLI](https://sasjs.io/sasjs-cli-context/#sasjs-context-create).
|
||||||
|
|
||||||
|
### Using JES Web App
|
||||||
|
|
||||||
|
In this setup, all requests are routed through the JES web app, at `YOURSERVER/SASJobExecution`. This is the most reliable method, and also the slowest. One request is made to the JES app, and remaining requests (getting job uri, session spawning, passing parameters, running the program, fetching the log) are made on the SAS server by the JES app.
|
||||||
|
|
||||||
|
```
|
||||||
|
{
|
||||||
|
appLoc:"/Your/Path",
|
||||||
|
serverType:"SASVIYA"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### Using the JES API
|
||||||
|
Here we are running Jobs using the Job Execution Service except this time we are making the requests directly using the REST API instead of through the JES Web App. This is helpful when we need to call web services outside of a browser (eg with the SASjs CLI or other commandline tools). To save one network request, the adapter prefetches the JOB URIs and passes them in the `__job` parameter.
|
||||||
|
|
||||||
|
```
|
||||||
|
{
|
||||||
|
appLoc:"/Your/Path",
|
||||||
|
serverType:"SASVIYA",
|
||||||
|
useComputeApi: true
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### Using the Compute API
|
||||||
|
This approach is by far the fastest, as a result of the optimisations we have built into the adapter. With this configuration, in the first sasjs request, we take a URI map of the services in the target folder, and create a session manager - which spawns an extra session. The next time a request is made, the adapter will use the 'hot' session. Sessions are deleted after every use, which actually makes this _less_ resource intensive than a typical JES web app, in which all sessions are kept alive by default for 15 minutes.
|
||||||
|
|
||||||
|
```
|
||||||
|
{
|
||||||
|
appLoc:"/Your/Path",
|
||||||
|
serverType:"SASVIYA",
|
||||||
|
useComputeApi: true,
|
||||||
|
contextName: 'yourComputeContext'
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
# More resources
|
# More resources
|
||||||
|
|
||||||
For more information and examples specific to this adapter you can check out the [user guide](https://sasjs.io/sasjs-adapter/) or the [technical](http://adapter.sasjs.io/) documentation.
|
For more information and examples specific to this adapter you can check out the [user guide](https://sasjs.io/sasjs-adapter/) or the [technical](http://adapter.sasjs.io/) documentation.
|
||||||
|
|
||||||
For more information on building web apps in general, check out these [resources](https://sasjs.io/training/resources/) or contact the [author](https://www.linkedin.com/in/allanbowe/) directly.
|
For more information on building web apps in general, check out these [resources](https://sasjs.io/training/resources/) or contact the [author](https://www.linkedin.com/in/allanbowe/) directly.
|
||||||
|
|
||||||
|
If you are a SAS 9 or SAS Viya customer you can also request a copy of [Data Controller](https://datacontroller.io) - free for up to 5 users, this tool makes use of all parts of the SASjs framework.
|
||||||
|
|||||||
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
286
docs/classes/types_errors.authorizeerror.html
Normal file
286
docs/classes/types_errors.authorizeerror.html
Normal file
File diff suppressed because one or more lines are too long
304
docs/classes/types_errors.computejobexecutionerror.html
Normal file
304
docs/classes/types_errors.computejobexecutionerror.html
Normal file
File diff suppressed because one or more lines are too long
209
docs/classes/types_errors.errorresponse.html
Normal file
209
docs/classes/types_errors.errorresponse.html
Normal file
File diff suppressed because one or more lines are too long
259
docs/classes/types_errors.internalservererror.html
Normal file
259
docs/classes/types_errors.internalservererror.html
Normal file
File diff suppressed because one or more lines are too long
325
docs/classes/types_errors.jobexecutionerror.html
Normal file
325
docs/classes/types_errors.jobexecutionerror.html
Normal file
File diff suppressed because one or more lines are too long
259
docs/classes/types_errors.loginrequirederror.html
Normal file
259
docs/classes/types_errors.loginrequirederror.html
Normal file
File diff suppressed because one or more lines are too long
283
docs/classes/types_errors.notfounderror.html
Normal file
283
docs/classes/types_errors.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
133
docs/index.html
133
docs/index.html
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
200
docs/interfaces/job_execution.waitingrequstpromise.html
Normal file
200
docs/interfaces/job_execution.waitingrequstpromise.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
209
docs/interfaces/types.logstatistics.html
Normal file
209
docs/interfaces/types.logstatistics.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
133
docs/modules/types_errors.html
Normal file
133
docs/modules/types_errors.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
264
package-lock.json
generated
264
package-lock.json
generated
@@ -816,9 +816,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"@sasjs/utils": {
|
"@sasjs/utils": {
|
||||||
"version": "2.5.0",
|
"version": "2.6.3",
|
||||||
"resolved": "https://registry.npmjs.org/@sasjs/utils/-/utils-2.5.0.tgz",
|
"resolved": "https://registry.npmjs.org/@sasjs/utils/-/utils-2.6.3.tgz",
|
||||||
"integrity": "sha512-1pOsyEOaTo1COu1SbaxJLh0PVo6Z7i+88lFkbkWNzlFO6oWa+aBJW3WCvbJ5UjRmmfVr3o0Z+VwoihrB6xo8iw==",
|
"integrity": "sha512-qfL61WW7LwdFrpLIt6Uyr3Eoh+HPwCG3gfhgq9E7XriLs7/YZL3WiUTasYadu8mDeXI/LhHwQh01o3bzFDCQfw==",
|
||||||
"requires": {
|
"requires": {
|
||||||
"@types/prompts": "^2.0.9",
|
"@types/prompts": "^2.0.9",
|
||||||
"consola": "^2.15.0",
|
"consola": "^2.15.0",
|
||||||
@@ -2042,64 +2042,19 @@
|
|||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
"cli-table": {
|
"cli-table": {
|
||||||
"version": "0.3.4",
|
"version": "0.3.5",
|
||||||
"resolved": "https://registry.npmjs.org/cli-table/-/cli-table-0.3.4.tgz",
|
"resolved": "https://registry.npmjs.org/cli-table/-/cli-table-0.3.5.tgz",
|
||||||
"integrity": "sha512-1vinpnX/ZERcmE443i3SZTmU5DF0rPO9DrL4I2iVAllhxzCM9SzPlHnz19fsZB78htkKZvYBvj6SZ6vXnaxmTA==",
|
"integrity": "sha512-7uo2+RMNQUZ13M199udxqwk1qxTOS53EUak4gmu/aioUpdH5RvBz0JkJslcWz6ABKedZNqXXzikMZgHh+qF16A==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"requires": {
|
"requires": {
|
||||||
"chalk": "^2.4.1",
|
"colors": "1.0.3"
|
||||||
"string-width": "^4.2.0"
|
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"ansi-styles": {
|
"colors": {
|
||||||
"version": "3.2.1",
|
"version": "1.0.3",
|
||||||
"resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz",
|
"resolved": "https://registry.npmjs.org/colors/-/colors-1.0.3.tgz",
|
||||||
"integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==",
|
"integrity": "sha1-BDP0TYCWgP3rYO0mDxsMJi6CpAs=",
|
||||||
"dev": true,
|
|
||||||
"requires": {
|
|
||||||
"color-convert": "^1.9.0"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"chalk": {
|
|
||||||
"version": "2.4.2",
|
|
||||||
"resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz",
|
|
||||||
"integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==",
|
|
||||||
"dev": true,
|
|
||||||
"requires": {
|
|
||||||
"ansi-styles": "^3.2.1",
|
|
||||||
"escape-string-regexp": "^1.0.5",
|
|
||||||
"supports-color": "^5.3.0"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"color-convert": {
|
|
||||||
"version": "1.9.3",
|
|
||||||
"resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz",
|
|
||||||
"integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==",
|
|
||||||
"dev": true,
|
|
||||||
"requires": {
|
|
||||||
"color-name": "1.1.3"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"color-name": {
|
|
||||||
"version": "1.1.3",
|
|
||||||
"resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz",
|
|
||||||
"integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=",
|
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
|
||||||
"has-flag": {
|
|
||||||
"version": "3.0.0",
|
|
||||||
"resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz",
|
|
||||||
"integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=",
|
|
||||||
"dev": true
|
|
||||||
},
|
|
||||||
"supports-color": {
|
|
||||||
"version": "5.5.0",
|
|
||||||
"resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz",
|
|
||||||
"integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==",
|
|
||||||
"dev": true,
|
|
||||||
"requires": {
|
|
||||||
"has-flag": "^3.0.0"
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@@ -2782,9 +2737,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"es-module-lexer": {
|
"es-module-lexer": {
|
||||||
"version": "0.3.26",
|
"version": "0.4.1",
|
||||||
"resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-0.3.26.tgz",
|
"resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-0.4.1.tgz",
|
||||||
"integrity": "sha512-Va0Q/xqtrss45hWzP8CZJwzGSZJjDM5/MJRE3IXXnUCcVLElR9BRaE9F62BopysASyc4nM3uwhSW7FFB9nlWAA==",
|
"integrity": "sha512-ooYciCUtfw6/d2w56UVeqHPcoCFAiJdz5XOkYpv/Txl1HMUozpXjz/2RIQgqwKdXNDPSF1W7mJCFse3G+HDyAA==",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
"escalade": {
|
"escalade": {
|
||||||
@@ -3203,15 +3158,15 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"fs-extra": {
|
"fs-extra": {
|
||||||
"version": "9.0.1",
|
"version": "9.1.0",
|
||||||
"resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-9.0.1.tgz",
|
"resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-9.1.0.tgz",
|
||||||
"integrity": "sha512-h2iAoN838FqAFJY2/qVpzFXy+EBxfVE220PalAqQLDVsFOHLJrZvut5puAbCdNv6WJk+B8ihI+k0c7JK5erwqQ==",
|
"integrity": "sha512-hcg3ZmepS30/7BSFqRvoo3DOMQu7IjqxO5nCDt+zM9XWjb33Wg7ziNT+Qvqbuc3+gWpzO02JubVyk2G4Zvo1OQ==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"requires": {
|
"requires": {
|
||||||
"at-least-node": "^1.0.0",
|
"at-least-node": "^1.0.0",
|
||||||
"graceful-fs": "^4.2.0",
|
"graceful-fs": "^4.2.0",
|
||||||
"jsonfile": "^6.0.1",
|
"jsonfile": "^6.0.1",
|
||||||
"universalify": "^1.0.0"
|
"universalify": "^2.0.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"fs-minipass": {
|
"fs-minipass": {
|
||||||
@@ -3382,9 +3337,9 @@
|
|||||||
"optional": true
|
"optional": true
|
||||||
},
|
},
|
||||||
"handlebars": {
|
"handlebars": {
|
||||||
"version": "4.7.6",
|
"version": "4.7.7",
|
||||||
"resolved": "https://registry.npmjs.org/handlebars/-/handlebars-4.7.6.tgz",
|
"resolved": "https://registry.npmjs.org/handlebars/-/handlebars-4.7.7.tgz",
|
||||||
"integrity": "sha512-1f2BACcBfiwAfStCKZNrUCgqNZkGsAT7UM3kkYtXuLo0KnaVfjKOyf7PRzB6++aK9STyT1Pd2ZCPe3EGOXleXA==",
|
"integrity": "sha512-aAcXm5OAfE/8IXkcZvCepKU3VzW1/39Fb5ZuqMtgI/hT8X2YgoMvBY5dLhq/cpOvw7Lk1nK/UF71aLG/ZnVYRA==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"requires": {
|
"requires": {
|
||||||
"minimist": "^1.2.5",
|
"minimist": "^1.2.5",
|
||||||
@@ -3483,12 +3438,6 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"highlight.js": {
|
|
||||||
"version": "10.5.0",
|
|
||||||
"resolved": "https://registry.npmjs.org/highlight.js/-/highlight.js-10.5.0.tgz",
|
|
||||||
"integrity": "sha512-xTmvd9HiIHR6L53TMC7TKolEj65zG1XU+Onr8oi86mYa+nLcIbxTTWkpW7CsEwv/vK7u1zb8alZIMLDqqN6KTw==",
|
|
||||||
"dev": true
|
|
||||||
},
|
|
||||||
"hook-std": {
|
"hook-std": {
|
||||||
"version": "2.0.0",
|
"version": "2.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/hook-std/-/hook-std-2.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/hook-std/-/hook-std-2.0.0.tgz",
|
||||||
@@ -4997,14 +4946,6 @@
|
|||||||
"requires": {
|
"requires": {
|
||||||
"graceful-fs": "^4.1.6",
|
"graceful-fs": "^4.1.6",
|
||||||
"universalify": "^2.0.0"
|
"universalify": "^2.0.0"
|
||||||
},
|
|
||||||
"dependencies": {
|
|
||||||
"universalify": {
|
|
||||||
"version": "2.0.0",
|
|
||||||
"resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.0.tgz",
|
|
||||||
"integrity": "sha512-hAZsKq7Yy11Zu1DE0OzWjw7nnLZmJZYTDZZyEFHZdUhV8FkH5MCfoU1XMaxXovpyW5nq5scPqq0ZDP9Zyl04oQ==",
|
|
||||||
"dev": true
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"jsonparse": {
|
"jsonparse": {
|
||||||
@@ -5115,9 +5056,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"lodash": {
|
"lodash": {
|
||||||
"version": "4.17.20",
|
"version": "4.17.21",
|
||||||
"resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.20.tgz",
|
"resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz",
|
||||||
"integrity": "sha512-PlhdFcillOINfeV7Ni6oF1TAEayyZBoZ8bcshTHqOYJYlrqzRK5hagpagky5o4HfCzzd1TRkXPMFq6cKk9rGmA==",
|
"integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
"lodash.capitalize": {
|
"lodash.capitalize": {
|
||||||
@@ -5235,20 +5176,20 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"marked": {
|
"marked": {
|
||||||
"version": "1.2.7",
|
"version": "2.0.1",
|
||||||
"resolved": "https://registry.npmjs.org/marked/-/marked-1.2.7.tgz",
|
"resolved": "https://registry.npmjs.org/marked/-/marked-2.0.1.tgz",
|
||||||
"integrity": "sha512-No11hFYcXr/zkBvL6qFmAp1z6BKY3zqLMHny/JN/ey+al7qwCM2+CMBL9BOgqMxZU36fz4cCWfn2poWIf7QRXA==",
|
"integrity": "sha512-5+/fKgMv2hARmMW7DOpykr2iLhl0NgjyELk5yn92iE7z8Se1IS9n3UsFm86hFXIkvMBmVxki8+ckcpjBeyo/hw==",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
"marked-terminal": {
|
"marked-terminal": {
|
||||||
"version": "4.1.0",
|
"version": "4.1.1",
|
||||||
"resolved": "https://registry.npmjs.org/marked-terminal/-/marked-terminal-4.1.0.tgz",
|
"resolved": "https://registry.npmjs.org/marked-terminal/-/marked-terminal-4.1.1.tgz",
|
||||||
"integrity": "sha512-5KllfAOW02WS6hLRQ7cNvGOxvKW1BKuXELH4EtbWfyWgxQhROoMxEvuQ/3fTgkNjledR0J48F4HbapvYp1zWkQ==",
|
"integrity": "sha512-t7Mdf6T3PvOEyN01c3tYxDzhyKZ8xnkp8Rs6Fohno63L/0pFTJ5Qtwto2AQVuDtbQiWzD+4E5AAu1Z2iLc8miQ==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"requires": {
|
"requires": {
|
||||||
"ansi-escapes": "^4.3.1",
|
"ansi-escapes": "^4.3.1",
|
||||||
"cardinal": "^2.1.1",
|
"cardinal": "^2.1.1",
|
||||||
"chalk": "^4.0.0",
|
"chalk": "^4.1.0",
|
||||||
"cli-table": "^0.3.1",
|
"cli-table": "^0.3.1",
|
||||||
"node-emoji": "^1.10.0",
|
"node-emoji": "^1.10.0",
|
||||||
"supports-hyperlinks": "^2.1.0"
|
"supports-hyperlinks": "^2.1.0"
|
||||||
@@ -10124,9 +10065,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"semantic-release": {
|
"semantic-release": {
|
||||||
"version": "17.3.9",
|
"version": "17.4.1",
|
||||||
"resolved": "https://registry.npmjs.org/semantic-release/-/semantic-release-17.3.9.tgz",
|
"resolved": "https://registry.npmjs.org/semantic-release/-/semantic-release-17.4.1.tgz",
|
||||||
"integrity": "sha512-iPDySFcAXG+7KiM0JH4bvF++imkf85VmfXpIBPAyDxK/P4+pe19KNFCfkzTKwUJkTIAyLUIr7WOg3W5h5aMwNg==",
|
"integrity": "sha512-o/Rjk0HCBUWEYxN99Vq04Th+XtRQAxbC+FN+pBQ49wpqQ5NW/cfwhfw0qyxeTEhbchQ/1/KGMPWqD4/rRScAag==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"requires": {
|
"requires": {
|
||||||
"@semantic-release/commit-analyzer": "^8.0.0",
|
"@semantic-release/commit-analyzer": "^8.0.0",
|
||||||
@@ -10147,7 +10088,7 @@
|
|||||||
"hosted-git-info": "^3.0.0",
|
"hosted-git-info": "^3.0.0",
|
||||||
"lodash": "^4.17.15",
|
"lodash": "^4.17.15",
|
||||||
"marked": "^2.0.0",
|
"marked": "^2.0.0",
|
||||||
"marked-terminal": "^4.0.0",
|
"marked-terminal": "^4.1.1",
|
||||||
"micromatch": "^4.0.2",
|
"micromatch": "^4.0.2",
|
||||||
"p-each-series": "^2.1.0",
|
"p-each-series": "^2.1.0",
|
||||||
"p-reduce": "^2.0.0",
|
"p-reduce": "^2.0.0",
|
||||||
@@ -10225,12 +10166,6 @@
|
|||||||
"integrity": "sha512-XCoy+WlUr7d1+Z8GgSuXmpuUFC9fOhRXglJMx+dwLKTkL44Cjd4W1Z5P+BQZpr+cR93aGP4S/s7Ftw6Nd/kiEw==",
|
"integrity": "sha512-XCoy+WlUr7d1+Z8GgSuXmpuUFC9fOhRXglJMx+dwLKTkL44Cjd4W1Z5P+BQZpr+cR93aGP4S/s7Ftw6Nd/kiEw==",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
"marked": {
|
|
||||||
"version": "2.0.0",
|
|
||||||
"resolved": "https://registry.npmjs.org/marked/-/marked-2.0.0.tgz",
|
|
||||||
"integrity": "sha512-NqRSh2+LlN2NInpqTQnS614Y/3NkVMFFU6sJlRFEpxJ/LHuK/qJECH7/fXZjk4VZstPW/Pevjil/VtSONsLc7Q==",
|
|
||||||
"dev": true
|
|
||||||
},
|
|
||||||
"npm-run-path": {
|
"npm-run-path": {
|
||||||
"version": "4.0.1",
|
"version": "4.0.1",
|
||||||
"resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-4.0.1.tgz",
|
"resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-4.0.1.tgz",
|
||||||
@@ -10412,33 +10347,12 @@
|
|||||||
"optional": true
|
"optional": true
|
||||||
},
|
},
|
||||||
"shiki": {
|
"shiki": {
|
||||||
"version": "0.2.7",
|
"version": "0.9.2",
|
||||||
"resolved": "https://registry.npmjs.org/shiki/-/shiki-0.2.7.tgz",
|
"resolved": "https://registry.npmjs.org/shiki/-/shiki-0.9.2.tgz",
|
||||||
"integrity": "sha512-bwVc7cdtYYHEO9O+XJ8aNOskKRfaQd5Y4ovLRfbQkmiLSUaR+bdlssbZUUhbQ0JAFMYcTcJ5tjG5KtnufttDHQ==",
|
"integrity": "sha512-BjUCxVbxMnvjs8jC4b+BQ808vwjJ9Q8NtLqPwXShZ307HdXiDFYP968ORSVfaTNNSWYDBYdMnVKJ0fYNsoZUBA==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"requires": {
|
"requires": {
|
||||||
"onigasm": "^2.2.5",
|
"onigasm": "^2.2.5",
|
||||||
"shiki-languages": "^0.2.7",
|
|
||||||
"shiki-themes": "^0.2.7",
|
|
||||||
"vscode-textmate": "^5.2.0"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"shiki-languages": {
|
|
||||||
"version": "0.2.7",
|
|
||||||
"resolved": "https://registry.npmjs.org/shiki-languages/-/shiki-languages-0.2.7.tgz",
|
|
||||||
"integrity": "sha512-REmakh7pn2jCn9GDMRSK36oDgqhh+rSvJPo77sdWTOmk44C5b0XlYPwJZcFOMJWUZJE0c7FCbKclw4FLwUKLRw==",
|
|
||||||
"dev": true,
|
|
||||||
"requires": {
|
|
||||||
"vscode-textmate": "^5.2.0"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"shiki-themes": {
|
|
||||||
"version": "0.2.7",
|
|
||||||
"resolved": "https://registry.npmjs.org/shiki-themes/-/shiki-themes-0.2.7.tgz",
|
|
||||||
"integrity": "sha512-ZMmboDYw5+SEpugM8KGUq3tkZ0vXg+k60XX6NngDK7gc1Sv6YLUlanpvG3evm57uKJvfXsky/S5MzSOTtYKLjA==",
|
|
||||||
"dev": true,
|
|
||||||
"requires": {
|
|
||||||
"json5": "^2.1.0",
|
|
||||||
"vscode-textmate": "^5.2.0"
|
"vscode-textmate": "^5.2.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@@ -11431,39 +11345,28 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"typedoc": {
|
"typedoc": {
|
||||||
"version": "0.19.2",
|
"version": "0.20.30",
|
||||||
"resolved": "https://registry.npmjs.org/typedoc/-/typedoc-0.19.2.tgz",
|
"resolved": "https://registry.npmjs.org/typedoc/-/typedoc-0.20.30.tgz",
|
||||||
"integrity": "sha512-oDEg1BLEzi1qvgdQXc658EYgJ5qJLVSeZ0hQ57Eq4JXy6Vj2VX4RVo18qYxRWz75ifAaYuYNBUCnbhjd37TfOg==",
|
"integrity": "sha512-A4L6JDShPFwZDt9qp7FBsEpW7C6rA5fRv6ywgBuxGxZnT2wuF5afbWzmrwqHR3Xw38V1H2L4v/VJ0S/llBwV6Q==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"requires": {
|
"requires": {
|
||||||
"fs-extra": "^9.0.1",
|
"colors": "^1.4.0",
|
||||||
"handlebars": "^4.7.6",
|
"fs-extra": "^9.1.0",
|
||||||
"highlight.js": "^10.2.0",
|
"handlebars": "^4.7.7",
|
||||||
"lodash": "^4.17.20",
|
"lodash": "^4.17.21",
|
||||||
"lunr": "^2.3.9",
|
"lunr": "^2.3.9",
|
||||||
"marked": "^1.1.1",
|
"marked": "^2.0.1",
|
||||||
"minimatch": "^3.0.0",
|
"minimatch": "^3.0.0",
|
||||||
"progress": "^2.0.3",
|
"progress": "^2.0.3",
|
||||||
"semver": "^7.3.2",
|
|
||||||
"shelljs": "^0.8.4",
|
"shelljs": "^0.8.4",
|
||||||
"typedoc-default-themes": "^0.11.4"
|
"shiki": "^0.9.2",
|
||||||
},
|
"typedoc-default-themes": "^0.12.8"
|
||||||
"dependencies": {
|
|
||||||
"semver": {
|
|
||||||
"version": "7.3.4",
|
|
||||||
"resolved": "https://registry.npmjs.org/semver/-/semver-7.3.4.tgz",
|
|
||||||
"integrity": "sha512-tCfb2WLjqFAtXn4KEdxIhalnRtoKFN7nAwj0B3ZXCbQloV2tq5eDbcTmT68JJD3nRJq24/XgxtQKFIpQdtvmVw==",
|
|
||||||
"dev": true,
|
|
||||||
"requires": {
|
|
||||||
"lru-cache": "^6.0.0"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"typedoc-default-themes": {
|
"typedoc-default-themes": {
|
||||||
"version": "0.11.4",
|
"version": "0.12.8",
|
||||||
"resolved": "https://registry.npmjs.org/typedoc-default-themes/-/typedoc-default-themes-0.11.4.tgz",
|
"resolved": "https://registry.npmjs.org/typedoc-default-themes/-/typedoc-default-themes-0.12.8.tgz",
|
||||||
"integrity": "sha512-Y4Lf+qIb9NTydrexlazAM46SSLrmrQRqWiD52593g53SsmUFioAsMWt8m834J6qsp+7wHRjxCXSZeiiW5cMUdw==",
|
"integrity": "sha512-tyjyDTKy/JLnBSwvhoqd99VIjrP33SdOtwcMD32b+OqnrjZWe8HmZECbfBoacqoxjHd58gfeNw6wA7uvqWFa4w==",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
"typedoc-neo-theme": {
|
"typedoc-neo-theme": {
|
||||||
@@ -11474,57 +11377,6 @@
|
|||||||
"requires": {
|
"requires": {
|
||||||
"lunr": "^2.3.8",
|
"lunr": "^2.3.8",
|
||||||
"typedoc": "~0.20.13"
|
"typedoc": "~0.20.13"
|
||||||
},
|
|
||||||
"dependencies": {
|
|
||||||
"fs-extra": {
|
|
||||||
"version": "9.1.0",
|
|
||||||
"resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-9.1.0.tgz",
|
|
||||||
"integrity": "sha512-hcg3ZmepS30/7BSFqRvoo3DOMQu7IjqxO5nCDt+zM9XWjb33Wg7ziNT+Qvqbuc3+gWpzO02JubVyk2G4Zvo1OQ==",
|
|
||||||
"dev": true,
|
|
||||||
"requires": {
|
|
||||||
"at-least-node": "^1.0.0",
|
|
||||||
"graceful-fs": "^4.2.0",
|
|
||||||
"jsonfile": "^6.0.1",
|
|
||||||
"universalify": "^2.0.0"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"marked": {
|
|
||||||
"version": "1.2.9",
|
|
||||||
"resolved": "https://registry.npmjs.org/marked/-/marked-1.2.9.tgz",
|
|
||||||
"integrity": "sha512-H8lIX2SvyitGX+TRdtS06m1jHMijKN/XjfH6Ooii9fvxMlh8QdqBfBDkGUpMWH2kQNrtixjzYUa3SH8ROTgRRw==",
|
|
||||||
"dev": true
|
|
||||||
},
|
|
||||||
"typedoc": {
|
|
||||||
"version": "0.20.21",
|
|
||||||
"resolved": "https://registry.npmjs.org/typedoc/-/typedoc-0.20.21.tgz",
|
|
||||||
"integrity": "sha512-KAXRnKyyhdA5Wgd96QMdld7gvlL/izUaJi2FAf6KoGuRNgYIUVHQy4KExl9enMt24l/y4LgTFqR6aw3P8NGiZg==",
|
|
||||||
"dev": true,
|
|
||||||
"requires": {
|
|
||||||
"colors": "^1.4.0",
|
|
||||||
"fs-extra": "^9.1.0",
|
|
||||||
"handlebars": "^4.7.6",
|
|
||||||
"lodash": "^4.17.20",
|
|
||||||
"lunr": "^2.3.9",
|
|
||||||
"marked": "^1.2.8",
|
|
||||||
"minimatch": "^3.0.0",
|
|
||||||
"progress": "^2.0.3",
|
|
||||||
"shelljs": "^0.8.4",
|
|
||||||
"shiki": "^0.2.7",
|
|
||||||
"typedoc-default-themes": "^0.12.7"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"typedoc-default-themes": {
|
|
||||||
"version": "0.12.7",
|
|
||||||
"resolved": "https://registry.npmjs.org/typedoc-default-themes/-/typedoc-default-themes-0.12.7.tgz",
|
|
||||||
"integrity": "sha512-0XAuGEqID+gon1+fhi4LycOEFM+5Mvm2PjwaiVZNAzU7pn3G2DEpsoXnFOPlLDnHY6ZW0BY0nO7ur9fHOFkBLQ==",
|
|
||||||
"dev": true
|
|
||||||
},
|
|
||||||
"universalify": {
|
|
||||||
"version": "2.0.0",
|
|
||||||
"resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.0.tgz",
|
|
||||||
"integrity": "sha512-hAZsKq7Yy11Zu1DE0OzWjw7nnLZmJZYTDZZyEFHZdUhV8FkH5MCfoU1XMaxXovpyW5nq5scPqq0ZDP9Zyl04oQ==",
|
|
||||||
"dev": true
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"typedoc-plugin-external-module-name": {
|
"typedoc-plugin-external-module-name": {
|
||||||
@@ -11607,9 +11459,9 @@
|
|||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
"universalify": {
|
"universalify": {
|
||||||
"version": "1.0.0",
|
"version": "2.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/universalify/-/universalify-1.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.0.tgz",
|
||||||
"integrity": "sha512-rb6X1W158d7pRQBg5gkR8uPaSfiids68LTJQYOtEUhoJUWBdaQHsuT/EUduxXYxcrt4r5PJ4fuHW1MHT6p0qug==",
|
"integrity": "sha512-hAZsKq7Yy11Zu1DE0OzWjw7nnLZmJZYTDZZyEFHZdUhV8FkH5MCfoU1XMaxXovpyW5nq5scPqq0ZDP9Zyl04oQ==",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
"unset-value": {
|
"unset-value": {
|
||||||
@@ -11810,9 +11662,9 @@
|
|||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
"webpack": {
|
"webpack": {
|
||||||
"version": "5.21.2",
|
"version": "5.24.4",
|
||||||
"resolved": "https://registry.npmjs.org/webpack/-/webpack-5.21.2.tgz",
|
"resolved": "https://registry.npmjs.org/webpack/-/webpack-5.24.4.tgz",
|
||||||
"integrity": "sha512-xHflCenx+AM4uWKX71SWHhxml5aMXdy2tu/vdi4lClm7PADKxlyDAFFN1rEFzNV0MAoPpHtBeJnl/+K6F4QBPg==",
|
"integrity": "sha512-RXOdxF9hFFFhg47BryCgyFrEyyu7Y/75/uiI2DoUiTMqysK+WczVSTppvkR47oZcmI/DPaXCiCiaXBP8QjkNpA==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"requires": {
|
"requires": {
|
||||||
"@types/eslint-scope": "^3.7.0",
|
"@types/eslint-scope": "^3.7.0",
|
||||||
@@ -11824,7 +11676,7 @@
|
|||||||
"browserslist": "^4.14.5",
|
"browserslist": "^4.14.5",
|
||||||
"chrome-trace-event": "^1.0.2",
|
"chrome-trace-event": "^1.0.2",
|
||||||
"enhanced-resolve": "^5.7.0",
|
"enhanced-resolve": "^5.7.0",
|
||||||
"es-module-lexer": "^0.3.26",
|
"es-module-lexer": "^0.4.0",
|
||||||
"eslint-scope": "^5.1.1",
|
"eslint-scope": "^5.1.1",
|
||||||
"events": "^3.2.0",
|
"events": "^3.2.0",
|
||||||
"glob-to-regexp": "^0.4.1",
|
"glob-to-regexp": "^0.4.1",
|
||||||
|
|||||||
@@ -43,23 +43,23 @@
|
|||||||
"jest-extended": "^0.11.5",
|
"jest-extended": "^0.11.5",
|
||||||
"path": "^0.12.7",
|
"path": "^0.12.7",
|
||||||
"rimraf": "^3.0.2",
|
"rimraf": "^3.0.2",
|
||||||
"semantic-release": "^17.3.9",
|
"semantic-release": "^17.4.1",
|
||||||
"terser-webpack-plugin": "^4.2.3",
|
"terser-webpack-plugin": "^4.2.3",
|
||||||
"ts-jest": "^25.5.1",
|
"ts-jest": "^25.5.1",
|
||||||
"ts-loader": "^8.0.17",
|
"ts-loader": "^8.0.17",
|
||||||
"tslint": "^6.1.3",
|
"tslint": "^6.1.3",
|
||||||
"tslint-config-prettier": "^1.18.0",
|
"tslint-config-prettier": "^1.18.0",
|
||||||
"typedoc": "^0.19.2",
|
"typedoc": "^0.20.30",
|
||||||
"typedoc-neo-theme": "^1.1.0",
|
"typedoc-neo-theme": "^1.1.0",
|
||||||
"typedoc-plugin-external-module-name": "^4.0.6",
|
"typedoc-plugin-external-module-name": "^4.0.6",
|
||||||
"typescript": "^3.9.9",
|
"typescript": "^3.9.9",
|
||||||
"webpack": "^5.21.2",
|
"webpack": "^5.24.4",
|
||||||
"webpack-cli": "^4.5.0"
|
"webpack-cli": "^4.5.0"
|
||||||
},
|
},
|
||||||
"main": "index.js",
|
"main": "index.js",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
"@sasjs/utils": "^2.6.3",
|
||||||
"axios": "^0.21.1",
|
"axios": "^0.21.1",
|
||||||
"@sasjs/utils": "^2.5.0",
|
|
||||||
"form-data": "^3.0.0",
|
"form-data": "^3.0.0",
|
||||||
"https": "^1.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": {
|
"@sasjs/adapter": {
|
||||||
"version": "2.1.0",
|
"version": "file:../build/sasjs-adapter-5.0.0.tgz",
|
||||||
"resolved": "https://registry.npmjs.org/@sasjs/adapter/-/adapter-2.1.0.tgz",
|
"integrity": "sha512-1t+3LIL2BFw8HpZUPI9QM24801+JH4DCAu4eHoLLmytYhN72asMi1aVtgSDb1xiJYgpbTG7EK3qRpHIV8cEN8w==",
|
||||||
"integrity": "sha512-FdvxAPzXHHwCurH5B1RxSGeO6h+lVqDGAtrTAQDByT7HhsikAMFi6mW5dJR/1CKcI2rLOdE/479yYqjwfX8nwg==",
|
|
||||||
"requires": {
|
"requires": {
|
||||||
"@sasjs/utils": "^2.0.2",
|
"@sasjs/utils": "^2.5.0",
|
||||||
"es6-promise": "^4.2.8",
|
"axios": "^0.21.1",
|
||||||
"form-data": "^3.0.0",
|
"form-data": "^3.0.0",
|
||||||
"https": "^1.0.0",
|
"https": "^1.0.0"
|
||||||
"isomorphic-fetch": "^2.2.1"
|
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"form-data": {
|
"form-data": {
|
||||||
"version": "3.0.0",
|
"version": "3.0.1",
|
||||||
"resolved": "https://registry.npmjs.org/form-data/-/form-data-3.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/form-data/-/form-data-3.0.1.tgz",
|
||||||
"integrity": "sha512-CKMFDglpbMi6PyN+brwB9Q/GOw0eAnsrEZDgcsH5Krhz5Od/haKHAX0NmQfha2zPPz0JpWzA7GJHGSnvCRLWsg==",
|
"integrity": "sha512-RHkBKtLWUVwd7SqRIvCZMEvAMoGUp0XU+seQiZejj0COz3RI3hWP4sCv3gZWWLjJTd7rGwcsF5eKZGii0r/hbg==",
|
||||||
"requires": {
|
"requires": {
|
||||||
"asynckit": "^0.4.0",
|
"asynckit": "^0.4.0",
|
||||||
"combined-stream": "^1.0.8",
|
"combined-stream": "^1.0.8",
|
||||||
@@ -2048,10 +2046,11 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"@sasjs/utils": {
|
"@sasjs/utils": {
|
||||||
"version": "2.2.0",
|
"version": "2.5.1",
|
||||||
"resolved": "https://registry.npmjs.org/@sasjs/utils/-/utils-2.2.0.tgz",
|
"resolved": "https://registry.npmjs.org/@sasjs/utils/-/utils-2.5.1.tgz",
|
||||||
"integrity": "sha512-T01TYAFU+WQ1uAUaunZXg0MotQe5jn3auVuMPPbY5RU5VhIn4oVhr6qz3EHyNsYYKD1aj5pP7w2elnBzkgWhGw==",
|
"integrity": "sha512-a3ISiUX8Yz7au4XYxq2KWf9ODT6nsIDbE4FEqS+AQ3McxZkfuAk4v+REXjOmIlcyQd4R4bufEK8XoB6AROn9sA==",
|
||||||
"requires": {
|
"requires": {
|
||||||
|
"@types/prompts": "^2.0.9",
|
||||||
"consola": "^2.15.0",
|
"consola": "^2.15.0",
|
||||||
"prompts": "^2.4.0",
|
"prompts": "^2.4.0",
|
||||||
"valid-url": "^1.0.9"
|
"valid-url": "^1.0.9"
|
||||||
@@ -2366,6 +2365,14 @@
|
|||||||
"resolved": "https://registry.npmjs.org/@types/prettier/-/prettier-2.1.6.tgz",
|
"resolved": "https://registry.npmjs.org/@types/prettier/-/prettier-2.1.6.tgz",
|
||||||
"integrity": "sha512-6gOkRe7OIioWAXfnO/2lFiv+SJichKVSys1mSsgyrYHSEjk8Ctv4tSR/Odvnu+HWlH2C8j53dahU03XmQdd5fA=="
|
"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": {
|
"@types/prop-types": {
|
||||||
"version": "15.7.3",
|
"version": "15.7.3",
|
||||||
"resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.3.tgz",
|
"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",
|
"resolved": "https://registry.npmjs.org/axe-core/-/axe-core-4.1.1.tgz",
|
||||||
"integrity": "sha512-5Kgy8Cz6LPC9DJcNb3yjAXTu3XihQgEdnIg50c//zOC/MyLP0Clg+Y8Sh9ZjjnvBrDZU4DgXS9C3T9r4/scGZQ=="
|
"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": {
|
"axobject-query": {
|
||||||
"version": "2.2.0",
|
"version": "2.2.0",
|
||||||
"resolved": "https://registry.npmjs.org/axobject-query/-/axobject-query-2.2.0.tgz",
|
"resolved": "https://registry.npmjs.org/axobject-query/-/axobject-query-2.2.0.tgz",
|
||||||
@@ -4677,9 +4692,9 @@
|
|||||||
"integrity": "sha512-e54B99q/OUoH64zYYRf3HBP5z24G38h5D3qXu23JGRoigpX5Ss4r9ZnDk3g0Z8uQC2x2lPaJ+UlWBc1ZWBWdLg=="
|
"integrity": "sha512-e54B99q/OUoH64zYYRf3HBP5z24G38h5D3qXu23JGRoigpX5Ss4r9ZnDk3g0Z8uQC2x2lPaJ+UlWBc1ZWBWdLg=="
|
||||||
},
|
},
|
||||||
"consola": {
|
"consola": {
|
||||||
"version": "2.15.2",
|
"version": "2.15.3",
|
||||||
"resolved": "https://registry.npmjs.org/consola/-/consola-2.15.2.tgz",
|
"resolved": "https://registry.npmjs.org/consola/-/consola-2.15.3.tgz",
|
||||||
"integrity": "sha512-VxqWw5C8O/mQpZYtfaaSCDJcVK3AxyvQ26rhgvyAI4j/QJISh8DLwFS8GQU+9154u4ngyCsSlnyIAYJme9kQug=="
|
"integrity": "sha512-9vAdYbHj6x2fLKC4+oPH0kFzY/orMZyG2Aj+kNylHxKGJ/Ed4dpNyAQYwJOdqO4zdM7XpVHmyejQDcQHrnuXbw=="
|
||||||
},
|
},
|
||||||
"console-browserify": {
|
"console-browserify": {
|
||||||
"version": "1.2.0",
|
"version": "1.2.0",
|
||||||
@@ -5722,24 +5737,6 @@
|
|||||||
"resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz",
|
"resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz",
|
||||||
"integrity": "sha1-rT/0yG7C0CkyL1oCw6mmBslbP1k="
|
"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": {
|
"end-of-stream": {
|
||||||
"version": "1.4.4",
|
"version": "1.4.4",
|
||||||
"resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.4.tgz",
|
"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-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": {
|
"es6-symbol": {
|
||||||
"version": "3.1.3",
|
"version": "3.1.3",
|
||||||
"resolved": "https://registry.npmjs.org/es6-symbol/-/es6-symbol-3.1.3.tgz",
|
"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",
|
"resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz",
|
||||||
"integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8="
|
"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": {
|
"isstream": {
|
||||||
"version": "0.1.2",
|
"version": "0.1.2",
|
||||||
"resolved": "https://registry.npmjs.org/isstream/-/isstream-0.1.2.tgz",
|
"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": {
|
"node-forge": {
|
||||||
"version": "0.10.0",
|
"version": "0.10.0",
|
||||||
"resolved": "https://registry.npmjs.org/node-forge/-/node-forge-0.10.0.tgz",
|
"resolved": "https://registry.npmjs.org/node-forge/-/node-forge-0.10.0.tgz",
|
||||||
|
|||||||
@@ -4,7 +4,7 @@
|
|||||||
"homepage": ".",
|
"homepage": ".",
|
||||||
"private": true,
|
"private": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@sasjs/adapter": "^2.1.0",
|
"@sasjs/adapter": "^2.2.4",
|
||||||
"@sasjs/test-framework": "^1.4.0",
|
"@sasjs/test-framework": "^1.4.0",
|
||||||
"@types/jest": "^26.0.20",
|
"@types/jest": "^26.0.20",
|
||||||
"@types/node": "^14.14.25",
|
"@types/node": "^14.14.25",
|
||||||
|
|||||||
@@ -6,7 +6,7 @@
|
|||||||
"appLoc": "/Public/app",
|
"appLoc": "/Public/app",
|
||||||
"serverType": "SASVIYA",
|
"serverType": "SASVIYA",
|
||||||
"debug": false,
|
"debug": false,
|
||||||
"contextName": "SharedCompute",
|
"contextName": "sasjs adapter compute context",
|
||||||
"useComputeApi": true
|
"useComputeApi": true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,6 +2,8 @@ import SASjs, { SASjsConfig } from "@sasjs/adapter";
|
|||||||
import { TestSuite } from "@sasjs/test-framework";
|
import { TestSuite } from "@sasjs/test-framework";
|
||||||
import { ServerType } from "@sasjs/utils/types";
|
import { ServerType } from "@sasjs/utils/types";
|
||||||
|
|
||||||
|
const stringData: any = { table1: [{ col1: "first col value" }] };
|
||||||
|
|
||||||
const defaultConfig: SASjsConfig = {
|
const defaultConfig: SASjsConfig = {
|
||||||
serverUrl: window.location.origin,
|
serverUrl: window.location.origin,
|
||||||
pathSAS9: "/SASStoredProcess/do",
|
pathSAS9: "/SASStoredProcess/do",
|
||||||
@@ -51,6 +53,36 @@ export const basicTests = (
|
|||||||
assertion: (response: any) =>
|
assertion: (response: any) =>
|
||||||
response && response.isLoggedIn && response.userName === userName
|
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",
|
title: "Default config",
|
||||||
description:
|
description:
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import { isUrl } from './utils'
|
import { isUrl } from './utils'
|
||||||
import { UploadFile } from './types/UploadFile'
|
import { UploadFile } from './types/UploadFile'
|
||||||
import { ErrorResponse, LoginRequiredError } from './types'
|
import { ErrorResponse, LoginRequiredError } from './types/errors'
|
||||||
import { RequestClient } from './request/RequestClient'
|
import { RequestClient } from './request/RequestClient'
|
||||||
|
|
||||||
export class FileUploader {
|
export class FileUploader {
|
||||||
|
|||||||
@@ -1,4 +1,10 @@
|
|||||||
import { convertToCSV, isRelativePath, isUri, isUrl } from './utils'
|
import {
|
||||||
|
convertToCSV,
|
||||||
|
isRelativePath,
|
||||||
|
isUri,
|
||||||
|
isUrl,
|
||||||
|
fetchLogByChunks
|
||||||
|
} from './utils'
|
||||||
import * as NodeFormData from 'form-data'
|
import * as NodeFormData from 'form-data'
|
||||||
import {
|
import {
|
||||||
Job,
|
Job,
|
||||||
@@ -8,10 +14,13 @@ import {
|
|||||||
Folder,
|
Folder,
|
||||||
EditContextInput,
|
EditContextInput,
|
||||||
JobDefinition,
|
JobDefinition,
|
||||||
PollOptions,
|
PollOptions
|
||||||
ComputeJobExecutionError,
|
|
||||||
JobExecutionError
|
|
||||||
} from './types'
|
} from './types'
|
||||||
|
import {
|
||||||
|
ComputeJobExecutionError,
|
||||||
|
JobExecutionError,
|
||||||
|
NotFoundError
|
||||||
|
} from './types/errors'
|
||||||
import { formatDataForRequest } from './utils/formatDataForRequest'
|
import { formatDataForRequest } from './utils/formatDataForRequest'
|
||||||
import { SessionManager } from './SessionManager'
|
import { SessionManager } from './SessionManager'
|
||||||
import { ContextManager } from './ContextManager'
|
import { ContextManager } from './ContextManager'
|
||||||
@@ -19,7 +28,6 @@ import { timestampToYYYYMMDDHHMMSS } from '@sasjs/utils/time'
|
|||||||
import { Logger, LogLevel } from '@sasjs/utils/logger'
|
import { Logger, LogLevel } from '@sasjs/utils/logger'
|
||||||
import { isAuthorizeFormRequired } from './auth/isAuthorizeFormRequired'
|
import { isAuthorizeFormRequired } from './auth/isAuthorizeFormRequired'
|
||||||
import { RequestClient } from './request/RequestClient'
|
import { RequestClient } from './request/RequestClient'
|
||||||
import { NotFoundError } from './types/NotFoundError'
|
|
||||||
import { SasAuthResponse } from '@sasjs/utils/types'
|
import { SasAuthResponse } from '@sasjs/utils/types'
|
||||||
import { prefixMessage } from '@sasjs/utils/error'
|
import { prefixMessage } from '@sasjs/utils/error'
|
||||||
|
|
||||||
@@ -418,19 +426,19 @@ export class SASViyaApiClient {
|
|||||||
})
|
})
|
||||||
|
|
||||||
let jobResult
|
let jobResult
|
||||||
let log
|
let log = ''
|
||||||
|
|
||||||
const logLink = currentJob.links.find((l) => l.rel === 'log')
|
const logLink = currentJob.links.find((l) => l.rel === 'log')
|
||||||
|
|
||||||
if (debug && logLink) {
|
if (debug && logLink) {
|
||||||
log = await this.requestClient
|
const logUrl = `${logLink.href}/content`
|
||||||
.get<any>(`${logLink.href}/content?limit=10000`, accessToken)
|
const logCount = currentJob.logStatistics?.lineCount ?? 1000000
|
||||||
.then((res: any) =>
|
log = await fetchLogByChunks(
|
||||||
res.result.items.map((i: any) => i.line).join('\n')
|
this.requestClient,
|
||||||
)
|
accessToken!,
|
||||||
.catch((err) => {
|
logUrl,
|
||||||
throw prefixMessage(err, 'Error while getting log. ')
|
logCount
|
||||||
})
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (jobStatus === 'failed' || jobStatus === 'error') {
|
if (jobStatus === 'failed' || jobStatus === 'error') {
|
||||||
@@ -451,14 +459,14 @@ export class SASViyaApiClient {
|
|||||||
.catch(async (e) => {
|
.catch(async (e) => {
|
||||||
if (e instanceof NotFoundError) {
|
if (e instanceof NotFoundError) {
|
||||||
if (logLink) {
|
if (logLink) {
|
||||||
log = await this.requestClient
|
const logUrl = `${logLink.href}/content`
|
||||||
.get<any>(`${logLink.href}/content?limit=10000`, accessToken)
|
const logCount = currentJob.logStatistics?.lineCount ?? 1000000
|
||||||
.then((res: any) =>
|
log = await fetchLogByChunks(
|
||||||
res.result.items.map((i: any) => i.line).join('\n')
|
this.requestClient,
|
||||||
)
|
accessToken!,
|
||||||
.catch((err) => {
|
logUrl,
|
||||||
throw prefixMessage(err, 'Error while getting log. ')
|
logCount
|
||||||
})
|
)
|
||||||
|
|
||||||
return Promise.reject({
|
return Promise.reject({
|
||||||
status: 500,
|
status: 500,
|
||||||
@@ -884,9 +892,7 @@ export class SASViyaApiClient {
|
|||||||
waitForResult,
|
waitForResult,
|
||||||
pollOptions,
|
pollOptions,
|
||||||
printPid
|
printPid
|
||||||
).catch((err) => {
|
)
|
||||||
throw prefixMessage(err, 'Error while executing script. ')
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -979,7 +985,13 @@ export class SASViyaApiClient {
|
|||||||
postJobRequestBody,
|
postJobRequestBody,
|
||||||
accessToken
|
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>(
|
const { result: currentJob } = await this.requestClient.get<Job>(
|
||||||
`${this.serverUrl}/jobExecution/jobs/${postedJob.id}`,
|
`${this.serverUrl}/jobExecution/jobs/${postedJob.id}`,
|
||||||
accessToken
|
accessToken
|
||||||
@@ -1078,7 +1090,9 @@ export class SASViyaApiClient {
|
|||||||
.get<string>(
|
.get<string>(
|
||||||
`${this.serverUrl}${stateLink.href}?_action=wait&wait=30`,
|
`${this.serverUrl}${stateLink.href}?_action=wait&wait=30`,
|
||||||
accessToken,
|
accessToken,
|
||||||
'text/plain'
|
'text/plain',
|
||||||
|
{},
|
||||||
|
this.debug
|
||||||
)
|
)
|
||||||
.catch((err) => {
|
.catch((err) => {
|
||||||
throw prefixMessage(err, 'Error while getting job state. ')
|
throw prefixMessage(err, 'Error while getting job state. ')
|
||||||
@@ -1103,10 +1117,15 @@ export class SASViyaApiClient {
|
|||||||
.get<string>(
|
.get<string>(
|
||||||
`${this.serverUrl}${stateLink.href}?_action=wait&wait=30`,
|
`${this.serverUrl}${stateLink.href}?_action=wait&wait=30`,
|
||||||
accessToken,
|
accessToken,
|
||||||
'text/plain'
|
'text/plain',
|
||||||
|
{},
|
||||||
|
this.debug
|
||||||
)
|
)
|
||||||
.catch((err) => {
|
.catch((err) => {
|
||||||
throw prefixMessage(err, 'Error while getting job state. ')
|
throw prefixMessage(
|
||||||
|
err,
|
||||||
|
'Error while getting job state after interval. '
|
||||||
|
)
|
||||||
})
|
})
|
||||||
|
|
||||||
postedJobState = jobState.trim()
|
postedJobState = jobState.trim()
|
||||||
|
|||||||
39
src/SASjs.ts
39
src/SASjs.ts
@@ -12,6 +12,7 @@ import {
|
|||||||
ComputeJobExecutor,
|
ComputeJobExecutor,
|
||||||
JesJobExecutor
|
JesJobExecutor
|
||||||
} from './job-execution'
|
} from './job-execution'
|
||||||
|
import { ErrorResponse } from './types/errors'
|
||||||
|
|
||||||
const defaultConfig: SASjsConfig = {
|
const defaultConfig: SASjsConfig = {
|
||||||
serverUrl: '',
|
serverUrl: '',
|
||||||
@@ -530,15 +531,19 @@ export default class SASjs {
|
|||||||
* @param config - provide any changes to the config here, for instance to
|
* @param config - provide any changes to the config here, for instance to
|
||||||
* enable/disable `debug`. Any change provided will override the global config,
|
* enable/disable `debug`. Any change provided will override the global config,
|
||||||
* for that particular function call.
|
* for that particular function call.
|
||||||
* @param loginRequiredCallback - provide a function here to be called if the
|
* @param loginRequiredCallback - a function that is called if the
|
||||||
* user is not logged in (eg to display a login form). The request will be
|
* user is not logged in (eg to display a login form). The request will be
|
||||||
* resubmitted after logon.
|
* resubmitted after successful login.
|
||||||
|
* When using a `loginRequiredCallback`, the call to the request will look, for example, like so:
|
||||||
|
* `await request(sasJobPath, data, config, () => setIsLoggedIn(false))`
|
||||||
|
* If you are not passing in any data and configuration, it will look like so:
|
||||||
|
* `await request(sasJobPath, {}, {}, () => setIsLoggedIn(false))`
|
||||||
*/
|
*/
|
||||||
public async request(
|
public async request(
|
||||||
sasJob: string,
|
sasJob: string,
|
||||||
data: any,
|
data: { [key: string]: any },
|
||||||
config: any = {},
|
config: { [key: string]: any } = {},
|
||||||
loginRequiredCallback?: any,
|
loginRequiredCallback?: () => any,
|
||||||
accessToken?: string
|
accessToken?: string
|
||||||
) {
|
) {
|
||||||
config = {
|
config = {
|
||||||
@@ -705,9 +710,27 @@ export default class SASjs {
|
|||||||
* @param accessToken - an access token for an authorized user.
|
* @param accessToken - an access token for an authorized 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) => {
|
||||||
JSON.stringify(res.result)
|
if (!res)
|
||||||
)
|
return Promise.reject(
|
||||||
|
new ErrorResponse(
|
||||||
|
'Error while fetching log. Response was not provided.'
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
try {
|
||||||
|
const result = JSON.stringify(res.result)
|
||||||
|
|
||||||
|
return result
|
||||||
|
} catch (err) {
|
||||||
|
return Promise.reject(
|
||||||
|
new ErrorResponse(
|
||||||
|
'Error while fetching log. The result is not valid.',
|
||||||
|
err
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
public getSasRequests() {
|
public getSasRequests() {
|
||||||
|
|||||||
@@ -82,17 +82,33 @@ export class AuthManager {
|
|||||||
* @returns - a promise which resolves with an object containing two values - a boolean `isLoggedIn`, and a string `userName`.
|
* @returns - a promise which resolves with an object containing two values - a boolean `isLoggedIn`, and a string `userName`.
|
||||||
*/
|
*/
|
||||||
public async checkSession() {
|
public async checkSession() {
|
||||||
const { result: loginResponse } = await this.requestClient.get<string>(
|
//For VIYA we will send request on API endpoint. Which is faster then pinging SASJobExecution.
|
||||||
this.loginUrl.replace('.do', ''),
|
//For SAS9 we will send request on SASStoredProcess
|
||||||
undefined,
|
const url =
|
||||||
'text/plain'
|
this.serverType === 'SASVIYA'
|
||||||
)
|
? `${this.serverUrl}/identities`
|
||||||
const responseText = loginResponse
|
: `${this.serverUrl}/SASStoredProcess`
|
||||||
const isLoggedIn = /<button.+onClick.+logout/gm.test(responseText)
|
|
||||||
let loginForm: any = null
|
const { result: loginResponse } = await this.requestClient
|
||||||
|
.get<string>(url, undefined, 'text/plain')
|
||||||
|
.catch((err: any) => {
|
||||||
|
return { result: 'authErr' }
|
||||||
|
})
|
||||||
|
|
||||||
|
const isLoggedIn = loginResponse !== 'authErr'
|
||||||
|
let loginForm = null
|
||||||
|
|
||||||
if (!isLoggedIn) {
|
if (!isLoggedIn) {
|
||||||
loginForm = await this.getLoginForm(responseText)
|
//We will logout to make sure cookies are removed and login form is presented
|
||||||
|
this.logOut()
|
||||||
|
|
||||||
|
const { result: formResponse } = await this.requestClient.get<string>(
|
||||||
|
this.loginUrl.replace('.do', ''),
|
||||||
|
undefined,
|
||||||
|
'text/plain'
|
||||||
|
)
|
||||||
|
|
||||||
|
loginForm = await this.getLoginForm(formResponse)
|
||||||
}
|
}
|
||||||
|
|
||||||
return Promise.resolve({
|
return Promise.resolve({
|
||||||
|
|||||||
@@ -176,41 +176,19 @@ describe('AuthManager', () => {
|
|||||||
|
|
||||||
const response = await authManager.checkSession()
|
const response = await authManager.checkSession()
|
||||||
expect(response.isLoggedIn).toBeTruthy()
|
expect(response.isLoggedIn).toBeTruthy()
|
||||||
expect(mockedAxios.get).toHaveBeenNthCalledWith(1, `/SASLogon/login`, {
|
expect(mockedAxios.get).toHaveBeenNthCalledWith(
|
||||||
withCredentials: true,
|
1,
|
||||||
responseType: 'text',
|
`http://test-server.com/identities`,
|
||||||
transformResponse: undefined,
|
{
|
||||||
headers: {
|
withCredentials: true,
|
||||||
Accept: '*/*',
|
responseType: 'text',
|
||||||
'Content-Type': 'text/plain'
|
transformResponse: undefined,
|
||||||
|
headers: {
|
||||||
|
Accept: '*/*',
|
||||||
|
'Content-Type': 'text/plain'
|
||||||
|
}
|
||||||
}
|
}
|
||||||
})
|
|
||||||
|
|
||||||
done()
|
|
||||||
})
|
|
||||||
|
|
||||||
it('should check and return session information if logged in', async (done) => {
|
|
||||||
const authManager = new AuthManager(
|
|
||||||
serverUrl,
|
|
||||||
serverType,
|
|
||||||
requestClient,
|
|
||||||
authCallback
|
|
||||||
)
|
)
|
||||||
mockedAxios.get.mockImplementation(() =>
|
|
||||||
Promise.resolve({ data: '<button onClick="logout">' })
|
|
||||||
)
|
|
||||||
|
|
||||||
const response = await authManager.checkSession()
|
|
||||||
expect(response.isLoggedIn).toBeTruthy()
|
|
||||||
expect(mockedAxios.get).toHaveBeenNthCalledWith(1, `/SASLogon/login`, {
|
|
||||||
withCredentials: true,
|
|
||||||
responseType: 'text',
|
|
||||||
transformResponse: undefined,
|
|
||||||
headers: {
|
|
||||||
Accept: '*/*',
|
|
||||||
'Content-Type': 'text/plain'
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
done()
|
done()
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
import SASjs from './SASjs'
|
import SASjs from './SASjs'
|
||||||
export * from './types'
|
export * from './types'
|
||||||
|
export * from './types/errors'
|
||||||
export * from './SASViyaApiClient'
|
export * from './SASViyaApiClient'
|
||||||
export * from './SAS9ApiClient'
|
export * from './SAS9ApiClient'
|
||||||
export default SASjs
|
export default SASjs
|
||||||
|
|||||||
@@ -1,7 +1,10 @@
|
|||||||
import { ServerType } from '@sasjs/utils/types'
|
import { ServerType } from '@sasjs/utils/types'
|
||||||
import { ErrorResponse } from '..'
|
|
||||||
import { SASViyaApiClient } from '../SASViyaApiClient'
|
import { SASViyaApiClient } from '../SASViyaApiClient'
|
||||||
import { ComputeJobExecutionError, LoginRequiredError } from '../types'
|
import {
|
||||||
|
ErrorResponse,
|
||||||
|
ComputeJobExecutionError,
|
||||||
|
LoginRequiredError
|
||||||
|
} from '../types/errors'
|
||||||
import { BaseJobExecutor } from './JobExecutor'
|
import { BaseJobExecutor } from './JobExecutor'
|
||||||
|
|
||||||
export class ComputeJobExecutor extends BaseJobExecutor {
|
export class ComputeJobExecutor extends BaseJobExecutor {
|
||||||
@@ -20,35 +23,52 @@ export class ComputeJobExecutor extends BaseJobExecutor {
|
|||||||
const waitForResult = true
|
const waitForResult = true
|
||||||
const expectWebout = true
|
const expectWebout = true
|
||||||
|
|
||||||
return this.sasViyaApiClient
|
const requestPromise = new Promise((resolve, reject) => {
|
||||||
?.executeComputeJob(
|
this.sasViyaApiClient
|
||||||
sasJob,
|
?.executeComputeJob(
|
||||||
config.contextName,
|
sasJob,
|
||||||
config.debug,
|
config.contextName,
|
||||||
data,
|
config.debug,
|
||||||
accessToken,
|
data,
|
||||||
waitForResult,
|
accessToken,
|
||||||
expectWebout
|
waitForResult,
|
||||||
)
|
expectWebout
|
||||||
.then((response) => {
|
)
|
||||||
this.appendRequest(response, sasJob, config.debug)
|
.then((response) => {
|
||||||
let responseJson
|
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
|
reject(new ErrorResponse(e?.message, e))
|
||||||
})
|
}
|
||||||
.catch(async (e: Error) => {
|
|
||||||
if (e instanceof ComputeJobExecutionError) {
|
if (e instanceof LoginRequiredError) {
|
||||||
this.appendRequest(e, sasJob, config.debug)
|
await loginCallback()
|
||||||
}
|
this.appendWaitingRequest(() => {
|
||||||
if (e instanceof LoginRequiredError) {
|
return this.execute(
|
||||||
await loginCallback()
|
sasJob,
|
||||||
this.appendWaitingRequest(() =>
|
data,
|
||||||
this.execute(sasJob, data, config, loginRequiredCallback)
|
config,
|
||||||
)
|
loginRequiredCallback
|
||||||
}
|
).then(
|
||||||
return Promise.reject(new ErrorResponse(e?.message, e))
|
(res: any) => {
|
||||||
})
|
resolve(res)
|
||||||
|
},
|
||||||
|
(err: any) => {
|
||||||
|
reject(err)
|
||||||
|
}
|
||||||
|
)
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
reject(new ErrorResponse(e?.message, e))
|
||||||
|
}
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
return requestPromise
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,7 +1,10 @@
|
|||||||
import { ServerType } from '@sasjs/utils/types'
|
import { ServerType } from '@sasjs/utils/types'
|
||||||
import { ErrorResponse } from '..'
|
|
||||||
import { SASViyaApiClient } from '../SASViyaApiClient'
|
import { SASViyaApiClient } from '../SASViyaApiClient'
|
||||||
import { JobExecutionError, LoginRequiredError } from '../types'
|
import {
|
||||||
|
ErrorResponse,
|
||||||
|
JobExecutionError,
|
||||||
|
LoginRequiredError
|
||||||
|
} from '../types/errors'
|
||||||
import { BaseJobExecutor } from './JobExecutor'
|
import { BaseJobExecutor } from './JobExecutor'
|
||||||
|
|
||||||
export class JesJobExecutor extends BaseJobExecutor {
|
export class JesJobExecutor extends BaseJobExecutor {
|
||||||
@@ -17,24 +20,52 @@ export class JesJobExecutor extends BaseJobExecutor {
|
|||||||
accessToken?: string
|
accessToken?: string
|
||||||
) {
|
) {
|
||||||
const loginCallback = loginRequiredCallback || (() => Promise.resolve())
|
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
|
const requestPromise = new Promise((resolve, reject) => {
|
||||||
})
|
this.sasViyaApiClient
|
||||||
.catch(async (e: Error) => {
|
?.executeJob(
|
||||||
if (e instanceof JobExecutionError) {
|
sasJob,
|
||||||
this.appendRequest(e, sasJob, config.debug)
|
config.contextName,
|
||||||
}
|
config.debug,
|
||||||
if (e instanceof LoginRequiredError) {
|
data,
|
||||||
await loginCallback()
|
accessToken
|
||||||
this.appendWaitingRequest(() =>
|
)
|
||||||
this.execute(sasJob, data, config, loginRequiredCallback)
|
.then((response) => {
|
||||||
)
|
this.appendRequest(response, sasJob, config.debug)
|
||||||
}
|
|
||||||
return Promise.reject(new ErrorResponse(e?.message, e))
|
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
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,9 @@
|
|||||||
import { ServerType } from '@sasjs/utils/types'
|
import { ServerType } from '@sasjs/utils/types'
|
||||||
import { ErrorResponse, JobExecutionError, LoginRequiredError } from '..'
|
import {
|
||||||
|
ErrorResponse,
|
||||||
|
JobExecutionError,
|
||||||
|
LoginRequiredError
|
||||||
|
} from '../types/errors'
|
||||||
import { generateFileUploadForm } from '../file/generateFileUploadForm'
|
import { generateFileUploadForm } from '../file/generateFileUploadForm'
|
||||||
import { generateTableUploadForm } from '../file/generateTableUploadForm'
|
import { generateTableUploadForm } from '../file/generateTableUploadForm'
|
||||||
import { RequestClient } from '../request/RequestClient'
|
import { RequestClient } from '../request/RequestClient'
|
||||||
@@ -7,6 +11,11 @@ import { SASViyaApiClient } from '../SASViyaApiClient'
|
|||||||
import { isRelativePath } from '../utils'
|
import { isRelativePath } from '../utils'
|
||||||
import { BaseJobExecutor } from './JobExecutor'
|
import { BaseJobExecutor } from './JobExecutor'
|
||||||
|
|
||||||
|
export interface WaitingRequstPromise {
|
||||||
|
promise: Promise<any> | null
|
||||||
|
resolve: any
|
||||||
|
reject: any
|
||||||
|
}
|
||||||
export class WebJobExecutor extends BaseJobExecutor {
|
export class WebJobExecutor extends BaseJobExecutor {
|
||||||
constructor(
|
constructor(
|
||||||
serverUrl: string,
|
serverUrl: string,
|
||||||
@@ -80,30 +89,51 @@ export class WebJobExecutor extends BaseJobExecutor {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return this.requestClient!.post(apiUrl, formData, undefined)
|
const requestPromise = new Promise((resolve, reject) => {
|
||||||
.then(async (res) => {
|
this.requestClient!.post(apiUrl, formData, undefined)
|
||||||
if (this.serverType === ServerType.SasViya && config.debug) {
|
.then(async (res) => {
|
||||||
const jsonResponse = await this.parseSasViyaDebugResponse(
|
if (this.serverType === ServerType.SasViya && config.debug) {
|
||||||
res.result as string
|
const jsonResponse = await this.parseSasViyaDebugResponse(
|
||||||
)
|
res.result as string
|
||||||
|
)
|
||||||
|
this.appendRequest(res, sasJob, config.debug)
|
||||||
|
resolve(jsonResponse)
|
||||||
|
}
|
||||||
this.appendRequest(res, sasJob, config.debug)
|
this.appendRequest(res, sasJob, config.debug)
|
||||||
return jsonResponse
|
resolve(res.result)
|
||||||
}
|
})
|
||||||
this.appendRequest(res, sasJob, config.debug)
|
.catch(async (e: Error) => {
|
||||||
return res.result
|
if (e instanceof JobExecutionError) {
|
||||||
})
|
this.appendRequest(e, sasJob, config.debug)
|
||||||
.catch(async (e: Error) => {
|
|
||||||
if (e instanceof JobExecutionError) {
|
reject(new ErrorResponse(e?.message, e))
|
||||||
this.appendRequest(e, sasJob, config.debug)
|
}
|
||||||
}
|
|
||||||
if (e instanceof LoginRequiredError) {
|
if (e instanceof LoginRequiredError) {
|
||||||
await loginCallback()
|
await loginCallback()
|
||||||
this.appendWaitingRequest(() =>
|
|
||||||
this.execute(sasJob, data, config, loginRequiredCallback)
|
this.appendWaitingRequest(() => {
|
||||||
)
|
return this.execute(
|
||||||
}
|
sasJob,
|
||||||
return Promise.reject(new ErrorResponse(e?.message, e))
|
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) => {
|
private parseSasViyaDebugResponse = async (response: string) => {
|
||||||
|
|||||||
@@ -1,9 +1,13 @@
|
|||||||
import axios, { AxiosInstance, AxiosRequestConfig, AxiosResponse } from 'axios'
|
import axios, { AxiosInstance, AxiosRequestConfig, AxiosResponse } from 'axios'
|
||||||
import { CsrfToken, JobExecutionError } from '..'
|
import { CsrfToken } from '..'
|
||||||
import { isAuthorizeFormRequired, isLogInRequired } from '../auth'
|
import { isAuthorizeFormRequired, isLogInRequired } from '../auth'
|
||||||
import { LoginRequiredError } from '../types'
|
import {
|
||||||
import { AuthorizeError } from '../types/AuthorizeError'
|
AuthorizeError,
|
||||||
import { NotFoundError } from '../types/NotFoundError'
|
LoginRequiredError,
|
||||||
|
NotFoundError,
|
||||||
|
InternalServerError,
|
||||||
|
JobExecutionError
|
||||||
|
} from '../types/errors'
|
||||||
import { parseWeboutResponse } from '../utils/parseWeboutResponse'
|
import { parseWeboutResponse } from '../utils/parseWeboutResponse'
|
||||||
import { prefixMessage } from '@sasjs/utils/error'
|
import { prefixMessage } from '@sasjs/utils/error'
|
||||||
|
|
||||||
@@ -73,7 +77,8 @@ export class RequestClient implements HttpClient {
|
|||||||
url: string,
|
url: string,
|
||||||
accessToken: string | undefined,
|
accessToken: string | undefined,
|
||||||
contentType: string = 'application/json',
|
contentType: string = 'application/json',
|
||||||
overrideHeaders: { [key: string]: string | number } = {}
|
overrideHeaders: { [key: string]: string | number } = {},
|
||||||
|
debug: boolean = false
|
||||||
): Promise<{ result: T; etag: string }> {
|
): Promise<{ result: T; etag: string }> {
|
||||||
const headers = {
|
const headers = {
|
||||||
...this.getHeaders(accessToken, contentType),
|
...this.getHeaders(accessToken, contentType),
|
||||||
@@ -93,11 +98,22 @@ export class RequestClient implements HttpClient {
|
|||||||
.get<T>(url, requestConfig)
|
.get<T>(url, requestConfig)
|
||||||
.then((response) => {
|
.then((response) => {
|
||||||
throwIfError(response)
|
throwIfError(response)
|
||||||
|
|
||||||
return this.parseResponse<T>(response)
|
return this.parseResponse<T>(response)
|
||||||
})
|
})
|
||||||
.catch(async (e) => {
|
.catch(async (e) => {
|
||||||
return await this.handleError(e, () =>
|
return await this.handleError(
|
||||||
this.get<T>(url, accessToken, contentType, overrideHeaders)
|
e,
|
||||||
|
() =>
|
||||||
|
this.get<T>(url, accessToken, contentType, overrideHeaders).catch(
|
||||||
|
(err) => {
|
||||||
|
throw prefixMessage(
|
||||||
|
err,
|
||||||
|
'Error while executing handle error callback. '
|
||||||
|
)
|
||||||
|
}
|
||||||
|
),
|
||||||
|
debug
|
||||||
).catch((err) => {
|
).catch((err) => {
|
||||||
throw prefixMessage(err, 'Error while handling error. ')
|
throw prefixMessage(err, 'Error while handling error. ')
|
||||||
})
|
})
|
||||||
@@ -332,7 +348,11 @@ export class RequestClient implements HttpClient {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private handleError = async (e: any, callback: any) => {
|
private handleError = async (
|
||||||
|
e: any,
|
||||||
|
callback: any,
|
||||||
|
debug: boolean = false
|
||||||
|
) => {
|
||||||
const response = e.response as AxiosResponse
|
const response = e.response as AxiosResponse
|
||||||
|
|
||||||
if (e instanceof AuthorizeError) {
|
if (e instanceof AuthorizeError) {
|
||||||
@@ -346,7 +366,9 @@ export class RequestClient implements HttpClient {
|
|||||||
})
|
})
|
||||||
|
|
||||||
if (isAuthorizeFormRequired(res?.data as string)) {
|
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().catch((err: any) => {
|
return await callback().catch((err: any) => {
|
||||||
@@ -376,6 +398,9 @@ export class RequestClient implements HttpClient {
|
|||||||
throw e
|
throw e
|
||||||
} else if (response?.status === 404) {
|
} else if (response?.status === 404) {
|
||||||
throw new NotFoundError(response.config.url!)
|
throw new NotFoundError(response.config.url!)
|
||||||
|
} else if (response?.status === 502) {
|
||||||
|
if (debug) throw new InternalServerError()
|
||||||
|
else return
|
||||||
}
|
}
|
||||||
|
|
||||||
throw e
|
throw e
|
||||||
@@ -384,6 +409,7 @@ export class RequestClient implements HttpClient {
|
|||||||
private parseResponse<T>(response: AxiosResponse<any>) {
|
private parseResponse<T>(response: AxiosResponse<any>) {
|
||||||
const etag = response?.headers ? response.headers['etag'] : ''
|
const etag = response?.headers ? response.headers['etag'] : ''
|
||||||
let parsedResponse
|
let parsedResponse
|
||||||
|
let includeSAS9Log: boolean = false
|
||||||
|
|
||||||
try {
|
try {
|
||||||
if (typeof response.data === 'string') {
|
if (typeof response.data === 'string') {
|
||||||
@@ -397,11 +423,20 @@ export class RequestClient implements HttpClient {
|
|||||||
} catch {
|
} catch {
|
||||||
parsedResponse = response.data
|
parsedResponse = response.data
|
||||||
}
|
}
|
||||||
|
|
||||||
|
includeSAS9Log = true
|
||||||
}
|
}
|
||||||
return {
|
|
||||||
|
let responseToReturn: { result: T; etag: any; log?: string } = {
|
||||||
result: parsedResponse as T,
|
result: parsedResponse as T,
|
||||||
etag
|
etag
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (includeSAS9Log) {
|
||||||
|
responseToReturn.log = response.data
|
||||||
|
}
|
||||||
|
|
||||||
|
return responseToReturn
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -437,6 +472,7 @@ const throwIfError = (response: AxiosResponse) => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const error = parseError(response.data as string)
|
const error = parseError(response.data as string)
|
||||||
|
|
||||||
if (error) {
|
if (error) {
|
||||||
throw error
|
throw error
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -29,7 +29,10 @@ describe('SessionManager', () => {
|
|||||||
Promise.resolve({ data: sampleResponse })
|
Promise.resolve({ data: sampleResponse })
|
||||||
)
|
)
|
||||||
|
|
||||||
const expectedResponse = { etag: '', result: sampleResponse }
|
const expectedResponse = {
|
||||||
|
etag: '',
|
||||||
|
result: sampleResponse
|
||||||
|
}
|
||||||
|
|
||||||
await expect(
|
await expect(
|
||||||
sessionManager.getVariable(
|
sessionManager.getVariable(
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
import { Link } from './Link'
|
import { Link } from './Link'
|
||||||
import { JobResult } from './JobResult'
|
import { JobResult } from './JobResult'
|
||||||
|
import { LogStatistics } from './LogStatistics'
|
||||||
|
|
||||||
export interface Job {
|
export interface Job {
|
||||||
id: string
|
id: string
|
||||||
@@ -10,4 +11,5 @@ export interface Job {
|
|||||||
links: Link[]
|
links: Link[]
|
||||||
results: JobResult
|
results: JobResult
|
||||||
error?: any
|
error?: any
|
||||||
|
logStatistics: LogStatistics
|
||||||
}
|
}
|
||||||
|
|||||||
4
src/types/LogStatistics.ts
Normal file
4
src/types/LogStatistics.ts
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
export interface LogStatistics {
|
||||||
|
lineCount: number
|
||||||
|
modifiedTimeStamp: string
|
||||||
|
}
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
import { Job } from './Job'
|
import { Job } from '../Job'
|
||||||
|
|
||||||
export class ComputeJobExecutionError extends Error {
|
export class ComputeJobExecutionError extends Error {
|
||||||
constructor(public job: Job, public log: string) {
|
constructor(public job: Job, public log: string) {
|
||||||
9
src/types/errors/InternalServerError.ts
Normal file
9
src/types/errors/InternalServerError.ts
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
export class InternalServerError extends Error {
|
||||||
|
constructor() {
|
||||||
|
super('Error: Internal server error.')
|
||||||
|
|
||||||
|
this.name = 'InternalServerError'
|
||||||
|
|
||||||
|
Object.setPrototypeOf(this, InternalServerError.prototype)
|
||||||
|
}
|
||||||
|
}
|
||||||
7
src/types/errors/index.ts
Normal file
7
src/types/errors/index.ts
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
export * from './AuthorizeError'
|
||||||
|
export * from './ComputeJobExecutionError'
|
||||||
|
export * from './InternalServerError'
|
||||||
|
export * from './JobExecutionError'
|
||||||
|
export * from './LoginRequiredError'
|
||||||
|
export * from './NotFoundError'
|
||||||
|
export * from './ErrorResponse'
|
||||||
@@ -1,14 +1,10 @@
|
|||||||
export * from './ComputeJobExecutionError'
|
|
||||||
export * from './Context'
|
export * from './Context'
|
||||||
export * from './CsrfToken'
|
export * from './CsrfToken'
|
||||||
export * from './ErrorResponse'
|
|
||||||
export * from './Folder'
|
export * from './Folder'
|
||||||
export * from './Job'
|
export * from './Job'
|
||||||
export * from './JobExecutionError'
|
|
||||||
export * from './JobDefinition'
|
export * from './JobDefinition'
|
||||||
export * from './JobResult'
|
export * from './JobResult'
|
||||||
export * from './Link'
|
export * from './Link'
|
||||||
export * from './LoginRequiredError'
|
|
||||||
export * from './SASjsConfig'
|
export * from './SASjsConfig'
|
||||||
export * from './SASjsRequest'
|
export * from './SASjsRequest'
|
||||||
export * from './Session'
|
export * from './Session'
|
||||||
|
|||||||
43
src/utils/fetchLogByChunks.ts
Normal file
43
src/utils/fetchLogByChunks.ts
Normal file
@@ -0,0 +1,43 @@
|
|||||||
|
import { RequestClient } from '../request/RequestClient'
|
||||||
|
import { prefixMessage } from '@sasjs/utils/error'
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Fetches content of the log file
|
||||||
|
* @param {object} requestClient - client object of Request Client.
|
||||||
|
* @param {string} accessToken - an access token for an authorized user.
|
||||||
|
* @param {string} logUrl - url of the log file.
|
||||||
|
* @param {number} logCount- total number of log lines in file.
|
||||||
|
* @returns an string containing log lines.
|
||||||
|
*/
|
||||||
|
export const fetchLogByChunks = async (
|
||||||
|
requestClient: RequestClient,
|
||||||
|
accessToken: string,
|
||||||
|
logUrl: string,
|
||||||
|
logCount: number
|
||||||
|
): Promise<string> => {
|
||||||
|
let log: string = ''
|
||||||
|
|
||||||
|
const loglimit = logCount < 10000 ? logCount : 10000
|
||||||
|
let start = 0
|
||||||
|
do {
|
||||||
|
console.log(
|
||||||
|
`Fetching logs from line no: ${start + 1} to ${
|
||||||
|
start + loglimit
|
||||||
|
} of ${logCount}.`
|
||||||
|
)
|
||||||
|
const logChunkJson = await requestClient!
|
||||||
|
.get<any>(`${logUrl}?start=${start}&limit=${loglimit}`, accessToken)
|
||||||
|
.then((res: any) => res.result)
|
||||||
|
.catch((err) => {
|
||||||
|
throw prefixMessage(err, 'Error while getting log. ')
|
||||||
|
})
|
||||||
|
|
||||||
|
if (logChunkJson.items.length === 0) break
|
||||||
|
|
||||||
|
const logChunk = logChunkJson.items.map((i: any) => i.line).join('\n')
|
||||||
|
log += logChunk
|
||||||
|
|
||||||
|
start += loglimit
|
||||||
|
} while (start < logCount)
|
||||||
|
return log
|
||||||
|
}
|
||||||
@@ -11,3 +11,4 @@ export * from './parseSasViyaLog'
|
|||||||
export * from './serialize'
|
export * from './serialize'
|
||||||
export * from './splitChunks'
|
export * from './splitChunks'
|
||||||
export * from './parseWeboutResponse'
|
export * from './parseWeboutResponse'
|
||||||
|
export * from './fetchLogByChunks'
|
||||||
|
|||||||
Reference in New Issue
Block a user