UNPKG

realm-router

Version:

Realm router is a bleeding edge restful framework (ec7 + decorators), based on realm dependency injection.

733 lines (614 loc) 23.8 kB
(function(___scope___) { var $isBackend = ___scope___.isNode; var realm = ___scope___.realm; "use strict"; var _slicedToArray = function () { function sliceIterator(arr, i) { var _arr = []; var _n = true; var _d = false; var _e = undefined; try { for (var _i = arr[Symbol.iterator](), _s; !(_n = (_s = _i.next()).done); _n = true) { _arr.push(_s.value); if (i && _arr.length === i) break; } } catch (err) { _d = true; _e = err; } finally { try { if (!_n && _i["return"]) _i["return"](); } finally { if (_d) throw _e; } } return _arr; } return function (arr, i) { if (Array.isArray(arr)) { return arr; } else if (Symbol.iterator in Object(arr)) { return sliceIterator(arr, i); } else { throw new TypeError("Invalid attempt to destructure non-iterable instance"); } }; }(); var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }(); function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } (function (___scope___) { var $isBackend = ___scope___.isNode;var realm = ___scope___.realm; realm.module("realm.router.Collection", [], function () { var $_exports; var routeMap = new Map(); var Collection = function () { function Collection() { _classCallCheck(this, Collection); } _createClass(Collection, null, [{ key: "register", value: function register(path, target) { routeMap.set(path, target); } }, { key: "getMap", value: function getMap() { return routeMap; } }]); return Collection; }(); $_exports = Collection; return $_exports; }); realm.module("realm.router.Decorator", ["realm.router.utils.lodash"], function (_) { var $_exports; /** * Decorator * Wraps a class into a function that stores information about * the current decorator into instance properties (__decorators) */ var Decorator = function () { function Decorator() { _classCallCheck(this, Decorator); } _createClass(Decorator, null, [{ key: "wrap", /** * static * * @param {type} decorator description * @return {type} description */ value: function wrap(decorator) { return function () { var attrs = _.flatten(arguments); return function (target, property, descriptor) { var decorators = target.__decorators = target.__decorators || {}; var collection; if (!property) { collection = decorators.cls = decorators.cls || []; } else { decorators.props = decorators.props || {}; collection = decorators.props[property] = decorators.props[property] || []; } collection.push({ decorator: decorator, attrs: attrs }); }; }; } }]); return Decorator; }(); $_exports = Decorator; return $_exports; }); realm.module("realm.router.Dispatcher", ["realm.router.Collection", "realm.router.Traceback", "realm.router.RequestInjectors", "realm.router.utils.path2exp", "realm.router.utils.Promise", "realm.router.utils.logger", "realm.router.utils.lodash"], function (Collection, Traceback, RequestInjectors, path2exp, Promise, logger, _) { var $_exports; var PRETTY_TRACE = false; /** * Router */ var Dispatcher = function () { /** * constructor - description * * @param {type} req description * @param {type} res description * @param {type} next description * @return {type} description */ function Dispatcher(req, res, next) { _classCallCheck(this, Dispatcher); this.req = req; this.res = res; this.next = next; } /** * dispatch - dispatches a route * * @return {type} description */ _createClass(Dispatcher, [{ key: "dispatch", value: function dispatch() { var item = this.getCandidate(this.req.path); if (!item) { return this.next(); } return this.invoke(item); } /** * error - sends error directly to express * * @param {type} code description * @param {type} message description * @return {type} description */ }, { key: "error", value: function error(code, message) { this.res.status(code).send({ error: code, message: message }); } }, { key: "promised", value: function promised() { return new Promise(function (resolve, reject) { return resolve(); }); } /** * include - calls a decorator * And decorates a parent object * Goes through 2 methods * : inject * Addes new services to local injections (expects plain object on the ext) * : interecpt * Can prevent method from execution in natural way (non expection) * * @param {type} parent description * @param {type} fn description * @return {type} description */ }, { key: "include", value: function include(parent, props) { var self = this; self.services.$attrs = self.services.$attrs || {}; self.services.$attrs[parent.name] = props.attrs || {}; return this.decorate(parent).then(function () { return self.promised().then(function () { if (parent.inject) { return realm.require(parent.inject, self.services).then(function (results) { if (_.isPlainObject(results)) { _.each(results, function (obj, key) { self.services[key] = obj; }); } }); } }).then(function () { if (parent.intercept) { return realm.require(parent.intercept, self.services).then(function (_ic) { if (_ic !== undefined) { self.intercepted = _ic; } }); } }); }); } /** * decorate - decorate an object * If method is specified - tries to to get the corresponding method instance * @param {type} obj description * @param {type} method description * @return {type} description */ }, { key: "decorate", value: function decorate(obj, method) { var self = this; var intercepted; return self.promised().then(function () { if (!obj.__decorators) { return; } return realm.each(obj.__decorators.cls, function (item) { return self.include(item.decorator, item); }).then(function () { var props = obj.__decorators.props; if (props && props[method]) { var items = props[method]; return realm.each(items, function (item) { return self.include(item.decorator, item); }); } }); }); } /** * Invokes a handler */ }, { key: "invoke", value: function invoke(item) { var self = this; var method = self.req.method.toLowerCase(); var target = item.target[method]; self.services = { $req: self.req, $res: self.res, $params: self._compactParams(item) }; var localInjectors = RequestInjectors.getInjectors(); _.each(localInjectors, function (fn, name) { self.services[name] = fn(self); }); if (!target) { return this.error(501, "Not implemented"); } return self.decorate(item.target, method).then(function () { if (self.intercepted !== undefined) { return self.res.send(self.intercepted); } return realm.require(item.target[method], self.services).then(function (response) { if (!response !== undefined) { return self.res.send(response); } }); }).catch(function (e) { return Traceback.handle(e, self.res, PRETTY_TRACE); }); } /** * Gets suitable candidate */ }, { key: "getCandidate", value: function getCandidate() { var routes = Collection.getMap(); var self = this; var _iteratorNormalCompletion = true; var _didIteratorError = false; var _iteratorError = undefined; try { for (var _iterator = routes[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true) { var _step$value = _slicedToArray(_step.value, 2); var path = _step$value[0]; var handler = _step$value[1]; var keys = []; var re = path2exp(path, keys); var params = re.exec(self.req.path); if (params) { return { params: params, keys: keys, target: handler }; } } } catch (err) { _didIteratorError = true; _iteratorError = err; } finally { try { if (!_iteratorNormalCompletion && _iterator.return) { _iterator.return(); } } finally { if (_didIteratorError) { throw _iteratorError; } } } } /** * _compactParams - description * * @param {type} item description * @return {type} description */ }, { key: "_compactParams", value: function _compactParams(item) { var params = {}; _.each(item.keys, function (i, index) { if (item.params[index + 1] !== undefined) { params[i.name] = item.params[index + 1]; } }); return params; } /** * static - init routes * Require all classes * @param {type} _package description * @return {type} description */ }], [{ key: "initRoutes", value: function initRoutes(_package, opts) { opts = opts || {}; PRETTY_TRACE = opts.prettyTrace; var packages = [].concat(_package); return realm.each(packages, function (pkg) { return realm.requirePackage(pkg).then(function (_packages) { logger.info("Package '%s' has been successfully required", pkg); logger.info("Injested %s routes", _.keys(_packages).length); // }).catch(function (e) { console.log(e.stack); }); }); } }]); return Dispatcher; }(); $_exports = Dispatcher; return $_exports; }); realm.module("realm.router.Express", ["realm.router.Dispatcher", "realm.router.RequestInjectors", "realm.router.utils.logger", "realm.router.utils.lodash"], function (Dispatcher, RequestInjectors, logger, _) { var $_exports; var Express = function Express(_package, opt) { Dispatcher.initRoutes(_package, opt); RequestInjectors.init("realm.router.injectors"); // actuall express middleware return function (req, res, next) { var dispatcher = new Dispatcher(req, res, next); return dispatcher.dispatch(); }; }; $_exports = Express; return $_exports; }); realm.module("realm.router.RequestInjectors", ["realm.router.utils.lodash"], function (_) { var $_exports; var INJECTORS = {}; /** * RequestInjectors * Collects local injections */ var RequestInjectors = function () { function RequestInjectors() { _classCallCheck(this, RequestInjectors); } _createClass(RequestInjectors, null, [{ key: "init", value: function init(_package) { realm.requirePackage(_package).then(function (items) { _.each(items, function (injector) { INJECTORS[injector.injectionName] = injector.inject; }); }).catch(function (e) { console.log(e.stack); }); } }, { key: "getInjectors", value: function getInjectors() { return INJECTORS; } }]); return RequestInjectors; }(); $_exports = RequestInjectors; return $_exports; }); realm.module("realm.router.Traceback", ["realm.router.utils.lodash", "realm.router.utils.swig", "realm.router.utils.parsetrace", "realm.router.utils.logger"], function (_, swig, parsetrace, logger) { var $_exports; var Traceback = function () { function Traceback() { _classCallCheck(this, Traceback); } _createClass(Traceback, null, [{ key: "handle", value: function handle(e, res, prettyTrace) { logger.fatal(e.stack || e); // If we have a direct error if (e.status) { return res.status(e.status).send(e); } if (prettyTrace) { if (e.stack) { var error = parsetrace(e, { sources: true }).object(); return res.status(500).send(swig.renderFile(__dirname + '/traceback.html', { error: error })); } } return res.status(500).send({ status: 500, message: "Server Error" }); } }]); return Traceback; }(); $_exports = Traceback; return $_exports; }); realm.module("realm.router.assert", [], function () { var $_exports; var _throw = function _throw(code, msg) { throw { status: code, message: msg }; }; var Assert = function () { function Assert() { _classCallCheck(this, Assert); } _createClass(Assert, null, [{ key: "bad_request", value: function bad_request(message) { return _throw(400, message || "Bad request"); } }, { key: "unauthorized", value: function unauthorized(message) { return _throw(401, message || "Unauthorized"); } }, { key: "not_found", value: function not_found(message) { return _throw(404, message || "Not found"); } }]); return Assert; }(); $_exports = Assert; return $_exports; }); "use realm backend-raw"; realm.module("realm.router.utils.path2exp", function () { return require('path-to-regexp'); }); realm.module("realm.router.utils.lodash", function () { return require("lodash"); }); realm.module("realm.router.utils.Promise", function () { return require("promise"); }); realm.module("realm.router.utils.parsetrace", function () { return require('parsetrace'); }); realm.module("realm.router.utils.swig", function () { return require('swig'); }); realm.module("realm.router.utils.jsep", function () { return require('jsep'); }); realm.module("realm.router.utils.logger", function () { return require('log4js').getLogger('realm.router'); }); realm.module("realm.router.test.MainRouter", ["realm.router.decorators.route", "realm.router.decorators.cors", "realm.router.test.Session"], function (route, cors, sess) { var _dec, _class; var $_exports; var MainRouter = (_dec = route("/api/panel/intel-translation-save/:id/:lang?"), _dec(_class = function () { function MainRouter() { _classCallCheck(this, MainRouter); } _createClass(MainRouter, null, [{ key: "get", value: function get($params, $query, $body) { return $params; } }, { key: "put", value: function put($params, $query, $body) { return $params; } }]); return MainRouter; }()) || _class); return $_exports; }); realm.module("realm.router.test.Permissions", ["realm.router.Decorator"], function (Decorator) { var $_exports; var Permissions = function () { function Permissions() { _classCallCheck(this, Permissions); } _createClass(Permissions, null, [{ key: "inject", value: function inject($req, $attrs) { return { $permissions: "this is permissions" }; } }]); return Permissions; }(); $_exports = Decorator.wrap(Permissions); return $_exports; }); realm.module("realm.router.test.Session", ["realm.router.Decorator", "realm.test.Permissions"], function (Decorator, permissions) { var _dec2, _class2; var $_exports; /** * Session */ var Session = (_dec2 = permissions(), _dec2(_class2 = function () { function Session() { _classCallCheck(this, Session); } _createClass(Session, null, [{ key: "inject", value: function inject($req, $permissions, $attrs) { return { $session: $attrs }; } }]); return Session; }()) || _class2); $_exports = Decorator.wrap(Session); return $_exports; }); realm.module("realm.router.injectors.Body", [], function () { var $_exports; var Body = function () { function Body() { _classCallCheck(this, Body); } _createClass(Body, null, [{ key: "inject", value: function inject(dispatcher) { return { attrs: dispatcher.req.body, get: function get(name) { return dispatcher.req.body[name]; } }; } }, { key: "injectionName", get: function get() { return "$body"; } }]); return Body; }(); $_exports = Body; return $_exports; }); realm.module("realm.router.injectors.Query", [], function () { var $_exports; var Query = function () { function Query() { _classCallCheck(this, Query); } _createClass(Query, null, [{ key: "inject", value: function inject(dispatcher) { return { attrs: dispatcher.req.query, get: function get(name) { return dispatcher.req.query[name]; } }; } }, { key: "injectionName", get: function get() { return "$query"; } }]); return Query; }(); $_exports = Query; return $_exports; }); realm.module("realm.router.decorators.cors", ["realm.router.Decorator"], function (Decorator) { var $_exports; var Cors = function () { function Cors() { _classCallCheck(this, Cors); } _createClass(Cors, null, [{ key: "intercept", value: function intercept($attrs, $req, $res) { var method = $req.method.toLowerCase(); if (method === "options") { $res.header("Access-Control-Allow-Origin", "*"); $res.header("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept, Session"); return {}; } $res.header("Access-Control-Allow-Origin", "*"); $res.header("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept, Session"); } }]); return Cors; }(); $_exports = Decorator.wrap(Cors); return $_exports; }); realm.module("realm.router.decorators.route", ["realm.router.Collection"], function (Collection) { var $_exports; var Route = function Route(path) { return function (target, property, descriptor) { Collection.register(path, target); }; }; $_exports = Route; return $_exports; }); })(function (self) { var isNode = typeof exports !== 'undefined';return { isNode: isNode, realm: isNode ? require('realm-js') : self.realm }; }(undefined)); })(function(self){ var isNode = typeof exports !== 'undefined'; return { isNode : isNode, realm : isNode ? require('realm-js') : self.realm}}(this));