diff --git a/api/package-lock.json b/api/package-lock.json index 2573a50..25fcb46 100644 --- a/api/package-lock.json +++ b/api/package-lock.json @@ -9,7 +9,7 @@ "version": "0.0.2", "dependencies": { "@sasjs/core": "4.9.0", - "@sasjs/utils": "2.34.1", + "@sasjs/utils": "2.36.2", "bcryptjs": "^2.4.3", "cookie-parser": "^1.4.6", "cors": "^2.8.5", @@ -1384,31 +1384,29 @@ "integrity": "sha512-zc1Ey0ylHt/eRZAfK0mVG3EqNyq//wLxbiguiK0R6FhVqwYFEkprs3IiLGZ5M9ttKs2rHRIjOe/ckklHm+6HNQ==" }, "node_modules/@sasjs/utils": { - "version": "2.34.1", - "resolved": "https://registry.npmjs.org/@sasjs/utils/-/utils-2.34.1.tgz", - "integrity": "sha512-hd1qieH3d7+xH96n5DpRGTEazeAhYyBBKCdnKhOXMgF2TZVoHFdRs5REfT88CKza6DHBGRVGnIVm5ORGP4cVLg==", + "version": "2.36.2", + "resolved": "https://registry.npmjs.org/@sasjs/utils/-/utils-2.36.2.tgz", + "integrity": "sha512-r0O9vkNIK5+2peBiGbcKc3Ei62eAMDt+1SQl17U9Vv26LYqezxQBwIYYMUjnkZE8Q7XlTI/FUS+SIHTCZMr4Jg==", "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", + "@types/fs-extra": "9.0.13", + "@types/prompts": "2.0.13", + "chalk": "4.1.1", + "cli-table": "0.3.6", + "consola": "2.15.0", + "csv-stringify": "5.6.5", "find": "0.3.0", - "fs-extra": "^10.0.0", - "jwt-decode": "^3.1.2", - "lodash.groupby": "4.6.0", - "lodash.uniqby": "4.7.0", - "prompts": "^2.4.1", - "rimraf": "^3.0.2", - "valid-url": "^1.0.9" + "fs-extra": "10.0.0", + "jwt-decode": "3.1.2", + "prompts": "2.4.1", + "rimraf": "3.0.2", + "valid-url": "1.0.9" } }, "node_modules/@sasjs/utils/node_modules/chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.1.tgz", + "integrity": "sha512-diHzdDKxcU+bAsUboHLPEDQiw0qEe0qd7SYUn3HgcFlWgbDcfLGswOHYeGrHKzG9z6UYf01d9VFMfZxPM1xZSg==", "dependencies": { "ansi-styles": "^4.1.0", "supports-color": "^7.1.0" @@ -2065,9 +2063,9 @@ "dev": true }, "node_modules/@types/prompts": { - "version": "2.0.14", - "resolved": "https://registry.npmjs.org/@types/prompts/-/prompts-2.0.14.tgz", - "integrity": "sha512-HZBd99fKxRWpYCErtm2/yxUZv6/PBI9J7N4TNFffl5JbrYMHBwF25DjQGTW3b3jmXq+9P6/8fCIb2ee57BFfYA==", + "version": "2.0.13", + "resolved": "https://registry.npmjs.org/@types/prompts/-/prompts-2.0.13.tgz", + "integrity": "sha512-jwMOIGy49VruR/gYehhJYgpVzB+EVpEE7t7j9m1oTo4HMpOe7KmsyqdBuoxAzA5B4caUgx0cKrWr7wUEqMXJ7Q==", "dependencies": { "@types/node": "*" } @@ -3219,9 +3217,9 @@ } }, "node_modules/consola": { - "version": "2.15.3", - "resolved": "https://registry.npmjs.org/consola/-/consola-2.15.3.tgz", - "integrity": "sha512-9vAdYbHj6x2fLKC4+oPH0kFzY/orMZyG2Aj+kNylHxKGJ/Ed4dpNyAQYwJOdqO4zdM7XpVHmyejQDcQHrnuXbw==" + "version": "2.15.0", + "resolved": "https://registry.npmjs.org/consola/-/consola-2.15.0.tgz", + "integrity": "sha512-vlcSGgdYS26mPf7qNi+dCisbhiyDnrN1zaRbw3CSuc2wGOMEGGPsp46PdRG5gqXwgtJfjxDkxRNAgRPr1B77vQ==" }, "node_modules/console-control-strings": { "version": "1.1.0", @@ -6820,11 +6818,6 @@ "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==" }, - "node_modules/lodash.groupby": { - "version": "4.6.0", - "resolved": "https://registry.npmjs.org/lodash.groupby/-/lodash.groupby-4.6.0.tgz", - "integrity": "sha1-Cwih3PaDl8OXhVwyOXg4Mt90A9E=" - }, "node_modules/lodash.includes": { "version": "4.3.0", "resolved": "https://registry.npmjs.org/lodash.includes/-/lodash.includes-4.3.0.tgz", @@ -6860,11 +6853,6 @@ "resolved": "https://registry.npmjs.org/lodash.once/-/lodash.once-4.1.1.tgz", "integrity": "sha1-DdOXEhPHxW34gJd9UEyI+0cal6w=" }, - "node_modules/lodash.uniqby": { - "version": "4.7.0", - "resolved": "https://registry.npmjs.org/lodash.uniqby/-/lodash.uniqby-4.7.0.tgz", - "integrity": "sha1-2ZwHpmnp5tJOE2Lf4mbGdhavEwI=" - }, "node_modules/lowercase-keys": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/lowercase-keys/-/lowercase-keys-1.0.1.tgz", @@ -11056,30 +11044,28 @@ "integrity": "sha512-zc1Ey0ylHt/eRZAfK0mVG3EqNyq//wLxbiguiK0R6FhVqwYFEkprs3IiLGZ5M9ttKs2rHRIjOe/ckklHm+6HNQ==" }, "@sasjs/utils": { - "version": "2.34.1", - "resolved": "https://registry.npmjs.org/@sasjs/utils/-/utils-2.34.1.tgz", - "integrity": "sha512-hd1qieH3d7+xH96n5DpRGTEazeAhYyBBKCdnKhOXMgF2TZVoHFdRs5REfT88CKza6DHBGRVGnIVm5ORGP4cVLg==", + "version": "2.36.2", + "resolved": "https://registry.npmjs.org/@sasjs/utils/-/utils-2.36.2.tgz", + "integrity": "sha512-r0O9vkNIK5+2peBiGbcKc3Ei62eAMDt+1SQl17U9Vv26LYqezxQBwIYYMUjnkZE8Q7XlTI/FUS+SIHTCZMr4Jg==", "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", + "@types/fs-extra": "9.0.13", + "@types/prompts": "2.0.13", + "chalk": "4.1.1", + "cli-table": "0.3.6", + "consola": "2.15.0", + "csv-stringify": "5.6.5", "find": "0.3.0", - "fs-extra": "^10.0.0", - "jwt-decode": "^3.1.2", - "lodash.groupby": "4.6.0", - "lodash.uniqby": "4.7.0", - "prompts": "^2.4.1", - "rimraf": "^3.0.2", - "valid-url": "^1.0.9" + "fs-extra": "10.0.0", + "jwt-decode": "3.1.2", + "prompts": "2.4.1", + "rimraf": "3.0.2", + "valid-url": "1.0.9" }, "dependencies": { "chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.1.tgz", + "integrity": "sha512-diHzdDKxcU+bAsUboHLPEDQiw0qEe0qd7SYUn3HgcFlWgbDcfLGswOHYeGrHKzG9z6UYf01d9VFMfZxPM1xZSg==", "requires": { "ansi-styles": "^4.1.0", "supports-color": "^7.1.0" @@ -11655,9 +11641,9 @@ "dev": true }, "@types/prompts": { - "version": "2.0.14", - "resolved": "https://registry.npmjs.org/@types/prompts/-/prompts-2.0.14.tgz", - "integrity": "sha512-HZBd99fKxRWpYCErtm2/yxUZv6/PBI9J7N4TNFffl5JbrYMHBwF25DjQGTW3b3jmXq+9P6/8fCIb2ee57BFfYA==", + "version": "2.0.13", + "resolved": "https://registry.npmjs.org/@types/prompts/-/prompts-2.0.13.tgz", + "integrity": "sha512-jwMOIGy49VruR/gYehhJYgpVzB+EVpEE7t7j9m1oTo4HMpOe7KmsyqdBuoxAzA5B4caUgx0cKrWr7wUEqMXJ7Q==", "requires": { "@types/node": "*" } @@ -12586,9 +12572,9 @@ } }, "consola": { - "version": "2.15.3", - "resolved": "https://registry.npmjs.org/consola/-/consola-2.15.3.tgz", - "integrity": "sha512-9vAdYbHj6x2fLKC4+oPH0kFzY/orMZyG2Aj+kNylHxKGJ/Ed4dpNyAQYwJOdqO4zdM7XpVHmyejQDcQHrnuXbw==" + "version": "2.15.0", + "resolved": "https://registry.npmjs.org/consola/-/consola-2.15.0.tgz", + "integrity": "sha512-vlcSGgdYS26mPf7qNi+dCisbhiyDnrN1zaRbw3CSuc2wGOMEGGPsp46PdRG5gqXwgtJfjxDkxRNAgRPr1B77vQ==" }, "console-control-strings": { "version": "1.1.0", @@ -15313,11 +15299,6 @@ "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==" }, - "lodash.groupby": { - "version": "4.6.0", - "resolved": "https://registry.npmjs.org/lodash.groupby/-/lodash.groupby-4.6.0.tgz", - "integrity": "sha1-Cwih3PaDl8OXhVwyOXg4Mt90A9E=" - }, "lodash.includes": { "version": "4.3.0", "resolved": "https://registry.npmjs.org/lodash.includes/-/lodash.includes-4.3.0.tgz", @@ -15353,11 +15334,6 @@ "resolved": "https://registry.npmjs.org/lodash.once/-/lodash.once-4.1.1.tgz", "integrity": "sha1-DdOXEhPHxW34gJd9UEyI+0cal6w=" }, - "lodash.uniqby": { - "version": "4.7.0", - "resolved": "https://registry.npmjs.org/lodash.uniqby/-/lodash.uniqby-4.7.0.tgz", - "integrity": "sha1-2ZwHpmnp5tJOE2Lf4mbGdhavEwI=" - }, "lowercase-keys": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/lowercase-keys/-/lowercase-keys-1.0.1.tgz", diff --git a/api/package.json b/api/package.json index d3b763f..6ee593b 100644 --- a/api/package.json +++ b/api/package.json @@ -46,7 +46,7 @@ "author": "4GL Ltd", "dependencies": { "@sasjs/core": "4.9.0", - "@sasjs/utils": "2.34.1", + "@sasjs/utils": "2.36.2", "bcryptjs": "^2.4.3", "cookie-parser": "^1.4.6", "cors": "^2.8.5", diff --git a/api/src/controllers/internal/deploy.ts b/api/src/controllers/internal/deploy.ts index 1c78d2f..662cea8 100644 --- a/api/src/controllers/internal/deploy.ts +++ b/api/src/controllers/internal/deploy.ts @@ -1,7 +1,7 @@ +import path from 'path' import { MemberType, FolderMember, ServiceMember, FileTree } from '../../types' import { getTmpFilesFolderPath } from '../../utils/file' import { createFolder, createFile, asyncForEach } from '@sasjs/utils' -import path from 'path' // REFACTOR: export FileTreeCpntroller export const createFileTree = async ( @@ -27,9 +27,13 @@ export const createFileTree = async ( (err) => Promise.reject({ error: err, failedToCreate: name }) ) } else { - await createFile(path.join(destinationPath, name), member.code).catch( - (err) => Promise.reject({ error: err, failedToCreate: name }) - ) + const encoding = member.type === MemberType.file ? 'base64' : undefined + + await createFile( + path.join(destinationPath, name), + member.code, + encoding + ).catch((err) => Promise.reject({ error: err, failedToCreate: name })) } }) diff --git a/api/src/routes/api/drive.ts b/api/src/routes/api/drive.ts index 881d884..ac56fe4 100644 --- a/api/src/routes/api/drive.ts +++ b/api/src/routes/api/drive.ts @@ -1,6 +1,8 @@ import express from 'express' import { deleteFile } from '@sasjs/utils' +import { publishAppStream } from '../appStream' + import { multerSingle } from '../../middlewares/multer' import { DriveController } from '../../controllers/' import { fileBodyValidation, fileParamValidation } from '../../utils' @@ -12,6 +14,12 @@ const driveRouter = express.Router() driveRouter.post('/deploy', async (req, res) => { try { const response = await controller.deploy(req.body) + + const data = req.body + const appLoc = data.appLoc ? data.appLoc.replace(/^\//, '').split('/') : [] + + publishAppStream(appLoc) + res.send(response) } catch (err: any) { const statusCode = err.code diff --git a/api/src/routes/appStream/index.ts b/api/src/routes/appStream/index.ts new file mode 100644 index 0000000..f502f82 --- /dev/null +++ b/api/src/routes/appStream/index.ts @@ -0,0 +1,22 @@ +import path from 'path' +import express from 'express' + +import { getTmpFilesFolderPath } from '../../utils' + +const router = express.Router() + +export const publishAppStream = (appLoc: string[]) => { + const appLocUrl = encodeURI(appLoc.join('/')) + const appLocPath = appLoc.join(path.sep) + + const pathToDeployment = path.join( + getTmpFilesFolderPath(), + appLocPath, + 'services', + 'webv' + ) + + router.use(`/${appLocUrl}`, express.static(pathToDeployment)) +} + +export default router diff --git a/api/src/routes/setupRoutes.ts b/api/src/routes/setupRoutes.ts index 02a6b61..b393ffc 100644 --- a/api/src/routes/setupRoutes.ts +++ b/api/src/routes/setupRoutes.ts @@ -2,8 +2,15 @@ import { Express } from 'express' import webRouter from './web' import apiRouter from './api' +import appStreamRouter from './appStream' export const setupRoutes = (app: Express) => { app.use('/', webRouter) app.use('/SASjsApi', apiRouter) + + app.use('/AppStream', function (req, res, next) { + // this needs to be a function to hook on + // whatever the current router is + appStreamRouter(req, res, next) + }) } diff --git a/api/src/types/FileTree.ts b/api/src/types/FileTree.ts index 2058736..940a68e 100644 --- a/api/src/types/FileTree.ts +++ b/api/src/types/FileTree.ts @@ -4,7 +4,8 @@ export interface FileTree { export enum MemberType { folder = 'folder', - service = 'service' + service = 'service', + file = 'file' } export interface FolderMember { @@ -15,7 +16,7 @@ export interface FolderMember { export interface ServiceMember { name: string - type: MemberType.service + type: MemberType.service | MemberType.file code: string } @@ -36,7 +37,9 @@ const isFolderMember = (arg: any): arg is FolderMember => Array.isArray(arg.members) && arg.members.filter( (member: FolderMember | ServiceMember) => - !isFolderMember(member) && !isServiceMember(member) + !isFolderMember(member) && + !isServiceMember(member) && + !isFileMember(member) ).length === 0 const isServiceMember = (arg: any): arg is ServiceMember => @@ -45,3 +48,10 @@ const isServiceMember = (arg: any): arg is ServiceMember => arg.type === MemberType.service && arg.code && typeof arg.code === 'string' + +const isFileMember = (arg: any): arg is ServiceMember => + arg && + typeof arg.name === 'string' && + arg.type === MemberType.file && + arg.code && + typeof arg.code === 'string'