├── .dockerignore ├── .eslintrc.js ├── .gitignore ├── @core-server ├── api-php │ ├── classes │ │ ├── ApiCreator.js │ │ └── MasterServer.js │ ├── cli │ │ └── phpbundle.js │ ├── package-plugin.json │ ├── php │ │ ├── GoogleAuthenticator.php │ │ ├── api.php │ │ ├── api_count_result.php │ │ ├── api_login.php │ │ ├── config.php │ │ ├── database.php │ │ ├── index.php │ │ ├── mysqli.php │ │ ├── remote_ip.php │ │ └── vars.php │ └── plugin.json ├── api │ ├── classes │ │ ├── ApiCreator.js │ │ ├── ApiEnvironment.js │ │ ├── Session.js │ │ ├── SessionsManager.js │ │ └── SiteManager.js │ ├── package.json │ ├── plugin.json │ └── wrappers │ │ ├── fs.js │ │ └── require.js ├── cli-utils │ ├── classes │ │ └── SSL.js │ ├── cli │ │ ├── disc.js │ │ ├── docs.js │ │ ├── gen-ssl-ca.js │ │ ├── gen-ssl.js │ │ ├── git.js │ │ ├── init.js │ │ └── vulnerabilities.js │ ├── modules-www │ │ └── template │ │ │ ├── error.vue │ │ │ ├── home.vue │ │ │ ├── init.js │ │ │ └── page.vue │ └── plugin.json ├── cli │ ├── bin │ │ ├── core-server-inspect.js │ │ └── core-server.js │ ├── lib │ │ ├── cli │ │ │ ├── help.js │ │ │ ├── index.js │ │ │ ├── install.js │ │ │ ├── prune.js │ │ │ └── version.js │ │ ├── index.js │ │ ├── logs │ │ │ └── index.js │ │ └── plugins │ │ │ ├── index.js │ │ │ └── require.js │ └── package.json ├── databases │ ├── classes │ │ ├── ApiEnvironment.js │ │ ├── Mongodb.js │ │ ├── Mysql.js │ │ └── SiteManager.js │ ├── cli │ │ └── cloudflare.js │ ├── package.json │ └── plugin.json ├── eslint │ ├── classes │ │ └── ApiCreator.js │ ├── package.json │ └── plugin.json ├── graphql │ ├── classes │ │ ├── ApiEnvironment.js │ │ ├── GraphDb.js │ │ ├── Session.js │ │ └── SiteManager.js │ ├── cli │ │ ├── check-indexes.js │ │ └── sync-schemas.js │ ├── lib │ │ ├── context.js │ │ ├── query.js │ │ ├── query_context.js │ │ ├── resolver.js │ │ └── typedeff.js │ ├── package.json │ └── plugin.json ├── http │ ├── classes │ │ ├── Crypter.js │ │ ├── Event.js │ │ ├── HttpServer.js │ │ ├── MasterServer.js │ │ ├── SiteManager.js │ │ └── Watcher.js │ ├── package.json │ └── plugin.json ├── kubeconfig │ ├── classes │ │ └── SiteManager.js │ ├── cli │ │ ├── decode-secrets.js │ │ └── publish-secrets.js │ ├── package.json │ └── plugin.json ├── mail │ ├── classes │ │ ├── ApiEnvironment.js │ │ └── Mailer.js │ ├── package.json │ └── plugin.json ├── network-tasks │ ├── classes │ │ ├── AirswarmTls.js │ │ ├── ApiEnvironment.js │ │ ├── Discovery.js │ │ ├── MasterServer.js │ │ ├── NetWorker.js │ │ ├── NetworkDiscovery.js │ │ ├── SiteManager.js │ │ └── TasksManager.js │ └── plugin.json ├── redis │ ├── classes │ │ ├── Redis.js │ │ ├── Session.js │ │ ├── SessionsManager.js │ │ └── SiteManager.js │ ├── package.json │ └── plugin.json ├── sentry │ ├── classes │ │ ├── ApiEnvironment.js │ │ ├── GraphDb.js │ │ ├── Session.js │ │ └── SiteManager.js │ ├── package.json │ └── plugin.json ├── tests │ ├── classes │ │ ├── Environment.js │ │ └── SiteManager.js │ └── plugin.json └── vue │ ├── additionals │ ├── bulkify-watch.js │ ├── bulkify.js │ ├── snapshotRequire.js │ ├── vue-server-renderer │ │ ├── build-copy.js │ │ ├── build.js │ │ ├── custom │ │ │ ├── TemplateRenderer.js │ │ │ ├── index.js │ │ │ └── utils.js │ │ ├── index.js │ │ ├── meta.js │ │ └── package.json │ └── watchify-cache.js │ ├── classes │ ├── MasterServer.js │ ├── PagesManager.js │ ├── RenderCache.js │ ├── Resources │ │ ├── CacheObject.js │ │ ├── CacheStream.js │ │ └── Manager.js │ ├── Session.js │ ├── SiteManager.js │ └── hmr │ │ ├── has.js │ │ ├── hmr-manager-template.js │ │ ├── index.js │ │ ├── socket-server.js │ │ └── str-set.js │ ├── cli │ ├── build.js │ └── bundle.js │ ├── modules-www │ ├── client │ │ ├── apiManager.js │ │ ├── entry.js │ │ ├── formPoster-jquery.js │ │ └── formPoster-vue.js │ ├── common │ │ ├── apiManager.js │ │ ├── init.js │ │ ├── merger.js │ │ ├── pageProperties.js │ │ ├── permissions.js │ │ ├── sha1.js │ │ └── storage.js │ ├── server │ │ ├── apiManager.js │ │ └── entry.js │ └── template.html │ ├── package.json │ ├── plugin.json │ ├── vueify │ ├── LICENSE │ ├── README.md │ ├── circle.yml │ ├── index.js │ ├── lib │ │ ├── compiler.js │ │ ├── compilers │ │ │ ├── babel.js │ │ │ ├── coffee.js │ │ │ ├── index.js │ │ │ ├── jade.js │ │ │ ├── less.js │ │ │ ├── pug.js │ │ │ ├── sass.js │ │ │ └── stylus.js │ │ ├── ensure-require.js │ │ ├── gen-id.js │ │ ├── insert-css.js │ │ ├── normalize.js │ │ ├── style-rewriter.js │ │ └── template-compiler.js │ ├── plugins │ │ └── extract-css.js │ └── test │ │ ├── fixtures │ │ ├── basic.vue │ │ ├── media-query.vue │ │ ├── postcss.vue │ │ ├── pre-processors.vue │ │ ├── pug.vue │ │ ├── scoped-css.vue │ │ ├── script-import.js │ │ ├── script-import.vue │ │ ├── style-export.vue │ │ ├── style-import-scoped.css │ │ ├── style-import.css │ │ ├── style-import.vue │ │ ├── template-import.jade │ │ └── template-import.vue │ │ └── test.js │ └── wrappers │ └── resource_url.js ├── CHANGELOG.md ├── CODE_OF_CONDUCT.md ├── CONTRIBUTING.md ├── DEVELOPMENT.md ├── LICENSE ├── README.md ├── _config.yml ├── deploy ├── install.sh ├── vue-au-graphql-loader ├── composables │ └── index.js ├── nuxt.js ├── package.json └── src │ ├── document.js │ ├── fragments.js │ ├── index.js │ ├── mutations.js │ ├── query.js │ └── test.js └── wiki └── img └── logo ├── logo-128.png └── logo-256.png /.dockerignore: -------------------------------------------------------------------------------- 1 | node_modules/ 2 | core-docs/ 3 | dist/ 4 | package-lock.json 5 | .DS_Store 6 | .vscode -------------------------------------------------------------------------------- /.eslintrc.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | // parser: "@babel/eslint-parser", 3 | globals: { 4 | session: true, 5 | post: true, 6 | SuperClass: true, 7 | plugins: true, 8 | }, 9 | env: { 10 | node: true, 11 | es2021: true, 12 | }, 13 | parserOptions: { 14 | // sourceType: 'module', 15 | // ecmaVersion: 'latest', 16 | ecmaVersion: 2017, 17 | ecmaFeatures: { 18 | globalReturn: true 19 | } 20 | 21 | }, 22 | extends: [ 23 | 'eslint:recommended', 24 | ], 25 | rules: { 26 | "spaced-comment": ["error", "always", { "exceptions": ["-", "+"] }], 27 | "indent": ["error", 4], 28 | "no-empty": ["error", { "allowEmptyCatch": true }], 29 | "no-redeclare": "off", 30 | "no-inner-declarations": "off", 31 | "no-unused-vars": ["error", { "vars": "all", "args": "after-used", "ignoreRestSiblings": true, "varsIgnorePattern": "React" }], 32 | "brace-style": ["error", "1tbs", { }], 33 | "object-curly-spacing": ["error", "always"], 34 | "nonblock-statement-body-position": ["error", "below"], 35 | "array-bracket-spacing": ["error", "never"], 36 | "space-before-blocks": ["error", "always"], 37 | "arrow-spacing": ["error", { "before": true, "after": true }], 38 | "no-multi-spaces": ["error", { ignoreEOLComments: true }], 39 | "key-spacing": ["error", { "beforeColon": false, "align": "value" }], 40 | "semi": ["error", "never"], 41 | "padding-line-between-statements": [ 42 | "error", 43 | { "blankLine": "always", "prev": "if", "next": "*" }, 44 | { "blankLine": "always", "prev": "switch", "next": "*" }, 45 | { "blankLine": "always", "prev": "*", "next": "switch" }, 46 | { "blankLine": "never", "prev": "*", "next": "block" }, 47 | ], 48 | }, 49 | } -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules/ 2 | core-docs/ 3 | dist/ 4 | package-lock.json 5 | .DS_Store 6 | .vscode -------------------------------------------------------------------------------- /@core-server/api-php/classes/ApiCreator.js: -------------------------------------------------------------------------------- 1 | var runner = require("child_process") 2 | var Path = require('path') 3 | var fs = require('fs') 4 | 5 | function tryParseJson(msg) { 6 | try { 7 | return JSON.parse(msg) 8 | } catch(e) { 9 | 10 | } 11 | 12 | return msg 13 | } 14 | 15 | 16 | class ApiCreator extends SuperClass { 17 | 18 | create(path, name) { 19 | const handler = this.createPhpHandler(path + '.php', name) 20 | 21 | if (handler != false) 22 | return { handler: handler, path: path + '.php' } 23 | 24 | return super.create(path, name) 25 | } 26 | 27 | createPhpHandler(path, name) { 28 | if(!fs.existsSync(path)) 29 | return false 30 | 31 | return async function() { 32 | const _this = this 33 | 34 | var cmd = "php '" + Path.join(process.cwd(), 'plugins', 'phpcore.php') + "'" 35 | 36 | if(process.platform.toString().toLowerCase().indexOf('win32') > -1) { 37 | cmd = "php " + Path.join(process.cwd(), 'plugins', 'phpcore.php') 38 | } 39 | 40 | const Run = new Promise(function(resolve, reject) { 41 | 42 | runner.exec(cmd, 43 | { 44 | env: 45 | { 46 | post: JSON.stringify(_this.post), 47 | session: JSON.stringify(_this.session), 48 | cookie: JSON.stringify(_this.cookie), 49 | client_ip: _this.client_ip, 50 | actions_path: Path.join(process.cwd(), 'api'), 51 | api_exec: Path.normalize(path) 52 | } 53 | }, 54 | function(err, phpResponse, stderr) { 55 | if(err) { 56 | reject(tryParseJson(stderr ? stderr : phpResponse)) 57 | } else { 58 | var json = tryParseJson(phpResponse) 59 | if(json['__core__[mails]__']) { 60 | var mails = json['__core__[mails]__'] 61 | 62 | for(var key in mails) { 63 | var mail = mails[key] 64 | var vars = mail['vars'] 65 | that.mail(vars['user_id'], vars['dest_mail'], mail['layout'], vars) 66 | } 67 | 68 | delete json['__core__[mails]__'] 69 | } 70 | 71 | resolve(json) 72 | } 73 | }) 74 | 75 | }) 76 | 77 | return await Run 78 | } 79 | } 80 | } 81 | 82 | module.exports = ApiCreator -------------------------------------------------------------------------------- /@core-server/api-php/classes/MasterServer.js: -------------------------------------------------------------------------------- 1 | const cluster = require('cluster') 2 | 3 | if(cluster.isWorker) { 4 | module.exports = SuperClass 5 | return 6 | } 7 | 8 | var BundleStarted = false 9 | 10 | class MasterServer extends SuperClass { 11 | 12 | constructor(config) { 13 | super(config) 14 | 15 | console.log('PHP Support enabled') 16 | this.startPhpBundler() 17 | } 18 | 19 | startPhpBundler() { 20 | if(BundleStarted) 21 | return 22 | 23 | this.phpWorker = new SuperClass.Worker({ 24 | cli: JSON.stringify({ 25 | phpbundle: true, 26 | hot: true 27 | }), 28 | NODE_ENV: process.env.NODE_ENV 29 | }) 30 | } 31 | 32 | } 33 | 34 | module.exports = MasterServer -------------------------------------------------------------------------------- /@core-server/api-php/cli/phpbundle.js: -------------------------------------------------------------------------------- 1 | const chalk = require('chalk') 2 | const fs = require('fs') 3 | const Path = require('path') 4 | const decomment = require('decomment') 5 | const collapse = require('condense-whitespace') 6 | const subConsole = console.create('PHP') 7 | 8 | const phpPath = Path.join(process.cwd(), 'plugins', 'phpcore.php') 9 | 10 | function ensureExists(path, mask, cb) { 11 | const fs = require('fs') 12 | 13 | fs.mkdir(path, mask, function(err) { 14 | if (err) { 15 | if (err.code == 'EEXIST') 16 | cb(null) // ignore the error if the folder already exists 17 | else 18 | cb(err) // something else went wrong 19 | } else 20 | cb(null) // successfully created folder 21 | }) 22 | } 23 | 24 | function bundlePhp(folder) { 25 | var files 26 | 27 | try { 28 | files = fs.readdirSync(folder) 29 | } catch (e) { 30 | return false 31 | } 32 | 33 | var nindex = '' 34 | var ncontent = '' 35 | 36 | for (var key in files) { 37 | if (Path.extname(files[key]) !== '.php') 38 | continue 39 | 40 | try { 41 | const content = fs.readFileSync(Path.join(folder, files[key])).toString() 42 | const index = content.indexOf(' "action not found"); 70 | } 71 | 72 | //----------------------------------------------------------- 73 | //Run PHP action 74 | 75 | global $_RESULT; 76 | $_RESULT = array(); 77 | $old_post = $_POST; 78 | $_POST = $vars; 79 | 80 | include($ppath); 81 | 82 | global $_RESULT; 83 | $_POST = $old_post; 84 | 85 | global $active_db; 86 | $active_db = $old_db; 87 | return $_RESULT; 88 | } 89 | 90 | function api_result($res) 91 | { 92 | global $_RESULT; 93 | 94 | if(!is_array($res) && !is_object($res)) 95 | { 96 | $res = array("result" => $res); 97 | } 98 | 99 | $_RESULT = $res; 100 | } 101 | 102 | function api_error($res) 103 | { 104 | global $_RESULT; 105 | $_RESULT = array("error" => $res); 106 | } 107 | 108 | function api_query($sql, $vars = null, $db_type = null) 109 | { 110 | if(!check_connection()) 111 | { 112 | global $_RESULT; 113 | return $_RESULT; 114 | } 115 | 116 | if($vars == null) 117 | { 118 | $vars = $_POST; 119 | } 120 | 121 | $query = query($sql, $vars, $db_type); 122 | $result = array(); 123 | 124 | while(($row = $query->fetchObject())) 125 | { 126 | $result[] = $row; 127 | } 128 | 129 | $db = db($db_type); 130 | if(count($result) == 0 && db_has_error()) 131 | { 132 | global $_RESULT; 133 | return $_RESULT; 134 | } 135 | else if(count($result) == 0) 136 | { 137 | if(($id = $db->insert_id())) 138 | { 139 | $result["id"] = $id; 140 | } 141 | } 142 | 143 | api_result($result); 144 | return $result; 145 | } -------------------------------------------------------------------------------- /@core-server/api-php/php/api_count_result.php: -------------------------------------------------------------------------------- 1 | insert_id(); 27 | return $res; 28 | } -------------------------------------------------------------------------------- /@core-server/api-php/php/api_login.php: -------------------------------------------------------------------------------- 1 | 0) 44 | $result['__core__[mails]__'] = $mailSends; 45 | 46 | print json_encode($result); -------------------------------------------------------------------------------- /@core-server/api-php/php/remote_ip.php: -------------------------------------------------------------------------------- 1 | $server, 'name' => $name, 'vars' => json_encode($vars), 'user_id' => $user_id, 'description' => $description)); 16 | } 17 | 18 | function remote_api($server, $name, $vars = null, $with_token = true, $retry = true, $post = true) 19 | { 20 | $url = 'https://'.$server.'/'.$name; 21 | 22 | if(is_null($vars)) 23 | { 24 | $vars = $_POST; 25 | } 26 | if(!is_array($vars)) 27 | { 28 | $vars = (array) $vars; 29 | } 30 | if($with_token) 31 | { 32 | $vars['token'] = remote_token(); 33 | } 34 | 35 | 36 | $params = array('http' => array( 37 | 'method' => 'POST', 38 | 'content' => http_build_query($vars) 39 | )); 40 | 41 | $ctx = stream_context_create($params); 42 | $fp = @fopen($url, 'rb', false, $ctx); 43 | if (!$fp) { 44 | return array('error' => "Unable to contact server"); 45 | } 46 | $response = @stream_get_contents($fp); 47 | if ($response === false) { 48 | return array('error' => "Unable to contact server"); 49 | } 50 | 51 | /* $ch = curl_init($url); 52 | 53 | curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, 0); 54 | curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, 0); 55 | curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); 56 | print_r(curl_getinfo($ch)); 57 | if($post) 58 | { 59 | curl_setopt($ch,CURLOPT_POST, count($vars)); 60 | curl_setopt($ch,CURLOPT_POSTFIELDS, http_build_query($vars)); 61 | } 62 | 63 | $response = curl_exec($ch);*/ 64 | 65 | $content = json_decode($response); 66 | 67 | if(is_array($content) || is_object($content)) 68 | { 69 | $content = (array)$content; 70 | if($retry && isset($content['error'])) 71 | { 72 | if(is_string($content['error'])) 73 | if(substr($content['error'], 0, 16) == 'Wrong token send') 74 | { 75 | return remote_api($server, $name, $vars, true, false); 76 | } 77 | 78 | return array('error' => $content['error']); 79 | } 80 | else if(isset($content['error']) && $with_token) 81 | { 82 | if(substr($content['error'], 0, 16) == 'Wrong token send') 83 | log_remote_api_fail($server, $name, $vars, $content['error']); 84 | } 85 | 86 | return $content; 87 | } 88 | 89 | if(is_null($content) && $with_token) 90 | { 91 | log_remote_api_fail($server, $name, $vars, 'Server unreachable: '.$response); 92 | } 93 | 94 | return array('error' => $response); 95 | } 96 | 97 | 98 | //------------------------------------------------------------------------------------------------ 99 | 100 | global $mailSends; 101 | $mailSends = []; 102 | 103 | function auto_mail($layout, $vars, $priority = false) 104 | { 105 | global $mailSends; 106 | 107 | if(!isset($vars['dest_mail'])) 108 | { 109 | return array('error' => 'dest_mail not found'); 110 | } 111 | if(!isset($vars['user_id']) && !connected()) 112 | { 113 | return array('error' => 'user_id not found and user not connected'); 114 | } 115 | 116 | $vars['name'] = isset($vars['name']) ? $vars['name'] : null; 117 | $vars['user_id'] = isset($vars['user_id']) ? $vars['user_id'] : auth_id(); 118 | 119 | $mailSends[] = [ 120 | 'layout' => $layout, 121 | 'vars' => $vars 122 | ]; 123 | 124 | return true; 125 | } 126 | -------------------------------------------------------------------------------- /@core-server/api-php/plugin.json: -------------------------------------------------------------------------------- 1 | { 2 | "classes": { 3 | "ApiCreator": "api/ApiCreator", 4 | "MasterServer": "http/MasterServer" 5 | }, 6 | 7 | "cli": { 8 | "phpbundle": "Generate a bundled script of the php core" 9 | } 10 | } -------------------------------------------------------------------------------- /@core-server/api/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@core-server/api", 3 | "version": "1.2.5", 4 | "private": false, 5 | "description": "", 6 | "main": "index.js", 7 | "scripts": { 8 | "test": "echo \"Error: no test specified\" && exit 1" 9 | }, 10 | "author": "Vandamme Sacha (https://www.skyhark.be)", 11 | "license": "MIT", 12 | "dependencies": { 13 | "minimatch": "^3.0.4", 14 | "request-promise-native": "^1.0.7", 15 | "uniqid": "^5.0.3" 16 | }, 17 | "engines": { 18 | "node": ">=7.0.0" 19 | }, 20 | "repository": { 21 | "type": "git", 22 | "url": "git+https://github.com/SachaSkyhark/Core-Server.git" 23 | }, 24 | "keywords": [ 25 | "Core-Server", 26 | "Vue", 27 | "Server", 28 | "api" 29 | ], 30 | "bugs": { 31 | "url": "https://github.com/SachaSkyhark/Core-Server/issues" 32 | }, 33 | "homepage": "https://www.core-server.io" 34 | } 35 | -------------------------------------------------------------------------------- /@core-server/api/plugin.json: -------------------------------------------------------------------------------- 1 | { 2 | "classes": { 3 | "SiteManager": "http/SiteManager", 4 | "SessionsManager": null, 5 | "Session": null, 6 | "ApiEnvironment": null, 7 | "ApiCreator": null 8 | } 9 | } -------------------------------------------------------------------------------- /@core-server/api/wrappers/require.js: -------------------------------------------------------------------------------- 1 | const fsWrapper = require('./fs.js') 2 | const Path = require('path') 3 | 4 | module.exports = function(dir, name) { 5 | if (name.toLowerCase() === 'fs') 6 | return fsWrapper 7 | 8 | var path 9 | try { 10 | return require(name) 11 | } catch(e) { 12 | if(e.code !== 'MODULE_NOT_FOUND') { 13 | throw(e) 14 | } 15 | 16 | path = Path.resolve(Path.join(process.cwd(), 'node_modules'), name) 17 | if(path === name) { 18 | throw(e) 19 | } 20 | } 21 | 22 | try { 23 | return require(path) 24 | } catch(e) { 25 | if(e.code !== 'MODULE_NOT_FOUND') { 26 | throw(e) 27 | } 28 | } 29 | 30 | path = Path.resolve(dir, name) 31 | return require(path) 32 | } -------------------------------------------------------------------------------- /@core-server/cli-utils/cli/disc.js: -------------------------------------------------------------------------------- 1 | const disc = require('disc') 2 | const cluster = require('cluster') 3 | const chalk = require('chalk') 4 | const fs = require('fs') 5 | const subConsole = console.create('DISC') 6 | const Path = require('path') 7 | 8 | const PagesManager = plugins.require('vue/PagesManager') 9 | 10 | module.exports = function(value) { 11 | if(value === undefined || value === null) 12 | value = 'client' 13 | 14 | if (['client', 'server'].indexOf(value) === -1) { 15 | subConsole.error('Wrong bundle type given', value) 16 | return false 17 | } 18 | 19 | if (cluster.isMaster) 20 | subConsole.info('Disc environment:', chalk.bold(process.env.NODE_ENV + '-' + value)) 21 | 22 | var serverStart = Date.now() 23 | 24 | PagesManager.compile(value, function() { 25 | subConsole.info(value.substr(0,1).toUpperCase() + value.substr(1), 'bundle done (' + (Date.now() - serverStart) + ' ms)') 26 | 27 | subConsole.log('Exporting bundle disc..') 28 | 29 | disc.bundle(fs.readFileSync(Path.join(process.cwd(), 'dist', 'bundle-'+value+'.js')), 30 | { 31 | mode: 'size' 32 | }, function(err, html) { 33 | if (err) 34 | throw err 35 | 36 | fs.writeFileSync(Path.join(process.cwd(), 'dist', 'disc.html'), html) 37 | console.log('Disc.html added to the dist folder') 38 | }) 39 | }) 40 | .on('bundle', function() { 41 | serverStart = Date.now() 42 | }) 43 | 44 | return false 45 | } -------------------------------------------------------------------------------- /@core-server/cli-utils/cli/docs.js: -------------------------------------------------------------------------------- 1 | const Path = require('path') 2 | const fs = require('fs') 3 | 4 | function getScripts() { 5 | var scripts = [] 6 | 7 | for(var path in plugins.loadedPlugins) { 8 | const plugin = plugins.loadedPlugins[path] 9 | 10 | if(!plugin.classes) 11 | continue 12 | 13 | for(var name in plugin.classes) 14 | scripts.push( Path.join(path, 'classes', name + '.js') ) 15 | } 16 | 17 | return scripts 18 | } 19 | 20 | module.exports = function(value) { 21 | const scripts = getScripts() 22 | 23 | const spawn = require('child_process').spawn 24 | const output = Path.join(process.cwd(), value || 'docs') 25 | 26 | const tmpPath1 = Path.join(process.pwd(), 'node_modules', 'ink-docstrap', 'template') 27 | const templatePath = fs.existsSync(tmpPath1) ? tmpPath1 : Path.join(__dirname, '..', 'node_modules', 'ink-docstrap', 'template') 28 | const ls = spawn('jsdoc', scripts.concat(['-t', templatePath, '-d', output])) 29 | 30 | console.log('Generating docs to', output) 31 | 32 | ls.stdout.on('data', (data) => { 33 | console.log(data.toString()) 34 | }) 35 | 36 | ls.stderr.on('data', (data) => { 37 | console.error(data.toString()) 38 | }) 39 | 40 | return false 41 | } -------------------------------------------------------------------------------- /@core-server/cli-utils/cli/gen-ssl-ca.js: -------------------------------------------------------------------------------- 1 | const forge = require('node-forge') 2 | const pki = forge.pki 3 | const Path = require('path') 4 | const fs = require('fs') 5 | 6 | function generateKey(attrs, issuer) { 7 | const keys = pki.rsa.generateKeyPair(2048) 8 | const cert = pki.createCertificate() 9 | cert.publicKey = keys.publicKey 10 | cert.serialNumber = '01' 11 | cert.validity.notBefore = new Date() 12 | cert.validity.notAfter = new Date() 13 | cert.validity.notAfter.setFullYear(cert.validity.notBefore.getFullYear() + 15) 14 | 15 | if(!issuer) 16 | issuer = attrs 17 | 18 | cert.setSubject(attrs) 19 | cert.setIssuer(issuer) 20 | 21 | //------------------------------------------------------------------------------------- 22 | 23 | cert.setExtensions([ 24 | { 25 | name: 'basicConstraints', 26 | cA: true 27 | }, 28 | { 29 | name: 'keyUsage', 30 | keyCertSign: true, 31 | digitalSignature: true, 32 | nonRepudiation: true, 33 | keyEncipherment: true, 34 | dataEncipherment: true 35 | }, 36 | { 37 | name: 'extKeyUsage', 38 | serverAuth: true, 39 | clientAuth: true, 40 | codeSigning: true, 41 | emailProtection: true, 42 | timeStamping: true 43 | }, 44 | { 45 | name: 'nsCertType', 46 | client: true, 47 | server: true, 48 | email: true, 49 | objsign: true, 50 | sslCA: true, 51 | emailCA: true, 52 | objCA: true 53 | }, 54 | { 55 | name: 'subjectKeyIdentifier' 56 | } 57 | ]) 58 | 59 | cert.sign(keys.privateKey) 60 | 61 | return { 62 | cert: pki.certificateToPem(cert), 63 | key: pki.privateKeyToPem(keys.privateKey) 64 | } 65 | } 66 | 67 | function mkdir(path) { 68 | return new Promise(function(resolve) { 69 | fs.mkdir(path, function(err) { 70 | if (err) { 71 | if (err.code == 'EEXIST') 72 | resolve() 73 | else 74 | reject(err) 75 | } else 76 | resolve() 77 | }) 78 | }) 79 | } 80 | 81 | module.exports = function(value) { 82 | value = value || ('core-server.' + Math.random()) 83 | console.log('Generating ca with commonName', value) 84 | 85 | const info = [ 86 | { 87 | name: 'commonName', 88 | value: value 89 | }, 90 | { 91 | name: 'countryName', 92 | value: 'CS' 93 | }, 94 | { 95 | shortName: 'ST', 96 | value: 'Core-Server' 97 | }, 98 | { 99 | name: 'localityName', 100 | value: 'Internal CA' 101 | }, 102 | { 103 | name: 'organizationName', 104 | value: 'Core-Server SSL' 105 | } 106 | ] 107 | 108 | const pem = generateKey(info) 109 | 110 | console.log('CA certificate generated') 111 | 112 | mkdir(Path.join(process.cwd(), 'ssl')).then(function() { 113 | fs.writeFileSync(Path.join(process.cwd(), 'ssl', 'ca.pem'), pem.cert) 114 | fs.writeFileSync(Path.join(process.cwd(), 'ssl', 'ca-key.pem'), pem.key) 115 | }) 116 | .catch(function(err) { 117 | console.error(err) 118 | }) 119 | 120 | return false 121 | } -------------------------------------------------------------------------------- /@core-server/cli-utils/cli/gen-ssl.js: -------------------------------------------------------------------------------- 1 | const forge = require('node-forge') 2 | const fs = require('fs') 3 | const Path = require('path') 4 | const pki = forge.pki 5 | 6 | function mkdir(path) { 7 | return new Promise(function(resolve) { 8 | fs.mkdir(path, function(err) { 9 | if (err) { 10 | if (err.code == 'EEXIST') 11 | resolve() 12 | else 13 | reject(err) 14 | } else 15 | resolve() 16 | }) 17 | }) 18 | } 19 | 20 | function generateKey(attrs, issuer) { 21 | const keys = pki.rsa.generateKeyPair(2048) 22 | const cert = pki.createCertificate() 23 | cert.publicKey = keys.publicKey 24 | cert.serialNumber = '01' 25 | cert.validity.notBefore = new Date() 26 | cert.validity.notAfter = new Date() 27 | cert.validity.notAfter.setFullYear(cert.validity.notBefore.getFullYear() + 15) 28 | 29 | if(!issuer) 30 | issuer = attrs 31 | 32 | cert.setSubject(attrs) 33 | cert.setIssuer(issuer) 34 | 35 | //------------------------------------------------------------------------------------- 36 | 37 | cert.setExtensions([ 38 | { 39 | name: 'basicConstraints', 40 | cA: true 41 | }, 42 | { 43 | name: 'keyUsage', 44 | keyCertSign: true, 45 | digitalSignature: true, 46 | nonRepudiation: true, 47 | keyEncipherment: true, 48 | dataEncipherment: true 49 | }, 50 | { 51 | name: 'extKeyUsage', 52 | serverAuth: true, 53 | clientAuth: true, 54 | codeSigning: true, 55 | emailProtection: true, 56 | timeStamping: true 57 | }, 58 | { 59 | name: 'nsCertType', 60 | client: true, 61 | server: true, 62 | email: true, 63 | objsign: true, 64 | sslCA: true, 65 | emailCA: true, 66 | objCA: true 67 | }/* , 68 | { 69 | name: 'subjectAltName', 70 | altNames: [ 71 | { 72 | type: 6, // URI 73 | value: 'https://www.elixir.io' 74 | }, 75 | { 76 | type: 7, // IP 77 | ip: '127.0.0.1' 78 | } 79 | ] 80 | }*/, 81 | { 82 | name: 'subjectKeyIdentifier' 83 | } 84 | ]) 85 | 86 | cert.sign(pki.privateKeyFromPem( 87 | fs.readFileSync(Path.join(process.cwd(), 'ssl', 'ca-key.pem')) 88 | )) 89 | 90 | return { 91 | cert: pki.certificateToPem(cert), 92 | key: pki.privateKeyToPem(keys.privateKey) 93 | } 94 | } 95 | 96 | 97 | module.exports = function(value) { 98 | value = value || ('core-server.' + Math.random()) 99 | console.log('Generating ca with commonName', value) 100 | 101 | const info = [ 102 | { 103 | name: 'commonName', 104 | value: value 105 | }, 106 | { 107 | name: 'countryName', 108 | value: 'CS' 109 | }, 110 | { 111 | shortName: 'ST', 112 | value: 'Core-Server' 113 | }, 114 | { 115 | name: 'localityName', 116 | value: 'Internal CA' 117 | }, 118 | { 119 | name: 'organizationName', 120 | value: 'Core-Server SSL' 121 | } 122 | ] 123 | 124 | const pem = generateKey(info) 125 | console.log('Ca certificates generated') 126 | 127 | mkdir(Path.join(process.cwd(), 'ssl')).then(function() { 128 | fs.writeFileSync(Path.join(process.cwd(), 'ssl', 'cert.pem'), pem.cert) 129 | fs.writeFileSync(Path.join(process.cwd(), 'ssl', 'cert-key.pem'), pem.key) 130 | }) 131 | .catch(function(err) { 132 | console.error(err) 133 | }) 134 | 135 | 136 | return false 137 | 138 | } -------------------------------------------------------------------------------- /@core-server/cli-utils/cli/git.js: -------------------------------------------------------------------------------- 1 | const GitStats = require("git-stats") 2 | const child = require('child_process') 3 | const Path = require('path') 4 | const Table = require('cli-table') 5 | 6 | function spawnLog(cmd) { 7 | child.exec(cmd, { cwd: process.cwd() }, function(error, stdout, stderr) { 8 | if (error) { 9 | console.error(error) 10 | return 11 | } 12 | 13 | console.log(stdout) 14 | }) 15 | } 16 | 17 | function exec(cmd, arg) { 18 | return child.execSync(cmd, { cwd: process.cwd() }).toString() 19 | } 20 | 21 | function onlyUnique(value, index, self) { 22 | return self.indexOf(value) === index 23 | } 24 | 25 | function getAuthorStats(name) { 26 | const statsTable = exec("git log --author=\""+name+"\" --since=2016-01-01 --pretty=tformat: --numstat").split("\n") 27 | const stats = [] 28 | var adds = 0 29 | var removes = 0 30 | var extensions = [] 31 | 32 | for(var key in statsTable) { 33 | statsTable[key] = statsTable[key].split("\t") 34 | const statsKey = statsTable[key] 35 | 36 | if(statsKey.length < 3) 37 | continue 38 | 39 | if(statsKey[2].indexOf("}") !== -1) 40 | statsKey[2] = statsKey[2].substr(0, statsKey[2].indexOf("}")) 41 | 42 | if(statsKey[2].indexOf("?") !== -1) 43 | statsKey[2] = statsKey[2].substr(0, statsKey[2].indexOf("?")) 44 | 45 | const ext = Path.extname(statsKey[2]) 46 | if(['', '.png', '.jpg', '.gif', '.eot', '.svg', '.ttf', '.woff', '.woff2', '.log', '.pem', '.crt', '.csr', '.otf', '.txt'].indexOf(ext) !== -1) 47 | continue 48 | 49 | const add = parseInt(statsKey[0]) 50 | if (!isNaN(add)) 51 | adds += add 52 | 53 | const rm = parseInt(statsKey[1]) 54 | if (!isNaN(rm)) 55 | removes += rm 56 | 57 | extensions.push(ext) 58 | } 59 | 60 | extensions = extensions.filter(onlyUnique) 61 | return { 62 | author: name, 63 | adds: adds, 64 | removes: removes, 65 | total: adds-removes, 66 | extensions: extensions.join('\n') 67 | } 68 | } 69 | 70 | function getAuthors() { 71 | return exec("git log --format='%aN' | sort -u").split("\n") 72 | } 73 | 74 | function getAuthorCommits() { 75 | const result = [] 76 | const authors = getAuthors() 77 | 78 | for(var key in authors) { 79 | if(authors[key] !== "") 80 | result.push( getAuthorStats(authors[key]) ) 81 | } 82 | 83 | return result 84 | } 85 | 86 | module.exports = function(gitShow) { 87 | const g1 = new GitStats() 88 | 89 | if (!gitShow || gitShow === 'calendar') { 90 | g1.ansiCalendar({ 91 | theme: "LIGHT" 92 | }, function (err, data) { 93 | console.log(err || data) 94 | }) 95 | } 96 | 97 | if (!gitShow || gitShow === 'authors') { 98 | g1.authorsPie({ 99 | repo: process.cwd(), 100 | start: '2016-01-01', 101 | end: '2020-01-01', 102 | radius: 10 103 | }, function (err, data) { 104 | console.log(err || data) 105 | }) 106 | 107 | //---------------------------------------- 108 | 109 | const table = new Table({ 110 | head: ['Name', 'New lines', 'Deleted lines', "Total lines", "Extensions"], 111 | colWidths: [50, 30, 30, 30, 50] 112 | }) 113 | 114 | const subStats = getAuthorCommits() 115 | for(var key in subStats) 116 | table.push([subStats[key].author, subStats[key].adds, subStats[key].removes, subStats[key].total, subStats[key].extensions]) 117 | 118 | console.log(table.toString()) 119 | } 120 | 121 | if(gitShow === 'authors-list') { 122 | console.log(getAuthors().join("\n")) 123 | } 124 | 125 | return false 126 | } -------------------------------------------------------------------------------- /@core-server/cli-utils/modules-www/template/error.vue: -------------------------------------------------------------------------------- 1 | 14 | 15 | -------------------------------------------------------------------------------- /@core-server/cli-utils/modules-www/template/home.vue: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /@core-server/cli-utils/modules-www/template/init.js: -------------------------------------------------------------------------------- 1 | //import store from './store'; 2 | import app from '../../menu/page.vue'; 3 | 4 | const bulk = require('bulk-require'); 5 | const vue_templates = bulk(__dirname + "/../../components/", ['**/*.vue']); 6 | 7 | export function initComponents( register ) 8 | { 9 | var folder = null; 10 | 11 | for(var x in vue_templates) 12 | { 13 | if(typeof(vue_templates[x]) === 'object') 14 | { 15 | folder = vue_templates[x]; 16 | 17 | for(var key in folder) 18 | { 19 | var name = (x + "-" + key).replace('/', '-'); 20 | register(name, folder[key]); 21 | } 22 | } 23 | } 24 | } 25 | /* 26 | export function getRavenKey() 27 | { 28 | return '...'; 29 | } 30 | */ 31 | export function getApp() 32 | { 33 | /*return Vue.util.extend({ 34 | store: store 35 | }, app);*/ 36 | 37 | return app; 38 | } 39 | 40 | export function getDefaultPost() 41 | { 42 | return { } 43 | } 44 | 45 | export function setupEnvironment( apiManager, isClient ) 46 | { 47 | //... 48 | } -------------------------------------------------------------------------------- /@core-server/cli-utils/modules-www/template/page.vue: -------------------------------------------------------------------------------- 1 | 6 | 7 | -------------------------------------------------------------------------------- /@core-server/cli-utils/plugin.json: -------------------------------------------------------------------------------- 1 | { 2 | "classes": { 3 | "SSL": null 4 | }, 5 | 6 | "cli": { 7 | "disc": "Generate a disc overview of the js bundle size", 8 | "docs": "Generate the core-server documentations", 9 | "gen-ssl-ca": "Generate a root certificate authority", 10 | "gen-ssl": "Generate ssl certificates for your server", 11 | "init": "Create a new project", 12 | "vulnerabilities": "Generate a report of your dependencies vulnerabilities", 13 | "git": "Show git stats" 14 | } 15 | } -------------------------------------------------------------------------------- /@core-server/cli/bin/core-server-inspect.js: -------------------------------------------------------------------------------- 1 | #!/usr/local/bin/node --inspect=0.0.0.0:9229 2 | 3 | const lib = require('../lib/index.js') 4 | const console = lib.logs.create('CLI') 5 | 6 | lib.plugins.loadConfig() 7 | 8 | lib.plugins.executeCLI().then(function(execute) { 9 | 10 | if(execute) 11 | plugins.createEntries() 12 | 13 | }).catch(function(err) { 14 | 15 | console.error(err) 16 | 17 | }) -------------------------------------------------------------------------------- /@core-server/cli/bin/core-server.js: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | 3 | const lib = require('../lib/index.js') 4 | const console = lib.logs.create('CLI') 5 | 6 | lib.plugins.loadConfig() 7 | 8 | lib.plugins.executeCLI().then(function(execute) { 9 | 10 | if(execute) 11 | plugins.createEntries() 12 | 13 | }).catch(function(err) { 14 | 15 | console.error(err) 16 | 17 | }) -------------------------------------------------------------------------------- /@core-server/cli/lib/cli/help.js: -------------------------------------------------------------------------------- 1 | const chalk = require('chalk') 2 | 3 | function showCommands(category) { 4 | 5 | var maxLength = 15 6 | 7 | for(var key in category) 8 | maxLength = Math.max(maxLength, key.length + 3) 9 | 10 | for(var key in category) { 11 | var text = ' ' + key + ':' 12 | 13 | for(var i=key.length; i { 10 | process.stdout.write(data) 11 | }) 12 | 13 | ls.stderr.on('data', (data) => { 14 | process.stderr.write(data) 15 | }) 16 | 17 | ls.on('close', (code) => { 18 | if(code !== 0) 19 | console.log(cwd, `exited with code ${code}`) 20 | }) 21 | } 22 | 23 | module.exports = function(value) { 24 | if(value !== 'plugins') { 25 | spawn(process.pwd()) 26 | spawn(process.cwd()) 27 | } 28 | 29 | for(var path in plugins.loadedPlugins) { 30 | spawn(path) 31 | } 32 | 33 | return false 34 | } -------------------------------------------------------------------------------- /@core-server/cli/lib/cli/prune.js: -------------------------------------------------------------------------------- 1 | const fs = require('fs') 2 | const { spawnSync } = require('child_process') 3 | 4 | function prune(dir) { 5 | try { 6 | spawnSync("npm", ['prune', '--production'], { 7 | cwd: dir, 8 | env: process.env, 9 | stdio: [process.stdin, process.stdout, process.stdout], 10 | encoding: 'utf-8' 11 | }) 12 | } catch(e) { 13 | console.error(e) 14 | } 15 | } 16 | 17 | module.exports = function() { 18 | const corePackage = require(process.pwd() + '/package.json') 19 | const coreBackup = JSON.parse(JSON.stringify(corePackage)) 20 | fs.writeFileSync(process.pwd() + '/package-backup.json', JSON.stringify(corePackage, null, 2)) 21 | 22 | for(var plugin in plugins.projectConfig) { 23 | if(plugins.projectConfig[plugin] || !corePackage.pluginDependencies[plugin]) 24 | continue 25 | 26 | for(var package in corePackage.pluginDependencies[plugin]) { 27 | delete corePackage.dependencies[package] 28 | } 29 | } 30 | 31 | fs.writeFileSync(process.pwd() + '/package.json', JSON.stringify(corePackage, null, 2)) 32 | prune(process.pwd()) 33 | prune(process.cwd()) 34 | 35 | fs.writeFileSync(process.pwd() + '/package.json', JSON.stringify(coreBackup, null, 2)) 36 | return false 37 | } -------------------------------------------------------------------------------- /@core-server/cli/lib/cli/version.js: -------------------------------------------------------------------------------- 1 | const Path = require('path') 2 | 3 | function getAppVersion(basePath) { 4 | try { 5 | return require(Path.join(basePath, 'package.json')).version || 'dev' 6 | } catch(e) { 7 | if(e.code === 'MODULE_NOT_FOUND') 8 | return 'dev' 9 | 10 | throw(e) 11 | } 12 | } 13 | 14 | module.exports = function() { 15 | 16 | console.log('Current app version: ', getAppVersion(process.cwd())) 17 | console.log('Current core-server version: ', getAppVersion(process.pwd())) 18 | console.log('Running node version: ', process.version) 19 | 20 | return false 21 | } -------------------------------------------------------------------------------- /@core-server/cli/lib/index.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | cli: require('./cli/index.js'), 3 | logs: require('./logs/index.js'), 4 | plugins: require('./plugins/index.js'), 5 | } -------------------------------------------------------------------------------- /@core-server/cli/lib/plugins/require.js: -------------------------------------------------------------------------------- 1 | const Console = require('../logs/index.js') 2 | const Module = require('module') 3 | const vm = require('vm') 4 | const Path = require('path') 5 | 6 | function makeRequireFunction(mod) { 7 | const Module = mod.constructor 8 | 9 | function require(path) { 10 | try { 11 | exports.requireDepth += 1 12 | return mod.require(path) 13 | } finally { 14 | exports.requireDepth -= 1 15 | } 16 | } 17 | 18 | function resolve(request) { 19 | return Module._resolveFilename(request, mod) 20 | } 21 | 22 | require.resolve = resolve 23 | 24 | require.main = process.mainModule 25 | 26 | // Enable support to add extra extension types. 27 | require.extensions = Module._extensions 28 | 29 | require.cache = Module._cache 30 | 31 | return require 32 | } 33 | 34 | function _compile(content, filename) { 35 | // create wrapper function 36 | Module.wrapper[0] = '(function (exports, require, module, __filename, __dirname, console, SuperClass) { ' 37 | var wrapper = Module.wrap(content) 38 | Module.wrapper[0] = '(function (exports, require, module, __filename, __dirname) { ' 39 | 40 | var compiledWrapper = vm.runInThisContext(wrapper, { 41 | filename: filename, 42 | lineOffset: 0, 43 | displayErrors: true 44 | }) 45 | 46 | var dirname = Path.dirname(filename) 47 | 48 | var DebugName = Path.basename(filename) 49 | DebugName = DebugName.substr(0, DebugName.length - Path.extname(DebugName).length) 50 | 51 | const require = makeRequireFunction(this) 52 | 53 | var result = compiledWrapper.call(this.exports, this.exports, require, this, 54 | filename, dirname, Console.create(DebugName), this.SuperClass) 55 | 56 | return result 57 | } 58 | 59 | const parent = module 60 | 61 | exports.plugin = function(filename, SuperClass) { 62 | var module = new Module(filename, parent) 63 | module._compile = _compile 64 | module.SuperClass = SuperClass 65 | 66 | module.load(filename) 67 | 68 | return module.exports 69 | } -------------------------------------------------------------------------------- /@core-server/cli/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@core-server/cli", 3 | "version": "1.0.8", 4 | "private": false, 5 | "description": "", 6 | "main": "lib/index.js", 7 | "scripts": { 8 | "test": "echo \"Error: no test specified\" && exit 1", 9 | "start": "node bin/core-server.js", 10 | "core-server": "node bin/core-server.js", 11 | "core-server-inspect": "node --inspect=0.0.0.0:9229 bin/core-server.js" 12 | }, 13 | "bin": { 14 | "core-server": "bin/core-server.js", 15 | "core-server-inspect": "bin/core-server-inspect.js" 16 | }, 17 | "author": "Vandamme Sacha (https://www.skyhark.be)", 18 | "license": "MIT", 19 | "dependencies": { 20 | "chalk": "^2.4.2", 21 | "dateformat": "^3.0.3", 22 | "process-argv": "^1.0.0" 23 | }, 24 | "engines": { 25 | "node": ">=7.0.0" 26 | }, 27 | "repository": { 28 | "type": "git", 29 | "url": "git+https://github.com/SachaSkyhark/Core-Server.git" 30 | }, 31 | "keywords": [ 32 | "Core-Server", 33 | "Vue", 34 | "Server", 35 | "api" 36 | ], 37 | "bugs": { 38 | "url": "https://github.com/SachaSkyhark/Core-Server/issues" 39 | }, 40 | "homepage": "https://www.core-server.io" 41 | } 42 | -------------------------------------------------------------------------------- /@core-server/databases/classes/ApiEnvironment.js: -------------------------------------------------------------------------------- 1 | class ApiEnvironment extends SuperClass { 2 | 3 | getConnections() { 4 | return this.siteManager.connections || {} 5 | } 6 | 7 | /** 8 | * send a query to the database 9 | * @param sql {String} 10 | * @param vars {Object} 11 | */ 12 | async query(sql, vars) { 13 | if (vars === undefined || vars === null) 14 | vars = this.post 15 | 16 | vars['auth_id'] = this.session['auth_id'] 17 | 18 | if (this.queryVars) { 19 | for (var key in this.queryVars) 20 | vars[key] = this.queryVars[key] 21 | } 22 | 23 | const database = this.getConnections().mysql 24 | if (!database) 25 | throw('No Mysql connection found') 26 | 27 | return await database.query(sql, vars, this.console) 28 | } 29 | 30 | /** 31 | * send a query to the database and get the first row 32 | * @param sql {String} 33 | * @param vars {Object} 34 | * @param default 35 | */ 36 | async query_object(sql, vars, def) { 37 | const result = await this.query(sql, vars) 38 | 39 | if (result.length === 0 || result[0] === undefined) { 40 | if(def !== undefined) 41 | return def 42 | else 43 | throw('No results found') 44 | } 45 | 46 | return result[0] 47 | } 48 | 49 | /** 50 | * Prepare an sql statement (for debug testing) 51 | * @param sql {String} 52 | * @param vars {Object} 53 | */ 54 | query_prepare(sql, vars) { 55 | if (vars === undefined || vars === null) 56 | vars = this.post 57 | 58 | const database = this.getConnections().mysql 59 | 60 | if(!database) 61 | return sql 62 | 63 | return plugins.require('databases/Mysql').queryFormat.call(database.connection, sql, vars) 64 | } 65 | 66 | } 67 | 68 | module.exports = ApiEnvironment -------------------------------------------------------------------------------- /@core-server/databases/classes/SiteManager.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | 3 | class SiteManager extends SuperClass { 4 | autoSetupFromConfig() { 5 | super.autoSetupFromConfig() 6 | 7 | const config = this.getConfig('servers') 8 | 9 | if (config.mysql) 10 | this.setupMysql(config.mysql) 11 | 12 | if (config.cloudflare) 13 | this.setupCloudflare(config.cloudflare) 14 | 15 | if (config.mongodb) 16 | this.setupMongodb(config.mongodb) 17 | } 18 | 19 | //------------------------------------------ 20 | 21 | /** 22 | * Setup a cloudflare api link 23 | * @param config {Object} 24 | */ 25 | setupCloudflare(config) { 26 | this.connections = this.connections || {} 27 | 28 | try { 29 | if (config === undefined) 30 | config = this.getConfig('servers').cloudflare 31 | 32 | const Cloudflare = require('cloudflare') 33 | this.connections.cloudflare = new Cloudflare(config) 34 | 35 | //------------------------------------------------------- 36 | 37 | if(process.env.NODE_ENV === 'production' && config["zone-id"]) { 38 | console.log("Purging cloudflare cache..") 39 | 40 | this.connections.cloudflare.deleteCache(config["zone-id"], { 41 | purge_everything: true 42 | }) 43 | .then(function() { 44 | console.log('Cloudflare cache successfully purged') 45 | }) 46 | .catch(function(err) { 47 | console.error(err) 48 | }) 49 | } 50 | 51 | } catch (e) { 52 | console.error(e) 53 | } 54 | } 55 | 56 | /** 57 | * Setup a mongodb connection that will be used by the api's 58 | * @param config {Object} 59 | */ 60 | setupMongodb(config) { 61 | this.connections = this.connections || {} 62 | 63 | try { 64 | if (config === undefined) 65 | config = this.getConfig('servers').mongodb 66 | 67 | const Mongodb = plugins.require('databases/Mongodb') 68 | this.connections.mongodb = new Mongodb(config) 69 | } catch (e) { 70 | console.error(e) 71 | } 72 | } 73 | 74 | /** 75 | * Setup a database connection that will be used by the api's 76 | * @param config {Object} 77 | */ 78 | setupMysql(config) { 79 | this.connections = this.connections || {} 80 | 81 | try { 82 | if (config === undefined) 83 | config = this.getConfig('servers').mysql 84 | 85 | const Mysql = plugins.require('databases/Mysql') 86 | this.connections.mysql = new Mysql(config) 87 | } catch (e) { 88 | console.error(e) 89 | } 90 | } 91 | 92 | 93 | } 94 | 95 | module.exports = SiteManager -------------------------------------------------------------------------------- /@core-server/databases/cli/cloudflare.js: -------------------------------------------------------------------------------- 1 | const fs = require('fs') 2 | const CFClient = require('cloudflare') 3 | const Path = require('path') 4 | 5 | function getConfig() { 6 | if (process.env.NODE_ENV === 'production') { 7 | const onlinePath = Path.join(process.cwd(), 'config', 'servers-production.json') 8 | if (fs.existsSync(onlinePath)) 9 | return require(onlinePath) 10 | } 11 | 12 | return require(Path.join(process.cwd(), 'config', 'servers.json')) 13 | } 14 | 15 | const config = getConfig() 16 | 17 | //-------------------------------------------------------------------------------------------- 18 | 19 | async function purgeAll(cloudflare) { 20 | console.log("Purging cloudflare cache..") 21 | 22 | await cloudflare.deleteCache( config.cloudflare["zone-id"], { 23 | purge_everything: true 24 | }) 25 | 26 | console.log('Cache successfully purged') 27 | } 28 | 29 | module.exports = async function(options) { 30 | if(!config.cloudflare) { 31 | console.error('Cloudflare config not found') 32 | return false 33 | } 34 | 35 | const action = options.cloudflare 36 | const cloudflare = new CFClient(config.cloudflare) 37 | 38 | if(action === 'purge') { 39 | await purgeAll(cloudflare) 40 | } else { 41 | console.log('Cloudflare action not found: ' + action) 42 | } 43 | 44 | return false 45 | } -------------------------------------------------------------------------------- /@core-server/databases/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@core-server/databases", 3 | "version": "1.0.3", 4 | "private": false, 5 | "description": "", 6 | "main": "index.js", 7 | "scripts": { 8 | "test": "echo \"Error: no test specified\" && exit 1" 9 | }, 10 | "author": "Vandamme Sacha (https://www.skyhark.be)", 11 | "license": "MIT", 12 | "dependencies": { 13 | "cloudflare": "2.7.0", 14 | "mongodb": "3.5.5", 15 | "mysql2": "2.1.0" 16 | }, 17 | "engines": { 18 | "node": ">=7.0.0" 19 | }, 20 | "repository": { 21 | "type": "git", 22 | "url": "git+https://github.com/SachaSkyhark/Core-Server.git" 23 | }, 24 | "keywords": [ 25 | "Core-Server", 26 | "Vue", 27 | "Server", 28 | "api" 29 | ], 30 | "bugs": { 31 | "url": "https://github.com/SachaSkyhark/Core-Server/issues" 32 | }, 33 | "homepage": "https://www.core-server.io" 34 | } 35 | -------------------------------------------------------------------------------- /@core-server/databases/plugin.json: -------------------------------------------------------------------------------- 1 | { 2 | "depencies": [ ], 3 | 4 | "classes": { 5 | "ApiEnvironment": "api/ApiEnvironment", 6 | "SiteManager": "http/SiteManager", 7 | "Mysql": null, 8 | "Mongodb": null 9 | }, 10 | 11 | "cli": { 12 | "cloudflare": "options: purge, Execute a full purge on your web site", 13 | "disable-mysql-errors": { 14 | "fake": true, 15 | "description": "Disable auto logging of mysql errors" 16 | } 17 | } 18 | } -------------------------------------------------------------------------------- /@core-server/eslint/classes/ApiCreator.js: -------------------------------------------------------------------------------- 1 | module.exports = SuperClass 2 | 3 | if(process.env.NODE_ENV !== 'development') 4 | return 5 | 6 | // Load eslint config 7 | var config 8 | try { 9 | config = require(process.cwd() + '/.eslintrc.js') 10 | } catch(e) { 11 | if(e.code != 'MODULE_NOT_FOUND') 12 | console.error('could not load eslint config', e) 13 | 14 | return 15 | } 16 | 17 | // Import packages 18 | const Linter = require("eslint").Linter 19 | const { logger, mapper } = require('vite-plugin-eslint-logger/src/logger.js') 20 | const linter = new Linter({ cwd: process.cwd() }) 21 | const fs = require('fs') 22 | 23 | linter.defineParser('@babel/eslint-parser', require('@babel/eslint-parser')) 24 | 25 | if(String.prototype.replaceAll === undefined) { 26 | String.prototype.replaceAll = function(search, replacement) { 27 | return this.split(search).join(replacement) 28 | } 29 | } 30 | 31 | // ESLint validator 32 | function verify(path, data, config) { 33 | var filename = path 34 | var index = path.lastIndexOf("/") 35 | if(index >= 0) 36 | filename = filename.substring(index + 1) 37 | 38 | var res = linter.verifyAndFix(data, config, { filename }) 39 | if(res.fixed && res.output) { 40 | fs.writeFileSync(path, res.output) 41 | return res.output 42 | } else if(res.messages.length == 0) { 43 | return data 44 | } 45 | 46 | res = mapper({ 47 | filePath: path, 48 | messages: res.messages, 49 | source: data, 50 | }) 51 | 52 | for(var item of res) 53 | logger(item) 54 | 55 | throw('eslint failed') 56 | } 57 | 58 | // override api file reader 59 | SuperClass.fileContent = function(path) { 60 | if (SuperClass.fileExists(path)) { 61 | var data = "" 62 | try { 63 | data = fs.readFileSync(path, 'utf8').toString() 64 | } catch (e) { 65 | console.error('fileContent', e) 66 | return false 67 | } 68 | 69 | if(path.substr(-3) != ".js") 70 | return data 71 | 72 | return verify(path, data, config) 73 | } 74 | 75 | return false 76 | } -------------------------------------------------------------------------------- /@core-server/eslint/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@core-server/eslint", 3 | "version": "1.0.3", 4 | "private": false, 5 | "description": "", 6 | "main": "index.js", 7 | "scripts": { 8 | "test": "echo \"Error: no test specified\" && exit 1" 9 | }, 10 | "author": "Vandamme Sacha (https://www.skyhark.be)", 11 | "license": "MIT", 12 | "dependencies": { 13 | "@babel/core": "^7.16.0", 14 | "@babel/eslint-parser": "^7.16.3", 15 | "@babel/plugin-syntax-top-level-await": "^7.14.5", 16 | "eslint": "^8.3.0", 17 | "vite-plugin-eslint-logger": "^1.1.0" 18 | }, 19 | "engines": { 20 | "node": ">=13.0.0" 21 | }, 22 | "repository": { 23 | "type": "git", 24 | "url": "git+https://github.com/SachaSkyhark/Core-Server.git" 25 | }, 26 | "keywords": [ 27 | "Core-Server", 28 | "Vue", 29 | "Server", 30 | "eslint" 31 | ], 32 | "bugs": { 33 | "url": "https://github.com/SachaSkyhark/Core-Server/issues" 34 | }, 35 | "homepage": "https://www.core-server.io" 36 | } 37 | -------------------------------------------------------------------------------- /@core-server/eslint/plugin.json: -------------------------------------------------------------------------------- 1 | { 2 | "classes": { 3 | "ApiCreator": "api/ApiCreator" 4 | } 5 | } -------------------------------------------------------------------------------- /@core-server/graphql/classes/ApiEnvironment.js: -------------------------------------------------------------------------------- 1 | const GraphDB = plugins.require('graphql/GraphDb').Instance() 2 | const sequelize = require('sequelize') 3 | 4 | class ApiEnvironment extends SuperClass { 5 | 6 | get schemas() { 7 | return this.siteManager.schemas 8 | } 9 | 10 | get sequelize() { 11 | return GraphDB.sequelize 12 | } 13 | 14 | /** 15 | * send a query to the database 16 | * @param sql {String} 17 | * @param vars {Object} 18 | */ 19 | async query(sql, vars, config = {}) { 20 | return GraphDB.sequelize.query( this.query_prepare(sql, vars), Object.assign({ type: sequelize.QueryTypes.SELECT }, config) ) 21 | } 22 | 23 | /** 24 | * send a query to the database and get the first row 25 | * @param sql {String} 26 | * @param vars {Object} 27 | * @param default 28 | */ 29 | async query_object(sql, vars, def) { 30 | const result = await this.query(sql, vars) 31 | 32 | if (result.length === 0 || result[0] === undefined) { 33 | if(def !== undefined) 34 | return def 35 | else 36 | throw('No results found') 37 | } 38 | 39 | return result[0] 40 | } 41 | 42 | /** 43 | * Prepare an sql statement (for debug testing) 44 | * @param sql {String} 45 | * @param vars {Object} 46 | */ 47 | query_prepare(sql, vars) { 48 | if (vars === undefined || vars === null) 49 | vars = this.post 50 | 51 | vars['auth_id'] = this.session['auth_id'] 52 | if (this.queryVars) { 53 | for (var key in this.queryVars) 54 | vars[key] = this.queryVars[key] 55 | } 56 | 57 | return queryFormat(sql, vars) 58 | } 59 | 60 | } 61 | 62 | module.exports = ApiEnvironment 63 | 64 | // ----------- 65 | 66 | function queryFormat(sql, values) { 67 | if (values === null || values === undefined) 68 | values = {} 69 | 70 | if (!(values instanceof Object || Object.isPrototypeOf(values) || typeof (values) === 'object')) 71 | values = {} 72 | 73 | var chunkIndex = 0 74 | var placeholdersRegex = /{@(.*?)}/g 75 | var result = '' 76 | var match, value 77 | 78 | while (match = placeholdersRegex.exec(sql)) { 79 | // ToDo Check if surrounded by quotes or not ..? 80 | value = values[match[1]] 81 | value = this.escape(value == undefined ? '' : value) 82 | // this.escapeId(..?) 83 | 84 | if (value.substr(0, 1) == "'" && value.substr(value.length - 1) == "'") 85 | 86 | value = value.substr(1, value.length - 2) 87 | 88 | result += sql.slice(chunkIndex, match.index) + value 89 | chunkIndex = placeholdersRegex.lastIndex 90 | } 91 | 92 | if (chunkIndex === 0) { 93 | // Nothing was replaced 94 | if (global.logSQL) 95 | console.log(sql) 96 | 97 | return sql 98 | } 99 | 100 | if (chunkIndex < sql.length) 101 | 102 | result += sql.slice(chunkIndex) 103 | 104 | if (global.logSQL) 105 | console.log(result) 106 | 107 | return result 108 | } -------------------------------------------------------------------------------- /@core-server/graphql/classes/Session.js: -------------------------------------------------------------------------------- 1 | const query = require('../lib/query') 2 | class Session extends SuperClass { 3 | 4 | handleSocketMessage(socket, message) { 5 | if(message.query !== undefined || message.live !== undefined || message.bulk || message.live !== undefined) 6 | return query(this, socket, message, this.dbWatcher) 7 | 8 | super.handleSocketMessage(socket, message) 9 | } 10 | 11 | } 12 | 13 | module.exports = Session -------------------------------------------------------------------------------- /@core-server/graphql/classes/SiteManager.js: -------------------------------------------------------------------------------- 1 | const { ApolloServer } = require('apollo-server-express') 2 | const GraphDB = plugins.require('graphql/GraphDb').Instance() 3 | const Session = plugins.require('api/Session') 4 | const context = require('../lib/context') 5 | const fs = require('fs') 6 | const path = require('path') 7 | const HttpServer = plugins.require('http/HttpServer') 8 | 9 | /* const typeDefs = gql(` 10 | # Comments in GraphQL strings (such as this one) start with the hash (#) symbol. 11 | 12 | # This "Book" type defines the queryable fields for every book in our data source. 13 | type Book { 14 | title: String 15 | author: String 16 | } 17 | 18 | # The "Query" type is special: it lists all of the available queries that 19 | # clients can execute, along with the return type for each. In this 20 | # case, the "books" query returns an array of zero or more Books (defined above). 21 | type Query { 22 | books(id: ID!): Formula 23 | } 24 | `); 25 | 26 | console.log(JSON.stringify(typeDefs.definitions, null, 2))*/ 27 | 28 | class SiteManager extends SuperClass { 29 | 30 | async getGraphqlContext({ req }) { 31 | var sess = null 32 | req.getClientIp = req.getClientIp || function() { 33 | return HttpServer.getClientIpFromHeaders(this, this.socket) 34 | } 35 | 36 | // Try loading session from headers (parsed from LB) 37 | if(req.session) { 38 | sess = req.session 39 | } else if(req.headers.session) { 40 | if(this.getConfig('graphql').sessionHeaders) { 41 | try { 42 | const data = JSON.parse(req.headers.session) 43 | sess = new Session(this, '', { 44 | localeOnly: true, 45 | data, 46 | }) 47 | } catch(e) { 48 | console.error('Could not load session', e.message) 49 | } 50 | } 51 | } else if(!this.getConfig('graphql').sessionHeaders) { 52 | sess = this.sessionsManager.getFromCookies(req.cookies) 53 | await sess.onReady() 54 | } 55 | 56 | // Create empty session if no session available 57 | 58 | if(sess == null) { 59 | sess = new Session(this, '', { 60 | localeOnly: true, 61 | data: {}, 62 | }) 63 | } 64 | 65 | // Create context object 66 | var res = Object.assign({}, sess.data) 67 | res.api = (name, post) => { 68 | return sess.api(name, post, req) 69 | } 70 | 71 | res.session_object = sess 72 | res.session = sess.data 73 | res.req = req 74 | return res 75 | } 76 | 77 | autoSetupFromConfig() { 78 | super.autoSetupFromConfig() 79 | console.log('Setup graphql server') 80 | 81 | var config = this.getConfig('servers') 82 | if(config.mysql) { 83 | config = config.mysql 84 | const { schemas, resolvers, typeDefs } = GraphDB.construct(config.host || config.server, config.user || config.username, config.password || config.pass, config.database || config.db) 85 | context.Schemas = schemas 86 | context.SiteManager = this 87 | this.Sequelize = require('sequelize') 88 | 89 | if(fs.existsSync(path.join(process.cwd(), 'graphql', 'src', 'mixin.js'))) { 90 | const mixin = require(path.join(process.cwd(), 'graphql', 'src', 'mixin.js')) 91 | this.schemas = mixin(schemas, resolvers, typeDefs) 92 | } else { 93 | this.schemas = schemas 94 | } 95 | 96 | if(typeDefs.definitions[0].fields.length == 0) 97 | return 98 | 99 | this.apollo = new ApolloServer({ 100 | typeDefs, 101 | resolvers, 102 | context: this.getGraphqlContext.bind(this), 103 | // validationRules: [depthLimit(10)], 104 | }) 105 | 106 | this.apollo.applyMiddleware({ 107 | app: this, 108 | path: this.getConfig('servers').graphqlEndpoint || '/graphql' 109 | }) 110 | } 111 | } 112 | } 113 | 114 | module.exports = SiteManager -------------------------------------------------------------------------------- /@core-server/graphql/cli/check-indexes.js: -------------------------------------------------------------------------------- 1 | const GraphDB = plugins.require('graphql/GraphDb') 2 | 3 | var Sequelize 4 | 5 | function getTables() { 6 | return Sequelize.query("SHOW TABLES").then((res) => { 7 | return res[0].map((o) => Object.values(o)[0]) 8 | }) 9 | } 10 | 11 | function getIndexes(table) { 12 | return Sequelize.query("SHOW CREATE TABLE `"+table+"`").then((res) => { 13 | if(!res[0][0]['Create Table']) { 14 | console.warn('undefined create table', res[0][0]) 15 | return 16 | } 17 | 18 | var sql = res[0][0]['Create Table'].split("\n") 19 | sql = sql.filter((o) => o.indexOf(' KEY `') !== -1 && o.indexOf('CONSTRAINT ') === -1) 20 | 21 | return sql.map((o) => { 22 | const index = o.indexOf('KEY `') 23 | const end = o.indexOf("`", index+5) 24 | const fields = o.substr(end + 4, o.length - end - 7).split("`, `").sort().join(',') 25 | 26 | return { 27 | name: o.substr(index + 5, end-index - 5), 28 | fields: fields 29 | } 30 | }) 31 | 32 | }) 33 | } 34 | 35 | function detectDuplicateKeys(table) { 36 | return getIndexes(table).then((indexes) => { 37 | return indexes.filter((value, index, self) => { 38 | return self.findIndex((val) => val.fields === value.fields) !== index 39 | }) 40 | }) 41 | } 42 | 43 | async function removeDuplicateKeys(table) { 44 | const duplicates = await detectDuplicateKeys(table) 45 | 46 | for(var key in duplicates) { 47 | await Sequelize.query("ALTER TABLE `"+table+"` DROP INDEX `"+duplicates[key].name+"`;") 48 | } 49 | 50 | if(duplicates.length > 0) 51 | console.log(`removed ${duplicates.length} duplicate keys from table ${table}`) 52 | 53 | return duplicates 54 | } 55 | 56 | module.exports = async function(seq) { 57 | try { 58 | if(typeof(seq) === "object") { 59 | Sequelize = seq 60 | } else { 61 | var config = plugins.getProjectConfig('servers') 62 | GraphDB.construct(config.host, config.user, config.password || config.pass, config.database || config.db) 63 | Sequelize = GraphDB.sequelize 64 | } 65 | 66 | const tables = await getTables() 67 | 68 | for(var x in tables) { 69 | await removeDuplicateKeys(tables[x]) 70 | } 71 | } catch(e) { 72 | console.error(e) 73 | } 74 | 75 | console.log('Done!') 76 | process.exit(0) 77 | } -------------------------------------------------------------------------------- /@core-server/graphql/cli/sync-schemas.js: -------------------------------------------------------------------------------- 1 | const GraphDB = plugins.require('graphql/GraphDb') 2 | const checkIndexes = require('./check-indexes') 3 | 4 | module.exports = async function() { 5 | var config = plugins.getProjectConfig('servers').mysql 6 | GraphDB.construct(config.host, config.user, config.password || config.pass, config.database || config.db) 7 | const { sequelize } = GraphDB 8 | 9 | // if(triggers !== 't' && triggers !== 'triggers') { 10 | try { 11 | const start = new Date().getTime() 12 | // await mysqldump(dumpConfig); 13 | const timeDump = new Date().getTime() 14 | console.log('Mysqldump took:', timeDump - start, 'ms.') 15 | await sequelize.sync({ 16 | alter: true 17 | }) 18 | const timeSync = new Date().getTime() 19 | console.log('Sequelize sync took:', timeSync - timeDump, 'ms.') 20 | } catch(e) { 21 | if (e.sql) { 22 | console.log('Sync error sql: ', e.sql) 23 | } 24 | 25 | throw(e) 26 | } 27 | // } 28 | 29 | // try { 30 | // const timeSync = new Date().getTime(); 31 | // await sequelize.syncTriggers(); 32 | // console.log('Sequelize triggers took:', new Date().getTime() - timeSync, 'ms.'); 33 | // } catch(e) { 34 | // if (e.sql) { 35 | // console.log('Sync error sql: ', e.sql); 36 | // } 37 | 38 | // throw(e); 39 | // } 40 | 41 | if(process.options['no-indexes'] === undefined) 42 | await checkIndexes(sequelize) 43 | 44 | console.log('Done!') 45 | process.exit(0) 46 | } -------------------------------------------------------------------------------- /@core-server/graphql/lib/typedeff.js: -------------------------------------------------------------------------------- 1 | function camelize(str) { 2 | str = str.split('-').join(' ').split('_').join(' ').toLowerCase().split(' ').map((r) => { 3 | return r.substr(0,1).toUpperCase() + r.substr(1) 4 | }).join('') 5 | 6 | if(str.substr(-1, 1) == 's') 7 | return str.substr(0, str.length - 1) 8 | 9 | return str 10 | } 11 | 12 | module.exports = { 13 | camelize, 14 | 15 | schemaDeffinition(schemaName, fields) { 16 | 17 | // Serialize fields 18 | const gFields = [] 19 | for(var name in fields) { 20 | if(!fields[name].graphql) 21 | continue 22 | 23 | const config = fields[name].graphql 24 | 25 | if(fields[name].foreign) { 26 | const foreign = fields[name].foreign 27 | if(name.substr(-3) == '_id') 28 | name = name.substr(0, name.length-3) 29 | 30 | config.typeName = config.typeName || camelize(foreign) 31 | } 32 | 33 | gFields.push({ 34 | kind: "FieldDefinition", 35 | name: { 36 | kind: "Name", 37 | value: config.name || name 38 | }, 39 | arguments: config.arguments || [], 40 | type: config.type || { 41 | kind: "NamedType", 42 | name: { 43 | kind: "Name", 44 | value: config.typeName || 'String', 45 | } 46 | }, 47 | directives: config.directives || [] 48 | }) 49 | } 50 | 51 | // Return object 52 | return { 53 | kind: "ObjectTypeDefinition", 54 | name: { 55 | kind: "Name", 56 | value: camelize(schemaName), 57 | }, 58 | interfaces: [], 59 | directives: [], 60 | fields: gFields, 61 | } 62 | }, 63 | 64 | graphConfig(config, deff = {}) { 65 | if(!config || config.graphql === false) 66 | return null 67 | 68 | if(typeof(config.graphql) == 'string') 69 | config.graphql = { name: config.graphql } 70 | 71 | return Object.assign(deff, config.graphql || {}) 72 | }, 73 | 74 | getComputedFields(table, fields) { 75 | var res = null 76 | 77 | for(var key in fields) { 78 | const field = fields[key] 79 | if(!field.graphql || !field.graphql.resolve) 80 | continue 81 | 82 | res = res || {} 83 | res[key] = field.graphql.resolve 84 | } 85 | 86 | if(!res) 87 | return null 88 | 89 | return { 90 | type: { 91 | [camelize(table)]: res 92 | } 93 | } 94 | } 95 | 96 | } -------------------------------------------------------------------------------- /@core-server/graphql/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@core-server/graphql", 3 | "version": "1.7.1", 4 | "description": "", 5 | "main": "index.js", 6 | "scripts": { 7 | "test": "echo \"Error: no test specified\" && exit 1" 8 | }, 9 | "author": "Vandamme Sacha (https://www.skyhark.be)", 10 | "license": "MIT", 11 | "dependencies": { 12 | "apollo-server-express": "2.15.1", 13 | "mysql2": "2.3.2", 14 | "sequelize": "5.21.10" 15 | }, 16 | "engines": { 17 | "node": ">=7.0.0" 18 | }, 19 | "repository": { 20 | "type": "git", 21 | "url": "git+https://github.com/SachaSkyhark/Core-Server.git" 22 | }, 23 | "keywords": [ 24 | "Core-Server", 25 | "Vue", 26 | "Server", 27 | "api" 28 | ], 29 | "bugs": { 30 | "url": "https://github.com/SachaSkyhark/Core-Server/issues" 31 | }, 32 | "homepage": "https://www.core-server.io" 33 | } 34 | -------------------------------------------------------------------------------- /@core-server/graphql/plugin.json: -------------------------------------------------------------------------------- 1 | { 2 | "classes": { 3 | "SiteManager": "http/SiteManager", 4 | "ApiEnvironment": "api/ApiEnvironment", 5 | "Session": "api/Session", 6 | "GraphDb": null 7 | }, 8 | "cli": { 9 | "check-indexes": "Verify mysql indexes", 10 | "sync-schemas": "Sync mysql schemas" 11 | } 12 | } -------------------------------------------------------------------------------- /@core-server/http/classes/Event.js: -------------------------------------------------------------------------------- 1 | const nativeConsole = console 2 | 3 | class Event { 4 | 5 | constructor(config) { 6 | const { retainTrigger, console } = config || {} 7 | 8 | this.callbacks = [] 9 | this.retainTrigger = retainTrigger 10 | this.triggerData = null 11 | this.console = console || nativeConsole 12 | } 13 | 14 | execCallback(cb, data, err) { 15 | try { 16 | cb(data, err) 17 | } catch(e) { 18 | this.console.error(e) 19 | } 20 | 21 | return this 22 | } 23 | 24 | on(cb) { 25 | if(this.triggerData !== null) 26 | this.execCallback(cb, this.triggerData) 27 | 28 | this.callbacks.push(cb) 29 | return this 30 | } 31 | 32 | once(cb, errCb) { 33 | if(!cb) { 34 | return new Promise((resolve, reject) => { 35 | this.once(function(res, err) { 36 | if(err) 37 | reject(err) 38 | else 39 | resolve(res) 40 | }) 41 | }) 42 | } 43 | 44 | if(this.triggerData !== null) 45 | return this.execCallback(cb, this.triggerData) 46 | 47 | var cc = (function ccx(data, err) { 48 | try { 49 | if(err && errCb) 50 | errCb(err) 51 | else 52 | cb(data, err) 53 | 54 | this.remove(cc) 55 | } catch(e) { 56 | this.remove(cc) 57 | throw(e) 58 | } 59 | }).bind(this) 60 | 61 | this.callbacks.push(cc) 62 | return this 63 | } 64 | 65 | remove(cb) { 66 | var index = this.callbacks.indexOf(cb) 67 | 68 | if(index !== -1) 69 | this.callbacks.splice(index, 1) 70 | } 71 | 72 | then(cb, errCb) { 73 | return this.once(cb, errCb) 74 | } 75 | 76 | catch(cb) { 77 | return this.once((res, err) => { 78 | if(err) 79 | cb(err) 80 | }) 81 | } 82 | 83 | trigger(data, err) { 84 | if(this.retainTrigger) 85 | this.triggerData = data 86 | 87 | const cbCopy = [] 88 | 89 | this.callbacks.forEach((cb) => cbCopy.push(cb)) 90 | 91 | cbCopy.forEach((cb) => { 92 | this.execCallback(cb, data, err) 93 | }) 94 | } 95 | 96 | valueOf() { 97 | if(!this.retainTrigger) 98 | return null 99 | 100 | return this.triggerData 101 | } 102 | 103 | toString() { 104 | return String(this.valueOf()) 105 | } 106 | } 107 | 108 | module.exports = Event -------------------------------------------------------------------------------- /@core-server/http/classes/Watcher.js: -------------------------------------------------------------------------------- 1 | const Path = require('path') 2 | const cluster = require('cluster') 3 | 4 | class Watcher { 5 | constructor() { 6 | this.timeout = null 7 | 8 | this.siteChangeListeners = [] 9 | this.fileChangeListeners = {} 10 | 11 | if (cluster.isMaster || process.env.NODE_ENV !== 'development') 12 | return 13 | 14 | const _this = this 15 | function changeDetected() { 16 | _this.changeDetected.apply(_this, arguments) 17 | } 18 | 19 | var useWatchman = false 20 | try { 21 | const spawn = require("child_process").spawnSync('watchman') 22 | if(!spawn.error) 23 | useWatchman = true 24 | } catch(e) { } 25 | 26 | const sane = require('sane') 27 | var sWatch = sane(process.cwd(), { dot: false, watchman: useWatchman }) 28 | sWatch.on('change', changeDetected) 29 | sWatch.on('add', changeDetected) 30 | sWatch.on('delete', changeDetected) 31 | } 32 | 33 | clearTimeout() { 34 | try { 35 | if (this.timeout != null) 36 | clearTimeout(this.timeout) 37 | } catch (e) { 38 | console.error(e) 39 | } 40 | 41 | this.timeout = null 42 | } 43 | 44 | setTimeout() { 45 | const _this = this 46 | this.timeout = setTimeout(function() { 47 | console.warn('Thread restarting') 48 | process.send('restartWorker') 49 | }, 200) 50 | } 51 | 52 | onChange(dir, callback) { 53 | this.siteChangeListeners.push({ 54 | dir: Path.normalize(dir), 55 | callback: callback 56 | }) 57 | } 58 | 59 | onFileChange(file, callback) { 60 | file = Path.normalize(file) 61 | if (this.fileChangeListeners[file] === undefined) 62 | this.fileChangeListeners[file] = [] 63 | 64 | this.fileChangeListeners[file].push(callback) 65 | } 66 | 67 | emitFileChanged(file) { 68 | if (this.fileChangeListeners[file] !== undefined) { 69 | try { 70 | var listeners = this.fileChangeListeners[file] 71 | for (var key in listeners) { 72 | try { 73 | listeners[key](file) 74 | } catch (e) { 75 | console.error(e) 76 | } 77 | } 78 | } catch (e) { 79 | console.error(e) 80 | } 81 | } 82 | } 83 | 84 | executeCallback(obj, relativePath, fullPath) { 85 | try { 86 | if (relativePath.substr(0, obj.dir.length) === obj.dir || obj.dir === fullPath.substr(0, obj.dir.length)) 87 | obj.callback(fullPath, relativePath) 88 | } catch (e) { 89 | console.error(e) 90 | } 91 | } 92 | 93 | emitSiteChanged(relativePath, fullPath) { 94 | try { 95 | const listeners = this.siteChangeListeners 96 | for (var key in listeners) 97 | this.executeCallback(listeners[key], relativePath, fullPath) 98 | } catch (e) { 99 | console.error(e) 100 | } 101 | 102 | this.emitFileChanged(relativePath) 103 | this.emitFileChanged(Path.normalize(fullPath)) 104 | } 105 | 106 | onCoreChanged(filepath) { 107 | this.clearTimeout() 108 | this.setTimeout() 109 | } 110 | 111 | changeDetected(filepath, root) { 112 | if (Path.normalize(root) === Path.join(__dirname, '..', '..')) { 113 | if ((filepath.substr(0, 8) === 'modules' + Path.sep && Path.extname(filepath) != '.php') || filepath === 'server.js') 114 | return this.onCoreChanged(filepath) 115 | } 116 | 117 | if (Path.normalize(root) === Path.normalize(process.cwd())) { 118 | if (filepath.substr(0, 5) === 'core' + Path.sep) 119 | this.onCoreChanged(filepath) 120 | else 121 | this.emitSiteChanged(filepath, Path.join(root, filepath)) 122 | } 123 | } 124 | } 125 | 126 | module.exports = new Watcher() -------------------------------------------------------------------------------- /@core-server/http/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@core-server/http", 3 | "version": "1.1.7", 4 | "description": "", 5 | "main": "index.js", 6 | "scripts": { 7 | "test": "echo \"Error: no test specified\" && exit 1" 8 | }, 9 | "author": "Vandamme Sacha (https://www.skyhark.be)", 10 | "license": "MIT", 11 | "devDependencies": { 12 | "sane": "^4.1.0" 13 | }, 14 | "dependencies": { 15 | "cookie": "^0.4.0", 16 | "google_authenticator": "^2.0.0", 17 | "hi-base32": "^0.5.0", 18 | "mime-types": "^2.1.24", 19 | "request": "^2.88.0", 20 | "sockjs": "^0.3.24", 21 | "spdy": "^4.0.2", 22 | "xxhashjs": "^0.2.2" 23 | }, 24 | "engines": { 25 | "node": ">=7.0.0" 26 | }, 27 | "repository": { 28 | "type": "git", 29 | "url": "git+https://github.com/SachaSkyhark/Core-Server.git" 30 | }, 31 | "keywords": [ 32 | "Core-Server", 33 | "Vue", 34 | "Server", 35 | "api" 36 | ], 37 | "bugs": { 38 | "url": "https://github.com/SachaSkyhark/Core-Server/issues" 39 | }, 40 | "homepage": "https://www.core-server.io" 41 | } 42 | -------------------------------------------------------------------------------- /@core-server/http/plugin.json: -------------------------------------------------------------------------------- 1 | { 2 | "classes": { 3 | "SiteManager": null, 4 | "MasterServer": null, 5 | "HttpServer": null, 6 | "Crypter": null, 7 | "Watcher": null, 8 | "Event": null 9 | }, 10 | 11 | "cli": { 12 | "port": { 13 | "fake": true, 14 | "description": "Specify a startup port for the web server" 15 | }, 16 | 17 | "threads": { 18 | "fake": true, 19 | "description": "Specify the number of threads that will be started for the server" 20 | }, 21 | 22 | "secure": { 23 | "fake": true, 24 | "description": "Start server using ssl" 25 | } 26 | }, 27 | 28 | "entry": "MasterServer" 29 | } -------------------------------------------------------------------------------- /@core-server/kubeconfig/classes/SiteManager.js: -------------------------------------------------------------------------------- 1 | class SiteManager extends SuperClass { 2 | 3 | getConfig(name) { 4 | if (this.configs[name]) 5 | return this.configs[name] 6 | else if(process.env.NODE_ENV !== 'production') 7 | return super.getConfig(name) 8 | 9 | // Get config from prod path 10 | try { 11 | const prodPath = '/var/config/' + name + '.json' 12 | const fs = require('fs') 13 | 14 | if (fs.existsSync(prodPath)) { 15 | const Crypter = plugins.require('http/Crypter') 16 | const config = SiteManager.getConfigSecret() 17 | const content = fs.readFileSync(prodPath).toString() 18 | const res = Crypter.decrypt(content, config.secret, config.iv) 19 | 20 | if(res) { 21 | this.configs[name] = JSON.parse(res) 22 | return this.configs[name] 23 | } 24 | } 25 | } catch(e) { 26 | console.error(e) 27 | } 28 | 29 | return super.getConfig(name) 30 | } 31 | 32 | static getConfigSecret() { 33 | const pkg = require(process.cwd() + '/package.json') 34 | if(pkg.iv && pkg.secret) { 35 | return { 36 | name: pkg.k8sName || pkg.name, 37 | namespace: pkg.namespace || 'default', 38 | secret: pkg.secret, 39 | iv: pkg.iv, 40 | } 41 | } 42 | 43 | const Crypter = plugins.require('http/Crypter') 44 | const hash = Crypter.sha1Hex(pkg.name) 45 | 46 | return { 47 | name: pkg.k8sName || pkg.name, 48 | namespace: pkg.namespace || 'default', 49 | secret: hash.substr(16), 50 | iv: hash.substr(0, 16) 51 | } 52 | } 53 | 54 | } 55 | 56 | module.exports = SiteManager -------------------------------------------------------------------------------- /@core-server/kubeconfig/cli/decode-secrets.js: -------------------------------------------------------------------------------- 1 | const fs = require('fs') 2 | const Crypter = plugins.require('http/Crypter') 3 | const Manager = plugins.require('http/SiteManager') 4 | const config = Manager.getConfigSecret() 5 | 6 | module.exports = function(path) { 7 | if(!path) 8 | throw('No path provided') 9 | 10 | const content = fs.readFileSync(path).toString() 11 | const decrypt = Crypter.decrypt(Buffer.from(content, 'base64'), config.secret, config.iv) 12 | console.log(decrypt) 13 | 14 | return false 15 | } -------------------------------------------------------------------------------- /@core-server/kubeconfig/cli/publish-secrets.js: -------------------------------------------------------------------------------- 1 | const fs = require('fs') 2 | const Path = require('path') 3 | const Crypter = plugins.require('http/Crypter') 4 | const Manager = plugins.require('http/SiteManager') 5 | const config = Manager.getConfigSecret() 6 | 7 | function getFiles(path) { 8 | const files = fs.readdirSync(path) 9 | const res = {} 10 | 11 | for(var name of files) { 12 | const content = fs.readFileSync(Path.join(path, name)).toString() 13 | res[name] = Crypter.encrypt(content, config.secret, config.iv) 14 | } 15 | 16 | return res 17 | } 18 | 19 | module.exports = function(arg) { 20 | const files = getFiles(Path.join(process.cwd(), 'config', '_prod')) 21 | 22 | const args = ['create', 'secret', 'generic', config.name, '--namespace=' + (config.namespace || 'default'), '--dry-run', '-o=json'].concat( Object.keys(files).map((file) => "--from-literal=" + file + "=" + files[file]) ) 23 | var spawn = require('child_process').execSync 24 | 25 | // kick off process of listing files 26 | var child = spawn('kubectl ' + args.join(' ') + ' | kubectl apply -f -') 27 | console.log(child.toString()) 28 | 29 | return false 30 | } -------------------------------------------------------------------------------- /@core-server/kubeconfig/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@core-server/kubeconfig", 3 | "version": "1.0.2", 4 | "private": false, 5 | "author": "Vandamme Sacha (https://www.skyhark.be)", 6 | "license": "MIT", 7 | "main": "index.js", 8 | "repository": { 9 | "type": "git", 10 | "url": "git+https://github.com/SachaSkyhark/Core-Server.git" 11 | }, 12 | "keywords": [ 13 | "Core-Server", 14 | "kubernetes", 15 | "config" 16 | ], 17 | "scripts": { 18 | 19 | }, 20 | "bugs": { 21 | "url": "https://github.com/SachaSkyhark/Core-Server/issues" 22 | }, 23 | "homepage": "https://www.core-server.io" 24 | } 25 | -------------------------------------------------------------------------------- /@core-server/kubeconfig/plugin.json: -------------------------------------------------------------------------------- 1 | { 2 | "classes": { 3 | "SiteManager": "http/SiteManager" 4 | }, 5 | "cli": { 6 | "decode-secrets": { 7 | "description": "Decode secrets from kubernetes config" 8 | }, 9 | 10 | "publish-secrets": { 11 | "description": "Publish secrets to kubernetes" 12 | } 13 | } 14 | } -------------------------------------------------------------------------------- /@core-server/mail/classes/ApiEnvironment.js: -------------------------------------------------------------------------------- 1 | const Path = require('path') 2 | 3 | class ApiEnvironment extends SuperClass { 4 | 5 | //---------------------------------------------------- 6 | // Mail environment functions 7 | 8 | /** 9 | * send a mail 10 | * @param user_id {Numeric} 11 | * @param email {String} 12 | * @param layout_name {String} 13 | * @param data {Object} 14 | */ 15 | async mail(user_id, email, layout, data) { 16 | const Mailer = plugins.require('mail/Mailer') 17 | 18 | data = data || this.post 19 | 20 | var recv_name = '' 21 | var subject = '' 22 | var message = '' 23 | const mymail = this.siteManager.getConfig('servers').mail.user 24 | const myname = this.siteManager.getConfig('servers').mail.name || mymail 25 | 26 | try { 27 | const info = await Mailer.parseLayout(Path.join(process.cwd(), 'mails'), layout, data) 28 | 29 | info.name = myname 30 | info.destination = email 31 | info.source = mymail 32 | 33 | // recv_name = ''; 34 | subject = info.subject 35 | message = info.html 36 | 37 | return { 38 | result: await Mailer.send(info), 39 | 40 | send_mail: mymail, 41 | send_name: myname, 42 | recv_mail: email, 43 | recv_name: recv_name, 44 | subject: subject, 45 | message: message, 46 | } 47 | } catch(e) { 48 | 49 | e.send_mail = mymail 50 | e.send_name = myname 51 | e.recv_mail = email 52 | e.recv_name = recv_name 53 | e.subject = subject 54 | e.message = message 55 | 56 | e.message = e.message || e.code || 'An error occured while sending the email' 57 | throw(e) 58 | } 59 | } 60 | 61 | } 62 | 63 | module.exports = ApiEnvironment -------------------------------------------------------------------------------- /@core-server/mail/classes/Mailer.js: -------------------------------------------------------------------------------- 1 | const fs = require('fs') 2 | const Path = require('path') 3 | const placeholdersRegex = /{@(.*?)}/g 4 | const nodemailer = require('nodemailer') 5 | const htmlToText = require('html-to-text') 6 | const jsesc = require('jsesc') 7 | 8 | function parseMailLayout(baseDir, layout, data) { 9 | return new Promise(function(resolve, reject) { 10 | var result = '' 11 | var match, value 12 | var chunkIndex = 0 13 | 14 | fs.readFile(Path.join(baseDir, 'layout.html'), function(err, htmlLayout) { 15 | if (err) 16 | return reject(err) 17 | 18 | htmlLayout = htmlLayout.toString() 19 | fs.readFile(Path.join(baseDir, layout + '.html'), function(err, html) { 20 | if (err) 21 | return reject(err) 22 | 23 | html = html.toString() 24 | // html = html.replace('{@content}', html2.toString()); 25 | 26 | match = placeholdersRegex.exec(html) 27 | if(!match) 28 | result = html 29 | 30 | while (match) { 31 | value = data[match[1]] 32 | value = (value === undefined ? '' : value) 33 | 34 | if (value.substr(0, 1) === "'" && value.substr(value.length - 1) === "'") 35 | 36 | value = value.substr(1, value.length - 2) 37 | 38 | result += html.slice(chunkIndex, match.index) + value 39 | chunkIndex = placeholdersRegex.lastIndex 40 | match = placeholdersRegex.exec(html) 41 | } 42 | 43 | if (chunkIndex !== 0 && chunkIndex < html.length) 44 | result += html.slice(chunkIndex) 45 | 46 | var index = result.indexOf('\n') 47 | var subject = result.substr(0, index) 48 | html = htmlLayout.replace('{@content}', result.substr(result.indexOf('\n', index + 1) + 1)) 49 | 50 | resolve({ 51 | subject: subject, 52 | html: html 53 | }) 54 | }) 55 | }) 56 | }) 57 | } 58 | 59 | function sendMail(options) { 60 | // options.subject 61 | // options.html 62 | // options.destination 63 | // options.source 64 | 65 | return new Promise(function(resolve, reject) { 66 | var config = options.mailServer 67 | if(!config) { 68 | const server = plugins.getEntry('http/MasterServer') 69 | config = server.siteManager.getConfig('servers').mail 70 | 71 | if(!config) { 72 | const keys = server.siteManager.getConfig('keys') 73 | if(keys.mailgun) { 74 | config = Object.assign(keys.mailgun, { service: 'mailgun' }) 75 | } 76 | } 77 | } 78 | 79 | var transporterConfig = {} 80 | if(config.service === 'gmail') { 81 | transporterConfig.service = 'gmail' 82 | transporterConfig.auth = { 83 | user: config.user, 84 | pass: config.password 85 | } 86 | } else if(config.service === 'mailgun') { 87 | var mg = require('nodemailer-mailgun-transport') 88 | transporterConfig = mg(config) 89 | } 90 | 91 | let transporter = nodemailer.createTransport(transporterConfig) 92 | 93 | // To 94 | var from = options['source'] 95 | if (options.name !== undefined) 96 | from = "'" + jsesc(options.name) + "' <" + from + '>' 97 | 98 | const text = htmlToText.fromString(options.html, { 99 | wordwrap: 130 100 | }) 101 | 102 | let mailOptions = { 103 | from, 104 | replyTo: options['source'], 105 | sender: options['source'], 106 | to: options.destination, 107 | subject: options.subject, 108 | text: text, 109 | html: options.html 110 | } 111 | 112 | // send mail with defined transport object 113 | transporter.sendMail(mailOptions, (error, info) => { 114 | if (error) 115 | reject(error) 116 | else 117 | resolve(info) 118 | }) 119 | }) 120 | } 121 | 122 | module.exports = { 123 | parseLayout: parseMailLayout, 124 | send: sendMail 125 | } -------------------------------------------------------------------------------- /@core-server/mail/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@core-server/mail", 3 | "version": "1.0.1", 4 | "description": "", 5 | "main": "index.js", 6 | "scripts": { 7 | "test": "echo \"Error: no test specified\" && exit 1" 8 | }, 9 | "author": "Vandamme Sacha (https://www.skyhark.be)", 10 | "license": "MIT", 11 | "devDependencies": {}, 12 | "dependencies": { 13 | "html-to-text": "^5.1.1", 14 | "jsesc": "^2.5.2", 15 | "nodemailer": "^6.3.0" 16 | }, 17 | "engines": { 18 | "node": ">=7.0.0" 19 | }, 20 | "repository": { 21 | "type": "git", 22 | "url": "git+https://github.com/SachaSkyhark/Core-Server.git" 23 | }, 24 | "keywords": [ 25 | "Core-Server", 26 | "Vue", 27 | "Server", 28 | "api" 29 | ], 30 | "bugs": { 31 | "url": "https://github.com/SachaSkyhark/Core-Server/issues" 32 | }, 33 | "homepage": "https://www.core-server.io" 34 | } 35 | -------------------------------------------------------------------------------- /@core-server/mail/plugin.json: -------------------------------------------------------------------------------- 1 | { 2 | "classes": { 3 | "Mailer": null, 4 | "ApiEnvironment": "api/ApiEnvironment" 5 | } 6 | } -------------------------------------------------------------------------------- /@core-server/network-tasks/classes/ApiEnvironment.js: -------------------------------------------------------------------------------- 1 | class ApiEnvironment extends SuperClass { 2 | 3 | /** 4 | * Send a task over the network 5 | * @param name {String} 6 | * @param task {Object} 7 | */ 8 | sendTask(name, task) { 9 | return this.siteManager.sendTask(name, task) 10 | } 11 | 12 | } 13 | 14 | module.exports = ApiEnvironment -------------------------------------------------------------------------------- /@core-server/network-tasks/classes/MasterServer.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | const cluster = require('cluster') 3 | 4 | if(!cluster.isMaster) { 5 | module.exports = SuperClass 6 | return 7 | } 8 | 9 | class MasterServer extends SuperClass { 10 | startWorker() { 11 | const worker = super.startWorker() 12 | 13 | if(this.setupNetworkDiscovery()) 14 | this.networkDiscovery.registerWorker(worker) 15 | 16 | return worker 17 | } 18 | 19 | getConfig(name, retry) { 20 | try { 21 | const Path = require('path') 22 | return require(Path.join(process.cwd(), 'config', 'servers.json')) 23 | } catch(e) { 24 | return {} 25 | } 26 | } 27 | 28 | setupNetworkDiscovery() { 29 | if(this.networkDiscovery) 30 | return true 31 | 32 | var discoveryIdentifier = process.options.discovery || process.env.discovery 33 | 34 | if(!discoveryIdentifier) { 35 | const config = this.getConfig('servers') 36 | discoveryIdentifier = config['network-discovery'] 37 | } 38 | 39 | const NetworkDiscovery = plugins.require('network-tasks/NetworkDiscovery') 40 | this.networkDiscovery = NetworkDiscovery.Create(discoveryIdentifier) 41 | return true 42 | } 43 | } 44 | 45 | module.exports = MasterServer -------------------------------------------------------------------------------- /@core-server/network-tasks/classes/NetWorker.js: -------------------------------------------------------------------------------- 1 | const missive = require('missive') 2 | var idIncrement = 0 3 | 4 | class NetWorker { 5 | 6 | constructor(discovery) { 7 | this.threads = 1 8 | this.discovery = discovery 9 | this.disconnectListeners = [] 10 | this.id = idIncrement 11 | 12 | idIncrement++ 13 | } 14 | 15 | equals(obj) { 16 | if(!obj) 17 | return false 18 | 19 | return (obj.id === this.id) 20 | } 21 | 22 | setSocket(socket) { 23 | this.socket = socket 24 | 25 | this.socket.once('close', function() { 26 | this.disconnected() 27 | }.bind(this)) 28 | 29 | const parse = missive.parse() 30 | const encode = missive.encode() 31 | 32 | encode.pipe(socket) 33 | socket.pipe( parse ).on('message', function(obj) { 34 | this.handleMessage( obj ) 35 | }.bind(this)) 36 | 37 | socket.encoder = encode 38 | socket.workerThreads = socket.workerThreads || 0 39 | } 40 | 41 | setWorker(worker) { 42 | this.worker = worker 43 | 44 | this.worker.on('restart', function() { 45 | this.disconnected() 46 | }.bind(this)) 47 | 48 | worker.on('message', function(obj) { 49 | this.handleMessage(obj) 50 | }.bind(this)) 51 | } 52 | 53 | handleMessage(obj) { 54 | if(!obj) 55 | return 56 | 57 | if(obj.event) 58 | this.discovery.emit(obj.event, obj.argv || {}, this) 59 | 60 | if(obj.event === 'threads') 61 | this.onThreads(obj.argv) 62 | } 63 | 64 | send(event, argv) { 65 | try { 66 | const data = { 67 | event: event, 68 | argv: argv 69 | } 70 | 71 | if(this.worker) 72 | this.worker.sendMessage(JSON.stringify(data)) 73 | else 74 | this.socket.encoder.write(data) 75 | } catch(e) { 76 | console.error(e) 77 | } 78 | } 79 | 80 | disconnected() { 81 | for(var key in this.disconnectListeners) { 82 | try { 83 | this.disconnectListeners[key]() 84 | } catch(e) { 85 | console.error(e) 86 | } 87 | } 88 | } 89 | 90 | onDisconnected(cb) { 91 | this.disconnectListeners.push(cb) 92 | /* if(this.worker) 93 | return this.worker.once('restart', cb); 94 | else 95 | return this.socket.once('close', cb);*/ 96 | } 97 | 98 | removeListener(cb) { 99 | 100 | const index = this.disconnectListeners.indexOf(cb) 101 | if(index !== -1) 102 | this.disconnectListeners.slice(index, 1) 103 | 104 | /* if(this.worker) 105 | return this.worker.removeListener('restart', cb); 106 | else 107 | return this.socket.removeListener('close', cb);*/ 108 | } 109 | 110 | onThreads(threads) { 111 | const val = parseInt(threads) 112 | 113 | if(!isNaN(val)) 114 | this.threads = threads 115 | } 116 | 117 | } 118 | 119 | module.exports = NetWorker -------------------------------------------------------------------------------- /@core-server/network-tasks/classes/SiteManager.js: -------------------------------------------------------------------------------- 1 | class SiteManager extends SuperClass { 2 | 3 | constructor(server) { 4 | super(server) 5 | 6 | const NetworkDiscovery = plugins.require('network-tasks/NetworkDiscovery') 7 | this.networkDiscovery = NetworkDiscovery.Create() 8 | this.isMaster = false 9 | 10 | this.updateMasterStatus() 11 | } 12 | 13 | //-------------------------- 14 | 15 | autoSetupFromConfig() { 16 | super.autoSetupFromConfig() 17 | const config = this.getConfig('servers') 18 | 19 | if (config.tasks) { 20 | process.nextTick(() => { 21 | for(var key in config.tasks) 22 | this.registerTaskApi(key, config.tasks[key]) 23 | }) 24 | } 25 | } 26 | 27 | onTask(name, cb) { 28 | return this.networkDiscovery.onTask(name, cb.bind(this)) 29 | } 30 | 31 | registerTaskApi(name, api) { 32 | this.onTask(name, function(params) { 33 | const session = this.sessionsManager.getFromToken('__global__') 34 | return session.api(api, params, '*', {}, {}) 35 | }) 36 | } 37 | 38 | sendTask(name, params) { 39 | return this.networkDiscovery.distributeTask(name, params) 40 | } 41 | 42 | networkBroadcast(event, data) { 43 | return this.networkDiscovery.networkBroadcast(event, data) 44 | } 45 | 46 | onNetworkBroadcast(event, fn) { 47 | this.networkDiscovery.onBroadcast.push({ 48 | event: event, 49 | fn: fn.bind(this) 50 | }) 51 | } 52 | 53 | onceNetworkBroadcast(event, fn) { 54 | this.networkDiscovery.broadcastEvent.once(event, fn.bind(this)) 55 | } 56 | 57 | //-------------------------- 58 | 59 | updateMasterStatus() { 60 | const _this = this 61 | if(!this.networkDiscovery) 62 | return 63 | 64 | this.networkDiscovery.isMaster().then(function(res) { 65 | _this.onMasterStateChanged(res) 66 | 67 | setTimeout(() => { 68 | _this.updateMasterStatus() 69 | }, 5000) 70 | }).catch(function(err) { 71 | console.error(err) 72 | }) 73 | } 74 | 75 | onMasterStateChanged(isMaster) { 76 | if(this.isMaster !== isMaster) { 77 | if(isMaster) 78 | console.log('Node becomes the new master') 79 | else 80 | console.log('Master downgraded to slave status') 81 | } 82 | 83 | this.isMaster = isMaster 84 | } 85 | } 86 | 87 | module.exports = SiteManager -------------------------------------------------------------------------------- /@core-server/network-tasks/plugin.json: -------------------------------------------------------------------------------- 1 | { 2 | "depencies": [ ], 3 | 4 | "classes": { 5 | "MasterServer": "http/MasterServer", 6 | "SiteManager": "http/SiteManager", 7 | "ApiEnvironment": "api/ApiEnvironment", 8 | "Discovery": null, 9 | "AirswarmTls": null, 10 | "NetworkDiscovery": null, 11 | "TasksManager": null, 12 | "NetWorker": null 13 | }, 14 | 15 | "cli": { 16 | "discovery": { 17 | "fake": true, 18 | "description": "Enable the discovery service with a specified identifier" 19 | }, 20 | "discoveryPort": { 21 | "fake": true, 22 | "description": "Port that will be used for the network tasks" 23 | } 24 | } 25 | } -------------------------------------------------------------------------------- /@core-server/redis/classes/SessionsManager.js: -------------------------------------------------------------------------------- 1 | class SessionsManager extends SuperClass { 2 | setupRedis() { 3 | var _this = this 4 | this.siteManager.onRedisBroadcast('SESSION_UPDATE', function(msg) { 5 | if (msg.token && msg.data) 6 | _this.sessionUpdateFromRedis(msg.token, msg.data, msg.time) 7 | }) 8 | } 9 | 10 | sessionUpdateFromRedis(token, data, time) { 11 | try { 12 | if (typeof (data) !== 'object') 13 | console.error('Wrong session data type received from redis (' + typeof (data) + ')') 14 | else if (typeof (token) !== 'string') 15 | console.error('Wrong session token type received from redis (' + typeof (token) + ')') 16 | else { 17 | if (this.sessions[token]) { 18 | if (this.sessions[token].updateTime < time) 19 | this.sessions[token].data = data 20 | } 21 | 22 | if (!isNaN(parseInt(data.auth_id))) { 23 | const auth_id = parseInt(data.auth_id) 24 | 25 | for (var tokenX in this.sessions) { 26 | if (tokenX === token) 27 | continue 28 | 29 | try { 30 | if (parseInt(this.sessions[tokenX].data.auth_id) === auth_id) { 31 | if (this.sessions[tokenX].updateTime < time) 32 | this.sessions[tokenX].data = data 33 | } 34 | } catch (e) { 35 | _console.error(e) 36 | } 37 | } 38 | } 39 | } 40 | } catch (e) { 41 | console.error(e) 42 | } 43 | } 44 | } 45 | 46 | module.exports = SessionsManager -------------------------------------------------------------------------------- /@core-server/redis/classes/SiteManager.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | 3 | class SiteManager extends SuperClass { 4 | autoSetupFromConfig() { 5 | super.autoSetupFromConfig() 6 | const config = this.getConfig('servers') 7 | 8 | if (config.redis) { 9 | const _this = this 10 | process.nextTick(function() { 11 | _this.setupRedis(config.redis) 12 | }) 13 | } 14 | } 15 | 16 | /** 17 | * Setup a redis connection that will be used by the api's 18 | * @param config {Object} 19 | */ 20 | setupRedis(config) { 21 | this.connections = this.connections || {} 22 | 23 | try { 24 | if (config === undefined) 25 | config = this.getConfig('servers').redis 26 | 27 | const Redis = plugins.require('redis/Redis') 28 | 29 | this.connections.redis = new Redis(config) 30 | this.sessionsManager.setupRedis() 31 | 32 | this.onRedisBroadcast('SMBroadcast', ({ api, data, selector }) => { 33 | super.broadcast(api, data, selector) 34 | }) 35 | } catch (e) { 36 | console.error('{setupRedis}', e) 37 | } 38 | } 39 | 40 | broadcast(api, data, selector) { 41 | if(this.connections && this.connections.redis) { 42 | return this.broadcastToRedis('SMBroadcast', { 43 | api, 44 | data, 45 | selector 46 | }) 47 | } 48 | 49 | return super.broadcast(api, data, selector) 50 | } 51 | 52 | /** 53 | * Broadcast a message over a channel using the redis service 54 | * @param channel {String} 55 | * @param msg {String|Object} 56 | */ 57 | broadcastToRedis(channel, msg) { 58 | this.connections = this.connections || {} 59 | 60 | try { 61 | if(!this.connections.redis) { 62 | console.warn('Cannot broadcast redis event, redis server not instantiated') 63 | return 64 | } 65 | 66 | this.connections.redis.emit(channel, msg) 67 | } catch(e) { 68 | console.error('{broadcastToRedis}', e) 69 | } 70 | } 71 | 72 | /** 73 | * Listen to a redis broadcast channel 74 | * @param channel {String} 75 | * @param callback {Function} 76 | */ 77 | onRedisBroadcast(channel, cb) { 78 | this.connections = this.connections || {} 79 | 80 | if (!this.connections.redis) 81 | return console.error('Please instantiate a redis server before listening some broadcast events') 82 | 83 | this.connections.redis.onChannel(channel, cb) 84 | } 85 | 86 | } 87 | 88 | module.exports = SiteManager -------------------------------------------------------------------------------- /@core-server/redis/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@core-server/redis", 3 | "version": "1.0.2", 4 | "description": "", 5 | "main": "index.js", 6 | "scripts": { 7 | "test": "echo \"Error: no test specified\" && exit 1" 8 | }, 9 | "author": "Sacha Vandamme (https://www.core-server.io)", 10 | "license": "MIT", 11 | "dependencies": { 12 | "redis": "^3.1.2" 13 | }, 14 | "engines": { 15 | "node": ">=7.0.0" 16 | }, 17 | "repository": { 18 | "type": "git", 19 | "url": "git+https://github.com/SachaSkyhark/Core-Server.git" 20 | }, 21 | "keywords": [ 22 | "Core-Server", 23 | "Vue", 24 | "Server", 25 | "api" 26 | ], 27 | "bugs": { 28 | "url": "https://github.com/SachaSkyhark/Core-Server/issues" 29 | }, 30 | "homepage": "https://www.core-server.io" 31 | } 32 | -------------------------------------------------------------------------------- /@core-server/redis/plugin.json: -------------------------------------------------------------------------------- 1 | { 2 | "classes": { 3 | "Session": "api/Session", 4 | "SessionsManager": "api/SessionsManager", 5 | "SiteManager": "api/SiteManager", 6 | "Redis": null 7 | } 8 | } -------------------------------------------------------------------------------- /@core-server/sentry/classes/ApiEnvironment.js: -------------------------------------------------------------------------------- 1 | class ApiEnvironment extends SuperClass { 2 | api(name, post) { 3 | this.$req.$sentryTransaction = this.$sentryTransaction 4 | return this.sessionObject.api(name, post || this.post, this.$req) 5 | } 6 | 7 | captureException(error, info = {}) { 8 | if(this.sessionObject.onException) { 9 | info.$sentryTransaction = info.$sentryTransaction || this.$sentryTransaction 10 | info.environment = info.environment || this 11 | info.name = info.name || this.name 12 | 13 | this.sessionObject.onException(error, info) 14 | } 15 | } 16 | } 17 | 18 | module.exports = ApiEnvironment -------------------------------------------------------------------------------- /@core-server/sentry/classes/GraphDb.js: -------------------------------------------------------------------------------- 1 | const Sentry = require("@sentry/node") 2 | 3 | class GraphDB extends SuperClass { 4 | 5 | withResolver(resolver, name) { 6 | const fn = function(parent, args, context, info) { 7 | var transaction 8 | if(context.$sentryTransaction) { 9 | transaction = context.$sentryTransaction.startChild({ 10 | op: "resolve", 11 | description: name, 12 | }) 13 | } else { 14 | transaction = Sentry.startTransaction({ 15 | op: "graphql", 16 | description: name, 17 | name: name, 18 | }) 19 | } 20 | 21 | return resolver.call(this, parent, args, Object.assign({ 22 | $sentryTransaction: transaction, 23 | }, context), info).catch((e) => { 24 | const hasStack = e.stack && e.message && context.session_object && context.session_object.onException 25 | if(hasStack && !(e.extensions && e.extensions.code == 'UNAUTHENTICATED')) { 26 | try { 27 | console.error('error ', context.session.auth_id, context.permissions) 28 | 29 | context.session_object.onException(e, { 30 | graphql: name, 31 | $sentryTransaction: transaction, 32 | context: [ 33 | { 34 | name: 'args', 35 | data: args, 36 | }, 37 | { 38 | name: 'context', 39 | data: { 40 | permissions: context.permissions, 41 | }, 42 | }, 43 | ] 44 | }) 45 | } catch(e) { 46 | console.error(e) 47 | } 48 | } 49 | 50 | throw(e) 51 | }).finally(() => { 52 | transaction.finish() 53 | }) 54 | } 55 | 56 | for(var key in resolver) 57 | fn[key] = resolver[key] 58 | 59 | return fn 60 | } 61 | 62 | } 63 | 64 | module.exports = GraphDB -------------------------------------------------------------------------------- /@core-server/sentry/classes/Session.js: -------------------------------------------------------------------------------- 1 | const Sentry = require("@sentry/node") 2 | const pkg = require(process.cwd() + "/package.json") 3 | // const Tracing = require("@sentry/tracing") 4 | 5 | if(!pkg.sentry || (pkg.sentry.onlyProd && process.env.NODE_ENV != "production")) { 6 | module.exports = SuperClass 7 | return 8 | } 9 | 10 | console.log('Setting up sentry config') 11 | 12 | if(!pkg.sentry.release) 13 | pkg.sentry.release = pkg.version 14 | 15 | if(!pkg.sentry.environment) 16 | pkg.sentry.environment = process.env.SENTRY_ENV || process.env.NODE_ENV || 'development' 17 | 18 | // pkg.sentry.integrations = pkg.sentry.integrations || [ 19 | // new Tracing.Integrations.Mongo({ 20 | // useMongoose: true // Default: false 21 | // }) 22 | // ] 23 | 24 | var sentryConfig = JSON.parse(JSON.stringify(pkg.sentry)); 25 | delete sentryConfig.onlyProd 26 | delete sentryConfig.tags 27 | Sentry.init(sentryConfig) 28 | 29 | /** session */ 30 | class Session extends SuperClass { 31 | 32 | __execApi(apiHandler, environment) { 33 | var transaction 34 | if(environment.$req.$sentryTransaction && !environment.$sentryTransaction) { 35 | transaction = environment.$req.$sentryTransaction.startChild({ 36 | op: "api", 37 | description: apiHandler.name, 38 | }) 39 | } else if(!environment.$sentryTransaction) { 40 | transaction = Sentry.startTransaction({ 41 | op: "api", 42 | description: apiHandler.name, 43 | name: apiHandler.name, 44 | }) 45 | } 46 | 47 | if(!transaction) 48 | return super.__execApi(apiHandler, environment) 49 | 50 | environment.$sentryTransaction = transaction 51 | return super.__execApi(apiHandler, environment).finally(res => { 52 | transaction.finish() 53 | return res 54 | }) 55 | } 56 | 57 | onException(e, info) { 58 | if(e.captured) 59 | return 60 | 61 | e.captured = true 62 | Sentry.withScope(scope => { 63 | if (typeof(pkg.sentry.tags) == "object") { 64 | for (var key in pkg.sentry.tags) { 65 | scope.setTag(key, pkg.sentry.tags[key]) 66 | } 67 | } 68 | 69 | if (info && info.name) 70 | scope.setTag('api', info.name) 71 | 72 | if (info && info.method) 73 | scope.setTag('method', info.method) 74 | else if (info && info.environment && info.environment.$req && info.environment.$req.method) 75 | scope.setTag('method', info.environment.$req.method) 76 | 77 | if (info && info.graphql) 78 | scope.setTag('graphql', info.graphql) 79 | 80 | if (info && info.$sentryTransaction) 81 | scope.setSpan(info.$sentryTransaction) 82 | else if (info && info.environment && info.environment.$sentryTransaction) 83 | scope.setSpan(info.environment.$sentryTransaction) 84 | 85 | if (Array.isArray(e.context) || info.context) { 86 | for (var ctx of (e.context || info.context)) { 87 | if (ctx.name && ctx.data) 88 | scope.setContext(ctx.name, ctx.data) 89 | } 90 | } 91 | 92 | if (typeof(e.tags) == "object") { 93 | for (var key in e.tags) { 94 | scope.setTag(key, e.tags[key]) 95 | } 96 | } 97 | 98 | if(this.data && this.data.auth_id) 99 | scope.setUser({ id: this.data.auth_id }) 100 | 101 | Sentry.captureException(e, scope) 102 | }) 103 | } 104 | 105 | } 106 | 107 | module.exports = Session 108 | -------------------------------------------------------------------------------- /@core-server/sentry/classes/SiteManager.js: -------------------------------------------------------------------------------- 1 | const Sentry = require("@sentry/node") 2 | 3 | class SiteManager extends SuperClass { 4 | 5 | getGraphqlContext(info) { 6 | const tx = Sentry.startTransaction({ 7 | op: "graphql", 8 | description: "graphql", 9 | name: "graphql", 10 | }) 11 | 12 | if(!tx) 13 | return super.getGraphqlContext(info) 14 | 15 | info.res.once('close', () => tx.finish()) 16 | return super.getGraphqlContext(info).then((r) => { 17 | r.$sentryTransaction = tx 18 | const or = r.api 19 | 20 | r.api = (name, post) => { 21 | info.req.$sentryTransaction = tx 22 | return or(name, post) 23 | } 24 | 25 | return r 26 | }) 27 | } 28 | 29 | } 30 | 31 | module.exports = SiteManager -------------------------------------------------------------------------------- /@core-server/sentry/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@core-server/sentry", 3 | "version": "1.2.6", 4 | "description": "", 5 | "private": false, 6 | "main": "index.js", 7 | "author": "Vandamme Sacha (https://www.skyhark.be)", 8 | "license": "MIT", 9 | "scripts": { 10 | "test": "echo \"Error: no test specified\" && exit 1" 11 | }, 12 | "engines": { 13 | "node": ">=7.0.0" 14 | }, 15 | "repository": { 16 | "type": "git", 17 | "url": "git+https://github.com/SachaSkyhark/Core-Server.git" 18 | }, 19 | "keywords": [ 20 | "Core-Server", 21 | "Vue", 22 | "Server", 23 | "sentry" 24 | ], 25 | "bugs": { 26 | "url": "https://github.com/SachaSkyhark/Core-Server/issues" 27 | }, 28 | "homepage": "https://www.core-server.io", 29 | "dependencies": { 30 | "@sentry/node": "6.13.3", 31 | "@sentry/tracing": "6.13.3" 32 | } 33 | } -------------------------------------------------------------------------------- /@core-server/sentry/plugin.json: -------------------------------------------------------------------------------- 1 | { 2 | "classes": { 3 | "Session": "api/Session", 4 | "ApiEnvironment": "api/ApiEnvironment", 5 | "GraphDb": "graphql/GraphDb", 6 | "SiteManager": "graphql/SiteManager" 7 | } 8 | } -------------------------------------------------------------------------------- /@core-server/tests/classes/Environment.js: -------------------------------------------------------------------------------- 1 | const siteManager = plugins.getEntry('http/MasterServer').siteManager 2 | const ApiEnvironment = plugins.require('api/ApiEnvironment') 3 | 4 | module.exports = new ApiEnvironment({ 5 | siteManager: siteManager, 6 | session: { auth_id: 0 }, 7 | sessionObject: null, 8 | cookie: {}, 9 | post: {}, 10 | $get: {}, 11 | file: {}, 12 | client_ip: '' 13 | }) -------------------------------------------------------------------------------- /@core-server/tests/classes/SiteManager.js: -------------------------------------------------------------------------------- 1 | const Mocha = require('mocha') 2 | const fs = require('fs') 3 | const Path = require('path') 4 | 5 | const testFolder = Path.join(process.cwd(), 'tests') 6 | 7 | class SiteManager extends SuperClass { 8 | 9 | constructor(server) { 10 | super(server) 11 | 12 | if(process.options.test !== undefined) { 13 | process.nextTick(() => { 14 | this.executeTests() 15 | }) 16 | } 17 | 18 | } 19 | 20 | executeTests() { 21 | const mocha = new Mocha({}) 22 | 23 | fs.readdirSync(testFolder).forEach(file => { 24 | mocha.files.push(Path.join(testFolder, file)) 25 | }) 26 | 27 | mocha.run(function () { 28 | 29 | // ToDo exit process if with --tests argument 30 | 31 | }) 32 | } 33 | 34 | } 35 | 36 | module.exports = SiteManager -------------------------------------------------------------------------------- /@core-server/tests/plugin.json: -------------------------------------------------------------------------------- 1 | { 2 | "classes": { 3 | "SiteManager": "http/SiteManager", 4 | "Environment": null 5 | } 6 | } -------------------------------------------------------------------------------- /@core-server/vue/additionals/bulkify-watch.js: -------------------------------------------------------------------------------- 1 | const EventEmitter = require('events').EventEmitter 2 | const Path = require('path') 3 | const sane = require('sane') 4 | const minimatch = require("minimatch") 5 | 6 | module.exports = function (b, opts) { 7 | if (!opts) 8 | opts = {} 9 | 10 | var useWatchman = false 11 | try { 12 | const spawn = require("child_process").spawnSync('watchman') 13 | if(!spawn.error) 14 | useWatchman = true 15 | } catch(e) { } 16 | 17 | const sWatch = sane(process.cwd(), { dot: false, watchman: useWatchman }) 18 | var cache = b._options.cache 19 | var pkgcache = b._options.packageCache 20 | 21 | function changeDetected(filepath, root) { 22 | const fullpath = Path.join(root, filepath) 23 | const bulks = BrowserifyRequiredBulks 24 | 25 | for(var key in bulks) { 26 | if(minimatch(fullpath, bulks[key].path)) { 27 | const id = bulks[key].file 28 | if (cache) 29 | delete cache[id] 30 | 31 | if (pkgcache) 32 | delete pkgcache[id] 33 | 34 | // b.emit('file', fullpath); 35 | b.emit('file', id) 36 | b.emit('update', id) 37 | } 38 | } 39 | } 40 | 41 | sWatch.on('add', changeDetected) 42 | sWatch.on('delete', changeDetected) 43 | 44 | return b 45 | } -------------------------------------------------------------------------------- /@core-server/vue/additionals/bulkify.js: -------------------------------------------------------------------------------- 1 | var staticModule = require('static-module') 2 | var path = require('path') 3 | var through = require('through2') 4 | var bulk = require('bulk-require') 5 | var concat = require('concat-stream') 6 | 7 | global.BrowserifyRequiredBulks = [] 8 | 9 | module.exports = function (file, opts) { 10 | if (/\.json$/.test(file)) 11 | return through() 12 | 13 | if (!opts) 14 | opts = {} 15 | 16 | var filedir = path.dirname(file) 17 | var vars = opts.vars || { 18 | __filename: file, 19 | __dirname: filedir 20 | } 21 | 22 | const Requires = [] 23 | 24 | function bulkRequire (dir, globs, opts) { 25 | var stream = through() 26 | var res = bulk(dir, globs, { 27 | index: opts && opts.index, 28 | require: function (x) { 29 | if (!file) 30 | return path.resolve(x) 31 | 32 | var r = path.relative(filedir, x) 33 | return /^\./.test(r) ? r : './' + r 34 | } 35 | }) 36 | stream.push(walk(res, opts)) 37 | stream.push(null) 38 | 39 | BrowserifyRequiredBulks.push({ 40 | file: file, 41 | path: path.normalize(dir) + globs 42 | }) 43 | 44 | return stream 45 | } 46 | 47 | var sm = staticModule( 48 | { 'bulk-require': bulkRequire }, 49 | { vars: vars, varModules: { path: path } } 50 | ) 51 | 52 | return through(function (buf, enc, next) { 53 | sm.write(buf) 54 | sm.end() 55 | sm.pipe(concat(function (output) { 56 | next(null, output) 57 | })) 58 | }) 59 | } 60 | 61 | function walk (obj, opts) { 62 | if (!opts) 63 | opts = {} 64 | 65 | opts.index = opts.index === false ? false : true 66 | if (typeof obj === 'string') { 67 | return 'require(' + JSON.stringify(obj) + ')' 68 | } else if (obj && typeof obj === 'object' && obj.index && opts.index) { 69 | return '(function () {' 70 | + 'var f = ' + walk(obj.index) + ';' 71 | + Object.keys(obj).map(function (key) { 72 | return 'f[' + JSON.stringify(key) + ']=' + walk(obj[key], opts) + ';' 73 | }).join('') 74 | + 'return f;' 75 | + '})()' 76 | 77 | } else if (obj && typeof obj === 'object') { 78 | return '({' + Object.keys(obj).map(function (key) { 79 | return JSON.stringify(key) + ':' + walk(obj[key], opts) 80 | }).join(',') + '})' 81 | } else 82 | throw new Error('unexpected object in bulk-require result: ' + obj) 83 | } -------------------------------------------------------------------------------- /@core-server/vue/additionals/snapshotRequire.js: -------------------------------------------------------------------------------- 1 | const EventEmitter = require('events').EventEmitter 2 | const through = require('through2') 3 | const fs = require('fs') 4 | 5 | module.exports = function (bundle, opts) { 6 | if (!opts) 7 | opts = {} 8 | 9 | const em = new EventEmitter() 10 | 11 | bundle.pipeline.get('record').push(through.obj(function (row, enc, next) { 12 | if(!row.file) 13 | return next(null, row) 14 | 15 | if(row.file.substr(0, 10) !== '/snapshot/') 16 | return next(null, row) 17 | 18 | this.push({ 19 | entry: row.entry, 20 | expose: row.expose, 21 | basedir: row.basedir, 22 | file: row.file, 23 | id: row.id, 24 | source: fs.readFileSync(row.file), 25 | order: row.order 26 | }) 27 | 28 | next(null) 29 | }, 30 | function (next, row) { 31 | next() 32 | })) 33 | 34 | return em 35 | } 36 | -------------------------------------------------------------------------------- /@core-server/vue/additionals/vue-server-renderer/custom/utils.js: -------------------------------------------------------------------------------- 1 | module.exports.makeMap = function makeMap ( str, expectsLowerCase ) { 2 | var map = Object.create(null) 3 | var list = str.split(',') 4 | for (var i = 0; i < list.length; i++) { 5 | map[list[i]] = true 6 | } 7 | return expectsLowerCase 8 | ? function (val) { 9 | return map[val.toLowerCase()] 10 | } 11 | : function (val) { 12 | return map[val] 13 | } 14 | } 15 | 16 | module.exports.extend = function extend (to, _from) { 17 | for (var key in _from) { 18 | to[key] = _from[key] 19 | } 20 | return to 21 | } -------------------------------------------------------------------------------- /@core-server/vue/additionals/vue-server-renderer/index.js: -------------------------------------------------------------------------------- 1 | try { 2 | var vueVersion = require('vue').version 3 | } catch (e) {} 4 | 5 | var packageName = require('./package.json').name 6 | var packageVersion = require('./package.json').version 7 | if (vueVersion && vueVersion !== packageVersion) { 8 | throw new Error( 9 | '\n\nVue packages version mismatch:\n\n' + 10 | '- vue@' + vueVersion + '\n' + 11 | '- ' + packageName + '@' + packageVersion + '\n\n' + 12 | 'This may cause things to work incorrectly. Make sure to use the same version for both.\n' 13 | ) 14 | } 15 | 16 | module.exports = require('./build') 17 | -------------------------------------------------------------------------------- /@core-server/vue/additionals/vue-server-renderer/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "_from": "vue-server-renderer", 3 | "_id": "vue-server-renderer@2.5.9", 4 | "_inBundle": false, 5 | "_integrity": "sha512-YSR5hERVSr48w9MsxflyAx6RSJjDGkUQXEwdZ5mtWAIOzhC5XqLzOuarMLUpzBUvWK8KPbbJ5yk+MFeKMOwaZg==", 6 | "_location": "/vue-server-renderer", 7 | "_phantomChildren": {}, 8 | "_requested": { 9 | "type": "tag", 10 | "registry": true, 11 | "raw": "vue-server-renderer", 12 | "name": "vue-server-renderer", 13 | "escapedName": "vue-server-renderer", 14 | "rawSpec": "", 15 | "saveSpec": null, 16 | "fetchSpec": "latest" 17 | }, 18 | "_requiredBy": [ 19 | "#USER", 20 | "/" 21 | ], 22 | "_resolved": "https://registry.npmjs.org/vue-server-renderer/-/vue-server-renderer-2.5.9.tgz", 23 | "_shasum": "936e42ba9a8d31ada2da36f29b7386c787908489", 24 | "_spec": "vue-server-renderer", 25 | "_where": "/Users/sachavandamme/Documents/projects/servers/core-server-docs/vue-acc", 26 | "author": { 27 | "name": "Evan You" 28 | }, 29 | "bugs": { 30 | "url": "https://github.com/vuejs/vue/issues" 31 | }, 32 | "bundleDependencies": false, 33 | "dependencies": { 34 | "chalk": "^1.1.3", 35 | "hash-sum": "^1.0.2", 36 | "he": "^1.1.0", 37 | "lodash.template": "^4.4.0", 38 | "lodash.uniq": "^4.5.0", 39 | "resolve": "^1.2.0", 40 | "serialize-javascript": "^4.0.0", 41 | "source-map": "0.5.6" 42 | }, 43 | "deprecated": false, 44 | "description": "server renderer for Vue 2.0", 45 | "devDependencies": { 46 | "vue": "file:../.." 47 | }, 48 | "homepage": "https://github.com/vuejs/vue/tree/dev/packages/vue-server-renderer#readme", 49 | "keywords": [ 50 | "vue", 51 | "server", 52 | "ssr" 53 | ], 54 | "license": "MIT", 55 | "main": "index.js", 56 | "name": "vue-server-renderer", 57 | "repository": { 58 | "type": "git", 59 | "url": "git+https://github.com/vuejs/vue.git" 60 | }, 61 | "types": "types/index.d.ts", 62 | "version": "2.5.9" 63 | } 64 | -------------------------------------------------------------------------------- /@core-server/vue/additionals/watchify-cache.js: -------------------------------------------------------------------------------- 1 | const EventEmitter = require('events').EventEmitter 2 | const fs = require('fs') 3 | const cluster = require('cluster') 4 | 5 | function save(b, opts) { 6 | const file = b._options.cacheFile 7 | const cache = { 8 | cache: b._options.cache, 9 | package: b._options.packageCache, 10 | styles: b._options.stylesCache 11 | } 12 | 13 | fs.writeFileSync(file, JSON.stringify(cache)) 14 | } 15 | 16 | module.exports = function (b, opts) { 17 | if (!opts) 18 | opts = {} 19 | 20 | const em = new EventEmitter() 21 | 22 | var timeout = null 23 | 24 | b.once('bundle', function() { 25 | for(var key in b._options.cache) { 26 | b.emit('file', key) 27 | } 28 | 29 | b.on('file', function() { 30 | if(timeout !== null) 31 | clearTimeout(timeout) 32 | 33 | timeout = setTimeout(function() { 34 | save(b, opts) 35 | }, 1500) 36 | }) 37 | }) 38 | 39 | return em 40 | } 41 | 42 | function rm(cache, file) { 43 | delete cache.cache[file] 44 | 45 | if(cache.package[file]) 46 | delete cache.package[file] 47 | 48 | if(cache.styles[file]) 49 | delete cache.styles[file] 50 | } 51 | 52 | function verifyCache(cache, file) { 53 | const fileTime = (new Date(fs.statSync(file).mtime)).getTime() 54 | 55 | for(var key in cache.cache) { 56 | if(key.substr(0, 10) === '/snapshot/') 57 | continue 58 | 59 | try { 60 | const time = (new Date(fs.statSync(key).mtime)).getTime() 61 | 62 | if(time > fileTime) 63 | rm(cache, key) 64 | } catch(e) { 65 | rm(cache, key) 66 | } 67 | } 68 | } 69 | 70 | function verifyDeps(obj, existingFiles, notExisintg) { 71 | const add = [] 72 | 73 | for(var key in obj.deps) { 74 | const path = obj.deps[key] 75 | 76 | if(existingFiles.indexOf(path) !== -1) 77 | continue 78 | 79 | if(notExisintg.indexOf(path) !== -1) 80 | return false 81 | 82 | if(fs.existsSync(path)) { 83 | existingFiles.push(path) 84 | } else { 85 | notExisintg.push(path) 86 | return false 87 | } 88 | } 89 | 90 | return true 91 | } 92 | 93 | module.exports.getCache = function(file) { 94 | var cache = { 95 | cache: {}, 96 | package: {}, 97 | styles: {} 98 | } 99 | 100 | if(fs.existsSync(file) && !cluster.isMaster) { 101 | const cache2 = require(file) 102 | cache = { 103 | cache: cache2.cache || {}, 104 | package: cache2.package || {}, 105 | styles: cache2.styles || {} 106 | } 107 | 108 | try { 109 | verifyCache(cache, file) 110 | 111 | var existingFiles = Object.keys(cache.cache) 112 | var notExisintg = [] 113 | 114 | for(var name in cache.cache) { 115 | if(!verifyDeps(cache.cache[name], existingFiles, notExisintg)) { 116 | rm(cache, name) 117 | } 118 | } 119 | } catch(e) { 120 | console.error(e) 121 | 122 | cache.cache = {} 123 | cache.package = {} 124 | cache.styles = {} 125 | } 126 | } 127 | 128 | return cache 129 | } -------------------------------------------------------------------------------- /@core-server/vue/classes/MasterServer.js: -------------------------------------------------------------------------------- 1 | const cluster = require('cluster') 2 | 3 | if(cluster.isWorker) { 4 | module.exports = SuperClass 5 | return 6 | } 7 | 8 | var BundleStarted = false 9 | 10 | class MasterServer extends SuperClass { 11 | 12 | constructor(config) { 13 | super(config) 14 | 15 | if(process.env.NODE_ENV === 'development' && process.options['disable-ui'] === undefined) 16 | this.startVueBundler() 17 | } 18 | 19 | startVueBundler() { 20 | if(BundleStarted) 21 | return 22 | 23 | function spawn(mode) { 24 | const worker = new SuperClass.Worker({ 25 | cli: JSON.stringify({ 26 | bundle: mode, 27 | hot: true 28 | }), 29 | NODE_ENV: process.env.NODE_ENV 30 | }) 31 | 32 | return worker 33 | } 34 | 35 | this.clientWorker = spawn('client') 36 | this.serverWorker = spawn('server') 37 | 38 | this.clientWorker.worker.on('message', function(msg) { 39 | if (msg.SocketServer && msg.method && msg.data) { 40 | for (var key in cluster.workers) { 41 | if (cluster.workers[key].id !== msg.SocketServer) 42 | cluster.workers[key].send(msg) 43 | } 44 | } 45 | }) 46 | } 47 | 48 | } 49 | 50 | module.exports = MasterServer -------------------------------------------------------------------------------- /@core-server/vue/classes/Resources/CacheStream.js: -------------------------------------------------------------------------------- 1 | const Stream = require('stream') 2 | 3 | class CacheStream extends Stream.Stream { 4 | constructor(inputStream) { 5 | super({}) 6 | 7 | this.writable = true 8 | this.readable = false 9 | 10 | this._buffers = [] 11 | this._dests = [] 12 | this._ended = false 13 | 14 | inputStream.pipe(this) 15 | 16 | inputStream.once('readable', () => { 17 | this.readable = true 18 | this.emit('readable', this) 19 | }) 20 | 21 | inputStream.on('error', (err) => { 22 | this.emit('error', err) 23 | }) 24 | } 25 | 26 | write(buffer) { 27 | this._buffers.push(buffer) 28 | // this.emit('readable', this); 29 | 30 | this._dests.forEach(function(dest) { 31 | if(!dest.$_readable) { 32 | dest.$_readable = true 33 | dest.emit('readable', dest) 34 | } 35 | 36 | dest.write(buffer) 37 | }) 38 | } 39 | 40 | pipe(dest, options) { 41 | if (options) 42 | throw Error('StreamCache#pipe: options are not supported yet.') 43 | 44 | try { 45 | if(this._buffers.length > 0) { 46 | dest.$_readable = true 47 | dest.emit('readable', this) 48 | 49 | if(this._buffers.length > 1) { 50 | this._buffers = [Buffer.concat(this._buffers)] 51 | } 52 | 53 | if (this._ended) 54 | return dest.end(this._buffers[0]) 55 | 56 | dest.write(this._buffers[0]) 57 | } 58 | 59 | if (this._ended) { 60 | dest.end() 61 | return dest 62 | } 63 | 64 | this._dests.push(dest) 65 | } catch(e) { 66 | console.error(e) 67 | } 68 | 69 | return dest 70 | } 71 | 72 | getLength() { 73 | return this._buffers.reduce(function(totalLength, buffer) { 74 | return totalLength + buffer.length 75 | }, 0) 76 | } 77 | 78 | end() { 79 | this._dests.forEach(function(dest) { 80 | try { 81 | dest.end() 82 | } catch(e) { 83 | console.error(e) 84 | } 85 | }) 86 | 87 | this._ended = true 88 | this._dests = [] 89 | } 90 | } 91 | 92 | module.exports = CacheStream 93 | 94 | //-------------------------------- 95 | /* 96 | class Test 97 | { 98 | 99 | fromFile(name) 100 | { 101 | const fs = require('fs'); 102 | var raw = fs.createReadStream(name); 103 | 104 | const stream = new CacheStream(raw); 105 | 106 | stream.pipe(process.stdout); 107 | } 108 | 109 | } 110 | 111 | const test = new Test(); 112 | 113 | test.fromFile(__dirname + '/cacheObject.js');*/ -------------------------------------------------------------------------------- /@core-server/vue/classes/Session.js: -------------------------------------------------------------------------------- 1 | const RenderCache = plugins.require('vue/RenderCache') 2 | 3 | class Session extends SuperClass { 4 | 5 | getComponentsCache() { 6 | if(!this.componentsCache) { 7 | this.componentsCache = new RenderCache(this) 8 | } 9 | 10 | return this.componentsCache 11 | } 12 | 13 | } 14 | 15 | module.exports = Session -------------------------------------------------------------------------------- /@core-server/vue/classes/SiteManager.js: -------------------------------------------------------------------------------- 1 | const helmet = require('helmet') 2 | const ResourceManager = plugins.require('http/Resources/Manager') 3 | 4 | class SiteManager extends SuperClass { 5 | 6 | constructor(httpServer) { 7 | super(httpServer) 8 | 9 | this.resourceManager = new ResourceManager(this) 10 | this._helmet = helmet() 11 | this.pagesCache = {} 12 | const _this = this 13 | 14 | process.nextTick(() => { 15 | const PagesManager = plugins.require('vue/PagesManager') 16 | _this.pagesManager = new PagesManager(_this) 17 | }) 18 | } 19 | 20 | //------------------------------------------ 21 | 22 | /** 23 | * Remove an object from the CDN and locally memory 24 | * @param file_name {String} 25 | */ 26 | purgeCache(name) { 27 | try { 28 | if (process.env.NODE_ENV !== 'production') 29 | console.warn('Clearing cache for resource', name) 30 | 31 | const object = this.resourceManager.getObject('/' + name) 32 | if (object) 33 | object.purge() 34 | } catch (e) { 35 | console.error(e) 36 | } 37 | } 38 | 39 | preHandle(req, res, prePath) { 40 | const preHandle = this.resourceManager.handle(req, res, prePath) 41 | if (preHandle === true) 42 | return true 43 | 44 | return false 45 | } 46 | 47 | sendErrorPage(code, req, res) { 48 | if(this.pagesManager) 49 | return this.pagesManager.handleError(code, req, res).catch(function(err) { 50 | console.error(err) 51 | }) 52 | else 53 | return super.sendErrorPage(code, req, res) 54 | } 55 | 56 | handleVueJs(req, res) { 57 | try { 58 | if(!this.pagesManager) { 59 | 60 | if(!disableForce) { 61 | process.nextTick(() => { 62 | _this.handle(req, res, true) 63 | }) 64 | } else { 65 | console.error('PagesManager not found') 66 | this.sendErrorPage(500, req, res) 67 | } 68 | 69 | return true 70 | } 71 | 72 | //----------------------------------------------------------------- 73 | 74 | var index = req.url.indexOf('?') 75 | var url = index >= 0 ? req.url.substr(0, index) : req.url 76 | 77 | const _this = this 78 | function handle() { 79 | if(this.pagesCache[url] && process.env.NODE_ENV === 'production') { 80 | const r = this.pagesCache[url] 81 | 82 | res.writeHead(r.httpCode || 200, { 'Content-Type': 'text/html; charset=utf-8' }) 83 | res.end(r.html) 84 | return 85 | } 86 | 87 | this.pagesManager.handleRequest(req, res).then((r) => { 88 | this.pagesCache[url] = r 89 | }).catch(function(err) { 90 | console.error(err) 91 | }) 92 | } 93 | 94 | if(res._headerSent) { 95 | handle.call(this) 96 | } else { 97 | this._helmet(req, res, () => { 98 | handle.call(this) 99 | }) 100 | } 101 | } catch (e) { 102 | console.error(e) 103 | this.sendErrorPage(500, req, res) 104 | } 105 | } 106 | 107 | handle(req, res, disableForce) { 108 | try { 109 | if(!super.handle(req, res)) { 110 | this.handleVueJs(req, res) 111 | } 112 | } catch (e) { 113 | console.error(e) 114 | this.sendErrorPage(500, req, res) 115 | } 116 | 117 | return true 118 | } 119 | } 120 | 121 | module.exports = SiteManager -------------------------------------------------------------------------------- /@core-server/vue/classes/hmr/has.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | 3 | function has(object, propName) { 4 | return Object.prototype.hasOwnProperty.call(object, propName) 5 | } 6 | module.exports = has 7 | -------------------------------------------------------------------------------- /@core-server/vue/classes/hmr/str-set.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | 3 | var has = require('./has') 4 | 5 | function StrSet(other) { 6 | this._map = {} 7 | this._size = 0 8 | if (other) { 9 | for (var i=0,len=other.length; i { 44 | if (code !== 0) 45 | process.exit(code) 46 | }) 47 | 48 | cluster.fork({ cli: JSON.stringify({ build: 'client', production: true }) }) 49 | cluster.fork({ cli: JSON.stringify({ build: 'server', production: true }) }) 50 | } 51 | 52 | return false 53 | } -------------------------------------------------------------------------------- /@core-server/vue/cli/bundle.js: -------------------------------------------------------------------------------- 1 | // const cluster = require('cluster'); 2 | const chalk = require('chalk') 3 | const subConsole = console.create('Bundle') 4 | 5 | const PagesManager = plugins.require('vue/PagesManager') 6 | 7 | module.exports = function(value, cb) { 8 | if(value === undefined || value === null) 9 | value = 'client' 10 | 11 | // if (cluster.isMaster) 12 | subConsole.info('Starting bundle in environment:', chalk.bold(process.env.NODE_ENV + '-' + value), 'for', value, 'use') 13 | 14 | var serverStart = Date.now() 15 | 16 | try { 17 | PagesManager.compile(value, function() { 18 | subConsole.info(value.substr(0,1).toUpperCase() + value.substr(1), 'bundle done (' + (Date.now() - serverStart) + ' ms)') 19 | 20 | if(cb) 21 | cb() 22 | }) 23 | .on('bundle', function() { 24 | serverStart = Date.now() 25 | }) 26 | } catch(e) { 27 | subConsole.error(e) 28 | } 29 | 30 | return false 31 | } -------------------------------------------------------------------------------- /@core-server/vue/modules-www/client/entry.js: -------------------------------------------------------------------------------- 1 | import { initApp, initGlobalApp } from '../common/init.js'; 2 | import api from './apiManager.js'; 3 | /*import Raven from 'raven-js'; 4 | import RavenVue from 'raven-js/plugins/vue'; 5 | 6 | if(process.env.NODE_ENV === 'production' && InitReq.getRavenKey) 7 | { 8 | Raven 9 | .config(InitReq.getRavenKey()) 10 | .addPlugin(RavenVue, Vue) 11 | .install(); 12 | }*/ 13 | 14 | const options = { 15 | apiManager: api 16 | }; 17 | 18 | initGlobalApp(options); 19 | 20 | const app = initApp(options); 21 | 22 | if(app.$store && window.STATE) 23 | app.$store.replaceState(window.STATE); 24 | 25 | app.$mount('#app'); -------------------------------------------------------------------------------- /@core-server/vue/modules-www/common/init.js: -------------------------------------------------------------------------------- 1 | import Router from 'vue-router'; 2 | import Meta from 'vue-meta'; 3 | import serializeProperties from './pageProperties'; 4 | import Storage from './storage.js'; 5 | 6 | var options = {}; 7 | var errorComponent = null; 8 | const routes = []; 9 | 10 | Vue.use(Router); 11 | Vue.use(Meta); 12 | Vue.use(Storage); 13 | 14 | //------------------------------------------------------------------ 15 | 16 | function registerComponent(name, component) 17 | { 18 | if(options.onComponent) 19 | options.onComponent(name, component); 20 | 21 | var componentRoutes = []; 22 | 23 | if(name.substr(name.length-7) === '-layout') 24 | { 25 | const meta = {}; 26 | 27 | if(component.permissions) 28 | meta.permissions = component.permissions; 29 | if(component.permissionsRedirect) 30 | meta.permissionsRedirect = component.permissionsRedirect; 31 | 32 | var page = name.substr(0, name.length-7); 33 | name = 'page-'+page; 34 | 35 | const config = { 36 | path: '/' + page, 37 | component: Vue.component('page-'+page, component), 38 | meta: meta 39 | }; 40 | 41 | if(page === 'error' || page === '404') 42 | errorComponent = config.component; 43 | else if(page === 'home' && errorComponent === null) 44 | errorComponent = config.component; 45 | 46 | if(page === 'home') 47 | config.path = '/'; 48 | 49 | const ser = serializeProperties(component); 50 | 51 | if(ser.length === 0) 52 | { 53 | routes.push(config); 54 | componentRoutes.push(config); 55 | } 56 | 57 | for(var key in ser) 58 | { 59 | const r = { 60 | path: '/' + page + ser[key], 61 | component: config.component, 62 | meta: meta, 63 | props: true 64 | }; 65 | 66 | componentRoutes.push(r); 67 | routes.push(r); 68 | } 69 | } 70 | else 71 | { 72 | if(name.substr(0, 6) === 'tools-') 73 | name = name.substr(6); 74 | 75 | Vue.component(name, component); 76 | } 77 | 78 | return { 79 | routes: componentRoutes 80 | } 81 | } 82 | 83 | function checkRoutePermission(to, from, next) { 84 | 85 | if (process.env.VUE_ENV !== 'client' || !to.meta) 86 | return next(); 87 | 88 | const manager = options.apiManager.permissionsManager; 89 | if (!manager) 90 | return next(); 91 | 92 | if(!manager.layoutAuthorized( to.meta )) 93 | return next({ path: manager.layoutRedirectPath( to.meta ) }); 94 | 95 | next(); 96 | } 97 | 98 | export function mergePost(post, api, apiManager, force) 99 | { 100 | if(InitReq.getDefaultPost) 101 | { 102 | const npost = InitReq.getDefaultPost.call(apiManager, api, post); 103 | 104 | for(var key in npost) 105 | { 106 | if(post[key] === undefined || force) 107 | post[key] = npost[key]; 108 | } 109 | } 110 | 111 | return post; 112 | } 113 | 114 | export function initGlobalApp(_options) { 115 | options = _options || {}; 116 | 117 | InitReq.setupEnvironment( _options.apiManager, _options.apiManager.isClient ); 118 | InitReq.initComponents( registerComponent ); 119 | 120 | if(errorComponent !== null) 121 | routes.push({ path: '*', component: errorComponent, meta: { httpCode: 404 } }); 122 | 123 | Vue.use(_options.apiManager); 124 | } 125 | 126 | export function initApp( _options ) 127 | { 128 | const router = new Router({ 129 | mode: 'history', 130 | abstract: true, 131 | scrollBehavior: function(to, from, savedPosition) { 132 | if (to.hash) { 133 | return {selector: to.hash} 134 | } else { 135 | return { x: 0, y: 0 } 136 | } 137 | }, 138 | routes 139 | }); 140 | 141 | router.beforeEach(checkRoutePermission); 142 | 143 | const app = InitReq.getApp(router, _options.apiManager.isClient); 144 | 145 | return new Vue( 146 | Vue.util.extend({ 147 | //i18n, 148 | router: router, 149 | api: _options.apiManager 150 | }, app) 151 | ); 152 | } -------------------------------------------------------------------------------- /@core-server/vue/modules-www/common/merger.js: -------------------------------------------------------------------------------- 1 | 2 | function vueMerge(vueObject, nData) 3 | { 4 | try 5 | { 6 | if(vueObject.initialData == undefined) 7 | vueObject.initialData = JSON.parse(JSON.stringify(vueObject._data)); 8 | 9 | if(nData instanceof Array) 10 | nData = { items: nData }; 11 | if(nData.push) //SSR 12 | nData = { items: nData }; 13 | 14 | //Analyse simple properties 15 | for(var key in nData) 16 | { 17 | if(vueObject[key] != nData[key] && vueObject[key] !== undefined) 18 | { 19 | Vue.set(vueObject, key, nData[key]); 20 | } 21 | } 22 | 23 | if(nData.items instanceof Array) 24 | { 25 | if(nData.items.length === 1 && !Array.isArray(vueObject.items)) 26 | { 27 | nData = nData.items[0]; 28 | 29 | for(var key in nData) 30 | { 31 | if(vueObject[key] != nData[key] && vueObject[key] !== undefined) 32 | { 33 | Vue.set(vueObject, key, nData[key]); 34 | } 35 | } 36 | 37 | if(vueObject.info instanceof Object) 38 | { 39 | vueObject.info = nData; 40 | } 41 | } 42 | } 43 | 44 | vueObject.$forceUpdate(); 45 | } 46 | catch(e) 47 | { 48 | console.error(e); 49 | } 50 | 51 | return vueObject; 52 | } 53 | 54 | export default vueMerge; -------------------------------------------------------------------------------- /@core-server/vue/modules-www/common/pageProperties.js: -------------------------------------------------------------------------------- 1 | export default function serializeProperites(component) 2 | { 3 | const props = {}; 4 | 5 | function addProps(p) 6 | { 7 | for(var key in p) 8 | props[key] = p[key]; 9 | } 10 | 11 | function addMixin(mixin) 12 | { 13 | for(var key in mixin) 14 | { 15 | if(key === 'mixins') 16 | { 17 | const mixins = mixin[key]; 18 | for(var x in mixins) 19 | { 20 | addMixin(mixins[x]); 21 | } 22 | } 23 | else if(key === 'props') 24 | { 25 | addProps(mixin[key]); 26 | } 27 | } 28 | } 29 | 30 | addMixin(component); 31 | 32 | const routes = []; 33 | var mandatory = true; 34 | var path = ''; 35 | 36 | for(var key in props) 37 | { 38 | if(props[key].urlProp === false) 39 | continue; 40 | 41 | if(typeof(key) !== 'string') 42 | { 43 | path += '/:' + props[key]; 44 | } 45 | else 46 | { 47 | if((props[key].default !== undefined && props[key].default !== null) || props[key].required === false) 48 | routes.push(path); 49 | 50 | path += '/:' + key; 51 | } 52 | } 53 | 54 | if(routes.length === 0 && path === '') 55 | return routes; 56 | 57 | routes.push(path); 58 | return routes; 59 | } -------------------------------------------------------------------------------- /@core-server/vue/modules-www/common/sha1.js: -------------------------------------------------------------------------------- 1 | function SHA1(a) { 2 | function b(a,b) { 3 | return a<>>32-b 4 | }function d(a) { 5 | var c,d,b="";for(c=7;c>=0;c--) 6 | d=a>>>4*c&15,b+=d.toString(16);return b 7 | }function e(a) { 8 | a=a.replace(/\r\n/g,"\n");for(var b="",c=0;c127&&d<2048?(b+=String.fromCharCode(d>>6|192),b+=String.fromCharCode(63&d|128)):(b+=String.fromCharCode(d>>12|224),b+=String.fromCharCode(d>>6&63|128),b+=String.fromCharCode(63&d|128)) 10 | }return b 11 | }var f,g,h,o,p,q,r,s,t,i=new Array(80),j=1732584193,k=4023233417,l=2562383102,m=271733878,n=3285377520;a=e(a);var u=a.length,v=new Array;for(g=0;g>>29),v.push(u<<3&4294967295),f=0;f { 51 | const app = initApp(options); 52 | 53 | api.ctx = ctx; 54 | app.$router.push(ctx.url); 55 | 56 | return Promise.all( // initialize components 57 | app.$router.getMatchedComponents().map(c => c.prefetch ? c.prefetch.call(app) : null) 58 | ).then(() => { 59 | if(app.$store) 60 | ctx.state = app.$store.state; // set initial state 61 | 62 | ctx.routeMeta = app.$route.meta; 63 | ctx.httpCode = app.$route.meta.httpCode || 200; 64 | }).then(() => { 65 | const metatags = app.$meta(); 66 | 67 | ctx.meta = { inject: function () { 68 | const injected = metatags.inject(); 69 | 70 | for(var key in injected) { 71 | if(injected[key].text && key.indexOf('__') === -1) 72 | this[key] = injected[key].text(); 73 | } 74 | }} 75 | 76 | return app; 77 | }); 78 | }; 79 | -------------------------------------------------------------------------------- /@core-server/vue/modules-www/template.html: -------------------------------------------------------------------------------- 1 | {{ meta.inject() }} 2 | 3 | 4 | 5 | 6 | 7 | 8 | {{{ meta.title }}} 9 | {{{ meta.meta }}} 10 | {{{ meta.link }}} 11 | {{{ meta.base }}} 12 | {{{ meta.style }}} 13 | {{{ meta.noscript }}} 14 | {{{ meta.httpCode && meta.httpCode !== 200 && meta.httpCode !== 404 ? `` : '' }}} 15 | 16 | 17 | 18 | 19 | {{{ meta.script }}} 20 | 21 | 22 | -------------------------------------------------------------------------------- /@core-server/vue/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@core-server/vue", 3 | "version": "1.0.6", 4 | "description": "", 5 | "main": "index.js", 6 | "scripts": { 7 | "test": "echo \"Error: no test specified\" && exit 1" 8 | }, 9 | "author": "Sacha Vandamme (https://www.core-server.io)", 10 | "license": "MIT", 11 | "dependencies": { 12 | "babelify": "10.0.0", 13 | "browserify": "14.4.0", 14 | "bulk-require": "1.0.1", 15 | "clean-css": "^5.1.5", 16 | "concat-stream": "1.6.0", 17 | "convert-source-map": "1.5.0", 18 | "cssnano": "^5.0.7", 19 | "envify": "4.1.0", 20 | "helmet": "^3.21.2", 21 | "lodash": "^4.17.21", 22 | "lru-cache": "4.1.1", 23 | "minimatch": "3.0.4", 24 | "node-sass": "^6.0.1", 25 | "postcss": "6.0.12", 26 | "postcss-selector-parser": "2.2.3", 27 | "rsvp": "4.0.1", 28 | "sane": "^5.0.1", 29 | "sockjs-client": "1.1.4", 30 | "source-map": "0.5.7", 31 | "static-module": "^3.0.4", 32 | "synchd": "1.0.2", 33 | "through2": "2.0.3", 34 | "uglify-es": "3.1.2", 35 | "vue": "2.6.11", 36 | "vue-meta": "2.3.2", 37 | "vue-server-renderer": "^2.6.14", 38 | "vue-template-compiler": "2.6.11", 39 | "watchify": "^4.0.0" 40 | }, 41 | "engines": { 42 | "node": ">=7.0.0" 43 | }, 44 | "repository": { 45 | "type": "git", 46 | "url": "git+https://github.com/SachaSkyhark/Core-Server.git" 47 | }, 48 | "keywords": [ 49 | "Core-Server", 50 | "Vue", 51 | "Server", 52 | "api" 53 | ], 54 | "bugs": { 55 | "url": "https://github.com/SachaSkyhark/Core-Server/issues" 56 | }, 57 | "homepage": "https://www.core-server.io" 58 | } 59 | -------------------------------------------------------------------------------- /@core-server/vue/plugin.json: -------------------------------------------------------------------------------- 1 | { 2 | "classes": { 3 | "MasterServer": "http/MasterServer", 4 | "SiteManager": "http/SiteManager", 5 | "Session": "api/Session", 6 | "Resources/Manager": null, 7 | "Resources/CacheObject": null, 8 | "Resources/CacheStream": null, 9 | "PagesManager": null, 10 | "RenderCache": null, 11 | "hmr/socket-server": null, 12 | "hmr/index": null 13 | }, 14 | 15 | "cli": { 16 | "build": "build the full bundle for production", 17 | "bundle": "[client|server] bundle the sources for a server or client environment", 18 | "hot": { 19 | "fake": true, 20 | "description": "Enable bundle hot compile mode" 21 | }, 22 | "disable-ui": { 23 | "fake": true, 24 | "description": "Disable the ui while running the core-server" 25 | } 26 | } 27 | } -------------------------------------------------------------------------------- /@core-server/vue/vueify/LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2014-2016 Evan You 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in 13 | all copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | THE SOFTWARE. 22 | -------------------------------------------------------------------------------- /@core-server/vue/vueify/circle.yml: -------------------------------------------------------------------------------- 1 | machine: 2 | node: 3 | version: 6 4 | -------------------------------------------------------------------------------- /@core-server/vue/vueify/index.js: -------------------------------------------------------------------------------- 1 | var through = require('through') 2 | var compiler = require('./lib/compiler') 3 | 4 | module.exports = function vueify(file, options) { 5 | if (!/.vue$/.test(file)) { 6 | return through() 7 | } 8 | 9 | compiler.applyConfig(options) 10 | compiler.applyConfig({ 11 | sourceMap: options._flags.debug 12 | }) 13 | 14 | var data = '' 15 | var stream = through(write, end) 16 | stream.vueify = true 17 | 18 | function dependency(file) { 19 | stream.emit('file', file) 20 | } 21 | 22 | function emitStyle(e) { 23 | stream.emit('vueify-style', e) 24 | } 25 | 26 | function write(buf) { 27 | data += buf 28 | } 29 | 30 | function end() { 31 | stream.emit('file', file) 32 | compiler.on('dependency', dependency) 33 | compiler.on('style', emitStyle) 34 | 35 | compiler.compile(data, file, options, function (error, result) { 36 | compiler.removeListener('dependency', dependency) 37 | compiler.removeListener('style', emitStyle) 38 | if (error) { 39 | stream.emit('error', error) 40 | // browserify doesn't log the stack by default... 41 | console.error(error.stack.replace(/^.*?\n/, '')) 42 | } 43 | 44 | stream.queue(result) 45 | stream.queue(null) 46 | }) 47 | } 48 | 49 | return stream 50 | } 51 | 52 | // expose compiler 53 | module.exports.compiler = compiler 54 | -------------------------------------------------------------------------------- /@core-server/vue/vueify/lib/compilers/babel.js: -------------------------------------------------------------------------------- 1 | var fs = require('fs') 2 | var path = require('path') 3 | var assign = require('object-assign') 4 | var ensureRequire = require('../ensure-require') 5 | 6 | var defaultBabelOptions = { 7 | presets: ['env'], 8 | plugins: ['transform-runtime'] 9 | } 10 | 11 | var babelRcPath = path.resolve(process.cwd(), '.babelrc') 12 | var babelOptions = fs.existsSync(babelRcPath) 13 | ? getBabelRc() || defaultBabelOptions 14 | : defaultBabelOptions 15 | 16 | function getBabelRc () { 17 | var rc 18 | try { 19 | rc = JSON.parse(fs.readFileSync(babelRcPath, 'utf-8')) 20 | } catch (e) { 21 | throw new Error('[vueify] Your .babelrc seems to be incorrectly formatted.') 22 | } 23 | return rc 24 | } 25 | 26 | module.exports = function (raw, cb, compiler, filePath) { 27 | if (babelOptions === defaultBabelOptions) { 28 | try { 29 | ensureRequire('babel', ['babel-preset-env', 'babel-runtime', 'babel-plugin-transform-runtime']) 30 | } catch (e) { 31 | console.error(e.message) 32 | console.error( 33 | '\n^^^ You are seeing this because you are using Vueify\'s default babel ' + 34 | 'configuration. You can override this with .babelrc or the babel option ' + 35 | 'in vue.config.js.' 36 | ) 37 | } 38 | } 39 | 40 | try { 41 | var babel = require('@babel/core') 42 | var options = assign({ 43 | comments: false, 44 | filename: filePath, 45 | sourceMaps: compiler.options.sourceMap 46 | }, compiler.options.babel || babelOptions) 47 | var res = babel.transform(raw, options) 48 | } catch (err) { 49 | console.error(err) 50 | return cb(err) 51 | } 52 | cb(null, res) 53 | } 54 | -------------------------------------------------------------------------------- /@core-server/vue/vueify/lib/compilers/coffee.js: -------------------------------------------------------------------------------- 1 | var ensureRequire = require('../ensure-require.js') 2 | 3 | module.exports = function (raw, cb, compiler) { 4 | ensureRequire('coffee', ['coffee-script']) 5 | var coffee = require('coffee-script') 6 | var compiled 7 | try { 8 | compiled = coffee.compile(raw, compiler.options.coffee || { 9 | bare: true, 10 | sourceMap: compiler.options.sourceMap 11 | }) 12 | } catch (err) { 13 | return cb(err) 14 | } 15 | if (compiler.options.sourceMap) { 16 | compiled = { 17 | code: compiled.js, 18 | map: compiled.v3SourceMap 19 | } 20 | } 21 | 22 | cb(null, compiled) 23 | } 24 | -------------------------------------------------------------------------------- /@core-server/vue/vueify/lib/compilers/index.js: -------------------------------------------------------------------------------- 1 | // built-in compilers 2 | module.exports = { 3 | coffee: require('./coffee'), 4 | babel: require('./babel'), 5 | less: require('./less'), 6 | sass: require('./sass'), 7 | scss: require('./sass'), 8 | stylus: require('./stylus'), 9 | jade: require('./jade'), 10 | pug: require('./pug') 11 | } 12 | -------------------------------------------------------------------------------- /@core-server/vue/vueify/lib/compilers/jade.js: -------------------------------------------------------------------------------- 1 | var ensureRequire = require('../ensure-require.js') 2 | 3 | module.exports = function (raw, cb, compiler) { 4 | ensureRequire('jade', 'jade') 5 | var jade = require('jade') 6 | try { 7 | var html = jade.compile(raw, compiler.options.jade || {})() 8 | } catch (err) { 9 | return cb(err) 10 | } 11 | cb(null, html) 12 | } 13 | -------------------------------------------------------------------------------- /@core-server/vue/vueify/lib/compilers/less.js: -------------------------------------------------------------------------------- 1 | var assign = require('object-assign') 2 | var path = require('path') 3 | var ensureRequire = require('../ensure-require.js') 4 | 5 | module.exports = function (raw, cb, compiler, filePath) { 6 | ensureRequire('less', 'less') 7 | var less = require('less') 8 | 9 | var opts = assign({ 10 | filename: path.basename(filePath) 11 | }, compiler.options.less) 12 | 13 | // provide import path 14 | var dir = path.dirname(filePath) 15 | var paths = [dir, process.cwd()] 16 | opts.paths = opts.paths 17 | ? opts.paths.concat(paths) 18 | : paths 19 | 20 | less.render(raw, opts, function (err, res) { 21 | if (err) { 22 | return cb(err) 23 | } 24 | 25 | // Less 2.0 returns an object instead rendered string 26 | if (typeof res === 'object') { 27 | res.imports.forEach(function (file) { 28 | compiler.emit('dependency', file) 29 | }) 30 | res = res.css 31 | } 32 | 33 | cb(null, res) 34 | }) 35 | } 36 | -------------------------------------------------------------------------------- /@core-server/vue/vueify/lib/compilers/pug.js: -------------------------------------------------------------------------------- 1 | var ensureRequire = require('../ensure-require.js') 2 | 3 | module.exports = function (raw, cb, compiler) { 4 | ensureRequire('pug', 'pug') 5 | var pug = require('pug') 6 | try { 7 | var html = pug.compile(raw, compiler.options.pug || {})() 8 | } catch (err) { 9 | return cb(err) 10 | } 11 | cb(null, html) 12 | } 13 | -------------------------------------------------------------------------------- /@core-server/vue/vueify/lib/compilers/sass.js: -------------------------------------------------------------------------------- 1 | var assign = require('object-assign') 2 | var path = require('path') 3 | 4 | module.exports = function (raw, cb, compiler, filePath) { 5 | var sass = require('node-sass') 6 | 7 | var sassOptions = assign({ 8 | data: raw, 9 | success: function (res) { 10 | if (typeof res === 'object') { 11 | cb(null, res.css) 12 | } else { 13 | cb(null, res) // compat for node-sass < 2.0.0 14 | } 15 | }, 16 | error: function (err) { 17 | cb(err) 18 | } 19 | }, compiler.options.sass || { 20 | sourceComments: true 21 | }) 22 | 23 | var dir = path.dirname(filePath) 24 | var paths = [dir, process.cwd()] 25 | sassOptions.includePaths = sassOptions.includePaths 26 | ? sassOptions.includePaths.concat(paths) 27 | : paths 28 | 29 | sass.render( 30 | sassOptions, 31 | // callback for node-sass > 3.0.0 32 | function (err, res) { 33 | if (err) { 34 | cb(err) 35 | } else { 36 | res.stats.includedFiles.forEach(function (file) { 37 | compiler.emit('dependency', file) 38 | }) 39 | cb(null, res.css.toString()) 40 | } 41 | } 42 | ) 43 | } 44 | -------------------------------------------------------------------------------- /@core-server/vue/vueify/lib/compilers/stylus.js: -------------------------------------------------------------------------------- 1 | var assign = require('object-assign') 2 | var path = require('path') 3 | var ensureRequire = require('../ensure-require.js') 4 | 5 | module.exports = function (raw, cb, compiler, filePath) { 6 | ensureRequire('stylus', 'stylus') 7 | var stylus = require('stylus') 8 | 9 | var opts = assign({ 10 | filename: path.basename(filePath) 11 | }, compiler.options.stylus || {}) 12 | 13 | var dir = path.dirname(filePath) 14 | var paths = [dir, process.cwd()] 15 | opts.paths = opts.paths 16 | ? opts.paths.concat(paths) 17 | : paths 18 | 19 | // using the renderer API so that we can 20 | // check deps after compilation 21 | var renderer = stylus(raw) 22 | Object.keys(opts).forEach(function (key) { 23 | renderer.set(key, opts[key]) 24 | }) 25 | 26 | renderer.render(function (err, css) { 27 | if (err) 28 | return cb(err) 29 | 30 | renderer.deps().forEach(function (file) { 31 | compiler.emit('dependency', file) 32 | }) 33 | cb(null, css) 34 | }) 35 | } 36 | -------------------------------------------------------------------------------- /@core-server/vue/vueify/lib/ensure-require.js: -------------------------------------------------------------------------------- 1 | module.exports = function (name, deps) { 2 | var i, len 3 | var missing = [] 4 | if (typeof deps === 'string') { 5 | deps = [deps] 6 | } 7 | 8 | for (i = 0, len = deps.length; i < len; i++) { 9 | var mis 10 | var req = deps[i] 11 | if (typeof req === 'string') { 12 | mis = req 13 | } else { 14 | mis = req[1] 15 | req = req[0] 16 | } 17 | 18 | try { 19 | // hack for babel-runtime because it does not expose "main" field 20 | if (req === 'babel-runtime') { 21 | req = 'babel-runtime/core-js' 22 | } 23 | 24 | require.resolve(req) 25 | } catch (e) { 26 | missing.push(mis) 27 | } 28 | } 29 | if (missing.length > 0) { 30 | var message = 'You are trying to use "' + name + '". ' 31 | var npmInstall = 'npm install --save-dev ' + missing.join(' ') 32 | if (missing.length > 1) { 33 | var last = missing.pop() 34 | message += missing.join(', ') + ' and ' + last + ' are ' 35 | } else { 36 | message += missing[0] + ' is ' 37 | } 38 | 39 | message += 'missing.\n\nTo install run:\n' + npmInstall 40 | throw new Error(message) 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /@core-server/vue/vueify/lib/gen-id.js: -------------------------------------------------------------------------------- 1 | // utility for generating a uid for each component file 2 | // used in scoped CSS rewriting 3 | var fileUid = 1 4 | var fileRegistry = Object.create(null) 5 | 6 | module.exports = function genId (file) { 7 | return fileRegistry[file] || (fileRegistry[file] = fileUid++) 8 | } 9 | -------------------------------------------------------------------------------- /@core-server/vue/vueify/lib/insert-css.js: -------------------------------------------------------------------------------- 1 | var inserted = exports.cache = {} 2 | 3 | function noop () {} 4 | 5 | exports.insert = function (css) { 6 | if (inserted[css]) 7 | return noop 8 | 9 | inserted[css] = true 10 | 11 | var elem = document.createElement('style') 12 | elem.setAttribute('type', 'text/css') 13 | 14 | if ('textContent' in elem) { 15 | elem.textContent = css 16 | } else { 17 | elem.styleSheet.cssText = css 18 | } 19 | 20 | document.getElementsByTagName('head')[0].appendChild(elem) 21 | return function () { 22 | document.getElementsByTagName('head')[0].removeChild(elem) 23 | inserted[css] = false 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /@core-server/vue/vueify/lib/normalize.js: -------------------------------------------------------------------------------- 1 | var IS_TEST = !!process.env.VUEIFY_TEST 2 | var fs = require('fs') 3 | var path = require('path') 4 | 5 | exports.lib = function (file) { 6 | if (IS_TEST) { 7 | return path.resolve(__dirname, file) 8 | } else { 9 | return 'vueify/lib/' + file 10 | } 11 | } 12 | 13 | exports.dep = function (dep) { 14 | if (IS_TEST) { 15 | return dep 16 | } else if (fs.existsSync(path.resolve(__dirname, '../node_modules', dep))) { 17 | // npm 2 or npm linked 18 | return 'vueify/node_modules/' + dep 19 | } else { 20 | // npm 3 21 | return dep 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /@core-server/vue/vueify/lib/style-rewriter.js: -------------------------------------------------------------------------------- 1 | var postcss = require('postcss') 2 | var selectorParser = require('postcss-selector-parser') 3 | var cache = require('lru-cache')(100) 4 | var assign = require('object-assign') 5 | 6 | var currentId 7 | var addId = postcss.plugin('add-id', function () { 8 | return function (root) { 9 | root.each(function rewriteSelector (node) { 10 | if (!node.selector) { 11 | // handle media queries 12 | if (node.type === 'atrule' && node.name === 'media') { 13 | node.each(rewriteSelector) 14 | } 15 | 16 | return 17 | } 18 | 19 | node.selector = selectorParser(function (selectors) { 20 | selectors.each(function (selector) { 21 | var node = null 22 | selector.each(function (n) { 23 | if (n.type !== 'pseudo') 24 | node = n 25 | }) 26 | selector.insertAfter(node, selectorParser.attribute({ 27 | attribute: currentId 28 | })) 29 | }) 30 | }).process(node.selector).result 31 | }) 32 | } 33 | }) 34 | 35 | /** 36 | * Add attribute selector to css 37 | * 38 | * @param {String} id 39 | * @param {String} css 40 | * @param {Boolean} scoped 41 | * @param {Object} options 42 | * @return {Promise} 43 | */ 44 | 45 | module.exports = function (id, css, scoped, options) { 46 | var key = id + '!!' + css 47 | var val = cache.get(key) 48 | if (val) { 49 | return Promise.resolve(val) 50 | } else { 51 | var plugins = [] 52 | var opts = { 53 | from: undefined 54 | } 55 | 56 | if (options.postcss instanceof Array) { 57 | plugins = options.postcss.slice() 58 | } else if (options.postcss instanceof Object) { 59 | plugins = options.postcss.plugins || [] 60 | opts = options.postcss.options 61 | } 62 | 63 | // scoped css rewrite 64 | if (scoped) { 65 | plugins.push(addId) 66 | } 67 | 68 | // minification 69 | if (process.env.NODE_ENV === 'production') { 70 | plugins.push(require('cssnano')(assign({ 71 | safe: true 72 | }, options.cssnano))) 73 | } 74 | 75 | currentId = id 76 | return postcss(plugins) 77 | .process(css, opts) 78 | .then(function (res) { 79 | cache.set(key, res.css) 80 | return res.css 81 | }) 82 | } 83 | } 84 | 85 | -------------------------------------------------------------------------------- /@core-server/vue/vueify/lib/template-compiler.js: -------------------------------------------------------------------------------- 1 | var chalk = require('chalk') 2 | var vueCompiler = require('vue-template-compiler') 3 | 4 | module.exports = function compileTemplate (template, compiler) { 5 | var compiled = vueCompiler.compile(template) 6 | if (compiled.errors.length) { 7 | compiled.errors.forEach(function (msg) { 8 | console.error('\n' + chalk.red(msg) + '\n') 9 | }) 10 | throw new Error('Vue template compilation failed') 11 | } else { 12 | return { 13 | render: toFunction(compiled.render), 14 | staticRenderFns: '[' + compiled.staticRenderFns.map(toFunction).join(',') + ']' 15 | } 16 | } 17 | } 18 | 19 | function toFunction (code) { 20 | return 'function(){' + code + '}' 21 | } 22 | -------------------------------------------------------------------------------- /@core-server/vue/vueify/plugins/extract-css.js: -------------------------------------------------------------------------------- 1 | var fs = require('fs') 2 | var compiler = require('../lib/compiler') 3 | var CleanCSS = require('clean-css') 4 | 5 | function minify(css) { 6 | return new CleanCSS({ 7 | level: 2 8 | }).minify(css).styles 9 | } 10 | 11 | function write(b, outPath, css) { 12 | if (typeof outPath === 'object' && outPath.write) { 13 | outPath.write(css) 14 | outPath.end() 15 | } else if (typeof outPath === 'string') { 16 | fs.writeFile(outPath, css, function (err) { 17 | if (err) 18 | console.error(err) 19 | }) 20 | } 21 | } 22 | 23 | module.exports = function (b, opts) { 24 | compiler.applyConfig({ 25 | extractCSS: true 26 | }) 27 | 28 | var styles = b._options.stylesCache 29 | 30 | var outPath = opts.out || opts.o || 'bundle.css' 31 | 32 | b.on('bundle', function (bs) { 33 | bs.on('end', function () { 34 | var css = Object.keys(styles) 35 | .map(function (file) { 36 | return styles[file] 37 | }) 38 | .join('\n') 39 | 40 | if (opts.minify) 41 | css = minify(css) 42 | 43 | write(b, outPath, css) 44 | 45 | }) 46 | }) 47 | 48 | b.on('transform', function (tr, file) { 49 | if (tr.vueify) { 50 | tr.on('vueify-style', function (e) { 51 | styles[e.file] = e.style 52 | }) 53 | } 54 | }) 55 | } 56 | -------------------------------------------------------------------------------- /@core-server/vue/vueify/test/fixtures/basic.vue: -------------------------------------------------------------------------------- 1 | 4 | 5 | 14 | 15 | 20 | -------------------------------------------------------------------------------- /@core-server/vue/vueify/test/fixtures/media-query.vue: -------------------------------------------------------------------------------- 1 | 8 | -------------------------------------------------------------------------------- /@core-server/vue/vueify/test/fixtures/postcss.vue: -------------------------------------------------------------------------------- 1 | 6 | -------------------------------------------------------------------------------- /@core-server/vue/vueify/test/fixtures/pre-processors.vue: -------------------------------------------------------------------------------- 1 | 8 | 9 | 15 | 16 | 22 | 23 | 29 | 30 | 35 | -------------------------------------------------------------------------------- /@core-server/vue/vueify/test/fixtures/pug.vue: -------------------------------------------------------------------------------- 1 | 7 | -------------------------------------------------------------------------------- /@core-server/vue/vueify/test/fixtures/scoped-css.vue: -------------------------------------------------------------------------------- 1 | 12 | 13 | 19 | 20 | 21 | -------------------------------------------------------------------------------- /@core-server/vue/vueify/test/fixtures/script-import.js: -------------------------------------------------------------------------------- 1 | export default { 2 | data () { 3 | return { 4 | msg: 'Hello from Component A!' 5 | } 6 | } 7 | }; -------------------------------------------------------------------------------- /@core-server/vue/vueify/test/fixtures/script-import.vue: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /@core-server/vue/vueify/test/fixtures/style-export.vue: -------------------------------------------------------------------------------- 1 | 4 | -------------------------------------------------------------------------------- /@core-server/vue/vueify/test/fixtures/style-import-scoped.css: -------------------------------------------------------------------------------- 1 | h1 { color: green; } 2 | -------------------------------------------------------------------------------- /@core-server/vue/vueify/test/fixtures/style-import.css: -------------------------------------------------------------------------------- 1 | h1 { color: red; } 2 | -------------------------------------------------------------------------------- /@core-server/vue/vueify/test/fixtures/style-import.vue: -------------------------------------------------------------------------------- 1 | 2 | 3 | -------------------------------------------------------------------------------- /@core-server/vue/vueify/test/fixtures/template-import.jade: -------------------------------------------------------------------------------- 1 | div 2 | h1 hello 3 | -------------------------------------------------------------------------------- /@core-server/vue/vueify/test/fixtures/template-import.vue: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /@core-server/vue/wrappers/resource_url.js: -------------------------------------------------------------------------------- 1 | function getResource(name) { 2 | try { 3 | return plugins.getEntry('http/MasterServer').siteManager.resourceManager.getObject(name) 4 | } catch (e) { 5 | console.error('getResource', e) 6 | } 7 | 8 | return false 9 | } 10 | 11 | module.exports = function(name) { 12 | if (name.substr(0, 1) !== '/') 13 | name = '/' + name 14 | 15 | const index = name.indexOf('?') 16 | var resource = null 17 | 18 | if (index == -1) { 19 | resource = getResource(name) 20 | name += '?' 21 | } else { 22 | resource = getResource(name.substr(0, index)) 23 | name += '&' 24 | } 25 | 26 | if (resource) { 27 | const hash = resource.getHash() 28 | if (!hash) 29 | return false 30 | 31 | return name + hash 32 | } 33 | 34 | return name 35 | } -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | All notable changes to this project will be documented in this file. 2 | 3 | --- 4 | 5 | ## 1.0.0 6 | 7 | ## Added 8 | **Modules** 9 | - Core Server source 10 | - Modular plugin system 11 | - CLI 12 | - Global logging system 13 | 14 | **Base Plugins** 15 | - API system 16 | - Databases (MySQL / Mongo) 17 | - Mail 18 | - Network Tasks 19 | - Redis 20 | - Sessions 21 | - TSV 22 | - VueJS 23 | - Web Server 24 | 25 | ### Deprecated 26 | - Nothing. 27 | ### Removed 28 | - Nothing. 29 | ### Fixed 30 | - Nothing. 31 | 32 | --- 33 | 34 | 35 | -------------------------------------------------------------------------------- /CODE_OF_CONDUCT.md: -------------------------------------------------------------------------------- 1 | # Contributor Covenant Code of Conduct 2 | 3 | ## Our Pledge 4 | 5 | In the interest of fostering an open and welcoming environment, we as contributors and maintainers pledge to making participation in our project and our community a harassment-free experience for everyone, regardless of age, body size, disability, ethnicity, gender identity and expression, level of experience, nationality, personal appearance, race, religion, or sexual identity and orientation. 6 | 7 | ## Our Standards 8 | 9 | Examples of behavior that contributes to creating a positive environment include: 10 | 11 | * Using welcoming and inclusive language 12 | * Being respectful of differing viewpoints and experiences 13 | * Gracefully accepting constructive criticism 14 | * Focusing on what is best for the community 15 | * Showing empathy towards other community members 16 | 17 | Examples of unacceptable behavior by participants include: 18 | 19 | * The use of sexualized language or imagery and unwelcome sexual attention or advances 20 | * Trolling, insulting/derogatory comments, and personal or political attacks 21 | * Public or private harassment 22 | * Publishing others' private information, such as a physical or electronic address, without explicit permission 23 | * Other conduct which could reasonably be considered inappropriate in a professional setting 24 | 25 | ## Our Responsibilities 26 | 27 | Project maintainers are responsible for clarifying the standards of acceptable behavior and are expected to take appropriate and fair corrective action in response to any instances of unacceptable behavior. 28 | 29 | Project maintainers have the right and responsibility to remove, edit, or reject comments, commits, code, wiki edits, issues, and other contributions that are not aligned to this Code of Conduct, or to ban temporarily or permanently any contributor for other behaviors that they deem inappropriate, threatening, offensive, or harmful. 30 | 31 | ## Scope 32 | 33 | This Code of Conduct applies both within project spaces and in public spaces when an individual is representing the project or its community. Examples of representing a project or community include using an official project e-mail address, posting via an official social media account, or acting as an appointed representative at an online or offline event. Representation of a project may be further defined and clarified by project maintainers. 34 | 35 | ## Enforcement 36 | 37 | Instances of abusive, harassing, or otherwise unacceptable behavior may be reported by contacting the project team at sacha@skyhark.be. The project team will review and investigate all complaints, and will respond in a way that it deems appropriate to the circumstances. The project team is obligated to maintain confidentiality with regard to the reporter of an incident. Further details of specific enforcement policies may be posted separately. 38 | 39 | Project maintainers who do not follow or enforce the Code of Conduct in good faith may face temporary or permanent repercussions as determined by other members of the project's leadership. 40 | 41 | ## Attribution 42 | 43 | This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4, available at [http://contributor-covenant.org/version/1/4][version] 44 | 45 | [homepage]: http://contributor-covenant.org 46 | [version]: http://contributor-covenant.org/version/1/4/ 47 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # Guidance on how to contribute 2 | 3 | > All contributions to this project will be released under the MIT license 4 | > dedication. By submitting a pull request or filing a bug, issue, or 5 | > feature request, you are agreeing to comply with this waiver of copyright interest. 6 | > Details can be found in: [LICENSE](LICENSE). 7 | 8 | 9 | There are two primary ways to help: 10 | - Using the issue tracker, and 11 | - Changing the code-base. 12 | 13 | 14 | ## Using the issue tracker 15 | 16 | Use the issue tracker to suggest feature requests, report bugs, and ask questions. 17 | This is also a great way to connect with the core developers and/or community 18 | who are interested in this question/solution/issue/feature. 19 | 20 | Use the issue tracker to find ways to contribute. Find a bug or a feature, mention in 21 | the issue that you will take on that effort, then follow the _Changing the code-base_ 22 | guidance below. 23 | 24 | 25 | ## Changing the code-base 26 | 27 | Generally speaking, you should fork this repository, make changes in your 28 | own fork, and then submit a pull-request. All new code should have associated unit 29 | tests that validate implemented features and the presence or lack of defects. 30 | Additionally, the code should follow any stylistic and architectural guidelines 31 | prescribed by the project. In the absence of such guidelines, mimic the styles 32 | and patterns in the existing code-base. 33 | -------------------------------------------------------------------------------- /DEVELOPMENT.md: -------------------------------------------------------------------------------- 1 | # Development instructions 2 | 3 | Detailed instructions on how to install, compile, edit, configure, and compile Core Server. 4 | Still need to be written. 5 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | 2 | MIT License 3 | 4 | Copyright (c) 2017 Skyhark 5 | 6 | Permission is hereby granted, free of charge, to any person obtaining a copy 7 | of this software and associated documentation files (the "Software"), to deal 8 | in the Software without restriction, including without limitation the rights 9 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | copies of the Software, and to permit persons to whom the Software is 11 | furnished to do so, subject to the following conditions: 12 | 13 | The above copyright notice and this permission notice shall be included in all 14 | copies or substantial portions of the Software. 15 | 16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | SOFTWARE. -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 |

2 | 3 |
4 | Core Server
5 | https://www.core-server.io 6 |

7 | 8 | ## Quick Installation 9 | 10 | To install Core Server and start a new project, run the following commands: 11 | 12 | ``` 13 | npm install -g core-server 14 | core-server --init 15 | ``` 16 | 17 | ---- 18 | 19 | # Core Server 20 | 21 | **Description**: 22 | Core Server helps teams set a standard project structure and workings for all sort of Node projects. 23 | 24 | We developed Core Server to provide a standard and global project structure for our web platforms developed in-house. We were loosing to much time figuring out a project structure for each seperate project. We open sourced as it may help other developers facing the same problems. 25 | 26 | **Technology stack**: 27 | Core Server is based on Node's v10 architecture and has a tight integration with VueJS. 28 | 29 | **Status**: 30 | Currently used by multiple launched projects! 31 | This open-source version is currently not yet production ready. 32 | We recently added a CLI and modular plugin system before open sourcing, which still needs testing. 33 | We started versioning since open sourcing the project. [CHANGELOG](CHANGELOG.md). 34 | 35 | **Projects using Core Server** 36 | - [SkyHark](https://www.skyhark.com/) 37 | - [FameBroker](https://www.famebroker.com/) 38 | - 3 Projects under an NDA 39 | 40 | ---- 41 | 42 | ## Usage 43 | 44 | **Project folder structure**: 45 | 46 | Using this project means that a certain folder structure is desired. 47 | This can be achieved by running: 48 | ``` core-server init ``` 49 | 50 | The folder structure looks like this: 51 | ``` 52 | Project root 53 | │ 54 | └─── api 55 | │ └─── ... 56 | │ 57 | └─── components 58 | │ └─── ... 59 | │ 60 | └─── resources 61 | │ └─── styles 62 | │ └─── ... 63 | │ └─── fonts 64 | │ └─── ... 65 | │ └─── img 66 | │ └─── ... 67 | │ └─── lib 68 | │ └─── init.js 69 | │ 70 | └─── config 71 | │ └─── servers.json 72 | │ └─── servers-production.json 73 | │ └─── public-api.json 74 | │ └─── plugins.json 75 | │ 76 | └─── package.json 77 | ``` 78 | To learn more about project setup please take a look at our [Wiki](wiki). 79 | 80 | Open up a terminal and make your way to your project root folder an run following command: 81 | ``` core-server [--port XXXX] ``` 82 | 83 | The default port is 8080. 84 | Your project will be accessible on http://localhost:8080/ 85 | 86 | ---- 87 | 88 | ## Getting involved 89 | 90 | **Devlopment**: 91 | 92 | Detailed instructions to develop and build Core Server from source can be found in our [DEVELOPMENT](DEVELOPMENT.md) document. 93 | We hope to see your great changes as contributions to this project. 94 | 95 | **Contributions**: 96 | 97 | We hope to provide a working project that fits many needs. 98 | In return we hope to improve Core Server with the help of the community. 99 | 100 | Contributing can be done in many ways.Instructions on _how_ to contribute scan be found in our [CONTRIBUTING](CONTRIBUTING.md) guide. 101 | 102 | ---- 103 | 104 | ## Getting help 105 | 106 | If you have questions, concerns, bug reports, etc, please file an issue in this repository's Issue Tracker. 107 | 108 | ## Known issues to solve & Todo list 109 | 110 | - [ ] We currently do not have unit tests in the repository. (Help would be appreciated) 111 | - [ ] Our [DEVELOPMENT](DEVELOPMENT) guide still needs to be written. 112 | - [ ] The Wiki is currently empty but is currently being worked on. 113 | 114 | ---- 115 | 116 | ## License 117 | 118 | [MIT](LICENSE) 119 | 120 | Copyright (c) 2016-present, Sacha Vandamme 121 | 122 | ---- -------------------------------------------------------------------------------- /_config.yml: -------------------------------------------------------------------------------- 1 | theme: jekyll-theme-cayman -------------------------------------------------------------------------------- /deploy: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | VERSION=$(cat package.json | grep 'version' | awk '{print $2}' | tr -d \" | tr -d ,); 4 | 5 | echo "Building version" $VERSION; 6 | 7 | npm publish 8 | 9 | #eval "$(boot2docker shellinit)" 10 | 11 | docker build . -t skyhark/core-server:v$VERSION 12 | 13 | docker push skyhark/core-server:v$VERSION -------------------------------------------------------------------------------- /install.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | ln -s ./core-server /usr/local/bin/core-server 4 | echo 'You may now utilise core-server commands. Use core-server --help to get started!' 5 | -------------------------------------------------------------------------------- /vue-au-graphql-loader/composables/index.js: -------------------------------------------------------------------------------- 1 | import { getCurrentInstance } from 'vue' 2 | 3 | export function useGraphql(data) { 4 | const instance = getCurrentInstance() 5 | const $gql = instance.type.$gql || {} 6 | 7 | for(var e in $gql) { 8 | return $gql[e].query.use(instance, data) 9 | } 10 | 11 | throw('no graphql query found') 12 | } -------------------------------------------------------------------------------- /vue-au-graphql-loader/nuxt.js: -------------------------------------------------------------------------------- 1 | import { defineNuxtModule, extendViteConfig, addImports } from '@nuxt/kit' 2 | import plugin from './src/index.js' 3 | 4 | // export module 5 | export default defineNuxtModule({ 6 | async setup(options) { 7 | await addImports([ 8 | { name: "useGraphql", from: __dirname + '/composables' }, 9 | ]) 10 | 11 | // register vue compiler and web extensions 12 | extendViteConfig((config) => { 13 | config.plugins.push(plugin.vite(options)) 14 | }) 15 | } 16 | }) -------------------------------------------------------------------------------- /vue-au-graphql-loader/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "author": { 3 | "name": "Sacha Vandamme", 4 | "email": "sacha@skyhark.be", 5 | "url": "https://www.core-server.io" 6 | }, 7 | "dependencies": { 8 | "graphql": "^16.6.0", 9 | "graphql-tag": "^2.12.6" 10 | }, 11 | "description": "", 12 | "directories": { 13 | "test": "test" 14 | }, 15 | "license": "ISC", 16 | "main": "./src/index.js", 17 | "name": "vue-au-graphql-loader", 18 | "scripts": { 19 | "test": "echo \"Error: no test specified\" && exit 1" 20 | }, 21 | "version": "2.3.1" 22 | } 23 | -------------------------------------------------------------------------------- /vue-au-graphql-loader/src/fragments.js: -------------------------------------------------------------------------------- 1 | function hasFragment(selections, name) { 2 | for(var key in selections) { 3 | var selection = selections[key] 4 | if(selection.kind == "FragmentSpread" && selection.name.value === name) 5 | return true 6 | 7 | if(selection.selectionSet && hasFragment(selection.selectionSet.selections, name)) 8 | return true 9 | } 10 | 11 | return false 12 | } 13 | 14 | export default function fragmentsInFilter(selection) { 15 | return function(fragment) { 16 | if(!selection.selectionSet) 17 | return false 18 | 19 | return hasFragment(selection.selectionSet.selections, fragment.name.value) 20 | } 21 | } 22 | 23 | export function withFragments(selection, fragments) { 24 | if(fragments.length === 0) 25 | return selection 26 | 27 | return { 28 | kind: 'Document', 29 | definitions: [ 30 | selection, 31 | ].concat(fragments) 32 | } 33 | } -------------------------------------------------------------------------------- /vue-au-graphql-loader/src/mutations.js: -------------------------------------------------------------------------------- 1 | import { withFragments } from './fragments' 2 | 3 | export default function create_mutation(handler, attributes, selection, document, fragments) { 4 | return function(variables) { 5 | if(typeof(variables) !== "object" && variables !== null && variables !== undefined) 6 | throw('Exepected object argument containing all variables') 7 | 8 | // Prepare mutation query 9 | var query = { 10 | kind: document.kind, 11 | operation: document.operation, 12 | directives: document.directives, 13 | variableDefinitions: [], 14 | selectionSet: { 15 | kind: "SelectionSet", 16 | selections: [ selection ] 17 | } 18 | } 19 | 20 | // Add all received variables 21 | if(variables) { 22 | for(var key in variables) { 23 | var deff = document.variableDefinitions.find((o) => o.variable.name.value == key) 24 | if(deff) 25 | query.variableDefinitions.push(deff) 26 | } 27 | } 28 | 29 | // Execute graphql query throught handler 30 | return handler({ 31 | query: withFragments(query, fragments), 32 | variables, 33 | attributes, 34 | stream: null, 35 | component: this, 36 | }) 37 | } 38 | } -------------------------------------------------------------------------------- /vue-au-graphql-loader/src/query.js: -------------------------------------------------------------------------------- 1 | import { withFragments } from './fragments' 2 | import { shallowRef, watchEffect } from 'vue' 3 | 4 | function exec(cb, self, data) { 5 | if(typeof cb === 'function') 6 | return cb.call(self, data) 7 | 8 | if(Array.isArray(cb)) { 9 | for(var i = 0; i < cb.length; i++) 10 | exec(cb[i], self, data) 11 | } 12 | 13 | return cb 14 | } 15 | 16 | function initial_data(document) { 17 | var vars = document.selectionSet.selections.map((o) => o.alias && o.alias.value || o.name.value) 18 | var res = {} 19 | for(var key of vars) 20 | res[key] = null 21 | 22 | return shallowRef(res) 23 | } 24 | 25 | export default function create_query(data, handler, attributes, query, fragments) { 26 | var self = this 27 | var $graphql = this.type?.graphql 28 | var current_data = initial_data(query) 29 | var catchers = [] 30 | 31 | current_data.loading = shallowRef(true) 32 | current_data.initial_loading = shallowRef(true) 33 | 34 | // Create a stream object to assign results to component 35 | var stream = { 36 | emit(data) { 37 | current_data.value = data 38 | current_data.loading.value = false 39 | current_data.initial_loading.value = false 40 | updating = false 41 | 42 | // Call graphql hooks 43 | exec($graphql?.success, self.ctx, data) 44 | exec($graphql?.done, self.ctx) 45 | }, 46 | 47 | error(err) { 48 | updating = false 49 | current_data.loading.value = false 50 | current_data.initial_loading.value = false 51 | 52 | // Call graphql hooks 53 | exec($graphql?.error, self.ctx, err) 54 | exec(catchers, self.ctx, err) 55 | exec($graphql?.done, self.ctx) 56 | } 57 | } 58 | 59 | // Query execution function 60 | var execute = () => { 61 | try { 62 | current_data.loading.value = true 63 | // Call query on handler 64 | var res = handler({ 65 | query: withFragments(query, fragments), 66 | variables: query.variables(data, this), 67 | attributes: attributes, 68 | component: this, 69 | stream, 70 | }) 71 | 72 | // Send handler result to data stream 73 | if(!res || res == stream) { 74 | updating = false 75 | } else if(res.then) { 76 | res.then(stream.emit).catch(stream.error) 77 | } else { 78 | stream.emit(res) 79 | } 80 | } catch(e) { 81 | stream.error(e) 82 | } 83 | 84 | updating = false 85 | } 86 | 87 | // Execute query 88 | var updating = false 89 | const stop_watcher = watchEffect(() => { 90 | if(updating) 91 | return 92 | 93 | updating = true 94 | 95 | if(stream.close) { 96 | stream.close() 97 | delete stream.close() 98 | } 99 | 100 | execute() 101 | }) 102 | 103 | // Return object to be able to update on variable change or close stream on component destroyed 104 | current_data.update = () => { 105 | // Dependency variable updated, update query on next tick 106 | if(updating) 107 | return current_data 108 | 109 | updating = true 110 | self.ctx.$nextTick(() => { 111 | if(stream.close) { 112 | stream.close() 113 | delete stream.close() 114 | } 115 | 116 | execute() 117 | }) 118 | 119 | return current_data 120 | } 121 | 122 | current_data.close = () => { 123 | stream.close && stream.close() 124 | stop_watcher() 125 | return current_data 126 | } 127 | 128 | current_data.catch = (cb) => { 129 | if(!cb) { 130 | var dest = shallowRef(null) 131 | catchers.push((err) => dest.value = err) 132 | return dest 133 | } 134 | 135 | catchers.push(cb) 136 | return current_data 137 | } 138 | 139 | return current_data 140 | } -------------------------------------------------------------------------------- /vue-au-graphql-loader/src/test.js: -------------------------------------------------------------------------------- 1 | 2 | class Component { 3 | constructor(options = {}) { 4 | this.plugin = require('./index').raw(options) 5 | this.resourceQuery = '?' 6 | this.options = options 7 | } 8 | 9 | setAttributes(attrs) { 10 | this.resourceQuery = '?' + require('querystring').stringify(attrs) 11 | } 12 | 13 | parse(src) { 14 | return this.plugin.transform(src, this.resourceQuery) 15 | } 16 | } 17 | 18 | var compo = new Component({ 19 | handler: '../src/addons/graphql', 20 | print: true, 21 | static_types: { 22 | simulation: 'Boolean!', 23 | } 24 | }) 25 | 26 | var res = compo.parse(`query($id: String!) { 27 | test(simulation: $simulation, id: $id) { 28 | abc 29 | } 30 | } 31 | 32 | mutation($label: String!) { 33 | addTag(label: $label) { 34 | id 35 | label 36 | } 37 | }`) 38 | 39 | // console.log(res) -------------------------------------------------------------------------------- /wiki/img/logo/logo-128.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chainius/Core-Server/4e1ae3df38991197983aac6b50309a01a92127a8/wiki/img/logo/logo-128.png -------------------------------------------------------------------------------- /wiki/img/logo/logo-256.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chainius/Core-Server/4e1ae3df38991197983aac6b50309a01a92127a8/wiki/img/logo/logo-256.png --------------------------------------------------------------------------------