1
0
mirror of https://github.com/sasjs/adapter.git synced 2025-12-11 01:14:36 +00:00

Compare commits

...

233 Commits

Author SHA1 Message Date
Krishna Acondy
1d31ec4dcc Merge pull request #218 from sasjs/axios-fetch
fix(*): replace native fetch calls with axios
2021-02-15 12:50:13 +00:00
Krishna Acondy
4407ed68ae Merge branch 'master' of https://github.com/sasjs/adapter into axios-fetch 2021-02-15 12:46:11 +00:00
Krishna Acondy
b3359f2138 Merge pull request #241 from sasjs/dependabot/npm_and_yarn/webpack-5.21.2
chore(deps-dev): bump webpack from 5.13.0 to 5.21.2
2021-02-15 08:43:03 +00:00
dependabot-preview[bot]
cff9104adf chore(deps-dev): bump webpack from 5.13.0 to 5.21.2
Bumps [webpack](https://github.com/webpack/webpack) from 5.13.0 to 5.21.2.
- [Release notes](https://github.com/webpack/webpack/releases)
- [Commits](https://github.com/webpack/webpack/compare/v5.13.0...v5.21.2)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>
2021-02-15 08:41:19 +00:00
Krishna Acondy
b73f821c19 Merge pull request #250 from sasjs/dependabot/npm_and_yarn/sasjs/utils-2.5.0
chore(deps): bump @sasjs/utils from 2.0.2 to 2.5.0
2021-02-15 08:39:09 +00:00
dependabot-preview[bot]
dd3c1a7375 chore(deps): bump @sasjs/utils from 2.0.2 to 2.5.0
Bumps [@sasjs/utils](https://github.com/sasjs/utils) from 2.0.2 to 2.5.0.
- [Release notes](https://github.com/sasjs/utils/releases)
- [Commits](https://github.com/sasjs/utils/compare/v2.0.2...v2.5.0)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>
2021-02-15 08:37:17 +00:00
Krishna Acondy
c10b5368af Merge pull request #251 from sasjs/dependabot/npm_and_yarn/semantic-release-17.3.9
chore(deps-dev): bump semantic-release from 17.3.1 to 17.3.9
2021-02-15 08:35:10 +00:00
dependabot-preview[bot]
2df66765c0 chore(deps-dev): bump semantic-release from 17.3.1 to 17.3.9
Bumps [semantic-release](https://github.com/semantic-release/semantic-release) from 17.3.1 to 17.3.9.
- [Release notes](https://github.com/semantic-release/semantic-release/releases)
- [Commits](https://github.com/semantic-release/semantic-release/compare/v17.3.1...v17.3.9)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>
2021-02-15 08:29:58 +00:00
Krishna Acondy
ed65545571 Merge pull request #248 from sasjs/dependabot/npm_and_yarn/ts-loader-8.0.17
chore(deps-dev): bump ts-loader from 8.0.14 to 8.0.17
2021-02-15 08:27:46 +00:00
dependabot-preview[bot]
b4ae486520 chore(deps-dev): bump ts-loader from 8.0.14 to 8.0.17
Bumps [ts-loader](https://github.com/TypeStrong/ts-loader) from 8.0.14 to 8.0.17.
- [Release notes](https://github.com/TypeStrong/ts-loader/releases)
- [Changelog](https://github.com/TypeStrong/ts-loader/blob/master/CHANGELOG.md)
- [Commits](https://github.com/TypeStrong/ts-loader/compare/v8.0.14...v8.0.17)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>
2021-02-15 08:23:51 +00:00
Krishna Acondy
bb7b3d0b84 Merge pull request #249 from sasjs/dependabot/npm_and_yarn/typescript-3.9.9
chore(deps-dev): bump typescript from 3.9.7 to 3.9.9
2021-02-15 08:21:44 +00:00
dependabot-preview[bot]
65b34aa015 chore(deps-dev): bump typescript from 3.9.7 to 3.9.9
Bumps [typescript](https://github.com/Microsoft/TypeScript) from 3.9.7 to 3.9.9.
- [Release notes](https://github.com/Microsoft/TypeScript/releases)
- [Commits](https://github.com/Microsoft/TypeScript/compare/v3.9.7...v3.9.9)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>
2021-02-15 08:12:05 +00:00
Krishna Acondy
b3c9303def Merge pull request #235 from sasjs/dependabot/npm_and_yarn/webpack-cli-4.5.0
chore(deps-dev): bump webpack-cli from 4.3.1 to 4.5.0
2021-02-15 08:09:42 +00:00
dependabot-preview[bot]
19dfda9b6a chore(deps-dev): bump webpack-cli from 4.3.1 to 4.5.0
Bumps [webpack-cli](https://github.com/webpack/webpack-cli) from 4.3.1 to 4.5.0.
- [Release notes](https://github.com/webpack/webpack-cli/releases)
- [Changelog](https://github.com/webpack/webpack-cli/blob/master/CHANGELOG.md)
- [Commits](https://github.com/webpack/webpack-cli/compare/webpack-cli@4.3.1...webpack-cli@4.5.0)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>
2021-02-15 08:01:11 +00:00
Krishna Acondy
ce2abb448f Merge pull request #217 from sasjs/dependabot/npm_and_yarn/typedoc-neo-theme-1.1.0
chore(deps-dev): bump typedoc-neo-theme from 1.0.10 to 1.1.0
2021-02-15 07:59:06 +00:00
Krishna Acondy
413c3b8098 Merge branch 'axios-fetch' of https://github.com/sasjs/adapter into axios-fetch 2021-02-10 08:19:51 +00:00
Krishna Acondy
269514a44f fix(*): expose CSRF token, add getFolder API 2021-02-10 08:19:48 +00:00
Saad Jutt
5fc334dd8b chore: param 'insecure' removed 2021-02-09 17:57:01 +05:00
Krishna Acondy
1b251f1cea fix(auth): auto submit auth form if needed 2021-02-08 19:07:37 +00:00
Krishna Acondy
70d3e25c7f Merge branch 'axios-fetch' of https://github.com/sasjs/adapter into axios-fetch 2021-02-08 08:31:55 +00:00
Krishna Acondy
5e9b33e346 chore(*): fix sasjs tests 2021-02-08 08:31:42 +00:00
Krishna Acondy
eb52ec7532 Merge branch 'master' into axios-fetch 2021-02-06 13:23:30 +00:00
Krishna Acondy
f46c4bf3ca Merge branch 'axios-fetch' of https://github.com/sasjs/adapter into axios-fetch 2021-02-06 13:00:31 +00:00
Krishna Acondy
d8176912cf fix(requests): only allow insecure requests if https module is available 2021-02-06 13:00:27 +00:00
dependabot-preview[bot]
4c54ade2d3 chore(deps-dev): bump typedoc-neo-theme from 1.0.10 to 1.1.0
Bumps [typedoc-neo-theme](https://github.com/google/typedoc-neo-theme) from 1.0.10 to 1.1.0.
- [Release notes](https://github.com/google/typedoc-neo-theme/releases)
- [Commits](https://github.com/google/typedoc-neo-theme/commits)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>
2021-02-06 06:54:47 +00:00
Yury Shkoda
52c41dfb3a Merge pull request #196 from sasjs/releaseScript
Release script
2021-02-06 09:52:44 +03:00
Yury Shkoda
36f0aa7411 Merge branch 'master' into releaseScript 2021-02-06 09:31:21 +03:00
Saad Jutt
a10e4ec264 fix(*): fix invalid typing 2021-02-05 19:03:20 +05:00
Krishna Acondy
851b6bc273 chore(*): change import to require 2021-02-05 12:21:33 +00:00
Krishna Acondy
23f8d31b1b fix(*): support multipart form data post 2021-02-05 11:10:57 +00:00
Krishna Acondy
a5683bcd07 fix(insecure-requests): add flag to config 2021-02-05 09:33:42 +00:00
Krishna Acondy
c7be71c781 fix(*): add the ability to ignore SSL errors 2021-02-05 08:56:40 +00:00
Krishna Acondy
594f274323 chore(*): bump dependencies for sasjs-tests 2021-02-05 08:24:13 +00:00
Krishna Acondy
ba1ed5e732 fix(job-execution): throw error if job name is empty 2021-02-05 08:23:25 +00:00
Krishna Acondy
613cc6b9ef chore(*): clean up, handle debug responses 2021-02-04 09:42:39 +00:00
Krishna Acondy
8edb00f869 fix(request-client): handle SAS9 error scenarios, clear CSRF tokens on log out 2021-02-03 09:34:34 +00:00
Krishna Acondy
60a1f84604 chore(*): clean up, address review comments 2021-02-02 08:42:01 +00:00
Krishna Acondy
36cfaee5db chore(*): fix package.json format 2021-02-02 08:21:25 +00:00
Krishna Acondy
cb607c93ca Merge branch 'master' into axios-fetch 2021-02-02 08:19:53 +00:00
Krishna Acondy
03b5e1d824 chore(*): refactor common functionality into JobExecutor, handle all auth-related scenarios 2021-02-02 08:18:48 +00:00
Krishna Acondy
85a530ae5a Merge pull request #231 from sasjs/insecure-connection
feat: enable insecure connection for accessToken
2021-01-29 12:10:41 +00:00
Krishna Acondy
2ea49a425f fix(*): post request bodies as JSON 2021-01-28 20:36:41 +00:00
Krishna Acondy
3c894c4147 fix(*): handled 404s, set correct accept headers 2021-01-28 19:25:23 +00:00
Krishna Acondy
23d151c919 chore(*): commit missed file 2021-01-28 17:02:19 +00:00
Krishna Acondy
6d1c4ff81a fix(*): fix compute job execution 2021-01-28 17:01:59 +00:00
Krishna Acondy
0eba6bdcf4 chore(*): fix tests 2021-01-27 22:03:40 +00:00
Krishna Acondy
d7ecaf5932 fix(*): separate job execution code from main SASjs class 2021-01-27 20:30:13 +00:00
Saad Jutt
1fc6db114d chore: docs updated 2021-01-27 15:57:21 +05:00
Saad Jutt
8d203b8df4 chore: annotation added 2021-01-27 15:47:15 +05:00
Saad Jutt
39924ff078 chore: added 'https' 2021-01-26 18:45:21 +05:00
Saad Jutt
de25f106ec feat: enable insecure connection for accessToken 2021-01-26 17:17:46 +05:00
Krishna Acondy
e0d85f458b fix(*): store CSRF tokens in Request Client 2021-01-24 18:23:18 +00:00
Krishna Acondy
3a9cd46e6e chore(*): use server type from utils types 2021-01-24 16:02:34 +00:00
Krishna Acondy
301edab8ad chore(*): refactor and add tests 2021-01-24 15:08:35 +00:00
Krishna Acondy
aed39c2ec4 chore(*): refactor, move all auth-related code to auth folder 2021-01-24 13:07:15 +00:00
Krishna Acondy
e31774ae9d fix(*): fix login issue 2021-01-19 09:29:29 +00:00
Krishna Acondy
00f09179a8 chore(*): remove unnecessary imports 2021-01-19 09:07:40 +00:00
Krishna Acondy
4196901e01 chore(*): remove comment 2021-01-19 08:17:42 +00:00
Krishna Acondy
bf35dd072a chore(*): fix failing tests 2021-01-19 08:16:08 +00:00
Krishna Acondy
75e3fd018d chore(*): replace fetch calls with axios 2021-01-18 09:22:10 +00:00
Krishna Acondy
965dfff7c6 chore(*): use axios instead of fetch 2021-01-18 09:07:36 +00:00
Krishna Acondy
ff64dd22ad chore(*): use local axios instance 2021-01-18 09:01:07 +00:00
Krishna Acondy
e7cceab065 chore(*): add axios 2021-01-18 09:00:16 +00:00
Krishna Acondy
f789b8f7a2 fix(*): extracted auth logic into separate class, used axios instead of fetch 2021-01-18 08:59:58 +00:00
Yury Shkoda
c0b82c5125 Merge pull request #211 from sasjs/deps-fix
chore(deps): rolled back isomorphic-fetch
2021-01-13 15:38:27 +03:00
Yury Shkoda
1c1b5baefe chore(deps): rolled back isomorphic-fetch 2021-01-13 15:22:07 +03:00
Yury Shkoda
8b17aeaea2 Merge pull request #121 from sasjs/dependabot/npm_and_yarn/isomorphic-fetch-3.0.0
chore(deps): bump isomorphic-fetch from 2.2.1 to 3.0.0
2021-01-13 12:36:28 +03:00
Yury Shkoda
cb0d03c965 Merge branch 'master' into dependabot/npm_and_yarn/isomorphic-fetch-3.0.0 2021-01-13 12:34:40 +03:00
Yury Shkoda
9e77f3d64e Merge pull request #191 from sasjs/dependabot/npm_and_yarn/typedoc-0.19.2
chore(deps-dev): bump typedoc from 0.17.8 to 0.19.2
2021-01-13 12:34:03 +03:00
Yury Shkoda
25f61815dc Merge branch 'master' into dependabot/npm_and_yarn/typedoc-0.19.2 2021-01-13 12:30:51 +03:00
dependabot-preview[bot]
3a2252e69c chore(deps-dev): bump typedoc from 0.17.8 to 0.19.2
Bumps [typedoc](https://github.com/TypeStrong/TypeDoc) from 0.17.8 to 0.19.2.
- [Release notes](https://github.com/TypeStrong/TypeDoc/releases)
- [Commits](https://github.com/TypeStrong/TypeDoc/compare/0.17.8...v0.19.2)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>
2021-01-13 09:30:42 +00:00
dependabot-preview[bot]
8a08980e6a chore(deps): bump isomorphic-fetch from 2.2.1 to 3.0.0
Bumps [isomorphic-fetch](https://github.com/matthew-andrews/isomorphic-fetch) from 2.2.1 to 3.0.0.
- [Release notes](https://github.com/matthew-andrews/isomorphic-fetch/releases)
- [Commits](https://github.com/matthew-andrews/isomorphic-fetch/compare/v2.2.1...v3.0.0)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>
2021-01-13 09:30:40 +00:00
Yury Shkoda
d0f31771ad Merge pull request #194 from sasjs/dependabot/npm_and_yarn/semantic-release-17.3.1
chore(deps-dev): bump semantic-release from 17.3.0 to 17.3.1
2021-01-13 12:30:22 +03:00
Yury Shkoda
e9e2c9372d Merge branch 'master' into dependabot/npm_and_yarn/semantic-release-17.3.1 2021-01-13 12:28:50 +03:00
Yury Shkoda
70c4a095a0 Merge pull request #199 from sasjs/dependabot/npm_and_yarn/webpack-cli-4.3.1
chore(deps-dev): bump webpack-cli from 4.2.0 to 4.3.1
2021-01-13 12:28:29 +03:00
Yury Shkoda
82e2fc4445 Merge branch 'master' into dependabot/npm_and_yarn/webpack-cli-4.3.1 2021-01-13 12:26:22 +03:00
dependabot-preview[bot]
6661d81fdf chore(deps-dev): bump semantic-release from 17.3.0 to 17.3.1
Bumps [semantic-release](https://github.com/semantic-release/semantic-release) from 17.3.0 to 17.3.1.
- [Release notes](https://github.com/semantic-release/semantic-release/releases)
- [Commits](https://github.com/semantic-release/semantic-release/compare/v17.3.0...v17.3.1)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>
2021-01-13 09:26:20 +00:00
dependabot-preview[bot]
e76abaafa8 chore(deps-dev): bump webpack-cli from 4.2.0 to 4.3.1
Bumps [webpack-cli](https://github.com/webpack/webpack-cli) from 4.2.0 to 4.3.1.
- [Release notes](https://github.com/webpack/webpack-cli/releases)
- [Changelog](https://github.com/webpack/webpack-cli/blob/master/CHANGELOG.md)
- [Commits](https://github.com/webpack/webpack-cli/compare/webpack-cli@4.2.0...webpack-cli@4.3.1)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>
2021-01-13 09:26:13 +00:00
Yury Shkoda
fbfc1c05d6 Merge pull request #200 from sasjs/dependabot/npm_and_yarn/typedoc-plugin-external-module-name-4.0.6
chore(deps-dev): bump typedoc-plugin-external-module-name from 4.0.5 to 4.0.6
2021-01-13 12:25:47 +03:00
Yury Shkoda
839c211c64 Merge branch 'master' into dependabot/npm_and_yarn/typedoc-plugin-external-module-name-4.0.6 2021-01-13 12:24:19 +03:00
Yury Shkoda
f3ff82143a Merge pull request #204 from sasjs/dependabot/npm_and_yarn/ts-loader-8.0.14
chore(deps-dev): bump ts-loader from 8.0.12 to 8.0.14
2021-01-13 12:24:02 +03:00
dependabot-preview[bot]
0dd0abae87 chore(deps-dev): bump typedoc-plugin-external-module-name
Bumps [typedoc-plugin-external-module-name](https://github.com/christopherthielen/typedoc-plugin-external-module-name) from 4.0.5 to 4.0.6.
- [Release notes](https://github.com/christopherthielen/typedoc-plugin-external-module-name/releases)
- [Changelog](https://github.com/christopherthielen/typedoc-plugin-external-module-name/blob/master/CHANGELOG.md)
- [Commits](https://github.com/christopherthielen/typedoc-plugin-external-module-name/compare/4.0.5...4.0.6)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>
2021-01-13 09:23:15 +00:00
Yury Shkoda
13781c993e Merge branch 'master' into dependabot/npm_and_yarn/ts-loader-8.0.14 2021-01-13 12:21:25 +03:00
Yury Shkoda
7616cacbec Merge pull request #205 from sasjs/dependabot/npm_and_yarn/types/jest-26.0.20
chore(deps-dev): bump @types/jest from 26.0.19 to 26.0.20
2021-01-13 12:21:01 +03:00
dependabot-preview[bot]
cab7d3c012 chore(deps-dev): bump ts-loader from 8.0.12 to 8.0.14
Bumps [ts-loader](https://github.com/TypeStrong/ts-loader) from 8.0.12 to 8.0.14.
- [Release notes](https://github.com/TypeStrong/ts-loader/releases)
- [Changelog](https://github.com/TypeStrong/ts-loader/blob/master/CHANGELOG.md)
- [Commits](https://github.com/TypeStrong/ts-loader/compare/v8.0.12...v8.0.14)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>
2021-01-13 09:20:57 +00:00
Yury Shkoda
dfce676fdf Merge branch 'master' into dependabot/npm_and_yarn/types/jest-26.0.20 2021-01-13 12:18:53 +03:00
dependabot-preview[bot]
1890cab623 chore(deps-dev): bump @types/jest from 26.0.19 to 26.0.20
Bumps [@types/jest](https://github.com/DefinitelyTyped/DefinitelyTyped/tree/HEAD/types/jest) from 26.0.19 to 26.0.20.
- [Release notes](https://github.com/DefinitelyTyped/DefinitelyTyped/releases)
- [Commits](https://github.com/DefinitelyTyped/DefinitelyTyped/commits/HEAD/types/jest)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>
2021-01-13 09:18:44 +00:00
Yury Shkoda
4307d8fe43 Merge pull request #207 from sasjs/dependabot/npm_and_yarn/webpack-5.13.0
chore(deps-dev): bump webpack from 4.44.2 to 5.13.0
2021-01-13 12:18:17 +03:00
Yury Shkoda
8df6fdbee6 Merge branch 'master' into dependabot/npm_and_yarn/webpack-5.13.0 2021-01-13 12:16:49 +03:00
Yury Shkoda
ac5c2a3088 Merge pull request #210 from sasjs/dependabot/npm_and_yarn/sasjs/utils-2.0.2
chore(deps): bump @sasjs/utils from 1.5.0 to 2.0.2
2021-01-13 12:16:18 +03:00
dependabot-preview[bot]
0212b677ae chore(deps): bump @sasjs/utils from 1.5.0 to 2.0.2
Bumps [@sasjs/utils](https://github.com/sasjs/utils) from 1.5.0 to 2.0.2.
- [Release notes](https://github.com/sasjs/utils/releases)
- [Commits](https://github.com/sasjs/utils/compare/v1.5.0...v2.0.2)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>
2021-01-13 08:03:31 +00:00
Yury Shkoda
1a0d62d8f3 Merge pull request #209 from sasjs/job-status-fix
feat(*): improved session and job logging
2021-01-12 17:53:25 +03:00
Yury Shkoda
8f4d1c7aea chore(*): improved session and job state logging 2021-01-12 17:26:57 +03:00
dependabot-preview[bot]
2a4735c6f2 chore(deps-dev): bump webpack from 4.44.2 to 5.13.0
Bumps [webpack](https://github.com/webpack/webpack) from 4.44.2 to 5.13.0.
- [Release notes](https://github.com/webpack/webpack/releases)
- [Commits](https://github.com/webpack/webpack/compare/v4.44.2...v5.13.0)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>
2021-01-12 08:21:08 +00:00
Yury Shkoda
5a2ee88cbc fix(job-status): print job status only if it changes 2021-01-11 13:52:38 +03:00
Allan Bowe
b23f199334 Merge pull request #203 from sasjs/relative-service-paths
fix(relative-paths): process relative and absolute paths the same way
2021-01-05 21:02:45 +01:00
Krishna Acondy
ed5dabee9f fix(relative-paths): process relative and absolute paths the same way 2021-01-05 19:37:40 +00:00
Allan Bowe
0c88c5a522 Merge pull request #201 from sasjs/services-subfolder
fix(deploy-service-pack): deploy services into 'services' subfolder
2021-01-05 18:23:52 +01:00
Krishna Acondy
640e7015c8 fix(*): deploy services into 'services' subfolder 2021-01-05 17:19:05 +00:00
Mihajlo Medjedovic
a2906abf71 Merge branch 'master' into releaseScript 2020-12-30 13:40:22 +01:00
Yury Shkoda
2fd306f435 Merge pull request #195 from sasjs/v2-bump
test(coverage): enabled gathering coverage
2020-12-30 15:31:01 +03:00
Yury Shkoda
e3f779dbd1 test(coverage): enabled gathering coverage
BREAKING CHANGE: SASjs Adapter 2.0 - Electric Boogaloo
2020-12-30 15:04:59 +03:00
Yury Shkoda
1064f11663 Merge pull request #177 from sasjs/cli-issue-182
feat(context): moved context related logic to ContextManager
2020-12-30 13:24:34 +03:00
Yury Shkoda
46abc54cb0 chore(default-contexts): made default contexts private 2020-12-30 13:13:28 +03:00
Yury Shkoda
2c808a937a docs(*): updated docs 2020-12-30 11:43:10 +03:00
Yury Shkoda
52cf9a420f style(*): fixed styling 2020-12-30 11:42:31 +03:00
Yury Shkoda
2d29be45f5 test(contextManager): added unit tests 2020-12-30 11:38:56 +03:00
Yury Shkoda
a44222c3ba refactor(contextManager): used helper methods 2020-12-30 11:38:10 +03:00
Yury Shkoda
efc82101c1 chore(context-delete): renamed method 2020-12-30 11:36:10 +03:00
Yury Shkoda
09ce2fb6be chore(context-delete): renamed method 2020-12-30 11:35:41 +03:00
Yury Shkoda
a383388e54 feat(context-delete): restricted system compute context deletion 2020-12-29 11:42:14 +03:00
Yury Shkoda
362078b12c docs(context): updated docs 2020-12-29 11:12:33 +03:00
Yury Shkoda
9d0c3410a5 feat(context-edit): restricted editing system compute contexts 2020-12-29 11:11:26 +03:00
Yury Shkoda
dfb9c28f3a feat(createComputeContext): added throw an error if context already exists 2020-12-29 10:00:49 +03:00
Yury Shkoda
8d155283dd fix(context): fixed executeScript method 2020-12-24 13:54:19 +03:00
Yury Shkoda
d991ead86a Merge branch 'master' into cli-issue-182 2020-12-23 15:11:19 +03:00
Yury Shkoda
33a202fa1c Merge pull request #189 from sasjs/job-pid
feat(job-pid): added print PID of the executed job
2020-12-23 12:06:24 +03:00
Yury Shkoda
ff5463a84c chore(example): fixed example 2020-12-23 09:24:15 +03:00
Yury Shkoda
aa7c3ae4a9 docs(pid): updated docs 2020-12-23 09:18:49 +03:00
Yury Shkoda
2e66bfde4b chore(pid): made printing PID optional 2020-12-23 09:17:40 +03:00
Yury Shkoda
16e21adb20 chore: updated docs 2020-12-22 16:58:14 +03:00
Yury Shkoda
01c5682c3d Merge branch 'job-pid' of https://github.com/sasjs/adapter into job-pid 2020-12-22 16:46:48 +03:00
Yury Shkoda
cfc8ff2837 chore: added 'Assign Reviewer' CI step 2020-12-22 16:46:16 +03:00
Yury Shkoda
edf25b471a chore: added 'Assign Reviewer' CI step 2020-12-22 16:41:22 +03:00
Yury Shkoda
bb894e6107 feat(job-pid): added print PID of the executed job 2020-12-22 16:21:24 +03:00
Yury Shkoda
6b3a0cdb13 wip(context): created ContextManager 2020-12-21 14:51:01 +03:00
Yury Shkoda
8c98a26160 chore(SessionManager): removed unnecessary comment 2020-12-11 08:50:44 +03:00
Yury Shkoda
bcd9310f26 feat(context): add public method createLauncherContext 2020-12-09 16:51:07 +03:00
Yury Shkoda
57e9b67207 feat(context): added create launcher context method 2020-12-09 16:41:29 +03:00
Yury Shkoda
7bf53858f0 Merge pull request #176 from sasjs/cli-issue-317
fix(session-status): fixed stop polling session status
2020-12-09 12:56:17 +03:00
Yury Shkoda
02780d0bcd fix(session-status): fixed stop polling session status 2020-12-09 12:45:37 +03:00
Allan Bowe
6356aed06b Merge pull request #173 from sasjs/fix
fix: fetch all items of folder
2020-12-08 00:43:38 +01:00
Saad Jutt
69fd7b2cb5 fix: fetch all items of folder 2020-12-08 04:37:42 +05:00
Allan Bowe
5d1eed1494 Merge pull request #169 from sasjs/execScriptReturn
fix: executeScript return no log
2020-12-04 15:01:47 +01:00
Mihajlo Medjedovic
e2e2824f37 chore: cleanup 2020-12-03 13:05:02 +01:00
Mihajlo Medjedovic
d461135980 chore: job object rename 2020-12-03 12:29:50 +01:00
Mihajlo Medjedovic
65fbae7610 docs: generated 2020-12-03 12:26:23 +01:00
Mihajlo Medjedovic
761428502a fix: added debug override on executeScriptSASViya and added tests for same function 2020-12-03 12:25:42 +01:00
Mihajlo Medjedovic
6eb2ceaf53 test: fixed compute job 2020-12-02 20:48:31 +01:00
Mihajlo Medjedovic
66813b9824 fix: executeScript return no log 2020-12-02 18:18:56 +01:00
Krishna Acondy
140d8e4eac Merge pull request #165 from sasjs/debugIssue
fix: sasjsconfig.debug not passed in executeScriptSASViya function
2020-12-01 11:13:37 +00:00
Mihajlo Medjedovic
0d730e0576 Merge branch 'master' into debugIssue 2020-12-01 12:09:46 +01:00
Yury Shkoda
ca18fcecf0 Merge pull request #167 from sasjs/cli-issue-249
feat(pollJobState): added ability to configure poll options
2020-11-30 12:55:11 +03:00
Yury Shkoda
009069169f chore(pollJobState): updated docs and added note 2020-11-30 12:45:37 +03:00
Yury Shkoda
6d166efd11 feat(pollJobState): made pollOptions optional and updated docs 2020-11-30 12:27:09 +03:00
Yury Shkoda
1b117a67aa feat(pollJobState): added ability to configure poll options 2020-11-30 10:21:49 +03:00
Mihajlo Medjedovic
9037160362 fix: sasjsconfig.debug not passed in executeScriptSASViya function 2020-11-27 15:45:36 +01:00
Yury Shkoda
505d85c256 Merge pull request #163 from sasjs/context-fix
fix(context): fixed result parsing
2020-11-26 13:36:07 +03:00
Yury Shkoda
71a3fe04a0 fix(context): fixed result parsing 2020-11-26 13:27:35 +03:00
Mihajlo Medjedovic
1555afe771 ci: slack webhook secret update 2020-11-26 10:06:47 +01:00
Krishna Acondy
79bb27524c fix(package): include node version of adapter in package 2020-11-26 08:27:55 +00:00
Krishna Acondy
9651b7adb4 Merge pull request #161 from sasjs/fix-build-process
fix(*): export type declarations for node version of adapter
2020-11-25 21:06:20 +00:00
Krishna Acondy
59e5bec731 chore(*): fix PR template 2020-11-25 20:29:43 +00:00
Krishna Acondy
182e66216f fix(*): export type declarations for node version of adapter 2020-11-25 20:23:59 +00:00
Mihajlo Medjedovic
a2832f1e1a ci: slack webhook secret 2020-11-25 17:09:05 +01:00
Mihajlo Medjedovic
56f34508fa ci: after release ci will send slack message 2020-11-25 16:40:04 +01:00
Krishna Acondy
2408fd091e Merge pull request #155 from sasjs/dependabot/npm_and_yarn/semantic-release-17.3.0
chore(deps-dev): bump semantic-release from 17.2.3 to 17.3.0
2020-11-25 11:23:15 +00:00
dependabot-preview[bot]
0e38a24664 chore(deps-dev): bump semantic-release from 17.2.3 to 17.3.0
Bumps [semantic-release](https://github.com/semantic-release/semantic-release) from 17.2.3 to 17.3.0.
- [Release notes](https://github.com/semantic-release/semantic-release/releases)
- [Commits](https://github.com/semantic-release/semantic-release/compare/v17.2.3...v17.3.0)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>
2020-11-25 11:20:35 +00:00
Krishna Acondy
aa643d1782 Merge pull request #159 from sasjs/dependabot/npm_and_yarn/highlight.js-10.4.0
chore(deps): [security] bump highlight.js from 10.1.1 to 10.4.0
2020-11-25 11:18:17 +00:00
dependabot-preview[bot]
cdc91e9cda chore(deps): [security] bump highlight.js from 10.1.1 to 10.4.0
Bumps [highlight.js](https://github.com/highlightjs/highlight.js) from 10.1.1 to 10.4.0. **This update includes a security fix.**
- [Release notes](https://github.com/highlightjs/highlight.js/releases)
- [Changelog](https://github.com/highlightjs/highlight.js/blob/master/CHANGES.md)
- [Commits](https://github.com/highlightjs/highlight.js/compare/10.1.1...10.4.0)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>
2020-11-25 11:16:14 +00:00
Krishna Acondy
3f0590e0fe Merge pull request #158 from sasjs/issue157
Issue157
2020-11-25 11:14:39 +00:00
Mihajlo Medjedovic
5efb294ff2 fix: tests updated 2020-11-25 12:03:07 +01:00
Mihajlo Medjedovic
011e2d83dc fix: computeApi debug override 2020-11-24 15:19:19 +01:00
Mihajlo Medjedovic
e36b511530 test: make error and capture log, fixed 2020-11-24 13:02:17 +01:00
Mihajlo Medjedovic
b6a2a85d1d fix: compute api log not appended to sasjs requests 2020-11-24 11:59:17 +01:00
Krishna Acondy
f1cceeb5e6 Merge pull request #156 from sasjs/fix
fix(job execute): details for failing job
2020-11-24 07:46:32 +00:00
Krishna Acondy
6fee2548fd fix(job-failure): return original job object when a job has failed 2020-11-24 07:44:11 +00:00
Saad Jutt
91005066cf fix(job execute): details for failing job 2020-11-24 04:16:18 +05:00
Krishna Acondy
e1f17ef47d Merge pull request #127 from sasjs/dependabot/npm_and_yarn/terser-webpack-plugin-4.2.3
chore(deps-dev): bump terser-webpack-plugin from 4.2.2 to 4.2.3
2020-11-20 09:07:14 +00:00
dependabot-preview[bot]
8a40071c35 chore(deps-dev): bump terser-webpack-plugin from 4.2.2 to 4.2.3
Bumps [terser-webpack-plugin](https://github.com/webpack-contrib/terser-webpack-plugin) from 4.2.2 to 4.2.3.
- [Release notes](https://github.com/webpack-contrib/terser-webpack-plugin/releases)
- [Changelog](https://github.com/webpack-contrib/terser-webpack-plugin/blob/master/CHANGELOG.md)
- [Commits](https://github.com/webpack-contrib/terser-webpack-plugin/compare/v4.2.2...v4.2.3)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>
2020-11-20 09:01:25 +00:00
Krishna Acondy
430957eb3d Merge pull request #132 from sasjs/dependabot/npm_and_yarn/npm-user-validate-1.0.1
chore(deps): [security] bump npm-user-validate from 1.0.0 to 1.0.1
2020-11-20 08:58:57 +00:00
dependabot-preview[bot]
25874be679 chore(deps): [security] bump npm-user-validate from 1.0.0 to 1.0.1
Bumps [npm-user-validate](https://github.com/npm/npm-user-validate) from 1.0.0 to 1.0.1. **This update includes a security fix.**
- [Release notes](https://github.com/npm/npm-user-validate/releases)
- [Commits](https://github.com/npm/npm-user-validate/compare/v1.0.0...v1.0.1)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>
2020-11-20 08:57:20 +00:00
Krishna Acondy
ed8440434f Merge pull request #135 from sasjs/dependabot/npm_and_yarn/types/jest-26.0.15
chore(deps-dev): bump @types/jest from 26.0.14 to 26.0.15
2020-11-20 08:55:42 +00:00
dependabot-preview[bot]
0f9884c1b6 chore(deps-dev): bump @types/jest from 26.0.14 to 26.0.15
Bumps [@types/jest](https://github.com/DefinitelyTyped/DefinitelyTyped/tree/HEAD/types/jest) from 26.0.14 to 26.0.15.
- [Release notes](https://github.com/DefinitelyTyped/DefinitelyTyped/releases)
- [Commits](https://github.com/DefinitelyTyped/DefinitelyTyped/commits/HEAD/types/jest)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>
2020-11-20 08:46:00 +00:00
Krishna Acondy
d126a05347 Merge pull request #146 from sasjs/dependabot/npm_and_yarn/webpack-cli-4.2.0
chore(deps-dev): bump webpack-cli from 3.3.12 to 4.2.0
2020-11-20 08:43:50 +00:00
dependabot-preview[bot]
3e26bbbbba chore(deps-dev): bump webpack-cli from 3.3.12 to 4.2.0
Bumps [webpack-cli](https://github.com/webpack/webpack-cli) from 3.3.12 to 4.2.0.
- [Release notes](https://github.com/webpack/webpack-cli/releases)
- [Changelog](https://github.com/webpack/webpack-cli/blob/master/CHANGELOG.md)
- [Commits](https://github.com/webpack/webpack-cli/compare/v3.3.12...webpack-cli@4.2.0)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>
2020-11-20 08:34:49 +00:00
Krishna Acondy
982cc8f7a0 Merge pull request #149 from sasjs/dependabot/npm_and_yarn/ts-loader-8.0.11
chore(deps-dev): bump ts-loader from 8.0.4 to 8.0.11
2020-11-20 08:32:39 +00:00
dependabot-preview[bot]
d1770698e0 chore(deps-dev): bump ts-loader from 8.0.4 to 8.0.11
Bumps [ts-loader](https://github.com/TypeStrong/ts-loader) from 8.0.4 to 8.0.11.
- [Release notes](https://github.com/TypeStrong/ts-loader/releases)
- [Changelog](https://github.com/TypeStrong/ts-loader/blob/master/CHANGELOG.md)
- [Commits](https://github.com/TypeStrong/ts-loader/compare/8.0.4...v8.0.11)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>
2020-11-20 08:29:41 +00:00
Krishna Acondy
b78e8617c4 Merge pull request #151 from sasjs/dependabot/npm_and_yarn/semantic-release-17.2.3
[security] chore(deps-dev): bump semantic-release from 17.1.2 to 17.2.3
2020-11-20 08:27:32 +00:00
dependabot-preview[bot]
3ce9ca0986 chore(deps-dev): bump semantic-release from 17.1.2 to 17.2.3
Bumps [semantic-release](https://github.com/semantic-release/semantic-release) from 17.1.2 to 17.2.3.
- [Release notes](https://github.com/semantic-release/semantic-release/releases)
- [Commits](https://github.com/semantic-release/semantic-release/compare/v17.1.2...v17.2.3)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>
2020-11-20 08:19:07 +00:00
Yury Shkoda
04d17c3680 Merge pull request #153 from sasjs/context-issue
fix(context): fixed log parsing
2020-11-19 16:53:48 +03:00
Yury Shkoda
d26e15f91c Merge branch 'master' into context-issue 2020-11-19 16:43:30 +03:00
Yury Shkoda
83c46091b3 fix(context): fixed log parsing 2020-11-19 16:39:47 +03:00
Krishna Acondy
d640d7c040 Merge pull request #152 from sasjs/issue117
fix: viya login issue
2020-11-18 17:16:26 +00:00
Mihajlo Medjedovic
c934eb2b08 test: added test for multiple login attempts 2020-11-18 14:13:13 +01:00
Mihajlo Medjedovic
24dd5e32ad style: lint 2020-11-18 13:10:29 +01:00
Mihajlo Medjedovic
a23103b2c3 fix: viya login issue 2020-11-18 13:09:49 +01:00
Yury Shkoda
35aa4235e4 Merge pull request #148 from sasjs/issue113
feat: service not found error handling
2020-11-16 09:54:03 +03:00
Mihajlo Medjedovic
e9be1cf99a fix: service not found error handling 2020-11-12 16:03:32 +01:00
Mihajlo Medjedovic
c7b0821081 style: lint 2020-11-09 18:24:10 +01:00
Mihajlo Medjedovic
4a4618dd32 feat: service not found error handling for SAS9 2020-11-09 18:19:39 +01:00
Krishna Acondy
d223e83c60 Merge pull request #142 from sasjs/issue138
fix(file-uploader): handle errors during file upload
2020-11-02 14:54:58 +00:00
Krishna Acondy
d1f1a20126 chore(file-uploader): move uploader to describe scope 2020-11-02 09:29:33 +00:00
Krishna Acondy
4b89e3762f chore(file-uploader): remove duplication 2020-11-02 08:54:26 +00:00
Krishna Acondy
bc110288de chore(file-uploader): improve mocking of fetch, add tests for all error scenarios 2020-11-02 08:51:27 +00:00
Krishna Acondy
e94e16b52c chore(*): fix linting errors 2020-11-02 07:55:48 +00:00
Krishna Acondy
76aacee016 Merge branch 'master' into issue138 2020-11-02 07:42:39 +00:00
Mihajlo Medjedovic
1a3bd5d1f5 chore: lint 2020-10-30 16:13:03 +01:00
Mihajlo Medjedovic
3f6e89d716 fix: file uploader error handling and tests 2020-10-30 16:11:50 +01:00
Yury Shkoda
361ec84638 Merge pull request #141 from sasjs/fetch-log-feat
chore(log): made 'fetchLogFileContent' method public
2020-10-30 11:28:07 +03:00
Yury Shkoda
35cc1e4f62 chore(fetchLogFileContent): made accessToken optional 2020-10-30 11:26:43 +03:00
Yury Shkoda
64a976e888 doc: updated docs 2020-10-30 10:36:53 +03:00
Yury Shkoda
7e2cb8491f feat(log): made 'fetchLogFileContent' method public 2020-10-30 10:36:04 +03:00
Krishna Acondy
2cdab7522d Merge pull request #139 from sasjs/location-issue
fix(location): added handle cases when 'location' is not defined
2020-10-29 08:07:11 +00:00
Yury Shkoda
a07eabc408 fix(location): added handle cases when 'location' is not defined 2020-10-29 10:07:30 +03:00
Mihajlo Medjedovic
7279c23fe2 fix: FIleUploader added catch 2020-10-27 14:50:05 +01:00
Mihajlo Medjedovic
80707d77d9 gitfe Merge branches 'errorResponse' and 'master' of github.com:sasjs/adapter 2020-10-27 14:40:41 +01:00
Yury Shkoda
d5920c5885 Merge pull request #134 from sasjs/executeComputeJob
fix(executeComputeJob): added fix for cases when code was not provided
2020-10-21 11:55:43 +03:00
Yury Shkoda
6a3a6b4485 fix(executeComputeJob): added fix for cases when code was not provided 2020-10-21 11:45:21 +03:00
Krishna Acondy
2b1df0c61a Merge pull request #123 from sasjs/sasjs-job
feat(start-compute-job): Add API that returns immediately after job is started
2020-10-16 11:27:02 +01:00
Krishna Acondy
216725f306 chore(doc): update documentation 2020-10-16 11:04:03 +01:00
Krishna Acondy
3183f89a62 chore(*): fix lint warning 2020-10-16 10:58:04 +01:00
Krishna Acondy
f5cc16c3bd chore(create-job): add tests 2020-10-16 10:56:10 +01:00
Krishna Acondy
e78dc76e56 fix(config): set debug to false by default
feat(create-job): add the ability to wait for result
2020-10-16 10:55:56 +01:00
Krishna Acondy
bfdb5ef0a6 chore(*): regenerate documentation 2020-10-16 09:13:48 +01:00
Krishna Acondy
35353d3fce Merge branch 'master' into sasjs-job 2020-10-15 09:11:50 +01:00
Yury Shkoda
7a02c8ad34 Merge pull request #131 from sasjs/issue-124
fix(session): add internal SAS error handler
2020-10-14 14:03:58 +03:00
Yury Shkoda
331d9b0010 fix(session): add internal SAS error handler 2020-10-14 12:53:59 +03:00
Yury Shkoda
ef5686cce7 Merge branch 'master' into sasjs-job 2020-10-12 09:21:00 +03:00
Yury Shkoda
fa87111f4a Merge pull request #126 from sasjs/issue-124
fix(context): fixed 'getExecutableContexts' method
2020-10-07 17:53:31 +03:00
Yury Shkoda
94967b0f6c fix(context): fixed 'getExecutableContexts' method 2020-10-07 17:25:47 +03:00
Mihajlo Medjedovic
3f796b300d fix: ErrorResponse body changed to error 2020-10-07 11:15:00 +02:00
Krishna Acondy
a07c16fb52 chore(start-compute-job): add test 2020-10-06 09:21:58 +01:00
Krishna Acondy
fd6905ea9f feat(start-compute-job): add API that starts a compute job and immediately returns the session 2020-10-06 09:21:15 +01:00
Krishna Acondy
08f58b5f4f fix(debug): only set session manager debug if it is defined 2020-10-06 08:17:02 +01:00
Krishna Acondy
bd8012fe3e fix(*): revert to older version of isomorphic-fetch 2020-10-03 18:19:06 +01:00
Krishna Acondy
fa531b34fd Merge pull request #120 from sasjs/session-manager-debug
fix(debug): propagate debug value from SASjs config
2020-10-03 17:41:35 +01:00
Krishna Acondy
354443c98b fix(debug): propagate debug value from SASjs config 2020-10-03 16:53:00 +01:00
Krishna Acondy
ee30ab195f Merge pull request #115 from sasjs/issue-114
chore(error-message): updated error message for forbidden request
2020-10-01 09:10:35 +01:00
Yury Shkoda
02c1712d22 chore(error-message): updated error message for forbidden request 2020-10-01 09:49:24 +03:00
Krishna Acondy
37def7a956 Merge pull request #111 from sasjs/dependabot/npm_and_yarn/isomorphic-fetch-3.0.0
chore(deps): bump isomorphic-fetch from 2.2.1 to 3.0.0
2020-09-29 20:03:06 +01:00
Krishna Acondy
653e3d05e0 Merge branch 'master' into dependabot/npm_and_yarn/isomorphic-fetch-3.0.0 2020-09-29 19:55:08 +01:00
dependabot-preview[bot]
e2ea3f4ddc chore(deps): bump isomorphic-fetch from 2.2.1 to 3.0.0
Bumps [isomorphic-fetch](https://github.com/matthew-andrews/isomorphic-fetch) from 2.2.1 to 3.0.0.
- [Release notes](https://github.com/matthew-andrews/isomorphic-fetch/releases)
- [Commits](https://github.com/matthew-andrews/isomorphic-fetch/compare/v2.2.1...v3.0.0)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>
2020-09-25 23:51:17 +00:00
128 changed files with 48658 additions and 20422 deletions

2
.env.example Normal file
View File

@@ -0,0 +1,2 @@
SERVER_URL=https://server.com
DEFAULT_COMPUTE_CONTEXT=SAS Job Execution compute context

9
.github/reviewer-lottery.yml vendored Normal file
View File

@@ -0,0 +1,9 @@
groups:
- name: SASjs Devs # name of the group
reviewers: 1 # how many reviewers do you want to assign?
usernames: # github usernames of the reviewers
- krishna-acondy
- YuryShkoda
- saadjutt01
- medjedovicm
- allanbowe

13
.github/workflows/assign-reviewer.yml vendored Normal file
View File

@@ -0,0 +1,13 @@
name: 'Assign Reviewer'
on:
pull_request:
types: [opened]
jobs:
test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- uses: uesteibar/reviewer-lottery@v1
with:
repo-token: ${{ secrets.GH_TOKEN }}

View File

@@ -25,3 +25,5 @@ jobs:
env:
GITHUB_TOKEN: ${{ secrets.GH_TOKEN }}
NPM_TOKEN: ${{ secrets.NPM_TOKEN }}
- name: Send Slack message
run: curl -X POST --data-urlencode "payload={\"channel\":\"#sasjs\", \"username\":\"GitHub CI\", \"text\":\"New version of @sasjs/adapter has been released! \n Please deploy and run `dctests` with new adapter to make sure everything is still in place.\", \"icon_emoji\":\":rocket:\"}" ${{ secrets.SLACK_WEBHOOK }}

4
.gitignore vendored
View File

@@ -1,2 +1,6 @@
node_modules
build
.env
/coverage

View File

@@ -14,4 +14,5 @@ What code changes have been made to achieve the intent.
- [ ] Code is formatted correctly (`npm run lint:fix`).
- [ ] All unit tests are passing (`npm test`).
- [ ] All `sasjs-cli` unit tests are passing (`npm test`).
- [ ] All `sasjs-tests` are passing (instructions available [here](https://github.com/sasjs/adapter/blob/master/sasjs-tests/README.md)).

View File

@@ -1,13 +0,0 @@
{
"defaultCommandTimeout": 10000,
"chromeWebSecurity": false,
"screenshotOnRunFailure": false,
"env": {
"serverUrl": "",
"appLoc": "/Public/app",
"serverType": "SAS9",
"debug": false,
"username": "",
"password": ""
}
}

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

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

1838
docs/classes/root.sasjs.html Normal file

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

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

129
docs/modules/root.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

View File

@@ -1,10 +1,184 @@
// For a detailed explanation regarding each configuration property, visit:
// https://jestjs.io/docs/en/configuration.html
module.exports = {
roots: ["<rootDir>/src"],
testMatch: [
"**/__tests__/**/*.+(ts|tsx|js)",
"**/?(*.)+(spec|test).+(ts|tsx|js)"
],
testTimeout: 90000,
// All imported modules in your tests should be mocked automatically
// automock: false,
// Stop running tests after `n` failures
// bail: 1,
// Respect "browser" field in package.json when resolving modules
// browser: false,
// The directory where Jest should store its cached dependency information
// cacheDirectory: "/private/var/folders/7y/nmqg1srj29q6210rs9dfsdzc0000gn/T/jest_dx",
// Automatically clear mock calls and instances between every test
clearMocks: true,
// Indicates whether the coverage information should be collected while executing the test
// collectCoverage: false,
// An array of glob patterns indicating a set of files for which coverage information should be collected
// collectCoverageFrom: undefined,
// The directory where Jest should output its coverage files
coverageDirectory: 'coverage',
// An array of regexp pattern strings used to skip coverage collection
// coveragePathIgnorePatterns: [
// "/node_modules/"
// ],
// A list of reporter names that Jest uses when writing coverage reports
// coverageReporters: [
// "json",
// "text",
// "lcov",
// "clover"
// ],
// An object that configures minimum threshold enforcement for coverage results
// coverageThreshold: undefined,
// A path to a custom dependency extractor
// dependencyExtractor: undefined,
// Make calling deprecated APIs throw helpful error messages
// errorOnDeprecated: false,
// Force coverage collection from ignored files using an array of glob patterns
// forceCoverageMatch: [],
// A path to a module which exports an async function that is triggered once before all test suites
// globalSetup: undefined,
// A path to a module which exports an async function that is triggered once after all test suites
// globalTeardown: undefined,
// A set of global variables that need to be available in all test environments
// globals: {},
// The maximum amount of workers used to run your tests. Can be specified as % or a number. E.g. maxWorkers: 10% will use 10% of your CPU amount + 1 as the maximum worker number. maxWorkers: 2 will use a maximum of 2 workers.
// maxWorkers: "50%",
// An array of directory names to be searched recursively up from the requiring module's location
// moduleDirectories: [
// "node_modules"
// ],
// An array of file extensions your modules use
// moduleFileExtensions: [
// "js",
// "json",
// "jsx",
// "ts",
// "tsx",
// "node"
// ],
// A map from regular expressions to module names that allow to stub out resources with a single module
moduleNameMapper: {},
// An array of regexp pattern strings, matched against all module paths before considered 'visible' to the module loader
// modulePathIgnorePatterns: [],
// Activates notifications for test results
// notify: false,
// An enum that specifies notification mode. Requires { notify: true }
// notifyMode: "failure-change",
// A preset that is used as a base for Jest's configuration
preset: 'ts-jest/presets/js-with-ts',
// Run tests from one or more projects
// projects: undefined,
// Use this configuration option to add custom reporters to Jest
// reporters: undefined,
// Automatically reset mock state between every test
// resetMocks: false,
// Reset the module registry before running each individual test
// resetModules: false,
// A path to a custom resolver
// resolver: undefined,
// Automatically restore mock state between every test
// restoreMocks: false,
// The root directory that Jest should scan for tests and modules within
// rootDir: undefined,
// A list of paths to directories that Jest should use to search for files in
// roots: [
// "<rootDir>"
// ],
// Allows you to use a custom runner instead of Jest's default test runner
// runner: "jest-runner",
// The paths to modules that run some code to configure or set up the testing environment before each test
setupFiles: [],
// A list of paths to modules that run some code to configure or set up the testing framework before each test
setupFilesAfterEnv: ['jest-extended'],
// A list of paths to snapshot serializer modules Jest should use for snapshot testing
// snapshotSerializers: [],
// Options that will be passed to the testEnvironment
// testEnvironmentOptions: {},
// Adds a location field to test results
// testLocationInResults: false,
// The glob patterns Jest uses to detect test files
testMatch: ['**/*spec.[j|t]s?(x)'],
// An array of regexp pattern strings that are matched against all test paths, matched tests are skipped
testPathIgnorePatterns: ['/node_modules/', '/build'],
// The regexp pattern or array of patterns that Jest uses to detect test files
// testRegex: [],
// This option allows the use of a custom results processor
// testResultsProcessor: undefined,
// This option allows use of a custom test runner
// testRunner: "jasmine2",
// This option sets the URL for the jsdom environment. It is reflected in properties such as location.href
// testURL: "http://localhost",
// Setting this value to "fake" allows the use of fake timers for functions such as "setTimeout"
// timers: "real",
// A map from regular expressions to paths to transformers
transform: {
"^.+\\.(ts|tsx)$": "ts-jest"
'^.+\\.ts?$': 'ts-jest'
}
};
// An array of regexp pattern strings that are matched against all source file paths, matched files will skip transformation
// transformIgnorePatterns: [
// '**/test/**/*.ts?(x)',
// '**/?(*.)+(spec|test).ts?(x)'
// ]
// An array of regexp pattern strings that are matched against all modules before the module loader will automatically return a mock for them
// unmockedModulePathPatterns: undefined,
// Indicates whether each individual test should be reported during the run
// verbose: undefined,
// An array of regexp patterns that are matched against all source file paths before re-running tests in watch mode
// watchPathIgnorePatterns: [],
// Whether to use watchman for file crawling
// watchman: true,
}

23808
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@@ -2,12 +2,12 @@
"name": "@sasjs/adapter",
"description": "JavaScript adapter for SAS",
"scripts": {
"build": "rimraf build && webpack",
"build": "rimraf build && rimraf node && mkdir node && cp -r src/* node && webpack && rimraf build/src && rimraf node",
"package:lib": "npm run build && cp ./package.json build && cd build && npm version \"5.0.0\" && npm pack",
"publish:lib": "npm run build && cd build && npm publish",
"lint:fix": "npx prettier --write 'src/**/*.{ts,tsx,js,jsx,html,css,sass,less,json,yml,md,graphql}'",
"lint": "npx prettier --check 'src/**/*.{ts,tsx,js,jsx,html,css,sass,less,json,yml,md,graphql}'",
"test": "jest",
"test": "jest --silent --coverage",
"prepublishOnly": "cp -r ./build/* . && rm -rf ./build",
"postpublish": "git clean -fd",
"semantic-release": "semantic-release",
@@ -36,29 +36,31 @@
},
"license": "ISC",
"devDependencies": {
"@types/isomorphic-fetch": "0.0.35",
"@types/jest": "^26.0.14",
"@types/jest": "^26.0.20",
"cp": "^0.2.0",
"jest": "^25.5.4",
"dotenv": "^8.2.0",
"jest": "^26.6.3",
"jest-extended": "^0.11.5",
"path": "^0.12.7",
"rimraf": "^3.0.2",
"semantic-release": "^17.1.2",
"terser-webpack-plugin": "^4.2.2",
"semantic-release": "^17.3.9",
"terser-webpack-plugin": "^4.2.3",
"ts-jest": "^25.5.1",
"ts-loader": "^8.0.4",
"ts-loader": "^8.0.17",
"tslint": "^6.1.3",
"tslint-config-prettier": "^1.18.0",
"typedoc": "^0.17.8",
"typedoc-neo-theme": "^1.0.10",
"typedoc-plugin-external-module-name": "^4.0.3",
"typescript": "^3.9.7",
"webpack": "^4.44.2",
"webpack-cli": "^3.3.12"
"typedoc": "^0.19.2",
"typedoc-neo-theme": "^1.1.0",
"typedoc-plugin-external-module-name": "^4.0.6",
"typescript": "^3.9.9",
"webpack": "^5.21.2",
"webpack-cli": "^4.5.0"
},
"main": "index.js",
"dependencies": {
"es6-promise": "^4.2.8",
"axios": "^0.21.1",
"@sasjs/utils": "^2.5.0",
"form-data": "^3.0.0",
"isomorphic-fetch": "^2.2.1"
"https": "^1.0.0"
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -4,21 +4,18 @@
"homepage": ".",
"private": true,
"dependencies": {
"@sasjs/adapter": "^1.12.0",
"@sasjs/adapter": "^2.1.0",
"@sasjs/test-framework": "^1.4.0",
"@testing-library/jest-dom": "^4.2.4",
"@testing-library/react": "^9.5.0",
"@testing-library/user-event": "^7.2.1",
"@types/jest": "^26.0.3",
"@types/node": "^14.0.14",
"@types/react": "^16.9.41",
"@types/react-dom": "^16.9.8",
"@types/react-router-dom": "^5.1.5",
"react": "^16.13.1",
"react-dom": "^16.13.1",
"@types/jest": "^26.0.20",
"@types/node": "^14.14.25",
"@types/react": "^17.0.1",
"@types/react-dom": "^17.0.0",
"@types/react-router-dom": "^5.1.7",
"react": "^17.0.1",
"react-dom": "^17.0.1",
"react-router-dom": "^5.2.0",
"react-scripts": "3.4.1",
"typescript": "^3.9.6"
"react-scripts": "^4.0.2",
"typescript": "^4.1.3"
},
"scripts": {
"start": "react-scripts start",
@@ -45,6 +42,6 @@
]
},
"devDependencies": {
"node-sass": "^4.14.1"
"node-sass": "^5.0.0"
}
}

View File

@@ -1,9 +0,0 @@
import React from "react";
import { render } from "@testing-library/react";
import App from "./App";
test("renders learn react link", () => {
const { getByText } = render(<App />);
const linkElement = getByText(/learn react/i);
expect(linkElement).toBeInTheDocument();
});

View File

@@ -5,6 +5,7 @@ import { sendArrTests, sendObjTests } from "./testSuites/RequestData";
import { specialCaseTests } from "./testSuites/SpecialCases";
import { sasjsRequestTests } from "./testSuites/SasjsRequests";
import "@sasjs/test-framework/dist/index.css";
import { computeTests } from "./testSuites/Compute";
const App = (): ReactElement<{}> => {
const { adapter, config } = useContext(AppContext);
@@ -17,7 +18,8 @@ const App = (): ReactElement<{}> => {
sendArrTests(adapter),
sendObjTests(adapter),
specialCaseTests(adapter),
sasjsRequestTests(adapter)
sasjsRequestTests(adapter),
computeTests(adapter)
]);
}
}, [adapter, config]);

View File

@@ -1,15 +1,17 @@
import SASjs, { ServerType, SASjsConfig } from "@sasjs/adapter";
import SASjs, { SASjsConfig } from "@sasjs/adapter";
import { TestSuite } from "@sasjs/test-framework";
import { ServerType } from "@sasjs/utils/types";
const defaultConfig: SASjsConfig = {
serverUrl: window.location.origin,
pathSAS9: "/SASStoredProcess/do",
pathSASViya: "/SASJobExecution",
appLoc: "/Public/seedapp",
serverType: ServerType.SASViya,
debug: true,
serverType: ServerType.SasViya,
debug: false,
contextName: "SAS Job Execution compute context",
useComputeApi: false
useComputeApi: false,
allowInsecureRequests: false
};
const customConfig = {
@@ -17,7 +19,7 @@ const customConfig = {
pathSAS9: "sas9",
pathSASViya: "viya",
appLoc: "/Public/seedapp",
serverType: ServerType.SAS9,
serverType: ServerType.Sas9,
debug: false
};
@@ -37,6 +39,18 @@ export const basicTests = (
assertion: (response: any) =>
response && response.isLoggedIn && response.userName === userName
},
{
title: "Multiple Log in attempts",
description:
"Should fail on first attempt and should log the user in on second attempt",
test: async () => {
await adapter.logOut();
await adapter.logIn("invalid", "invalid");
return adapter.logIn(userName, password);
},
assertion: (response: any) =>
response && response.isLoggedIn && response.userName === userName
},
{
title: "Default config",
description:
@@ -46,6 +60,7 @@ export const basicTests = (
},
assertion: (sasjsInstance: SASjs) => {
const sasjsConfig = sasjsInstance.getSasjsConfig();
return (
sasjsConfig.serverUrl === defaultConfig.serverUrl &&
sasjsConfig.pathSAS9 === defaultConfig.pathSAS9 &&

View File

@@ -0,0 +1,106 @@
import SASjs from "@sasjs/adapter";
import { TestSuite } from "@sasjs/test-framework";
export const computeTests = (adapter: SASjs): TestSuite => ({
name: "Compute",
tests: [
{
title: "Start Compute Job - not waiting for result",
description: "Should start a compute job and return the session",
test: () => {
const data: any = { table1: [{ col1: "first col value" }] };
return adapter.startComputeJob("/Public/app/common/sendArr", data);
},
assertion: (res: any) => {
const expectedProperties = ["id", "applicationName", "attributes"];
return validate(expectedProperties, res);
}
},
{
title: "Start Compute Job - waiting for result",
description: "Should start a compute job and return the job",
test: () => {
const data: any = { table1: [{ col1: "first col value" }] };
return adapter.startComputeJob(
"/Public/app/common/sendArr",
data,
{},
"",
true
);
},
assertion: (res: any) => {
const expectedProperties = [
"id",
"state",
"creationTimeStamp",
"jobConditionCode"
];
return validate(expectedProperties, res.job);
}
},
{
title: "Execute Script Viya - complete job",
description: "Should execute sas file and return log",
test: () => {
const fileLines = [
`data;`,
`do x=1 to 100;`,
`output;`,
`end;`,
`run;`
];
return adapter.executeScriptSASViya(
"sasCode.sas",
fileLines,
"SAS Studio compute context",
undefined,
true
);
},
assertion: (res: any) => {
const expectedLogContent = `1 data;\\n2 do x=1 to 100;\\n3 output;\\n4 end;\\n5 run;\\n\\n`;
return validateLog(expectedLogContent, res.log);
}
},
{
title: "Execute Script Viya - failed job",
description: "Should execute sas file and return log",
test: () => {
const fileLines = [`%abort;`];
return adapter
.executeScriptSASViya(
"sasCode.sas",
fileLines,
"SAS Studio compute context",
undefined,
true
)
.catch((err: any) => err);
},
assertion: (res: any) => {
const expectedLogContent = `1 %abort;\\nERROR: The %ABORT statement is not valid in open code.\\n`;
return validateLog(expectedLogContent, res.log);
}
}
]
});
const validateLog = (text: string, log: string): boolean => {
const isValid = JSON.stringify(log).includes(text);
return isValid;
};
const validate = (expectedProperties: string[], data: any): boolean => {
const actualProperties = Object.keys(data);
const isValid = expectedProperties.every((property) =>
actualProperties.includes(property)
);
return isValid;
};

View File

@@ -88,7 +88,7 @@ export const sendArrTests = (adapter: SASjs): TestSuite => ({
return adapter.request("common/sendArr", data).catch((e) => e);
},
assertion: (error: any) => {
return !!error && !!error.body && !!error.body.message;
return !!error && !!error.error && !!error.error.message;
}
},
{
@@ -185,7 +185,8 @@ export const sendObjTests = (adapter: SASjs): TestSuite => ({
};
return adapter.request("common/sendObj", invalidData).catch((e) => e);
},
assertion: (error: any) => !!error && !!error.body && !!error.body.message
assertion: (error: any) =>
!!error && !!error.error && !!error.error.message
},
{
title: "Single string value",
@@ -219,7 +220,7 @@ export const sendObjTests = (adapter: SASjs): TestSuite => ({
.catch((e) => e);
},
assertion: (error: any) => {
return !!error && !!error.body && !!error.body.message;
return !!error && !!error.error && !!error.error.message;
}
},
{

View File

@@ -23,24 +23,23 @@ export const sasjsRequestTests = (adapter: SASjs): TestSuite => ({
},
{
title: "Make error and capture log",
description: "Should make an error and capture log",
description:
"Should make an error and capture log, in the same time it is testing if debug override is working",
test: async () => {
return new Promise(async (resolve, reject) => {
adapter
.request("common/makeErr", data)
.then((res) => {
//no action here, this request must throw error
})
.catch((err) => {
let sasRequests = adapter.getSasRequests();
let makeErrRequest =
sasRequests.find((req) =>
req.serviceLink.includes("makeErr")
) || null;
return adapter
.request("common/makeErr", data, { debug: true })
.catch(() => {
const sasRequests = adapter.getSasRequests();
const makeErrRequest: any =
sasRequests.find((req) => req.serviceLink.includes("makeErr")) ||
null;
resolve(!!makeErrRequest);
});
});
if (!makeErrRequest) return false;
return !!(
makeErrRequest.logFile && makeErrRequest.logFile.length > 0
);
});
},
assertion: (response) => {
return response;

View File

@@ -17,7 +17,8 @@
"resolveJsonModule": true,
"isolatedModules": true,
"noEmit": true,
"jsx": "react"
"jsx": "react-jsx",
"noFallthroughCasesInSwitch": true
},
"include": [
"src"

450
src/ContextManager.ts Normal file
View File

@@ -0,0 +1,450 @@
import { Context, EditContextInput, ContextAllAttributes } from './types'
import { isUrl } from './utils'
import { prefixMessage } from '@sasjs/utils/error'
import { RequestClient } from './request/RequestClient'
export class ContextManager {
private defaultComputeContexts = [
'CAS Formats service compute context',
'Data Mining compute context',
'Import 9 service compute context',
'SAS Job Execution compute context',
'SAS Model Manager compute context',
'SAS Studio compute context',
'SAS Visual Forecasting compute context'
]
private defaultLauncherContexts = [
'CAS Formats service launcher context',
'Data Mining launcher context',
'Import 9 service launcher context',
'Job Flow Execution launcher context',
'SAS Job Execution launcher context',
'SAS Model Manager launcher context',
'SAS Studio launcher context',
'SAS Visual Forecasting launcher context'
]
get getDefaultComputeContexts() {
return this.defaultComputeContexts
}
get getDefaultLauncherContexts() {
return this.defaultLauncherContexts
}
constructor(private serverUrl: string, private requestClient: RequestClient) {
if (serverUrl) isUrl(serverUrl)
}
public async getComputeContexts(accessToken?: string) {
const { result: contexts } = await this.requestClient
.get<{ items: Context[] }>(
`${this.serverUrl}/compute/contexts?limit=10000`,
accessToken
)
.catch((err) => {
throw prefixMessage(err, 'Error while getting compute contexts. ')
})
const contextsList = contexts && contexts.items ? contexts.items : []
return contextsList.map((context: any) => ({
createdBy: context.createdBy,
id: context.id,
name: context.name,
version: context.version,
attributes: {}
}))
}
public async getLauncherContexts(accessToken?: string) {
const { result: contexts } = await this.requestClient
.get<{ items: Context[] }>(
`${this.serverUrl}/launcher/contexts?limit=10000`,
accessToken
)
.catch((err) => {
throw prefixMessage(err, 'Error while getting launcher contexts. ')
})
const contextsList = contexts && contexts.items ? contexts.items : []
return contextsList.map((context: any) => ({
createdBy: context.createdBy,
id: context.id,
name: context.name,
version: context.version,
attributes: {}
}))
}
public async createComputeContext(
contextName: string,
launchContextName: string,
sharedAccountId: string,
autoExecLines: string[],
accessToken?: string,
authorizedUsers?: string[]
) {
this.validateContextName(contextName)
this.isDefaultContext(
contextName,
this.defaultComputeContexts,
`Compute context '${contextName}' already exists.`
)
const existingComputeContexts = await this.getComputeContexts(accessToken)
if (
existingComputeContexts.find((context) => context.name === contextName)
) {
throw new Error(`Compute context '${contextName}' already exists.`)
}
if (launchContextName) {
if (!this.defaultLauncherContexts.includes(launchContextName)) {
const launcherContexts = await this.getLauncherContexts(accessToken)
if (
!launcherContexts.find(
(context) => context.name === launchContextName
)
) {
const description = `The launcher context for ${launchContextName}`
const launchType = 'direct'
const newLauncherContext = await this.createLauncherContext(
launchContextName,
description,
launchType,
accessToken
).catch((err) => {
throw new Error(`Error while creating launcher context. ${err}`)
})
if (newLauncherContext && newLauncherContext.name) {
launchContextName = newLauncherContext.name
} else {
throw new Error('Error while creating launcher context.')
}
}
}
}
const headers: any = {
'Content-Type': 'application/json'
}
if (accessToken) {
headers.Authorization = `Bearer ${accessToken}`
}
let attributes = { reuseServerProcesses: true } as object
if (sharedAccountId)
attributes = { ...attributes, runServerAs: sharedAccountId }
const requestBody: any = {
name: contextName,
launchContext: {
contextName: launchContextName || ''
},
attributes
}
if (authorizedUsers && authorizedUsers.length) {
requestBody['authorizedUsers'] = authorizedUsers
} else {
requestBody['authorizeAllAuthenticatedUsers'] = true
}
if (autoExecLines) {
requestBody.environment = { autoExecLines }
}
const { result: context } = await this.requestClient
.post<Context>(
`${this.serverUrl}/compute/contexts`,
requestBody,
accessToken
)
.catch((err) => {
throw prefixMessage(err, 'Error while creating compute context. ')
})
return context
}
public async createLauncherContext(
contextName: string,
description: string,
launchType = 'direct',
accessToken?: string
) {
if (!contextName) {
throw new Error('Context name is required.')
}
this.isDefaultContext(
contextName,
this.defaultLauncherContexts,
`Launcher context '${contextName}' already exists.`
)
const existingLauncherContexts = await this.getLauncherContexts(accessToken)
if (
existingLauncherContexts.find((context) => context.name === contextName)
) {
throw new Error(`Launcher context '${contextName}' already exists.`)
}
const headers: any = {
'Content-Type': 'application/json'
}
if (accessToken) {
headers.Authorization = `Bearer ${accessToken}`
}
const requestBody: any = {
name: contextName,
description: description,
launchType
}
const { result: context } = await this.requestClient
.post<Context>(
`${this.serverUrl}/launcher/contexts`,
requestBody,
accessToken
)
.catch((err) => {
throw prefixMessage(err, 'Error while creating launcher context. ')
})
return context
}
public async editComputeContext(
contextName: string,
editedContext: EditContextInput,
accessToken?: string
) {
this.validateContextName(contextName)
this.isDefaultContext(
contextName,
this.defaultComputeContexts,
'Editing default SAS compute contexts is not allowed.',
true
)
let originalContext
originalContext = await this.getComputeContextByName(
contextName,
accessToken
)
// Try to find context by id, when context name has been changed.
if (!originalContext) {
originalContext = await this.getComputeContextById(
editedContext.id!,
accessToken
)
}
const { result: context, etag } = await this.requestClient
.get<Context>(
`${this.serverUrl}/compute/contexts/${originalContext.id}`,
accessToken
)
.catch((err) => {
if (err && err.status === 404) {
throw new Error(
`The context '${contextName}' was not found on this server.`
)
}
throw err
})
// An If-Match header with the value of the last ETag for the context
// is required to be able to update it
// https://developer.sas.com/apis/rest/Compute/#update-a-context-definition
return await this.requestClient.put<Context>(
`/compute/contexts/${context.id}`,
{
...context,
...editedContext,
attributes: { ...context.attributes, ...editedContext.attributes }
},
accessToken,
{ 'If-Match': etag }
)
}
public async getComputeContextByName(
contextName: string,
accessToken?: string
): Promise<Context> {
const { result: contexts } = await this.requestClient
.get<{ items: Context[] }>(
`${this.serverUrl}/compute/contexts?filter=eq(name, "${contextName}")`,
accessToken
)
.catch((err) => {
throw prefixMessage(
err,
'Error while getting compute context by name. '
)
})
if (!contexts || !(contexts.items && contexts.items.length)) {
throw new Error(
`The context '${contextName}' was not found at '${this.serverUrl}'.`
)
}
return contexts.items[0]
}
public async getComputeContextById(
contextId: string,
accessToken?: string
): Promise<ContextAllAttributes> {
const {
result: context
} = await this.requestClient
.get<ContextAllAttributes>(
`${this.serverUrl}/compute/contexts/${contextId}`,
accessToken
)
.catch((err) => {
throw prefixMessage(err, 'Error while getting compute context by id. ')
})
return context
}
public async getExecutableContexts(
executeScript: Function,
accessToken?: string
) {
const { result: contexts } = await this.requestClient
.get<{ items: Context[] }>(
`${this.serverUrl}/compute/contexts?limit=10000`,
accessToken
)
.catch((err) => {
throw prefixMessage(err, 'Error while fetching compute contexts.')
})
const contextsList = contexts.items || []
const executableContexts: any[] = []
const promises = contextsList.map((context: any) => {
const linesOfCode = ['%put &=sysuserid;']
return () =>
executeScript(
`test-${context.name}`,
linesOfCode,
context.name,
accessToken,
null,
false,
true,
true
).catch((err: any) => err)
})
let results: any[] = []
for (const promise of promises) results.push(await promise())
results.forEach((result: any, index: number) => {
if (result && result.log) {
try {
const resultParsed = result.log
let sysUserId = ''
const sysUserIdLog = resultParsed
.split('\n')
.find((line: string) => line.startsWith('SYSUSERID='))
if (sysUserIdLog) {
sysUserId = sysUserIdLog.replace('SYSUSERID=', '')
executableContexts.push({
createdBy: contextsList[index].createdBy,
id: contextsList[index].id,
name: contextsList[index].name,
version: contextsList[index].version,
attributes: {
sysUserId
}
})
}
} catch (error) {
throw error
}
}
})
return executableContexts
}
public async deleteComputeContext(contextName: string, accessToken?: string) {
this.validateContextName(contextName)
this.isDefaultContext(
contextName,
this.defaultComputeContexts,
'Deleting default SAS compute contexts is not allowed.',
true
)
const headers: any = {
'Content-Type': 'application/json'
}
if (accessToken) {
headers.Authorization = `Bearer ${accessToken}`
}
const context = await this.getComputeContextByName(contextName, accessToken)
return await this.requestClient.delete<Context>(
`${this.serverUrl}/compute/contexts/${context.id}`,
accessToken
)
}
// TODO: implement editLauncherContext method
// TODO: implement deleteLauncherContext method
private validateContextName(name: string) {
if (!name) throw new Error('Context name is required.')
}
public isDefaultContext(
context: string,
defaultContexts: string[] = this.defaultComputeContexts,
errorMessage = '',
listDefaults = false
) {
if (defaultContexts.includes(context)) {
throw new Error(
`${errorMessage}${
listDefaults
? '\nDefault contexts:' +
defaultContexts.map((context, i) => `\n${i + 1}. ${context}`)
: ''
}`
)
}
}
}

View File

@@ -1,25 +1,25 @@
import { isLogInRequired, needsRetry, isUrl } from './utils'
import { CsrfToken } from './types/CsrfToken'
import { isUrl } from './utils'
import { UploadFile } from './types/UploadFile'
const requestRetryLimit = 5
import { ErrorResponse, LoginRequiredError } from './types'
import { RequestClient } from './request/RequestClient'
export class FileUploader {
constructor(
private appLoc: string,
private serverUrl: string,
serverUrl: string,
private jobsPath: string,
private setCsrfTokenWeb: any,
private csrfToken: CsrfToken | null = null
private requestClient: RequestClient
) {
if (serverUrl) isUrl(serverUrl)
}
private retryCount = 0
public uploadFile(sasJob: string, files: UploadFile[], params: any) {
if (files?.length < 1)
throw new Error('At least one file must be provided.')
return Promise.reject(
new ErrorResponse('At least one file must be provided.')
)
if (!sasJob || sasJob === '')
return Promise.reject(new ErrorResponse('sasJob must be provided.'))
let paramsString = ''
@@ -32,73 +32,39 @@ export class FileUploader {
const program = this.appLoc
? this.appLoc.replace(/\/?$/, '/') + sasJob.replace(/^\//, '')
: sasJob
const uploadUrl = `${this.serverUrl}${this.jobsPath}/?${
const uploadUrl = `${this.jobsPath}/?${
'_program=' + program
}${paramsString}`
const headers = {
'cache-control': 'no-cache'
const formData = new FormData()
for (let file of files) {
formData.append('file', file.file, file.fileName)
}
return new Promise((resolve, reject) => {
const formData = new FormData()
const csrfToken = this.requestClient.getCsrfToken('file')
if (csrfToken) formData.append('_csrf', csrfToken.value)
for (let file of files) {
formData.append('file', file.file, file.fileName)
}
const headers = {
'cache-control': 'no-cache',
Accept: '*/*',
'Content-Type': 'text/plain'
}
if (this.csrfToken) formData.append('_csrf', this.csrfToken.value)
fetch(uploadUrl, {
method: 'POST',
body: formData,
referrerPolicy: 'same-origin',
headers
return this.requestClient
.post(uploadUrl, formData, undefined, 'application/json', headers)
.then((res) =>
typeof res.result === 'string' ? JSON.parse(res.result) : res.result
)
.catch((err: Error) => {
if (err instanceof LoginRequiredError) {
return Promise.reject(
new ErrorResponse('You must be logged in to upload a file.', err)
)
}
return Promise.reject(
new ErrorResponse('File upload request failed.', err)
)
})
.then(async (response) => {
if (!response.ok) {
if (response.status === 403) {
const tokenHeader = response.headers.get('X-CSRF-HEADER')
if (tokenHeader) {
const token = response.headers.get(tokenHeader)
this.csrfToken = {
headerName: tokenHeader,
value: token || ''
}
this.setCsrfTokenWeb(this.csrfToken)
}
}
}
return response.text()
})
.then((responseText) => {
if (isLogInRequired(responseText))
reject('You must be logged in to upload a file')
if (needsRetry(responseText)) {
if (this.retryCount < requestRetryLimit) {
this.retryCount++
this.uploadFile(sasJob, files, params).then(
(res: any) => resolve(res),
(err: any) => reject(err)
)
} else {
this.retryCount = 0
reject(responseText)
}
} else {
this.retryCount = 0
try {
resolve(JSON.parse(responseText))
} catch (e) {
reject(e)
}
}
})
})
}
}

View File

@@ -1,3 +1,4 @@
import axios, { AxiosInstance } from 'axios'
import { isUrl } from './utils'
/**
@@ -5,8 +6,11 @@ import { isUrl } from './utils'
*
*/
export class SAS9ApiClient {
private httpClient: AxiosInstance
constructor(private serverUrl: string) {
if (serverUrl) isUrl(serverUrl)
this.httpClient = axios.create({ baseURL: this.serverUrl })
}
/**
@@ -38,18 +42,18 @@ export class SAS9ApiClient {
repositoryName: string
) {
const requestPayload = linesOfCode.join('\n')
const executeScriptRequest = {
method: 'PUT',
headers: {
Accept: 'application/json'
},
body: `command=${requestPayload}`
}
const executeScriptResponse = await fetch(
`${this.serverUrl}/sas/servers/${serverName}/cmd?repositoryName=${repositoryName}`,
executeScriptRequest
).then((res) => res.text())
return executeScriptResponse
const executeScriptResponse = await this.httpClient.put(
`/sas/servers/${serverName}/cmd?repositoryName=${repositoryName}`,
`command=${requestPayload}`,
{
headers: {
Accept: 'application/json'
},
responseType: 'text'
}
)
return executeScriptResponse.data
}
}

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -1,86 +1,127 @@
import { Session, Context, CsrfToken } from './types'
import { asyncForEach, makeRequest, isUrl } from './utils'
import { Session, Context, CsrfToken, SessionVariable } from './types'
import { asyncForEach, isUrl } from './utils'
import { prefixMessage } from '@sasjs/utils/error'
import { RequestClient } from './request/RequestClient'
const MAX_SESSION_COUNT = 1
const RETRY_LIMIT: number = 3
let RETRY_COUNT: number = 0
const INTERNAL_SAS_ERROR = {
status: 304,
message: 'Not Modified'
}
export class SessionManager {
constructor(
private serverUrl: string,
private contextName: string,
private setCsrfToken: (csrfToken: CsrfToken) => void
private requestClient: RequestClient
) {
if (serverUrl) isUrl(serverUrl)
}
private sessions: Session[] = []
private currentContext: Context | null = null
private csrfToken: CsrfToken | null = null
private _debug: boolean = false
private printedSessionState = {
printed: false,
state: ''
}
public get debug() {
return this._debug
}
public set debug(value: boolean) {
this._debug = value
}
async getSession(accessToken?: string) {
await this.createSessions(accessToken)
this.createAndWaitForSession(accessToken)
await this.createAndWaitForSession(accessToken)
const session = this.sessions.pop()
const secondsSinceSessionCreation =
(new Date().getTime() - new Date(session!.creationTimeStamp).getTime()) /
1000
if (
!session!.attributes ||
secondsSinceSessionCreation >= session!.attributes.sessionInactiveTimeout
) {
await this.createSessions(accessToken)
const freshSession = this.sessions.pop()
return freshSession
}
return session
}
async clearSession(id: string, accessToken?: string) {
const deleteSessionRequest = {
method: 'DELETE',
headers: this.getHeaders(accessToken)
}
return await this.request<Session>(
`${this.serverUrl}/compute/sessions/${id}`,
deleteSessionRequest
).then(() => {
this.sessions = this.sessions.filter((s) => s.id !== id)
})
return await this.requestClient
.delete<Session>(`/compute/sessions/${id}`, accessToken)
.then(() => {
this.sessions = this.sessions.filter((s) => s.id !== id)
})
.catch((err) => {
throw err
})
}
private async createSessions(accessToken?: string) {
if (!this.sessions.length) {
if (!this.currentContext) {
await this.setCurrentContext(accessToken)
await this.setCurrentContext(accessToken).catch((err) => {
throw err
})
}
await asyncForEach(new Array(MAX_SESSION_COUNT), async () => {
const createdSession = await this.createAndWaitForSession(accessToken)
const createdSession = await this.createAndWaitForSession(
accessToken
).catch((err) => {
throw err
})
this.sessions.push(createdSession)
}).catch((err) => {
throw err
})
}
}
private async createAndWaitForSession(accessToken?: string) {
const createSessionRequest = {
method: 'POST',
headers: this.getHeaders(accessToken)
}
const { result: createdSession, etag } = await this.request<Session>(
`${this.serverUrl}/compute/contexts/${this.currentContext!.id}/sessions`,
createSessionRequest
)
const {
result: createdSession,
etag
} = await this.requestClient
.post<Session>(
`${this.serverUrl}/compute/contexts/${
this.currentContext!.id
}/sessions`,
{},
accessToken
)
.catch((err) => {
throw err
})
await this.waitForSession(createdSession, etag, accessToken)
this.sessions.push(createdSession)
return createdSession
}
private async setCurrentContext(accessToken?: string) {
if (!this.currentContext) {
const { result: contexts } = await this.request<{
items: Context[]
}>(`${this.serverUrl}/compute/contexts?limit=10000`, {
headers: this.getHeaders(accessToken)
})
const { result: contexts } = await this.requestClient
.get<{
items: Context[]
}>(`${this.serverUrl}/compute/contexts?limit=10000`, accessToken)
.catch((err) => {
throw err
})
const contextsList =
contexts && contexts.items && contexts.items.length
@@ -98,6 +139,8 @@ export class SessionManager {
}
this.currentContext = currentContext
Promise.resolve()
}
}
@@ -105,6 +148,7 @@ export class SessionManager {
const headers: any = {
'Content-Type': 'application/json'
}
if (accessToken) {
headers.Authorization = `Bearer ${accessToken}`
}
@@ -115,33 +159,53 @@ export class SessionManager {
private async waitForSession(
session: Session,
etag: string | null,
accessToken?: string,
silent = false
accessToken?: string
) {
let sessionState = session.state
const headers: any = {
...this.getHeaders(accessToken),
'If-None-Match': etag
}
const stateLink = session.links.find((l: any) => l.rel === 'state')
return new Promise(async (resolve, _) => {
if (sessionState === 'pending') {
if (
sessionState === 'pending' ||
sessionState === 'running' ||
sessionState === ''
) {
if (stateLink) {
if (!silent) {
console.log('Polling session status... \n') // ?
if (this.debug && !this.printedSessionState.printed) {
console.log('Polling session status...')
this.printedSessionState.printed = true
}
const { result: state } = await this.request<string>(
const state = await this.getSessionState(
`${this.serverUrl}${stateLink.href}?wait=30`,
{
headers
},
'text'
)
etag!,
accessToken
).catch((err) => {
throw err
})
sessionState = state.trim()
if (!silent) {
console.log(`Current state is '${sessionState}'\n`)
if (this.debug && this.printedSessionState.state !== sessionState) {
console.log(`Current session state is '${sessionState}'`)
this.printedSessionState.state = sessionState
this.printedSessionState.printed = false
}
// There is an internal error present in SAS Viya 3.5
// Retry to wait for a session status in such case of SAS internal error
if (
sessionState === INTERNAL_SAS_ERROR.message &&
RETRY_COUNT < RETRY_LIMIT
) {
RETRY_COUNT++
resolve(this.waitForSession(session, etag, accessToken))
}
resolve(sessionState)
}
} else {
@@ -150,25 +214,33 @@ export class SessionManager {
})
}
private async request<T>(
private async getSessionState(
url: string,
options: RequestInit,
contentType: 'text' | 'json' = 'json'
etag: string,
accessToken?: string
) {
if (this.csrfToken) {
options.headers = {
...options.headers,
[this.csrfToken.headerName]: this.csrfToken.value
}
}
return await makeRequest<T>(
url,
options,
(token) => {
this.csrfToken = token
this.setCsrfToken(token)
},
contentType
)
return await this.requestClient
.get(url, accessToken, 'text/plain', { 'If-None-Match': etag })
.then((res) => res.result as string)
.catch((err) => {
if (err.status === INTERNAL_SAS_ERROR.status)
return INTERNAL_SAS_ERROR.message
throw err
})
}
async getVariable(sessionId: string, variable: string, accessToken?: string) {
return await this.requestClient
.get<SessionVariable>(
`${this.serverUrl}/compute/sessions/${sessionId}/variables/${variable}`,
accessToken
)
.catch((err) => {
throw prefixMessage(
err,
`Error while fetching session variable '${variable}'.`
)
})
}
}

7
src/__mocks__/axios.ts Normal file
View File

@@ -0,0 +1,7 @@
import { AxiosStatic } from 'axios'
const mockAxios = jest.genMockFromModule('axios') as AxiosStatic
mockAxios.create = jest.fn(() => mockAxios)
export default mockAxios

156
src/auth/AuthManager.ts Normal file
View File

@@ -0,0 +1,156 @@
import { ServerType } from '@sasjs/utils/types'
import { isAuthorizeFormRequired } from '.'
import { RequestClient } from '../request/RequestClient'
import { serialize } from '../utils'
export class AuthManager {
public userName = ''
private loginUrl: string
private logoutUrl: string
constructor(
private serverUrl: string,
private serverType: ServerType,
private requestClient: RequestClient,
private loginCallback: () => Promise<void>
) {
this.loginUrl = `/SASLogon/login`
this.logoutUrl =
this.serverType === ServerType.Sas9
? '/SASLogon/logout?'
: '/SASLogon/logout.do?'
}
/**
* Logs into the SAS server with the supplied credentials.
* @param username - a string representing the username.
* @param password - a string representing the password.
*/
public async logIn(username: string, password: string) {
const loginParams: any = {
_service: 'default',
username,
password
}
this.userName = loginParams.username
const { isLoggedIn, loginForm } = await this.checkSession()
if (isLoggedIn) {
await this.loginCallback()
return {
isLoggedIn,
userName: this.userName
}
}
for (const key in loginForm) {
loginParams[key] = loginForm[key]
}
const loginParamsStr = serialize(loginParams)
const { result: loginResponse } = await this.requestClient.post<string>(
this.loginUrl,
loginParamsStr,
undefined,
'text/plain',
{
'Content-Type': 'application/x-www-form-urlencoded',
Accept: '*/*'
}
)
let loggedIn = isLogInSuccess(loginResponse)
if (!loggedIn) {
const currentSession = await this.checkSession()
loggedIn = currentSession.isLoggedIn
}
if (loggedIn) {
this.loginCallback()
}
return {
isLoggedIn: !!loggedIn,
userName: this.userName
}
}
/**
* Checks whether a session is active, or login is required.
* @returns - a promise which resolves with an object containing two values - a boolean `isLoggedIn`, and a string `userName`.
*/
public async checkSession() {
const { result: loginResponse } = await this.requestClient.get<string>(
this.loginUrl.replace('.do', ''),
undefined,
'text/plain'
)
const responseText = loginResponse
const isLoggedIn = /<button.+onClick.+logout/gm.test(responseText)
let loginForm: any = null
if (!isLoggedIn) {
loginForm = await this.getLoginForm(responseText)
}
return Promise.resolve({
isLoggedIn,
userName: this.userName,
loginForm
})
}
private getLoginForm(response: any) {
const pattern: RegExp = /<form.+action="(.*Logon[^"]*).*>/
const matches = pattern.exec(response)
const formInputs: any = {}
if (matches && matches.length) {
this.setLoginUrl(matches)
const inputs = response.match(/<input.*"hidden"[^>]*>/g)
if (inputs) {
inputs.forEach((inputStr: string) => {
const valueMatch = inputStr.match(/name="([^"]*)"\svalue="([^"]*)/)
if (valueMatch && valueMatch.length) {
formInputs[valueMatch[1]] = valueMatch[2]
}
})
}
}
return Object.keys(formInputs).length ? formInputs : null
}
private setLoginUrl = (matches: RegExpExecArray) => {
let parsedURL = matches[1].replace(/\?.*/, '')
if (parsedURL[0] === '/') {
parsedURL = parsedURL.substr(1)
const tempLoginLink = this.serverUrl
? `${this.serverUrl}/${parsedURL}`
: `${parsedURL}`
const loginUrl = tempLoginLink
this.loginUrl =
this.serverType === ServerType.SasViya
? tempLoginLink
: loginUrl.replace('.do', '')
}
}
/**
* Logs out of the configured SAS server.
*/
public logOut() {
this.requestClient.clearCsrfTokens()
return this.requestClient.get(this.logoutUrl, undefined).then(() => true)
}
}
const isLogInSuccess = (response: string): boolean =>
/You have signed in/gm.test(response)

3
src/auth/index.ts Normal file
View File

@@ -0,0 +1,3 @@
export * from './AuthManager'
export * from './isAuthorizeFormRequired'
export * from './isLoginRequired'

View File

@@ -0,0 +1,217 @@
import { AuthManager } from '../AuthManager'
import * as dotenv from 'dotenv'
import { ServerType } from '@sasjs/utils/types'
import axios from 'axios'
import {
mockLoginAuthoriseRequiredResponse,
mockLoginSuccessResponse
} from './mockResponses'
import { serialize } from '../../utils'
import { RequestClient } from '../../request/RequestClient'
jest.mock('axios')
const mockedAxios = axios as jest.Mocked<typeof axios>
describe('AuthManager', () => {
const authCallback = jest.fn().mockImplementation(() => Promise.resolve())
const serverUrl = 'http://test-server.com'
const serverType = ServerType.SasViya
const userName = 'test-username'
const password = 'test-password'
const requestClient = new RequestClient(serverUrl)
beforeAll(() => {
dotenv.config()
jest.restoreAllMocks()
})
it('should instantiate and set the correct URLs for a Viya server', () => {
const authManager = new AuthManager(
serverUrl,
serverType,
requestClient,
authCallback
)
expect(authManager).toBeTruthy()
expect((authManager as any).serverUrl).toEqual(serverUrl)
expect((authManager as any).serverType).toEqual(serverType)
expect((authManager as any).loginUrl).toEqual(`/SASLogon/login`)
expect((authManager as any).logoutUrl).toEqual('/SASLogon/logout.do?')
})
it('should instantiate and set the correct URLs for a SAS9 server', () => {
const authCallback = () => Promise.resolve()
const serverType = ServerType.Sas9
const authManager = new AuthManager(
serverUrl,
serverType,
requestClient,
authCallback
)
expect(authManager).toBeTruthy()
expect((authManager as any).serverUrl).toEqual(serverUrl)
expect((authManager as any).serverType).toEqual(serverType)
expect((authManager as any).loginUrl).toEqual(`/SASLogon/login`)
expect((authManager as any).logoutUrl).toEqual('/SASLogon/logout?')
})
it('should call the auth callback and return when already logged in', async (done) => {
const authManager = new AuthManager(
serverUrl,
serverType,
requestClient,
authCallback
)
jest.spyOn(authManager, 'checkSession').mockImplementation(() =>
Promise.resolve({
isLoggedIn: true,
userName: 'test',
loginForm: 'test'
})
)
const loginResponse = await authManager.logIn(userName, password)
expect(loginResponse.isLoggedIn).toBeTruthy()
expect(loginResponse.userName).toEqual(userName)
expect(authCallback).toHaveBeenCalledTimes(1)
done()
})
it('should post a login request to the server if not logged in', async (done) => {
const authManager = new AuthManager(
serverUrl,
serverType,
requestClient,
authCallback
)
jest.spyOn(authManager, 'checkSession').mockImplementation(() =>
Promise.resolve({
isLoggedIn: false,
userName: 'test',
loginForm: { name: 'test' }
})
)
mockedAxios.post.mockImplementation(() =>
Promise.resolve({ data: mockLoginSuccessResponse })
)
const loginResponse = await authManager.logIn(userName, password)
expect(loginResponse.isLoggedIn).toBeTruthy()
expect(loginResponse.userName).toEqual(userName)
const loginParams = serialize({
_service: 'default',
username: userName,
password,
name: 'test'
})
expect(mockedAxios.post).toHaveBeenCalledWith(
`/SASLogon/login`,
loginParams,
{
withCredentials: true,
headers: {
'Content-Type': 'application/x-www-form-urlencoded',
Accept: '*/*'
}
}
)
expect(authCallback).toHaveBeenCalledTimes(1)
done()
})
it('should parse and submit the authorisation form when necessary', async (done) => {
const authManager = new AuthManager(
serverUrl,
serverType,
requestClient,
authCallback
)
jest
.spyOn(requestClient, 'authorize')
.mockImplementation(() => Promise.resolve())
jest.spyOn(authManager, 'checkSession').mockImplementation(() =>
Promise.resolve({
isLoggedIn: false,
userName: 'test',
loginForm: { name: 'test' }
})
)
mockedAxios.post.mockImplementationOnce(() =>
Promise.resolve({
data: mockLoginAuthoriseRequiredResponse,
config: { url: 'https://test.com/SASLogon/login' },
request: { responseURL: 'https://test.com/OAuth/authorize' }
})
)
mockedAxios.get.mockImplementationOnce(() =>
Promise.resolve({
data: mockLoginAuthoriseRequiredResponse
})
)
await authManager.logIn(userName, password)
expect(requestClient.authorize).toHaveBeenCalledWith(
mockLoginAuthoriseRequiredResponse
)
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()
})
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()
})
})

View File

@@ -0,0 +1,2 @@
export const mockLoginAuthoriseRequiredResponse = `<form id="application_authorization" action="/SASLogon/oauth/authorize" method="POST"><input type="hidden" name="X-Uaa-Csrf" value="2nfuxIn6WaOURWL7tzTXCe"/>`
export const mockLoginSuccessResponse = `You have signed in`

View File

@@ -0,0 +1,24 @@
import { convertToCSV } from '../utils/convertToCsv'
export const generateFileUploadForm = (
formData: FormData,
data: any
): FormData => {
for (const tableName in data) {
const name = tableName
const csv = convertToCSV(data[tableName])
if (csv === 'ERROR: LARGE STRING LENGTH') {
throw new Error(
'The max length of a string value in SASjs is 32765 characters.'
)
}
const file = new Blob([csv], {
type: 'application/csv'
})
formData.append(name, file, `${name}.csv`)
}
return formData
}

View File

@@ -0,0 +1,31 @@
import { convertToCSV } from '../utils/convertToCsv'
import { splitChunks } from '../utils/splitChunks'
export const generateTableUploadForm = (formData: FormData, data: any) => {
const sasjsTables = []
const requestParams: any = {}
let tableCounter = 0
for (const tableName in data) {
tableCounter++
sasjsTables.push(tableName)
const csv = convertToCSV(data[tableName])
if (csv === 'ERROR: LARGE STRING LENGTH') {
throw new Error(
'The max length of a string value in SASjs is 32765 characters.'
)
}
// if csv has length more then 16k, send in chunks
if (csv.length > 16000) {
const csvChunks = splitChunks(csv)
// append chunks to form data with same key
csvChunks.map((chunk) => {
formData.append(`sasjs${tableCounter}data`, chunk)
})
} else {
requestParams[`sasjs${tableCounter}data`] = csv
}
}
requestParams['sasjs_tables'] = sasjsTables.join(' ')
return { formData, requestParams }
}

View File

@@ -0,0 +1,54 @@
import { ServerType } from '@sasjs/utils/types'
import { ErrorResponse } from '..'
import { SASViyaApiClient } from '../SASViyaApiClient'
import { ComputeJobExecutionError, LoginRequiredError } from '../types'
import { BaseJobExecutor } from './JobExecutor'
export class ComputeJobExecutor extends BaseJobExecutor {
constructor(serverUrl: string, private sasViyaApiClient: SASViyaApiClient) {
super(serverUrl, ServerType.SasViya)
}
async execute(
sasJob: string,
data: any,
config: any,
loginRequiredCallback?: any,
accessToken?: string
) {
const loginCallback = loginRequiredCallback || (() => Promise.resolve())
const waitForResult = true
const expectWebout = true
return this.sasViyaApiClient
?.executeComputeJob(
sasJob,
config.contextName,
config.debug,
data,
accessToken,
waitForResult,
expectWebout
)
.then((response) => {
this.appendRequest(response, sasJob, config.debug)
let responseJson
return response.result
return responseJson
})
.catch(async (e: Error) => {
if (e instanceof ComputeJobExecutionError) {
this.appendRequest(e, sasJob, config.debug)
}
if (e instanceof LoginRequiredError) {
await loginCallback()
this.appendWaitingRequest(() =>
this.execute(sasJob, data, config, loginRequiredCallback)
)
}
return Promise.reject(new ErrorResponse(e?.message, e))
})
}
}

Some files were not shown because too many files have changed in this diff Show More