diff --git a/api/.env.example b/api/.env.example index 4c75eda..3e14bda 100644 --- a/api/.env.example +++ b/api/.env.example @@ -1,3 +1,4 @@ +MODE=[server] ACCESS_TOKEN_SECRET= REFRESH_TOKEN_SECRET= AUTH_CODE_SECRET= diff --git a/api/package-lock.json b/api/package-lock.json index 96adc00..6dc3fab 100644 --- a/api/package-lock.json +++ b/api/package-lock.json @@ -8,7 +8,7 @@ "name": "api", "version": "0.0.1", "dependencies": { - "@sasjs/utils": "^2.23.3", + "@sasjs/utils": "^2.33.1", "bcryptjs": "^2.4.3", "express": "^4.17.1", "joi": "^17.4.2", @@ -17,6 +17,7 @@ "mongoose-sequence": "^5.3.1", "morgan": "^1.10.0", "multer": "^1.4.3", + "prompt": "^1.2.0", "swagger-ui-express": "^4.1.6", "tsoa": "^3.14.0" }, @@ -32,6 +33,7 @@ "@types/morgan": "^1.9.3", "@types/multer": "^1.4.7", "@types/node": "^15.12.2", + "@types/prompt": "^1.1.1", "@types/supertest": "^2.0.11", "@types/swagger-ui-express": "^4.1.3", "dotenv": "^10.0.0", @@ -1557,17 +1559,21 @@ } }, "node_modules/@sasjs/utils": { - "version": "2.23.3", - "resolved": "https://registry.npmjs.org/@sasjs/utils/-/utils-2.23.3.tgz", - "integrity": "sha512-tEh4mGG80eUxSLpbPivA0vl4akMdauL+yZrLn1uUM8EyiXPvlcWPkQTeN6oHbyyAH108D9cfEBidTePZh1p5VQ==", + "version": "2.33.1", + "resolved": "https://registry.npmjs.org/@sasjs/utils/-/utils-2.33.1.tgz", + "integrity": "sha512-QQqI9+G/riMrbNSjambYwaJwGY3om2f3N9z9tNxBSva+W0g3JaOl4qeOqpRS91KhOmNhrLMCohg6jScMCz3YFQ==", + "hasInstallScript": true, "dependencies": { + "@types/fs-extra": "^9.0.11", "@types/prompts": "^2.0.13", "chalk": "^4.1.1", "cli-table": "^0.3.6", "consola": "^2.15.0", + "csv-stringify": "^5.6.5", "fs-extra": "^10.0.0", "jwt-decode": "^3.1.2", "prompts": "^2.4.1", + "rimraf": "^3.0.2", "valid-url": "^1.0.9" } }, @@ -2222,6 +2228,14 @@ "@types/range-parser": "*" } }, + "node_modules/@types/fs-extra": { + "version": "9.0.13", + "resolved": "https://registry.npmjs.org/@types/fs-extra/-/fs-extra-9.0.13.tgz", + "integrity": "sha512-nEnwB++1u5lVDM2UI4c1+5R+FYaKfaAzS4OococimjVm3nQw3TuzH5UNsocrcTBbhnerblyHj4A49qXbIiZdpA==", + "dependencies": { + "@types/node": "*" + } + }, "node_modules/@types/graceful-fs": { "version": "4.1.5", "resolved": "https://registry.npmjs.org/@types/graceful-fs/-/graceful-fs-4.1.5.tgz", @@ -2465,6 +2479,16 @@ "integrity": "sha512-eI5Yrz3Qv4KPUa/nSIAi0h+qX0XyewOliug5F2QAtuRg6Kjg6jfmxe1GIwoIRhZspD1A0RP8ANrPwvEXXtRFog==", "dev": true }, + "node_modules/@types/prompt": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@types/prompt/-/prompt-1.1.1.tgz", + "integrity": "sha512-Ht3nSZy87jqKM5Y92GWKD6RQTqQIi6tAKhrWgEvFPh+P13L5olqBYs+P1HySBYRHyIezEqrB3StK4X7lBFmIEQ==", + "dev": true, + "dependencies": { + "@types/node": "*", + "@types/revalidator": "*" + } + }, "node_modules/@types/prompts": { "version": "2.0.13", "resolved": "https://registry.npmjs.org/@types/prompts/-/prompts-2.0.13.tgz", @@ -2491,6 +2515,12 @@ "integrity": "sha512-wWKOClTTiizcZhXnPY4wikVAwmdYHp8q6DmC+EJUzAMsycb7HB32Kh9RN4+0gExjmPmZSAQjgURXIGATPegAvA==", "dev": true }, + "node_modules/@types/revalidator": { + "version": "0.3.8", + "resolved": "https://registry.npmjs.org/@types/revalidator/-/revalidator-0.3.8.tgz", + "integrity": "sha512-q6KSi3PklLGQ0CesZ/XuLwly4DXXlnJuucYOG9lrBqrP8rKiuPZThav2h2+pFjaheNpnT0qKK3i304QWIePeJw==", + "dev": true + }, "node_modules/@types/serve-static": { "version": "1.13.9", "resolved": "https://registry.npmjs.org/@types/serve-static/-/serve-static-1.13.9.tgz", @@ -3960,6 +3990,19 @@ "integrity": "sha512-b0tGHbfegbhPJpxpiBPU2sCkigAqtM9O121le6bbOlgyV+NyGyCmVfJ6QW9eRjz8CpNfWEOYBIMIGRYkLwsIYg==", "dev": true }, + "node_modules/csv-stringify": { + "version": "5.6.5", + "resolved": "https://registry.npmjs.org/csv-stringify/-/csv-stringify-5.6.5.tgz", + "integrity": "sha512-PjiQ659aQ+fUTQqSrd1XEDnOr52jh30RBurfzkscaE2tPaFsDH5wOAHJiw8XAHphRknCwMUE9KRayc4K/NbO8A==" + }, + "node_modules/cycle": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/cycle/-/cycle-1.0.3.tgz", + "integrity": "sha1-IegLK+hYD5i0aPN5QwZisEbDStI=", + "engines": { + "node": ">=0.4.0" + } + }, "node_modules/data-urls": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/data-urls/-/data-urls-2.0.0.tgz", @@ -4762,6 +4805,14 @@ "node": ">= 0.10.0" } }, + "node_modules/eyes": { + "version": "0.1.8", + "resolved": "https://registry.npmjs.org/eyes/-/eyes-0.1.8.tgz", + "integrity": "sha1-Ys8SAjTGg3hdkCNIqADvPgzCC8A=", + "engines": { + "node": "> 0.1.90" + } + }, "node_modules/fast-glob": { "version": "3.2.5", "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.2.5.tgz", @@ -6157,6 +6208,11 @@ "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=", "dev": true }, + "node_modules/isstream": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/isstream/-/isstream-0.1.2.tgz", + "integrity": "sha1-R+Y/evVa+m+S4VAOaQ64uFKcCZo=" + }, "node_modules/issue-parser": { "version": "6.0.0", "resolved": "https://registry.npmjs.org/issue-parser/-/issue-parser-6.0.0.tgz", @@ -8625,6 +8681,11 @@ "readable-stream": "^3.6.0" } }, + "node_modules/mute-stream": { + "version": "0.0.8", + "resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-0.0.8.tgz", + "integrity": "sha512-nnbWWOkoWyUsTjKrhgD0dcz22mdkSnpYqbEjIm2nhwhuxlSkpywJmBo8h0ZqJdkp73mb90SssHkN4rsRaBAfAA==" + }, "node_modules/napi-build-utils": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/napi-build-utils/-/napi-build-utils-1.0.2.tgz", @@ -12513,6 +12574,34 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/prompt": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/prompt/-/prompt-1.2.0.tgz", + "integrity": "sha512-iGerYRpRUg5ZyC+FJ/25G5PUKuWAGRjW1uOlhX7Pi3O5YygdK6R+KEaBjRbHSkU5vfS5PZCltSPZdDtUYwRCZA==", + "dependencies": { + "async": "~0.9.0", + "colors": "^1.1.2", + "read": "1.0.x", + "revalidator": "0.1.x", + "winston": "2.x" + }, + "engines": { + "node": ">= 0.6.6" + } + }, + "node_modules/prompt/node_modules/async": { + "version": "0.9.2", + "resolved": "https://registry.npmjs.org/async/-/async-0.9.2.tgz", + "integrity": "sha1-rqdNXmHB+JlhO/ZL2mbUx48v0X0=" + }, + "node_modules/prompt/node_modules/colors": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/colors/-/colors-1.4.0.tgz", + "integrity": "sha512-a+UqTh4kgZg/SlGvfbzDHpgRu7AAQOmmqRHJnxhRZICKFUT91brVhNNt58CMWU9PsBbv3PDCZUHbVxuDiH2mtA==", + "engines": { + "node": ">=0.1.90" + } + }, "node_modules/prompts": { "version": "2.4.1", "resolved": "https://registry.npmjs.org/prompts/-/prompts-2.4.1.tgz", @@ -12669,6 +12758,17 @@ "integrity": "sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w==", "dev": true }, + "node_modules/read": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/read/-/read-1.0.7.tgz", + "integrity": "sha1-s9oZvQUkMal2cdRKQmNK33ELQMQ=", + "dependencies": { + "mute-stream": "~0.0.4" + }, + "engines": { + "node": ">=0.8" + } + }, "node_modules/read-pkg": { "version": "5.2.0", "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-5.2.0.tgz", @@ -12880,11 +12980,18 @@ "node": ">=0.10.0" } }, + "node_modules/revalidator": { + "version": "0.1.8", + "resolved": "https://registry.npmjs.org/revalidator/-/revalidator-0.1.8.tgz", + "integrity": "sha1-/s5hv6DBtSoga9axgZgYS91SOjs=", + "engines": { + "node": ">= 0.4.0" + } + }, "node_modules/rimraf": { "version": "3.0.2", "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", - "dev": true, "dependencies": { "glob": "^7.1.3" }, @@ -13414,6 +13521,14 @@ "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", "integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw=" }, + "node_modules/stack-trace": { + "version": "0.0.10", + "resolved": "https://registry.npmjs.org/stack-trace/-/stack-trace-0.0.10.tgz", + "integrity": "sha1-VHxws0fo0ytOEI6hoqFZ5f3eGcA=", + "engines": { + "node": "*" + } + }, "node_modules/stack-utils": { "version": "2.0.3", "resolved": "https://registry.npmjs.org/stack-utils/-/stack-utils-2.0.3.tgz", @@ -14648,6 +14763,27 @@ "node": ">=8" } }, + "node_modules/winston": { + "version": "2.4.5", + "resolved": "https://registry.npmjs.org/winston/-/winston-2.4.5.tgz", + "integrity": "sha512-TWoamHt5yYvsMarGlGEQE59SbJHqGsZV8/lwC+iCcGeAe0vUaOh+Lv6SYM17ouzC/a/LB1/hz/7sxFBtlu1l4A==", + "dependencies": { + "async": "~1.0.0", + "colors": "1.0.x", + "cycle": "1.0.x", + "eyes": "0.1.x", + "isstream": "0.1.x", + "stack-trace": "0.0.x" + }, + "engines": { + "node": ">= 0.10.0" + } + }, + "node_modules/winston/node_modules/async": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/async/-/async-1.0.0.tgz", + "integrity": "sha1-+PwEyjoTeErenhZBr5hXjPvWR6k=" + }, "node_modules/word-wrap": { "version": "1.2.3", "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.3.tgz", @@ -16046,17 +16182,20 @@ } }, "@sasjs/utils": { - "version": "2.23.3", - "resolved": "https://registry.npmjs.org/@sasjs/utils/-/utils-2.23.3.tgz", - "integrity": "sha512-tEh4mGG80eUxSLpbPivA0vl4akMdauL+yZrLn1uUM8EyiXPvlcWPkQTeN6oHbyyAH108D9cfEBidTePZh1p5VQ==", + "version": "2.33.1", + "resolved": "https://registry.npmjs.org/@sasjs/utils/-/utils-2.33.1.tgz", + "integrity": "sha512-QQqI9+G/riMrbNSjambYwaJwGY3om2f3N9z9tNxBSva+W0g3JaOl4qeOqpRS91KhOmNhrLMCohg6jScMCz3YFQ==", "requires": { + "@types/fs-extra": "^9.0.11", "@types/prompts": "^2.0.13", "chalk": "^4.1.1", "cli-table": "^0.3.6", "consola": "^2.15.0", + "csv-stringify": "^5.6.5", "fs-extra": "^10.0.0", "jwt-decode": "^3.1.2", "prompts": "^2.4.1", + "rimraf": "^3.0.2", "valid-url": "^1.0.9" }, "dependencies": { @@ -16592,6 +16731,14 @@ "@types/range-parser": "*" } }, + "@types/fs-extra": { + "version": "9.0.13", + "resolved": "https://registry.npmjs.org/@types/fs-extra/-/fs-extra-9.0.13.tgz", + "integrity": "sha512-nEnwB++1u5lVDM2UI4c1+5R+FYaKfaAzS4OococimjVm3nQw3TuzH5UNsocrcTBbhnerblyHj4A49qXbIiZdpA==", + "requires": { + "@types/node": "*" + } + }, "@types/graceful-fs": { "version": "4.1.5", "resolved": "https://registry.npmjs.org/@types/graceful-fs/-/graceful-fs-4.1.5.tgz", @@ -16806,6 +16953,16 @@ "integrity": "sha512-eI5Yrz3Qv4KPUa/nSIAi0h+qX0XyewOliug5F2QAtuRg6Kjg6jfmxe1GIwoIRhZspD1A0RP8ANrPwvEXXtRFog==", "dev": true }, + "@types/prompt": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@types/prompt/-/prompt-1.1.1.tgz", + "integrity": "sha512-Ht3nSZy87jqKM5Y92GWKD6RQTqQIi6tAKhrWgEvFPh+P13L5olqBYs+P1HySBYRHyIezEqrB3StK4X7lBFmIEQ==", + "dev": true, + "requires": { + "@types/node": "*", + "@types/revalidator": "*" + } + }, "@types/prompts": { "version": "2.0.13", "resolved": "https://registry.npmjs.org/@types/prompts/-/prompts-2.0.13.tgz", @@ -16832,6 +16989,12 @@ "integrity": "sha512-wWKOClTTiizcZhXnPY4wikVAwmdYHp8q6DmC+EJUzAMsycb7HB32Kh9RN4+0gExjmPmZSAQjgURXIGATPegAvA==", "dev": true }, + "@types/revalidator": { + "version": "0.3.8", + "resolved": "https://registry.npmjs.org/@types/revalidator/-/revalidator-0.3.8.tgz", + "integrity": "sha512-q6KSi3PklLGQ0CesZ/XuLwly4DXXlnJuucYOG9lrBqrP8rKiuPZThav2h2+pFjaheNpnT0qKK3i304QWIePeJw==", + "dev": true + }, "@types/serve-static": { "version": "1.13.9", "resolved": "https://registry.npmjs.org/@types/serve-static/-/serve-static-1.13.9.tgz", @@ -18018,6 +18181,16 @@ } } }, + "csv-stringify": { + "version": "5.6.5", + "resolved": "https://registry.npmjs.org/csv-stringify/-/csv-stringify-5.6.5.tgz", + "integrity": "sha512-PjiQ659aQ+fUTQqSrd1XEDnOr52jh30RBurfzkscaE2tPaFsDH5wOAHJiw8XAHphRknCwMUE9KRayc4K/NbO8A==" + }, + "cycle": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/cycle/-/cycle-1.0.3.tgz", + "integrity": "sha1-IegLK+hYD5i0aPN5QwZisEbDStI=" + }, "data-urls": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/data-urls/-/data-urls-2.0.0.tgz", @@ -18645,6 +18818,11 @@ "vary": "~1.1.2" } }, + "eyes": { + "version": "0.1.8", + "resolved": "https://registry.npmjs.org/eyes/-/eyes-0.1.8.tgz", + "integrity": "sha1-Ys8SAjTGg3hdkCNIqADvPgzCC8A=" + }, "fast-glob": { "version": "3.2.5", "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.2.5.tgz", @@ -19670,6 +19848,11 @@ "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=", "dev": true }, + "isstream": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/isstream/-/isstream-0.1.2.tgz", + "integrity": "sha1-R+Y/evVa+m+S4VAOaQ64uFKcCZo=" + }, "issue-parser": { "version": "6.0.0", "resolved": "https://registry.npmjs.org/issue-parser/-/issue-parser-6.0.0.tgz", @@ -21555,6 +21738,11 @@ "readable-stream": "^3.6.0" } }, + "mute-stream": { + "version": "0.0.8", + "resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-0.0.8.tgz", + "integrity": "sha512-nnbWWOkoWyUsTjKrhgD0dcz22mdkSnpYqbEjIm2nhwhuxlSkpywJmBo8h0ZqJdkp73mb90SssHkN4rsRaBAfAA==" + }, "napi-build-utils": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/napi-build-utils/-/napi-build-utils-1.0.2.tgz", @@ -24378,6 +24566,30 @@ "iterate-value": "^1.0.2" } }, + "prompt": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/prompt/-/prompt-1.2.0.tgz", + "integrity": "sha512-iGerYRpRUg5ZyC+FJ/25G5PUKuWAGRjW1uOlhX7Pi3O5YygdK6R+KEaBjRbHSkU5vfS5PZCltSPZdDtUYwRCZA==", + "requires": { + "async": "~0.9.0", + "colors": "^1.1.2", + "read": "1.0.x", + "revalidator": "0.1.x", + "winston": "2.x" + }, + "dependencies": { + "async": { + "version": "0.9.2", + "resolved": "https://registry.npmjs.org/async/-/async-0.9.2.tgz", + "integrity": "sha1-rqdNXmHB+JlhO/ZL2mbUx48v0X0=" + }, + "colors": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/colors/-/colors-1.4.0.tgz", + "integrity": "sha512-a+UqTh4kgZg/SlGvfbzDHpgRu7AAQOmmqRHJnxhRZICKFUT91brVhNNt58CMWU9PsBbv3PDCZUHbVxuDiH2mtA==" + } + } + }, "prompts": { "version": "2.4.1", "resolved": "https://registry.npmjs.org/prompts/-/prompts-2.4.1.tgz", @@ -24489,6 +24701,14 @@ "integrity": "sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w==", "dev": true }, + "read": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/read/-/read-1.0.7.tgz", + "integrity": "sha1-s9oZvQUkMal2cdRKQmNK33ELQMQ=", + "requires": { + "mute-stream": "~0.0.4" + } + }, "read-pkg": { "version": "5.2.0", "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-5.2.0.tgz", @@ -24656,11 +24876,15 @@ "integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==", "dev": true }, + "revalidator": { + "version": "0.1.8", + "resolved": "https://registry.npmjs.org/revalidator/-/revalidator-0.1.8.tgz", + "integrity": "sha1-/s5hv6DBtSoga9axgZgYS91SOjs=" + }, "rimraf": { "version": "3.0.2", "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", - "dev": true, "requires": { "glob": "^7.1.3" } @@ -25074,6 +25298,11 @@ "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", "integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw=" }, + "stack-trace": { + "version": "0.0.10", + "resolved": "https://registry.npmjs.org/stack-trace/-/stack-trace-0.0.10.tgz", + "integrity": "sha1-VHxws0fo0ytOEI6hoqFZ5f3eGcA=" + }, "stack-utils": { "version": "2.0.3", "resolved": "https://registry.npmjs.org/stack-utils/-/stack-utils-2.0.3.tgz", @@ -26010,6 +26239,26 @@ "string-width": "^4.0.0" } }, + "winston": { + "version": "2.4.5", + "resolved": "https://registry.npmjs.org/winston/-/winston-2.4.5.tgz", + "integrity": "sha512-TWoamHt5yYvsMarGlGEQE59SbJHqGsZV8/lwC+iCcGeAe0vUaOh+Lv6SYM17ouzC/a/LB1/hz/7sxFBtlu1l4A==", + "requires": { + "async": "~1.0.0", + "colors": "1.0.x", + "cycle": "1.0.x", + "eyes": "0.1.x", + "isstream": "0.1.x", + "stack-trace": "0.0.x" + }, + "dependencies": { + "async": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/async/-/async-1.0.0.tgz", + "integrity": "sha1-+PwEyjoTeErenhZBr5hXjPvWR6k=" + } + } + }, "word-wrap": { "version": "1.2.3", "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.3.tgz", diff --git a/api/package.json b/api/package.json index e4c196e..5cc5147 100644 --- a/api/package.json +++ b/api/package.json @@ -15,9 +15,7 @@ "lint:fix": "npx prettier --write \"src/**/*.{ts,tsx,js,jsx,html,css,sass,less,yml,md,graphql}\"", "lint": "npx prettier --check \"src/**/*.{ts,tsx,js,jsx,html,css,sass,less,yml,md,graphql}\"", "package:lib": "npm run build && cp ./package.json build && cp README.md build && cd build && npm version \"5.0.0\" && npm pack", - "exe": "npm run exe:prepare && npm run exe:run", - "exe:prepare": "npm run build && cd build && npm run public:copy && npm run web && pkg .", - "exe:run": "cd build && ACCESS_TOKEN_SECRET=123 REFRESH_TOKEN_SECRET=456 AUTH_CODE_SECRET=789 DB_CONNECT=\"mongodb+srv://deved:69OFYcgJ1r3Z8ilN@cluster0.hj4h5.mongodb.net/sasjs_server?retryWrites=true&w=majority\" ./dist/api", + "exe": "npm run build && cd build && npm run public:copy && npm run web && pkg .", "public:copy": "cp -r ../public/ ./public/", "web": "cd .. && npm run web:mkdir && npm run web:copy && cd build", "web:mkdir": "rimraf web && mkdir web && mkdir web/build", @@ -38,7 +36,7 @@ }, "author": "Analytium Ltd", "dependencies": { - "@sasjs/utils": "^2.23.3", + "@sasjs/utils": "^2.33.1", "bcryptjs": "^2.4.3", "express": "^4.17.1", "joi": "^17.4.2", diff --git a/api/src/app.ts b/api/src/app.ts index b1ffdbe..0874ad0 100644 --- a/api/src/app.ts +++ b/api/src/app.ts @@ -1,10 +1,12 @@ import path from 'path' import express from 'express' - import morgan from 'morgan' +import dotenv from 'dotenv' + import webRouter from './routes/web' import apiRouter from './routes/api' import { getWebBuildFolderPath } from './utils' +import { connectDB } from './routes/api/auth' const app = express() @@ -18,4 +20,6 @@ app.use(express.json({ limit: '50mb' })) app.use(express.static(getWebBuildFolderPath())) -export default app +dotenv.config() + +export default connectDB().then(() => app) diff --git a/api/src/controllers/internal/Execution.ts b/api/src/controllers/internal/Execution.ts index f03ed64..2aaf4de 100644 --- a/api/src/controllers/internal/Execution.ts +++ b/api/src/controllers/internal/Execution.ts @@ -84,7 +84,8 @@ ${program}` let additionalArgs: string[] = [] if (autoExec) additionalArgs = ['-AUTOEXEC', autoExec] - const { stdout, stderr } = await execFilePromise(configuration.sasPath, [ + const sasLoc = process.sasLoc ?? configuration.sasPath + const { stdout, stderr } = await execFilePromise(sasLoc, [ '-SYSIN', code, '-LOG', diff --git a/api/src/middlewares/authenticateToken.ts b/api/src/middlewares/authenticateToken.ts index 9543080..ed5aa7b 100644 --- a/api/src/middlewares/authenticateToken.ts +++ b/api/src/middlewares/authenticateToken.ts @@ -29,7 +29,7 @@ const authenticateToken = ( tokenType: 'accessToken' | 'refreshToken' = 'accessToken' ) => { const { MODE } = process.env - if (MODE?.trim() === 'desktop') return next() + if (MODE?.trim() !== 'server') return next() const authHeader = req.headers['authorization'] const token = authHeader?.split(' ')[1] diff --git a/api/src/middlewares/desktopRestrict.ts b/api/src/middlewares/desktopRestrict.ts index 0f45aa7..f555293 100644 --- a/api/src/middlewares/desktopRestrict.ts +++ b/api/src/middlewares/desktopRestrict.ts @@ -1,6 +1,6 @@ export const desktopRestrict = (req: any, res: any, next: any) => { const { MODE } = process.env - if (MODE?.trim() === 'desktop') + if (MODE?.trim() !== 'server') return res.status(403).send('Not Allowed while in Desktop Mode.') next() diff --git a/api/src/middlewares/verifyAdmin.ts b/api/src/middlewares/verifyAdmin.ts index 2d94a7e..0488b9e 100644 --- a/api/src/middlewares/verifyAdmin.ts +++ b/api/src/middlewares/verifyAdmin.ts @@ -1,6 +1,6 @@ export const verifyAdmin = (req: any, res: any, next: any) => { const { MODE } = process.env - if (MODE?.trim() === 'desktop') return next() + if (MODE?.trim() !== 'server') return next() const { user } = req if (!user?.isAdmin) return res.status(401).send('Admin account required') diff --git a/api/src/prod-server.ts b/api/src/prod-server.ts index 1a4ce4a..6c6693b 100644 --- a/api/src/prod-server.ts +++ b/api/src/prod-server.ts @@ -2,7 +2,7 @@ import path from 'path' import { readFileSync } from 'fs' import * as https from 'https' import { configuration } from '../package.json' -import app from './app' +import appPromise from './app' const keyPath = path.join('..', 'certificates', 'privkey.pem') const certPath = path.join('..', 'certificates', 'fullchain.pem') @@ -10,10 +10,12 @@ const certPath = path.join('..', 'certificates', 'fullchain.pem') const key = readFileSync(keyPath) const cert = readFileSync(certPath) -const httpsServer = https.createServer({ key, cert }, app) +appPromise.then((app) => { + const httpsServer = https.createServer({ key, cert }, app) -httpsServer.listen(configuration.sasJsPort, () => { - console.log( - `⚡️[server]: Server is running at https://localhost:${configuration.sasJsPort}` - ) + httpsServer.listen(configuration.sasJsPort, () => { + console.log( + `⚡️[server]: Server is running at https://localhost:${configuration.sasJsPort}` + ) + }) }) diff --git a/api/src/routes/api/auth.ts b/api/src/routes/api/auth.ts index db7e91c..32929ef 100644 --- a/api/src/routes/api/auth.ts +++ b/api/src/routes/api/auth.ts @@ -9,7 +9,11 @@ import { authenticateRefreshToken } from '../../middlewares' -import { authorizeValidation, tokenValidation } from '../../utils' +import { + authorizeValidation, + getDesktopFields, + tokenValidation +} from '../../utils' import { InfoJWT } from '../../types' const authRouter = express.Router() @@ -24,10 +28,16 @@ export const populateClients = async () => { }) } -export const connectDB = () => { +export const connectDB = async () => { const { MODE } = process.env - if (MODE?.trim() === 'desktop') { + if (MODE?.trim() !== 'server') { console.log('Running in Destop Mode, no DB to connect.') + + const { sasLoc, driveLoc } = await getDesktopFields() + + process.sasLoc = sasLoc + process.driveLoc = driveLoc + return } diff --git a/api/src/routes/api/index.ts b/api/src/routes/api/index.ts index 22cec0f..fcfb6d9 100644 --- a/api/src/routes/api/index.ts +++ b/api/src/routes/api/index.ts @@ -1,5 +1,5 @@ import express from 'express' -import dotenv from 'dotenv' + import swaggerUi from 'swagger-ui-express' import { @@ -13,10 +13,7 @@ import stpRouter from './stp' import userRouter from './user' import groupRouter from './group' import clientRouter from './client' -import authRouter, { connectDB } from './auth' - -dotenv.config() -connectDB() +import authRouter from './auth' const router = express.Router() diff --git a/api/src/routes/web/web.ts b/api/src/routes/web/web.ts index 3006d01..d95f067 100644 --- a/api/src/routes/web/web.ts +++ b/api/src/routes/web/web.ts @@ -9,7 +9,7 @@ webRouter.get('/', async (_, res) => { const indexHtmlPath = path.join(getWebBuildFolderPath(), 'index.html') const { MODE } = process.env - if (MODE?.trim() === 'desktop') { + if (MODE?.trim() !== 'server') { const content = await readFile(indexHtmlPath) const codeToInject = ` diff --git a/api/src/server.ts b/api/src/server.ts index aa3867e..0c62154 100644 --- a/api/src/server.ts +++ b/api/src/server.ts @@ -1,8 +1,10 @@ -import app from './app' +import appPromise from './app' import { configuration } from '../package.json' -app.listen(configuration.sasJsPort, () => { - console.log( - `⚡️[server]: Server is running at http://localhost:${configuration.sasJsPort}` - ) +appPromise.then((app) => { + app.listen(configuration.sasJsPort, () => { + console.log( + `⚡️[server]: Server is running at http://localhost:${configuration.sasJsPort}` + ) + }) }) diff --git a/api/src/types/Process.d.ts b/api/src/types/Process.d.ts index 2c4dbf4..f90ae02 100644 --- a/api/src/types/Process.d.ts +++ b/api/src/types/Process.d.ts @@ -1,5 +1,7 @@ declare namespace NodeJS { export interface Process { + sasLoc?: string + driveLoc?: string sessionController?: import('../controllers/internal').SessionController } } diff --git a/api/src/utils/file.ts b/api/src/utils/file.ts index 1b99740..1745845 100644 --- a/api/src/utils/file.ts +++ b/api/src/utils/file.ts @@ -5,7 +5,7 @@ export const getWebBuildFolderPath = () => getRealPath(path.join(__dirname, '..', '..', '..', 'web', 'build')) export const getTmpFolderPath = () => - getRealPath(path.join(process.cwd(), 'tmp')) + process.driveLoc ?? getRealPath(path.join(process.cwd(), 'tmp')) export const getTmpFilesFolderPath = () => path.join(getTmpFolderPath(), 'files') diff --git a/api/src/utils/getDesktopFields.ts b/api/src/utils/getDesktopFields.ts new file mode 100644 index 0000000..dc083c0 --- /dev/null +++ b/api/src/utils/getDesktopFields.ts @@ -0,0 +1,61 @@ +import path from 'path' +import { getString } from '@sasjs/utils/input' +import { createFolder, fileExists, folderExists } from '@sasjs/utils' + +const isWindows = () => process.platform === 'win32' + +export const getDesktopFields = async () => { + const sasLoc = await getSASLocation() + const driveLoc = await getDriveLocation() + + return { sasLoc, driveLoc } +} + +const getDriveLocation = async (): Promise => { + const validator = async (filePath: string) => { + if (!filePath) return 'Path to files/drive is required.' + + const drivePath = path.join(process.cwd(), filePath) + + if (!(await folderExists(drivePath))) { + await createFolder(drivePath) + await createFolder(path.join(drivePath, 'files')) + } + + return true + } + + const defaultLocation = isWindows() ? '.\\tmp\\' : './tmp/' + + const targetName = await getString( + 'Please enter path to file/drive (relative to executable): ', + validator, + defaultLocation + ) + + return targetName +} + +const getSASLocation = async (): Promise => { + const validator = async (filePath: string) => { + if (!filePath) return 'Path to SAS executable is required.' + + if (!(await fileExists(filePath))) { + return 'No file found at provided path.' + } + + return true + } + + const defaultLocation = isWindows() + ? 'C:\\Program Files\\SASHome\\SASFoundation\\9.4\\sas.exe' + : '/opt/sas/sas9/SASHome/SASFoundation/9.4/sasexe/sas' + + const targetName = await getString( + 'Please enter path to SAS executable (absolute path): ', + validator, + defaultLocation + ) + + return targetName +} diff --git a/api/src/utils/index.ts b/api/src/utils/index.ts index f2f14bd..ade03b5 100644 --- a/api/src/utils/index.ts +++ b/api/src/utils/index.ts @@ -2,6 +2,7 @@ export * from './file' export * from './generateAccessToken' export * from './generateAuthCode' export * from './generateRefreshToken' +export * from './getDesktopFields' export * from './removeTokensInDB' export * from './saveTokensInDB' export * from './sleep'