mirror of
https://github.com/sasjs/server.git
synced 2025-12-10 19:34:34 +00:00
Compare commits
1 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
b03a5db22f |
@@ -1,5 +1,4 @@
|
|||||||
SAS_EXEC_PATH=<path to folder containing SAS executable>
|
SAS_EXEC=<path to folder containing SAS executable 'sas'>
|
||||||
SAS_EXEC_NAME=<name of SAS executable file>
|
|
||||||
PORT_API=<port for sasjs server (api)>
|
PORT_API=<port for sasjs server (api)>
|
||||||
PORT_WEB=<port for sasjs web component(react)>
|
PORT_WEB=<port for sasjs web component(react)>
|
||||||
ACCESS_TOKEN_SECRET=<secret>
|
ACCESS_TOKEN_SECRET=<secret>
|
||||||
|
|||||||
115
.github/CONTRIBUTING.md
vendored
115
.github/CONTRIBUTING.md
vendored
@@ -1,115 +0,0 @@
|
|||||||
# CONTRIBUTING
|
|
||||||
|
|
||||||
Contributions are very welcome! Feel free to raise an issue or start a discussion, for help in getting started.
|
|
||||||
|
|
||||||
|
|
||||||
## Configuration
|
|
||||||
|
|
||||||
Configuration is made in the `configuration` section of `package.json`:
|
|
||||||
|
|
||||||
- Provide path to SAS9 executable.
|
|
||||||
|
|
||||||
|
|
||||||
### Using dockers:
|
|
||||||
|
|
||||||
There is `.env.example` file present at root of the project. [for Production]
|
|
||||||
|
|
||||||
There is `.env.example` file present at `./api` of the project. [for Development]
|
|
||||||
|
|
||||||
There is `.env.example` file present at `./web` of the project. [for Development]
|
|
||||||
|
|
||||||
Remember to provide enviornment variables.
|
|
||||||
|
|
||||||
#### Development
|
|
||||||
|
|
||||||
Command to run docker for development:
|
|
||||||
|
|
||||||
```
|
|
||||||
docker-compose up -d
|
|
||||||
```
|
|
||||||
|
|
||||||
It uses default docker compose file i.e. `docker-compose.yml` present at root.
|
|
||||||
It will build following images if running first time:
|
|
||||||
|
|
||||||
- `sasjs_server_api` - image for sasjs api server app based on _ExpressJS_
|
|
||||||
- `sasjs_server_web` - image for sasjs web component app based on _ReactJS_
|
|
||||||
- `mongodb` - image for mongo database
|
|
||||||
- `mongo-seed-users` - will be populating user data specified in _./mongo-seed/users/user.json_
|
|
||||||
- `mongo-seed-clients` - will be populating client data specified in _./mongo-seed/clients/client.json_
|
|
||||||
|
|
||||||
|
|
||||||
#### Production
|
|
||||||
|
|
||||||
Command to run docker for production:
|
|
||||||
|
|
||||||
```
|
|
||||||
docker-compose -f docker-compose.prod.yml up -d
|
|
||||||
```
|
|
||||||
|
|
||||||
It uses specified docker compose file i.e. `docker-compose.prod.yml` present at root.
|
|
||||||
It will build following images if running first time:
|
|
||||||
|
|
||||||
- `sasjs_server_prod` - image for sasjs server app containing api and web component's build served at route `/`
|
|
||||||
- `mongodb` - image for mongo database
|
|
||||||
- `mongo-seed-users` - will be populating user data specified in _./mongo-seed/users/user.json_
|
|
||||||
- `mongo-seed-clients` - will be populating client data specified in _./mongo-seed/clients/client.json_
|
|
||||||
|
|
||||||
### Using node:
|
|
||||||
|
|
||||||
#### Development (running api and web seperately):
|
|
||||||
|
|
||||||
##### API
|
|
||||||
|
|
||||||
Navigate to `./api`
|
|
||||||
There is `.env.example` file present at `./api` directory. Remember to provide enviornment variables else default values will be used mentioned in `.env.example` files
|
|
||||||
Command to install and run api server.
|
|
||||||
|
|
||||||
```
|
|
||||||
npm install
|
|
||||||
npm start
|
|
||||||
```
|
|
||||||
|
|
||||||
##### Web
|
|
||||||
|
|
||||||
Navigate to `./web`
|
|
||||||
There is `.env.example` file present at `./web` directory. Remember to provide enviornment variables else default values will be used mentioned in `.env.example` files
|
|
||||||
Command to install and run api server.
|
|
||||||
|
|
||||||
```
|
|
||||||
npm install
|
|
||||||
npm start
|
|
||||||
```
|
|
||||||
|
|
||||||
#### Development (running only api server and have web build served):
|
|
||||||
|
|
||||||
##### API server also serving Web build files
|
|
||||||
|
|
||||||
There is `.env.example` file present at `./api` directory. Remember to provide enviornment variables else default values will be used mentioned in `.env.example` files
|
|
||||||
Command to install and run api server.
|
|
||||||
|
|
||||||
```
|
|
||||||
cd ./web && npm i && npm build && cd ../
|
|
||||||
cd ./api && npm i && npm start
|
|
||||||
```
|
|
||||||
|
|
||||||
#### Production
|
|
||||||
|
|
||||||
##### API & WEB
|
|
||||||
|
|
||||||
```
|
|
||||||
npm run server
|
|
||||||
```
|
|
||||||
|
|
||||||
This will install/build `web` and install `api`, then start prod server.
|
|
||||||
|
|
||||||
|
|
||||||
## Executables
|
|
||||||
|
|
||||||
Command to generate executables
|
|
||||||
|
|
||||||
```
|
|
||||||
cd ./web && npm i && npm build && cd ../
|
|
||||||
cd ./api && npm i && npm run exe
|
|
||||||
```
|
|
||||||
|
|
||||||
This will install/build web app and install/create executables of sasjs server at root `./executables`
|
|
||||||
@@ -2,13 +2,6 @@
|
|||||||
|
|
||||||
All notable changes to this project will be documented in this file. See [standard-version](https://github.com/conventional-changelog/standard-version) for commit guidelines.
|
All notable changes to this project will be documented in this file. See [standard-version](https://github.com/conventional-changelog/standard-version) for commit guidelines.
|
||||||
|
|
||||||
### [0.0.24](https://github.com/sasjs/server/compare/v0.0.23...v0.0.24) (2022-02-11)
|
|
||||||
|
|
||||||
|
|
||||||
### Bug Fixes
|
|
||||||
|
|
||||||
* removing sysmacdelete ([480ee4d](https://github.com/sasjs/server/commit/480ee4da831d2a89888c58ebec26bd89802ee2f5))
|
|
||||||
|
|
||||||
### [0.0.23](https://github.com/sasjs/server/compare/v0.0.22...v0.0.23) (2022-02-08)
|
### [0.0.23](https://github.com/sasjs/server/compare/v0.0.22...v0.0.23) (2022-02-08)
|
||||||
|
|
||||||
### [0.0.22](https://github.com/sasjs/server/compare/v0.0.17...v0.0.22) (2022-02-08)
|
### [0.0.22](https://github.com/sasjs/server/compare/v0.0.17...v0.0.22) (2022-02-08)
|
||||||
|
|||||||
137
README.md
137
README.md
@@ -8,68 +8,127 @@ SASjs Server provides a NodeJS wrapper for calling the SAS binary executable. It
|
|||||||
|
|
||||||
One major benefit of using SASjs Server (alongside other components of the SASjs framework such as the [CLI](https://cli.sasjs.io), [Adapter](https://adapter.sasjs.io) and [Core](https://core.sasjs.io) library) is that the projects you create can be very easily ported to SAS 9 (Stored Process server) or Viya (Job Execution server).
|
One major benefit of using SASjs Server (alongside other components of the SASjs framework such as the [CLI](https://cli.sasjs.io), [Adapter](https://adapter.sasjs.io) and [Core](https://core.sasjs.io) library) is that the projects you create can be very easily ported to SAS 9 (Stored Process server) or Viya (Job Execution server).
|
||||||
|
|
||||||
SASjs Server is available in two modes - Desktop (without authentication) and Server (with authentiation, and a database)
|
## Installation
|
||||||
## Desktop Version
|
|
||||||
|
|
||||||
### Manual Installation
|
First, download the relevant package from the [releases](https://github.com/sasjs/server/releases) page - either manually, or with commandline, eg as follow:
|
||||||
Download the relevant package from the [releases](https://github.com/sasjs/server/releases) page
|
|
||||||
|
|
||||||
Next, trigger by double clicking (windows) or executing from commandline.
|
```bash
|
||||||
|
curl -L https://github.com/sasjs/server/releases/latest/download/linux.zip > linux.zip
|
||||||
|
unzip linux.zip
|
||||||
|
./api-linux
|
||||||
|
```
|
||||||
|
|
||||||
|
Second, trigger by double clicking (windows) or executing from commandline.
|
||||||
|
|
||||||
You are presented with two prompts:
|
You are presented with two prompts:
|
||||||
|
|
||||||
* Location of your `sas.exe` / `sas.sh` executable
|
* Location of your `sas.exe` / `sas.sh` executable
|
||||||
* Path to a filesystem location for Stored Programs and temporary files
|
* Path to a filesystem location for Stored Programs and temporary files
|
||||||
|
|
||||||
|
## Configuration
|
||||||
|
|
||||||
## Programmatic Installation
|
Configuration is made in the `configuration` section of `package.json`:
|
||||||
|
|
||||||
Fetch the relevant package from github using `curl`, eg as follows (for linux):
|
- Provide path to SAS9 executable.
|
||||||
|
|
||||||
```bash
|
### Using dockers:
|
||||||
curl -L https://github.com/sasjs/server/releases/latest/download/linux.zip > linux.zip
|
|
||||||
unzip linux.zip
|
|
||||||
```
|
|
||||||
|
|
||||||
The app can then be launched with `./api-linux` and prompts followed.
|
There is `.env.example` file present at root of the project. [for Production]
|
||||||
|
|
||||||
When launching the app, it will make use of specific environment variables. These can be set in the following places:
|
There is `.env.example` file present at `./api` of the project. [for Development]
|
||||||
|
|
||||||
- Configured globally in /etc/environment file
|
There is `.env.example` file present at `./web` of the project. [for Development]
|
||||||
- Export in terminal or shell script (`export VAR=VALUE`)
|
|
||||||
- Prepend in command
|
|
||||||
- Enter in the `.env` file alongside the executable
|
|
||||||
|
|
||||||
Example variables:
|
Remember to provide enviornment variables.
|
||||||
|
|
||||||
|
#### Development
|
||||||
|
|
||||||
|
Command to run docker for development:
|
||||||
|
|
||||||
```
|
```
|
||||||
PORT=5004
|
docker-compose up -d
|
||||||
SAS_PATH=/path/to/sas/executable.exe
|
|
||||||
DRIVE_PATH=./tmp
|
|
||||||
```
|
```
|
||||||
|
|
||||||
Setting these prompts variables will avoid the need for prompts.
|
It uses default docker compose file i.e. `docker-compose.yml` present at root.
|
||||||
|
It will build following images if running first time:
|
||||||
|
|
||||||
Normally the server process will stop when your terminal dies. To keep it going you can use the npm package [forever](https://www.npmjs.com/package/forever) (`npm i -g forever`) as follows:
|
- `sasjs_server_api` - image for sasjs api server app based on _ExpressJS_
|
||||||
|
- `sasjs_server_web` - image for sasjs web component app based on _ReactJS_
|
||||||
|
- `mongodb` - image for mongo database
|
||||||
|
- `mongo-seed-users` - will be populating user data specified in _./mongo-seed/users/user.json_
|
||||||
|
- `mongo-seed-clients` - will be populating client data specified in _./mongo-seed/clients/client.json_
|
||||||
|
|
||||||
```bash
|
#### Production
|
||||||
export SAS_PATH=/opt/sas9/SASHome/SASFoundation/9.4/sasexe/sas
|
|
||||||
export PORT=5001
|
|
||||||
export DRIVE_PATH=./tmp
|
|
||||||
|
|
||||||
forever start -c "./api-linux" ./
|
Command to run docker for production:
|
||||||
```
|
|
||||||
|
|
||||||
To get the log files:
|
|
||||||
```bash
|
|
||||||
forever list
|
|
||||||
# grap log file link
|
|
||||||
tail -f LOGFILE
|
|
||||||
```
|
|
||||||
|
|
||||||
To stop:
|
|
||||||
|
|
||||||
```
|
```
|
||||||
forever stop <pid>
|
docker-compose -f docker-compose.prod.yml up -d
|
||||||
```
|
```
|
||||||
|
|
||||||
|
It uses specified docker compose file i.e. `docker-compose.prod.yml` present at root.
|
||||||
|
It will build following images if running first time:
|
||||||
|
|
||||||
|
- `sasjs_server_prod` - image for sasjs server app containing api and web component's build served at route `/`
|
||||||
|
- `mongodb` - image for mongo database
|
||||||
|
- `mongo-seed-users` - will be populating user data specified in _./mongo-seed/users/user.json_
|
||||||
|
- `mongo-seed-clients` - will be populating client data specified in _./mongo-seed/clients/client.json_
|
||||||
|
|
||||||
|
### Using node:
|
||||||
|
|
||||||
|
#### Development (running api and web seperately):
|
||||||
|
|
||||||
|
##### API
|
||||||
|
|
||||||
|
Navigate to `./api`
|
||||||
|
There is `.env.example` file present at `./api` directory. Remember to provide enviornment variables else default values will be used mentioned in `.env.example` files
|
||||||
|
Command to install and run api server.
|
||||||
|
|
||||||
|
```
|
||||||
|
npm install
|
||||||
|
npm start
|
||||||
|
```
|
||||||
|
|
||||||
|
##### Web
|
||||||
|
|
||||||
|
Navigate to `./web`
|
||||||
|
There is `.env.example` file present at `./web` directory. Remember to provide enviornment variables else default values will be used mentioned in `.env.example` files
|
||||||
|
Command to install and run api server.
|
||||||
|
|
||||||
|
```
|
||||||
|
npm install
|
||||||
|
npm start
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Development (running only api server and have web build served):
|
||||||
|
|
||||||
|
##### API server also serving Web build files
|
||||||
|
|
||||||
|
There is `.env.example` file present at `./api` directory. Remember to provide enviornment variables else default values will be used mentioned in `.env.example` files
|
||||||
|
Command to install and run api server.
|
||||||
|
|
||||||
|
```
|
||||||
|
cd ./web && npm i && npm build && cd ../
|
||||||
|
cd ./api && npm i && npm start
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Production
|
||||||
|
|
||||||
|
##### API & WEB
|
||||||
|
|
||||||
|
```
|
||||||
|
npm run server
|
||||||
|
```
|
||||||
|
|
||||||
|
This will install/build `web` and install `api`, then start prod server.
|
||||||
|
|
||||||
|
## Executables
|
||||||
|
|
||||||
|
Command to generate executables
|
||||||
|
|
||||||
|
```
|
||||||
|
cd ./web && npm i && npm build && cd ../
|
||||||
|
cd ./api && npm i && npm run exe
|
||||||
|
```
|
||||||
|
|
||||||
|
This will install/build web app and install/create executables of sasjs server at root `./executables`
|
||||||
|
|||||||
@@ -1,84 +1,206 @@
|
|||||||
<mxfile host="65bd71144e">
|
<mxfile host="65bd71144e">
|
||||||
<diagram id="HJy_QFGaI9JSrArARLup" name="Page-1">
|
<diagram id="HJy_QFGaI9JSrArARLup" name="Page-1">
|
||||||
<mxGraphModel dx="1908" dy="2140" grid="1" gridSize="10" guides="1" tooltips="1" connect="1" arrows="1" fold="1" page="1" pageScale="1" pageWidth="827" pageHeight="1169" math="0" shadow="0">
|
<mxGraphModel dx="3103" dy="2723" grid="1" gridSize="10" guides="1" tooltips="1" connect="1" arrows="1" fold="1" page="1" pageScale="1" pageWidth="827" pageHeight="1169" math="0" shadow="0">
|
||||||
<root>
|
<root>
|
||||||
<mxCell id="0"/>
|
<mxCell id="0"/>
|
||||||
<mxCell id="1" parent="0"/>
|
<mxCell id="1" parent="0"/>
|
||||||
<mxCell id="4" value="End user" style="shape=umlActor;verticalLabelPosition=bottom;verticalAlign=top;html=1;outlineConnect=0;fontStyle=0" vertex="1" parent="1">
|
<mxCell id="7" value="SASjs Server" style="whiteSpace=wrap;html=1;verticalAlign=top;fontStyle=0;fontSize=30;" parent="1" vertex="1">
|
||||||
<mxGeometry x="-360" y="-120" width="40" height="80" as="geometry"/>
|
<mxGeometry x="30" y="-150" width="360" height="1250" as="geometry"/>
|
||||||
</mxCell>
|
</mxCell>
|
||||||
<mxCell id="7" value="SASjs Server" style="whiteSpace=wrap;html=1;verticalAlign=top;fontStyle=0;fontSize=30;" vertex="1" parent="1">
|
<mxCell id="36" value="<font style="font-size: 22px">Internal Authentication</font>" style="whiteSpace=wrap;html=1;verticalAlign=top;fontStyle=0;" vertex="1" parent="1">
|
||||||
<mxGeometry x="30" y="-150" width="360" height="850" as="geometry"/>
|
<mxGeometry x="50" y="-60" width="320" height="330" as="geometry"/>
|
||||||
</mxCell>
|
</mxCell>
|
||||||
<mxCell id="8" value="" style="edgeStyle=none;html=1;entryX=0;entryY=0.25;entryDx=0;entryDy=0;" edge="1" parent="1" target="28">
|
<mxCell id="4" value="End user" style="shape=umlActor;verticalLabelPosition=bottom;verticalAlign=top;html=1;outlineConnect=0;fontStyle=0" parent="1" vertex="1">
|
||||||
|
<mxGeometry x="-740" y="-120" width="40" height="80" as="geometry"/>
|
||||||
|
</mxCell>
|
||||||
|
<mxCell id="8" value="" style="edgeStyle=none;html=1;entryX=0;entryY=0.25;entryDx=0;entryDy=0;" parent="1" target="28" edge="1">
|
||||||
<mxGeometry relative="1" as="geometry">
|
<mxGeometry relative="1" as="geometry">
|
||||||
<mxPoint x="-340" y="23" as="sourcePoint"/>
|
<mxPoint x="-530" y="23" as="sourcePoint"/>
|
||||||
<mxPoint x="115" y="22.586363636363558" as="targetPoint"/>
|
<mxPoint x="115" y="22.586363636363558" as="targetPoint"/>
|
||||||
</mxGeometry>
|
</mxGeometry>
|
||||||
</mxCell>
|
</mxCell>
|
||||||
<mxCell id="11" value="<div style="font-family: &#34;menlo&#34; , &#34;monaco&#34; , &#34;courier new&#34; , monospace ; font-size: 12px ; line-height: 18px"><span style="color: #a31515">/SASjsApi/auth/authorize<br>(username,password,clientId)</span></div>" style="edgeLabel;html=1;align=center;verticalAlign=middle;resizable=0;points=[];" vertex="1" connectable="0" parent="8">
|
<mxCell id="11" value="<div style="font-family: &#34;menlo&#34; , &#34;monaco&#34; , &#34;courier new&#34; , monospace ; font-size: 12px ; line-height: 18px"><span style="color: #a31515">/SASjsApi/auth/authorize<br>(username,password,clientId)</span></div>" style="edgeLabel;html=1;align=center;verticalAlign=middle;resizable=0;points=[];" parent="8" vertex="1" connectable="0">
|
||||||
<mxGeometry x="-0.1257" y="2" relative="1" as="geometry">
|
<mxGeometry x="-0.1257" y="2" relative="1" as="geometry">
|
||||||
<mxPoint as="offset"/>
|
<mxPoint as="offset"/>
|
||||||
</mxGeometry>
|
</mxGeometry>
|
||||||
</mxCell>
|
</mxCell>
|
||||||
<mxCell id="14" value="" style="edgeStyle=none;html=1;exitX=-0.002;exitY=0.874;exitDx=0;exitDy=0;exitPerimeter=0;" edge="1" parent="1" source="28">
|
<mxCell id="14" value="" style="edgeStyle=none;html=1;exitX=-0.002;exitY=0.874;exitDx=0;exitDy=0;exitPerimeter=0;" parent="1" source="28" edge="1">
|
||||||
<mxGeometry relative="1" as="geometry">
|
<mxGeometry relative="1" as="geometry">
|
||||||
<mxPoint x="110" y="80" as="sourcePoint"/>
|
<mxPoint x="110" y="80" as="sourcePoint"/>
|
||||||
<mxPoint x="-340" y="80" as="targetPoint"/>
|
<mxPoint x="-530" y="80" as="targetPoint"/>
|
||||||
</mxGeometry>
|
</mxGeometry>
|
||||||
</mxCell>
|
</mxCell>
|
||||||
<mxCell id="16" value="<font color="#a31515" face="menlo, monaco, courier new, monospace"><span style="font-size: 12px">`code`</span></font>" style="edgeLabel;html=1;align=center;verticalAlign=middle;resizable=0;points=[];" vertex="1" connectable="0" parent="14">
|
<mxCell id="16" value="<font color="#a31515" face="menlo, monaco, courier new, monospace"><span style="font-size: 12px">`code`</span></font>" style="edgeLabel;html=1;align=center;verticalAlign=middle;resizable=0;points=[];" parent="14" vertex="1" connectable="0">
|
||||||
<mxGeometry x="0.1931" y="-1" relative="1" as="geometry">
|
<mxGeometry x="0.1931" y="-1" relative="1" as="geometry">
|
||||||
<mxPoint as="offset"/>
|
<mxPoint as="offset"/>
|
||||||
</mxGeometry>
|
</mxGeometry>
|
||||||
</mxCell>
|
</mxCell>
|
||||||
<mxCell id="21" value="End user" style="shape=umlActor;verticalLabelPosition=bottom;verticalAlign=top;html=1;outlineConnect=0;fontStyle=0" vertex="1" parent="1">
|
<mxCell id="21" value="End user" style="shape=umlActor;verticalLabelPosition=bottom;verticalAlign=top;html=1;outlineConnect=0;fontStyle=0" parent="1" vertex="1">
|
||||||
<mxGeometry x="-360" y="545" width="40" height="80" as="geometry"/>
|
<mxGeometry x="-730" y="1100" width="40" height="80" as="geometry"/>
|
||||||
</mxCell>
|
</mxCell>
|
||||||
<mxCell id="22" value="" style="edgeStyle=none;html=1;entryX=0;entryY=0.25;entryDx=0;entryDy=0;" edge="1" parent="1" target="30">
|
<mxCell id="22" value="" style="edgeStyle=none;html=1;entryX=0;entryY=0.25;entryDx=0;entryDy=0;" parent="1" target="30" edge="1">
|
||||||
<mxGeometry relative="1" as="geometry">
|
<mxGeometry relative="1" as="geometry">
|
||||||
<mxPoint x="-340" y="165" as="sourcePoint"/>
|
<mxPoint x="-530" y="163" as="sourcePoint"/>
|
||||||
<mxPoint x="115" y="165" as="targetPoint"/>
|
<mxPoint x="115" y="165" as="targetPoint"/>
|
||||||
</mxGeometry>
|
</mxGeometry>
|
||||||
</mxCell>
|
</mxCell>
|
||||||
<mxCell id="23" value="<div style="font-family: &#34;menlo&#34; , &#34;monaco&#34; , &#34;courier new&#34; , monospace ; font-size: 12px ; line-height: 18px"><div style="font-family: &#34;menlo&#34; , &#34;monaco&#34; , &#34;courier new&#34; , monospace ; line-height: 18px"><span style="color: #a31515">/SASjsApi/auth/token</span></div><span style="color: #a31515">(clientId,code)</span></div>" style="edgeLabel;html=1;align=center;verticalAlign=middle;resizable=0;points=[];" vertex="1" connectable="0" parent="22">
|
<mxCell id="23" value="<div style="font-family: &#34;menlo&#34; , &#34;monaco&#34; , &#34;courier new&#34; , monospace ; font-size: 12px ; line-height: 18px"><div style="font-family: &#34;menlo&#34; , &#34;monaco&#34; , &#34;courier new&#34; , monospace ; line-height: 18px"><span style="color: #a31515">/SASjsApi/auth/token</span></div><span style="color: #a31515">(clientId,code)</span></div>" style="edgeLabel;html=1;align=center;verticalAlign=middle;resizable=0;points=[];" parent="22" vertex="1" connectable="0">
|
||||||
<mxGeometry x="-0.1257" y="2" relative="1" as="geometry">
|
<mxGeometry x="-0.1257" y="2" relative="1" as="geometry">
|
||||||
<mxPoint as="offset"/>
|
<mxPoint as="offset"/>
|
||||||
</mxGeometry>
|
</mxGeometry>
|
||||||
</mxCell>
|
</mxCell>
|
||||||
<mxCell id="24" value="" style="edgeStyle=none;html=1;exitX=0.009;exitY=0.905;exitDx=0;exitDy=0;exitPerimeter=0;" edge="1" parent="1" source="30">
|
<mxCell id="24" value="" style="edgeStyle=none;html=1;exitX=0.009;exitY=0.905;exitDx=0;exitDy=0;exitPerimeter=0;" parent="1" source="30" edge="1">
|
||||||
<mxGeometry relative="1" as="geometry">
|
<mxGeometry relative="1" as="geometry">
|
||||||
<mxPoint x="210" y="222.5" as="sourcePoint"/>
|
<mxPoint x="210" y="222.5" as="sourcePoint"/>
|
||||||
<mxPoint x="-340" y="223" as="targetPoint"/>
|
<mxPoint x="-530" y="223" as="targetPoint"/>
|
||||||
</mxGeometry>
|
</mxGeometry>
|
||||||
</mxCell>
|
</mxCell>
|
||||||
<mxCell id="25" value="<font color="#a31515" face="menlo, monaco, courier new, monospace"><span style="font-size: 12px">`</span></font><span style="color: rgb(163 , 21 , 21) ; font-family: &#34;menlo&#34; , &#34;monaco&#34; , &#34;courier new&#34; , monospace ; font-size: 12px">accessToken</span><span style="font-size: 12px ; color: rgb(163 , 21 , 21) ; font-family: &#34;menlo&#34; , &#34;monaco&#34; , &#34;courier new&#34; , monospace">` &amp; `</span><span style="color: rgb(163 , 21 , 21) ; font-family: &#34;menlo&#34; , &#34;monaco&#34; , &#34;courier new&#34; , monospace ; font-size: 12px">refreshToken</span><span style="color: rgb(163 , 21 , 21) ; font-family: &#34;menlo&#34; , &#34;monaco&#34; , &#34;courier new&#34; , monospace ; font-size: 12px">`</span>" style="edgeLabel;html=1;align=center;verticalAlign=middle;resizable=0;points=[];" vertex="1" connectable="0" parent="24">
|
<mxCell id="25" value="<font color="#a31515" face="menlo, monaco, courier new, monospace"><span style="font-size: 12px">`</span></font><span style="color: rgb(163 , 21 , 21) ; font-family: &#34;menlo&#34; , &#34;monaco&#34; , &#34;courier new&#34; , monospace ; font-size: 12px">accessToken</span><span style="font-size: 12px ; color: rgb(163 , 21 , 21) ; font-family: &#34;menlo&#34; , &#34;monaco&#34; , &#34;courier new&#34; , monospace">` &amp; `</span><span style="color: rgb(163 , 21 , 21) ; font-family: &#34;menlo&#34; , &#34;monaco&#34; , &#34;courier new&#34; , monospace ; font-size: 12px">refreshToken</span><span style="color: rgb(163 , 21 , 21) ; font-family: &#34;menlo&#34; , &#34;monaco&#34; , &#34;courier new&#34; , monospace ; font-size: 12px">`</span>" style="edgeLabel;html=1;align=center;verticalAlign=middle;resizable=0;points=[];" parent="24" vertex="1" connectable="0">
|
||||||
<mxGeometry x="0.1931" y="-1" relative="1" as="geometry">
|
<mxGeometry x="0.1931" y="-1" relative="1" as="geometry">
|
||||||
<mxPoint as="offset"/>
|
<mxPoint as="offset"/>
|
||||||
</mxGeometry>
|
</mxGeometry>
|
||||||
</mxCell>
|
</mxCell>
|
||||||
<mxCell id="26" value="" style="endArrow=none;dashed=1;html=1;dashPattern=1 3;strokeWidth=2;" edge="1" parent="1" source="21" target="4">
|
<mxCell id="26" value="" style="endArrow=none;dashed=1;html=1;dashPattern=1 3;strokeWidth=2;" parent="1" source="21" target="4" edge="1">
|
||||||
<mxGeometry width="50" height="50" relative="1" as="geometry">
|
<mxGeometry width="50" height="50" relative="1" as="geometry">
|
||||||
<mxPoint x="40" y="240" as="sourcePoint"/>
|
<mxPoint x="-340" y="240" as="sourcePoint"/>
|
||||||
<mxPoint x="90" y="190" as="targetPoint"/>
|
<mxPoint x="-290" y="190" as="targetPoint"/>
|
||||||
</mxGeometry>
|
</mxGeometry>
|
||||||
</mxCell>
|
</mxCell>
|
||||||
<mxCell id="28" value="<span>Validates</span><br><span>username/password/clientId</span><br><span>and issue short</span><br><span>Authorization code</span>" style="rounded=1;whiteSpace=wrap;html=1;" vertex="1" parent="1">
|
<mxCell id="28" value="<span>Validates</span><br><span>username/password/clientId</span><br><span>and issue short</span><br><span>Authorization code</span>" style="rounded=1;whiteSpace=wrap;html=1;" parent="1" vertex="1">
|
||||||
<mxGeometry x="115" width="190" height="90" as="geometry"/>
|
<mxGeometry x="115" width="190" height="90" as="geometry"/>
|
||||||
</mxCell>
|
</mxCell>
|
||||||
<mxCell id="30" value="Validates<br>clientId &amp; authorization code<br>and issue<br>Access Token &amp; Refresh Token" style="rounded=1;whiteSpace=wrap;html=1;" vertex="1" parent="1">
|
<mxCell id="30" value="Validates<br>clientId &amp; authorization code<br>and issue<br>Access Token &amp; Refresh Token" style="rounded=1;whiteSpace=wrap;html=1;" parent="1" vertex="1">
|
||||||
<mxGeometry x="115" y="140" width="190" height="90" as="geometry"/>
|
<mxGeometry x="115" y="140" width="190" height="90" as="geometry"/>
|
||||||
</mxCell>
|
</mxCell>
|
||||||
<mxCell id="32" value="Protected APIs<br>Authenticate requests <br>with provided Bearer Token" style="whiteSpace=wrap;html=1;verticalAlign=top;fontStyle=0;" vertex="1" parent="1">
|
<mxCell id="32" value="Protected APIs<br>Authenticate requests <br>with provided Bearer Token" style="whiteSpace=wrap;html=1;verticalAlign=top;fontStyle=0;" parent="1" vertex="1">
|
||||||
<mxGeometry x="50" y="280" width="320" height="400" as="geometry"/>
|
<mxGeometry x="50" y="920" width="320" height="150" as="geometry"/>
|
||||||
</mxCell>
|
</mxCell>
|
||||||
<mxCell id="33" value="" style="edgeStyle=none;html=1;entryX=0;entryY=0.373;entryDx=0;entryDy=0;entryPerimeter=0;" edge="1" parent="1" target="32">
|
<mxCell id="33" value="" style="edgeStyle=none;html=1;entryX=-0.012;entryY=0.384;entryDx=0;entryDy=0;entryPerimeter=0;" parent="1" target="32" edge="1">
|
||||||
<mxGeometry relative="1" as="geometry">
|
<mxGeometry relative="1" as="geometry">
|
||||||
<mxPoint x="-340" y="432.5" as="sourcePoint"/>
|
<mxPoint x="-520" y="978" as="sourcePoint"/>
|
||||||
<mxPoint x="-10" y="430" as="targetPoint"/>
|
<mxPoint x="-80" y="819" as="targetPoint"/>
|
||||||
</mxGeometry>
|
</mxGeometry>
|
||||||
</mxCell>
|
</mxCell>
|
||||||
<mxCell id="34" value="<div style="font-family: &#34;menlo&#34; , &#34;monaco&#34; , &#34;courier new&#34; , monospace ; font-size: 12px ; line-height: 18px"><div style="font-family: &#34;menlo&#34; , &#34;monaco&#34; , &#34;courier new&#34; , monospace ; line-height: 18px"><font color="#a31515">Request with Access Token</font></div></div>" style="edgeLabel;html=1;align=center;verticalAlign=middle;resizable=0;points=[];" vertex="1" connectable="0" parent="33">
|
<mxCell id="34" value="<div style="font-family: &#34;menlo&#34; , &#34;monaco&#34; , &#34;courier new&#34; , monospace ; font-size: 12px ; line-height: 18px"><div style="font-family: &#34;menlo&#34; , &#34;monaco&#34; , &#34;courier new&#34; , monospace ; line-height: 18px"><font color="#a31515">Request with Access Token</font></div></div>" style="edgeLabel;html=1;align=center;verticalAlign=middle;resizable=0;points=[];" parent="33" vertex="1" connectable="0">
|
||||||
|
<mxGeometry x="-0.1257" y="2" relative="1" as="geometry">
|
||||||
|
<mxPoint as="offset"/>
|
||||||
|
</mxGeometry>
|
||||||
|
</mxCell>
|
||||||
|
<mxCell id="37" value="Browser" style="rounded=0;whiteSpace=wrap;html=1;fontSize=22;" vertex="1" parent="1">
|
||||||
|
<mxGeometry x="-590" y="-100" width="120" height="60" as="geometry"/>
|
||||||
|
</mxCell>
|
||||||
|
<mxCell id="38" value="Browser" style="rounded=0;whiteSpace=wrap;html=1;fontSize=22;" vertex="1" parent="1">
|
||||||
|
<mxGeometry x="-590" y="1110" width="120" height="60" as="geometry"/>
|
||||||
|
</mxCell>
|
||||||
|
<mxCell id="39" value="" style="endArrow=none;dashed=1;html=1;fontSize=22;entryX=0.5;entryY=1;entryDx=0;entryDy=0;exitX=0.5;exitY=0;exitDx=0;exitDy=0;" edge="1" parent="1" source="38" target="37">
|
||||||
|
<mxGeometry width="50" height="50" relative="1" as="geometry">
|
||||||
|
<mxPoint x="-340" y="390" as="sourcePoint"/>
|
||||||
|
<mxPoint x="-290" y="340" as="targetPoint"/>
|
||||||
|
<Array as="points"/>
|
||||||
|
</mxGeometry>
|
||||||
|
</mxCell>
|
||||||
|
<mxCell id="40" value="<font style="font-size: 22px">Okta Authentication</font>" style="whiteSpace=wrap;html=1;verticalAlign=top;fontStyle=0;" vertex="1" parent="1">
|
||||||
|
<mxGeometry x="50" y="300" width="320" height="560" as="geometry"/>
|
||||||
|
</mxCell>
|
||||||
|
<mxCell id="41" value="" style="edgeStyle=none;html=1;entryX=-0.013;entryY=0.092;entryDx=0;entryDy=0;entryPerimeter=0;" edge="1" parent="1" target="49">
|
||||||
|
<mxGeometry relative="1" as="geometry">
|
||||||
|
<mxPoint x="-530" y="373" as="sourcePoint"/>
|
||||||
|
<mxPoint x="115" y="372.58636363636356" as="targetPoint"/>
|
||||||
|
</mxGeometry>
|
||||||
|
</mxCell>
|
||||||
|
<mxCell id="42" value="<div style="font-family: &#34;menlo&#34; , &#34;monaco&#34; , &#34;courier new&#34; , monospace ; font-size: 12px ; line-height: 18px"><span style="color: #a31515">/SASjsApi/auth/okta/authorize<br></span></div>" style="edgeLabel;html=1;align=center;verticalAlign=middle;resizable=0;points=[];" vertex="1" connectable="0" parent="41">
|
||||||
|
<mxGeometry x="-0.1257" y="2" relative="1" as="geometry">
|
||||||
|
<mxPoint as="offset"/>
|
||||||
|
</mxGeometry>
|
||||||
|
</mxCell>
|
||||||
|
<mxCell id="49" value="redirects to okta server<br><br><br><br>OKTA OIDC middleware<br>https://github.com/okta/okta-oidc-middleware<br><br><br><br>OKTA nodeJS Express implementation<br>https://github.com/okta/samples-nodejs-express-4/tree/master/okta-hosted-login<br>" style="rounded=1;whiteSpace=wrap;html=1;" vertex="1" parent="1">
|
||||||
|
<mxGeometry x="115" y="350" width="190" height="280" as="geometry"/>
|
||||||
|
</mxCell>
|
||||||
|
<mxCell id="75" style="edgeStyle=none;html=1;exitX=0.5;exitY=1;exitDx=0;exitDy=0;entryX=0.5;entryY=0;entryDx=0;entryDy=0;fontSize=14;" edge="1" parent="1" source="50" target="32">
|
||||||
|
<mxGeometry relative="1" as="geometry"/>
|
||||||
|
</mxCell>
|
||||||
|
<mxCell id="50" value="Validates express session <br>through OKTA OIDC middleware" style="rounded=1;whiteSpace=wrap;html=1;" vertex="1" parent="1">
|
||||||
|
<mxGeometry x="115" y="710" width="190" height="90" as="geometry"/>
|
||||||
|
</mxCell>
|
||||||
|
<mxCell id="51" value="<span style="font-size: 22px">Okta Authorization Server<br></span>" style="whiteSpace=wrap;html=1;verticalAlign=top;fontStyle=0;" vertex="1" parent="1">
|
||||||
|
<mxGeometry x="600" y="300" width="320" height="380" as="geometry"/>
|
||||||
|
</mxCell>
|
||||||
|
<mxCell id="52" value="" style="rounded=1;whiteSpace=wrap;html=1;" vertex="1" parent="1">
|
||||||
|
<mxGeometry x="665" y="350" width="190" height="280" as="geometry"/>
|
||||||
|
</mxCell>
|
||||||
|
<mxCell id="53" value="" style="endArrow=classic;html=1;fontSize=22;exitX=1.002;exitY=0.123;exitDx=0;exitDy=0;exitPerimeter=0;" edge="1" parent="1" source="49">
|
||||||
|
<mxGeometry width="50" height="50" relative="1" as="geometry">
|
||||||
|
<mxPoint x="400" y="480" as="sourcePoint"/>
|
||||||
|
<mxPoint x="660" y="384" as="targetPoint"/>
|
||||||
|
</mxGeometry>
|
||||||
|
</mxCell>
|
||||||
|
<mxCell id="54" value="<span style="color: rgb(163 , 21 , 21) ; font-family: &#34;menlo&#34; , &#34;monaco&#34; , &#34;courier new&#34; , monospace ; font-size: 12px">/authorize</span>" style="edgeLabel;html=1;align=center;verticalAlign=middle;resizable=0;points=[];fontSize=22;" vertex="1" connectable="0" parent="53">
|
||||||
|
<mxGeometry x="0.0222" y="1" relative="1" as="geometry">
|
||||||
|
<mxPoint as="offset"/>
|
||||||
|
</mxGeometry>
|
||||||
|
</mxCell>
|
||||||
|
<mxCell id="58" value="" style="endArrow=classic;html=1;fontSize=22;exitX=-0.016;exitY=0.291;exitDx=0;exitDy=0;exitPerimeter=0;" edge="1" parent="1" source="52">
|
||||||
|
<mxGeometry relative="1" as="geometry">
|
||||||
|
<mxPoint x="-300" y="470" as="sourcePoint"/>
|
||||||
|
<mxPoint x="-530" y="431" as="targetPoint"/>
|
||||||
|
</mxGeometry>
|
||||||
|
</mxCell>
|
||||||
|
<mxCell id="61" value="302 redirect to authentication prompt&nbsp;" style="edgeLabel;html=1;align=center;verticalAlign=middle;resizable=0;points=[];fontSize=22;" vertex="1" connectable="0" parent="58">
|
||||||
|
<mxGeometry x="-0.659" y="3" relative="1" as="geometry">
|
||||||
|
<mxPoint x="-630" as="offset"/>
|
||||||
|
</mxGeometry>
|
||||||
|
</mxCell>
|
||||||
|
<mxCell id="62" value="" style="endArrow=classic;html=1;fontSize=22;" edge="1" parent="1">
|
||||||
|
<mxGeometry relative="1" as="geometry">
|
||||||
|
<mxPoint x="-530" y="500" as="sourcePoint"/>
|
||||||
|
<mxPoint x="665" y="500.48" as="targetPoint"/>
|
||||||
|
</mxGeometry>
|
||||||
|
</mxCell>
|
||||||
|
<mxCell id="64" value="Authentication &amp; Consent" style="edgeLabel;html=1;align=center;verticalAlign=middle;resizable=0;points=[];fontSize=22;" vertex="1" connectable="0" parent="62">
|
||||||
|
<mxGeometry x="-0.4695" y="6" relative="1" as="geometry">
|
||||||
|
<mxPoint as="offset"/>
|
||||||
|
</mxGeometry>
|
||||||
|
</mxCell>
|
||||||
|
<mxCell id="65" value="" style="endArrow=classic;html=1;fontSize=22;exitX=0;exitY=0.679;exitDx=0;exitDy=0;exitPerimeter=0;entryX=0.995;entryY=0.679;entryDx=0;entryDy=0;entryPerimeter=0;" edge="1" parent="1" source="52" target="49">
|
||||||
|
<mxGeometry width="50" height="50" relative="1" as="geometry">
|
||||||
|
<mxPoint x="230" y="560" as="sourcePoint"/>
|
||||||
|
<mxPoint x="280" y="510" as="targetPoint"/>
|
||||||
|
</mxGeometry>
|
||||||
|
</mxCell>
|
||||||
|
<mxCell id="66" value="Authorization Code to redirect uri" style="edgeLabel;html=1;align=center;verticalAlign=middle;resizable=0;points=[];fontSize=14;" vertex="1" connectable="0" parent="65">
|
||||||
|
<mxGeometry x="0.0583" y="1" relative="1" as="geometry">
|
||||||
|
<mxPoint x="26" as="offset"/>
|
||||||
|
</mxGeometry>
|
||||||
|
</mxCell>
|
||||||
|
<mxCell id="67" value="" style="endArrow=classic;html=1;fontSize=22;exitX=0;exitY=0.679;exitDx=0;exitDy=0;exitPerimeter=0;entryX=0.995;entryY=0.679;entryDx=0;entryDy=0;entryPerimeter=0;" edge="1" parent="1">
|
||||||
|
<mxGeometry width="50" height="50" relative="1" as="geometry">
|
||||||
|
<mxPoint x="304.0500000000002" y="569.9999999999999" as="sourcePoint"/>
|
||||||
|
<mxPoint x="665.0000000000005" y="569.9999999999999" as="targetPoint"/>
|
||||||
|
</mxGeometry>
|
||||||
|
</mxCell>
|
||||||
|
<mxCell id="68" value="<span style="color: rgb(163 , 21 , 21) ; font-family: &#34;menlo&#34; , &#34;monaco&#34; , &#34;courier new&#34; , monospace ; font-size: 12px">/token</span>" style="edgeLabel;html=1;align=center;verticalAlign=middle;resizable=0;points=[];fontSize=14;" vertex="1" connectable="0" parent="67">
|
||||||
|
<mxGeometry x="0.0583" y="1" relative="1" as="geometry">
|
||||||
|
<mxPoint x="-5" y="1" as="offset"/>
|
||||||
|
</mxGeometry>
|
||||||
|
</mxCell>
|
||||||
|
<mxCell id="69" value="" style="endArrow=classic;html=1;fontSize=22;exitX=0;exitY=0.679;exitDx=0;exitDy=0;exitPerimeter=0;entryX=0.995;entryY=0.679;entryDx=0;entryDy=0;entryPerimeter=0;" edge="1" parent="1">
|
||||||
|
<mxGeometry width="50" height="50" relative="1" as="geometry">
|
||||||
|
<mxPoint x="665.9500000000005" y="599.9999999999999" as="sourcePoint"/>
|
||||||
|
<mxPoint x="305.00000000000017" y="599.9999999999999" as="targetPoint"/>
|
||||||
|
</mxGeometry>
|
||||||
|
</mxCell>
|
||||||
|
<mxCell id="70" value="Access Token" style="edgeLabel;html=1;align=center;verticalAlign=middle;resizable=0;points=[];fontSize=14;" vertex="1" connectable="0" parent="69">
|
||||||
|
<mxGeometry x="0.0583" y="1" relative="1" as="geometry">
|
||||||
|
<mxPoint x="26" as="offset"/>
|
||||||
|
</mxGeometry>
|
||||||
|
</mxCell>
|
||||||
|
<mxCell id="71" value="" style="edgeStyle=none;html=1;entryX=-0.012;entryY=0.384;entryDx=0;entryDy=0;entryPerimeter=0;" edge="1" parent="1">
|
||||||
|
<mxGeometry relative="1" as="geometry">
|
||||||
|
<mxPoint x="-530" y="760" as="sourcePoint"/>
|
||||||
|
<mxPoint x="115.00000000000031" y="759.9999999999999" as="targetPoint"/>
|
||||||
|
</mxGeometry>
|
||||||
|
</mxCell>
|
||||||
|
<mxCell id="72" value="<div style="font-family: &#34;menlo&#34; , &#34;monaco&#34; , &#34;courier new&#34; , monospace ; font-size: 12px ; line-height: 18px"><div style="font-family: &#34;menlo&#34; , &#34;monaco&#34; , &#34;courier new&#34; , monospace ; line-height: 18px"><font color="#a31515">Request with OKTA mechanism</font></div></div>" style="edgeLabel;html=1;align=center;verticalAlign=middle;resizable=0;points=[];" vertex="1" connectable="0" parent="71">
|
||||||
<mxGeometry x="-0.1257" y="2" relative="1" as="geometry">
|
<mxGeometry x="-0.1257" y="2" relative="1" as="geometry">
|
||||||
<mxPoint as="offset"/>
|
<mxPoint as="offset"/>
|
||||||
</mxGeometry>
|
</mxGeometry>
|
||||||
|
|||||||
3
SASjsServer.svg
Normal file
3
SASjsServer.svg
Normal file
File diff suppressed because one or more lines are too long
|
After Width: | Height: | Size: 37 KiB |
@@ -72,6 +72,7 @@ export class ExecutionController {
|
|||||||
%if "&SYSTCPIPHOSTNAME"="" %then %let SYSTCPIPHOSTNAME=&_sasjs_apiserverurl;
|
%if "&SYSTCPIPHOSTNAME"="" %then %let SYSTCPIPHOSTNAME=&_sasjs_apiserverurl;
|
||||||
%mend;
|
%mend;
|
||||||
%_sasjs_server_init()
|
%_sasjs_server_init()
|
||||||
|
%sysmacdelete _sasjs_server_init;
|
||||||
`
|
`
|
||||||
|
|
||||||
program = `
|
program = `
|
||||||
|
|||||||
@@ -14,14 +14,14 @@ services:
|
|||||||
REFRESH_TOKEN_SECRET: ${REFRESH_TOKEN_SECRET}
|
REFRESH_TOKEN_SECRET: ${REFRESH_TOKEN_SECRET}
|
||||||
AUTH_CODE_SECRET: ${AUTH_CODE_SECRET}
|
AUTH_CODE_SECRET: ${AUTH_CODE_SECRET}
|
||||||
DB_CONNECT: mongodb://mongodb:27017/sasjs
|
DB_CONNECT: mongodb://mongodb:27017/sasjs
|
||||||
SAS_PATH: /usr/server/sasexe/${SAS_EXEC_NAME}
|
SAS_PATH: /usr/server/sasexe
|
||||||
expose:
|
expose:
|
||||||
- ${PORT_API}
|
- ${PORT_API}
|
||||||
ports:
|
ports:
|
||||||
- ${PORT_API}:${PORT_API}
|
- ${PORT_API}:${PORT_API}
|
||||||
volumes:
|
volumes:
|
||||||
- type: bind
|
- type: bind
|
||||||
source: ${SAS_EXEC_PATH}
|
source: ${SAS_EXEC}
|
||||||
target: /usr/server/sasexe
|
target: /usr/server/sasexe
|
||||||
read_only: true
|
read_only: true
|
||||||
links:
|
links:
|
||||||
|
|||||||
4
package-lock.json
generated
4
package-lock.json
generated
@@ -1,12 +1,12 @@
|
|||||||
{
|
{
|
||||||
"name": "server",
|
"name": "server",
|
||||||
"version": "0.0.24",
|
"version": "0.0.23",
|
||||||
"lockfileVersion": 2,
|
"lockfileVersion": 2,
|
||||||
"requires": true,
|
"requires": true,
|
||||||
"packages": {
|
"packages": {
|
||||||
"": {
|
"": {
|
||||||
"name": "server",
|
"name": "server",
|
||||||
"version": "0.0.24",
|
"version": "0.0.23",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@sasjs/core": "3.11.0"
|
"@sasjs/core": "3.11.0"
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "server",
|
"name": "server",
|
||||||
"version": "0.0.24",
|
"version": "0.0.23",
|
||||||
"description": "NodeJS wrapper for calling the SAS binary executable",
|
"description": "NodeJS wrapper for calling the SAS binary executable",
|
||||||
"repository": "https://github.com/sasjs/server",
|
"repository": "https://github.com/sasjs/server",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
|
|||||||
Reference in New Issue
Block a user