From 18585b27699127ba4ab9acd322dfb1315f84cd15 Mon Sep 17 00:00:00 2001 From: joelchu Date: Thu, 19 Mar 2020 23:13:12 +0800 Subject: [PATCH 01/11] Just hook the get interceptor method in ws-server-core but not going to implement it just yet --- packages/ws-server-core/package.json | 6 +-- .../src/handles/get-socket-handler.js | 11 ++--- .../src/handles/handle-intercom.js | 43 +++++++++++++------ .../src/handles/handle-standalone-login.js | 11 ++--- .../src/share/get-node-cache.js | 11 ++--- .../ws-server-core/src/share/node-store.js | 14 +++--- packages/ws-server/package.json | 4 +- 7 files changed, 59 insertions(+), 41 deletions(-) diff --git a/packages/ws-server-core/package.json b/packages/ws-server-core/package.json index f2adfd57..e1e99f66 100644 --- a/packages/ws-server-core/package.json +++ b/packages/ws-server-core/package.json @@ -31,11 +31,11 @@ "debug": "^4.1.1", "esm": "^3.2.25", "fs-extra": "^8.1.0", - "jsonql-constants": "^2.0.4", + "jsonql-constants": "^2.0.6", "jsonql-errors": "^1.2.1", "jsonql-jwt": "^1.3.10", "jsonql-params-validator": "^1.6.1", - "jsonql-resolver": "^1.1.3", + "jsonql-resolver": "^1.2.0", "jsonql-utils": "^1.2.4", "lodash": "^4.17.15", "nanoid": "^2.1.11", @@ -43,7 +43,7 @@ }, "devDependencies": { "ava": "^3.5.0", - "jsonql-contract": "^1.8.10" + "jsonql-contract": "^1.9.1" }, "ava": { "files": [ diff --git a/packages/ws-server-core/src/handles/get-socket-handler.js b/packages/ws-server-core/src/handles/get-socket-handler.js index 5293cc13..7d6a3684 100644 --- a/packages/ws-server-core/src/handles/get-socket-handler.js +++ b/packages/ws-server-core/src/handles/get-socket-handler.js @@ -5,9 +5,10 @@ const { HELLO_FN } = require('jsonql-constants') const { getResolverFromPayload } = require('jsonql-utils') + +const { handleHello } = require('./handle-hello') const { handleInterCom } = require('./handle-intercom') const { handleNspResolvers } = require('./handle-nsp-resolvers') -const { handleHello } = require('./handle-hello') const { handleUnknownPayload } = require('./handle-unknown-payload') const { getRainbowDebug } = require('../share/helpers') @@ -59,15 +60,15 @@ function getSocketHandler(config, ws, deliverFn, req, connectedNamespace, payloa default: const contractParam = matchResolverByNamespace(resolverName, connectedNamespace, nspGroup) debug('getSocketHandler:default', contractParam) - + if (contractParam === false) { // just return an error return handleUnknownPayload(deliverFn, resolverName, args) } - + handleNspResolvers(deliverFn, ws, resolverName, args, contractParam.params, config, userdata) - + } } -module.exports = { getSocketHandler } \ No newline at end of file +module.exports = { getSocketHandler } diff --git a/packages/ws-server-core/src/handles/handle-intercom.js b/packages/ws-server-core/src/handles/handle-intercom.js index fee61911..1b1660f1 100644 --- a/packages/ws-server-core/src/handles/handle-intercom.js +++ b/packages/ws-server-core/src/handles/handle-intercom.js @@ -1,17 +1,17 @@ /* -We now group all the ping, login, logout, disconnect, switch event -into one group as the intercom, and all using the same internal resolverName INTERCOME_RESOLVER_NAME +We now group all the ping, login, logout, disconnect, switch event +into one group as the intercom, and all using the same internal resolverName INTERCOME_RESOLVER_NAME and use the type to tell the different, the main com type REPLY ACKNOWLEDGE will get handle by the ee -but the rest are outside of that scope, therefore it won't affect the currenct operation +but the rest are outside of that scope, therefore it won't affect the currenct operation */ const { getDebug } = require('../share/helpers') const debug = getDebug('handle-intercome') const { SOCKET_PING_EVENT_NAME, SA_LOGIN_EVENT_NAME, + LOGIN_EVENT_NAME , LOGOUT_EVENT_NAME, DISCONNECT_EVENT_NAME - // LOGIN_EVENT_NAME // TBC } = require('jsonql-constants') const { handleInitPing } = require('./handle-init-ping') @@ -19,38 +19,53 @@ const { handleLogout } = require('./handle-logout') const { handleStandaloneLogin } = require('./handle-standalone-login') const { handleDisconnect } = require('./handle-disconnet') const { handleUnknownPayload } = require('./handle-unknown-payload') +// we handle the get interceptor here in one place +const { getSocketInterceptor } = require('jsonql-resolver') /** * @TODO handle the intercom event disconnect / switch-user (future feature) - * @param {object} config configuraton - * @param {object} ws the socket instance + * @param {object} config configuraton + * @param {object} ws the socket instance * @param {function} deliverFn framework specific to send out message * @param {object} req the request object - * @param {string} connectedNamespace the namesapce its connected to + * @param {string} connectedNamespace the namesapce its connected to * @param {array} payload extract from the payload, the first is the event name * @param {*} userdata it could be empty most of the time * @return {void} nothing return just send back a reply */ function handleInterCom(config, ws, deliverFn, req, connectedNamespace, payload, userdata) { - // the payload is part wrap iside the arg key + // the payload is part wrap iside the arg key const { args } = payload // the most important one to take a look at const eventName = args[0] - + args.splice(0, 1) // take the first one out, it could be empty - + debug('handleIntercom', eventName, args) + let interceptorFn + switch (eventName) { + case SA_LOGIN_EVENT_NAME: + case LOGOUT_EVENT_NAME: + case DISCONNECT_EVENT_NAME: + case LOGIN_EVENT_NAME: + interceptorFn = getSocketInterceptor(eventName, config) + break + default: + // nothing + } + switch (eventName) { case SOCKET_PING_EVENT_NAME: return handleInitPing(config, ws, deliverFn, req, connectedNamespace, args) case SA_LOGIN_EVENT_NAME: - return handleStandaloneLogin(config, ws, deliverFn, req, connectedNamespace, args) + case LOGIN_EVENT_NAME: + return handleStandaloneLogin(config, ws, deliverFn, req, connectedNamespace, args, interceptorFn) case LOGOUT_EVENT_NAME: - return handleLogout(config, ws, deliverFn, req, connectedNamespace, args, userdata) + return handleLogout(config, ws, deliverFn, req, connectedNamespace, args, userdata, interceptorFn) case DISCONNECT_EVENT_NAME: - return handleDisconnect(config, ws, deliverFn, req, connectedNamespace, args, userdata) - default: + return handleDisconnect(config, ws, deliverFn, req, connectedNamespace, args, userdata, interceptorFn) + default: handleUnknownPayload(config, ws, deliverFn, req, connectedNamespace, args, userdata) } } diff --git a/packages/ws-server-core/src/handles/handle-standalone-login.js b/packages/ws-server-core/src/handles/handle-standalone-login.js index 22731461..872ce91b 100644 --- a/packages/ws-server-core/src/handles/handle-standalone-login.js +++ b/packages/ws-server-core/src/handles/handle-standalone-login.js @@ -7,17 +7,18 @@ const debug = getDebug('handle-intercome') /** * When standalone:true and there is a login method in the folder * then we will use that resolver to deal with the login over socket - * @param {object} config configuraton - * @param {object} ws the socket instance + * @param {object} config configuraton + * @param {object} ws the socket instance * @param {function} deliverFn framework specific to send out message * @param {object} req the request object - * @param {string} connectedNamespace the namesapce its connected to + * @param {string} connectedNamespace the namesapce its connected to * @param {array} args extract from the payload, the first is the event name + * @param {function} interceptorFn developer provide method * @return {void} nothing return just send back a reply */ -function handleStandaloneLogin(config, ws, deliverFn, req, connectedNamespace, args) { +function handleStandaloneLogin(config, ws, deliverFn, req, connectedNamespace, args, interceptorFn) { debug(`handleStanealoneLogin called`, args) - + } diff --git a/packages/ws-server-core/src/share/get-node-cache.js b/packages/ws-server-core/src/share/get-node-cache.js index 01919b1c..b2a706e1 100644 --- a/packages/ws-server-core/src/share/get-node-cache.js +++ b/packages/ws-server-core/src/share/get-node-cache.js @@ -11,18 +11,19 @@ enableLegacyCallbacks: (default: false) re-enables the usage of callbacks instea maxKeys: (default: -1) specifies a maximum amount of keys that can be stored in the cache. If a new item is set and the cache is full, an error is thrown and the key will not be saved in the cache. -1 disables the key limit. */ -// using node-cache to store can be throw away data -// here we implement a simple store to store the CSRF token +// using node-cache to store can be throw away data +// here we implement a simple store to store the CSRF token // in this structure {CSRF-TOKEN: TIMESTAMP} -// so you can check if this key actually exist or not +// so you can check if this key actually exist or not const debug = require('debug')('jsonql-ws-server-core:share:get-node-cache') const nodeCache = require('node-cache') global.localNodeCacheStore + /** * We don't want to init the node cache everytime * so we put that in a global value * @param {objec} opts configuration - * @return {object} the nodeCache instance + * @return {object} the nodeCache instance */ module.exports = function getNodeCache(opts = {}) { if (!global.localNodeCacheStore) { @@ -30,4 +31,4 @@ module.exports = function getNodeCache(opts = {}) { global.localNodeCacheStore = new nodeCache(opts) } return global.localNodeCacheStore -} \ No newline at end of file +} diff --git a/packages/ws-server-core/src/share/node-store.js b/packages/ws-server-core/src/share/node-store.js index e48e39f3..8281886f 100644 --- a/packages/ws-server-core/src/share/node-store.js +++ b/packages/ws-server-core/src/share/node-store.js @@ -1,7 +1,7 @@ const nanoid = require('nanoid') const { JsonqlError } = require('jsonql-errors') -const getNodeCache = require('../share/get-node-cache') -// call this first +const getNodeCache = require('./get-node-cache') +// call this first const store = getNodeCache() const STORE_FAIL_ERR = 'unable to store the token in node cache!' @@ -11,12 +11,12 @@ const STORE_FAIL_ERR = 'unable to store the token in node cache!' */ function getToken() { let token = nanoid() - // test if the token exist + // test if the token exist if (store.has(token)) { // call itself again until find a key not in store return getToken() } - return token + return token } /** @@ -27,15 +27,15 @@ function createCSRFToken() { let token = getToken() // not setting the TTL at the moment, but we should in the future if (store.set(token, Date.now())) { - return token + return token } throw new JsonqlError('createCSRFToken', STORE_FAIL_ERR) } /** - * Check if the key existed + * Check if the key existed * @param {string} token - * @return {boolean} + * @return {boolean} */ function isCSRFTokenExist(token) { return store.has(token) diff --git a/packages/ws-server/package.json b/packages/ws-server/package.json index 5baad1e4..cebeea45 100755 --- a/packages/ws-server/package.json +++ b/packages/ws-server/package.json @@ -33,14 +33,14 @@ "dependencies": { "colors": "^1.4.0", "debug": "^4.1.1", - "jsonql-constants": "^2.0.4", + "jsonql-constants": "^2.0.6", "jsonql-utils": "^1.2.4", "jsonql-ws-server-core": "^0.7.10", "ws": "^7.2.3" }, "devDependencies": { "ava": "^3.5.0", - "jsonql-contract": "^1.8.10", + "jsonql-contract": "^1.9.1", "open": "^7.0.3" }, "ava": { -- Gitee From f23db6606df9539904a58bf0eb6378c1097c7df9 Mon Sep 17 00:00:00 2001 From: joelchu Date: Thu, 19 Mar 2020 23:42:53 +0800 Subject: [PATCH 02/11] Fix the onReady fire multiple times problem --- packages/@jsonql/ws/main.js | 53 ++++++++++--------- packages/@jsonql/ws/main.js.map | 2 +- .../create-nsp/bind-socket-event-handler.js | 39 +++++++------- .../@jsonql/ws/tests/ws-client-auth.test.js | 26 ++++++--- .../src/callers/generator-methods.js | 36 ++++++------- 5 files changed, 82 insertions(+), 74 deletions(-) diff --git a/packages/@jsonql/ws/main.js b/packages/@jsonql/ws/main.js index 724e9e25..d757b91a 100644 --- a/packages/@jsonql/ws/main.js +++ b/packages/@jsonql/ws/main.js @@ -7488,7 +7488,7 @@ function setupResolver(namespace, resolverName, params, fn, ee, log) { * @param {string} namespace this resolver end point * @param {string} resolverName name of resolver as event name * @param {object} params from contract - * @param {function} log pass the log function + * @param {function} log pass the log function * @return {function} resolver */ function createResolver(ee, namespace, resolverName, params, log) { @@ -7513,7 +7513,7 @@ function createResolver(ee, namespace, resolverName, params, log) { function generateResolvers(opts, ee, nspGroup) { var client= {}; var log = opts.log; - + for (var namespace in nspGroup) { var list = nspGroup[namespace]; for (var resolverName in list) { @@ -7523,8 +7523,8 @@ function generateResolvers(opts, ee, nspGroup) { // this should set as a getter therefore can not be overwrite by accident // obj[resolverName] = setupResolver(namespace, resolverName, params, fn, ee) client = injectToFn( - client, - resolverName, + client, + resolverName, setupResolver(namespace, resolverName, params, fn, ee, log) ); } @@ -7541,13 +7541,13 @@ function generateResolvers(opts, ee, nspGroup) { * @param {object} opts configuration * @param {object} ee Event Emitter * @param {object} nspGroup namespace keys - * @return {array} [obj, opts, ee] + * @return {array} [obj, opts, ee] */ function createNamespaceErrorListener(client, opts, ee, nspGroup) { return [ objDefineProps( - client, - ON_ERROR_FN_NAME, + client, + ON_ERROR_FN_NAME, function namespaceErrorCallbackHandler(namespaceErrorHandler) { if (isFunc(namespaceErrorHandler)) { // please note ON_ERROR_FN_NAME can add multiple listners @@ -7574,12 +7574,14 @@ function createNamespaceErrorListener(client, opts, ee, nspGroup) { function createOnReadyListener(client, opts, ee) { return [ objDefineProps( - client, - ON_READY_FN_NAME, + client, + ON_READY_FN_NAME, function onReadyCallbackHandler(onReadyCallback) { if (isFunc(onReadyCallback)) { // reduce it down to just one flat level - ee.$on(ON_READY_FN_NAME, onReadyCallback); + // @2020-03-19 only allow ONE onReady callback otherwise + // it will get fire multiple times which is not what we want + ee.$only(ON_READY_FN_NAME, onReadyCallback); } } ), @@ -10681,7 +10683,7 @@ var logoutEventListener = function (ee, ws) { // listen to the LOGOUT_EVENT_NAME when this is a private nsp ee.$on(LOGOUT_EVENT_NAME$1, function closeEvtHandler() { try { - // @TODO we need find a way to get the userdata + // @TODO we need find a way to get the userdata ws.send(createIntercomPayload(LOGOUT_EVENT_NAME$1)); log('terminate ws connection'); ws.terminate(); @@ -10702,32 +10704,31 @@ var logoutEventListener = function (ee, ws) { */ function bindSocketEventHandler(namespace, ws, ee, isPrivate, opts) { var log = opts.log; - - log("log test, isPrivate:", isPrivate); + // log(`log test, isPrivate:`, isPrivate) // connection open ws.onopen = function onOpenCallback() { - - log('ws.onopen listened'); + + log('=== ws.onopen listened -->', namespace); // we just call the onReady - ee.$call(ON_READY_FN_NAME$1, namespace); + ee.$call(ON_READY_FN_NAME$1)(namespace); // need an extra parameter here to id the private nsp if (isPrivate) { log(("isPrivate and fire the " + ON_LOGIN_FN_NAME$1)); - ee.$call(ON_LOGIN_FN_NAME$1, namespace); + ee.$call(ON_LOGIN_FN_NAME$1)(namespace); } // add listener only after the open is called ee.$only( createEvt$1(namespace, EMIT_REPLY_TYPE$1), /** * actually send the payload to server - * @param {string} resolverName - * @param {array} args NEED TO CHECK HOW WE PASS THIS! + * @param {string} resolverName + * @param {array} args NEED TO CHECK HOW WE PASS THIS! */ function wsMainOnEvtHandler(resolverName, args) { - + var payload = createQueryStr$1(resolverName, args); log('ws.onopen.send', resolverName, args, payload); - + ws.send(payload); } ); @@ -10740,12 +10741,12 @@ function bindSocketEventHandler(namespace, ws, ee, isPrivate, opts) { // console.log(`on.message`, typeof payload, payload) try { // log(`ws.onmessage raw payload`, payload) - // @TODO the payload actually contain quite a few things - is that changed? + // @TODO the payload actually contain quite a few things - is that changed? // type: message, data: data_send_from_server var json = extractWsPayload$1(payload.data); var resolverName = json.resolverName; var type = json.type; - + log('Respond from server', type, json); switch (type) { @@ -10764,7 +10765,7 @@ function bindSocketEventHandler(namespace, ws, ee, isPrivate, opts) { // we need to extract the error from json log("ERROR_KEY"); errorTypeHandler(ee, namespace, resolverName, json); - break + break // @TODO there should be an error type instead of roll into the other two types? TBC default: // if this happen then we should throw it and halt the operation all together @@ -10784,9 +10785,9 @@ function bindSocketEventHandler(namespace, ws, ee, isPrivate, opts) { // @TODO what to do with this // ee.$trigger(LOGOUT_EVENT_NAME, [namespace]) }; - // add a onerror event handler here + // add a onerror event handler here ws.onerror = function onErrorCallback(err) { - // trigger a global error event + // trigger a global error event log("ws.onerror", err); handleNamespaceOnError(ee, namespace, err); }; diff --git a/packages/@jsonql/ws/main.js.map b/packages/@jsonql/ws/main.js.map index d991c07c..451bcfb7 100644 --- a/packages/@jsonql/ws/main.js.map +++ b/packages/@jsonql/ws/main.js.map @@ -1 +1 @@ -{"version":3,"file":"main.js","sources":["../../ws-client-core/node_modules/lodash-es/isArray.js","node_modules/rollup-plugin-node-globals/src/global.js","../../ws-client-core/node_modules/lodash-es/_objectToString.js","../../ws-client-core/node_modules/lodash-es/_overArg.js","../../ws-client-core/node_modules/lodash-es/isObjectLike.js","../../ws-client-core/node_modules/lodash-es/_arrayMap.js","../../ws-client-core/node_modules/lodash-es/_baseSlice.js","../../ws-client-core/node_modules/lodash-es/_baseFindIndex.js","../../ws-client-core/node_modules/lodash-es/_baseIsNaN.js","../../ws-client-core/node_modules/lodash-es/_strictIndexOf.js","../../ws-client-core/node_modules/lodash-es/_asciiToArray.js","../../ws-client-core/node_modules/lodash-es/_hasUnicode.js","../../ws-client-core/node_modules/lodash-es/_unicodeToArray.js","../../ws-client-core/node_modules/jsonql-utils/src/generic.js","../../ws-client-core/node_modules/lodash-es/_listCacheClear.js","../../ws-client-core/node_modules/lodash-es/eq.js","../../ws-client-core/node_modules/lodash-es/_stackDelete.js","../../ws-client-core/node_modules/lodash-es/_stackGet.js","../../ws-client-core/node_modules/lodash-es/_stackHas.js","../../ws-client-core/node_modules/lodash-es/isObject.js","../../ws-client-core/node_modules/lodash-es/_toSource.js","../../ws-client-core/node_modules/lodash-es/_getValue.js","../../ws-client-core/node_modules/lodash-es/_hashDelete.js","../../ws-client-core/node_modules/lodash-es/_isKeyable.js","../../ws-client-core/node_modules/lodash-es/_createBaseFor.js","../../ws-client-core/node_modules/lodash-es/_copyArray.js","../../ws-client-core/node_modules/lodash-es/_isPrototype.js","../../ws-client-core/node_modules/lodash-es/isLength.js","../../ws-client-core/node_modules/lodash-es/stubFalse.js","../../ws-client-core/node_modules/lodash-es/_baseUnary.js","../../ws-client-core/node_modules/lodash-es/_safeGet.js","../../ws-client-core/node_modules/lodash-es/_baseTimes.js","../../ws-client-core/node_modules/lodash-es/_isIndex.js","../../ws-client-core/node_modules/lodash-es/_nativeKeysIn.js","../../ws-client-core/node_modules/lodash-es/identity.js","../../ws-client-core/node_modules/lodash-es/_apply.js","../../ws-client-core/node_modules/lodash-es/constant.js","../../ws-client-core/node_modules/lodash-es/_shortOut.js","../../ws-client-core/node_modules/jsonql-errors/src/enum-error.js","../../ws-client-core/node_modules/jsonql-errors/src/type-error.js","../../ws-client-core/node_modules/jsonql-errors/src/checker-error.js","../../ws-client-core/node_modules/jsonql-errors/src/validation-error.js","../../ws-client-core/node_modules/jsonql-utils/src/contract.js","../../ws-client-core/node_modules/jsonql-utils/src/timestamp.js","../../ws-client-core/node_modules/jsonql-utils/src/params-api.js","../../ws-client-core/node_modules/jsonql-utils/src/namespace.js","../../ws-client-core/node_modules/jsonql-utils/src/socket.js","../../ws-client-core/src/callers/intercom-methods.js","../../ws-client-core/node_modules/jsonql-params-validator/src/number.js","../../ws-client-core/node_modules/jsonql-params-validator/src/string.js","../../ws-client-core/node_modules/jsonql-params-validator/src/boolean.js","../../ws-client-core/node_modules/jsonql-params-validator/src/any.js","../../ws-client-core/node_modules/jsonql-params-validator/src/constants.js","../../ws-client-core/node_modules/jsonql-params-validator/src/combine.js","../../ws-client-core/node_modules/jsonql-params-validator/src/array.js","../../ws-client-core/node_modules/jsonql-params-validator/src/object.js","../../ws-client-core/node_modules/jsonql-params-validator/src/validator.js","../../ws-client-core/node_modules/lodash-es/_setCacheAdd.js","../../ws-client-core/node_modules/lodash-es/_setCacheHas.js","../../ws-client-core/node_modules/lodash-es/_arraySome.js","../../ws-client-core/node_modules/lodash-es/_cacheHas.js","../../ws-client-core/node_modules/lodash-es/_mapToArray.js","../../ws-client-core/node_modules/lodash-es/_setToArray.js","../../ws-client-core/node_modules/lodash-es/_arrayPush.js","../../ws-client-core/node_modules/lodash-es/_arrayFilter.js","../../ws-client-core/node_modules/lodash-es/stubArray.js","../../ws-client-core/node_modules/lodash-es/_matchesStrictComparable.js","../../ws-client-core/node_modules/lodash-es/_baseHasIn.js","../../ws-client-core/node_modules/lodash-es/_baseProperty.js","../../ws-client-core/node_modules/lodash-es/negate.js","../../ws-client-core/node_modules/lodash-es/_baseFindKey.js","../../ws-client-core/node_modules/jsonql-params-validator/src/is-in-array.js","../../ws-client-core/node_modules/jsonql-params-validator/src/options/run-validation.js","../../ws-client-core/node_modules/jsonql-params-validator/src/options/check-options-async.js","../../ws-client-core/node_modules/jsonql-params-validator/src/options/construct-config.js","../../ws-client-core/node_modules/jsonql-params-validator/src/options/index.js","../../ws-client-core/node_modules/jsonql-params-validator/index.js","../../ws-client-core/src/utils/get-log-fn.js","../../ws-client-core/node_modules/@to1source/event/src/constants.js","../../ws-client-core/node_modules/@to1source/event/src/store.js","../../ws-client-core/node_modules/@to1source/event/src/utils.js","../../ws-client-core/node_modules/@to1source/event/src/suspend.js","../../ws-client-core/node_modules/@to1source/event/src/store-service.js","../../ws-client-core/node_modules/@to1source/event/src/event-service.js","../../ws-client-core/node_modules/@to1source/event/index.js","../../ws-client-core/src/utils/get-event-emitter.js","../../ws-client-core/src/utils/helpers.js","../../ws-client-core/src/callers/setup-auth-methods.js","../../ws-client-core/src/options/constants.js","../../ws-client-core/src/callers/respond-handler.js","../../ws-client-core/src/callers/action-call.js","../../ws-client-core/src/callers/setup-send-method.js","../../ws-client-core/src/callers/setup-resolver.js","../../ws-client-core/src/callers/generator-methods.js","../../ws-client-core/src/callers/setup-intercom.js","../../ws-client-core/src/callers/setup-final-step.js","../../ws-client-core/src/callers/callers-generator.js","../../ws-client-core/src/options/index.js","../../ws-client-core/src/api.js","../../ws-client-core/src/listener/create-nsp-clients.js","../../ws-client-core/src/listener/trigger-namespaces-on-error.js","../../ws-client-core/src/listener/event-listeners.js","../../ws-client-core/src/listener/client-event-listener.js","src/options/index.js","src/core/create-websocket-binding/init-websocket-client.js","node_modules/lodash-es/_objectToString.js","node_modules/lodash-es/_overArg.js","node_modules/lodash-es/isObjectLike.js","node_modules/lodash-es/_listCacheClear.js","node_modules/lodash-es/eq.js","node_modules/lodash-es/_stackDelete.js","node_modules/lodash-es/_stackGet.js","node_modules/lodash-es/_stackHas.js","node_modules/lodash-es/isObject.js","node_modules/lodash-es/_toSource.js","node_modules/lodash-es/_getValue.js","node_modules/lodash-es/_hashDelete.js","node_modules/lodash-es/_isKeyable.js","node_modules/lodash-es/_createBaseFor.js","node_modules/lodash-es/_copyArray.js","node_modules/lodash-es/_isPrototype.js","node_modules/lodash-es/isArray.js","node_modules/lodash-es/isLength.js","node_modules/lodash-es/stubFalse.js","node_modules/lodash-es/_baseUnary.js","node_modules/lodash-es/_safeGet.js","node_modules/lodash-es/_baseTimes.js","node_modules/lodash-es/_isIndex.js","node_modules/lodash-es/_nativeKeysIn.js","node_modules/lodash-es/identity.js","node_modules/lodash-es/_apply.js","node_modules/lodash-es/constant.js","node_modules/lodash-es/_shortOut.js","node_modules/jsonql-utils/src/chain-promises.js","src/core/create-nsp/login-event-handler.js","node_modules/jsonql-utils/src/generic.js","node_modules/jsonql-errors/src/validation-error.js","node_modules/jsonql-utils/src/timestamp.js","node_modules/jsonql-utils/src/params-api.js","node_modules/jsonql-utils/src/socket.js","src/core/create-nsp/bind-socket-event-handler.js","src/core/create-nsp/create-nsp.js","src/core/create-nsp/index.js","src/core/create-websocket-binding/bind-framework-to-jsonql.js","src/node/node-framework-socket-engine.js","src/node-ws-client.js"],"sourcesContent":["/**\n * Checks if `value` is classified as an `Array` object.\n *\n * @static\n * @memberOf _\n * @since 0.1.0\n * @category Lang\n * @param {*} value The value to check.\n * @returns {boolean} Returns `true` if `value` is an array, else `false`.\n * @example\n *\n * _.isArray([1, 2, 3]);\n * // => true\n *\n * _.isArray(document.body.children);\n * // => false\n *\n * _.isArray('abc');\n * // => false\n *\n * _.isArray(_.noop);\n * // => false\n */\nvar isArray = Array.isArray;\n\nexport default isArray;\n","export default (typeof global !== \"undefined\" ? global :\n typeof self !== \"undefined\" ? self :\n typeof window !== \"undefined\" ? window : {});\n","/** Used for built-in method references. */\nvar objectProto = Object.prototype;\n\n/**\n * Used to resolve the\n * [`toStringTag`](http://ecma-international.org/ecma-262/7.0/#sec-object.prototype.tostring)\n * of values.\n */\nvar nativeObjectToString = objectProto.toString;\n\n/**\n * Converts `value` to a string using `Object.prototype.toString`.\n *\n * @private\n * @param {*} value The value to convert.\n * @returns {string} Returns the converted string.\n */\nfunction objectToString(value) {\n return nativeObjectToString.call(value);\n}\n\nexport default objectToString;\n","/**\n * Creates a unary function that invokes `func` with its argument transformed.\n *\n * @private\n * @param {Function} func The function to wrap.\n * @param {Function} transform The argument transform.\n * @returns {Function} Returns the new function.\n */\nfunction overArg(func, transform) {\n return function(arg) {\n return func(transform(arg));\n };\n}\n\nexport default overArg;\n","/**\n * Checks if `value` is object-like. A value is object-like if it's not `null`\n * and has a `typeof` result of \"object\".\n *\n * @static\n * @memberOf _\n * @since 4.0.0\n * @category Lang\n * @param {*} value The value to check.\n * @returns {boolean} Returns `true` if `value` is object-like, else `false`.\n * @example\n *\n * _.isObjectLike({});\n * // => true\n *\n * _.isObjectLike([1, 2, 3]);\n * // => true\n *\n * _.isObjectLike(_.noop);\n * // => false\n *\n * _.isObjectLike(null);\n * // => false\n */\nfunction isObjectLike(value) {\n return value != null && typeof value == 'object';\n}\n\nexport default isObjectLike;\n","/**\n * A specialized version of `_.map` for arrays without support for iteratee\n * shorthands.\n *\n * @private\n * @param {Array} [array] The array to iterate over.\n * @param {Function} iteratee The function invoked per iteration.\n * @returns {Array} Returns the new mapped array.\n */\nfunction arrayMap(array, iteratee) {\n var index = -1,\n length = array == null ? 0 : array.length,\n result = Array(length);\n\n while (++index < length) {\n result[index] = iteratee(array[index], index, array);\n }\n return result;\n}\n\nexport default arrayMap;\n","/**\n * The base implementation of `_.slice` without an iteratee call guard.\n *\n * @private\n * @param {Array} array The array to slice.\n * @param {number} [start=0] The start position.\n * @param {number} [end=array.length] The end position.\n * @returns {Array} Returns the slice of `array`.\n */\nfunction baseSlice(array, start, end) {\n var index = -1,\n length = array.length;\n\n if (start < 0) {\n start = -start > length ? 0 : (length + start);\n }\n end = end > length ? length : end;\n if (end < 0) {\n end += length;\n }\n length = start > end ? 0 : ((end - start) >>> 0);\n start >>>= 0;\n\n var result = Array(length);\n while (++index < length) {\n result[index] = array[index + start];\n }\n return result;\n}\n\nexport default baseSlice;\n","/**\n * The base implementation of `_.findIndex` and `_.findLastIndex` without\n * support for iteratee shorthands.\n *\n * @private\n * @param {Array} array The array to inspect.\n * @param {Function} predicate The function invoked per iteration.\n * @param {number} fromIndex The index to search from.\n * @param {boolean} [fromRight] Specify iterating from right to left.\n * @returns {number} Returns the index of the matched value, else `-1`.\n */\nfunction baseFindIndex(array, predicate, fromIndex, fromRight) {\n var length = array.length,\n index = fromIndex + (fromRight ? 1 : -1);\n\n while ((fromRight ? index-- : ++index < length)) {\n if (predicate(array[index], index, array)) {\n return index;\n }\n }\n return -1;\n}\n\nexport default baseFindIndex;\n","/**\n * The base implementation of `_.isNaN` without support for number objects.\n *\n * @private\n * @param {*} value The value to check.\n * @returns {boolean} Returns `true` if `value` is `NaN`, else `false`.\n */\nfunction baseIsNaN(value) {\n return value !== value;\n}\n\nexport default baseIsNaN;\n","/**\n * A specialized version of `_.indexOf` which performs strict equality\n * comparisons of values, i.e. `===`.\n *\n * @private\n * @param {Array} array The array to inspect.\n * @param {*} value The value to search for.\n * @param {number} fromIndex The index to search from.\n * @returns {number} Returns the index of the matched value, else `-1`.\n */\nfunction strictIndexOf(array, value, fromIndex) {\n var index = fromIndex - 1,\n length = array.length;\n\n while (++index < length) {\n if (array[index] === value) {\n return index;\n }\n }\n return -1;\n}\n\nexport default strictIndexOf;\n","/**\n * Converts an ASCII `string` to an array.\n *\n * @private\n * @param {string} string The string to convert.\n * @returns {Array} Returns the converted array.\n */\nfunction asciiToArray(string) {\n return string.split('');\n}\n\nexport default asciiToArray;\n","/** Used to compose unicode character classes. */\nvar rsAstralRange = '\\\\ud800-\\\\udfff',\n rsComboMarksRange = '\\\\u0300-\\\\u036f',\n reComboHalfMarksRange = '\\\\ufe20-\\\\ufe2f',\n rsComboSymbolsRange = '\\\\u20d0-\\\\u20ff',\n rsComboRange = rsComboMarksRange + reComboHalfMarksRange + rsComboSymbolsRange,\n rsVarRange = '\\\\ufe0e\\\\ufe0f';\n\n/** Used to compose unicode capture groups. */\nvar rsZWJ = '\\\\u200d';\n\n/** Used to detect strings with [zero-width joiners or code points from the astral planes](http://eev.ee/blog/2015/09/12/dark-corners-of-unicode/). */\nvar reHasUnicode = RegExp('[' + rsZWJ + rsAstralRange + rsComboRange + rsVarRange + ']');\n\n/**\n * Checks if `string` contains Unicode symbols.\n *\n * @private\n * @param {string} string The string to inspect.\n * @returns {boolean} Returns `true` if a symbol is found, else `false`.\n */\nfunction hasUnicode(string) {\n return reHasUnicode.test(string);\n}\n\nexport default hasUnicode;\n","/** Used to compose unicode character classes. */\nvar rsAstralRange = '\\\\ud800-\\\\udfff',\n rsComboMarksRange = '\\\\u0300-\\\\u036f',\n reComboHalfMarksRange = '\\\\ufe20-\\\\ufe2f',\n rsComboSymbolsRange = '\\\\u20d0-\\\\u20ff',\n rsComboRange = rsComboMarksRange + reComboHalfMarksRange + rsComboSymbolsRange,\n rsVarRange = '\\\\ufe0e\\\\ufe0f';\n\n/** Used to compose unicode capture groups. */\nvar rsAstral = '[' + rsAstralRange + ']',\n rsCombo = '[' + rsComboRange + ']',\n rsFitz = '\\\\ud83c[\\\\udffb-\\\\udfff]',\n rsModifier = '(?:' + rsCombo + '|' + rsFitz + ')',\n rsNonAstral = '[^' + rsAstralRange + ']',\n rsRegional = '(?:\\\\ud83c[\\\\udde6-\\\\uddff]){2}',\n rsSurrPair = '[\\\\ud800-\\\\udbff][\\\\udc00-\\\\udfff]',\n rsZWJ = '\\\\u200d';\n\n/** Used to compose unicode regexes. */\nvar reOptMod = rsModifier + '?',\n rsOptVar = '[' + rsVarRange + ']?',\n rsOptJoin = '(?:' + rsZWJ + '(?:' + [rsNonAstral, rsRegional, rsSurrPair].join('|') + ')' + rsOptVar + reOptMod + ')*',\n rsSeq = rsOptVar + reOptMod + rsOptJoin,\n rsSymbol = '(?:' + [rsNonAstral + rsCombo + '?', rsCombo, rsRegional, rsSurrPair, rsAstral].join('|') + ')';\n\n/** Used to match [string symbols](https://mathiasbynens.be/notes/javascript-unicode). */\nvar reUnicode = RegExp(rsFitz + '(?=' + rsFitz + ')|' + rsSymbol + rsSeq, 'g');\n\n/**\n * Converts a Unicode `string` to an array.\n *\n * @private\n * @param {string} string The string to convert.\n * @returns {Array} Returns the converted array.\n */\nfunction unicodeToArray(string) {\n return string.match(reUnicode) || [];\n}\n\nexport default unicodeToArray;\n","// bunch of generic helpers\n\nimport isArray from 'lodash-es/isArray'\nimport isPlainObject from 'lodash-es/isPlainObject'\nimport trim from 'lodash-es/trim'\n\n/**\n * DIY in Array\n * @param {array} arr to check from\n * @param {*} value to check against\n * @return {boolean} true on found\n */\nexport const inArray = (arr, value) => !!arr.filter(a => a === value).length\n\n// quick and dirty to turn non array to array\nexport const toArray = (arg) => isArray(arg) ? arg : [arg]\n\n/**\n * parse string to json or just return the original value if error happened\n * @param {*} n input\n * @param {boolean} [t=true] or throw\n * @return {*} json object on success\n */\nexport const parseJson = function(n, t=true) {\n try {\n return JSON.parse(n)\n } catch(e) {\n if (t) {\n return n\n }\n throw new Error(e)\n }\n}\n\n/**\n * @param {object} obj for search\n * @param {string} key target\n * @return {boolean} true on success\n */\nexport const isObjectHasKey = function(obj, key) {\n try {\n const keys = Object.keys(obj)\n return inArray(keys, key)\n } catch(e) {\n // @BUG when the obj is not an OBJECT we got some weird output\n return false\n }\n}\n\n/**\n * create a event name\n * @param {string[]} args\n * @return {string} event name for use\n */\nexport const createEvt = (...args) => args.join('_')\n\n/**\n * simple util method to get the value\n * @param {string} name of the key\n * @param {object} obj to take value from\n * @return {*} the object value id by name or undefined\n */\nexport const getConfigValue = (name, obj) => (\n obj && isPlainObject(obj) ? ( (name in obj) ? obj[name] : undefined ) : undefined\n)\n\n/**\n * small util to make sure the return value is valid JSON object\n * @param {*} n input\n * @return {object} correct JSON object\n */\nexport const toJson = n => {\n if (typeof n === 'string') {\n return parseJson(n)\n }\n return parseJson(JSON.stringify(n))\n}\n\n/**\n * Check several parameter that there is something in the param\n * @param {*} param input\n * @return {boolean}\n */\nexport const isNotEmpty = function(param) {\n return param !== undefined && param !== false && param !== null && trim(param) !== ''\n}\n\n/**\n * Simple check if the prop is function\n * @param {*} prop input\n * @return {boolean} true on success\n */\nexport const isFunc = prop => {\n if (typeof prop === 'function') {\n return true;\n }\n console.error(`Expect to be Function type! Got ${typeof prop}`)\n}\n\n/**\n * Shorthand method for Object.assign \n * @param {array} args \n * @return {object} merge together object by key \n */\nexport const assign = (...args) => Reflect.apply(Object.assign, Object, args)\n \n/** \n * generic placeholder function\n * @return {boolean} false \n */\nexport const nil = () => false\n\n/**\n * generic turn config into immutatble \n */\nexport const freeze = config => Object.freeze(config)","/**\n * Removes all key-value entries from the list cache.\n *\n * @private\n * @name clear\n * @memberOf ListCache\n */\nfunction listCacheClear() {\n this.__data__ = [];\n this.size = 0;\n}\n\nexport default listCacheClear;\n","/**\n * Performs a\n * [`SameValueZero`](http://ecma-international.org/ecma-262/7.0/#sec-samevaluezero)\n * comparison between two values to determine if they are equivalent.\n *\n * @static\n * @memberOf _\n * @since 4.0.0\n * @category Lang\n * @param {*} value The value to compare.\n * @param {*} other The other value to compare.\n * @returns {boolean} Returns `true` if the values are equivalent, else `false`.\n * @example\n *\n * var object = { 'a': 1 };\n * var other = { 'a': 1 };\n *\n * _.eq(object, object);\n * // => true\n *\n * _.eq(object, other);\n * // => false\n *\n * _.eq('a', 'a');\n * // => true\n *\n * _.eq('a', Object('a'));\n * // => false\n *\n * _.eq(NaN, NaN);\n * // => true\n */\nfunction eq(value, other) {\n return value === other || (value !== value && other !== other);\n}\n\nexport default eq;\n","/**\n * Removes `key` and its value from the stack.\n *\n * @private\n * @name delete\n * @memberOf Stack\n * @param {string} key The key of the value to remove.\n * @returns {boolean} Returns `true` if the entry was removed, else `false`.\n */\nfunction stackDelete(key) {\n var data = this.__data__,\n result = data['delete'](key);\n\n this.size = data.size;\n return result;\n}\n\nexport default stackDelete;\n","/**\n * Gets the stack value for `key`.\n *\n * @private\n * @name get\n * @memberOf Stack\n * @param {string} key The key of the value to get.\n * @returns {*} Returns the entry value.\n */\nfunction stackGet(key) {\n return this.__data__.get(key);\n}\n\nexport default stackGet;\n","/**\n * Checks if a stack value for `key` exists.\n *\n * @private\n * @name has\n * @memberOf Stack\n * @param {string} key The key of the entry to check.\n * @returns {boolean} Returns `true` if an entry for `key` exists, else `false`.\n */\nfunction stackHas(key) {\n return this.__data__.has(key);\n}\n\nexport default stackHas;\n","/**\n * Checks if `value` is the\n * [language type](http://www.ecma-international.org/ecma-262/7.0/#sec-ecmascript-language-types)\n * of `Object`. (e.g. arrays, functions, objects, regexes, `new Number(0)`, and `new String('')`)\n *\n * @static\n * @memberOf _\n * @since 0.1.0\n * @category Lang\n * @param {*} value The value to check.\n * @returns {boolean} Returns `true` if `value` is an object, else `false`.\n * @example\n *\n * _.isObject({});\n * // => true\n *\n * _.isObject([1, 2, 3]);\n * // => true\n *\n * _.isObject(_.noop);\n * // => true\n *\n * _.isObject(null);\n * // => false\n */\nfunction isObject(value) {\n var type = typeof value;\n return value != null && (type == 'object' || type == 'function');\n}\n\nexport default isObject;\n","/** Used for built-in method references. */\nvar funcProto = Function.prototype;\n\n/** Used to resolve the decompiled source of functions. */\nvar funcToString = funcProto.toString;\n\n/**\n * Converts `func` to its source code.\n *\n * @private\n * @param {Function} func The function to convert.\n * @returns {string} Returns the source code.\n */\nfunction toSource(func) {\n if (func != null) {\n try {\n return funcToString.call(func);\n } catch (e) {}\n try {\n return (func + '');\n } catch (e) {}\n }\n return '';\n}\n\nexport default toSource;\n","/**\n * Gets the value at `key` of `object`.\n *\n * @private\n * @param {Object} [object] The object to query.\n * @param {string} key The key of the property to get.\n * @returns {*} Returns the property value.\n */\nfunction getValue(object, key) {\n return object == null ? undefined : object[key];\n}\n\nexport default getValue;\n","/**\n * Removes `key` and its value from the hash.\n *\n * @private\n * @name delete\n * @memberOf Hash\n * @param {Object} hash The hash to modify.\n * @param {string} key The key of the value to remove.\n * @returns {boolean} Returns `true` if the entry was removed, else `false`.\n */\nfunction hashDelete(key) {\n var result = this.has(key) && delete this.__data__[key];\n this.size -= result ? 1 : 0;\n return result;\n}\n\nexport default hashDelete;\n","/**\n * Checks if `value` is suitable for use as unique object key.\n *\n * @private\n * @param {*} value The value to check.\n * @returns {boolean} Returns `true` if `value` is suitable, else `false`.\n */\nfunction isKeyable(value) {\n var type = typeof value;\n return (type == 'string' || type == 'number' || type == 'symbol' || type == 'boolean')\n ? (value !== '__proto__')\n : (value === null);\n}\n\nexport default isKeyable;\n","/**\n * Creates a base function for methods like `_.forIn` and `_.forOwn`.\n *\n * @private\n * @param {boolean} [fromRight] Specify iterating from right to left.\n * @returns {Function} Returns the new base function.\n */\nfunction createBaseFor(fromRight) {\n return function(object, iteratee, keysFunc) {\n var index = -1,\n iterable = Object(object),\n props = keysFunc(object),\n length = props.length;\n\n while (length--) {\n var key = props[fromRight ? length : ++index];\n if (iteratee(iterable[key], key, iterable) === false) {\n break;\n }\n }\n return object;\n };\n}\n\nexport default createBaseFor;\n","/**\n * Copies the values of `source` to `array`.\n *\n * @private\n * @param {Array} source The array to copy values from.\n * @param {Array} [array=[]] The array to copy values to.\n * @returns {Array} Returns `array`.\n */\nfunction copyArray(source, array) {\n var index = -1,\n length = source.length;\n\n array || (array = Array(length));\n while (++index < length) {\n array[index] = source[index];\n }\n return array;\n}\n\nexport default copyArray;\n","/** Used for built-in method references. */\nvar objectProto = Object.prototype;\n\n/**\n * Checks if `value` is likely a prototype object.\n *\n * @private\n * @param {*} value The value to check.\n * @returns {boolean} Returns `true` if `value` is a prototype, else `false`.\n */\nfunction isPrototype(value) {\n var Ctor = value && value.constructor,\n proto = (typeof Ctor == 'function' && Ctor.prototype) || objectProto;\n\n return value === proto;\n}\n\nexport default isPrototype;\n","/** Used as references for various `Number` constants. */\nvar MAX_SAFE_INTEGER = 9007199254740991;\n\n/**\n * Checks if `value` is a valid array-like length.\n *\n * **Note:** This method is loosely based on\n * [`ToLength`](http://ecma-international.org/ecma-262/7.0/#sec-tolength).\n *\n * @static\n * @memberOf _\n * @since 4.0.0\n * @category Lang\n * @param {*} value The value to check.\n * @returns {boolean} Returns `true` if `value` is a valid length, else `false`.\n * @example\n *\n * _.isLength(3);\n * // => true\n *\n * _.isLength(Number.MIN_VALUE);\n * // => false\n *\n * _.isLength(Infinity);\n * // => false\n *\n * _.isLength('3');\n * // => false\n */\nfunction isLength(value) {\n return typeof value == 'number' &&\n value > -1 && value % 1 == 0 && value <= MAX_SAFE_INTEGER;\n}\n\nexport default isLength;\n","/**\n * This method returns `false`.\n *\n * @static\n * @memberOf _\n * @since 4.13.0\n * @category Util\n * @returns {boolean} Returns `false`.\n * @example\n *\n * _.times(2, _.stubFalse);\n * // => [false, false]\n */\nfunction stubFalse() {\n return false;\n}\n\nexport default stubFalse;\n","/**\n * The base implementation of `_.unary` without support for storing metadata.\n *\n * @private\n * @param {Function} func The function to cap arguments for.\n * @returns {Function} Returns the new capped function.\n */\nfunction baseUnary(func) {\n return function(value) {\n return func(value);\n };\n}\n\nexport default baseUnary;\n","/**\n * Gets the value at `key`, unless `key` is \"__proto__\" or \"constructor\".\n *\n * @private\n * @param {Object} object The object to query.\n * @param {string} key The key of the property to get.\n * @returns {*} Returns the property value.\n */\nfunction safeGet(object, key) {\n if (key === 'constructor' && typeof object[key] === 'function') {\n return;\n }\n\n if (key == '__proto__') {\n return;\n }\n\n return object[key];\n}\n\nexport default safeGet;\n","/**\n * The base implementation of `_.times` without support for iteratee shorthands\n * or max array length checks.\n *\n * @private\n * @param {number} n The number of times to invoke `iteratee`.\n * @param {Function} iteratee The function invoked per iteration.\n * @returns {Array} Returns the array of results.\n */\nfunction baseTimes(n, iteratee) {\n var index = -1,\n result = Array(n);\n\n while (++index < n) {\n result[index] = iteratee(index);\n }\n return result;\n}\n\nexport default baseTimes;\n","/** Used as references for various `Number` constants. */\nvar MAX_SAFE_INTEGER = 9007199254740991;\n\n/** Used to detect unsigned integer values. */\nvar reIsUint = /^(?:0|[1-9]\\d*)$/;\n\n/**\n * Checks if `value` is a valid array-like index.\n *\n * @private\n * @param {*} value The value to check.\n * @param {number} [length=MAX_SAFE_INTEGER] The upper bounds of a valid index.\n * @returns {boolean} Returns `true` if `value` is a valid index, else `false`.\n */\nfunction isIndex(value, length) {\n var type = typeof value;\n length = length == null ? MAX_SAFE_INTEGER : length;\n\n return !!length &&\n (type == 'number' ||\n (type != 'symbol' && reIsUint.test(value))) &&\n (value > -1 && value % 1 == 0 && value < length);\n}\n\nexport default isIndex;\n","/**\n * This function is like\n * [`Object.keys`](http://ecma-international.org/ecma-262/7.0/#sec-object.keys)\n * except that it includes inherited enumerable properties.\n *\n * @private\n * @param {Object} object The object to query.\n * @returns {Array} Returns the array of property names.\n */\nfunction nativeKeysIn(object) {\n var result = [];\n if (object != null) {\n for (var key in Object(object)) {\n result.push(key);\n }\n }\n return result;\n}\n\nexport default nativeKeysIn;\n","/**\n * This method returns the first argument it receives.\n *\n * @static\n * @since 0.1.0\n * @memberOf _\n * @category Util\n * @param {*} value Any value.\n * @returns {*} Returns `value`.\n * @example\n *\n * var object = { 'a': 1 };\n *\n * console.log(_.identity(object) === object);\n * // => true\n */\nfunction identity(value) {\n return value;\n}\n\nexport default identity;\n","/**\n * A faster alternative to `Function#apply`, this function invokes `func`\n * with the `this` binding of `thisArg` and the arguments of `args`.\n *\n * @private\n * @param {Function} func The function to invoke.\n * @param {*} thisArg The `this` binding of `func`.\n * @param {Array} args The arguments to invoke `func` with.\n * @returns {*} Returns the result of `func`.\n */\nfunction apply(func, thisArg, args) {\n switch (args.length) {\n case 0: return func.call(thisArg);\n case 1: return func.call(thisArg, args[0]);\n case 2: return func.call(thisArg, args[0], args[1]);\n case 3: return func.call(thisArg, args[0], args[1], args[2]);\n }\n return func.apply(thisArg, args);\n}\n\nexport default apply;\n","/**\n * Creates a function that returns `value`.\n *\n * @static\n * @memberOf _\n * @since 2.4.0\n * @category Util\n * @param {*} value The value to return from the new function.\n * @returns {Function} Returns the new constant function.\n * @example\n *\n * var objects = _.times(2, _.constant({ 'a': 1 }));\n *\n * console.log(objects);\n * // => [{ 'a': 1 }, { 'a': 1 }]\n *\n * console.log(objects[0] === objects[1]);\n * // => true\n */\nfunction constant(value) {\n return function() {\n return value;\n };\n}\n\nexport default constant;\n","/** Used to detect hot functions by number of calls within a span of milliseconds. */\nvar HOT_COUNT = 800,\n HOT_SPAN = 16;\n\n/* Built-in method references for those with the same name as other `lodash` methods. */\nvar nativeNow = Date.now;\n\n/**\n * Creates a function that'll short out and invoke `identity` instead\n * of `func` when it's called `HOT_COUNT` or more times in `HOT_SPAN`\n * milliseconds.\n *\n * @private\n * @param {Function} func The function to restrict.\n * @returns {Function} Returns the new shortable function.\n */\nfunction shortOut(func) {\n var count = 0,\n lastCalled = 0;\n\n return function() {\n var stamp = nativeNow(),\n remaining = HOT_SPAN - (stamp - lastCalled);\n\n lastCalled = stamp;\n if (remaining > 0) {\n if (++count >= HOT_COUNT) {\n return arguments[0];\n }\n } else {\n count = 0;\n }\n return func.apply(undefined, arguments);\n };\n}\n\nexport default shortOut;\n","// this get throw from within the checkOptions when run through the enum failed\nexport default class JsonqlEnumError extends Error {\n constructor(...args) {\n super(...args)\n\n this.message = args[0]\n this.detail = args[1]\n\n this.className = JsonqlEnumError.name;\n\n if (Error.captureStackTrace) {\n Error.captureStackTrace(this, JsonqlEnumError)\n }\n }\n\n static get name() {\n return 'JsonqlEnumError'\n }\n}\n","// this will throw from inside the checkOptions\nexport default class JsonqlTypeError extends Error {\n constructor(...args) {\n super(...args)\n\n this.message = args[0]\n this.detail = args[1]\n\n this.className = JsonqlTypeError.name\n\n if (Error.captureStackTrace) {\n Error.captureStackTrace(this, JsonqlTypeError)\n }\n }\n\n static get name() {\n return 'JsonqlTypeError'\n }\n}\n","// allow supply a custom checker function\n// if that failed then we throw this error\nexport default class JsonqlCheckerError extends Error {\n constructor(...args) {\n super(...args)\n this.message = args[0]\n this.detail = args[1]\n\n this.className = JsonqlCheckerError.name;\n\n if (Error.captureStackTrace) {\n Error.captureStackTrace(this, JsonqlCheckerError)\n }\n }\n\n static get name() {\n return 'JsonqlCheckerError'\n }\n}\n","// custom validation error class\n// when validaton failed\nexport default class JsonqlValidationError extends Error {\n constructor(...args) {\n super(...args)\n\n this.message = args[0]\n this.detail = args[1]\n\n this.className = JsonqlValidationError.name;\n\n if (Error.captureStackTrace) {\n Error.captureStackTrace(this, JsonqlValidationError)\n }\n }\n\n static get name() {\n return 'JsonqlValidationError'\n }\n}\n","// split the contract into the node side and the generic side\nimport { isObjectHasKey } from './generic'\nimport isPlainObject from 'lodash-es/isPlainObject'\nimport {\n QUERY_NAME,\n MUTATION_NAME,\n SOCKET_NAME,\n QUERY_ARG_NAME,\n PAYLOAD_PARAM_NAME,\n CONDITION_PARAM_NAME\n} from 'jsonql-constants'\nimport { JsonqlError, JsonqlResolverNotFoundError } from 'jsonql-errors'\n/**\n * Check if the json is a contract file or not\n * @param {object} contract json object\n * @return {boolean} true\n */\nexport function checkIsContract(contract) {\n return isPlainObject(contract)\n && (\n isObjectHasKey(contract, QUERY_NAME)\n || isObjectHasKey(contract, MUTATION_NAME)\n || isObjectHasKey(contract, SOCKET_NAME)\n )\n}\n\n/**\n * Wrapper method that check if it's contract then return the contract or false\n * @param {object} contract the object to check\n * @return {boolean | object} false when it's not\n */\nexport function isContract(contract) {\n return checkIsContract(contract) ? contract : false\n}\n\n/**\n * Ported from jsonql-params-validator but different\n * if we don't find the socket part then return false\n * @param {object} contract the contract object\n * @return {object|boolean} false on failed\n */\nexport function extractSocketPart(contract) {\n if (isObjectHasKey(contract, SOCKET_NAME)) {\n return contract[SOCKET_NAME]\n }\n return false\n}\n\n/**\n * Extract the args from the payload\n * @param {object} payload to work with\n * @param {string} type of call\n * @return {array} args\n */\nexport function extractArgsFromPayload(payload, type) {\n switch (type) {\n case QUERY_NAME:\n return payload[QUERY_ARG_NAME]\n case MUTATION_NAME:\n return [\n payload[PAYLOAD_PARAM_NAME],\n payload[CONDITION_PARAM_NAME]\n ]\n default:\n throw new JsonqlError(`Unknown ${type} to extract argument from!`)\n }\n}\n\n/**\n * Like what the name said\n * @param {object} contract the contract json\n * @param {string} type query|mutation\n * @param {string} name of the function\n * @return {object} the params part of the contract\n */\nexport function extractParamsFromContract(contract, type, name) {\n try {\n const result = contract[type][name]\n // debug('extractParamsFromContract', result)\n if (!result) {\n // debug(name, type, contract)\n throw new JsonqlResolverNotFoundError(name, type)\n }\n return result\n } catch(e) {\n throw new JsonqlResolverNotFoundError(name, e)\n }\n}\n","/**\n * @param {boolean} sec return in second or not\n * @return {number} timestamp\n */\nexport const timestamp = (sec = false) => {\n let time = Date.now()\n return sec ? Math.floor( time / 1000 ) : time\n}\n","// ported from jsonql-params-validator\n// craete several helper function to construct / extract the payload\n// and make sure they are all the same\nimport {\n PAYLOAD_PARAM_NAME,\n CONDITION_PARAM_NAME,\n RESOLVER_PARAM_NAME,\n QUERY_ARG_NAME,\n TIMESTAMP_PARAM_NAME\n} from 'jsonql-constants'\n\nimport JsonqlValidationError from 'jsonql-errors/src/validation-error'\n\nimport isArray from 'lodash-es/isArray'\nimport isString from 'lodash-es/isString'\nimport isPlainObject from 'lodash-es/isPlainObject'\n\nimport { timestamp } from './timestamp'\nimport { parseJson } from './generic'\n\n/**\n * check if the payload has a timestamp field, then append a new timestamp to it\n * @param {object} payload from the com\n * @return {array} timestamp field with an array value\n */\nexport const handleTimestamp = payload => {\n let ts = payload[TIMESTAMP_PARAM_NAME]\n if (!isArray(ts)) {\n ts = [ts]\n }\n ts.push( timestamp() )\n\n return ts\n}\n\n/**\n * make sure it's an object (it was call formatPayload but it doesn't make sense)\n * @param {*} payload the object comes in could be string based\n * @return {object} the transformed payload\n */\nexport const toPayload = payload => isString(payload) ? parseJson(payload) : payload\n\n/**\n * @param {*} args arguments to send\n *@return {object} formatted payload\n */\nexport const formatPayload = (args) => (\n { [QUERY_ARG_NAME]: args }\n)\n\n/**\n * extract the resolver name from the payload \n * @param {object} payload\n * @return {string} resolver name \n */\nexport function getResolverFromPayload(payload) {\n const keys = Object.keys(payload)\n return keys.filter(key => key !== TIMESTAMP_PARAM_NAME)[0]\n}\n\n/**\n * wrapper method to add the timestamp as well\n * @param {string} resolverName\n * @param {*} payload\n * @return {object} delierable\n */\nexport function createDeliverable(resolverName, payload) {\n return {\n [resolverName]: payload,\n [TIMESTAMP_PARAM_NAME]: [ timestamp() ]\n }\n}\n\n/**\n * @param {string} resolverName name of function\n * @param {array} [args=[]] from the ...args\n * @param {boolean} [jsonp = false] add v1.3.0 to koa\n * @return {object} formatted argument\n */\nexport function createQuery(resolverName, args = [], jsonp = false) {\n if (isString(resolverName) && isArray(args)) {\n let payload = formatPayload(args)\n if (jsonp === true) {\n return payload\n }\n return createDeliverable(resolverName, payload)\n }\n throw new JsonqlValidationError(`[createQuery] expect resolverName to be string and args to be array!`, { resolverName, args })\n}\n\n/**\n * string version of the createQuery\n * @return {string}\n */\nexport function createQueryStr(resolverName, args = [], jsonp = false) {\n return JSON.stringify(createQuery(resolverName, args, jsonp))\n}\n\n/**\n * @param {string} resolverName name of function\n * @param {*} payload to send\n * @param {object} [condition={}] for what\n * @param {boolean} [jsonp = false] add v1.3.0 to koa\n * @return {object} formatted argument\n */\nexport function createMutation(resolverName, payload, condition = {}, jsonp = false) {\n const _payload = {\n [PAYLOAD_PARAM_NAME]: payload,\n [CONDITION_PARAM_NAME]: condition\n }\n if (jsonp === true) {\n return _payload\n }\n if (isString(resolverName)) {\n return createDeliverable(resolverName, _payload)\n }\n throw new JsonqlValidationError(`[createMutation] expect resolverName to be string!`, { resolverName, payload, condition })\n}\n\n/**\n * string version of createMutation\n * @return {string}\n */\nexport function createMutationStr(resolverName, payload, condition = {}, jsonp = false) {\n return JSON.stringify(createMutation(resolverName, payload, condition, jsonp))\n}\n\n/**\n * Extract the parts from payload and format for use\n * @param {string} resolverName name of fn\n * @param {object} payload the incoming json\n * @return {object|boolean} false on failed\n */\nexport function getQueryFromArgs(resolverName, payload) {\n if (resolverName && isPlainObject(payload)) {\n const args = payload[resolverName]\n if (args[QUERY_ARG_NAME]) {\n return {\n [RESOLVER_PARAM_NAME]: resolverName,\n [QUERY_ARG_NAME]: args[QUERY_ARG_NAME],\n [TIMESTAMP_PARAM_NAME]: handleTimestamp(payload)\n }\n }\n }\n return false\n}\n\n/**\n * Share function so no repeat\n * @param {object} payload the payload from client\n * @param {function} processor the last get result method\n * @return {*} result processed result\n */\nfunction processPayload(payload, processor) {\n const p = toPayload(payload)\n const resolverName = getResolverFromPayload(p)\n return Reflect.apply(processor, null, [resolverName, p])\n}\n\n/**\n * extra the payload back\n * @param {*} payload from http call\n * @return {object} resolverName and args\n */\nexport function getQueryFromPayload(payload) {\n const result = processPayload(payload, getQueryFromArgs)\n if (result !== false) {\n return result\n }\n throw new JsonqlValidationError('[getQueryArgs] Payload is malformed!', payload)\n}\n\n/**\n * Further break down from method below for use else where\n * @param {string} resolverName name of fn\n * @param {object} payload payload\n * @return {object|boolean} false on failed\n */\nexport function getMutationFromArgs(resolverName, payload) {\n if (resolverName && isPlainObject(payload)) {\n const args = payload[resolverName]\n if (args) {\n return {\n [RESOLVER_PARAM_NAME]: resolverName,\n [PAYLOAD_PARAM_NAME]: args[PAYLOAD_PARAM_NAME],\n [CONDITION_PARAM_NAME]: args[CONDITION_PARAM_NAME],\n [TIMESTAMP_PARAM_NAME]: handleTimestamp(payload)\n }\n }\n }\n return false\n}\n\n/**\n * @param {object} payload\n * @return {object} resolverName, payload, conditon\n */\nexport function getMutationFromPayload(payload) {\n const result = processPayload(payload, getMutationFromArgs)\n\n if (result !== false) {\n return result\n }\n throw new JsonqlValidationError('[getMutationArgs] Payload is malformed!', payload)\n}\n","// take out all the namespace related methods in one place for easy to find\nimport {\n JSONQL_PATH,\n PUBLIC_KEY,\n NSP_GROUP,\n PUBLIC_NAMESPACE\n} from 'jsonql-constants'\nimport { extractSocketPart } from './contract'\nconst SOCKET_NOT_FOUND_ERR = `socket not found in contract!`\nconst SIZE = 'size'\n\n/**\n * create the group using publicNamespace when there is only public\n * @param {object} socket from contract\n * @param {string} publicNamespace\n */\nfunction groupPublicNamespace(socket, publicNamespace) {\n let g = {}\n for (let resolverName in socket) {\n let params = socket[resolverName]\n g[resolverName] = params\n }\n return { size: 1, nspGroup: {[publicNamespace]: g}, publicNamespace}\n}\n\n\n/**\n * @BUG we should check the socket part instead of expect the downstream to read the menu!\n * We only need this when the enableAuth is true otherwise there is only one namespace\n * @param {object} contract the socket part of the contract file\n * @return {object} 1. remap the contract using the namespace --> resolvers\n * 2. the size of the object (1 all private, 2 mixed public with private)\n * 3. which namespace is public\n */\nexport function groupByNamespace(contract) {\n let socket = extractSocketPart(contract)\n if (socket === false) {\n throw new JsonqlError('groupByNamespace', SOCKET_NOT_FOUND_ERR)\n }\n let prop = {\n [NSP_GROUP]: {},\n [PUBLIC_NAMESPACE]: null,\n [SIZE]: 0 \n }\n\n for (let resolverName in socket) {\n let params = socket[resolverName]\n let { namespace } = params\n if (namespace) {\n if (!prop[NSP_GROUP][namespace]) {\n ++prop[SIZE]\n prop[NSP_GROUP][namespace] = {}\n }\n prop[NSP_GROUP][namespace][resolverName] = params\n // get the public namespace\n if (!prop[PUBLIC_NAMESPACE] && params[PUBLIC_KEY]) {\n prop[PUBLIC_NAMESPACE] = namespace\n }\n }\n }\n \n return prop \n}\n\n/**\n * @NOTE ported from jsonql-ws-client\n * Got to make sure the connection order otherwise\n * it will hang\n * @param {object} nspGroup contract\n * @param {string} publicNamespace like the name said\n * @return {array} namespaces in order\n */\nexport function getNamespaceInOrder(nspGroup, publicNamespace) {\n let names = [] // need to make sure the order!\n for (let namespace in nspGroup) {\n if (namespace === publicNamespace) {\n names[1] = namespace\n } else {\n names[0] = namespace\n }\n }\n return names\n}\n\n/**\n * @TODO this might change, what if we want to do room with ws\n * 1. there will only be max two namespace\n * 2. when it's normal we will have the stock path as namespace\n * 3. when enableAuth then we will have two, one is jsonql/public + private\n * @param {object} config options\n * @return {array} of namespace(s)\n */\nexport function getNamespace(config) {\n const base = JSONQL_PATH\n if (config.enableAuth) {\n // the public come first @1.0.1 we use the constants instead of the user supplied value\n // @1.0.4 we use the config value again, because we could control this via the post init\n return [\n [ base , config.privateNamespace ].join('/'),\n [ base , config.publicNamespace ].join('/')\n ]\n }\n return [ base ]\n}\n\n/**\n * get the private namespace\n * @param {array} namespaces array\n * @return {*} string on success\n */\nexport function getPrivateNamespace(namespaces) {\n return namespaces.length > 1 ? namespaces[0] : false\n}\n\n/**\n * Got a problem with a contract that is public only the groupByNamespace is wrong\n * which is actually not a problem when using a fallback, but to be sure things in order\n * we could combine with the config to group it\n * @param {object} config configuration\n * @return {object} nspInfo object\n */\nexport function getNspInfoByConfig(config) {\n const { contract, enableAuth } = config\n const namespaces = getNamespace(config)\n let nspInfo = enableAuth ? groupByNamespace(contract)\n : groupPublicNamespace(contract.socket, namespaces[0])\n // add the namespaces into it as well\n return Object.assign(nspInfo, { namespaces })\n}\n\n","// There are the socket related methods ported back from \n// ws-server-core and ws-client-core \nimport {\n WS_REPLY_TYPE,\n WS_EVT_NAME,\n WS_DATA_NAME,\n TIMESTAMP_PARAM_NAME,\n ERROR_KEY,\n EMIT_REPLY_TYPE,\n ACKNOWLEDGE_REPLY_TYPE\n} from 'jsonql-constants'\nimport { JsonqlError } from 'jsonql-errors' \nimport isString from 'lodash-es/isString'\n\nimport { toJson, isObjectHasKey, nil } from './generic'\nimport { timestamp } from './timestamp'\n\nconst PAYLOAD_NOT_DECODED_ERR = 'payload can not decoded'\nconst WS_KEYS = [\n WS_REPLY_TYPE,\n WS_EVT_NAME,\n WS_DATA_NAME\n]\n\n/////////////////////////////////////\n// REPLY FROM SERVER //\n/////////////////////////////////////\n\n\n/**\n * The ws doesn't have a acknowledge callback like socket.io\n * so we have to DIY one for ws and other that doesn't have it\n * @param {string} type of reply\n * @param {string} resolverName which is replying\n * @param {*} data payload\n * @param {array} [ts= []] the last received ts, if any \n * @return {string} stringify json\n */\nexport const createWsReply = (type, resolverName, data, ts = []) => {\n ts.push(timestamp())\n return JSON.stringify({\n data: {\n [WS_REPLY_TYPE]: type,\n [WS_EVT_NAME]: resolverName,\n [WS_DATA_NAME]: toJson(data)\n },\n [TIMESTAMP_PARAM_NAME]: ts \n })\n}\n\n// extended function \nexport const createReplyMsg = (resolverName, data, ts = []) => (\n createWsReply(EMIT_REPLY_TYPE, resolverName, data, ts)\n)\n\nexport const createAcknowledgeMsg = (resolverName, data, ts = []) => (\n createWsReply(ACKNOWLEDGE_REPLY_TYPE, resolverName, data, ts)\n)\n\n/**\n * @param {string|object} payload should be string when reply but could be transformed\n * @return {boolean} true is OK\n */\nexport const isWsReply = payload => {\n const json = isString(payload) ? toJson(payload) : payload\n const { data } = json\n if (data) {\n let result = WS_KEYS.filter(key => isObjectHasKey(data, key))\n return (result.length === WS_KEYS.length) ? data : false\n }\n return false\n}\n\n/**\n * @param {string|object} data received data\n * @param {function} [cb=nil] this is for extracting the TS field or when it's error\n * @return {object} false on failed\n */\nexport const extractWsPayload = (payload, cb = nil) => {\n try {\n const json = toJson(payload)\n // now handle the data\n let _data\n if ((_data = isWsReply(json)) !== false) {\n // note the ts property is on its own \n cb(TIMESTAMP_PARAM_NAME, json[TIMESTAMP_PARAM_NAME])\n \n return {\n data: toJson(_data[WS_DATA_NAME]),\n resolverName: _data[WS_EVT_NAME],\n type: _data[WS_REPLY_TYPE]\n }\n }\n throw new JsonqlError(PAYLOAD_NOT_DECODED_ERR, payload)\n } catch(e) {\n return cb(ERROR_KEY, e)\n }\n}\n","// this will be part of the init client sequence\n// as soon as we create a ws client\n// we listen to the on.connect event \n// then we send a init-ping event back to the server\n// and server issue a csrf token back to use \n// we use this token to create a new client and destroy the old one\nimport {\n INTERCOM_RESOLVER_NAME, \n SOCKET_PING_EVENT_NAME,\n HEADERS_KEY,\n DATA_KEY,\n CSRF_HEADER_KEY\n} from 'jsonql-constants'\nimport { \n createQueryStr, \n extractWsPayload,\n timestamp,\n toJson \n} from 'jsonql-utils/module'\nimport {\n JsonqlError\n} from 'jsonql-errors'\nconst CSRF_HEADER_NOT_EXIST_ERR = 'CSRF header is not in the received payload'\n\n/**\n * Util method \n * @param {string} payload return from server\n * @return {object} the useful bit \n */\nfunction extractSrvPayload(payload) {\n let json = toJson(payload)\n \n if (json && typeof json === 'object') {\n // note this method expect the json.data inside\n return extractWsPayload(json)\n }\n \n throw new JsonqlError('extractSrvPayload', json)\n}\n\n/**\n * call the server to get a csrf token \n * @return {string} formatted payload to send to the server \n */\nfunction createInitPing() {\n const ts = timestamp()\n\n return createQueryStr(INTERCOM_RESOLVER_NAME, [SOCKET_PING_EVENT_NAME, ts])\n}\n\n/**\n * Take the raw on.message result back then decoded it \n * @param {*} payload the raw result from server\n * @return {object} the csrf payload\n */\nfunction extractPingResult(payload) {\n const result = extractSrvPayload(payload)\n \n if (result && result[DATA_KEY] && result[DATA_KEY][CSRF_HEADER_KEY]) {\n return {\n [HEADERS_KEY]: result[DATA_KEY]\n }\n }\n\n throw new JsonqlError('extractPingResult', CSRF_HEADER_NOT_EXIST_ERR)\n}\n\n\n/**\n * Create a generic intercom method\n * @param {string} type the event type \n * @param {array} args if any \n * @return {string} formatted payload to send\n */\nfunction createIntercomPayload(type, ...args) {\n const ts = timestamp()\n let payload = [type].concat(args)\n payload.push(ts)\n return createQueryStr(INTERCOM_RESOLVER_NAME, payload)\n}\n\n\nexport { \n extractSrvPayload,\n createInitPing, \n extractPingResult, \n createIntercomPayload \n}","// validator numbers\n// import { NUMBER_TYPES } from './constants';\n\nimport isNaN from 'lodash-es/isNaN'\nimport isString from 'lodash-es/isString'\n/**\n * @2015-05-04 found a problem if the value is a number like string\n * it will pass, so add a chck if it's string before we pass to next\n * @param {number} value expected value\n * @return {boolean} true if OK\n */\nconst checkIsNumber = function(value) {\n return isString(value) ? false : !isNaN( parseFloat(value) )\n}\n\nexport default checkIsNumber\n","// validate string type\nimport trim from 'lodash-es/trim'\nimport isString from 'lodash-es/isString'\n/**\n * @param {string} value expected value\n * @return {boolean} true if OK\n */\nconst checkIsString = function(value) {\n return (trim(value) !== '') ? isString(value) : false\n}\n\nexport default checkIsString\n","// check for boolean\n\n/**\n * @param {boolean} value expected\n * @return {boolean} true if OK\n */\nconst checkIsBoolean = function(value) {\n return value !== null && value !== undefined && typeof value === 'boolean'\n}\n\nexport default checkIsBoolean\n","// validate any thing only check if there is something\n\nimport trim from 'lodash-es/trim'\n\n/**\n * @param {*} value the value\n * @param {boolean} [checkNull=true] strict check if there is null value\n * @return {boolean} true is OK\n */\nconst checkIsAny = function(value, checkNull = true) {\n if (value !== undefined && value !== '' && trim(value) !== '') {\n if (checkNull === false || (checkNull === true && value !== null)) {\n return true;\n }\n }\n return false;\n}\n\nexport default checkIsAny\n","// Good practice rule - No magic number\n\nconst ARGS_NOT_ARRAY_ERR = `args is not an array! You might want to do: ES6 Array.from(arguments) or ES5 Array.prototype.slice.call(arguments)`\nconst PARAMS_NOT_ARRAY_ERR = `params is not an array! Did something gone wrong when you generate the contract.json?`\nconst EXCEPTION_CASE_ERR = 'Could not understand your arguments and parameter structure!'\nconst UNUSUAL_CASE_ERR = 'This is an unusual situation where the arguments are more than the params, but not mark as spread'\n\nconst RETURNS_NAME = 'returns'\n\nimport {\n \n DEFAULT_TYPE, // this is a mistake should move back to the validation\n DATA_KEY, \n ERROR_KEY,\n\n TYPE_KEY,\n OPTIONAL_KEY,\n ENUM_KEY,\n ARGS_KEY,\n CHECKER_KEY,\n ALIAS_KEY,\n\n ARRAY_TYPE_LFT,\n ARRAY_TYPE_RGT,\n \n ARRAY_TYPE,\n OBJECT_TYPE,\n STRING_TYPE,\n BOOLEAN_TYPE,\n NUMBER_TYPE,\n KEY_WORD,\n OR_SEPERATOR\n} from 'jsonql-constants'\n\n// group all export in one \nexport {\n ARGS_NOT_ARRAY_ERR,\n PARAMS_NOT_ARRAY_ERR,\n EXCEPTION_CASE_ERR,\n UNUSUAL_CASE_ERR,\n DEFAULT_TYPE,\n ARRAY_TYPE_LFT,\n ARRAY_TYPE_RGT,\n TYPE_KEY,\n OPTIONAL_KEY,\n ENUM_KEY,\n ARGS_KEY,\n CHECKER_KEY,\n ALIAS_KEY,\n ARRAY_TYPE,\n OBJECT_TYPE,\n STRING_TYPE,\n BOOLEAN_TYPE,\n NUMBER_TYPE,\n KEY_WORD,\n OR_SEPERATOR,\n\n RETURNS_NAME,\n\n DATA_KEY, \n ERROR_KEY \n}","// primitive types\nimport checkIsNumber from './number'\nimport checkIsString from './string'\nimport checkIsBoolean from './boolean'\nimport checkIsAny from './any'\nimport { NUMBER_TYPE, STRING_TYPE, BOOLEAN_TYPE } from './constants'\n\n/**\n * this is a wrapper method to call different one based on their type\n * @param {string} type to check\n * @return {function} a function to handle the type\n */\nconst combineFn = function(type) {\n switch (type) {\n case NUMBER_TYPE:\n return checkIsNumber\n case STRING_TYPE:\n return checkIsString\n case BOOLEAN_TYPE:\n return checkIsBoolean\n default:\n return checkIsAny\n }\n}\n\nexport default combineFn\n","// validate array type\n\nimport isArray from 'lodash-es/isArray'\nimport trim from 'lodash-es/trim'\nimport combineFn from './combine'\nimport {\n ARRAY_TYPE_LFT,\n ARRAY_TYPE_RGT,\n OR_SEPERATOR\n} from './constants'\n\n/**\n * @param {array} value expected\n * @param {string} [type=''] pass the type if we encounter array. then we need to check the value as well\n * @return {boolean} true if OK\n */\nexport const checkIsArray = function(value, type='') {\n if (isArray(value)) {\n if (type === '' || trim(type)==='') {\n return true;\n }\n // we test it in reverse\n // @TODO if the type is an array (OR) then what?\n // we need to take into account this could be an array\n const c = value.filter(v => !combineFn(type)(v))\n return !(c.length > 0)\n }\n return false\n}\n\n/**\n * check if it matches the array. pattern\n * @param {string} type\n * @return {boolean|array} false means NO, always return array\n */\nexport const isArrayLike = function(type) {\n // @TODO could that have something like array<> instead of array.<>? missing the dot?\n // because type script is Array without the dot\n if (type.indexOf(ARRAY_TYPE_LFT) > -1 && type.indexOf(ARRAY_TYPE_RGT) > -1) {\n const _type = type.replace(ARRAY_TYPE_LFT, '').replace(ARRAY_TYPE_RGT, '')\n if (_type.indexOf(OR_SEPERATOR)) {\n return _type.split(OR_SEPERATOR)\n }\n return [_type]\n }\n return false\n}\n\n/**\n * we might encounter something like array. then we need to take it apart\n * @param {object} p the prepared object for processing\n * @param {string|array} type the type came from \n * @return {boolean} for the filter to operate on\n */\nexport const arrayTypeHandler = function(p, type) {\n const { arg } = p\n // need a special case to handle the OR type\n // we need to test the args instead of the type(s)\n if (type.length > 1) {\n return !arg.filter(v => (\n !(type.length > type.filter(t => !combineFn(t)(v)).length)\n )).length\n }\n // type is array so this will be or!\n return type.length > type.filter(t => !checkIsArray(arg, t)).length\n}\n","// validate object type\n\nimport isPlainObject from 'lodash-es/isPlainObject'\n// import filter from 'lodash-es/filter'\nimport combineFn from './combine'\nimport { checkIsArray, isArrayLike, arrayTypeHandler } from './array'\n/**\n * @TODO if provide with the keys then we need to check if the key:value type as well\n * @param {object} value expected\n * @param {array} [keys=null] if it has the keys array to compare as well\n * @return {boolean} true if OK\n */\nexport const checkIsObject = function(value, keys=null) {\n if (isPlainObject(value)) {\n if (!keys) {\n return true\n }\n if (checkIsArray(keys)) {\n // please note we DON'T care if some is optional\n // plese refer to the contract.json for the keys\n return !keys.filter(key => {\n let _value = value[key.name];\n return !(key.type.length > key.type.filter(type => {\n let tmp;\n if (_value !== undefined) {\n if ((tmp = isArrayLike(type)) !== false) {\n return !arrayTypeHandler({arg: _value}, tmp)\n // return tmp.filter(t => !checkIsArray(_value, t)).length;\n // @TODO there might be an object within an object with keys as well :S\n }\n return !combineFn(type)(_value)\n }\n return true\n }).length)\n }).length;\n }\n }\n return false\n}\n\n/**\n * fold this into it's own function to handler different object type\n * @param {object} p the prepared object for process\n * @return {boolean}\n */\nexport const objectTypeHandler = function(p) {\n const { arg, param } = p\n let _args = [arg]\n if (Array.isArray(param.keys) && param.keys.length) {\n _args.push(param.keys)\n }\n // just simple check\n return Reflect.apply(checkIsObject, null, _args)\n}\n","// move the index.js code here that make more sense to find where things are\n\nimport {\n checkIsArray,\n isArrayLike,\n arrayTypeHandler,\n objectTypeHandler,\n combineFn,\n notEmpty\n} from './index'\n\nimport {\n DEFAULT_TYPE,\n ARRAY_TYPE,\n OBJECT_TYPE,\n ARGS_NOT_ARRAY_ERR,\n PARAMS_NOT_ARRAY_ERR,\n EXCEPTION_CASE_ERR,\n DATA_KEY, \n ERROR_KEY \n} from './constants'\n\n\nimport JsonqlValidationError from 'jsonql-errors/src/validation-error'\nimport JsonqlError from 'jsonql-errors/src/error'\n// import debug from 'debug'\n// const debugFn = debug('jsonql-params-validator:validator')\n// also export this for use in other places\n\n/**\n * We need to handle those optional parameter without a default value\n * @param {object} params from contract.json\n * @return {boolean} for filter operation false is actually OK\n */\nconst optionalHandler = function( params ) {\n const { arg, param } = params\n if (notEmpty(arg)) {\n // debug('call optional handler', arg, params);\n // loop through the type in param\n return !(param.type.length > param.type.filter(type =>\n validateHandler(type, params)\n ).length)\n }\n return false\n}\n\n/**\n * actually picking the validator\n * @param {*} type for checking\n * @param {*} value for checking\n * @return {boolean} true on OK\n */\nconst validateHandler = function(type, value) {\n let tmp;\n switch (true) {\n case type === OBJECT_TYPE:\n // debugFn('call OBJECT_TYPE')\n return !objectTypeHandler(value)\n case type === ARRAY_TYPE:\n // debugFn('call ARRAY_TYPE')\n return !checkIsArray(value.arg)\n // @TODO when the type is not present, it always fall through here\n // so we need to find a way to actually pre-check the type first\n // AKA check the contract.json map before running here\n case (tmp = isArrayLike(type)) !== false:\n // debugFn('call ARRAY_LIKE: %O', value)\n return !arrayTypeHandler(value, tmp)\n default:\n return !combineFn(type)(value.arg)\n }\n}\n\n/**\n * it get too longer to fit in one line so break it out from the fn below\n * @param {*} arg value\n * @param {object} param config\n * @return {*} value or apply default value\n */\nconst getOptionalValue = function(arg, param) {\n if (arg !== undefined) {\n return arg\n }\n return (param.optional === true && param.defaultvalue !== undefined ? param.defaultvalue : null)\n}\n\n/**\n * padding the arguments with defaultValue if the arguments did not provide the value\n * this will be the name export\n * @param {array} args normalized arguments\n * @param {array} params from contract.json\n * @return {array} merge the two together\n */\nexport const normalizeArgs = function(args, params) {\n // first we should check if this call require a validation at all\n // there will be situation where the function doesn't need args and params\n if (!checkIsArray(params)) {\n // debugFn('params value', params)\n throw new JsonqlValidationError(PARAMS_NOT_ARRAY_ERR)\n }\n if (params.length === 0) {\n return []\n }\n if (!checkIsArray(args)) {\n throw new JsonqlValidationError(ARGS_NOT_ARRAY_ERR)\n }\n // debugFn(args, params);\n // fall through switch\n switch(true) {\n case args.length == params.length: // standard\n return args.map((arg, i) => (\n {\n arg,\n index: i,\n param: params[i]\n }\n ))\n case params[0].variable === true: // using spread syntax\n const type = params[0].type;\n return args.map((arg, i) => (\n {\n arg,\n index: i, // keep the index for reference\n param: params[i] || { type, name: '_' }\n }\n ))\n // with optional defaultValue parameters\n case args.length < params.length:\n return params.map((param, i) => (\n {\n param,\n index: i,\n arg: getOptionalValue(args[i], param),\n optional: param.optional || false\n }\n ))\n // this one pass more than it should have anything after the args.length will be cast as any type\n case args.length > params.length:\n let ctn = params.length;\n // this happens when we have those array. type\n let _type = [ DEFAULT_TYPE ]\n // we only looking at the first one, this might be a @BUG\n /*\n if ((tmp = isArrayLike(params[0].type[0])) !== false) {\n _type = tmp;\n } */\n // if we use the params as guide then the rest will get throw out\n // which is not what we want, instead, anything without the param\n // will get a any type and optional flag\n return args.map((arg, i) => {\n let optional = i >= ctn ? true : !!params[i].optional\n let param = params[i] || { type: _type, name: `_${i}` }\n return {\n arg: optional ? getOptionalValue(arg, param) : arg,\n index: i,\n param,\n optional\n }\n })\n // @TODO find out if there is more cases not cover\n default: // this should never happen\n // debugFn('args', args)\n // debugFn('params', params)\n // this is unknown therefore we just throw it!\n throw new JsonqlError(EXCEPTION_CASE_ERR, { args, params })\n }\n}\n\n// what we want is after the validaton we also get the normalized result\n// which is with the optional property if the argument didn't provide it\n/**\n * process the array of params back to their arguments\n * @param {array} result the params result\n * @return {array} arguments\n */\nconst processReturn = result => result.map(r => r.arg)\n\n/**\n * validator main interface\n * @param {array} args the arguments pass to the method call\n * @param {array} params from the contract for that method\n * @param {boolean} [withResul=false] if true then this will return the normalize result as well\n * @return {array} empty array on success, or failed parameter and reasons\n */\nexport const validateSync = function(args, params, withResult = false) {\n let cleanArgs = normalizeArgs(args, params)\n let checkResult = cleanArgs.filter(p => {\n // v1.4.4 this fixed the problem, the root level optional is from the last fn\n if (p.optional === true || p.param.optional === true) {\n return optionalHandler(p)\n }\n // because array of types means OR so if one pass means pass\n return !(p.param.type.length > p.param.type.filter(\n type => validateHandler(type, p)\n ).length)\n })\n // using the same convention we been using all this time\n return !withResult ? checkResult : {\n [ERROR_KEY]: checkResult,\n [DATA_KEY]: processReturn(cleanArgs)\n }\n}\n\n/**\n * A wrapper method that return promise\n * @param {array} args arguments\n * @param {array} params from contract.json\n * @param {boolean} [withResul=false] if true then this will return the normalize result as well\n * @return {object} promise.then or catch\n */\nexport const validateAsync = function(args, params, withResult = false) {\n return new Promise((resolver, rejecter) => {\n const result = validateSync(args, params, withResult)\n if (withResult) {\n return result[ERROR_KEY].length ? rejecter(result[ERROR_KEY])\n : resolver(result[DATA_KEY])\n }\n // the different is just in the then or catch phrase\n return result.length ? rejecter(result) : resolver([])\n })\n}\n","/** Used to stand-in for `undefined` hash values. */\nvar HASH_UNDEFINED = '__lodash_hash_undefined__';\n\n/**\n * Adds `value` to the array cache.\n *\n * @private\n * @name add\n * @memberOf SetCache\n * @alias push\n * @param {*} value The value to cache.\n * @returns {Object} Returns the cache instance.\n */\nfunction setCacheAdd(value) {\n this.__data__.set(value, HASH_UNDEFINED);\n return this;\n}\n\nexport default setCacheAdd;\n","/**\n * Checks if `value` is in the array cache.\n *\n * @private\n * @name has\n * @memberOf SetCache\n * @param {*} value The value to search for.\n * @returns {number} Returns `true` if `value` is found, else `false`.\n */\nfunction setCacheHas(value) {\n return this.__data__.has(value);\n}\n\nexport default setCacheHas;\n","/**\n * A specialized version of `_.some` for arrays without support for iteratee\n * shorthands.\n *\n * @private\n * @param {Array} [array] The array to iterate over.\n * @param {Function} predicate The function invoked per iteration.\n * @returns {boolean} Returns `true` if any element passes the predicate check,\n * else `false`.\n */\nfunction arraySome(array, predicate) {\n var index = -1,\n length = array == null ? 0 : array.length;\n\n while (++index < length) {\n if (predicate(array[index], index, array)) {\n return true;\n }\n }\n return false;\n}\n\nexport default arraySome;\n","/**\n * Checks if a `cache` value for `key` exists.\n *\n * @private\n * @param {Object} cache The cache to query.\n * @param {string} key The key of the entry to check.\n * @returns {boolean} Returns `true` if an entry for `key` exists, else `false`.\n */\nfunction cacheHas(cache, key) {\n return cache.has(key);\n}\n\nexport default cacheHas;\n","/**\n * Converts `map` to its key-value pairs.\n *\n * @private\n * @param {Object} map The map to convert.\n * @returns {Array} Returns the key-value pairs.\n */\nfunction mapToArray(map) {\n var index = -1,\n result = Array(map.size);\n\n map.forEach(function(value, key) {\n result[++index] = [key, value];\n });\n return result;\n}\n\nexport default mapToArray;\n","/**\n * Converts `set` to an array of its values.\n *\n * @private\n * @param {Object} set The set to convert.\n * @returns {Array} Returns the values.\n */\nfunction setToArray(set) {\n var index = -1,\n result = Array(set.size);\n\n set.forEach(function(value) {\n result[++index] = value;\n });\n return result;\n}\n\nexport default setToArray;\n","/**\n * Appends the elements of `values` to `array`.\n *\n * @private\n * @param {Array} array The array to modify.\n * @param {Array} values The values to append.\n * @returns {Array} Returns `array`.\n */\nfunction arrayPush(array, values) {\n var index = -1,\n length = values.length,\n offset = array.length;\n\n while (++index < length) {\n array[offset + index] = values[index];\n }\n return array;\n}\n\nexport default arrayPush;\n","/**\n * A specialized version of `_.filter` for arrays without support for\n * iteratee shorthands.\n *\n * @private\n * @param {Array} [array] The array to iterate over.\n * @param {Function} predicate The function invoked per iteration.\n * @returns {Array} Returns the new filtered array.\n */\nfunction arrayFilter(array, predicate) {\n var index = -1,\n length = array == null ? 0 : array.length,\n resIndex = 0,\n result = [];\n\n while (++index < length) {\n var value = array[index];\n if (predicate(value, index, array)) {\n result[resIndex++] = value;\n }\n }\n return result;\n}\n\nexport default arrayFilter;\n","/**\n * This method returns a new empty array.\n *\n * @static\n * @memberOf _\n * @since 4.13.0\n * @category Util\n * @returns {Array} Returns the new empty array.\n * @example\n *\n * var arrays = _.times(2, _.stubArray);\n *\n * console.log(arrays);\n * // => [[], []]\n *\n * console.log(arrays[0] === arrays[1]);\n * // => false\n */\nfunction stubArray() {\n return [];\n}\n\nexport default stubArray;\n","/**\n * A specialized version of `matchesProperty` for source values suitable\n * for strict equality comparisons, i.e. `===`.\n *\n * @private\n * @param {string} key The key of the property to get.\n * @param {*} srcValue The value to match.\n * @returns {Function} Returns the new spec function.\n */\nfunction matchesStrictComparable(key, srcValue) {\n return function(object) {\n if (object == null) {\n return false;\n }\n return object[key] === srcValue &&\n (srcValue !== undefined || (key in Object(object)));\n };\n}\n\nexport default matchesStrictComparable;\n","/**\n * The base implementation of `_.hasIn` without support for deep paths.\n *\n * @private\n * @param {Object} [object] The object to query.\n * @param {Array|string} key The key to check.\n * @returns {boolean} Returns `true` if `key` exists, else `false`.\n */\nfunction baseHasIn(object, key) {\n return object != null && key in Object(object);\n}\n\nexport default baseHasIn;\n","/**\n * The base implementation of `_.property` without support for deep paths.\n *\n * @private\n * @param {string} key The key of the property to get.\n * @returns {Function} Returns the new accessor function.\n */\nfunction baseProperty(key) {\n return function(object) {\n return object == null ? undefined : object[key];\n };\n}\n\nexport default baseProperty;\n","/** Error message constants. */\nvar FUNC_ERROR_TEXT = 'Expected a function';\n\n/**\n * Creates a function that negates the result of the predicate `func`. The\n * `func` predicate is invoked with the `this` binding and arguments of the\n * created function.\n *\n * @static\n * @memberOf _\n * @since 3.0.0\n * @category Function\n * @param {Function} predicate The predicate to negate.\n * @returns {Function} Returns the new negated function.\n * @example\n *\n * function isEven(n) {\n * return n % 2 == 0;\n * }\n *\n * _.filter([1, 2, 3, 4, 5, 6], _.negate(isEven));\n * // => [1, 3, 5]\n */\nfunction negate(predicate) {\n if (typeof predicate != 'function') {\n throw new TypeError(FUNC_ERROR_TEXT);\n }\n return function() {\n var args = arguments;\n switch (args.length) {\n case 0: return !predicate.call(this);\n case 1: return !predicate.call(this, args[0]);\n case 2: return !predicate.call(this, args[0], args[1]);\n case 3: return !predicate.call(this, args[0], args[1], args[2]);\n }\n return !predicate.apply(this, args);\n };\n}\n\nexport default negate;\n","/**\n * The base implementation of methods like `_.findKey` and `_.findLastKey`,\n * without support for iteratee shorthands, which iterates over `collection`\n * using `eachFunc`.\n *\n * @private\n * @param {Array|Object} collection The collection to inspect.\n * @param {Function} predicate The function invoked per iteration.\n * @param {Function} eachFunc The function to iterate over `collection`.\n * @returns {*} Returns the found element or its key, else `undefined`.\n */\nfunction baseFindKey(collection, predicate, eachFunc) {\n var result;\n eachFunc(collection, function(value, key, collection) {\n if (predicate(value, key, collection)) {\n result = key;\n return false;\n }\n });\n return result;\n}\n\nexport default baseFindKey;\n","/**\n * @param {array} arr Array for check\n * @param {*} value target\n * @return {boolean} true on successs\n */\nconst isInArray = function(arr, value) {\n return !!arr.filter(a => a === value).length\n}\n\nexport default isInArray\n","// breaking the whole thing up to see what cause the multiple calls issue\n\nimport isFunction from 'lodash-es/isFunction'\nimport merge from 'lodash-es/merge'\nimport mapValues from 'lodash-es/mapValues'\n\nimport JsonqlEnumError from 'jsonql-errors/src/enum-error'\nimport JsonqlTypeError from 'jsonql-errors/src/type-error'\nimport JsonqlCheckerError from 'jsonql-errors/src/checker-error'\n\nimport {\n TYPE_KEY,\n OPTIONAL_KEY,\n ENUM_KEY,\n ARGS_KEY,\n CHECKER_KEY,\n KEY_WORD\n} from '../constants'\nimport { checkIsArray } from '../array'\n\n// import debug from 'debug';\n// const debugFn = debug('jsonql-params-validator:options:validation')\n\n/**\n * just make sure it returns an array to use\n * @param {*} arg input\n * @return {array} output\n */\nconst toArray = arg => checkIsArray(arg) ? arg : [arg]\n\n/**\n * DIY in array\n * @param {array} arr to check against\n * @param {*} value to check\n * @return {boolean} true on OK\n */\nconst inArray = (arr, value) => (\n !!arr.filter(v => v === value).length\n)\n\n/**\n * break out to make the code easier to read\n * @param {object} value to process\n * @param {function} cb the validateSync\n * @return {array} empty on success\n */\nfunction validateHandler(value, cb) {\n // cb is the validateSync methods\n let args = [\n [ value[ARGS_KEY] ],\n [{\n [TYPE_KEY]: toArray(value[TYPE_KEY]),\n [OPTIONAL_KEY]: value[OPTIONAL_KEY]\n }]\n ]\n // debugFn('validateHandler', args)\n return Reflect.apply(cb, null, args)\n}\n\n/**\n * Check against the enum value if it's provided\n * @param {*} value to check\n * @param {*} enumv to check against if it's not false\n * @return {boolean} true on OK\n */\nconst enumHandler = (value, enumv) => {\n if (checkIsArray(enumv)) {\n return inArray(enumv, value)\n }\n return true\n}\n\n/**\n * Allow passing a function to check the value\n * There might be a problem here if the function is incorrect\n * and that will makes it hard to debug what is going on inside\n * @TODO there could be a few feature add to this one under different circumstance\n * @param {*} value to check\n * @param {function} checker for checking\n */\nconst checkerHandler = (value, checker) => {\n try {\n return isFunction(checker) ? checker.apply(null, [value]) : false\n } catch (e) {\n return false\n }\n}\n\n/**\n * Taken out from the runValidaton this only validate the required values\n * @param {array} args from the config2argsAction\n * @param {function} cb validateSync\n * @return {array} of configuration values\n */\nfunction runValidationAction(cb) {\n return (value, key) => {\n // debugFn('runValidationAction', key, value)\n if (value[KEY_WORD]) {\n return value[ARGS_KEY]\n }\n const check = validateHandler(value, cb)\n if (check.length) {\n // log('runValidationAction', key, value)\n throw new JsonqlTypeError(key, check)\n }\n if (value[ENUM_KEY] !== false && !enumHandler(value[ARGS_KEY], value[ENUM_KEY])) {\n // log(ENUM_KEY, value[ENUM_KEY])\n throw new JsonqlEnumError(key)\n }\n if (value[CHECKER_KEY] !== false && !checkerHandler(value[ARGS_KEY], value[CHECKER_KEY])) {\n // log(CHECKER_KEY, value[CHECKER_KEY])\n throw new JsonqlCheckerError(key)\n }\n return value[ARGS_KEY]\n }\n}\n\n/**\n * @param {object} args from the config2argsAction\n * @param {function} cb validateSync\n * @return {object} of configuration values\n */\nexport default function runValidation(args, cb) {\n const [ argsForValidate, pristineValues ] = args\n // turn the thing into an array and see what happen here\n // debugFn('_args', argsForValidate)\n const result = mapValues(argsForValidate, runValidationAction(cb))\n return merge(result, pristineValues)\n}\n","/// this is port back from the client to share across all projects\n\nimport merge from 'lodash-es/merge'\nimport { prepareArgsForValidation } from './prepare-args-for-validation'\nimport runValidation from './run-validation'\n\n// import debug from 'debug'\n// const debugFn = debug('jsonql-params-validator:check-options-async')\n\n/**\n * Quick transform\n * @param {object} config that one\n * @param {object} appProps mutation configuration options\n * @return {object} put that arg into the args\n */\nconst configToArgs = (config, appProps) => {\n return Promise.resolve(\n prepareArgsForValidation(config, appProps)\n )\n}\n\n/**\n * @param {object} config user provide configuration option\n * @param {object} appProps mutation configuration options\n * @param {object} constProps the immutable configuration options\n * @param {function} cb the validateSync method\n * @return {object} Promise resolve merge config object\n */\nexport default function(config = {}, appProps, constProps, cb) {\n return configToArgs(config, appProps)\n .then(args1 => runValidation(args1, cb))\n // next if every thing good then pass to final merging\n .then(args2 => merge({}, args2, constProps))\n}\n","// create function to construct the config entry so we don't need to keep building object\n\nimport isFunction from 'lodash-es/isFunction'\nimport isString from 'lodash-es/isString'\nimport {\n ARGS_KEY,\n TYPE_KEY,\n CHECKER_KEY,\n ENUM_KEY,\n OPTIONAL_KEY,\n ALIAS_KEY\n} from 'jsonql-constants'\n\nimport { checkIsArray } from '../array'\n// import checkIsBoolean from '../boolean'\n// import debug from 'debug';\n// const debugFn = debug('jsonql-params-validator:construct-config');\n/**\n * @param {*} args value\n * @param {string} type for value\n * @param {boolean} [optional=false]\n * @param {boolean|array} [enumv=false]\n * @param {boolean|function} [checker=false]\n * @return {object} config entry\n */\nexport default function constructConfig(args, type, optional=false, enumv=false, checker=false, alias=false) {\n let base = {\n [ARGS_KEY]: args,\n [TYPE_KEY]: type\n }\n if (optional === true) {\n base[OPTIONAL_KEY] = true\n }\n if (checkIsArray(enumv)) {\n base[ENUM_KEY] = enumv\n }\n if (isFunction(checker)) {\n base[CHECKER_KEY] = checker\n }\n if (isString(alias)) {\n base[ALIAS_KEY] = alias\n }\n return base\n}\n","// export also create wrapper methods\nimport checkOptionsAsync from './check-options-async'\nimport checkOptionsSync from './check-options-sync'\nimport constructConfigFn from './construct-config'\nimport {\n ENUM_KEY,\n CHECKER_KEY,\n ALIAS_KEY,\n OPTIONAL_KEY\n} from 'jsonql-constants'\n\n/**\n * This has a different interface\n * @param {*} value to supply\n * @param {string|array} type for checking\n * @param {object} params to map against the config check\n * @param {array} params.enumv NOT enum\n * @param {boolean} params.optional false then nothing\n * @param {function} params.checker need more work on this one later\n * @param {string} params.alias mostly for cmd\n */\nconst createConfig = (value, type, params = {}) => {\n // Note the enumv not ENUM\n // const { enumv, optional, checker, alias } = params;\n // let args = [value, type, optional, enumv, checker, alias];\n const {\n [OPTIONAL_KEY]: o,\n [ENUM_KEY]: e,\n [CHECKER_KEY]: c,\n [ALIAS_KEY]: a\n } = params;\n return constructConfigFn.apply(null, [value, type, o, e, c, a])\n}\n\n// for testing purpose\nconst JSONQL_PARAMS_VALIDATOR_INFO = '__PLACEHOLDER__'\n\n/**\n * construct the actual end user method, rename with prefix get since 1.5.2\n * @param {function} validateSync validation method\n * @return {function} for performaning the actual valdiation\n */\nconst getCheckConfigAsync = function(validateSync) {\n /**\n * We recreate the method here to avoid the circlar import\n * @param {object} config user supply configuration\n * @param {object} appProps mutation options\n * @param {object} [constantProps={}] optional: immutation options\n * @return {object} all checked configuration\n */\n return function(config, appProps, constantProps= {}) {\n return checkOptionsAsync(config, appProps, constantProps, validateSync)\n }\n}\n\n/**\n * copy of above but it's sync, rename with prefix get since 1.5.2\n * @param {function} validateSync validation method\n * @return {function} for performaning the actual valdiation\n */\nconst getCheckConfig = function(validateSync) {\n return function(config, appProps, constantProps = {}) {\n return checkOptionsSync(config, appProps, constantProps, validateSync)\n }\n}\n\n// re-export\nexport {\n createConfig,\n constructConfigFn,\n getCheckConfigAsync,\n getCheckConfig,\n JSONQL_PARAMS_VALIDATOR_INFO\n}\n","// export\nimport {\n checkIsObject,\n notEmpty,\n checkIsAny,\n checkIsString,\n checkIsBoolean,\n checkIsNumber,\n checkIsArray\n} from './src'\nimport * as validator from './src/validator'\n// configuration checking\nimport * as jsonqlOptions from './src/options'\n// the two extra functions\nimport isInArray from './src/is-in-array'\nimport isObjectHasKeyFn from './src/is-key-in-object'\n\nconst isObject = checkIsObject\nconst isAny = checkIsAny\nconst isString = checkIsString\nconst isBoolean = checkIsBoolean\nconst isNumber = checkIsNumber\nconst isArray = checkIsArray\nconst isNotEmpty = notEmpty\n\nconst normalizeArgs = validator.normalizeArgs\nconst validateSync = validator.validateSync\nconst validateAsync = validator.validateAsync\n\nconst JSONQL_PARAMS_VALIDATOR_INFO = jsonqlOptions.JSONQL_PARAMS_VALIDATOR_INFO\n\nconst createConfig = jsonqlOptions.createConfig\nconst constructConfig = jsonqlOptions.constructConfigFn\n// construct the final output 1.5.2\nconst checkConfigAsync = jsonqlOptions.getCheckConfigAsync(validator.validateSync)\nconst checkConfig = jsonqlOptions.getCheckConfig(validator.validateSync)\n\nconst inArray = isInArray\nconst isObjectHasKey = isObjectHasKeyFn\n\n// check returns methods \nimport { \n checkReturns, \n checkReturnsAsync, \n checkResolverReturns, \n checkResolverReturnsAsync \n} from './src/returns'\n\n\n// group the in one \nexport {\n JSONQL_PARAMS_VALIDATOR_INFO,\n \n isObject,\n isAny,\n isString,\n isBoolean,\n isNumber,\n isArray,\n isNotEmpty,\n \n inArray,\n isObjectHasKey,\n\n normalizeArgs,\n validateSync,\n validateAsync,\n\n createConfig,\n constructConfig,\n checkConfig,\n checkConfigAsync,\n\n checkReturns, \n checkReturnsAsync, \n checkResolverReturns, \n checkResolverReturnsAsync\n}\n\n\n\n\n\n","// move the get logger stuff here\n\n// it does nothing\nconst dummyLogger = () => {}\n\n/**\n * re-use the debugOn prop to control this log method\n * @param {object} opts configuration\n * @return {function} the log function\n */\nconst getLogger = (opts) => {\n const { debugOn } = opts \n if (debugOn) {\n return (...args) => {\n Reflect.apply(console.info, console, ['[jsonql-ws-client-core]', ...args])\n }\n }\n return dummyLogger\n}\n\n/**\n * Make sure there is a log method\n * @param {object} opts configuration\n * @return {object} opts\n */\nconst getLogFn = opts => {\n const { log } = opts // 1.3.9 if we pass a log method here then we use this\n if (!log || typeof log !== 'function') {\n return getLogger(opts)\n }\n opts.log('---> getLogFn user supplied log function <---', opts)\n return log\n}\n\nexport { getLogFn }","// group all the repetitive message here\n\nexport const TAKEN_BY_OTHER_TYPE_ERR = 'You are trying to register an event already been taken by other type:'\n","// Create two WeakMap store as a private keys\nexport const NB_EVENT_SERVICE_PRIVATE_STORE = new WeakMap()\nexport const NB_EVENT_SERVICE_PRIVATE_LAZY = new WeakMap()\n","/**\n * generate a 32bit hash based on the function.toString()\n * _from http://stackoverflow.com/questions/7616461/generate-a-hash-_from-string-in-javascript-jquery\n * @param {string} s the converted to string function\n * @return {string} the hashed function string\n */\nexport function hashCode(s) {\n\treturn s.split(\"\").reduce(function(a,b){a=((a<<5)-a)+b.charCodeAt(0);return a&a},0)\n}\n\n/**\n * wrapper to make sure it string\n * @param {*} input whatever\n * @return {string} output\n */\nexport function hashCode2Str(s) {\n return hashCode(s) + ''\n}\n\n/**\n * Just check if a pattern is an RegExp object\n * @param {*} pat whatever\n * @return {boolean} false when its not\n */\nexport function isRegExp(pat) {\n return pat instanceof RegExp\n}\n\n/**\n * check if its string\n * @param {*} arg whatever\n * @return {boolean} false when it's not\n */\nexport function isString(arg) {\n return typeof arg === 'string'\n}\n\n/**\n * Find from the array by matching the pattern\n * @param {*} pattern a string or RegExp object\n * @return {object} regex object or false when we can not id the input\n */\nexport function getRegex(pattern) {\n switch (true) {\n case isRegExp(pattern) === true:\n return pattern\n case isString(pattern) === true:\n return new RegExp(pattern)\n default:\n return false\n }\n}\n","// making all the functionality on it's own\n// import { WatchClass } from './watch'\n/*\nwe use a different way to do the same watch thing now\nthis.watch('suspend', function(value, prop, oldValue) {\n this.logger(`${prop} set from ${oldValue} to ${value}`)\n // it means it set the suspend = true then release it\n if (oldValue === true && value === false) {\n // we want this happen after the return happens\n setTimeout(() => {\n this.release()\n }, 1)\n }\n return value; // we need to return the value to store it\n})\n*/\nimport { getRegex, isRegExp } from './utils'\n\nexport default class SuspendClass {\n\n constructor() {\n // suspend, release and queue\n this.__suspend_state__ = null\n // to do this proper we don't use a new prop to hold the event name pattern\n this.__pattern__ = null\n this.queueStore = new Set()\n }\n\n /**\n * start suspend\n * @return {void}\n */\n $suspend() {\n this.logger(`---> SUSPEND ALL OPS <---`)\n this.__suspend__(true)\n }\n\n /**\n * release the queue\n * @return {void}\n */\n $release() {\n this.logger(`---> RELEASE SUSPENDED QUEUE <---`)\n this.__suspend__(false)\n }\n\n /**\n * suspend event by pattern\n * @param {string} pattern the pattern search matches the event name\n * @return {void}\n */\n $suspendEvent(pattern) {\n const regex = getRegex(pattern)\n if (isRegExp(regex)) {\n this.__pattern__ = regex\n return this.$suspend()\n }\n throw new Error(`We expect a pattern variable to be string or RegExp, but we got \"${typeof regex}\" instead`)\n }\n\n /**\n * queuing call up when it's in suspend mode\n * @param {string} evt the event name\n * @param {*} args unknown number of arguments\n * @return {boolean} true when added or false when it's not\n */\n $queue(evt, ...args) {\n this.logger('($queue) get called')\n if (this.__suspend_state__ === true) {\n if (isRegExp(this.__pattern__)) { // it's better then check if its not null\n // check the pattern and decide if we want to suspend it or not\n let found = this.__pattern__.test(evt)\n if (!found) {\n return false\n }\n }\n this.logger('($queue) added to $queue', args)\n // @TODO there shouldn't be any duplicate, but how to make sure?\n this.queueStore.add([evt].concat(args))\n // return this.queueStore.size\n }\n return !!this.__suspend_state__\n }\n\n /**\n * a getter to get all the store queue\n * @return {array} Set turn into Array before return\n */\n get $queues() {\n let size = this.queueStore.size\n this.logger('($queues)', `size: ${size}`)\n if (size > 0) {\n return Array.from(this.queueStore)\n }\n return []\n }\n\n /**\n * to set the suspend and check if it's boolean value\n * @param {boolean} value to trigger\n */\n __suspend__(value) {\n if (typeof value === 'boolean') {\n const lastValue = this.__suspend_state__\n this.__suspend_state__ = value\n this.logger(`($suspend) Change from \"${lastValue}\" --> \"${value}\"`)\n if (lastValue === true && value === false) {\n this.__release__()\n }\n } else {\n throw new Error(`$suspend only accept Boolean value! we got ${typeof value}`)\n }\n }\n\n /**\n * Release the queue\n * @return {int} size if any\n */\n __release__() {\n let size = this.queueStore.size\n let pattern = this.__pattern__\n this.__pattern__ = null\n this.logger(`(release) was called with ${size}${pattern ? ' for \"' + pattern + '\"': ''} item${size > 1 ? 's' : ''}`)\n if (size > 0) {\n const queue = Array.from(this.queueStore)\n this.queueStore.clear()\n this.logger('(release queue)', queue)\n queue.forEach(args => {\n this.logger(args)\n Reflect.apply(this.$trigger, this, args)\n })\n this.logger(`Release size ${this.queueStore.size}`)\n }\n\n return size\n }\n}\n","// break up the main file because its getting way too long\nimport {\n NB_EVENT_SERVICE_PRIVATE_STORE,\n NB_EVENT_SERVICE_PRIVATE_LAZY\n} from './store'\nimport { hashCode2Str, isString } from './utils'\nimport SuspendClass from './suspend'\n\nexport default class StoreService extends SuspendClass {\n\n constructor(config = {}) {\n super()\n if (config.logger && typeof config.logger === 'function') {\n this.logger = config.logger\n }\n this.keep = config.keep\n // for the $done setter\n this.result = config.keep ? [] : null\n // we need to init the store first otherwise it could be a lot of checking later\n this.normalStore = new Map()\n this.lazyStore = new Map()\n }\n\n /**\n * validate the event name(s)\n * @param {string[]} evt event name\n * @return {boolean} true when OK\n */\n validateEvt(...evt) {\n evt.forEach(e => {\n if (!isString(e)) {\n this.logger('(validateEvt)', e)\n throw new Error(`Event name must be string type! we got ${typeof e}`)\n }\n })\n return true\n }\n\n /**\n * Simple quick check on the two main parameters\n * @param {string} evt event name\n * @param {function} callback function to call\n * @return {boolean} true when OK\n */\n validate(evt, callback) {\n if (this.validateEvt(evt)) {\n if (typeof callback === 'function') {\n return true\n }\n }\n throw new Error(`callback required to be function type! we got ${typeof callback}`)\n }\n\n /**\n * Check if this type is correct or not added in V1.5.0\n * @param {string} type for checking\n * @return {boolean} true on OK\n */\n validateType(type) {\n this.validateEvt(type)\n const types = ['on', 'only', 'once', 'onlyOnce']\n return !!types.filter(t => type === t).length\n }\n\n /**\n * Run the callback\n * @param {function} callback function to execute\n * @param {array} payload for callback\n * @param {object} ctx context or null\n * @return {void} the result store in $done\n */\n run(callback, payload, ctx) {\n this.logger('(run) callback:', callback, 'payload:', payload, 'context:', ctx)\n this.$done = Reflect.apply(callback, ctx, this.toArray(payload))\n }\n\n /**\n * Take the content out and remove it from store id by the name\n * @param {string} evt event name\n * @param {string} [storeName = lazyStore] name of store\n * @return {object|boolean} content or false on not found\n */\n takeFromStore(evt, storeName = 'lazyStore') {\n let store = this[storeName] // it could be empty at this point\n if (store) {\n this.logger('(takeFromStore)', storeName, store)\n if (store.has(evt)) {\n let content = store.get(evt)\n this.logger(`(takeFromStore) has \"${evt}\"`, content)\n store.delete(evt)\n return content\n }\n return false\n }\n throw new Error(`\"${storeName}\" is not supported!`)\n }\n\n /**\n * This was part of the $get. We take it out\n * so we could use a regex to remove more than one event\n * @param {object} store the store to return from\n * @param {string} evt event name\n * @param {boolean} full return just the callback or everything\n * @return {array|boolean} false when not found\n */\n findFromStore(evt, store, full = false) {\n if (store.has(evt)) {\n return Array\n .from(store.get(evt))\n .map( l => {\n if (full) {\n return l\n }\n let [key, callback, ] = l\n return callback\n })\n }\n return false\n }\n\n /**\n * Similar to the findFromStore, but remove\n * @param {string} evt event name\n * @param {object} store the store to remove from\n * @return {boolean} false when not found\n */\n removeFromStore(evt, store) {\n if (store.has(evt)) {\n this.logger('($off)', evt)\n store.delete(evt)\n return true\n }\n return false\n }\n\n /**\n * The add to store step is similar so make it generic for resuse\n * @param {object} store which store to use\n * @param {string} evt event name\n * @param {spread} args because the lazy store and normal store store different things\n * @return {array} store and the size of the store\n */\n addToStore(store, evt, ...args) {\n let fnSet\n if (store.has(evt)) {\n this.logger(`(addToStore) \"${evt}\" existed`)\n fnSet = store.get(evt)\n } else {\n this.logger(`(addToStore) create new Set for \"${evt}\"`)\n // this is new\n fnSet = new Set()\n }\n // lazy only store 2 items - this is not the case in V1.6.0 anymore\n // we need to check the first parameter is string or not\n if (args.length > 2) {\n if (Array.isArray(args[0])) { // lazy store\n // check if this type of this event already register in the lazy store\n let [,,t] = args\n if (!this.checkTypeInLazyStore(evt, t)) {\n fnSet.add(args)\n }\n } else {\n if (!this.checkContentExist(args, fnSet)) {\n this.logger(`(addToStore) insert new`, args)\n fnSet.add(args)\n }\n }\n } else { // add straight to lazy store\n fnSet.add(args)\n }\n store.set(evt, fnSet)\n return [store, fnSet.size]\n }\n\n /**\n * @param {array} args for compare\n * @param {object} fnSet A Set to search from\n * @return {boolean} true on exist\n */\n checkContentExist(args, fnSet) {\n let list = Array.from(fnSet)\n return !!list.filter(li => {\n let [hash,] = li\n return hash === args[0]\n }).length\n }\n\n /**\n * get the existing type to make sure no mix type add to the same store\n * @param {string} evtName event name\n * @param {string} type the type to check\n * @return {boolean} true you can add, false then you can't add this type\n */\n checkTypeInStore(evtName, type) {\n this.validateEvt(evtName, type)\n let all = this.$get(evtName, true)\n if (all === false) {\n // pristine it means you can add\n return true\n }\n // it should only have ONE type in ONE event store\n return !all.filter(list => {\n let [ ,,,t ] = list\n return type !== t\n }).length\n }\n\n /**\n * This is checking just the lazy store because the structure is different\n * therefore we need to use a new method to check it\n */\n checkTypeInLazyStore(evtName, type) {\n this.validateEvt(evtName, type)\n let store = this.lazyStore.get(evtName)\n this.logger('(checkTypeInLazyStore)', store)\n if (store) {\n return !!Array\n .from(store)\n .filter(li => {\n let [,,t] = li\n return t !== type\n }).length\n }\n return false\n }\n\n /**\n * wrapper to re-use the addToStore,\n * V1.3.0 add extra check to see if this type can add to this evt\n * @param {string} evt event name\n * @param {string} type on or once\n * @param {function} callback function\n * @param {object} context the context the function execute in or null\n * @return {number} size of the store\n */\n addToNormalStore(evt, type, callback, context = null) {\n this.logger(`(addToNormalStore) try to add \"${type}\" --> \"${evt}\" to normal store`)\n // @TODO we need to check the existing store for the type first!\n if (this.checkTypeInStore(evt, type)) {\n this.logger('(addToNormalStore)', `\"${type}\" --> \"${evt}\" can add to normal store`)\n let key = this.hashFnToKey(callback)\n let args = [this.normalStore, evt, key, callback, context, type]\n let [_store, size] = Reflect.apply(this.addToStore, this, args)\n this.normalStore = _store\n return size\n }\n return false\n }\n\n /**\n * Add to lazy store this get calls when the callback is not register yet\n * so we only get a payload object or even nothing\n * @param {string} evt event name\n * @param {array} payload of arguments or empty if there is none\n * @param {object} [context=null] the context the callback execute in\n * @param {string} [type=false] register a type so no other type can add to this evt\n * @return {number} size of the store\n */\n addToLazyStore(evt, payload = [], context = null, type = false) {\n // this is add in V1.6.0\n // when there is type then we will need to check if this already added in lazy store\n // and no other type can add to this lazy store\n let args = [this.lazyStore, evt, this.toArray(payload), context]\n if (type) {\n args.push(type)\n }\n let [_store, size] = Reflect.apply(this.addToStore, this, args)\n this.lazyStore = _store\n this.logger(`(addToLazyStore) size: ${size}`)\n return size\n }\n\n /**\n * make sure we store the argument correctly\n * @param {*} arg could be array\n * @return {array} make sured\n */\n toArray(arg) {\n return Array.isArray(arg) ? arg : [arg]\n }\n\n /**\n * setter to store the Set in private\n * @param {object} obj a Set\n */\n set normalStore(obj) {\n NB_EVENT_SERVICE_PRIVATE_STORE.set(this, obj)\n }\n\n /**\n * @return {object} Set object\n */\n get normalStore() {\n return NB_EVENT_SERVICE_PRIVATE_STORE.get(this)\n }\n\n /**\n * setter to store the Set in lazy store\n * @param {object} obj a Set\n */\n set lazyStore(obj) {\n NB_EVENT_SERVICE_PRIVATE_LAZY.set(this , obj)\n }\n\n /**\n * @return {object} the lazy store Set\n */\n get lazyStore() {\n return NB_EVENT_SERVICE_PRIVATE_LAZY.get(this)\n }\n\n /**\n * generate a hashKey to identify the function call\n * The build-in store some how could store the same values!\n * @param {function} fn the converted to string function\n * @return {string} hashKey\n */\n hashFnToKey(fn) {\n return hashCode2Str(fn.toString())\n }\n}\n","// The top level\nimport { TAKEN_BY_OTHER_TYPE_ERR } from './constants'\nimport StoreService from './store-service'\n// export\nexport default class EventService extends StoreService {\n /**\n * class constructor\n */\n constructor(config = {}) {\n super(config)\n }\n\n /**\n * logger function for overwrite\n */\n logger() {}\n\n // for id if the instance is this class\n get $name() {\n return 'to1source-event'\n }\n\n // take this down in the next release\n get is() {\n return this.$name\n }\n\n //////////////////////////\n // PUBLIC METHODS //\n //////////////////////////\n\n /**\n * Register your evt handler, note we don't check the type here,\n * we expect you to be sensible and know what you are doing.\n * @param {string} evt name of event\n * @param {function} callback bind method --> if it's array or not\n * @param {object} [context=null] to execute this call in\n * @return {number} the size of the store\n */\n $on(evt , callback , context = null) {\n const type = 'on'\n this.validate(evt, callback)\n // first need to check if this evt is in lazy store\n let lazyStoreContent = this.takeFromStore(evt)\n // this is normal register first then call later\n if (lazyStoreContent === false) {\n this.logger(`($on) \"${evt}\" is not in lazy store`)\n // @TODO we need to check if there was other listener to this\n // event and are they the same type then we could solve that\n // register the different type to the same event name\n return this.addToNormalStore(evt, type, callback, context)\n }\n this.logger(`($on) ${evt} found in lazy store`)\n // this is when they call $trigger before register this callback\n let size = 0\n lazyStoreContent.forEach(content => {\n let [ payload, ctx, t ] = content\n if (t && t !== type) {\n throw new Error(`${TAKEN_BY_OTHER_TYPE_ERR} ${t}`)\n }\n this.logger(`($on)`, `call run \"${evt}\"`)\n this.run(callback, payload, context || ctx)\n size += this.addToNormalStore(evt, type, callback, context || ctx)\n })\n\n this.logger(`($on) return size ${size}`)\n return size\n }\n\n /**\n * once only registered it once, there is no overwrite option here\n * @NOTE change in v1.3.0 $once can add multiple listeners\n * but once the event fired, it will remove this event (see $only)\n * @param {string} evt name\n * @param {function} callback to execute\n * @param {object} [context=null] the handler execute in\n * @return {boolean} result\n */\n $once(evt , callback , context = null) {\n this.validate(evt, callback)\n const type = 'once'\n let lazyStoreContent = this.takeFromStore(evt)\n // this is normal register before call $trigger\n let nStore = this.normalStore;\n if (lazyStoreContent === false) {\n this.logger(`($once) \"${evt}\" is not in the lazy store`)\n // v1.3.0 $once now allow to add multiple listeners\n return this.addToNormalStore(evt, type, callback, context)\n } else {\n // now this is the tricky bit\n // there is a potential bug here that cause by the developer\n // if they call $trigger first, the lazy won't know it's a once call\n // so if in the middle they register any call with the same evt name\n // then this $once call will be fucked - add this to the documentation\n this.logger('($once)', lazyStoreContent)\n const list = Array.from(lazyStoreContent)\n // should never have more than 1\n const [ payload, ctx, t ] = list[0]\n if (t && t !== type) {\n throw new Error(`${TAKEN_BY_OTHER_TYPE_ERR} ${t}`)\n }\n this.logger('($once)', `call run \"${evt}\"`)\n this.run(callback, payload, context || ctx)\n // remove this evt from store\n this.$off(evt)\n }\n }\n\n /**\n * This one event can only bind one callbackback\n * @param {string} evt event name\n * @param {function} callback event handler\n * @param {object} [context=null] the context the event handler execute in\n * @return {boolean} true bind for first time, false already existed\n */\n $only(evt, callback, context = null) {\n this.validate(evt, callback)\n const type = 'only'\n let added = false\n let lazyStoreContent = this.takeFromStore(evt)\n // this is normal register before call $trigger\n let nStore = this.normalStore\n if (!nStore.has(evt)) {\n this.logger(`($only) \"${evt}\" add to normalStore`)\n added = this.addToNormalStore(evt, type, callback, context)\n }\n if (lazyStoreContent !== false) {\n // there are data store in lazy store\n this.logger(`($only) \"${evt}\" found data in lazy store to execute`)\n const list = Array.from(lazyStoreContent)\n // $only allow to trigger this multiple time on the single handler\n list.forEach( li => {\n const [ payload, ctx, t ] = li\n if (t && t !== type) {\n throw new Error(`${TAKEN_BY_OTHER_TYPE_ERR} ${t}`)\n }\n this.logger(`($only) call run \"${evt}\"`)\n this.run(callback, payload, context || ctx)\n })\n }\n return added\n }\n\n /**\n * $only + $once this is because I found a very subtile bug when we pass a\n * resolver, rejecter - and it never fire because that's OLD added in v1.4.0\n * @param {string} evt event name\n * @param {function} callback to call later\n * @param {object} [context=null] exeucte context\n * @return {void}\n */\n $onlyOnce(evt, callback, context = null) {\n this.validate(evt, callback)\n const type = 'onlyOnce'\n let added = false\n let lazyStoreContent = this.takeFromStore(evt)\n // this is normal register before call $trigger\n let nStore = this.normalStore;\n if (!nStore.has(evt)) {\n this.logger(`($onlyOnce) \"${evt}\" add to normalStore`)\n added = this.addToNormalStore(evt, type, callback, context)\n }\n if (lazyStoreContent !== false) {\n // there are data store in lazy store\n this.logger('($onlyOnce)', lazyStoreContent)\n const list = Array.from(lazyStoreContent)\n // should never have more than 1\n const [ payload, ctx, t ] = list[0]\n if (t && t !== 'onlyOnce') {\n throw new Error(`${TAKEN_BY_OTHER_TYPE_ERR} ${t}`)\n }\n this.logger(`($onlyOnce) call run \"${evt}\"`)\n this.run(callback, payload, context || ctx)\n // remove this evt from store\n this.$off(evt)\n }\n return added\n }\n\n /**\n * This is a shorthand of $off + $on added in V1.5.0\n * @param {string} evt event name\n * @param {function} callback to exeucte\n * @param {object} [context = null] or pass a string as type\n * @param {string} [type=on] what type of method to replace\n * @return {*}\n */\n $replace(evt, callback, context = null, type = 'on') {\n if (this.validateType(type)) {\n this.$off(evt)\n let method = this['$' + type]\n this.logger(`($replace)`, evt, callback)\n return Reflect.apply(method, this, [evt, callback, context])\n }\n throw new Error(`${type} is not supported!`)\n }\n\n /**\n * trigger the event\n * @param {string} evt name NOT allow array anymore!\n * @param {mixed} [payload = []] pass to fn\n * @param {object|string} [context = null] overwrite what stored\n * @param {string} [type=false] if pass this then we need to add type to store too\n * @return {number} if it has been execute how many times\n */\n $trigger(evt , payload = [] , context = null, type = false) {\n this.validateEvt(evt)\n let found = 0\n // first check the normal store\n let nStore = this.normalStore\n this.logger('($trigger) normalStore', nStore)\n if (nStore.has(evt)) {\n this.logger(`($trigger) \"${evt}\" found`)\n // @1.8.0 to add the suspend queue\n let added = this.$queue(evt, payload, context, type)\n if (added) {\n this.logger(`($trigger) Currently suspended \"${evt}\" added to queue, nothing executed. Exit now.`)\n return false // not executed\n }\n let nSet = Array.from(nStore.get(evt))\n let ctn = nSet.length\n let hasOnce = false\n let hasOnly = false\n for (let i=0; i < ctn; ++i) {\n ++found;\n // this.logger('found', found)\n let [ _, callback, ctx, type ] = nSet[i]\n this.logger(`($trigger) call run for ${evt}`)\n this.run(callback, payload, context || ctx)\n if (type === 'once' || type === 'onlyOnce') {\n hasOnce = true;\n }\n }\n if (hasOnce) {\n nStore.delete(evt)\n }\n return found\n }\n // now this is not register yet\n this.addToLazyStore(evt, payload, context, type)\n return found\n }\n\n /**\n * this is an alias to the $trigger\n * @NOTE breaking change in V1.6.0 we swap the parameter aroun\n * @NOTE breaking change: v1.9.1 it return an function to accept the params as spread\n * @param {string} evt event name\n * @param {string} type of call\n * @param {object} context what context callback execute in\n * @return {*} from $trigger\n */\n $call(evt, type = false, context = null) {\n const ctx = this\n\n return (...args) => {\n let _args = [evt, args, context, type]\n return Reflect.apply(ctx.$trigger, ctx, _args)\n }\n }\n\n /**\n * remove the evt from all the stores\n * @param {string} evt name\n * @return {boolean} true actually delete something\n */\n $off(evt) {\n // @TODO we will allow a regex pattern to mass remove event\n this.validateEvt(evt)\n let stores = [ this.lazyStore, this.normalStore ]\n\n return !!stores\n .filter(store => store.has(evt))\n .map(store => this.removeFromStore(evt, store))\n .length\n }\n\n /**\n * return all the listener bind to that event name\n * @param {string} evtName event name\n * @param {boolean} [full=false] if true then return the entire content\n * @return {array|boolean} listerner(s) or false when not found\n */\n $get(evt, full = false) {\n // @TODO should we allow the same Regex to search for all?\n this.validateEvt(evt)\n let store = this.normalStore\n return this.findFromStore(evt, store, full)\n }\n\n /**\n * store the return result from the run\n * @param {*} value whatever return from callback\n */\n set $done(value) {\n this.logger('($done) set value: ', value)\n if (this.keep) {\n this.result.push(value)\n } else {\n this.result = value\n }\n }\n\n /**\n * @TODO is there any real use with the keep prop?\n * getter for $done\n * @return {*} whatever last store result\n */\n get $done() {\n this.logger('($done) get result:', this.result)\n if (this.keep) {\n return this.result[this.result.length - 1]\n }\n return this.result\n }\n\n /**\n * Take a look inside the stores\n * @param {number|null} idx of the store, null means all\n * @return {void}\n */\n $debug(idx = null) {\n let names = ['lazyStore', 'normalStore']\n let stores = [this.lazyStore, this.normalStore]\n if (stores[idx]) {\n this.logger(names[idx], stores[idx])\n } else {\n stores.map((store, i) => {\n this.logger(names[i], store)\n })\n }\n }\n}\n","// default\nimport To1sourceEvent from './src/event-service'\n\nexport default To1sourceEvent\n","// this will generate a event emitter and will be use everywhere\nimport EventEmitterClass from '@to1source/event'\n// create a clone version so we know which one we actually is using\nclass JsonqlWsEvt extends EventEmitterClass {\n\n constructor(logger) {\n if (typeof logger !== 'function') {\n throw new Error(`Just die here the logger is not a function!`)\n }\n logger(`---> Create a new EventEmitter <---`)\n // this ee will always come with the logger\n // because we should take the ee from the configuration\n super({ logger })\n }\n\n get name() {\n return'jsonql-ws-client-core'\n }\n}\n\n/**\n * getting the event emitter\n * @param {object} opts configuration\n * @return {object} the event emitter instance\n */\nconst getEventEmitter = opts => {\n const { log, eventEmitter } = opts\n \n if (eventEmitter) {\n log(`eventEmitter is:`, eventEmitter.name)\n return eventEmitter\n }\n \n return new JsonqlWsEvt( opts.log )\n}\n\nexport { \n getEventEmitter, \n EventEmitterClass // for other module to build from \n}\n","// group all the small functions here\nimport { EMIT_REPLY_TYPE } from 'jsonql-constants'\nimport { toArray, createEvt } from 'jsonql-utils/src/generic'\nimport JsonqlValidationError from 'jsonql-errors/src/validation-error'\n\n\n/**\n * WebSocket is strict about the path, therefore we need to make sure before it goes in\n * @param {string} url input url\n * @return {string} url with correct path name\n */\nexport const fixWss = url => {\n const uri = url.toLowerCase()\n if (uri.indexOf('http') > -1) {\n if (uri.indexOf('https') > -1) {\n return uri.replace('https', 'wss')\n }\n return uri.replace('http', 'ws')\n }\n return uri\n}\n\n\n/**\n * get a stock host name from browser\n */\nexport const getHostName = () => {\n try {\n return [window.location.protocol, window.location.host].join('//')\n } catch(e) {\n throw new JsonqlValidationError(e)\n }\n}\n\n/**\n * Unbind the event\n * @param {object} ee EventEmitter\n * @param {string} namespace\n * @return {void}\n */\nexport const clearMainEmitEvt = (ee, namespace) => {\n let nsps = toArray(namespace)\n nsps.forEach(n => {\n ee.$off(createEvt(n, EMIT_REPLY_TYPE))\n })\n}\n\n\n","// take out from the resolver-methods\nimport { \n LOGIN_EVENT_NAME, \n LOGOUT_EVENT_NAME, \n ON_LOGIN_FN_NAME\n} from 'jsonql-constants'\nimport { JsonqlValidationError } from 'jsonql-errors'\nimport { injectToFn, chainFns, isString, objDefineProps, isFunc } from '../utils'\n\n\n/**\n * @TODO this is now become unnecessary because the login is a slave to the\n * http-client - but keep this for now and see what we want to do with it later\n * @UPDATE it might be better if we decoup the two http-client only emit a login event\n * Here should catch it and reload the ws client @TBC\n * break out from createAuthMethods to allow chaining call\n * @param {object} obj the main client object\n * @param {object} opts configuration\n * @param {object} ee event emitter\n * @return {array} [ obj, opts, ee ] what comes in what goes out\n */\nconst setupLoginHandler = (obj, opts, ee) => [ \n injectToFn(obj, opts.loginHandlerName, function loginHandler(token) {\n if (token && isString(token)) {\n opts.log(`Received ${LOGIN_EVENT_NAME} with ${token}`)\n // @TODO add the interceptor hook \n return ee.$trigger(LOGIN_EVENT_NAME, [token])\n }\n // should trigger a global error instead @TODO\n throw new JsonqlValidationError(opts.loginHandlerName, `Unexpected token ${token}`)\n }),\n opts,\n ee\n]\n\n\n/**\n * break out from createAuthMethods to allow chaining call - final in chain\n * @param {object} obj the main client object\n * @param {object} opts configuration\n * @param {object} ee event emitter\n * @return {array} [ obj, opts, ee ] what comes in what goes out\n */\nconst setupLogoutHandler = (obj, opts, ee) => [\n injectToFn(obj, opts.logoutHandlerName, function logoutHandler(...args) {\n ee.$trigger(LOGOUT_EVENT_NAME, args)\n }),\n opts, \n ee\n]\n\n\n/**\n * This event will fire when the socket.io.on('connection') and ws.onopen\n * Plus this will check if it's the private namespace that fired the event\n * @param {object} obj the client itself\n * @param {object} ee Event Emitter\n * @return {array} [ obj, opts, ee] what comes in what goes out\n */\nconst createOnLoginhandler = (obj, opts, ee) => [\n objDefineProps(obj, ON_LOGIN_FN_NAME, function onLoginCallbackHandler(onLoginCallback) {\n if (isFunc(onLoginCallback)) {\n // only one callback can registered with it, TBC\n ee.$only(ON_LOGIN_FN_NAME, onLoginCallback)\n }\n }),\n opts,\n ee \n]\n\n// @TODO future feature setup switch user\n\n\n/**\n * Create auth related methods\n * @param {object} obj the client itself\n * @param {object} opts configuration\n * @param {object} ee Event Emitter\n * @return {array} [ obj, opts, ee ] what comes in what goes out\n */\nexport function createAuthMethods(obj, opts, ee) {\n return chainFns(\n setupLoginHandler, \n setupLogoutHandler,\n createOnLoginhandler\n )(obj, opts, ee)\n}\n","// constants\n\nimport {\n EMIT_REPLY_TYPE,\n JS_WS_SOCKET_IO_NAME,\n JS_WS_NAME,\n ON_MESSAGE_FN_NAME,\n ON_RESULT_FN_NAME\n} from 'jsonql-constants'\n\nconst SOCKET_IO = JS_WS_SOCKET_IO_NAME\nconst WS = JS_WS_NAME\n\nconst AVAILABLE_SERVERS = [SOCKET_IO, WS]\n\nconst SOCKET_NOT_DEFINE_ERR = 'socket is not define in the contract file!'\n\nconst SERVER_NOT_SUPPORT_ERR = 'is not supported server name!'\n\nconst MISSING_PROP_ERR = 'Missing property in contract!'\n\nconst UNKNOWN_CLIENT_ERR = 'Unknown client type!'\n\nconst EMIT_EVT = EMIT_REPLY_TYPE\n\nconst NAMESPACE_KEY = 'namespaceMap'\n\nconst UNKNOWN_RESULT = 'UKNNOWN RESULT!'\n\nconst NOT_ALLOW_OP = 'This operation is not allow!'\n\nconst MY_NAMESPACE = 'myNamespace'\n\nconst CB_FN_NAME = 'on'\n// this is a socket only (for now) feature so we just put it here \nconst DISCONNECTED_ERROR_MSG = `You have disconnected from the socket server, please reconnect.`\n\nexport {\n SOCKET_IO,\n WS,\n AVAILABLE_SERVERS,\n SOCKET_NOT_DEFINE_ERR,\n SERVER_NOT_SUPPORT_ERR,\n MISSING_PROP_ERR,\n UNKNOWN_CLIENT_ERR,\n EMIT_EVT,\n ON_MESSAGE_FN_NAME,\n ON_RESULT_FN_NAME,\n NAMESPACE_KEY,\n UNKNOWN_RESULT,\n NOT_ALLOW_OP,\n MY_NAMESPACE,\n CB_FN_NAME,\n DISCONNECTED_ERROR_MSG\n}\n","// breaking it up further to share between methods\nimport { DATA_KEY, ERROR_KEY } from 'jsonql-constants'\nimport { UNKNOWN_RESULT } from '../options/constants'\nimport { isObjectHasKey } from '../utils'\n\n/**\n * break out to use in different places to handle the return from server\n * @param {object} data from server\n * @param {function} resolver NOT from promise\n * @param {function} rejecter NOT from promise\n * @return {void} nothing\n */\nexport function respondHandler(data, resolver, rejecter) {\n if (isObjectHasKey(data, ERROR_KEY)) {\n // debugFn('-- rejecter called --', data[ERROR_KEY])\n rejecter(data[ERROR_KEY])\n } else if (isObjectHasKey(data, DATA_KEY)) {\n // debugFn('-- resolver called --', data[DATA_KEY])\n resolver(data[DATA_KEY])\n } else {\n // debugFn('-- UNKNOWN_RESULT --', data)\n rejecter({message: UNKNOWN_RESULT, error: data})\n }\n}\n","// the actual trigger call method\nimport { ON_RESULT_FN_NAME, EMIT_REPLY_TYPE } from 'jsonql-constants'\nimport { createEvt, toArray } from '../utils'\nimport { respondHandler } from './respond-handler'\n\n/**\n * just wrapper\n * @param {object} ee EventEmitter\n * @param {string} namespace where this belongs\n * @param {string} resolverName resolver\n * @param {array} args arguments\n * @param {function} log function \n * @return {void} nothing\n */\nexport function actionCall(ee, namespace, resolverName, args = [], log) {\n // reply event \n const outEventName = createEvt(namespace, EMIT_REPLY_TYPE)\n\n log(`actionCall: ${outEventName} --> ${resolverName}`, args)\n // This is the out going call \n ee.$trigger(outEventName, [resolverName, toArray(args)])\n \n // then we need to listen to the event callback here as well\n return new Promise((resolver, rejecter) => {\n const inEventName = createEvt(namespace, resolverName, ON_RESULT_FN_NAME)\n // this cause the onResult got the result back first \n // and it should be the promise resolve first\n // @TODO we need to rewrote the respondHandler to change the problem stated above \n ee.$on(\n inEventName,\n function actionCallResultHandler(result) {\n log(`got the first result`, result)\n respondHandler(result, resolver, rejecter)\n }\n )\n })\n}\n","// setting up the send method \nimport { JsonqlValidationError } from 'jsonql-errors'\nimport {\n ON_ERROR_FN_NAME,\n SEND_MSG_FN_NAME\n} from 'jsonql-constants'\nimport { validateAsync } from 'jsonql-params-validator'\nimport { objDefineProps, createEvt, toArray, nil } from '../utils'\nimport { actionCall } from './action-call'\n\n/** \n * pairing with the server vesrion SEND_MSG_FN_NAME\n * last of the chain so only return the resolver (fn)\n * This is now change to a getter / setter method \n * and call like this: resolver.send(...args)\n * @param {function} fn the resolver function \n * @param {object} ee event emitter instance \n * @param {string} namespace the namespace it belongs to \n * @param {string} resolverName name of the resolver \n * @param {object} params from contract \n * @param {function} log a logger function\n * @return {function} return the resolver itself \n */ \nexport const setupSendMethod = (fn, ee, namespace, resolverName, params, log) => (\n objDefineProps(\n fn, \n SEND_MSG_FN_NAME, \n nil, \n function sendHandler() {\n // let _log = (...args) => Reflect.apply(console.info, console, ['[SEND]'].concat(args))\n /** \n * This will follow the same pattern like the resolver \n * @param {array} args list of unknown argument follow the resolver \n * @return {promise} resolve the result \n */\n return function sendCallback(...args) {\n return validateAsync(args, params.params, true)\n .then(_args => {\n // @TODO check the result \n // because the validation could failed with the list of fail properties \n log(namespace, resolverName, _args)\n return actionCall(ee, namespace, resolverName, _args, _log)\n })\n .catch(err => {\n // @TODO it shouldn't be just a validation error \n // it could be server return error, so we need to check \n // what error we got back here first \n log('send error', err)\n // @TODO it might not an validation error need the finalCatch here\n ee.$call(\n createEvt(namespace, resolverName, ON_ERROR_FN_NAME),\n [new JsonqlValidationError(resolverName, err)]\n )\n })\n } \n })\n)\n","// break up the original setup resolver method here\n// import { JsonqlValidationError, finalCatch } from 'jsonql-errors'\nimport {\n ON_ERROR_FN_NAME,\n ON_MESSAGE_FN_NAME,\n ON_RESULT_FN_NAME\n} from 'jsonql-constants'\n// local \nimport { MY_NAMESPACE } from '../options/constants'\nimport { chainFns, objDefineProps, injectToFn, createEvt, isFunc } from '../utils'\nimport { respondHandler } from './respond-handler'\nimport { setupSendMethod } from './setup-send-method'\n\n/**\n * The first one in the chain, just setup a namespace prop\n * the rest are passing through\n * @param {function} fn the resolver function\n * @param {object} ee the event emitter \n * @param {string} resolverName what it said\n * @param {object} params for resolver from contract\n * @param {function} log the logger function\n * @return {array}\n */\nconst setupNamespace = (fn, ee, namespace, resolverName, params, log) => [\n injectToFn(fn, MY_NAMESPACE, namespace),\n ee,\n namespace,\n resolverName,\n params,\n log \n]\n\n/** \n * onResult handler\n */ \nconst setupOnResult = (fn, ee, namespace, resolverName, params, log) => [\n objDefineProps(fn, ON_RESULT_FN_NAME, function(resultCallback) {\n if (isFunc(resultCallback)) {\n ee.$on(\n createEvt(namespace, resolverName, ON_RESULT_FN_NAME),\n function resultHandler(result) {\n respondHandler(result, resultCallback, (error) => {\n log(`Catch error: \"${resolverName}\"`, error)\n ee.$trigger(\n createEvt(namespace, resolverName, ON_ERROR_FN_NAME), \n error\n )\n })\n }\n )\n }\n }),\n ee,\n namespace,\n resolverName,\n params,\n log\n]\n\n/** \n * we do need to add the send prop back because it's the only way to deal with\n * bi-directional data stream \n */\nconst setupOnMessage = (fn, ee, namespace, resolverName, params, log) => [\n objDefineProps(fn, ON_MESSAGE_FN_NAME, function(messageCallback) {\n // we expect this to be a function\n if (isFunc(messageCallback)) {\n // did that add to the callback\n let onMessageCallback = (args) => {\n respondHandler(args, messageCallback, (error) => {\n log(`Catch error: \"${resolverName}\"`, error)\n ee.$trigger(\n createEvt(namespace, resolverName, ON_ERROR_FN_NAME), \n error\n )\n })\n }\n // register the handler for this message event\n ee.$only(\n createEvt(namespace, resolverName, ON_MESSAGE_FN_NAME), \n onMessageCallback\n )\n }\n }),\n ee,\n namespace,\n resolverName,\n params,\n log\n]\n\n/** \n * ON_ERROR_FN_NAME handler\n */\nconst setupOnError = (fn, ee, namespace, resolverName, params, log) => [\n objDefineProps(fn, ON_ERROR_FN_NAME, function(resolverErrorHandler) {\n if (isFunc(resolverErrorHandler)) {\n // please note ON_ERROR_FN_NAME can add multiple listners\n ee.$only(\n createEvt(namespace, resolverName, ON_ERROR_FN_NAME), \n resolverErrorHandler\n )\n }\n }),\n ee,\n namespace,\n resolverName,\n params,\n log\n]\n\n/**\n * Add extra property / listeners to the resolver\n * @param {string} namespace where this belongs\n * @param {string} resolverName name as event name\n * @param {object} params from contract\n * @param {function} fn resolver function\n * @param {object} ee EventEmitter\n * @param {function} log function \n * @return {function} resolver\n */\nexport function setupResolver(namespace, resolverName, params, fn, ee, log) {\n let fns = [\n setupNamespace, \n setupOnResult, \n setupOnMessage, \n setupOnError, \n setupSendMethod\n ]\n \n // get the executor\n const executor = Reflect.apply(chainFns, null, fns)\n const args = [fn, ee, namespace, resolverName, params, log]\n\n return Reflect.apply(executor, null, args)\n}\n","// put all the resolver related methods here to make it more clear\n\n// this will be a mini client server architect\n// The reason is when the enableAuth setup - the private route\n// might not be validated, but we need the callable point is ready\n// therefore this part will always take the contract and generate\n// callable api for the developer to setup their front end\n// the only thing is - when they call they might get an error or\n// NOT_LOGIN_IN and they can react to this error accordingly\nimport { finalCatch } from 'jsonql-errors'\nimport { validateAsync } from 'jsonql-params-validator'\nimport { setupResolver } from './setup-resolver'\nimport { actionCall } from './action-call'\nimport { \n createEvt, \n objDefineProps, \n isFunc, \n injectToFn \n} from '../utils'\nimport {\n ON_ERROR_FN_NAME,\n ON_READY_FN_NAME\n} from 'jsonql-constants'\n\n/**\n * create the actual function to send message to server\n * @param {object} ee EventEmitter instance\n * @param {string} namespace this resolver end point\n * @param {string} resolverName name of resolver as event name\n * @param {object} params from contract\n * @param {function} log pass the log function \n * @return {function} resolver\n */\nfunction createResolver(ee, namespace, resolverName, params, log) {\n // note we pass the new withResult=true option\n return function resolver(...args) {\n return validateAsync(args, params.params, true)\n .then(_args => actionCall(ee, namespace, resolverName, _args, log))\n .catch(finalCatch)\n }\n}\n\n/**\n * step one get the clientmap with the namespace\n * @param {object} opts configuration\n * @param {object} ee EventEmitter\n * @param {object} nspGroup resolvers index by their namespace\n * @return {promise} resolve the clientmapped, and start the chain\n */\nexport function generateResolvers(opts, ee, nspGroup) {\n let client= {}\n let { log } = opts\n \n for (let namespace in nspGroup) {\n let list = nspGroup[namespace]\n for (let resolverName in list) {\n // resolverNames.push(resolverName)\n let params = list[resolverName]\n let fn = createResolver(ee, namespace, resolverName, params, log)\n // this should set as a getter therefore can not be overwrite by accident\n // obj[resolverName] = setupResolver(namespace, resolverName, params, fn, ee)\n client = injectToFn(\n client, \n resolverName, \n setupResolver(namespace, resolverName, params, fn, ee, log)\n )\n }\n }\n // resolve the clientto start the chain\n // chain the result to allow the chain processing\n return [ client, opts, ee, nspGroup ]\n}\n\n/**\n * The problem is the namespace can have more than one\n * and we only have on onError message\n * @param {object} clientthe client itself\n * @param {object} opts configuration\n * @param {object} ee Event Emitter\n * @param {object} nspGroup namespace keys\n * @return {array} [obj, opts, ee] \n */\nexport function createNamespaceErrorListener(client, opts, ee, nspGroup) {\n return [\n objDefineProps(\n client, \n ON_ERROR_FN_NAME, \n function namespaceErrorCallbackHandler(namespaceErrorHandler) {\n if (isFunc(namespaceErrorHandler)) {\n // please note ON_ERROR_FN_NAME can add multiple listners\n for (let namespace in nspGroup) {\n // this one is very tricky, we need to make sure the trigger is calling\n // with the namespace as well as the error\n ee.$on(createEvt(namespace, ON_ERROR_FN_NAME), namespaceErrorHandler)\n }\n }\n }\n ),\n opts,\n ee\n ]\n}\n\n/**\n * This event will fire when the socket.io.on('connection') and ws.onopen\n * @param {object} client client itself\n * @param {object} opts configuration\n * @param {object} ee Event Emitter\n * @return {array} [ obj, opts, ee ]\n */\nexport function createOnReadyListener(client, opts, ee) {\n return [\n objDefineProps(\n client, \n ON_READY_FN_NAME, \n function onReadyCallbackHandler(onReadyCallback) {\n if (isFunc(onReadyCallback)) {\n // reduce it down to just one flat level\n ee.$on(ON_READY_FN_NAME, onReadyCallback)\n }\n }\n ),\n opts,\n ee\n ]\n}\n\n\n\n\n","// this is a new method that will create several \n// intercom method also reverse listen to the server \n// such as disconnect (server issue disconnect)\nimport { injectToFn } from '../utils'\nimport { DISCONNECT_EVENT_NAME } from 'jsonql-constants'\n\n/**\n * this is the new method that setup the intercom handler \n * also this serve as the final call in the then chain to \n * output the client\n * @param {object} client the client \n * @param {object} opts configuration \n * @param {object} ee the event emitter\n * @return {object} client \n */\nexport function setupInterCom(client, opts, ee) {\n const { disconnectHandlerName } = opts\n return injectToFn(client, disconnectHandlerName, function disconnectHandler(...args) {\n ee.$trigger(DISCONNECT_EVENT_NAME, args)\n })\n} ","// The final step of the setup before it returns the client\nimport { setupInterCom } from './setup-intercom'\n// import { HELLO_FN } from 'jsonql-constants'\n\n/** \n * The final step to return the client \n * @param {object} client the client \n * @param {object} opts configuration \n * @param {object} ee the event emitter\n * @return {object} client \n */\nfunction setupFinalStep(obj, opts, ee) {\n const client = setupInterCom(obj, opts, ee)\n opts.log(`---> The final step to return the ws-client <---`)\n // add some debug functions \n client.verifyEventEmitter = () => ee.is\n // we add back the two things into the client \n // then when we do integration, we run it in reverse, \n // create the ws client first then the host client \n client.eventEmitter = opts.eventEmitter\n client.log = opts.log\n // we just inject a helloWorld method here \n // client[HELLO_FN] = \n\n return client\n}\n\n\nexport { setupFinalStep }\n\n\n","// resolvers generator\n// we change the interface to return promise from v1.0.3\n// this way we make sure the obj return is correct and timely\nimport { chainFns } from '../utils'\nimport { createAuthMethods } from './setup-auth-methods'\nimport {\n generateResolvers,\n createOnReadyListener,\n createNamespaceErrorListener\n} from './generator-methods'\nimport {\n setupFinalStep \n} from './setup-final-step'\nimport {\n NSP_GROUP\n} from 'jsonql-constants'\n\n/**\n * prepare the methods\n * @param {object} opts configuration\n * @param {object} nspMap resolvers index by their namespace\n * @param {object} ee EventEmitter\n * @return {object} of resolvers\n * @public\n */\nexport function callersGenerator(opts, nspMap, ee) {\n let fns = [\n generateResolvers,\n createOnReadyListener,\n createNamespaceErrorListener\n ]\n if (opts.enableAuth) {\n fns.push(createAuthMethods)\n } \n // we will always get back the [ obj, opts, ee ]\n // then we only return the obj (wsClient)\n fns.push(setupFinalStep)\n // run it\n const generator = Reflect.apply(chainFns, null, fns)\n\n return generator(opts, ee, nspMap[NSP_GROUP])\n}\n","// create options\nimport { \n checkConfigAsync, \n checkConfig \n} from 'jsonql-params-validator'\nimport { \n wsCoreCheckMap, \n wsCoreConstProps, \n socketCheckMap \n} from './defaults'\nimport { \n fixWss, \n getHostName, \n getEventEmitter, \n getNspInfoByConfig,\n getLogFn \n} from '../utils'\n\n/**\n * We need this to find the socket server type \n * @param {*} config \n * @return {string} the name of the socket server if any\n */\nfunction checkSocketClientType(config) {\n return checkConfig(config, socketCheckMap)\n}\n\n/**\n * Create a combine checkConfig for the creating the combine client\n * @param {*} configCheckMap \n * @param {*} constProps \n * @return {function} takes the user input config then resolve the configuration \n */\nfunction createCombineConfigCheck(configCheckMap, constProps) {\n const combineCheckMap = Object.assign({}, configCheckMap, wsCoreCheckMap)\n const combineConstProps = Object.assign({}, constProps, wsCoreConstProps)\n return config => checkConfigAsync(config, combineCheckMap, combineConstProps)\n}\n\n\n/**\n * wrapper method to check this already did the pre check\n * @param {object} config user supply config\n * @param {object} defaultOptions for checking\n * @param {object} constProps user supply const props\n * @return {promise} resolve to the checked opitons\n */\nfunction checkConfiguration(config, defaultOptions, constProps) {\n const defaultCheckMap= Object.assign(wsCoreCheckMap, defaultOptions)\n const wsConstProps = Object.assign(wsCoreConstProps, constProps)\n\n return checkConfigAsync(config, defaultCheckMap, wsConstProps)\n}\n\n/**\n * Taking the `then` part from the method below \n * @param {object} opts \n * @return {promise} opts all done\n */\nfunction postCheckInjectOpts(opts) {\n return Promise.resolve(opts)\n .then(opts => {\n if (!opts.hostname) {\n opts.hostname = getHostName()\n }\n // @TODO the contract now will supply the namespace information\n // and we need to use that to group the namespace call\n opts.wssPath = fixWss([opts.hostname, opts.namespace].join('/'), opts.serverType)\n // get the log function here\n opts.log = getLogFn(opts)\n\n opts.eventEmitter = getEventEmitter(opts)\n\n return opts\n })\n}\n\n/**\n * Don't want to make things confusing\n * Breaking up the opts process in one place \n * then generate the necessary parameter in another step \n * @param {object} opts checked --> merge --> injected \n * @return {object} {opts, nspMap, ee} \n */\nfunction createRequiredParams(opts) {\n return {\n opts,\n nspMap: getNspInfoByConfig(opts),\n ee: opts.eventEmitter \n }\n}\n\nexport {\n // properties \n wsCoreCheckMap,\n wsCoreConstProps,\n // functions \n checkConfiguration,\n postCheckInjectOpts,\n createRequiredParams,\n // this will just get export for integration \n checkSocketClientType,\n createCombineConfigCheck\n}\n","// the top level API\n// The goal is to create a generic method that will able to handle\n// any kind of clients\n// import { injectToFn } from 'jsonql-utils'\nimport { callersGenerator } from './callers'\nimport { \n checkConfiguration, \n postCheckInjectOpts,\n createRequiredParams \n} from './options'\n\n/**\n * 0.5.0 we break up the wsClientCore in two parts one without the config check \n * @param {function} socketClientListerner \n * @return {function} to actually generate the client\n */\nexport function wsClientCoreAction(socketClientListerner) {\n /** \n * This is a breaking change, to continue the onion skin design\n * @param {object} config the already checked config\n * @return {promise} resolve the client\n */ \n return (config = {}) => {\n\n return postCheckInjectOpts(config)\n // the following two moved to wsPostConfig\n .then(createRequiredParams)\n .then(\n ({opts, nspMap, ee}) => socketClientListerner(opts, nspMap, ee)\n )\n .then( // there is problem here, we wrap up the operation inside\n ({opts, nspMap, ee}) => callersGenerator(opts, nspMap, ee)\n )\n .catch(err => {\n console.error(`jsonql-ws-core-client init error`, err)\n })\n }\n}\n\n/**\n * The main interface which will generate the socket clients and map all events\n * @param {object} socketClientListerner this is the one method export by various clients\n * @param {object} [configCheckMap={}] we should do all the checking in the core instead of the client\n * @param {object} [constProps={}] add this to supply the constProps from the downstream client\n * @return {function} accept a config then return the wsClient instance with all the available API\n */\nexport function wsClientCore(socketClientListerner, configCheckMap = {}, constProps = {}) {\n // we need to inject property to this client later\n return (config = {}) => checkConfiguration(config, configCheckMap, constProps)\n .then(wsClientCoreAction(socketClientListerner))\n}\n","// this is getting too confusing \n// therefore we move it back to the framework specific \n\n/**\n * wrapper method to create a nsp without login\n * @param {string|boolean} namespace namespace url could be false\n * @param {object} opts configuration\n * @return {object} ws client instance\n */\nfunction createNspClient(namespace, opts) {\n const { hostname, wssPath, wsOptions, nspClient, log } = opts\n const url = namespace ? [hostname, namespace].join('/') : wssPath\n log(`createNspClient --> `, url)\n\n return nspClient(url, wsOptions)\n}\n\n/**\n * wrapper method to create a nsp with token auth\n * @param {string} namespace namespace url\n * @param {object} opts configuration\n * @return {object} ws client instance\n */\nfunction createNspAuthClient(namespace, opts) {\n const { hostname, wssPath, token, wsOptions, nspAuthClient, log } = opts\n const url = namespace ? [hostname, namespace].join('/') : wssPath\n \n log(`createNspAuthClient -->`, url)\n\n if (token && typeof token !== 'string') {\n throw new Error(`Expect token to be string, but got ${token}`)\n }\n \n return nspAuthClient(url, token, wsOptions)\n}\n\nexport {\n createNspClient,\n createNspAuthClient\n}\n","// this use by client-event-handler\nimport { ON_ERROR_FN_NAME } from 'jsonql-constants'\nimport { createEvt } from '../utils'\n\n/**\n * trigger errors on all the namespace onError handler\n * @param {object} ee Event Emitter\n * @param {array} namespaces nsps string\n * @param {string} message optional\n * @return {void}\n */\nexport function triggerNamespacesOnError(ee, namespaces, message) {\n namespaces.forEach( namespace => {\n ee.$trigger(\n createEvt(namespace, ON_ERROR_FN_NAME), \n [{ message, namespace }]\n )\n })\n}\n\n/**\n * Handle the onerror callback \n * @param {object} ee event emitter \n * @param {string} namespace which namespace has error \n * @param {*} err error object\n * @return {void} \n */\nexport const handleNamespaceOnError = (ee, namespace, err) => {\n ee.$trigger(createEvt(namespace, ON_ERROR_FN_NAME), [err])\n}","// NOT IN USE AT THE MOMENT JUST KEEP IT HERE FOR THE TIME BEING \nimport {\n LOGOUT_EVENT_NAME,\n NOT_LOGIN_ERR_MSG,\n ON_ERROR_FN_NAME,\n ON_RESULT_FN_NAME,\n DISCONNECT_EVENT_NAME\n} from 'jsonql-constants'\nimport { EMIT_EVT, DISCONNECTED_ERROR_MSG } from '../options/constants'\nimport { createEvt, clearMainEmitEvt } from '../utils'\nimport { triggerNamespacesOnError } from './trigger-namespaces-on-error'\n\n/**\n * Only when there is a private namespace then we bind to this event\n * @param {object} nsps the available nsp(s)\n * @param {array} namespaces available namespace \n * @param {object} ee eventEmitter \n * @param {object} opts configuration\n * @return {void}\n */\nexport const logoutEvtListener = (nsps, namespaces, ee, opts) => {\n const { log } = opts \n // this will be available regardless enableAuth\n // because the server can log the client out\n ee.$on(\n LOGOUT_EVENT_NAME, \n function logoutEvtCallback() {\n const privateNamespace = getPrivateNamespace(namespaces)\n log(`${LOGOUT_EVENT_NAME} event triggered`)\n // disconnect(nsps, opts.serverType)\n // we need to issue error to all the namespace onError Listerner\n triggerNamespacesOnError(ee, [privateNamespace], LOGOUT_EVENT_NAME)\n // rebind all of the Listerner to the fake one\n log(`logout from ${privateNamespace}`)\n\n clearMainEmitEvt(ee, privateNamespace)\n // we need to issue one more call to the server before we disconnect\n // now this is a catch 22, here we are not suppose to do anything platform specific\n // so that should fire before trigger this event\n // clear out the nsp\n nsps[privateNamespace] = null \n // add a NOT LOGIN error if call\n notLoginWsListerner(privateNamespace, ee, opts)\n }\n )\n}\n\n/**\n * A Event Listerner placeholder when it's not connect to any nsp\n * @param {string} namespace nsp\n * @param {object} ee EventEmitter\n * @param {object} opts configuration\n * @return {void}\n */\nexport const notConnectedListener = (namespace, ee, opts) => {\n const { log } = opts \n\n ee.$only(\n createEvt(namespace, EMIT_EVT),\n function disconnectedEvtCallback(resolverName, args) {\n log(`[disconnectedListerner] hijack the ws call`, namespace, resolverName, args)\n const error = {\n message: DISCONNECTED_ERROR_MSG\n }\n ee.$call(createEvt(namespace, resolverName, ON_ERROR_FN_NAME), [ error ])\n // also trigger the result Listerner, but wrap inside the error key\n ee.$call(createEvt(namespace, resolverName, ON_RESULT_FN_NAME), [{ error }])\n }\n )\n}\n\n\n/**\n * The disconnect event Listerner, now we log the client out from everything\n * @TODO now we are another problem they disconnect, how to reconnect\n * @param {object} nsps the available nsp(s)\n * @param {array} namespaces available namespace \n * @param {object} ee eventEmitter \n * @param {object} opts configuration\n * @return {void}\n */\nexport const disconnectListener = (nsps, namespaces, ee, opts) => {\n const { log } = opts \n ee.$on(\n DISCONNECT_EVENT_NAME, \n function disconnectEvtCallback() {\n triggerNamespacesOnError(ee, namespaces, DISCONNECT_EVENT_NAME)\n namespaces.forEach( namespace => { \n log(`disconnect from ${namespace}`)\n\n clearMainEmitEvt(ee, namespace)\n nsps[namespace] = null \n disconnectedListerner(namespace, ee, opts)\n })\n }\n )\n}\n\n/**\n * A Event Listerner placeholder when it's not connect to the private nsp\n * @param {string} namespace nsp\n * @param {object} ee EventEmitter\n * @param {object} opts configuration\n * @return {void}\n */\nexport const notLoginListener = (namespace, ee, opts) => {\n const { log } = opts \n\n ee.$only(\n createEvt(namespace, EMIT_EVT),\n function notLoginListernerCallback(resolverName, args) {\n log('[notLoginListerner] hijack the ws call', namespace, resolverName, args)\n const error = { message: NOT_LOGIN_ERR_MSG }\n // It should just throw error here and should not call the result\n // because that's channel for handling normal event not the fake one\n ee.$call(createEvt(namespace, resolverName, ON_ERROR_FN_NAME), [ error ])\n // also trigger the result Listerner, but wrap inside the error key\n ee.$call(createEvt(namespace, resolverName, ON_RESULT_FN_NAME), [{ error }])\n }\n )\n}","// This is share between different clients so we export it\n// @TODO port what is in the ws-main-handler\n// because all the client side call are via the ee\n// and that makes it re-usable between different client setup\n\n/*\nInside the map call but we take it out for now and until the WebSocket version is fully working\nimport { SOCKET_IO } from '../options/constants'\n // @TODO need to double check this\n if (opts.serverType === SOCKET_IO) {\n let { nspGroup } = nspMap\n args.push(nspGroup[namespace])\n }\n*/\nimport { getPrivateNamespace } from 'jsonql-utils/src/namespace'\nimport { logoutEvtListener, notLoginListener } from './event-listeners'\n\n\n/**\n * centralize all the comm in one place\n * @param {function} bindSocketEventHandler binding the ee to ws --> this is the core bit\n * @param {object} nsps namespaced nsp\n * @return {void} nothing\n */\nexport function clientEventListener(bindSocketEventListener, nsps) {\n /**\n * BREAKING CHANGE instead of one flat structure\n * we return a function to accept the two \n * @param {object} opts configuration\n * @param {object} nspMap this is not in the opts \n * @param {object} ee Event Emitter instance\n * @return {array} although we return something but this is the last step and nothing to do further\n */\n return (opts, nspMap, ee) => {\n // since all these params already in the opts\n const { log } = opts\n const { namespaces } = nspMap\n // @1.1.3 add isPrivate prop to id which namespace is the private nsp\n // then we can use this prop to determine if we need to fire the ON_LOGIN_PROP_NAME event\n const privateNamespace = getPrivateNamespace(namespaces)\n \n return namespaces.map(namespace => {\n let isPrivate = privateNamespace === namespace\n log(namespace, ` --> ${isPrivate ? 'private': 'public'} nsp --> `, nsps[namespace] !== false)\n if (nsps[namespace]) {\n log('[call bindWsHandler]', isPrivate, namespace)\n\n let args = [namespace, nsps[namespace], ee, isPrivate, opts]\n // Finally we binding everything together\n Reflect.apply(bindSocketEventListener, null, args)\n\n } else {\n log(`binding notLoginWsHandler to ${namespace}`)\n // a dummy placeholder\n // @TODO but it should be a not connect handler \n // when it's not login (or fail) this should be handle differently \n notLoginListener(namespace, ee, opts)\n }\n if (isPrivate) {\n log(`Has private and add logoutEvtHandler`)\n logoutEvtListener(nsps, namespaces, ee, opts)\n }\n // just return something its not going to get use anywhere\n return isPrivate \n })\n }\n}\n","// jsonql-ws-core takes over the check configuration\n// here we only have to supply the options that is unique to this client\n// create options\nimport { JS_WS_NAME } from 'jsonql-constants'\n// constant props\nconst wsClientConstProps = {\n version: '__PLACEHOLDER__', // will get replace\n serverType: JS_WS_NAME\n}\n\nexport { wsClientConstProps }\n","// pass the different type of ws to generate the client\n// this is where the framework specific code get injected\nimport { TOKEN_PARAM_NAME } from 'jsonql-constants'\nimport { fixWss } from '../modules'\nimport {\n createInitPing, \n extractPingResult\n} from '../modules'\n\n/**\n * Group the ping and get respond create new client in one\n * @param {object} ws \n * @param {object} WebSocket \n * @param {string} url\n * @param {function} resolver \n * @param {function} rejecter \n * @param {boolean} auth client or not\n * @return {promise} resolve the confirm client\n */\nfunction initPingAction(ws, WebSocket, url, resolver, rejecter, wsOptions) {\n // @TODO how to we id this client can issue a CSRF\n // by origin? \n ws.onopen = function onOpenCallback() {\n ws.send(createInitPing())\n }\n\n ws.onmessage = function onMessageCallback(payload) {\n try {\n const header = extractPingResult(payload.data)\n // @NOTE the break down test in ws-client-core show no problems\n // the problem was cause by malform nspInfo that time? \n setTimeout(() => { // delay or not show no different but just on the safe side\n ws.terminate()\n }, 50)\n const newWs = new WebSocket(url, Object.assign(wsOptions, header)) \n resolver(newWs) \n } catch(e) {\n rejecter(e)\n }\n }\n\n ws.onerror = function onErrorCallback(err) {\n rejecter(err)\n }\n}\n\n/**\n * less duplicated code the better \n * @param {object} WebSocket \n * @param {string} url formatted url\n * @param {object} options or not\n * @return {promise} resolve the actual verified client\n */\nfunction asyncConnect(WebSocket, url, options) {\n \n return new Promise((resolver, rejecter) => { \n \n const unconfirmClient = new WebSocket(url, options)\n \n initPingAction(unconfirmClient, WebSocket, url, resolver, rejecter, options)\n })\n}\n\n\n/**\n * The bug was in the wsOptions where ws don't need it but socket.io do\n * therefore the object was pass as second parameter!\n * @NOTE here we only return a method to create the client, it might not get call \n * @param {object} WebSocket the client or node version of ws\n * @param {boolean} auth if it's auth then 3 param or just one\n * @param {object} opts this is a breaking change we will init the client twice\n */\nfunction initWebSocketClient(WebSocket, auth, log) {\n if (auth === false) {\n /**\n * Create a non-protected client\n * @param {string} url \n * @param {object} [wsOptions={}]\n * @return {promise} resolve to the confirmed client\n */\n return function createWsClient(url, wsOptions = {}) {\n const _url = fixWss(url)\n log(`nspClient: \\n${_url}\\n`, wsOptions)\n\n return asyncConnect(WebSocket, _url, wsOptions)\n }\n }\n\n /**\n * Create a client with auth token\n * @param {string} url start with ws:// @TODO check this?\n * @param {string} token the jwt token\n * @param {object} [wsOptions={}] extra options pass to the WebSocket object\n * @return {object} ws instance\n */\n return function createWsAuthClient(url, token, wsOptions = {}) {\n const ws_url = fixWss(url)\n // console.log('what happen here?', url, ws_url, token)\n const _url = token && typeof token === 'string' ? `${ws_url}?${TOKEN_PARAM_NAME}=${token}` : ws_url\n log(`nspAuthClient: \\n${_url}\\n`, wsOptions)\n\n return asyncConnect(WebSocket, _url, wsOptions)\n }\n}\n\nexport { initWebSocketClient }","/** Used for built-in method references. */\nvar objectProto = Object.prototype;\n\n/**\n * Used to resolve the\n * [`toStringTag`](http://ecma-international.org/ecma-262/7.0/#sec-object.prototype.tostring)\n * of values.\n */\nvar nativeObjectToString = objectProto.toString;\n\n/**\n * Converts `value` to a string using `Object.prototype.toString`.\n *\n * @private\n * @param {*} value The value to convert.\n * @returns {string} Returns the converted string.\n */\nfunction objectToString(value) {\n return nativeObjectToString.call(value);\n}\n\nexport default objectToString;\n","/**\n * Creates a unary function that invokes `func` with its argument transformed.\n *\n * @private\n * @param {Function} func The function to wrap.\n * @param {Function} transform The argument transform.\n * @returns {Function} Returns the new function.\n */\nfunction overArg(func, transform) {\n return function(arg) {\n return func(transform(arg));\n };\n}\n\nexport default overArg;\n","/**\n * Checks if `value` is object-like. A value is object-like if it's not `null`\n * and has a `typeof` result of \"object\".\n *\n * @static\n * @memberOf _\n * @since 4.0.0\n * @category Lang\n * @param {*} value The value to check.\n * @returns {boolean} Returns `true` if `value` is object-like, else `false`.\n * @example\n *\n * _.isObjectLike({});\n * // => true\n *\n * _.isObjectLike([1, 2, 3]);\n * // => true\n *\n * _.isObjectLike(_.noop);\n * // => false\n *\n * _.isObjectLike(null);\n * // => false\n */\nfunction isObjectLike(value) {\n return value != null && typeof value == 'object';\n}\n\nexport default isObjectLike;\n","/**\n * Removes all key-value entries from the list cache.\n *\n * @private\n * @name clear\n * @memberOf ListCache\n */\nfunction listCacheClear() {\n this.__data__ = [];\n this.size = 0;\n}\n\nexport default listCacheClear;\n","/**\n * Performs a\n * [`SameValueZero`](http://ecma-international.org/ecma-262/7.0/#sec-samevaluezero)\n * comparison between two values to determine if they are equivalent.\n *\n * @static\n * @memberOf _\n * @since 4.0.0\n * @category Lang\n * @param {*} value The value to compare.\n * @param {*} other The other value to compare.\n * @returns {boolean} Returns `true` if the values are equivalent, else `false`.\n * @example\n *\n * var object = { 'a': 1 };\n * var other = { 'a': 1 };\n *\n * _.eq(object, object);\n * // => true\n *\n * _.eq(object, other);\n * // => false\n *\n * _.eq('a', 'a');\n * // => true\n *\n * _.eq('a', Object('a'));\n * // => false\n *\n * _.eq(NaN, NaN);\n * // => true\n */\nfunction eq(value, other) {\n return value === other || (value !== value && other !== other);\n}\n\nexport default eq;\n","/**\n * Removes `key` and its value from the stack.\n *\n * @private\n * @name delete\n * @memberOf Stack\n * @param {string} key The key of the value to remove.\n * @returns {boolean} Returns `true` if the entry was removed, else `false`.\n */\nfunction stackDelete(key) {\n var data = this.__data__,\n result = data['delete'](key);\n\n this.size = data.size;\n return result;\n}\n\nexport default stackDelete;\n","/**\n * Gets the stack value for `key`.\n *\n * @private\n * @name get\n * @memberOf Stack\n * @param {string} key The key of the value to get.\n * @returns {*} Returns the entry value.\n */\nfunction stackGet(key) {\n return this.__data__.get(key);\n}\n\nexport default stackGet;\n","/**\n * Checks if a stack value for `key` exists.\n *\n * @private\n * @name has\n * @memberOf Stack\n * @param {string} key The key of the entry to check.\n * @returns {boolean} Returns `true` if an entry for `key` exists, else `false`.\n */\nfunction stackHas(key) {\n return this.__data__.has(key);\n}\n\nexport default stackHas;\n","/**\n * Checks if `value` is the\n * [language type](http://www.ecma-international.org/ecma-262/7.0/#sec-ecmascript-language-types)\n * of `Object`. (e.g. arrays, functions, objects, regexes, `new Number(0)`, and `new String('')`)\n *\n * @static\n * @memberOf _\n * @since 0.1.0\n * @category Lang\n * @param {*} value The value to check.\n * @returns {boolean} Returns `true` if `value` is an object, else `false`.\n * @example\n *\n * _.isObject({});\n * // => true\n *\n * _.isObject([1, 2, 3]);\n * // => true\n *\n * _.isObject(_.noop);\n * // => true\n *\n * _.isObject(null);\n * // => false\n */\nfunction isObject(value) {\n var type = typeof value;\n return value != null && (type == 'object' || type == 'function');\n}\n\nexport default isObject;\n","/** Used for built-in method references. */\nvar funcProto = Function.prototype;\n\n/** Used to resolve the decompiled source of functions. */\nvar funcToString = funcProto.toString;\n\n/**\n * Converts `func` to its source code.\n *\n * @private\n * @param {Function} func The function to convert.\n * @returns {string} Returns the source code.\n */\nfunction toSource(func) {\n if (func != null) {\n try {\n return funcToString.call(func);\n } catch (e) {}\n try {\n return (func + '');\n } catch (e) {}\n }\n return '';\n}\n\nexport default toSource;\n","/**\n * Gets the value at `key` of `object`.\n *\n * @private\n * @param {Object} [object] The object to query.\n * @param {string} key The key of the property to get.\n * @returns {*} Returns the property value.\n */\nfunction getValue(object, key) {\n return object == null ? undefined : object[key];\n}\n\nexport default getValue;\n","/**\n * Removes `key` and its value from the hash.\n *\n * @private\n * @name delete\n * @memberOf Hash\n * @param {Object} hash The hash to modify.\n * @param {string} key The key of the value to remove.\n * @returns {boolean} Returns `true` if the entry was removed, else `false`.\n */\nfunction hashDelete(key) {\n var result = this.has(key) && delete this.__data__[key];\n this.size -= result ? 1 : 0;\n return result;\n}\n\nexport default hashDelete;\n","/**\n * Checks if `value` is suitable for use as unique object key.\n *\n * @private\n * @param {*} value The value to check.\n * @returns {boolean} Returns `true` if `value` is suitable, else `false`.\n */\nfunction isKeyable(value) {\n var type = typeof value;\n return (type == 'string' || type == 'number' || type == 'symbol' || type == 'boolean')\n ? (value !== '__proto__')\n : (value === null);\n}\n\nexport default isKeyable;\n","/**\n * Creates a base function for methods like `_.forIn` and `_.forOwn`.\n *\n * @private\n * @param {boolean} [fromRight] Specify iterating from right to left.\n * @returns {Function} Returns the new base function.\n */\nfunction createBaseFor(fromRight) {\n return function(object, iteratee, keysFunc) {\n var index = -1,\n iterable = Object(object),\n props = keysFunc(object),\n length = props.length;\n\n while (length--) {\n var key = props[fromRight ? length : ++index];\n if (iteratee(iterable[key], key, iterable) === false) {\n break;\n }\n }\n return object;\n };\n}\n\nexport default createBaseFor;\n","/**\n * Copies the values of `source` to `array`.\n *\n * @private\n * @param {Array} source The array to copy values from.\n * @param {Array} [array=[]] The array to copy values to.\n * @returns {Array} Returns `array`.\n */\nfunction copyArray(source, array) {\n var index = -1,\n length = source.length;\n\n array || (array = Array(length));\n while (++index < length) {\n array[index] = source[index];\n }\n return array;\n}\n\nexport default copyArray;\n","/** Used for built-in method references. */\nvar objectProto = Object.prototype;\n\n/**\n * Checks if `value` is likely a prototype object.\n *\n * @private\n * @param {*} value The value to check.\n * @returns {boolean} Returns `true` if `value` is a prototype, else `false`.\n */\nfunction isPrototype(value) {\n var Ctor = value && value.constructor,\n proto = (typeof Ctor == 'function' && Ctor.prototype) || objectProto;\n\n return value === proto;\n}\n\nexport default isPrototype;\n","/**\n * Checks if `value` is classified as an `Array` object.\n *\n * @static\n * @memberOf _\n * @since 0.1.0\n * @category Lang\n * @param {*} value The value to check.\n * @returns {boolean} Returns `true` if `value` is an array, else `false`.\n * @example\n *\n * _.isArray([1, 2, 3]);\n * // => true\n *\n * _.isArray(document.body.children);\n * // => false\n *\n * _.isArray('abc');\n * // => false\n *\n * _.isArray(_.noop);\n * // => false\n */\nvar isArray = Array.isArray;\n\nexport default isArray;\n","/** Used as references for various `Number` constants. */\nvar MAX_SAFE_INTEGER = 9007199254740991;\n\n/**\n * Checks if `value` is a valid array-like length.\n *\n * **Note:** This method is loosely based on\n * [`ToLength`](http://ecma-international.org/ecma-262/7.0/#sec-tolength).\n *\n * @static\n * @memberOf _\n * @since 4.0.0\n * @category Lang\n * @param {*} value The value to check.\n * @returns {boolean} Returns `true` if `value` is a valid length, else `false`.\n * @example\n *\n * _.isLength(3);\n * // => true\n *\n * _.isLength(Number.MIN_VALUE);\n * // => false\n *\n * _.isLength(Infinity);\n * // => false\n *\n * _.isLength('3');\n * // => false\n */\nfunction isLength(value) {\n return typeof value == 'number' &&\n value > -1 && value % 1 == 0 && value <= MAX_SAFE_INTEGER;\n}\n\nexport default isLength;\n","/**\n * This method returns `false`.\n *\n * @static\n * @memberOf _\n * @since 4.13.0\n * @category Util\n * @returns {boolean} Returns `false`.\n * @example\n *\n * _.times(2, _.stubFalse);\n * // => [false, false]\n */\nfunction stubFalse() {\n return false;\n}\n\nexport default stubFalse;\n","/**\n * The base implementation of `_.unary` without support for storing metadata.\n *\n * @private\n * @param {Function} func The function to cap arguments for.\n * @returns {Function} Returns the new capped function.\n */\nfunction baseUnary(func) {\n return function(value) {\n return func(value);\n };\n}\n\nexport default baseUnary;\n","/**\n * Gets the value at `key`, unless `key` is \"__proto__\" or \"constructor\".\n *\n * @private\n * @param {Object} object The object to query.\n * @param {string} key The key of the property to get.\n * @returns {*} Returns the property value.\n */\nfunction safeGet(object, key) {\n if (key === 'constructor' && typeof object[key] === 'function') {\n return;\n }\n\n if (key == '__proto__') {\n return;\n }\n\n return object[key];\n}\n\nexport default safeGet;\n","/**\n * The base implementation of `_.times` without support for iteratee shorthands\n * or max array length checks.\n *\n * @private\n * @param {number} n The number of times to invoke `iteratee`.\n * @param {Function} iteratee The function invoked per iteration.\n * @returns {Array} Returns the array of results.\n */\nfunction baseTimes(n, iteratee) {\n var index = -1,\n result = Array(n);\n\n while (++index < n) {\n result[index] = iteratee(index);\n }\n return result;\n}\n\nexport default baseTimes;\n","/** Used as references for various `Number` constants. */\nvar MAX_SAFE_INTEGER = 9007199254740991;\n\n/** Used to detect unsigned integer values. */\nvar reIsUint = /^(?:0|[1-9]\\d*)$/;\n\n/**\n * Checks if `value` is a valid array-like index.\n *\n * @private\n * @param {*} value The value to check.\n * @param {number} [length=MAX_SAFE_INTEGER] The upper bounds of a valid index.\n * @returns {boolean} Returns `true` if `value` is a valid index, else `false`.\n */\nfunction isIndex(value, length) {\n var type = typeof value;\n length = length == null ? MAX_SAFE_INTEGER : length;\n\n return !!length &&\n (type == 'number' ||\n (type != 'symbol' && reIsUint.test(value))) &&\n (value > -1 && value % 1 == 0 && value < length);\n}\n\nexport default isIndex;\n","/**\n * This function is like\n * [`Object.keys`](http://ecma-international.org/ecma-262/7.0/#sec-object.keys)\n * except that it includes inherited enumerable properties.\n *\n * @private\n * @param {Object} object The object to query.\n * @returns {Array} Returns the array of property names.\n */\nfunction nativeKeysIn(object) {\n var result = [];\n if (object != null) {\n for (var key in Object(object)) {\n result.push(key);\n }\n }\n return result;\n}\n\nexport default nativeKeysIn;\n","/**\n * This method returns the first argument it receives.\n *\n * @static\n * @since 0.1.0\n * @memberOf _\n * @category Util\n * @param {*} value Any value.\n * @returns {*} Returns `value`.\n * @example\n *\n * var object = { 'a': 1 };\n *\n * console.log(_.identity(object) === object);\n * // => true\n */\nfunction identity(value) {\n return value;\n}\n\nexport default identity;\n","/**\n * A faster alternative to `Function#apply`, this function invokes `func`\n * with the `this` binding of `thisArg` and the arguments of `args`.\n *\n * @private\n * @param {Function} func The function to invoke.\n * @param {*} thisArg The `this` binding of `func`.\n * @param {Array} args The arguments to invoke `func` with.\n * @returns {*} Returns the result of `func`.\n */\nfunction apply(func, thisArg, args) {\n switch (args.length) {\n case 0: return func.call(thisArg);\n case 1: return func.call(thisArg, args[0]);\n case 2: return func.call(thisArg, args[0], args[1]);\n case 3: return func.call(thisArg, args[0], args[1], args[2]);\n }\n return func.apply(thisArg, args);\n}\n\nexport default apply;\n","/**\n * Creates a function that returns `value`.\n *\n * @static\n * @memberOf _\n * @since 2.4.0\n * @category Util\n * @param {*} value The value to return from the new function.\n * @returns {Function} Returns the new constant function.\n * @example\n *\n * var objects = _.times(2, _.constant({ 'a': 1 }));\n *\n * console.log(objects);\n * // => [{ 'a': 1 }, { 'a': 1 }]\n *\n * console.log(objects[0] === objects[1]);\n * // => true\n */\nfunction constant(value) {\n return function() {\n return value;\n };\n}\n\nexport default constant;\n","/** Used to detect hot functions by number of calls within a span of milliseconds. */\nvar HOT_COUNT = 800,\n HOT_SPAN = 16;\n\n/* Built-in method references for those with the same name as other `lodash` methods. */\nvar nativeNow = Date.now;\n\n/**\n * Creates a function that'll short out and invoke `identity` instead\n * of `func` when it's called `HOT_COUNT` or more times in `HOT_SPAN`\n * milliseconds.\n *\n * @private\n * @param {Function} func The function to restrict.\n * @returns {Function} Returns the new shortable function.\n */\nfunction shortOut(func) {\n var count = 0,\n lastCalled = 0;\n\n return function() {\n var stamp = nativeNow(),\n remaining = HOT_SPAN - (stamp - lastCalled);\n\n lastCalled = stamp;\n if (remaining > 0) {\n if (++count >= HOT_COUNT) {\n return arguments[0];\n }\n } else {\n count = 0;\n }\n return func.apply(undefined, arguments);\n };\n}\n\nexport default shortOut;\n","// break it out on its own because\n// it's building from the lodash-es from scratch\n// according to this discussion https://github.com/lodash/lodash/issues/3298\nimport isPlainObject from 'lodash-es/isPlainObject'\nimport merge from 'lodash-es/merge'\n\n/**\n * previously we already make sure the order of the namespaces\n * and attach the auth client to it\n * @param {array} promises array of unresolved promises\n * @param {boolean} asObject if true then merge the result object\n * @return {object} promise resolved with the array of promises resolved results\n */\nexport function chainPromises(promises, asObject = false) {\n return promises.reduce((promiseChain, currentTask) => (\n promiseChain.then(chainResults => (\n currentTask.then(currentResult => (\n asObject === false ? [...chainResults, currentResult] : merge(chainResults, currentResult)\n ))\n ))\n ), Promise.resolve(\n asObject === false ? [] : (isPlainObject(asObject) ? asObject : {})\n ))\n}\n\n\n/**\n * This one return a different result from the chainPromises\n * it will be the same like chainFns that take one promise resolve as the next fn parameter\n * @param {function} initPromise a function that accept param and resolve result\n * @param {array} promises array of function pass that resolve promises\n * @return {promise} resolve the processed result\n */\nexport function chainProcessPromises(initPromise, ...promises) {\n return (...args) => (\n promises.reduce((promiseChain, currentTask) => (\n promiseChain.then(chainResult => (\n currentTask(chainResult)\n )\n )\n ), Reflect.apply(initPromise, null, args))\n )\n}\n","// @BUG when call disconnected \n// this keep causing an \"Disconnect call failed TypeError: Cannot read property 'readyState' of null\"\n// I think that is because it's not login then it can not be disconnect\n// how do we track this state globally\nimport { LOGIN_EVENT_NAME } from 'jsonql-constants'\nimport { clearMainEmitEvt } from '../modules'\n\n/**\n * create a login event handler \n * @param {object} opts configurations \n * @param {object} nspMap contain all the required info\n * @param {object} ee event emitter \n * @return {void}\n */\nexport function loginEventHandler(opts, nspMap, ee) {\n const { log } = opts\n const { namespaces } = nspMap\n\n ee.$only(LOGIN_EVENT_NAME, function loginEventHandlerCallback(tokenFromLoginAction) {\n \n log('createClient LOGIN_EVENT_NAME $only handler')\n\n clearMainEmitEvt(ee, namespaces)\n // console.log('LOGIN_EVENT_NAME', token)\n const newNsps = createNspAction(opts, nspMap, tokenFromLoginAction)\n // rebind it\n Reflect.apply(\n clientEventHandler, // @NOTE is this the problem that cause the hang up?\n null,\n args.concat([newNsps.namespaces, newNsps.nsps])\n )\n })\n}","// bunch of generic helpers\n\nimport isArray from 'lodash-es/isArray'\nimport isPlainObject from 'lodash-es/isPlainObject'\nimport trim from 'lodash-es/trim'\n\n/**\n * DIY in Array\n * @param {array} arr to check from\n * @param {*} value to check against\n * @return {boolean} true on found\n */\nexport const inArray = (arr, value) => !!arr.filter(a => a === value).length\n\n// quick and dirty to turn non array to array\nexport const toArray = (arg) => isArray(arg) ? arg : [arg]\n\n/**\n * parse string to json or just return the original value if error happened\n * @param {*} n input\n * @param {boolean} [t=true] or throw\n * @return {*} json object on success\n */\nexport const parseJson = function(n, t=true) {\n try {\n return JSON.parse(n)\n } catch(e) {\n if (t) {\n return n\n }\n throw new Error(e)\n }\n}\n\n/**\n * @param {object} obj for search\n * @param {string} key target\n * @return {boolean} true on success\n */\nexport const isObjectHasKey = function(obj, key) {\n try {\n const keys = Object.keys(obj)\n return inArray(keys, key)\n } catch(e) {\n // @BUG when the obj is not an OBJECT we got some weird output\n return false\n }\n}\n\n/**\n * create a event name\n * @param {string[]} args\n * @return {string} event name for use\n */\nexport const createEvt = (...args) => args.join('_')\n\n/**\n * simple util method to get the value\n * @param {string} name of the key\n * @param {object} obj to take value from\n * @return {*} the object value id by name or undefined\n */\nexport const getConfigValue = (name, obj) => (\n obj && isPlainObject(obj) ? ( (name in obj) ? obj[name] : undefined ) : undefined\n)\n\n/**\n * small util to make sure the return value is valid JSON object\n * @param {*} n input\n * @return {object} correct JSON object\n */\nexport const toJson = n => {\n if (typeof n === 'string') {\n return parseJson(n)\n }\n return parseJson(JSON.stringify(n))\n}\n\n/**\n * Check several parameter that there is something in the param\n * @param {*} param input\n * @return {boolean}\n */\nexport const isNotEmpty = function(param) {\n return param !== undefined && param !== false && param !== null && trim(param) !== ''\n}\n\n/**\n * Simple check if the prop is function\n * @param {*} prop input\n * @return {boolean} true on success\n */\nexport const isFunc = prop => {\n if (typeof prop === 'function') {\n return true;\n }\n console.error(`Expect to be Function type! Got ${typeof prop}`)\n}\n\n// generic placeholder function\nexport const nil = () => false\n","// custom validation error class\n// when validaton failed\nexport default class JsonqlValidationError extends Error {\n constructor(...args) {\n super(...args)\n\n this.message = args[0]\n this.detail = args[1]\n\n this.className = JsonqlValidationError.name;\n\n if (Error.captureStackTrace) {\n Error.captureStackTrace(this, JsonqlValidationError)\n }\n }\n\n static get name() {\n return 'JsonqlValidationError'\n }\n}\n","/**\n * @param {boolean} sec return in second or not\n * @return {number} timestamp\n */\nexport const timestamp = (sec = false) => {\n let time = Date.now()\n return sec ? Math.floor( time / 1000 ) : time\n}\n","// ported from jsonql-params-validator\n// craete several helper function to construct / extract the payload\n// and make sure they are all the same\nimport {\n PAYLOAD_PARAM_NAME,\n CONDITION_PARAM_NAME,\n RESOLVER_PARAM_NAME,\n QUERY_ARG_NAME,\n TIMESTAMP_PARAM_NAME\n} from 'jsonql-constants'\n\nimport JsonqlValidationError from 'jsonql-errors/src/validation-error'\n\nimport isArray from 'lodash-es/isArray'\nimport isString from 'lodash-es/isString'\nimport isPlainObject from 'lodash-es/isPlainObject'\n\nimport { timestamp } from './timestamp'\nimport { parseJson } from './generic'\n\n/**\n * check if the payload has a timestamp field, then append a new timestamp to it\n * @param {object} payload from the com\n * @return {array} timestamp field with an array value\n */\nexport const handleTimestamp = payload => {\n let ts = payload[TIMESTAMP_PARAM_NAME]\n if (!isArray(ts)) {\n ts = [ts]\n }\n ts.push( timestamp() )\n\n return ts\n}\n\n/**\n * make sure it's an object (it was call formatPayload but it doesn't make sense)\n * @param {*} payload the object comes in could be string based\n * @return {object} the transformed payload\n */\nexport const toPayload = payload => isString(payload) ? parseJson(payload) : payload\n\n/**\n * @param {*} args arguments to send\n *@return {object} formatted payload\n */\nexport const formatPayload = (args) => (\n { [QUERY_ARG_NAME]: args }\n)\n\n/**\n * extract the resolver name from the payload \n * @param {object} payload\n * @return {string} resolver name \n */\nexport function getResolverFromPayload(payload) {\n const keys = Object.keys(payload)\n return keys.filter(key => key !== TIMESTAMP_PARAM_NAME)[0]\n}\n\n/**\n * wrapper method to add the timestamp as well\n * @param {string} resolverName\n * @param {*} payload\n * @return {object} delierable\n */\nexport function createDeliverable(resolverName, payload) {\n return {\n [resolverName]: payload,\n [TIMESTAMP_PARAM_NAME]: [ timestamp() ]\n }\n}\n\n/**\n * @param {string} resolverName name of function\n * @param {array} [args=[]] from the ...args\n * @param {boolean} [jsonp = false] add v1.3.0 to koa\n * @return {object} formatted argument\n */\nexport function createQuery(resolverName, args = [], jsonp = false) {\n if (isString(resolverName) && isArray(args)) {\n let payload = formatPayload(args)\n if (jsonp === true) {\n return payload\n }\n return createDeliverable(resolverName, payload)\n }\n throw new JsonqlValidationError(`[createQuery] expect resolverName to be string and args to be array!`, { resolverName, args })\n}\n\n/**\n * string version of the createQuery\n * @return {string}\n */\nexport function createQueryStr(resolverName, args = [], jsonp = false) {\n return JSON.stringify(createQuery(resolverName, args, jsonp))\n}\n\n/**\n * @param {string} resolverName name of function\n * @param {*} payload to send\n * @param {object} [condition={}] for what\n * @param {boolean} [jsonp = false] add v1.3.0 to koa\n * @return {object} formatted argument\n */\nexport function createMutation(resolverName, payload, condition = {}, jsonp = false) {\n const _payload = {\n [PAYLOAD_PARAM_NAME]: payload,\n [CONDITION_PARAM_NAME]: condition\n }\n if (jsonp === true) {\n return _payload\n }\n if (isString(resolverName)) {\n return createDeliverable(resolverName, _payload)\n }\n throw new JsonqlValidationError(`[createMutation] expect resolverName to be string!`, { resolverName, payload, condition })\n}\n\n/**\n * string version of createMutation\n * @return {string}\n */\nexport function createMutationStr(resolverName, payload, condition = {}, jsonp = false) {\n return JSON.stringify(createMutation(resolverName, payload, condition, jsonp))\n}\n\n/**\n * Extract the parts from payload and format for use\n * @param {string} resolverName name of fn\n * @param {object} payload the incoming json\n * @return {object|boolean} false on failed\n */\nexport function getQueryFromArgs(resolverName, payload) {\n if (resolverName && isPlainObject(payload)) {\n const args = payload[resolverName]\n if (args[QUERY_ARG_NAME]) {\n return {\n [RESOLVER_PARAM_NAME]: resolverName,\n [QUERY_ARG_NAME]: args[QUERY_ARG_NAME],\n [TIMESTAMP_PARAM_NAME]: handleTimestamp(payload)\n }\n }\n }\n return false\n}\n\n/**\n * Share function so no repeat\n * @param {object} payload the payload from client\n * @param {function} processor the last get result method\n * @return {*} result processed result\n */\nfunction processPayload(payload, processor) {\n const p = toPayload(payload)\n const resolverName = getResolverFromPayload(p)\n return Reflect.apply(processor, null, [resolverName, p])\n}\n\n/**\n * extra the payload back\n * @param {*} payload from http call\n * @return {object} resolverName and args\n */\nexport function getQueryFromPayload(payload) {\n const result = processPayload(payload, getQueryFromArgs)\n if (result !== false) {\n return result\n }\n throw new JsonqlValidationError('[getQueryArgs] Payload is malformed!', payload)\n}\n\n/**\n * Further break down from method below for use else where\n * @param {string} resolverName name of fn\n * @param {object} payload payload\n * @return {object|boolean} false on failed\n */\nexport function getMutationFromArgs(resolverName, payload) {\n if (resolverName && isPlainObject(payload)) {\n const args = payload[resolverName]\n if (args) {\n return {\n [RESOLVER_PARAM_NAME]: resolverName,\n [PAYLOAD_PARAM_NAME]: args[PAYLOAD_PARAM_NAME],\n [CONDITION_PARAM_NAME]: args[CONDITION_PARAM_NAME],\n [TIMESTAMP_PARAM_NAME]: handleTimestamp(payload)\n }\n }\n }\n return false\n}\n\n/**\n * @param {object} payload\n * @return {object} resolverName, payload, conditon\n */\nexport function getMutationFromPayload(payload) {\n const result = processPayload(payload, getMutationFromArgs)\n\n if (result !== false) {\n return result\n }\n throw new JsonqlValidationError('[getMutationArgs] Payload is malformed!', payload)\n}\n","// There are the socket related methods ported back from \n// ws-server-core and ws-client-core \nimport {\n WS_REPLY_TYPE,\n WS_EVT_NAME,\n WS_DATA_NAME,\n TIMESTAMP_PARAM_NAME,\n ERROR_KEY,\n EMIT_REPLY_TYPE,\n ACKNOWLEDGE_REPLY_TYPE\n} from 'jsonql-constants'\nimport { JsonqlError } from 'jsonql-errors' \nimport isString from 'lodash-es/isString'\n\nimport { toJson, isObjectHasKey, nil } from './generic'\nimport { timestamp } from './timestamp'\n\nconst PAYLOAD_NOT_DECODED_ERR = 'payload can not decoded'\nconst WS_KEYS = [\n WS_REPLY_TYPE,\n WS_EVT_NAME,\n WS_DATA_NAME\n]\n\n\n/**\n * The ws doesn't have a acknowledge callback like socket.io\n * so we have to DIY one for ws and other that doesn't have it\n * @param {string} type of reply\n * @param {string} resolverName which is replying\n * @param {*} data payload\n * @param {array} [ts= []] the last received ts, if any \n * @return {string} stringify json\n */\nexport const createWsReply = (type, resolverName, data, ts = []) => {\n ts.push(timestamp())\n return JSON.stringify({\n data: {\n [WS_REPLY_TYPE]: type,\n [WS_EVT_NAME]: resolverName,\n [WS_DATA_NAME]: toJson(data)\n },\n [TIMESTAMP_PARAM_NAME]: ts \n })\n}\n\n// extended function \nexport const createReplyMsg = (resolverName, data, ts = []) => (\n createWsReply(EMIT_REPLY_TYPE, resolverName, data, ts)\n)\n\nexport const createAcknowledgeMsg = (resolverName, data, ts = []) => (\n createWsReply(ACKNOWLEDGE_REPLY_TYPE, resolverName, data, ts)\n)\n\n/**\n * @param {string|object} payload should be string when reply but could be transformed\n * @return {boolean} true is OK\n */\nexport const isWsReply = payload => {\n const json = isString(payload) ? toJson(payload) : payload\n const { data } = json\n if (data) {\n let result = WS_KEYS.filter(key => isObjectHasKey(data, key))\n return (result.length === WS_KEYS.length) ? data : false\n }\n return false\n}\n\n/**\n * @param {string|object} data received data\n * @param {function} [cb=nil] this is for extracting the TS field or when it's error\n * @return {object} false on failed\n */\nexport const extractWsPayload = (payload, cb = nil) => {\n try {\n const json = toJson(payload)\n // now handle the data\n let _data\n if ((_data = isWsReply(json)) !== false) {\n // note the ts property is on its own \n cb(TIMESTAMP_PARAM_NAME, json[TIMESTAMP_PARAM_NAME])\n \n return {\n data: toJson(_data[WS_DATA_NAME]),\n resolverName: _data[WS_EVT_NAME],\n type: _data[WS_REPLY_TYPE]\n }\n }\n throw new JsonqlError(PAYLOAD_NOT_DECODED_ERR, payload)\n } catch(e) {\n return cb(ERROR_KEY, e)\n }\n}\n","// the WebSocket main handler\nimport {\n LOGOUT_EVENT_NAME,\n ACKNOWLEDGE_REPLY_TYPE,\n EMIT_REPLY_TYPE,\n ERROR_KEY,\n\n ON_ERROR_FN_NAME,\n ON_MESSAGE_FN_NAME,\n ON_RESULT_FN_NAME,\n ON_READY_FN_NAME,\n ON_LOGIN_FN_NAME\n} from 'jsonql-constants'\nimport { \n createQueryStr, \n createEvt, \n extractWsPayload \n} from 'jsonql-utils/module'\nimport {\n handleNamespaceOnError,\n createIntercomPayload\n} from '../modules'\n\n/**\n * in some edge case we might not even have a resolverName, then\n * we issue a global error for the developer to catch it\n * @param {object} ee event emitter\n * @param {string} namespace nsp\n * @param {string} resolverName resolver\n * @param {object} json decoded payload or error object\n * @return {undefined} nothing return\n */\nconst errorTypeHandler = (ee, namespace, resolverName, json) => {\n let evt = [namespace]\n if (resolverName) {\n evt.push(resolverName)\n }\n evt.push(ON_ERROR_FN_NAME)\n let evtName = Reflect.apply(createEvt, null, evt)\n // test if there is a data field\n let payload = json.data || json\n ee.$trigger(evtName, [payload])\n}\n\n/**\n * Handle the logout event when it's enableAuth\n * @param {object} ee eventEmitter\n * @param {object} ws the WebSocket instance\n * @return {void}\n */\nconst logoutEventListener = (ee, ws) => {\n // listen to the LOGOUT_EVENT_NAME when this is a private nsp\n ee.$on(LOGOUT_EVENT_NAME, function closeEvtHandler() {\n try {\n // @TODO we need find a way to get the userdata \n ws.send(createIntercomPayload(LOGOUT_EVENT_NAME))\n log('terminate ws connection')\n ws.terminate()\n } catch(e) {\n console.error('ws.terminate error', e)\n }\n })\n}\n\n/**\n * Binding the event to socket normally\n * @param {string} namespace\n * @param {object} ws the nsp\n * @param {object} ee EventEmitter\n * @param {boolean} isPrivate to id if this namespace is private or not\n * @param {object} opts configuration\n * @return {object} promise resolve after the onopen event\n */\nexport function bindSocketEventHandler(namespace, ws, ee, isPrivate, opts) {\n const { log } = opts\n\n log(`log test, isPrivate:`, isPrivate)\n // connection open\n ws.onopen = function onOpenCallback() {\n \n log('ws.onopen listened')\n // we just call the onReady\n ee.$call(ON_READY_FN_NAME, namespace)\n // need an extra parameter here to id the private nsp\n if (isPrivate) {\n log(`isPrivate and fire the ${ON_LOGIN_FN_NAME}`)\n ee.$call(ON_LOGIN_FN_NAME, namespace)\n }\n // add listener only after the open is called\n ee.$only(\n createEvt(namespace, EMIT_REPLY_TYPE),\n /**\n * actually send the payload to server\n * @param {string} resolverName \n * @param {array} args NEED TO CHECK HOW WE PASS THIS! \n */\n function wsMainOnEvtHandler(resolverName, args) {\n \n const payload = createQueryStr(resolverName, args)\n log('ws.onopen.send', resolverName, args, payload)\n \n ws.send(payload)\n }\n )\n }\n\n // reply\n // If we change it to the event callback style\n // then the payload will just be the payload and fucks up the extractWsPayload call @TODO\n ws.onmessage = function onMessageCallback(payload) {\n // console.log(`on.message`, typeof payload, payload)\n try {\n // log(`ws.onmessage raw payload`, payload)\n // @TODO the payload actually contain quite a few things - is that changed? \n // type: message, data: data_send_from_server\n const json = extractWsPayload(payload.data)\n const { resolverName, type } = json\n \n log('Respond from server', type, json)\n\n switch (type) {\n case EMIT_REPLY_TYPE:\n let e1 = createEvt(namespace, resolverName, ON_MESSAGE_FN_NAME)\n let r = ee.$trigger(e1, [json])\n log(`EMIT_REPLY_TYPE`, e1, r)\n break\n case ACKNOWLEDGE_REPLY_TYPE:\n let e2 = createEvt(namespace, resolverName, ON_RESULT_FN_NAME)\n let x2 = ee.$trigger(e2, [json])\n log(`ACKNOWLEDGE_REPLY_TYPE`, e2, x2)\n break\n case ERROR_KEY:\n // this is handled error and we won't throw it\n // we need to extract the error from json\n log(`ERROR_KEY`)\n errorTypeHandler(ee, namespace, resolverName, json)\n break \n // @TODO there should be an error type instead of roll into the other two types? TBC\n default:\n // if this happen then we should throw it and halt the operation all together\n log('Unhandled event!', json)\n errorTypeHandler(ee, namespace, resolverName, json)\n // let error = {error: {'message': 'Unhandled event!', type}};\n // ee.$trigger(createEvt(namespace, resolverName, ON_RESULT_FN_NAME), [error])\n }\n } catch(e) {\n console.error(`ws.onmessage error`, e)\n errorTypeHandler(ee, namespace, false, e)\n }\n }\n // when the server close the connection\n ws.onclose = function onCloseCallback() {\n log('ws.onclose callback')\n // @TODO what to do with this\n // ee.$trigger(LOGOUT_EVENT_NAME, [namespace])\n }\n // add a onerror event handler here \n ws.onerror = function onErrorCallback(err) {\n // trigger a global error event \n log(`ws.onerror`, err)\n handleNamespaceOnError(ee, namespace, err)\n }\n\n if (isPrivate) {\n logoutEventListener(ee, ws)\n }\n\n}\n","// actually binding the event client to the socket client\n\n// from the jsonql-ws-client-core\nimport { clientEventListener } from '../modules'\n// local \nimport { createNspAction } from './create-nsp-action'\nimport { loginEventHandler } from './login-event-handler'\nimport { bindSocketEventHandler } from './bind-socket-event-handler'\n\n/**\n * create the NSP(s) and determine if this require auth or not \n * @param {object} opts configuration\n * @param {object} nspMap namespace with resolvers\n * @param {object} ee EventEmitter to pass through\n * @return {object} what comes in what goes out\n */\nfunction createNsp(opts, nspMap, ee) {\n // now create the nsps\n // const { namespaces } = nspMap\n const { token } = opts\n\n return createNspAction(opts, nspMap, token)\n .then(nsps => {\n const listenerFn = clientEventListener(bindSocketEventHandler, nsps)\n // now run it\n listenerFn(opts, nspMap, ee)\n\n if (opts.enableAuth) {\n loginEventHandler(opts, nspMap, ee)\n }\n // return what input\n return { opts, nspMap, ee }\n }) \n}\n\nexport { createNsp }","// breaking up the create-nsp.js file \n// then regroup them back together here \nimport { createNsp } from './create-nsp'\n\nexport default createNsp\n","// share method to create the wsClientResolver\nimport { initWebSocketClient } from './init-websocket-client'\nimport createNsp from '../create-nsp'\nimport { NSP_CLIENT, NSP_AUTH_CLIENT } from 'jsonql-constants'\n\n/**\n * Create the framework <---> jsonql client binding\n * @param {object} frameworkModule the different WebSocket module\n * @return {function} the wsClientResolver\n */\nfunction bindFrameworkToJsonql(frameworkModule) {\n /**\n * wsClientResolver\n * @param {object} opts configuration\n * @param {object} nspMap from the contract\n * @param {object} ee instance of the eventEmitter\n * @return {object} passing the same 3 input out with additional in the opts\n */\n return function createClientBindingAction(opts, nspMap, ee) {\n const { log } = opts\n opts[NSP_CLIENT] = initWebSocketClient(frameworkModule, false, log)\n opts[NSP_AUTH_CLIENT] = initWebSocketClient(frameworkModule, true, log) \n // @1.0.7 remove later once everything fixed \n \n log(`bindFrameworkToJsonql`, ee.name, nspMap)\n // console.log(`contract`, opts.contract)\n return createNsp(opts, nspMap, ee)\n }\n}\n\nexport { bindFrameworkToJsonql }","// this will be the news style interface that will pass to the jsonql-ws-client\n// then return a function for accepting an opts to generate the final\n// client api\nimport WebSocket from 'ws'\nimport createWebSocketBinding from '../core/create-websocket-binding'\n\n/**\n * @param {object} opts configuration\n * @param {object} nspMap from the contract\n * @param {object} ee instance of the eventEmitter\n * @return {object} passing the same 3 input out with additional in the opts\n */\nexport default createWebSocketBinding(WebSocket)\n","// this is the module entry point for node client\nimport {\n wsClientCore\n} from './core/modules'\nimport { wsClientConstProps } from './options'\n\nimport nodeFrameworkSocketEngine from './node/node-framework-socket-engine'\n\n// export back the function and that's it\nexport default function wsNodeClient(config = {}, constProps = {}) {\n const initClientMethod = wsClientCore(\n nodeFrameworkSocketEngine, \n {}, \n Object.assign({}, wsClientConstProps, constProps)\n )\n return initClientMethod(config)\n}\n"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;ACAA;;;;;;;;;ACAA;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;ACAA;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;ACAA;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;"} \ No newline at end of file +{"version":3,"file":"main.js","sources":["../../ws-client-core/node_modules/lodash-es/isArray.js","node_modules/rollup-plugin-node-globals/src/global.js","../../ws-client-core/node_modules/lodash-es/_objectToString.js","../../ws-client-core/node_modules/lodash-es/_overArg.js","../../ws-client-core/node_modules/lodash-es/isObjectLike.js","../../ws-client-core/node_modules/lodash-es/_arrayMap.js","../../ws-client-core/node_modules/lodash-es/_baseSlice.js","../../ws-client-core/node_modules/lodash-es/_baseFindIndex.js","../../ws-client-core/node_modules/lodash-es/_baseIsNaN.js","../../ws-client-core/node_modules/lodash-es/_strictIndexOf.js","../../ws-client-core/node_modules/lodash-es/_asciiToArray.js","../../ws-client-core/node_modules/lodash-es/_hasUnicode.js","../../ws-client-core/node_modules/lodash-es/_unicodeToArray.js","../../ws-client-core/node_modules/jsonql-utils/src/generic.js","../../ws-client-core/node_modules/lodash-es/_listCacheClear.js","../../ws-client-core/node_modules/lodash-es/eq.js","../../ws-client-core/node_modules/lodash-es/_stackDelete.js","../../ws-client-core/node_modules/lodash-es/_stackGet.js","../../ws-client-core/node_modules/lodash-es/_stackHas.js","../../ws-client-core/node_modules/lodash-es/isObject.js","../../ws-client-core/node_modules/lodash-es/_toSource.js","../../ws-client-core/node_modules/lodash-es/_getValue.js","../../ws-client-core/node_modules/lodash-es/_hashDelete.js","../../ws-client-core/node_modules/lodash-es/_isKeyable.js","../../ws-client-core/node_modules/lodash-es/_createBaseFor.js","../../ws-client-core/node_modules/lodash-es/_copyArray.js","../../ws-client-core/node_modules/lodash-es/_isPrototype.js","../../ws-client-core/node_modules/lodash-es/isLength.js","../../ws-client-core/node_modules/lodash-es/stubFalse.js","../../ws-client-core/node_modules/lodash-es/_baseUnary.js","../../ws-client-core/node_modules/lodash-es/_safeGet.js","../../ws-client-core/node_modules/lodash-es/_baseTimes.js","../../ws-client-core/node_modules/lodash-es/_isIndex.js","../../ws-client-core/node_modules/lodash-es/_nativeKeysIn.js","../../ws-client-core/node_modules/lodash-es/identity.js","../../ws-client-core/node_modules/lodash-es/_apply.js","../../ws-client-core/node_modules/lodash-es/constant.js","../../ws-client-core/node_modules/lodash-es/_shortOut.js","../../ws-client-core/node_modules/jsonql-errors/src/enum-error.js","../../ws-client-core/node_modules/jsonql-errors/src/type-error.js","../../ws-client-core/node_modules/jsonql-errors/src/checker-error.js","../../ws-client-core/node_modules/jsonql-errors/src/validation-error.js","../../ws-client-core/node_modules/jsonql-utils/src/contract.js","../../ws-client-core/node_modules/jsonql-utils/src/timestamp.js","../../ws-client-core/node_modules/jsonql-utils/src/params-api.js","../../ws-client-core/node_modules/jsonql-utils/src/namespace.js","../../ws-client-core/node_modules/jsonql-utils/src/socket.js","../../ws-client-core/src/callers/intercom-methods.js","../../ws-client-core/node_modules/jsonql-params-validator/src/number.js","../../ws-client-core/node_modules/jsonql-params-validator/src/string.js","../../ws-client-core/node_modules/jsonql-params-validator/src/boolean.js","../../ws-client-core/node_modules/jsonql-params-validator/src/any.js","../../ws-client-core/node_modules/jsonql-params-validator/src/constants.js","../../ws-client-core/node_modules/jsonql-params-validator/src/combine.js","../../ws-client-core/node_modules/jsonql-params-validator/src/array.js","../../ws-client-core/node_modules/jsonql-params-validator/src/object.js","../../ws-client-core/node_modules/jsonql-params-validator/src/validator.js","../../ws-client-core/node_modules/lodash-es/_setCacheAdd.js","../../ws-client-core/node_modules/lodash-es/_setCacheHas.js","../../ws-client-core/node_modules/lodash-es/_arraySome.js","../../ws-client-core/node_modules/lodash-es/_cacheHas.js","../../ws-client-core/node_modules/lodash-es/_mapToArray.js","../../ws-client-core/node_modules/lodash-es/_setToArray.js","../../ws-client-core/node_modules/lodash-es/_arrayPush.js","../../ws-client-core/node_modules/lodash-es/_arrayFilter.js","../../ws-client-core/node_modules/lodash-es/stubArray.js","../../ws-client-core/node_modules/lodash-es/_matchesStrictComparable.js","../../ws-client-core/node_modules/lodash-es/_baseHasIn.js","../../ws-client-core/node_modules/lodash-es/_baseProperty.js","../../ws-client-core/node_modules/lodash-es/negate.js","../../ws-client-core/node_modules/lodash-es/_baseFindKey.js","../../ws-client-core/node_modules/jsonql-params-validator/src/is-in-array.js","../../ws-client-core/node_modules/jsonql-params-validator/src/options/run-validation.js","../../ws-client-core/node_modules/jsonql-params-validator/src/options/check-options-async.js","../../ws-client-core/node_modules/jsonql-params-validator/src/options/construct-config.js","../../ws-client-core/node_modules/jsonql-params-validator/src/options/index.js","../../ws-client-core/node_modules/jsonql-params-validator/index.js","../../ws-client-core/src/utils/get-log-fn.js","../../ws-client-core/node_modules/@to1source/event/src/constants.js","../../ws-client-core/node_modules/@to1source/event/src/store.js","../../ws-client-core/node_modules/@to1source/event/src/utils.js","../../ws-client-core/node_modules/@to1source/event/src/suspend.js","../../ws-client-core/node_modules/@to1source/event/src/store-service.js","../../ws-client-core/node_modules/@to1source/event/src/event-service.js","../../ws-client-core/node_modules/@to1source/event/index.js","../../ws-client-core/src/utils/get-event-emitter.js","../../ws-client-core/src/utils/helpers.js","../../ws-client-core/src/callers/setup-auth-methods.js","../../ws-client-core/src/options/constants.js","../../ws-client-core/src/callers/respond-handler.js","../../ws-client-core/src/callers/action-call.js","../../ws-client-core/src/callers/setup-send-method.js","../../ws-client-core/src/callers/setup-resolver.js","../../ws-client-core/src/callers/generator-methods.js","../../ws-client-core/src/callers/setup-intercom.js","../../ws-client-core/src/callers/setup-final-step.js","../../ws-client-core/src/callers/callers-generator.js","../../ws-client-core/src/options/index.js","../../ws-client-core/src/api.js","../../ws-client-core/src/listener/create-nsp-clients.js","../../ws-client-core/src/listener/trigger-namespaces-on-error.js","../../ws-client-core/src/listener/event-listeners.js","../../ws-client-core/src/listener/client-event-listener.js","src/options/index.js","src/core/create-websocket-binding/init-websocket-client.js","node_modules/lodash-es/_objectToString.js","node_modules/lodash-es/_overArg.js","node_modules/lodash-es/isObjectLike.js","node_modules/lodash-es/_listCacheClear.js","node_modules/lodash-es/eq.js","node_modules/lodash-es/_stackDelete.js","node_modules/lodash-es/_stackGet.js","node_modules/lodash-es/_stackHas.js","node_modules/lodash-es/isObject.js","node_modules/lodash-es/_toSource.js","node_modules/lodash-es/_getValue.js","node_modules/lodash-es/_hashDelete.js","node_modules/lodash-es/_isKeyable.js","node_modules/lodash-es/_createBaseFor.js","node_modules/lodash-es/_copyArray.js","node_modules/lodash-es/_isPrototype.js","node_modules/lodash-es/isArray.js","node_modules/lodash-es/isLength.js","node_modules/lodash-es/stubFalse.js","node_modules/lodash-es/_baseUnary.js","node_modules/lodash-es/_safeGet.js","node_modules/lodash-es/_baseTimes.js","node_modules/lodash-es/_isIndex.js","node_modules/lodash-es/_nativeKeysIn.js","node_modules/lodash-es/identity.js","node_modules/lodash-es/_apply.js","node_modules/lodash-es/constant.js","node_modules/lodash-es/_shortOut.js","node_modules/jsonql-utils/src/chain-promises.js","src/core/create-nsp/login-event-handler.js","node_modules/jsonql-utils/src/generic.js","node_modules/jsonql-errors/src/validation-error.js","node_modules/jsonql-utils/src/timestamp.js","node_modules/jsonql-utils/src/params-api.js","node_modules/jsonql-utils/src/socket.js","src/core/create-nsp/bind-socket-event-handler.js","src/core/create-nsp/create-nsp.js","src/core/create-nsp/index.js","src/core/create-websocket-binding/bind-framework-to-jsonql.js","src/node/node-framework-socket-engine.js","src/node-ws-client.js"],"sourcesContent":["/**\n * Checks if `value` is classified as an `Array` object.\n *\n * @static\n * @memberOf _\n * @since 0.1.0\n * @category Lang\n * @param {*} value The value to check.\n * @returns {boolean} Returns `true` if `value` is an array, else `false`.\n * @example\n *\n * _.isArray([1, 2, 3]);\n * // => true\n *\n * _.isArray(document.body.children);\n * // => false\n *\n * _.isArray('abc');\n * // => false\n *\n * _.isArray(_.noop);\n * // => false\n */\nvar isArray = Array.isArray;\n\nexport default isArray;\n","export default (typeof global !== \"undefined\" ? global :\n typeof self !== \"undefined\" ? self :\n typeof window !== \"undefined\" ? window : {});\n","/** Used for built-in method references. */\nvar objectProto = Object.prototype;\n\n/**\n * Used to resolve the\n * [`toStringTag`](http://ecma-international.org/ecma-262/7.0/#sec-object.prototype.tostring)\n * of values.\n */\nvar nativeObjectToString = objectProto.toString;\n\n/**\n * Converts `value` to a string using `Object.prototype.toString`.\n *\n * @private\n * @param {*} value The value to convert.\n * @returns {string} Returns the converted string.\n */\nfunction objectToString(value) {\n return nativeObjectToString.call(value);\n}\n\nexport default objectToString;\n","/**\n * Creates a unary function that invokes `func` with its argument transformed.\n *\n * @private\n * @param {Function} func The function to wrap.\n * @param {Function} transform The argument transform.\n * @returns {Function} Returns the new function.\n */\nfunction overArg(func, transform) {\n return function(arg) {\n return func(transform(arg));\n };\n}\n\nexport default overArg;\n","/**\n * Checks if `value` is object-like. A value is object-like if it's not `null`\n * and has a `typeof` result of \"object\".\n *\n * @static\n * @memberOf _\n * @since 4.0.0\n * @category Lang\n * @param {*} value The value to check.\n * @returns {boolean} Returns `true` if `value` is object-like, else `false`.\n * @example\n *\n * _.isObjectLike({});\n * // => true\n *\n * _.isObjectLike([1, 2, 3]);\n * // => true\n *\n * _.isObjectLike(_.noop);\n * // => false\n *\n * _.isObjectLike(null);\n * // => false\n */\nfunction isObjectLike(value) {\n return value != null && typeof value == 'object';\n}\n\nexport default isObjectLike;\n","/**\n * A specialized version of `_.map` for arrays without support for iteratee\n * shorthands.\n *\n * @private\n * @param {Array} [array] The array to iterate over.\n * @param {Function} iteratee The function invoked per iteration.\n * @returns {Array} Returns the new mapped array.\n */\nfunction arrayMap(array, iteratee) {\n var index = -1,\n length = array == null ? 0 : array.length,\n result = Array(length);\n\n while (++index < length) {\n result[index] = iteratee(array[index], index, array);\n }\n return result;\n}\n\nexport default arrayMap;\n","/**\n * The base implementation of `_.slice` without an iteratee call guard.\n *\n * @private\n * @param {Array} array The array to slice.\n * @param {number} [start=0] The start position.\n * @param {number} [end=array.length] The end position.\n * @returns {Array} Returns the slice of `array`.\n */\nfunction baseSlice(array, start, end) {\n var index = -1,\n length = array.length;\n\n if (start < 0) {\n start = -start > length ? 0 : (length + start);\n }\n end = end > length ? length : end;\n if (end < 0) {\n end += length;\n }\n length = start > end ? 0 : ((end - start) >>> 0);\n start >>>= 0;\n\n var result = Array(length);\n while (++index < length) {\n result[index] = array[index + start];\n }\n return result;\n}\n\nexport default baseSlice;\n","/**\n * The base implementation of `_.findIndex` and `_.findLastIndex` without\n * support for iteratee shorthands.\n *\n * @private\n * @param {Array} array The array to inspect.\n * @param {Function} predicate The function invoked per iteration.\n * @param {number} fromIndex The index to search from.\n * @param {boolean} [fromRight] Specify iterating from right to left.\n * @returns {number} Returns the index of the matched value, else `-1`.\n */\nfunction baseFindIndex(array, predicate, fromIndex, fromRight) {\n var length = array.length,\n index = fromIndex + (fromRight ? 1 : -1);\n\n while ((fromRight ? index-- : ++index < length)) {\n if (predicate(array[index], index, array)) {\n return index;\n }\n }\n return -1;\n}\n\nexport default baseFindIndex;\n","/**\n * The base implementation of `_.isNaN` without support for number objects.\n *\n * @private\n * @param {*} value The value to check.\n * @returns {boolean} Returns `true` if `value` is `NaN`, else `false`.\n */\nfunction baseIsNaN(value) {\n return value !== value;\n}\n\nexport default baseIsNaN;\n","/**\n * A specialized version of `_.indexOf` which performs strict equality\n * comparisons of values, i.e. `===`.\n *\n * @private\n * @param {Array} array The array to inspect.\n * @param {*} value The value to search for.\n * @param {number} fromIndex The index to search from.\n * @returns {number} Returns the index of the matched value, else `-1`.\n */\nfunction strictIndexOf(array, value, fromIndex) {\n var index = fromIndex - 1,\n length = array.length;\n\n while (++index < length) {\n if (array[index] === value) {\n return index;\n }\n }\n return -1;\n}\n\nexport default strictIndexOf;\n","/**\n * Converts an ASCII `string` to an array.\n *\n * @private\n * @param {string} string The string to convert.\n * @returns {Array} Returns the converted array.\n */\nfunction asciiToArray(string) {\n return string.split('');\n}\n\nexport default asciiToArray;\n","/** Used to compose unicode character classes. */\nvar rsAstralRange = '\\\\ud800-\\\\udfff',\n rsComboMarksRange = '\\\\u0300-\\\\u036f',\n reComboHalfMarksRange = '\\\\ufe20-\\\\ufe2f',\n rsComboSymbolsRange = '\\\\u20d0-\\\\u20ff',\n rsComboRange = rsComboMarksRange + reComboHalfMarksRange + rsComboSymbolsRange,\n rsVarRange = '\\\\ufe0e\\\\ufe0f';\n\n/** Used to compose unicode capture groups. */\nvar rsZWJ = '\\\\u200d';\n\n/** Used to detect strings with [zero-width joiners or code points from the astral planes](http://eev.ee/blog/2015/09/12/dark-corners-of-unicode/). */\nvar reHasUnicode = RegExp('[' + rsZWJ + rsAstralRange + rsComboRange + rsVarRange + ']');\n\n/**\n * Checks if `string` contains Unicode symbols.\n *\n * @private\n * @param {string} string The string to inspect.\n * @returns {boolean} Returns `true` if a symbol is found, else `false`.\n */\nfunction hasUnicode(string) {\n return reHasUnicode.test(string);\n}\n\nexport default hasUnicode;\n","/** Used to compose unicode character classes. */\nvar rsAstralRange = '\\\\ud800-\\\\udfff',\n rsComboMarksRange = '\\\\u0300-\\\\u036f',\n reComboHalfMarksRange = '\\\\ufe20-\\\\ufe2f',\n rsComboSymbolsRange = '\\\\u20d0-\\\\u20ff',\n rsComboRange = rsComboMarksRange + reComboHalfMarksRange + rsComboSymbolsRange,\n rsVarRange = '\\\\ufe0e\\\\ufe0f';\n\n/** Used to compose unicode capture groups. */\nvar rsAstral = '[' + rsAstralRange + ']',\n rsCombo = '[' + rsComboRange + ']',\n rsFitz = '\\\\ud83c[\\\\udffb-\\\\udfff]',\n rsModifier = '(?:' + rsCombo + '|' + rsFitz + ')',\n rsNonAstral = '[^' + rsAstralRange + ']',\n rsRegional = '(?:\\\\ud83c[\\\\udde6-\\\\uddff]){2}',\n rsSurrPair = '[\\\\ud800-\\\\udbff][\\\\udc00-\\\\udfff]',\n rsZWJ = '\\\\u200d';\n\n/** Used to compose unicode regexes. */\nvar reOptMod = rsModifier + '?',\n rsOptVar = '[' + rsVarRange + ']?',\n rsOptJoin = '(?:' + rsZWJ + '(?:' + [rsNonAstral, rsRegional, rsSurrPair].join('|') + ')' + rsOptVar + reOptMod + ')*',\n rsSeq = rsOptVar + reOptMod + rsOptJoin,\n rsSymbol = '(?:' + [rsNonAstral + rsCombo + '?', rsCombo, rsRegional, rsSurrPair, rsAstral].join('|') + ')';\n\n/** Used to match [string symbols](https://mathiasbynens.be/notes/javascript-unicode). */\nvar reUnicode = RegExp(rsFitz + '(?=' + rsFitz + ')|' + rsSymbol + rsSeq, 'g');\n\n/**\n * Converts a Unicode `string` to an array.\n *\n * @private\n * @param {string} string The string to convert.\n * @returns {Array} Returns the converted array.\n */\nfunction unicodeToArray(string) {\n return string.match(reUnicode) || [];\n}\n\nexport default unicodeToArray;\n","// bunch of generic helpers\n\nimport isArray from 'lodash-es/isArray'\nimport isPlainObject from 'lodash-es/isPlainObject'\nimport trim from 'lodash-es/trim'\n\n/**\n * DIY in Array\n * @param {array} arr to check from\n * @param {*} value to check against\n * @return {boolean} true on found\n */\nexport const inArray = (arr, value) => !!arr.filter(a => a === value).length\n\n// quick and dirty to turn non array to array\nexport const toArray = (arg) => isArray(arg) ? arg : [arg]\n\n/**\n * parse string to json or just return the original value if error happened\n * @param {*} n input\n * @param {boolean} [t=true] or throw\n * @return {*} json object on success\n */\nexport const parseJson = function(n, t=true) {\n try {\n return JSON.parse(n)\n } catch(e) {\n if (t) {\n return n\n }\n throw new Error(e)\n }\n}\n\n/**\n * @param {object} obj for search\n * @param {string} key target\n * @return {boolean} true on success\n */\nexport const isObjectHasKey = function(obj, key) {\n try {\n const keys = Object.keys(obj)\n return inArray(keys, key)\n } catch(e) {\n // @BUG when the obj is not an OBJECT we got some weird output\n return false\n }\n}\n\n/**\n * create a event name\n * @param {string[]} args\n * @return {string} event name for use\n */\nexport const createEvt = (...args) => args.join('_')\n\n/**\n * simple util method to get the value\n * @param {string} name of the key\n * @param {object} obj to take value from\n * @return {*} the object value id by name or undefined\n */\nexport const getConfigValue = (name, obj) => (\n obj && isPlainObject(obj) ? ( (name in obj) ? obj[name] : undefined ) : undefined\n)\n\n/**\n * small util to make sure the return value is valid JSON object\n * @param {*} n input\n * @return {object} correct JSON object\n */\nexport const toJson = n => {\n if (typeof n === 'string') {\n return parseJson(n)\n }\n return parseJson(JSON.stringify(n))\n}\n\n/**\n * Check several parameter that there is something in the param\n * @param {*} param input\n * @return {boolean}\n */\nexport const isNotEmpty = function(param) {\n return param !== undefined && param !== false && param !== null && trim(param) !== ''\n}\n\n/**\n * Simple check if the prop is function\n * @param {*} prop input\n * @return {boolean} true on success\n */\nexport const isFunc = prop => {\n if (typeof prop === 'function') {\n return true;\n }\n console.error(`Expect to be Function type! Got ${typeof prop}`)\n}\n\n/**\n * Shorthand method for Object.assign \n * @param {array} args \n * @return {object} merge together object by key \n */\nexport const assign = (...args) => Reflect.apply(Object.assign, Object, args)\n \n/** \n * generic placeholder function\n * @return {boolean} false \n */\nexport const nil = () => false\n\n/**\n * generic turn config into immutatble \n */\nexport const freeze = config => Object.freeze(config)","/**\n * Removes all key-value entries from the list cache.\n *\n * @private\n * @name clear\n * @memberOf ListCache\n */\nfunction listCacheClear() {\n this.__data__ = [];\n this.size = 0;\n}\n\nexport default listCacheClear;\n","/**\n * Performs a\n * [`SameValueZero`](http://ecma-international.org/ecma-262/7.0/#sec-samevaluezero)\n * comparison between two values to determine if they are equivalent.\n *\n * @static\n * @memberOf _\n * @since 4.0.0\n * @category Lang\n * @param {*} value The value to compare.\n * @param {*} other The other value to compare.\n * @returns {boolean} Returns `true` if the values are equivalent, else `false`.\n * @example\n *\n * var object = { 'a': 1 };\n * var other = { 'a': 1 };\n *\n * _.eq(object, object);\n * // => true\n *\n * _.eq(object, other);\n * // => false\n *\n * _.eq('a', 'a');\n * // => true\n *\n * _.eq('a', Object('a'));\n * // => false\n *\n * _.eq(NaN, NaN);\n * // => true\n */\nfunction eq(value, other) {\n return value === other || (value !== value && other !== other);\n}\n\nexport default eq;\n","/**\n * Removes `key` and its value from the stack.\n *\n * @private\n * @name delete\n * @memberOf Stack\n * @param {string} key The key of the value to remove.\n * @returns {boolean} Returns `true` if the entry was removed, else `false`.\n */\nfunction stackDelete(key) {\n var data = this.__data__,\n result = data['delete'](key);\n\n this.size = data.size;\n return result;\n}\n\nexport default stackDelete;\n","/**\n * Gets the stack value for `key`.\n *\n * @private\n * @name get\n * @memberOf Stack\n * @param {string} key The key of the value to get.\n * @returns {*} Returns the entry value.\n */\nfunction stackGet(key) {\n return this.__data__.get(key);\n}\n\nexport default stackGet;\n","/**\n * Checks if a stack value for `key` exists.\n *\n * @private\n * @name has\n * @memberOf Stack\n * @param {string} key The key of the entry to check.\n * @returns {boolean} Returns `true` if an entry for `key` exists, else `false`.\n */\nfunction stackHas(key) {\n return this.__data__.has(key);\n}\n\nexport default stackHas;\n","/**\n * Checks if `value` is the\n * [language type](http://www.ecma-international.org/ecma-262/7.0/#sec-ecmascript-language-types)\n * of `Object`. (e.g. arrays, functions, objects, regexes, `new Number(0)`, and `new String('')`)\n *\n * @static\n * @memberOf _\n * @since 0.1.0\n * @category Lang\n * @param {*} value The value to check.\n * @returns {boolean} Returns `true` if `value` is an object, else `false`.\n * @example\n *\n * _.isObject({});\n * // => true\n *\n * _.isObject([1, 2, 3]);\n * // => true\n *\n * _.isObject(_.noop);\n * // => true\n *\n * _.isObject(null);\n * // => false\n */\nfunction isObject(value) {\n var type = typeof value;\n return value != null && (type == 'object' || type == 'function');\n}\n\nexport default isObject;\n","/** Used for built-in method references. */\nvar funcProto = Function.prototype;\n\n/** Used to resolve the decompiled source of functions. */\nvar funcToString = funcProto.toString;\n\n/**\n * Converts `func` to its source code.\n *\n * @private\n * @param {Function} func The function to convert.\n * @returns {string} Returns the source code.\n */\nfunction toSource(func) {\n if (func != null) {\n try {\n return funcToString.call(func);\n } catch (e) {}\n try {\n return (func + '');\n } catch (e) {}\n }\n return '';\n}\n\nexport default toSource;\n","/**\n * Gets the value at `key` of `object`.\n *\n * @private\n * @param {Object} [object] The object to query.\n * @param {string} key The key of the property to get.\n * @returns {*} Returns the property value.\n */\nfunction getValue(object, key) {\n return object == null ? undefined : object[key];\n}\n\nexport default getValue;\n","/**\n * Removes `key` and its value from the hash.\n *\n * @private\n * @name delete\n * @memberOf Hash\n * @param {Object} hash The hash to modify.\n * @param {string} key The key of the value to remove.\n * @returns {boolean} Returns `true` if the entry was removed, else `false`.\n */\nfunction hashDelete(key) {\n var result = this.has(key) && delete this.__data__[key];\n this.size -= result ? 1 : 0;\n return result;\n}\n\nexport default hashDelete;\n","/**\n * Checks if `value` is suitable for use as unique object key.\n *\n * @private\n * @param {*} value The value to check.\n * @returns {boolean} Returns `true` if `value` is suitable, else `false`.\n */\nfunction isKeyable(value) {\n var type = typeof value;\n return (type == 'string' || type == 'number' || type == 'symbol' || type == 'boolean')\n ? (value !== '__proto__')\n : (value === null);\n}\n\nexport default isKeyable;\n","/**\n * Creates a base function for methods like `_.forIn` and `_.forOwn`.\n *\n * @private\n * @param {boolean} [fromRight] Specify iterating from right to left.\n * @returns {Function} Returns the new base function.\n */\nfunction createBaseFor(fromRight) {\n return function(object, iteratee, keysFunc) {\n var index = -1,\n iterable = Object(object),\n props = keysFunc(object),\n length = props.length;\n\n while (length--) {\n var key = props[fromRight ? length : ++index];\n if (iteratee(iterable[key], key, iterable) === false) {\n break;\n }\n }\n return object;\n };\n}\n\nexport default createBaseFor;\n","/**\n * Copies the values of `source` to `array`.\n *\n * @private\n * @param {Array} source The array to copy values from.\n * @param {Array} [array=[]] The array to copy values to.\n * @returns {Array} Returns `array`.\n */\nfunction copyArray(source, array) {\n var index = -1,\n length = source.length;\n\n array || (array = Array(length));\n while (++index < length) {\n array[index] = source[index];\n }\n return array;\n}\n\nexport default copyArray;\n","/** Used for built-in method references. */\nvar objectProto = Object.prototype;\n\n/**\n * Checks if `value` is likely a prototype object.\n *\n * @private\n * @param {*} value The value to check.\n * @returns {boolean} Returns `true` if `value` is a prototype, else `false`.\n */\nfunction isPrototype(value) {\n var Ctor = value && value.constructor,\n proto = (typeof Ctor == 'function' && Ctor.prototype) || objectProto;\n\n return value === proto;\n}\n\nexport default isPrototype;\n","/** Used as references for various `Number` constants. */\nvar MAX_SAFE_INTEGER = 9007199254740991;\n\n/**\n * Checks if `value` is a valid array-like length.\n *\n * **Note:** This method is loosely based on\n * [`ToLength`](http://ecma-international.org/ecma-262/7.0/#sec-tolength).\n *\n * @static\n * @memberOf _\n * @since 4.0.0\n * @category Lang\n * @param {*} value The value to check.\n * @returns {boolean} Returns `true` if `value` is a valid length, else `false`.\n * @example\n *\n * _.isLength(3);\n * // => true\n *\n * _.isLength(Number.MIN_VALUE);\n * // => false\n *\n * _.isLength(Infinity);\n * // => false\n *\n * _.isLength('3');\n * // => false\n */\nfunction isLength(value) {\n return typeof value == 'number' &&\n value > -1 && value % 1 == 0 && value <= MAX_SAFE_INTEGER;\n}\n\nexport default isLength;\n","/**\n * This method returns `false`.\n *\n * @static\n * @memberOf _\n * @since 4.13.0\n * @category Util\n * @returns {boolean} Returns `false`.\n * @example\n *\n * _.times(2, _.stubFalse);\n * // => [false, false]\n */\nfunction stubFalse() {\n return false;\n}\n\nexport default stubFalse;\n","/**\n * The base implementation of `_.unary` without support for storing metadata.\n *\n * @private\n * @param {Function} func The function to cap arguments for.\n * @returns {Function} Returns the new capped function.\n */\nfunction baseUnary(func) {\n return function(value) {\n return func(value);\n };\n}\n\nexport default baseUnary;\n","/**\n * Gets the value at `key`, unless `key` is \"__proto__\" or \"constructor\".\n *\n * @private\n * @param {Object} object The object to query.\n * @param {string} key The key of the property to get.\n * @returns {*} Returns the property value.\n */\nfunction safeGet(object, key) {\n if (key === 'constructor' && typeof object[key] === 'function') {\n return;\n }\n\n if (key == '__proto__') {\n return;\n }\n\n return object[key];\n}\n\nexport default safeGet;\n","/**\n * The base implementation of `_.times` without support for iteratee shorthands\n * or max array length checks.\n *\n * @private\n * @param {number} n The number of times to invoke `iteratee`.\n * @param {Function} iteratee The function invoked per iteration.\n * @returns {Array} Returns the array of results.\n */\nfunction baseTimes(n, iteratee) {\n var index = -1,\n result = Array(n);\n\n while (++index < n) {\n result[index] = iteratee(index);\n }\n return result;\n}\n\nexport default baseTimes;\n","/** Used as references for various `Number` constants. */\nvar MAX_SAFE_INTEGER = 9007199254740991;\n\n/** Used to detect unsigned integer values. */\nvar reIsUint = /^(?:0|[1-9]\\d*)$/;\n\n/**\n * Checks if `value` is a valid array-like index.\n *\n * @private\n * @param {*} value The value to check.\n * @param {number} [length=MAX_SAFE_INTEGER] The upper bounds of a valid index.\n * @returns {boolean} Returns `true` if `value` is a valid index, else `false`.\n */\nfunction isIndex(value, length) {\n var type = typeof value;\n length = length == null ? MAX_SAFE_INTEGER : length;\n\n return !!length &&\n (type == 'number' ||\n (type != 'symbol' && reIsUint.test(value))) &&\n (value > -1 && value % 1 == 0 && value < length);\n}\n\nexport default isIndex;\n","/**\n * This function is like\n * [`Object.keys`](http://ecma-international.org/ecma-262/7.0/#sec-object.keys)\n * except that it includes inherited enumerable properties.\n *\n * @private\n * @param {Object} object The object to query.\n * @returns {Array} Returns the array of property names.\n */\nfunction nativeKeysIn(object) {\n var result = [];\n if (object != null) {\n for (var key in Object(object)) {\n result.push(key);\n }\n }\n return result;\n}\n\nexport default nativeKeysIn;\n","/**\n * This method returns the first argument it receives.\n *\n * @static\n * @since 0.1.0\n * @memberOf _\n * @category Util\n * @param {*} value Any value.\n * @returns {*} Returns `value`.\n * @example\n *\n * var object = { 'a': 1 };\n *\n * console.log(_.identity(object) === object);\n * // => true\n */\nfunction identity(value) {\n return value;\n}\n\nexport default identity;\n","/**\n * A faster alternative to `Function#apply`, this function invokes `func`\n * with the `this` binding of `thisArg` and the arguments of `args`.\n *\n * @private\n * @param {Function} func The function to invoke.\n * @param {*} thisArg The `this` binding of `func`.\n * @param {Array} args The arguments to invoke `func` with.\n * @returns {*} Returns the result of `func`.\n */\nfunction apply(func, thisArg, args) {\n switch (args.length) {\n case 0: return func.call(thisArg);\n case 1: return func.call(thisArg, args[0]);\n case 2: return func.call(thisArg, args[0], args[1]);\n case 3: return func.call(thisArg, args[0], args[1], args[2]);\n }\n return func.apply(thisArg, args);\n}\n\nexport default apply;\n","/**\n * Creates a function that returns `value`.\n *\n * @static\n * @memberOf _\n * @since 2.4.0\n * @category Util\n * @param {*} value The value to return from the new function.\n * @returns {Function} Returns the new constant function.\n * @example\n *\n * var objects = _.times(2, _.constant({ 'a': 1 }));\n *\n * console.log(objects);\n * // => [{ 'a': 1 }, { 'a': 1 }]\n *\n * console.log(objects[0] === objects[1]);\n * // => true\n */\nfunction constant(value) {\n return function() {\n return value;\n };\n}\n\nexport default constant;\n","/** Used to detect hot functions by number of calls within a span of milliseconds. */\nvar HOT_COUNT = 800,\n HOT_SPAN = 16;\n\n/* Built-in method references for those with the same name as other `lodash` methods. */\nvar nativeNow = Date.now;\n\n/**\n * Creates a function that'll short out and invoke `identity` instead\n * of `func` when it's called `HOT_COUNT` or more times in `HOT_SPAN`\n * milliseconds.\n *\n * @private\n * @param {Function} func The function to restrict.\n * @returns {Function} Returns the new shortable function.\n */\nfunction shortOut(func) {\n var count = 0,\n lastCalled = 0;\n\n return function() {\n var stamp = nativeNow(),\n remaining = HOT_SPAN - (stamp - lastCalled);\n\n lastCalled = stamp;\n if (remaining > 0) {\n if (++count >= HOT_COUNT) {\n return arguments[0];\n }\n } else {\n count = 0;\n }\n return func.apply(undefined, arguments);\n };\n}\n\nexport default shortOut;\n","// this get throw from within the checkOptions when run through the enum failed\nexport default class JsonqlEnumError extends Error {\n constructor(...args) {\n super(...args)\n\n this.message = args[0]\n this.detail = args[1]\n\n this.className = JsonqlEnumError.name;\n\n if (Error.captureStackTrace) {\n Error.captureStackTrace(this, JsonqlEnumError)\n }\n }\n\n static get name() {\n return 'JsonqlEnumError'\n }\n}\n","// this will throw from inside the checkOptions\nexport default class JsonqlTypeError extends Error {\n constructor(...args) {\n super(...args)\n\n this.message = args[0]\n this.detail = args[1]\n\n this.className = JsonqlTypeError.name\n\n if (Error.captureStackTrace) {\n Error.captureStackTrace(this, JsonqlTypeError)\n }\n }\n\n static get name() {\n return 'JsonqlTypeError'\n }\n}\n","// allow supply a custom checker function\n// if that failed then we throw this error\nexport default class JsonqlCheckerError extends Error {\n constructor(...args) {\n super(...args)\n this.message = args[0]\n this.detail = args[1]\n\n this.className = JsonqlCheckerError.name;\n\n if (Error.captureStackTrace) {\n Error.captureStackTrace(this, JsonqlCheckerError)\n }\n }\n\n static get name() {\n return 'JsonqlCheckerError'\n }\n}\n","// custom validation error class\n// when validaton failed\nexport default class JsonqlValidationError extends Error {\n constructor(...args) {\n super(...args)\n\n this.message = args[0]\n this.detail = args[1]\n\n this.className = JsonqlValidationError.name;\n\n if (Error.captureStackTrace) {\n Error.captureStackTrace(this, JsonqlValidationError)\n }\n }\n\n static get name() {\n return 'JsonqlValidationError'\n }\n}\n","// split the contract into the node side and the generic side\nimport { isObjectHasKey } from './generic'\nimport isPlainObject from 'lodash-es/isPlainObject'\nimport {\n QUERY_NAME,\n MUTATION_NAME,\n SOCKET_NAME,\n QUERY_ARG_NAME,\n PAYLOAD_PARAM_NAME,\n CONDITION_PARAM_NAME\n} from 'jsonql-constants'\nimport { JsonqlError, JsonqlResolverNotFoundError } from 'jsonql-errors'\n/**\n * Check if the json is a contract file or not\n * @param {object} contract json object\n * @return {boolean} true\n */\nexport function checkIsContract(contract) {\n return isPlainObject(contract)\n && (\n isObjectHasKey(contract, QUERY_NAME)\n || isObjectHasKey(contract, MUTATION_NAME)\n || isObjectHasKey(contract, SOCKET_NAME)\n )\n}\n\n/**\n * Wrapper method that check if it's contract then return the contract or false\n * @param {object} contract the object to check\n * @return {boolean | object} false when it's not\n */\nexport function isContract(contract) {\n return checkIsContract(contract) ? contract : false\n}\n\n/**\n * Ported from jsonql-params-validator but different\n * if we don't find the socket part then return false\n * @param {object} contract the contract object\n * @return {object|boolean} false on failed\n */\nexport function extractSocketPart(contract) {\n if (isObjectHasKey(contract, SOCKET_NAME)) {\n return contract[SOCKET_NAME]\n }\n return false\n}\n\n/**\n * Extract the args from the payload\n * @param {object} payload to work with\n * @param {string} type of call\n * @return {array} args\n */\nexport function extractArgsFromPayload(payload, type) {\n switch (type) {\n case QUERY_NAME:\n return payload[QUERY_ARG_NAME]\n case MUTATION_NAME:\n return [\n payload[PAYLOAD_PARAM_NAME],\n payload[CONDITION_PARAM_NAME]\n ]\n default:\n throw new JsonqlError(`Unknown ${type} to extract argument from!`)\n }\n}\n\n/**\n * Like what the name said\n * @param {object} contract the contract json\n * @param {string} type query|mutation\n * @param {string} name of the function\n * @return {object} the params part of the contract\n */\nexport function extractParamsFromContract(contract, type, name) {\n try {\n const result = contract[type][name]\n // debug('extractParamsFromContract', result)\n if (!result) {\n // debug(name, type, contract)\n throw new JsonqlResolverNotFoundError(name, type)\n }\n return result\n } catch(e) {\n throw new JsonqlResolverNotFoundError(name, e)\n }\n}\n","/**\n * @param {boolean} sec return in second or not\n * @return {number} timestamp\n */\nexport const timestamp = (sec = false) => {\n let time = Date.now()\n return sec ? Math.floor( time / 1000 ) : time\n}\n","// ported from jsonql-params-validator\n// craete several helper function to construct / extract the payload\n// and make sure they are all the same\nimport {\n PAYLOAD_PARAM_NAME,\n CONDITION_PARAM_NAME,\n RESOLVER_PARAM_NAME,\n QUERY_ARG_NAME,\n TIMESTAMP_PARAM_NAME\n} from 'jsonql-constants'\n\nimport JsonqlValidationError from 'jsonql-errors/src/validation-error'\n\nimport isArray from 'lodash-es/isArray'\nimport isString from 'lodash-es/isString'\nimport isPlainObject from 'lodash-es/isPlainObject'\n\nimport { timestamp } from './timestamp'\nimport { parseJson } from './generic'\n\n/**\n * check if the payload has a timestamp field, then append a new timestamp to it\n * @param {object} payload from the com\n * @return {array} timestamp field with an array value\n */\nexport const handleTimestamp = payload => {\n let ts = payload[TIMESTAMP_PARAM_NAME]\n if (!isArray(ts)) {\n ts = [ts]\n }\n ts.push( timestamp() )\n\n return ts\n}\n\n/**\n * make sure it's an object (it was call formatPayload but it doesn't make sense)\n * @param {*} payload the object comes in could be string based\n * @return {object} the transformed payload\n */\nexport const toPayload = payload => isString(payload) ? parseJson(payload) : payload\n\n/**\n * @param {*} args arguments to send\n *@return {object} formatted payload\n */\nexport const formatPayload = (args) => (\n { [QUERY_ARG_NAME]: args }\n)\n\n/**\n * extract the resolver name from the payload \n * @param {object} payload\n * @return {string} resolver name \n */\nexport function getResolverFromPayload(payload) {\n const keys = Object.keys(payload)\n return keys.filter(key => key !== TIMESTAMP_PARAM_NAME)[0]\n}\n\n/**\n * wrapper method to add the timestamp as well\n * @param {string} resolverName\n * @param {*} payload\n * @return {object} delierable\n */\nexport function createDeliverable(resolverName, payload) {\n return {\n [resolverName]: payload,\n [TIMESTAMP_PARAM_NAME]: [ timestamp() ]\n }\n}\n\n/**\n * @param {string} resolverName name of function\n * @param {array} [args=[]] from the ...args\n * @param {boolean} [jsonp = false] add v1.3.0 to koa\n * @return {object} formatted argument\n */\nexport function createQuery(resolverName, args = [], jsonp = false) {\n if (isString(resolverName) && isArray(args)) {\n let payload = formatPayload(args)\n if (jsonp === true) {\n return payload\n }\n return createDeliverable(resolverName, payload)\n }\n throw new JsonqlValidationError(`[createQuery] expect resolverName to be string and args to be array!`, { resolverName, args })\n}\n\n/**\n * string version of the createQuery\n * @return {string}\n */\nexport function createQueryStr(resolverName, args = [], jsonp = false) {\n return JSON.stringify(createQuery(resolverName, args, jsonp))\n}\n\n/**\n * @param {string} resolverName name of function\n * @param {*} payload to send\n * @param {object} [condition={}] for what\n * @param {boolean} [jsonp = false] add v1.3.0 to koa\n * @return {object} formatted argument\n */\nexport function createMutation(resolverName, payload, condition = {}, jsonp = false) {\n const _payload = {\n [PAYLOAD_PARAM_NAME]: payload,\n [CONDITION_PARAM_NAME]: condition\n }\n if (jsonp === true) {\n return _payload\n }\n if (isString(resolverName)) {\n return createDeliverable(resolverName, _payload)\n }\n throw new JsonqlValidationError(`[createMutation] expect resolverName to be string!`, { resolverName, payload, condition })\n}\n\n/**\n * string version of createMutation\n * @return {string}\n */\nexport function createMutationStr(resolverName, payload, condition = {}, jsonp = false) {\n return JSON.stringify(createMutation(resolverName, payload, condition, jsonp))\n}\n\n/**\n * Extract the parts from payload and format for use\n * @param {string} resolverName name of fn\n * @param {object} payload the incoming json\n * @return {object|boolean} false on failed\n */\nexport function getQueryFromArgs(resolverName, payload) {\n if (resolverName && isPlainObject(payload)) {\n const args = payload[resolverName]\n if (args[QUERY_ARG_NAME]) {\n return {\n [RESOLVER_PARAM_NAME]: resolverName,\n [QUERY_ARG_NAME]: args[QUERY_ARG_NAME],\n [TIMESTAMP_PARAM_NAME]: handleTimestamp(payload)\n }\n }\n }\n return false\n}\n\n/**\n * Share function so no repeat\n * @param {object} payload the payload from client\n * @param {function} processor the last get result method\n * @return {*} result processed result\n */\nfunction processPayload(payload, processor) {\n const p = toPayload(payload)\n const resolverName = getResolverFromPayload(p)\n return Reflect.apply(processor, null, [resolverName, p])\n}\n\n/**\n * extra the payload back\n * @param {*} payload from http call\n * @return {object} resolverName and args\n */\nexport function getQueryFromPayload(payload) {\n const result = processPayload(payload, getQueryFromArgs)\n if (result !== false) {\n return result\n }\n throw new JsonqlValidationError('[getQueryArgs] Payload is malformed!', payload)\n}\n\n/**\n * Further break down from method below for use else where\n * @param {string} resolverName name of fn\n * @param {object} payload payload\n * @return {object|boolean} false on failed\n */\nexport function getMutationFromArgs(resolverName, payload) {\n if (resolverName && isPlainObject(payload)) {\n const args = payload[resolverName]\n if (args) {\n return {\n [RESOLVER_PARAM_NAME]: resolverName,\n [PAYLOAD_PARAM_NAME]: args[PAYLOAD_PARAM_NAME],\n [CONDITION_PARAM_NAME]: args[CONDITION_PARAM_NAME],\n [TIMESTAMP_PARAM_NAME]: handleTimestamp(payload)\n }\n }\n }\n return false\n}\n\n/**\n * @param {object} payload\n * @return {object} resolverName, payload, conditon\n */\nexport function getMutationFromPayload(payload) {\n const result = processPayload(payload, getMutationFromArgs)\n\n if (result !== false) {\n return result\n }\n throw new JsonqlValidationError('[getMutationArgs] Payload is malformed!', payload)\n}\n","// take out all the namespace related methods in one place for easy to find\nimport {\n JSONQL_PATH,\n PUBLIC_KEY,\n NSP_GROUP,\n PUBLIC_NAMESPACE\n} from 'jsonql-constants'\nimport { extractSocketPart } from './contract'\nconst SOCKET_NOT_FOUND_ERR = `socket not found in contract!`\nconst SIZE = 'size'\n\n/**\n * create the group using publicNamespace when there is only public\n * @param {object} socket from contract\n * @param {string} publicNamespace\n */\nfunction groupPublicNamespace(socket, publicNamespace) {\n let g = {}\n for (let resolverName in socket) {\n let params = socket[resolverName]\n g[resolverName] = params\n }\n return { size: 1, nspGroup: {[publicNamespace]: g}, publicNamespace}\n}\n\n\n/**\n * @BUG we should check the socket part instead of expect the downstream to read the menu!\n * We only need this when the enableAuth is true otherwise there is only one namespace\n * @param {object} contract the socket part of the contract file\n * @return {object} 1. remap the contract using the namespace --> resolvers\n * 2. the size of the object (1 all private, 2 mixed public with private)\n * 3. which namespace is public\n */\nexport function groupByNamespace(contract) {\n let socket = extractSocketPart(contract)\n if (socket === false) {\n throw new JsonqlError('groupByNamespace', SOCKET_NOT_FOUND_ERR)\n }\n let prop = {\n [NSP_GROUP]: {},\n [PUBLIC_NAMESPACE]: null,\n [SIZE]: 0 \n }\n\n for (let resolverName in socket) {\n let params = socket[resolverName]\n let { namespace } = params\n if (namespace) {\n if (!prop[NSP_GROUP][namespace]) {\n ++prop[SIZE]\n prop[NSP_GROUP][namespace] = {}\n }\n prop[NSP_GROUP][namespace][resolverName] = params\n // get the public namespace\n if (!prop[PUBLIC_NAMESPACE] && params[PUBLIC_KEY]) {\n prop[PUBLIC_NAMESPACE] = namespace\n }\n }\n }\n \n return prop \n}\n\n/**\n * @NOTE ported from jsonql-ws-client\n * Got to make sure the connection order otherwise\n * it will hang\n * @param {object} nspGroup contract\n * @param {string} publicNamespace like the name said\n * @return {array} namespaces in order\n */\nexport function getNamespaceInOrder(nspGroup, publicNamespace) {\n let names = [] // need to make sure the order!\n for (let namespace in nspGroup) {\n if (namespace === publicNamespace) {\n names[1] = namespace\n } else {\n names[0] = namespace\n }\n }\n return names\n}\n\n/**\n * @TODO this might change, what if we want to do room with ws\n * 1. there will only be max two namespace\n * 2. when it's normal we will have the stock path as namespace\n * 3. when enableAuth then we will have two, one is jsonql/public + private\n * @param {object} config options\n * @return {array} of namespace(s)\n */\nexport function getNamespace(config) {\n const base = JSONQL_PATH\n if (config.enableAuth) {\n // the public come first @1.0.1 we use the constants instead of the user supplied value\n // @1.0.4 we use the config value again, because we could control this via the post init\n return [\n [ base , config.privateNamespace ].join('/'),\n [ base , config.publicNamespace ].join('/')\n ]\n }\n return [ base ]\n}\n\n/**\n * get the private namespace\n * @param {array} namespaces array\n * @return {*} string on success\n */\nexport function getPrivateNamespace(namespaces) {\n return namespaces.length > 1 ? namespaces[0] : false\n}\n\n/**\n * Got a problem with a contract that is public only the groupByNamespace is wrong\n * which is actually not a problem when using a fallback, but to be sure things in order\n * we could combine with the config to group it\n * @param {object} config configuration\n * @return {object} nspInfo object\n */\nexport function getNspInfoByConfig(config) {\n const { contract, enableAuth } = config\n const namespaces = getNamespace(config)\n let nspInfo = enableAuth ? groupByNamespace(contract)\n : groupPublicNamespace(contract.socket, namespaces[0])\n // add the namespaces into it as well\n return Object.assign(nspInfo, { namespaces })\n}\n\n","// There are the socket related methods ported back from \n// ws-server-core and ws-client-core \nimport {\n WS_REPLY_TYPE,\n WS_EVT_NAME,\n WS_DATA_NAME,\n TIMESTAMP_PARAM_NAME,\n ERROR_KEY,\n EMIT_REPLY_TYPE,\n ACKNOWLEDGE_REPLY_TYPE\n} from 'jsonql-constants'\nimport { JsonqlError } from 'jsonql-errors' \nimport isString from 'lodash-es/isString'\n\nimport { toJson, isObjectHasKey, nil } from './generic'\nimport { timestamp } from './timestamp'\n\nconst PAYLOAD_NOT_DECODED_ERR = 'payload can not decoded'\nconst WS_KEYS = [\n WS_REPLY_TYPE,\n WS_EVT_NAME,\n WS_DATA_NAME\n]\n\n/////////////////////////////////////\n// REPLY FROM SERVER //\n/////////////////////////////////////\n\n\n/**\n * The ws doesn't have a acknowledge callback like socket.io\n * so we have to DIY one for ws and other that doesn't have it\n * @param {string} type of reply\n * @param {string} resolverName which is replying\n * @param {*} data payload\n * @param {array} [ts= []] the last received ts, if any \n * @return {string} stringify json\n */\nexport const createWsReply = (type, resolverName, data, ts = []) => {\n ts.push(timestamp())\n return JSON.stringify({\n data: {\n [WS_REPLY_TYPE]: type,\n [WS_EVT_NAME]: resolverName,\n [WS_DATA_NAME]: toJson(data)\n },\n [TIMESTAMP_PARAM_NAME]: ts \n })\n}\n\n// extended function \nexport const createReplyMsg = (resolverName, data, ts = []) => (\n createWsReply(EMIT_REPLY_TYPE, resolverName, data, ts)\n)\n\nexport const createAcknowledgeMsg = (resolverName, data, ts = []) => (\n createWsReply(ACKNOWLEDGE_REPLY_TYPE, resolverName, data, ts)\n)\n\n/**\n * @param {string|object} payload should be string when reply but could be transformed\n * @return {boolean} true is OK\n */\nexport const isWsReply = payload => {\n const json = isString(payload) ? toJson(payload) : payload\n const { data } = json\n if (data) {\n let result = WS_KEYS.filter(key => isObjectHasKey(data, key))\n return (result.length === WS_KEYS.length) ? data : false\n }\n return false\n}\n\n/**\n * @param {string|object} data received data\n * @param {function} [cb=nil] this is for extracting the TS field or when it's error\n * @return {object} false on failed\n */\nexport const extractWsPayload = (payload, cb = nil) => {\n try {\n const json = toJson(payload)\n // now handle the data\n let _data\n if ((_data = isWsReply(json)) !== false) {\n // note the ts property is on its own \n cb(TIMESTAMP_PARAM_NAME, json[TIMESTAMP_PARAM_NAME])\n \n return {\n data: toJson(_data[WS_DATA_NAME]),\n resolverName: _data[WS_EVT_NAME],\n type: _data[WS_REPLY_TYPE]\n }\n }\n throw new JsonqlError(PAYLOAD_NOT_DECODED_ERR, payload)\n } catch(e) {\n return cb(ERROR_KEY, e)\n }\n}\n","// this will be part of the init client sequence\n// as soon as we create a ws client\n// we listen to the on.connect event \n// then we send a init-ping event back to the server\n// and server issue a csrf token back to use \n// we use this token to create a new client and destroy the old one\nimport {\n INTERCOM_RESOLVER_NAME, \n SOCKET_PING_EVENT_NAME,\n HEADERS_KEY,\n DATA_KEY,\n CSRF_HEADER_KEY\n} from 'jsonql-constants'\nimport { \n createQueryStr, \n extractWsPayload,\n timestamp,\n toJson \n} from 'jsonql-utils/module'\nimport {\n JsonqlError\n} from 'jsonql-errors'\nconst CSRF_HEADER_NOT_EXIST_ERR = 'CSRF header is not in the received payload'\n\n/**\n * Util method \n * @param {string} payload return from server\n * @return {object} the useful bit \n */\nfunction extractSrvPayload(payload) {\n let json = toJson(payload)\n \n if (json && typeof json === 'object') {\n // note this method expect the json.data inside\n return extractWsPayload(json)\n }\n \n throw new JsonqlError('extractSrvPayload', json)\n}\n\n/**\n * call the server to get a csrf token \n * @return {string} formatted payload to send to the server \n */\nfunction createInitPing() {\n const ts = timestamp()\n\n return createQueryStr(INTERCOM_RESOLVER_NAME, [SOCKET_PING_EVENT_NAME, ts])\n}\n\n/**\n * Take the raw on.message result back then decoded it \n * @param {*} payload the raw result from server\n * @return {object} the csrf payload\n */\nfunction extractPingResult(payload) {\n const result = extractSrvPayload(payload)\n \n if (result && result[DATA_KEY] && result[DATA_KEY][CSRF_HEADER_KEY]) {\n return {\n [HEADERS_KEY]: result[DATA_KEY]\n }\n }\n\n throw new JsonqlError('extractPingResult', CSRF_HEADER_NOT_EXIST_ERR)\n}\n\n\n/**\n * Create a generic intercom method\n * @param {string} type the event type \n * @param {array} args if any \n * @return {string} formatted payload to send\n */\nfunction createIntercomPayload(type, ...args) {\n const ts = timestamp()\n let payload = [type].concat(args)\n payload.push(ts)\n return createQueryStr(INTERCOM_RESOLVER_NAME, payload)\n}\n\n\nexport { \n extractSrvPayload,\n createInitPing, \n extractPingResult, \n createIntercomPayload \n}","// validator numbers\n// import { NUMBER_TYPES } from './constants';\n\nimport isNaN from 'lodash-es/isNaN'\nimport isString from 'lodash-es/isString'\n/**\n * @2015-05-04 found a problem if the value is a number like string\n * it will pass, so add a chck if it's string before we pass to next\n * @param {number} value expected value\n * @return {boolean} true if OK\n */\nconst checkIsNumber = function(value) {\n return isString(value) ? false : !isNaN( parseFloat(value) )\n}\n\nexport default checkIsNumber\n","// validate string type\nimport trim from 'lodash-es/trim'\nimport isString from 'lodash-es/isString'\n/**\n * @param {string} value expected value\n * @return {boolean} true if OK\n */\nconst checkIsString = function(value) {\n return (trim(value) !== '') ? isString(value) : false\n}\n\nexport default checkIsString\n","// check for boolean\n\n/**\n * @param {boolean} value expected\n * @return {boolean} true if OK\n */\nconst checkIsBoolean = function(value) {\n return value !== null && value !== undefined && typeof value === 'boolean'\n}\n\nexport default checkIsBoolean\n","// validate any thing only check if there is something\n\nimport trim from 'lodash-es/trim'\n\n/**\n * @param {*} value the value\n * @param {boolean} [checkNull=true] strict check if there is null value\n * @return {boolean} true is OK\n */\nconst checkIsAny = function(value, checkNull = true) {\n if (value !== undefined && value !== '' && trim(value) !== '') {\n if (checkNull === false || (checkNull === true && value !== null)) {\n return true;\n }\n }\n return false;\n}\n\nexport default checkIsAny\n","// Good practice rule - No magic number\n\nconst ARGS_NOT_ARRAY_ERR = `args is not an array! You might want to do: ES6 Array.from(arguments) or ES5 Array.prototype.slice.call(arguments)`\nconst PARAMS_NOT_ARRAY_ERR = `params is not an array! Did something gone wrong when you generate the contract.json?`\nconst EXCEPTION_CASE_ERR = 'Could not understand your arguments and parameter structure!'\nconst UNUSUAL_CASE_ERR = 'This is an unusual situation where the arguments are more than the params, but not mark as spread'\n\nconst RETURNS_NAME = 'returns'\n\nimport {\n \n DEFAULT_TYPE, // this is a mistake should move back to the validation\n DATA_KEY, \n ERROR_KEY,\n\n TYPE_KEY,\n OPTIONAL_KEY,\n ENUM_KEY,\n ARGS_KEY,\n CHECKER_KEY,\n ALIAS_KEY,\n\n ARRAY_TYPE_LFT,\n ARRAY_TYPE_RGT,\n \n ARRAY_TYPE,\n OBJECT_TYPE,\n STRING_TYPE,\n BOOLEAN_TYPE,\n NUMBER_TYPE,\n KEY_WORD,\n OR_SEPERATOR\n} from 'jsonql-constants'\n\n// group all export in one \nexport {\n ARGS_NOT_ARRAY_ERR,\n PARAMS_NOT_ARRAY_ERR,\n EXCEPTION_CASE_ERR,\n UNUSUAL_CASE_ERR,\n DEFAULT_TYPE,\n ARRAY_TYPE_LFT,\n ARRAY_TYPE_RGT,\n TYPE_KEY,\n OPTIONAL_KEY,\n ENUM_KEY,\n ARGS_KEY,\n CHECKER_KEY,\n ALIAS_KEY,\n ARRAY_TYPE,\n OBJECT_TYPE,\n STRING_TYPE,\n BOOLEAN_TYPE,\n NUMBER_TYPE,\n KEY_WORD,\n OR_SEPERATOR,\n\n RETURNS_NAME,\n\n DATA_KEY, \n ERROR_KEY \n}","// primitive types\nimport checkIsNumber from './number'\nimport checkIsString from './string'\nimport checkIsBoolean from './boolean'\nimport checkIsAny from './any'\nimport { NUMBER_TYPE, STRING_TYPE, BOOLEAN_TYPE } from './constants'\n\n/**\n * this is a wrapper method to call different one based on their type\n * @param {string} type to check\n * @return {function} a function to handle the type\n */\nconst combineFn = function(type) {\n switch (type) {\n case NUMBER_TYPE:\n return checkIsNumber\n case STRING_TYPE:\n return checkIsString\n case BOOLEAN_TYPE:\n return checkIsBoolean\n default:\n return checkIsAny\n }\n}\n\nexport default combineFn\n","// validate array type\n\nimport isArray from 'lodash-es/isArray'\nimport trim from 'lodash-es/trim'\nimport combineFn from './combine'\nimport {\n ARRAY_TYPE_LFT,\n ARRAY_TYPE_RGT,\n OR_SEPERATOR\n} from './constants'\n\n/**\n * @param {array} value expected\n * @param {string} [type=''] pass the type if we encounter array. then we need to check the value as well\n * @return {boolean} true if OK\n */\nexport const checkIsArray = function(value, type='') {\n if (isArray(value)) {\n if (type === '' || trim(type)==='') {\n return true;\n }\n // we test it in reverse\n // @TODO if the type is an array (OR) then what?\n // we need to take into account this could be an array\n const c = value.filter(v => !combineFn(type)(v))\n return !(c.length > 0)\n }\n return false\n}\n\n/**\n * check if it matches the array. pattern\n * @param {string} type\n * @return {boolean|array} false means NO, always return array\n */\nexport const isArrayLike = function(type) {\n // @TODO could that have something like array<> instead of array.<>? missing the dot?\n // because type script is Array without the dot\n if (type.indexOf(ARRAY_TYPE_LFT) > -1 && type.indexOf(ARRAY_TYPE_RGT) > -1) {\n const _type = type.replace(ARRAY_TYPE_LFT, '').replace(ARRAY_TYPE_RGT, '')\n if (_type.indexOf(OR_SEPERATOR)) {\n return _type.split(OR_SEPERATOR)\n }\n return [_type]\n }\n return false\n}\n\n/**\n * we might encounter something like array. then we need to take it apart\n * @param {object} p the prepared object for processing\n * @param {string|array} type the type came from \n * @return {boolean} for the filter to operate on\n */\nexport const arrayTypeHandler = function(p, type) {\n const { arg } = p\n // need a special case to handle the OR type\n // we need to test the args instead of the type(s)\n if (type.length > 1) {\n return !arg.filter(v => (\n !(type.length > type.filter(t => !combineFn(t)(v)).length)\n )).length\n }\n // type is array so this will be or!\n return type.length > type.filter(t => !checkIsArray(arg, t)).length\n}\n","// validate object type\n\nimport isPlainObject from 'lodash-es/isPlainObject'\n// import filter from 'lodash-es/filter'\nimport combineFn from './combine'\nimport { checkIsArray, isArrayLike, arrayTypeHandler } from './array'\n/**\n * @TODO if provide with the keys then we need to check if the key:value type as well\n * @param {object} value expected\n * @param {array} [keys=null] if it has the keys array to compare as well\n * @return {boolean} true if OK\n */\nexport const checkIsObject = function(value, keys=null) {\n if (isPlainObject(value)) {\n if (!keys) {\n return true\n }\n if (checkIsArray(keys)) {\n // please note we DON'T care if some is optional\n // plese refer to the contract.json for the keys\n return !keys.filter(key => {\n let _value = value[key.name];\n return !(key.type.length > key.type.filter(type => {\n let tmp;\n if (_value !== undefined) {\n if ((tmp = isArrayLike(type)) !== false) {\n return !arrayTypeHandler({arg: _value}, tmp)\n // return tmp.filter(t => !checkIsArray(_value, t)).length;\n // @TODO there might be an object within an object with keys as well :S\n }\n return !combineFn(type)(_value)\n }\n return true\n }).length)\n }).length;\n }\n }\n return false\n}\n\n/**\n * fold this into it's own function to handler different object type\n * @param {object} p the prepared object for process\n * @return {boolean}\n */\nexport const objectTypeHandler = function(p) {\n const { arg, param } = p\n let _args = [arg]\n if (Array.isArray(param.keys) && param.keys.length) {\n _args.push(param.keys)\n }\n // just simple check\n return Reflect.apply(checkIsObject, null, _args)\n}\n","// move the index.js code here that make more sense to find where things are\n\nimport {\n checkIsArray,\n isArrayLike,\n arrayTypeHandler,\n objectTypeHandler,\n combineFn,\n notEmpty\n} from './index'\n\nimport {\n DEFAULT_TYPE,\n ARRAY_TYPE,\n OBJECT_TYPE,\n ARGS_NOT_ARRAY_ERR,\n PARAMS_NOT_ARRAY_ERR,\n EXCEPTION_CASE_ERR,\n DATA_KEY, \n ERROR_KEY \n} from './constants'\n\n\nimport JsonqlValidationError from 'jsonql-errors/src/validation-error'\nimport JsonqlError from 'jsonql-errors/src/error'\n// import debug from 'debug'\n// const debugFn = debug('jsonql-params-validator:validator')\n// also export this for use in other places\n\n/**\n * We need to handle those optional parameter without a default value\n * @param {object} params from contract.json\n * @return {boolean} for filter operation false is actually OK\n */\nconst optionalHandler = function( params ) {\n const { arg, param } = params\n if (notEmpty(arg)) {\n // debug('call optional handler', arg, params);\n // loop through the type in param\n return !(param.type.length > param.type.filter(type =>\n validateHandler(type, params)\n ).length)\n }\n return false\n}\n\n/**\n * actually picking the validator\n * @param {*} type for checking\n * @param {*} value for checking\n * @return {boolean} true on OK\n */\nconst validateHandler = function(type, value) {\n let tmp;\n switch (true) {\n case type === OBJECT_TYPE:\n // debugFn('call OBJECT_TYPE')\n return !objectTypeHandler(value)\n case type === ARRAY_TYPE:\n // debugFn('call ARRAY_TYPE')\n return !checkIsArray(value.arg)\n // @TODO when the type is not present, it always fall through here\n // so we need to find a way to actually pre-check the type first\n // AKA check the contract.json map before running here\n case (tmp = isArrayLike(type)) !== false:\n // debugFn('call ARRAY_LIKE: %O', value)\n return !arrayTypeHandler(value, tmp)\n default:\n return !combineFn(type)(value.arg)\n }\n}\n\n/**\n * it get too longer to fit in one line so break it out from the fn below\n * @param {*} arg value\n * @param {object} param config\n * @return {*} value or apply default value\n */\nconst getOptionalValue = function(arg, param) {\n if (arg !== undefined) {\n return arg\n }\n return (param.optional === true && param.defaultvalue !== undefined ? param.defaultvalue : null)\n}\n\n/**\n * padding the arguments with defaultValue if the arguments did not provide the value\n * this will be the name export\n * @param {array} args normalized arguments\n * @param {array} params from contract.json\n * @return {array} merge the two together\n */\nexport const normalizeArgs = function(args, params) {\n // first we should check if this call require a validation at all\n // there will be situation where the function doesn't need args and params\n if (!checkIsArray(params)) {\n // debugFn('params value', params)\n throw new JsonqlValidationError(PARAMS_NOT_ARRAY_ERR)\n }\n if (params.length === 0) {\n return []\n }\n if (!checkIsArray(args)) {\n throw new JsonqlValidationError(ARGS_NOT_ARRAY_ERR)\n }\n // debugFn(args, params);\n // fall through switch\n switch(true) {\n case args.length == params.length: // standard\n return args.map((arg, i) => (\n {\n arg,\n index: i,\n param: params[i]\n }\n ))\n case params[0].variable === true: // using spread syntax\n const type = params[0].type;\n return args.map((arg, i) => (\n {\n arg,\n index: i, // keep the index for reference\n param: params[i] || { type, name: '_' }\n }\n ))\n // with optional defaultValue parameters\n case args.length < params.length:\n return params.map((param, i) => (\n {\n param,\n index: i,\n arg: getOptionalValue(args[i], param),\n optional: param.optional || false\n }\n ))\n // this one pass more than it should have anything after the args.length will be cast as any type\n case args.length > params.length:\n let ctn = params.length;\n // this happens when we have those array. type\n let _type = [ DEFAULT_TYPE ]\n // we only looking at the first one, this might be a @BUG\n /*\n if ((tmp = isArrayLike(params[0].type[0])) !== false) {\n _type = tmp;\n } */\n // if we use the params as guide then the rest will get throw out\n // which is not what we want, instead, anything without the param\n // will get a any type and optional flag\n return args.map((arg, i) => {\n let optional = i >= ctn ? true : !!params[i].optional\n let param = params[i] || { type: _type, name: `_${i}` }\n return {\n arg: optional ? getOptionalValue(arg, param) : arg,\n index: i,\n param,\n optional\n }\n })\n // @TODO find out if there is more cases not cover\n default: // this should never happen\n // debugFn('args', args)\n // debugFn('params', params)\n // this is unknown therefore we just throw it!\n throw new JsonqlError(EXCEPTION_CASE_ERR, { args, params })\n }\n}\n\n// what we want is after the validaton we also get the normalized result\n// which is with the optional property if the argument didn't provide it\n/**\n * process the array of params back to their arguments\n * @param {array} result the params result\n * @return {array} arguments\n */\nconst processReturn = result => result.map(r => r.arg)\n\n/**\n * validator main interface\n * @param {array} args the arguments pass to the method call\n * @param {array} params from the contract for that method\n * @param {boolean} [withResul=false] if true then this will return the normalize result as well\n * @return {array} empty array on success, or failed parameter and reasons\n */\nexport const validateSync = function(args, params, withResult = false) {\n let cleanArgs = normalizeArgs(args, params)\n let checkResult = cleanArgs.filter(p => {\n // v1.4.4 this fixed the problem, the root level optional is from the last fn\n if (p.optional === true || p.param.optional === true) {\n return optionalHandler(p)\n }\n // because array of types means OR so if one pass means pass\n return !(p.param.type.length > p.param.type.filter(\n type => validateHandler(type, p)\n ).length)\n })\n // using the same convention we been using all this time\n return !withResult ? checkResult : {\n [ERROR_KEY]: checkResult,\n [DATA_KEY]: processReturn(cleanArgs)\n }\n}\n\n/**\n * A wrapper method that return promise\n * @param {array} args arguments\n * @param {array} params from contract.json\n * @param {boolean} [withResul=false] if true then this will return the normalize result as well\n * @return {object} promise.then or catch\n */\nexport const validateAsync = function(args, params, withResult = false) {\n return new Promise((resolver, rejecter) => {\n const result = validateSync(args, params, withResult)\n if (withResult) {\n return result[ERROR_KEY].length ? rejecter(result[ERROR_KEY])\n : resolver(result[DATA_KEY])\n }\n // the different is just in the then or catch phrase\n return result.length ? rejecter(result) : resolver([])\n })\n}\n","/** Used to stand-in for `undefined` hash values. */\nvar HASH_UNDEFINED = '__lodash_hash_undefined__';\n\n/**\n * Adds `value` to the array cache.\n *\n * @private\n * @name add\n * @memberOf SetCache\n * @alias push\n * @param {*} value The value to cache.\n * @returns {Object} Returns the cache instance.\n */\nfunction setCacheAdd(value) {\n this.__data__.set(value, HASH_UNDEFINED);\n return this;\n}\n\nexport default setCacheAdd;\n","/**\n * Checks if `value` is in the array cache.\n *\n * @private\n * @name has\n * @memberOf SetCache\n * @param {*} value The value to search for.\n * @returns {number} Returns `true` if `value` is found, else `false`.\n */\nfunction setCacheHas(value) {\n return this.__data__.has(value);\n}\n\nexport default setCacheHas;\n","/**\n * A specialized version of `_.some` for arrays without support for iteratee\n * shorthands.\n *\n * @private\n * @param {Array} [array] The array to iterate over.\n * @param {Function} predicate The function invoked per iteration.\n * @returns {boolean} Returns `true` if any element passes the predicate check,\n * else `false`.\n */\nfunction arraySome(array, predicate) {\n var index = -1,\n length = array == null ? 0 : array.length;\n\n while (++index < length) {\n if (predicate(array[index], index, array)) {\n return true;\n }\n }\n return false;\n}\n\nexport default arraySome;\n","/**\n * Checks if a `cache` value for `key` exists.\n *\n * @private\n * @param {Object} cache The cache to query.\n * @param {string} key The key of the entry to check.\n * @returns {boolean} Returns `true` if an entry for `key` exists, else `false`.\n */\nfunction cacheHas(cache, key) {\n return cache.has(key);\n}\n\nexport default cacheHas;\n","/**\n * Converts `map` to its key-value pairs.\n *\n * @private\n * @param {Object} map The map to convert.\n * @returns {Array} Returns the key-value pairs.\n */\nfunction mapToArray(map) {\n var index = -1,\n result = Array(map.size);\n\n map.forEach(function(value, key) {\n result[++index] = [key, value];\n });\n return result;\n}\n\nexport default mapToArray;\n","/**\n * Converts `set` to an array of its values.\n *\n * @private\n * @param {Object} set The set to convert.\n * @returns {Array} Returns the values.\n */\nfunction setToArray(set) {\n var index = -1,\n result = Array(set.size);\n\n set.forEach(function(value) {\n result[++index] = value;\n });\n return result;\n}\n\nexport default setToArray;\n","/**\n * Appends the elements of `values` to `array`.\n *\n * @private\n * @param {Array} array The array to modify.\n * @param {Array} values The values to append.\n * @returns {Array} Returns `array`.\n */\nfunction arrayPush(array, values) {\n var index = -1,\n length = values.length,\n offset = array.length;\n\n while (++index < length) {\n array[offset + index] = values[index];\n }\n return array;\n}\n\nexport default arrayPush;\n","/**\n * A specialized version of `_.filter` for arrays without support for\n * iteratee shorthands.\n *\n * @private\n * @param {Array} [array] The array to iterate over.\n * @param {Function} predicate The function invoked per iteration.\n * @returns {Array} Returns the new filtered array.\n */\nfunction arrayFilter(array, predicate) {\n var index = -1,\n length = array == null ? 0 : array.length,\n resIndex = 0,\n result = [];\n\n while (++index < length) {\n var value = array[index];\n if (predicate(value, index, array)) {\n result[resIndex++] = value;\n }\n }\n return result;\n}\n\nexport default arrayFilter;\n","/**\n * This method returns a new empty array.\n *\n * @static\n * @memberOf _\n * @since 4.13.0\n * @category Util\n * @returns {Array} Returns the new empty array.\n * @example\n *\n * var arrays = _.times(2, _.stubArray);\n *\n * console.log(arrays);\n * // => [[], []]\n *\n * console.log(arrays[0] === arrays[1]);\n * // => false\n */\nfunction stubArray() {\n return [];\n}\n\nexport default stubArray;\n","/**\n * A specialized version of `matchesProperty` for source values suitable\n * for strict equality comparisons, i.e. `===`.\n *\n * @private\n * @param {string} key The key of the property to get.\n * @param {*} srcValue The value to match.\n * @returns {Function} Returns the new spec function.\n */\nfunction matchesStrictComparable(key, srcValue) {\n return function(object) {\n if (object == null) {\n return false;\n }\n return object[key] === srcValue &&\n (srcValue !== undefined || (key in Object(object)));\n };\n}\n\nexport default matchesStrictComparable;\n","/**\n * The base implementation of `_.hasIn` without support for deep paths.\n *\n * @private\n * @param {Object} [object] The object to query.\n * @param {Array|string} key The key to check.\n * @returns {boolean} Returns `true` if `key` exists, else `false`.\n */\nfunction baseHasIn(object, key) {\n return object != null && key in Object(object);\n}\n\nexport default baseHasIn;\n","/**\n * The base implementation of `_.property` without support for deep paths.\n *\n * @private\n * @param {string} key The key of the property to get.\n * @returns {Function} Returns the new accessor function.\n */\nfunction baseProperty(key) {\n return function(object) {\n return object == null ? undefined : object[key];\n };\n}\n\nexport default baseProperty;\n","/** Error message constants. */\nvar FUNC_ERROR_TEXT = 'Expected a function';\n\n/**\n * Creates a function that negates the result of the predicate `func`. The\n * `func` predicate is invoked with the `this` binding and arguments of the\n * created function.\n *\n * @static\n * @memberOf _\n * @since 3.0.0\n * @category Function\n * @param {Function} predicate The predicate to negate.\n * @returns {Function} Returns the new negated function.\n * @example\n *\n * function isEven(n) {\n * return n % 2 == 0;\n * }\n *\n * _.filter([1, 2, 3, 4, 5, 6], _.negate(isEven));\n * // => [1, 3, 5]\n */\nfunction negate(predicate) {\n if (typeof predicate != 'function') {\n throw new TypeError(FUNC_ERROR_TEXT);\n }\n return function() {\n var args = arguments;\n switch (args.length) {\n case 0: return !predicate.call(this);\n case 1: return !predicate.call(this, args[0]);\n case 2: return !predicate.call(this, args[0], args[1]);\n case 3: return !predicate.call(this, args[0], args[1], args[2]);\n }\n return !predicate.apply(this, args);\n };\n}\n\nexport default negate;\n","/**\n * The base implementation of methods like `_.findKey` and `_.findLastKey`,\n * without support for iteratee shorthands, which iterates over `collection`\n * using `eachFunc`.\n *\n * @private\n * @param {Array|Object} collection The collection to inspect.\n * @param {Function} predicate The function invoked per iteration.\n * @param {Function} eachFunc The function to iterate over `collection`.\n * @returns {*} Returns the found element or its key, else `undefined`.\n */\nfunction baseFindKey(collection, predicate, eachFunc) {\n var result;\n eachFunc(collection, function(value, key, collection) {\n if (predicate(value, key, collection)) {\n result = key;\n return false;\n }\n });\n return result;\n}\n\nexport default baseFindKey;\n","/**\n * @param {array} arr Array for check\n * @param {*} value target\n * @return {boolean} true on successs\n */\nconst isInArray = function(arr, value) {\n return !!arr.filter(a => a === value).length\n}\n\nexport default isInArray\n","// breaking the whole thing up to see what cause the multiple calls issue\n\nimport isFunction from 'lodash-es/isFunction'\nimport merge from 'lodash-es/merge'\nimport mapValues from 'lodash-es/mapValues'\n\nimport JsonqlEnumError from 'jsonql-errors/src/enum-error'\nimport JsonqlTypeError from 'jsonql-errors/src/type-error'\nimport JsonqlCheckerError from 'jsonql-errors/src/checker-error'\n\nimport {\n TYPE_KEY,\n OPTIONAL_KEY,\n ENUM_KEY,\n ARGS_KEY,\n CHECKER_KEY,\n KEY_WORD\n} from '../constants'\nimport { checkIsArray } from '../array'\n\n// import debug from 'debug';\n// const debugFn = debug('jsonql-params-validator:options:validation')\n\n/**\n * just make sure it returns an array to use\n * @param {*} arg input\n * @return {array} output\n */\nconst toArray = arg => checkIsArray(arg) ? arg : [arg]\n\n/**\n * DIY in array\n * @param {array} arr to check against\n * @param {*} value to check\n * @return {boolean} true on OK\n */\nconst inArray = (arr, value) => (\n !!arr.filter(v => v === value).length\n)\n\n/**\n * break out to make the code easier to read\n * @param {object} value to process\n * @param {function} cb the validateSync\n * @return {array} empty on success\n */\nfunction validateHandler(value, cb) {\n // cb is the validateSync methods\n let args = [\n [ value[ARGS_KEY] ],\n [{\n [TYPE_KEY]: toArray(value[TYPE_KEY]),\n [OPTIONAL_KEY]: value[OPTIONAL_KEY]\n }]\n ]\n // debugFn('validateHandler', args)\n return Reflect.apply(cb, null, args)\n}\n\n/**\n * Check against the enum value if it's provided\n * @param {*} value to check\n * @param {*} enumv to check against if it's not false\n * @return {boolean} true on OK\n */\nconst enumHandler = (value, enumv) => {\n if (checkIsArray(enumv)) {\n return inArray(enumv, value)\n }\n return true\n}\n\n/**\n * Allow passing a function to check the value\n * There might be a problem here if the function is incorrect\n * and that will makes it hard to debug what is going on inside\n * @TODO there could be a few feature add to this one under different circumstance\n * @param {*} value to check\n * @param {function} checker for checking\n */\nconst checkerHandler = (value, checker) => {\n try {\n return isFunction(checker) ? checker.apply(null, [value]) : false\n } catch (e) {\n return false\n }\n}\n\n/**\n * Taken out from the runValidaton this only validate the required values\n * @param {array} args from the config2argsAction\n * @param {function} cb validateSync\n * @return {array} of configuration values\n */\nfunction runValidationAction(cb) {\n return (value, key) => {\n // debugFn('runValidationAction', key, value)\n if (value[KEY_WORD]) {\n return value[ARGS_KEY]\n }\n const check = validateHandler(value, cb)\n if (check.length) {\n // log('runValidationAction', key, value)\n throw new JsonqlTypeError(key, check)\n }\n if (value[ENUM_KEY] !== false && !enumHandler(value[ARGS_KEY], value[ENUM_KEY])) {\n // log(ENUM_KEY, value[ENUM_KEY])\n throw new JsonqlEnumError(key)\n }\n if (value[CHECKER_KEY] !== false && !checkerHandler(value[ARGS_KEY], value[CHECKER_KEY])) {\n // log(CHECKER_KEY, value[CHECKER_KEY])\n throw new JsonqlCheckerError(key)\n }\n return value[ARGS_KEY]\n }\n}\n\n/**\n * @param {object} args from the config2argsAction\n * @param {function} cb validateSync\n * @return {object} of configuration values\n */\nexport default function runValidation(args, cb) {\n const [ argsForValidate, pristineValues ] = args\n // turn the thing into an array and see what happen here\n // debugFn('_args', argsForValidate)\n const result = mapValues(argsForValidate, runValidationAction(cb))\n return merge(result, pristineValues)\n}\n","/// this is port back from the client to share across all projects\n\nimport merge from 'lodash-es/merge'\nimport { prepareArgsForValidation } from './prepare-args-for-validation'\nimport runValidation from './run-validation'\n\n// import debug from 'debug'\n// const debugFn = debug('jsonql-params-validator:check-options-async')\n\n/**\n * Quick transform\n * @param {object} config that one\n * @param {object} appProps mutation configuration options\n * @return {object} put that arg into the args\n */\nconst configToArgs = (config, appProps) => {\n return Promise.resolve(\n prepareArgsForValidation(config, appProps)\n )\n}\n\n/**\n * @param {object} config user provide configuration option\n * @param {object} appProps mutation configuration options\n * @param {object} constProps the immutable configuration options\n * @param {function} cb the validateSync method\n * @return {object} Promise resolve merge config object\n */\nexport default function(config = {}, appProps, constProps, cb) {\n return configToArgs(config, appProps)\n .then(args1 => runValidation(args1, cb))\n // next if every thing good then pass to final merging\n .then(args2 => merge({}, args2, constProps))\n}\n","// create function to construct the config entry so we don't need to keep building object\n\nimport isFunction from 'lodash-es/isFunction'\nimport isString from 'lodash-es/isString'\nimport {\n ARGS_KEY,\n TYPE_KEY,\n CHECKER_KEY,\n ENUM_KEY,\n OPTIONAL_KEY,\n ALIAS_KEY\n} from 'jsonql-constants'\n\nimport { checkIsArray } from '../array'\n// import checkIsBoolean from '../boolean'\n// import debug from 'debug';\n// const debugFn = debug('jsonql-params-validator:construct-config');\n/**\n * @param {*} args value\n * @param {string} type for value\n * @param {boolean} [optional=false]\n * @param {boolean|array} [enumv=false]\n * @param {boolean|function} [checker=false]\n * @return {object} config entry\n */\nexport default function constructConfig(args, type, optional=false, enumv=false, checker=false, alias=false) {\n let base = {\n [ARGS_KEY]: args,\n [TYPE_KEY]: type\n }\n if (optional === true) {\n base[OPTIONAL_KEY] = true\n }\n if (checkIsArray(enumv)) {\n base[ENUM_KEY] = enumv\n }\n if (isFunction(checker)) {\n base[CHECKER_KEY] = checker\n }\n if (isString(alias)) {\n base[ALIAS_KEY] = alias\n }\n return base\n}\n","// export also create wrapper methods\nimport checkOptionsAsync from './check-options-async'\nimport checkOptionsSync from './check-options-sync'\nimport constructConfigFn from './construct-config'\nimport {\n ENUM_KEY,\n CHECKER_KEY,\n ALIAS_KEY,\n OPTIONAL_KEY\n} from 'jsonql-constants'\n\n/**\n * This has a different interface\n * @param {*} value to supply\n * @param {string|array} type for checking\n * @param {object} params to map against the config check\n * @param {array} params.enumv NOT enum\n * @param {boolean} params.optional false then nothing\n * @param {function} params.checker need more work on this one later\n * @param {string} params.alias mostly for cmd\n */\nconst createConfig = (value, type, params = {}) => {\n // Note the enumv not ENUM\n // const { enumv, optional, checker, alias } = params;\n // let args = [value, type, optional, enumv, checker, alias];\n const {\n [OPTIONAL_KEY]: o,\n [ENUM_KEY]: e,\n [CHECKER_KEY]: c,\n [ALIAS_KEY]: a\n } = params;\n return constructConfigFn.apply(null, [value, type, o, e, c, a])\n}\n\n// for testing purpose\nconst JSONQL_PARAMS_VALIDATOR_INFO = '__PLACEHOLDER__'\n\n/**\n * construct the actual end user method, rename with prefix get since 1.5.2\n * @param {function} validateSync validation method\n * @return {function} for performaning the actual valdiation\n */\nconst getCheckConfigAsync = function(validateSync) {\n /**\n * We recreate the method here to avoid the circlar import\n * @param {object} config user supply configuration\n * @param {object} appProps mutation options\n * @param {object} [constantProps={}] optional: immutation options\n * @return {object} all checked configuration\n */\n return function(config, appProps, constantProps= {}) {\n return checkOptionsAsync(config, appProps, constantProps, validateSync)\n }\n}\n\n/**\n * copy of above but it's sync, rename with prefix get since 1.5.2\n * @param {function} validateSync validation method\n * @return {function} for performaning the actual valdiation\n */\nconst getCheckConfig = function(validateSync) {\n return function(config, appProps, constantProps = {}) {\n return checkOptionsSync(config, appProps, constantProps, validateSync)\n }\n}\n\n// re-export\nexport {\n createConfig,\n constructConfigFn,\n getCheckConfigAsync,\n getCheckConfig,\n JSONQL_PARAMS_VALIDATOR_INFO\n}\n","// export\nimport {\n checkIsObject,\n notEmpty,\n checkIsAny,\n checkIsString,\n checkIsBoolean,\n checkIsNumber,\n checkIsArray\n} from './src'\nimport * as validator from './src/validator'\n// configuration checking\nimport * as jsonqlOptions from './src/options'\n// the two extra functions\nimport isInArray from './src/is-in-array'\nimport isObjectHasKeyFn from './src/is-key-in-object'\n\nconst isObject = checkIsObject\nconst isAny = checkIsAny\nconst isString = checkIsString\nconst isBoolean = checkIsBoolean\nconst isNumber = checkIsNumber\nconst isArray = checkIsArray\nconst isNotEmpty = notEmpty\n\nconst normalizeArgs = validator.normalizeArgs\nconst validateSync = validator.validateSync\nconst validateAsync = validator.validateAsync\n\nconst JSONQL_PARAMS_VALIDATOR_INFO = jsonqlOptions.JSONQL_PARAMS_VALIDATOR_INFO\n\nconst createConfig = jsonqlOptions.createConfig\nconst constructConfig = jsonqlOptions.constructConfigFn\n// construct the final output 1.5.2\nconst checkConfigAsync = jsonqlOptions.getCheckConfigAsync(validator.validateSync)\nconst checkConfig = jsonqlOptions.getCheckConfig(validator.validateSync)\n\nconst inArray = isInArray\nconst isObjectHasKey = isObjectHasKeyFn\n\n// check returns methods \nimport { \n checkReturns, \n checkReturnsAsync, \n checkResolverReturns, \n checkResolverReturnsAsync \n} from './src/returns'\n\n\n// group the in one \nexport {\n JSONQL_PARAMS_VALIDATOR_INFO,\n \n isObject,\n isAny,\n isString,\n isBoolean,\n isNumber,\n isArray,\n isNotEmpty,\n \n inArray,\n isObjectHasKey,\n\n normalizeArgs,\n validateSync,\n validateAsync,\n\n createConfig,\n constructConfig,\n checkConfig,\n checkConfigAsync,\n\n checkReturns, \n checkReturnsAsync, \n checkResolverReturns, \n checkResolverReturnsAsync\n}\n\n\n\n\n\n","// move the get logger stuff here\n\n// it does nothing\nconst dummyLogger = () => {}\n\n/**\n * re-use the debugOn prop to control this log method\n * @param {object} opts configuration\n * @return {function} the log function\n */\nconst getLogger = (opts) => {\n const { debugOn } = opts \n if (debugOn) {\n return (...args) => {\n Reflect.apply(console.info, console, ['[jsonql-ws-client-core]', ...args])\n }\n }\n return dummyLogger\n}\n\n/**\n * Make sure there is a log method\n * @param {object} opts configuration\n * @return {object} opts\n */\nconst getLogFn = opts => {\n const { log } = opts // 1.3.9 if we pass a log method here then we use this\n if (!log || typeof log !== 'function') {\n return getLogger(opts)\n }\n opts.log('---> getLogFn user supplied log function <---', opts)\n return log\n}\n\nexport { getLogFn }","// group all the repetitive message here\n\nexport const TAKEN_BY_OTHER_TYPE_ERR = 'You are trying to register an event already been taken by other type:'\n","// Create two WeakMap store as a private keys\nexport const NB_EVENT_SERVICE_PRIVATE_STORE = new WeakMap()\nexport const NB_EVENT_SERVICE_PRIVATE_LAZY = new WeakMap()\n","/**\n * generate a 32bit hash based on the function.toString()\n * _from http://stackoverflow.com/questions/7616461/generate-a-hash-_from-string-in-javascript-jquery\n * @param {string} s the converted to string function\n * @return {string} the hashed function string\n */\nexport function hashCode(s) {\n\treturn s.split(\"\").reduce(function(a,b){a=((a<<5)-a)+b.charCodeAt(0);return a&a},0)\n}\n\n/**\n * wrapper to make sure it string\n * @param {*} input whatever\n * @return {string} output\n */\nexport function hashCode2Str(s) {\n return hashCode(s) + ''\n}\n\n/**\n * Just check if a pattern is an RegExp object\n * @param {*} pat whatever\n * @return {boolean} false when its not\n */\nexport function isRegExp(pat) {\n return pat instanceof RegExp\n}\n\n/**\n * check if its string\n * @param {*} arg whatever\n * @return {boolean} false when it's not\n */\nexport function isString(arg) {\n return typeof arg === 'string'\n}\n\n/**\n * Find from the array by matching the pattern\n * @param {*} pattern a string or RegExp object\n * @return {object} regex object or false when we can not id the input\n */\nexport function getRegex(pattern) {\n switch (true) {\n case isRegExp(pattern) === true:\n return pattern\n case isString(pattern) === true:\n return new RegExp(pattern)\n default:\n return false\n }\n}\n","// making all the functionality on it's own\n// import { WatchClass } from './watch'\n/*\nwe use a different way to do the same watch thing now\nthis.watch('suspend', function(value, prop, oldValue) {\n this.logger(`${prop} set from ${oldValue} to ${value}`)\n // it means it set the suspend = true then release it\n if (oldValue === true && value === false) {\n // we want this happen after the return happens\n setTimeout(() => {\n this.release()\n }, 1)\n }\n return value; // we need to return the value to store it\n})\n*/\nimport { getRegex, isRegExp } from './utils'\n\nexport default class SuspendClass {\n\n constructor() {\n // suspend, release and queue\n this.__suspend_state__ = null\n // to do this proper we don't use a new prop to hold the event name pattern\n this.__pattern__ = null\n this.queueStore = new Set()\n }\n\n /**\n * start suspend\n * @return {void}\n */\n $suspend() {\n this.logger(`---> SUSPEND ALL OPS <---`)\n this.__suspend__(true)\n }\n\n /**\n * release the queue\n * @return {void}\n */\n $release() {\n this.logger(`---> RELEASE SUSPENDED QUEUE <---`)\n this.__suspend__(false)\n }\n\n /**\n * suspend event by pattern\n * @param {string} pattern the pattern search matches the event name\n * @return {void}\n */\n $suspendEvent(pattern) {\n const regex = getRegex(pattern)\n if (isRegExp(regex)) {\n this.__pattern__ = regex\n return this.$suspend()\n }\n throw new Error(`We expect a pattern variable to be string or RegExp, but we got \"${typeof regex}\" instead`)\n }\n\n /**\n * queuing call up when it's in suspend mode\n * @param {string} evt the event name\n * @param {*} args unknown number of arguments\n * @return {boolean} true when added or false when it's not\n */\n $queue(evt, ...args) {\n this.logger('($queue) get called')\n if (this.__suspend_state__ === true) {\n if (isRegExp(this.__pattern__)) { // it's better then check if its not null\n // check the pattern and decide if we want to suspend it or not\n let found = this.__pattern__.test(evt)\n if (!found) {\n return false\n }\n }\n this.logger('($queue) added to $queue', args)\n // @TODO there shouldn't be any duplicate, but how to make sure?\n this.queueStore.add([evt].concat(args))\n // return this.queueStore.size\n }\n return !!this.__suspend_state__\n }\n\n /**\n * a getter to get all the store queue\n * @return {array} Set turn into Array before return\n */\n get $queues() {\n let size = this.queueStore.size\n this.logger('($queues)', `size: ${size}`)\n if (size > 0) {\n return Array.from(this.queueStore)\n }\n return []\n }\n\n /**\n * to set the suspend and check if it's boolean value\n * @param {boolean} value to trigger\n */\n __suspend__(value) {\n if (typeof value === 'boolean') {\n const lastValue = this.__suspend_state__\n this.__suspend_state__ = value\n this.logger(`($suspend) Change from \"${lastValue}\" --> \"${value}\"`)\n if (lastValue === true && value === false) {\n this.__release__()\n }\n } else {\n throw new Error(`$suspend only accept Boolean value! we got ${typeof value}`)\n }\n }\n\n /**\n * Release the queue\n * @return {int} size if any\n */\n __release__() {\n let size = this.queueStore.size\n let pattern = this.__pattern__\n this.__pattern__ = null\n this.logger(`(release) was called with ${size}${pattern ? ' for \"' + pattern + '\"': ''} item${size > 1 ? 's' : ''}`)\n if (size > 0) {\n const queue = Array.from(this.queueStore)\n this.queueStore.clear()\n this.logger('(release queue)', queue)\n queue.forEach(args => {\n this.logger(args)\n Reflect.apply(this.$trigger, this, args)\n })\n this.logger(`Release size ${this.queueStore.size}`)\n }\n\n return size\n }\n}\n","// break up the main file because its getting way too long\nimport {\n NB_EVENT_SERVICE_PRIVATE_STORE,\n NB_EVENT_SERVICE_PRIVATE_LAZY\n} from './store'\nimport { hashCode2Str, isString } from './utils'\nimport SuspendClass from './suspend'\n\nexport default class StoreService extends SuspendClass {\n\n constructor(config = {}) {\n super()\n if (config.logger && typeof config.logger === 'function') {\n this.logger = config.logger\n }\n this.keep = config.keep\n // for the $done setter\n this.result = config.keep ? [] : null\n // we need to init the store first otherwise it could be a lot of checking later\n this.normalStore = new Map()\n this.lazyStore = new Map()\n }\n\n /**\n * validate the event name(s)\n * @param {string[]} evt event name\n * @return {boolean} true when OK\n */\n validateEvt(...evt) {\n evt.forEach(e => {\n if (!isString(e)) {\n this.logger('(validateEvt)', e)\n throw new Error(`Event name must be string type! we got ${typeof e}`)\n }\n })\n return true\n }\n\n /**\n * Simple quick check on the two main parameters\n * @param {string} evt event name\n * @param {function} callback function to call\n * @return {boolean} true when OK\n */\n validate(evt, callback) {\n if (this.validateEvt(evt)) {\n if (typeof callback === 'function') {\n return true\n }\n }\n throw new Error(`callback required to be function type! we got ${typeof callback}`)\n }\n\n /**\n * Check if this type is correct or not added in V1.5.0\n * @param {string} type for checking\n * @return {boolean} true on OK\n */\n validateType(type) {\n this.validateEvt(type)\n const types = ['on', 'only', 'once', 'onlyOnce']\n return !!types.filter(t => type === t).length\n }\n\n /**\n * Run the callback\n * @param {function} callback function to execute\n * @param {array} payload for callback\n * @param {object} ctx context or null\n * @return {void} the result store in $done\n */\n run(callback, payload, ctx) {\n this.logger('(run) callback:', callback, 'payload:', payload, 'context:', ctx)\n this.$done = Reflect.apply(callback, ctx, this.toArray(payload))\n }\n\n /**\n * Take the content out and remove it from store id by the name\n * @param {string} evt event name\n * @param {string} [storeName = lazyStore] name of store\n * @return {object|boolean} content or false on not found\n */\n takeFromStore(evt, storeName = 'lazyStore') {\n let store = this[storeName] // it could be empty at this point\n if (store) {\n this.logger('(takeFromStore)', storeName, store)\n if (store.has(evt)) {\n let content = store.get(evt)\n this.logger(`(takeFromStore) has \"${evt}\"`, content)\n store.delete(evt)\n return content\n }\n return false\n }\n throw new Error(`\"${storeName}\" is not supported!`)\n }\n\n /**\n * This was part of the $get. We take it out\n * so we could use a regex to remove more than one event\n * @param {object} store the store to return from\n * @param {string} evt event name\n * @param {boolean} full return just the callback or everything\n * @return {array|boolean} false when not found\n */\n findFromStore(evt, store, full = false) {\n if (store.has(evt)) {\n return Array\n .from(store.get(evt))\n .map( l => {\n if (full) {\n return l\n }\n let [key, callback, ] = l\n return callback\n })\n }\n return false\n }\n\n /**\n * Similar to the findFromStore, but remove\n * @param {string} evt event name\n * @param {object} store the store to remove from\n * @return {boolean} false when not found\n */\n removeFromStore(evt, store) {\n if (store.has(evt)) {\n this.logger('($off)', evt)\n store.delete(evt)\n return true\n }\n return false\n }\n\n /**\n * The add to store step is similar so make it generic for resuse\n * @param {object} store which store to use\n * @param {string} evt event name\n * @param {spread} args because the lazy store and normal store store different things\n * @return {array} store and the size of the store\n */\n addToStore(store, evt, ...args) {\n let fnSet\n if (store.has(evt)) {\n this.logger(`(addToStore) \"${evt}\" existed`)\n fnSet = store.get(evt)\n } else {\n this.logger(`(addToStore) create new Set for \"${evt}\"`)\n // this is new\n fnSet = new Set()\n }\n // lazy only store 2 items - this is not the case in V1.6.0 anymore\n // we need to check the first parameter is string or not\n if (args.length > 2) {\n if (Array.isArray(args[0])) { // lazy store\n // check if this type of this event already register in the lazy store\n let [,,t] = args\n if (!this.checkTypeInLazyStore(evt, t)) {\n fnSet.add(args)\n }\n } else {\n if (!this.checkContentExist(args, fnSet)) {\n this.logger(`(addToStore) insert new`, args)\n fnSet.add(args)\n }\n }\n } else { // add straight to lazy store\n fnSet.add(args)\n }\n store.set(evt, fnSet)\n return [store, fnSet.size]\n }\n\n /**\n * @param {array} args for compare\n * @param {object} fnSet A Set to search from\n * @return {boolean} true on exist\n */\n checkContentExist(args, fnSet) {\n let list = Array.from(fnSet)\n return !!list.filter(li => {\n let [hash,] = li\n return hash === args[0]\n }).length\n }\n\n /**\n * get the existing type to make sure no mix type add to the same store\n * @param {string} evtName event name\n * @param {string} type the type to check\n * @return {boolean} true you can add, false then you can't add this type\n */\n checkTypeInStore(evtName, type) {\n this.validateEvt(evtName, type)\n let all = this.$get(evtName, true)\n if (all === false) {\n // pristine it means you can add\n return true\n }\n // it should only have ONE type in ONE event store\n return !all.filter(list => {\n let [ ,,,t ] = list\n return type !== t\n }).length\n }\n\n /**\n * This is checking just the lazy store because the structure is different\n * therefore we need to use a new method to check it\n */\n checkTypeInLazyStore(evtName, type) {\n this.validateEvt(evtName, type)\n let store = this.lazyStore.get(evtName)\n this.logger('(checkTypeInLazyStore)', store)\n if (store) {\n return !!Array\n .from(store)\n .filter(li => {\n let [,,t] = li\n return t !== type\n }).length\n }\n return false\n }\n\n /**\n * wrapper to re-use the addToStore,\n * V1.3.0 add extra check to see if this type can add to this evt\n * @param {string} evt event name\n * @param {string} type on or once\n * @param {function} callback function\n * @param {object} context the context the function execute in or null\n * @return {number} size of the store\n */\n addToNormalStore(evt, type, callback, context = null) {\n this.logger(`(addToNormalStore) try to add \"${type}\" --> \"${evt}\" to normal store`)\n // @TODO we need to check the existing store for the type first!\n if (this.checkTypeInStore(evt, type)) {\n this.logger('(addToNormalStore)', `\"${type}\" --> \"${evt}\" can add to normal store`)\n let key = this.hashFnToKey(callback)\n let args = [this.normalStore, evt, key, callback, context, type]\n let [_store, size] = Reflect.apply(this.addToStore, this, args)\n this.normalStore = _store\n return size\n }\n return false\n }\n\n /**\n * Add to lazy store this get calls when the callback is not register yet\n * so we only get a payload object or even nothing\n * @param {string} evt event name\n * @param {array} payload of arguments or empty if there is none\n * @param {object} [context=null] the context the callback execute in\n * @param {string} [type=false] register a type so no other type can add to this evt\n * @return {number} size of the store\n */\n addToLazyStore(evt, payload = [], context = null, type = false) {\n // this is add in V1.6.0\n // when there is type then we will need to check if this already added in lazy store\n // and no other type can add to this lazy store\n let args = [this.lazyStore, evt, this.toArray(payload), context]\n if (type) {\n args.push(type)\n }\n let [_store, size] = Reflect.apply(this.addToStore, this, args)\n this.lazyStore = _store\n this.logger(`(addToLazyStore) size: ${size}`)\n return size\n }\n\n /**\n * make sure we store the argument correctly\n * @param {*} arg could be array\n * @return {array} make sured\n */\n toArray(arg) {\n return Array.isArray(arg) ? arg : [arg]\n }\n\n /**\n * setter to store the Set in private\n * @param {object} obj a Set\n */\n set normalStore(obj) {\n NB_EVENT_SERVICE_PRIVATE_STORE.set(this, obj)\n }\n\n /**\n * @return {object} Set object\n */\n get normalStore() {\n return NB_EVENT_SERVICE_PRIVATE_STORE.get(this)\n }\n\n /**\n * setter to store the Set in lazy store\n * @param {object} obj a Set\n */\n set lazyStore(obj) {\n NB_EVENT_SERVICE_PRIVATE_LAZY.set(this , obj)\n }\n\n /**\n * @return {object} the lazy store Set\n */\n get lazyStore() {\n return NB_EVENT_SERVICE_PRIVATE_LAZY.get(this)\n }\n\n /**\n * generate a hashKey to identify the function call\n * The build-in store some how could store the same values!\n * @param {function} fn the converted to string function\n * @return {string} hashKey\n */\n hashFnToKey(fn) {\n return hashCode2Str(fn.toString())\n }\n}\n","// The top level\nimport { TAKEN_BY_OTHER_TYPE_ERR } from './constants'\nimport StoreService from './store-service'\n// export\nexport default class EventService extends StoreService {\n /**\n * class constructor\n */\n constructor(config = {}) {\n super(config)\n }\n\n /**\n * logger function for overwrite\n */\n logger() {}\n\n // for id if the instance is this class\n get $name() {\n return 'to1source-event'\n }\n\n // take this down in the next release\n get is() {\n return this.$name\n }\n\n //////////////////////////\n // PUBLIC METHODS //\n //////////////////////////\n\n /**\n * Register your evt handler, note we don't check the type here,\n * we expect you to be sensible and know what you are doing.\n * @param {string} evt name of event\n * @param {function} callback bind method --> if it's array or not\n * @param {object} [context=null] to execute this call in\n * @return {number} the size of the store\n */\n $on(evt , callback , context = null) {\n const type = 'on'\n this.validate(evt, callback)\n // first need to check if this evt is in lazy store\n let lazyStoreContent = this.takeFromStore(evt)\n // this is normal register first then call later\n if (lazyStoreContent === false) {\n this.logger(`($on) \"${evt}\" is not in lazy store`)\n // @TODO we need to check if there was other listener to this\n // event and are they the same type then we could solve that\n // register the different type to the same event name\n return this.addToNormalStore(evt, type, callback, context)\n }\n this.logger(`($on) ${evt} found in lazy store`)\n // this is when they call $trigger before register this callback\n let size = 0\n lazyStoreContent.forEach(content => {\n let [ payload, ctx, t ] = content\n if (t && t !== type) {\n throw new Error(`${TAKEN_BY_OTHER_TYPE_ERR} ${t}`)\n }\n this.logger(`($on)`, `call run \"${evt}\"`)\n this.run(callback, payload, context || ctx)\n size += this.addToNormalStore(evt, type, callback, context || ctx)\n })\n\n this.logger(`($on) return size ${size}`)\n return size\n }\n\n /**\n * once only registered it once, there is no overwrite option here\n * @NOTE change in v1.3.0 $once can add multiple listeners\n * but once the event fired, it will remove this event (see $only)\n * @param {string} evt name\n * @param {function} callback to execute\n * @param {object} [context=null] the handler execute in\n * @return {boolean} result\n */\n $once(evt , callback , context = null) {\n this.validate(evt, callback)\n const type = 'once'\n let lazyStoreContent = this.takeFromStore(evt)\n // this is normal register before call $trigger\n let nStore = this.normalStore;\n if (lazyStoreContent === false) {\n this.logger(`($once) \"${evt}\" is not in the lazy store`)\n // v1.3.0 $once now allow to add multiple listeners\n return this.addToNormalStore(evt, type, callback, context)\n } else {\n // now this is the tricky bit\n // there is a potential bug here that cause by the developer\n // if they call $trigger first, the lazy won't know it's a once call\n // so if in the middle they register any call with the same evt name\n // then this $once call will be fucked - add this to the documentation\n this.logger('($once)', lazyStoreContent)\n const list = Array.from(lazyStoreContent)\n // should never have more than 1\n const [ payload, ctx, t ] = list[0]\n if (t && t !== type) {\n throw new Error(`${TAKEN_BY_OTHER_TYPE_ERR} ${t}`)\n }\n this.logger('($once)', `call run \"${evt}\"`)\n this.run(callback, payload, context || ctx)\n // remove this evt from store\n this.$off(evt)\n }\n }\n\n /**\n * This one event can only bind one callbackback\n * @param {string} evt event name\n * @param {function} callback event handler\n * @param {object} [context=null] the context the event handler execute in\n * @return {boolean} true bind for first time, false already existed\n */\n $only(evt, callback, context = null) {\n this.validate(evt, callback)\n const type = 'only'\n let added = false\n let lazyStoreContent = this.takeFromStore(evt)\n // this is normal register before call $trigger\n let nStore = this.normalStore\n if (!nStore.has(evt)) {\n this.logger(`($only) \"${evt}\" add to normalStore`)\n added = this.addToNormalStore(evt, type, callback, context)\n }\n if (lazyStoreContent !== false) {\n // there are data store in lazy store\n this.logger(`($only) \"${evt}\" found data in lazy store to execute`)\n const list = Array.from(lazyStoreContent)\n // $only allow to trigger this multiple time on the single handler\n list.forEach( li => {\n const [ payload, ctx, t ] = li\n if (t && t !== type) {\n throw new Error(`${TAKEN_BY_OTHER_TYPE_ERR} ${t}`)\n }\n this.logger(`($only) call run \"${evt}\"`)\n this.run(callback, payload, context || ctx)\n })\n }\n return added\n }\n\n /**\n * $only + $once this is because I found a very subtile bug when we pass a\n * resolver, rejecter - and it never fire because that's OLD added in v1.4.0\n * @param {string} evt event name\n * @param {function} callback to call later\n * @param {object} [context=null] exeucte context\n * @return {void}\n */\n $onlyOnce(evt, callback, context = null) {\n this.validate(evt, callback)\n const type = 'onlyOnce'\n let added = false\n let lazyStoreContent = this.takeFromStore(evt)\n // this is normal register before call $trigger\n let nStore = this.normalStore;\n if (!nStore.has(evt)) {\n this.logger(`($onlyOnce) \"${evt}\" add to normalStore`)\n added = this.addToNormalStore(evt, type, callback, context)\n }\n if (lazyStoreContent !== false) {\n // there are data store in lazy store\n this.logger('($onlyOnce)', lazyStoreContent)\n const list = Array.from(lazyStoreContent)\n // should never have more than 1\n const [ payload, ctx, t ] = list[0]\n if (t && t !== 'onlyOnce') {\n throw new Error(`${TAKEN_BY_OTHER_TYPE_ERR} ${t}`)\n }\n this.logger(`($onlyOnce) call run \"${evt}\"`)\n this.run(callback, payload, context || ctx)\n // remove this evt from store\n this.$off(evt)\n }\n return added\n }\n\n /**\n * This is a shorthand of $off + $on added in V1.5.0\n * @param {string} evt event name\n * @param {function} callback to exeucte\n * @param {object} [context = null] or pass a string as type\n * @param {string} [type=on] what type of method to replace\n * @return {*}\n */\n $replace(evt, callback, context = null, type = 'on') {\n if (this.validateType(type)) {\n this.$off(evt)\n let method = this['$' + type]\n this.logger(`($replace)`, evt, callback)\n return Reflect.apply(method, this, [evt, callback, context])\n }\n throw new Error(`${type} is not supported!`)\n }\n\n /**\n * trigger the event\n * @param {string} evt name NOT allow array anymore!\n * @param {mixed} [payload = []] pass to fn\n * @param {object|string} [context = null] overwrite what stored\n * @param {string} [type=false] if pass this then we need to add type to store too\n * @return {number} if it has been execute how many times\n */\n $trigger(evt , payload = [] , context = null, type = false) {\n this.validateEvt(evt)\n let found = 0\n // first check the normal store\n let nStore = this.normalStore\n this.logger('($trigger) normalStore', nStore)\n if (nStore.has(evt)) {\n this.logger(`($trigger) \"${evt}\" found`)\n // @1.8.0 to add the suspend queue\n let added = this.$queue(evt, payload, context, type)\n if (added) {\n this.logger(`($trigger) Currently suspended \"${evt}\" added to queue, nothing executed. Exit now.`)\n return false // not executed\n }\n let nSet = Array.from(nStore.get(evt))\n let ctn = nSet.length\n let hasOnce = false\n let hasOnly = false\n for (let i=0; i < ctn; ++i) {\n ++found;\n // this.logger('found', found)\n let [ _, callback, ctx, type ] = nSet[i]\n this.logger(`($trigger) call run for ${evt}`)\n this.run(callback, payload, context || ctx)\n if (type === 'once' || type === 'onlyOnce') {\n hasOnce = true;\n }\n }\n if (hasOnce) {\n nStore.delete(evt)\n }\n return found\n }\n // now this is not register yet\n this.addToLazyStore(evt, payload, context, type)\n return found\n }\n\n /**\n * this is an alias to the $trigger\n * @NOTE breaking change in V1.6.0 we swap the parameter aroun\n * @NOTE breaking change: v1.9.1 it return an function to accept the params as spread\n * @param {string} evt event name\n * @param {string} type of call\n * @param {object} context what context callback execute in\n * @return {*} from $trigger\n */\n $call(evt, type = false, context = null) {\n const ctx = this\n\n return (...args) => {\n let _args = [evt, args, context, type]\n return Reflect.apply(ctx.$trigger, ctx, _args)\n }\n }\n\n /**\n * remove the evt from all the stores\n * @param {string} evt name\n * @return {boolean} true actually delete something\n */\n $off(evt) {\n // @TODO we will allow a regex pattern to mass remove event\n this.validateEvt(evt)\n let stores = [ this.lazyStore, this.normalStore ]\n\n return !!stores\n .filter(store => store.has(evt))\n .map(store => this.removeFromStore(evt, store))\n .length\n }\n\n /**\n * return all the listener bind to that event name\n * @param {string} evtName event name\n * @param {boolean} [full=false] if true then return the entire content\n * @return {array|boolean} listerner(s) or false when not found\n */\n $get(evt, full = false) {\n // @TODO should we allow the same Regex to search for all?\n this.validateEvt(evt)\n let store = this.normalStore\n return this.findFromStore(evt, store, full)\n }\n\n /**\n * store the return result from the run\n * @param {*} value whatever return from callback\n */\n set $done(value) {\n this.logger('($done) set value: ', value)\n if (this.keep) {\n this.result.push(value)\n } else {\n this.result = value\n }\n }\n\n /**\n * @TODO is there any real use with the keep prop?\n * getter for $done\n * @return {*} whatever last store result\n */\n get $done() {\n this.logger('($done) get result:', this.result)\n if (this.keep) {\n return this.result[this.result.length - 1]\n }\n return this.result\n }\n\n /**\n * Take a look inside the stores\n * @param {number|null} idx of the store, null means all\n * @return {void}\n */\n $debug(idx = null) {\n let names = ['lazyStore', 'normalStore']\n let stores = [this.lazyStore, this.normalStore]\n if (stores[idx]) {\n this.logger(names[idx], stores[idx])\n } else {\n stores.map((store, i) => {\n this.logger(names[i], store)\n })\n }\n }\n}\n","// default\nimport To1sourceEvent from './src/event-service'\n\nexport default To1sourceEvent\n","// this will generate a event emitter and will be use everywhere\nimport EventEmitterClass from '@to1source/event'\n// create a clone version so we know which one we actually is using\nclass JsonqlWsEvt extends EventEmitterClass {\n\n constructor(logger) {\n if (typeof logger !== 'function') {\n throw new Error(`Just die here the logger is not a function!`)\n }\n logger(`---> Create a new EventEmitter <---`)\n // this ee will always come with the logger\n // because we should take the ee from the configuration\n super({ logger })\n }\n\n get name() {\n return'jsonql-ws-client-core'\n }\n}\n\n/**\n * getting the event emitter\n * @param {object} opts configuration\n * @return {object} the event emitter instance\n */\nconst getEventEmitter = opts => {\n const { log, eventEmitter } = opts\n \n if (eventEmitter) {\n log(`eventEmitter is:`, eventEmitter.name)\n return eventEmitter\n }\n \n return new JsonqlWsEvt( opts.log )\n}\n\nexport { \n getEventEmitter, \n EventEmitterClass // for other module to build from \n}\n","// group all the small functions here\nimport { EMIT_REPLY_TYPE } from 'jsonql-constants'\nimport { toArray, createEvt } from 'jsonql-utils/src/generic'\nimport JsonqlValidationError from 'jsonql-errors/src/validation-error'\n\n\n/**\n * WebSocket is strict about the path, therefore we need to make sure before it goes in\n * @param {string} url input url\n * @return {string} url with correct path name\n */\nexport const fixWss = url => {\n const uri = url.toLowerCase()\n if (uri.indexOf('http') > -1) {\n if (uri.indexOf('https') > -1) {\n return uri.replace('https', 'wss')\n }\n return uri.replace('http', 'ws')\n }\n return uri\n}\n\n\n/**\n * get a stock host name from browser\n */\nexport const getHostName = () => {\n try {\n return [window.location.protocol, window.location.host].join('//')\n } catch(e) {\n throw new JsonqlValidationError(e)\n }\n}\n\n/**\n * Unbind the event\n * @param {object} ee EventEmitter\n * @param {string} namespace\n * @return {void}\n */\nexport const clearMainEmitEvt = (ee, namespace) => {\n let nsps = toArray(namespace)\n nsps.forEach(n => {\n ee.$off(createEvt(n, EMIT_REPLY_TYPE))\n })\n}\n\n\n","// take out from the resolver-methods\nimport { \n LOGIN_EVENT_NAME, \n LOGOUT_EVENT_NAME, \n ON_LOGIN_FN_NAME\n} from 'jsonql-constants'\nimport { JsonqlValidationError } from 'jsonql-errors'\nimport { injectToFn, chainFns, isString, objDefineProps, isFunc } from '../utils'\n\n\n/**\n * @TODO this is now become unnecessary because the login is a slave to the\n * http-client - but keep this for now and see what we want to do with it later\n * @UPDATE it might be better if we decoup the two http-client only emit a login event\n * Here should catch it and reload the ws client @TBC\n * break out from createAuthMethods to allow chaining call\n * @param {object} obj the main client object\n * @param {object} opts configuration\n * @param {object} ee event emitter\n * @return {array} [ obj, opts, ee ] what comes in what goes out\n */\nconst setupLoginHandler = (obj, opts, ee) => [ \n injectToFn(obj, opts.loginHandlerName, function loginHandler(token) {\n if (token && isString(token)) {\n opts.log(`Received ${LOGIN_EVENT_NAME} with ${token}`)\n // @TODO add the interceptor hook \n return ee.$trigger(LOGIN_EVENT_NAME, [token])\n }\n // should trigger a global error instead @TODO\n throw new JsonqlValidationError(opts.loginHandlerName, `Unexpected token ${token}`)\n }),\n opts,\n ee\n]\n\n\n/**\n * break out from createAuthMethods to allow chaining call - final in chain\n * @param {object} obj the main client object\n * @param {object} opts configuration\n * @param {object} ee event emitter\n * @return {array} [ obj, opts, ee ] what comes in what goes out\n */\nconst setupLogoutHandler = (obj, opts, ee) => [\n injectToFn(obj, opts.logoutHandlerName, function logoutHandler(...args) {\n ee.$trigger(LOGOUT_EVENT_NAME, args)\n }),\n opts, \n ee\n]\n\n\n/**\n * This event will fire when the socket.io.on('connection') and ws.onopen\n * Plus this will check if it's the private namespace that fired the event\n * @param {object} obj the client itself\n * @param {object} ee Event Emitter\n * @return {array} [ obj, opts, ee] what comes in what goes out\n */\nconst createOnLoginhandler = (obj, opts, ee) => [\n objDefineProps(obj, ON_LOGIN_FN_NAME, function onLoginCallbackHandler(onLoginCallback) {\n if (isFunc(onLoginCallback)) {\n // only one callback can registered with it, TBC\n ee.$only(ON_LOGIN_FN_NAME, onLoginCallback)\n }\n }),\n opts,\n ee \n]\n\n// @TODO future feature setup switch user\n\n\n/**\n * Create auth related methods\n * @param {object} obj the client itself\n * @param {object} opts configuration\n * @param {object} ee Event Emitter\n * @return {array} [ obj, opts, ee ] what comes in what goes out\n */\nexport function createAuthMethods(obj, opts, ee) {\n return chainFns(\n setupLoginHandler, \n setupLogoutHandler,\n createOnLoginhandler\n )(obj, opts, ee)\n}\n","// constants\n\nimport {\n EMIT_REPLY_TYPE,\n JS_WS_SOCKET_IO_NAME,\n JS_WS_NAME,\n ON_MESSAGE_FN_NAME,\n ON_RESULT_FN_NAME\n} from 'jsonql-constants'\n\nconst SOCKET_IO = JS_WS_SOCKET_IO_NAME\nconst WS = JS_WS_NAME\n\nconst AVAILABLE_SERVERS = [SOCKET_IO, WS]\n\nconst SOCKET_NOT_DEFINE_ERR = 'socket is not define in the contract file!'\n\nconst SERVER_NOT_SUPPORT_ERR = 'is not supported server name!'\n\nconst MISSING_PROP_ERR = 'Missing property in contract!'\n\nconst UNKNOWN_CLIENT_ERR = 'Unknown client type!'\n\nconst EMIT_EVT = EMIT_REPLY_TYPE\n\nconst NAMESPACE_KEY = 'namespaceMap'\n\nconst UNKNOWN_RESULT = 'UKNNOWN RESULT!'\n\nconst NOT_ALLOW_OP = 'This operation is not allow!'\n\nconst MY_NAMESPACE = 'myNamespace'\n\nconst CB_FN_NAME = 'on'\n// this is a socket only (for now) feature so we just put it here \nconst DISCONNECTED_ERROR_MSG = `You have disconnected from the socket server, please reconnect.`\n\nexport {\n SOCKET_IO,\n WS,\n AVAILABLE_SERVERS,\n SOCKET_NOT_DEFINE_ERR,\n SERVER_NOT_SUPPORT_ERR,\n MISSING_PROP_ERR,\n UNKNOWN_CLIENT_ERR,\n EMIT_EVT,\n ON_MESSAGE_FN_NAME,\n ON_RESULT_FN_NAME,\n NAMESPACE_KEY,\n UNKNOWN_RESULT,\n NOT_ALLOW_OP,\n MY_NAMESPACE,\n CB_FN_NAME,\n DISCONNECTED_ERROR_MSG\n}\n","// breaking it up further to share between methods\nimport { DATA_KEY, ERROR_KEY } from 'jsonql-constants'\nimport { UNKNOWN_RESULT } from '../options/constants'\nimport { isObjectHasKey } from '../utils'\n\n/**\n * break out to use in different places to handle the return from server\n * @param {object} data from server\n * @param {function} resolver NOT from promise\n * @param {function} rejecter NOT from promise\n * @return {void} nothing\n */\nexport function respondHandler(data, resolver, rejecter) {\n if (isObjectHasKey(data, ERROR_KEY)) {\n // debugFn('-- rejecter called --', data[ERROR_KEY])\n rejecter(data[ERROR_KEY])\n } else if (isObjectHasKey(data, DATA_KEY)) {\n // debugFn('-- resolver called --', data[DATA_KEY])\n resolver(data[DATA_KEY])\n } else {\n // debugFn('-- UNKNOWN_RESULT --', data)\n rejecter({message: UNKNOWN_RESULT, error: data})\n }\n}\n","// the actual trigger call method\nimport { ON_RESULT_FN_NAME, EMIT_REPLY_TYPE } from 'jsonql-constants'\nimport { createEvt, toArray } from '../utils'\nimport { respondHandler } from './respond-handler'\n\n/**\n * just wrapper\n * @param {object} ee EventEmitter\n * @param {string} namespace where this belongs\n * @param {string} resolverName resolver\n * @param {array} args arguments\n * @param {function} log function \n * @return {void} nothing\n */\nexport function actionCall(ee, namespace, resolverName, args = [], log) {\n // reply event \n const outEventName = createEvt(namespace, EMIT_REPLY_TYPE)\n\n log(`actionCall: ${outEventName} --> ${resolverName}`, args)\n // This is the out going call \n ee.$trigger(outEventName, [resolverName, toArray(args)])\n \n // then we need to listen to the event callback here as well\n return new Promise((resolver, rejecter) => {\n const inEventName = createEvt(namespace, resolverName, ON_RESULT_FN_NAME)\n // this cause the onResult got the result back first \n // and it should be the promise resolve first\n // @TODO we need to rewrote the respondHandler to change the problem stated above \n ee.$on(\n inEventName,\n function actionCallResultHandler(result) {\n log(`got the first result`, result)\n respondHandler(result, resolver, rejecter)\n }\n )\n })\n}\n","// setting up the send method \nimport { JsonqlValidationError } from 'jsonql-errors'\nimport {\n ON_ERROR_FN_NAME,\n SEND_MSG_FN_NAME\n} from 'jsonql-constants'\nimport { validateAsync } from 'jsonql-params-validator'\nimport { objDefineProps, createEvt, toArray, nil } from '../utils'\nimport { actionCall } from './action-call'\n\n/** \n * pairing with the server vesrion SEND_MSG_FN_NAME\n * last of the chain so only return the resolver (fn)\n * This is now change to a getter / setter method \n * and call like this: resolver.send(...args)\n * @param {function} fn the resolver function \n * @param {object} ee event emitter instance \n * @param {string} namespace the namespace it belongs to \n * @param {string} resolverName name of the resolver \n * @param {object} params from contract \n * @param {function} log a logger function\n * @return {function} return the resolver itself \n */ \nexport const setupSendMethod = (fn, ee, namespace, resolverName, params, log) => (\n objDefineProps(\n fn, \n SEND_MSG_FN_NAME, \n nil, \n function sendHandler() {\n // let _log = (...args) => Reflect.apply(console.info, console, ['[SEND]'].concat(args))\n /** \n * This will follow the same pattern like the resolver \n * @param {array} args list of unknown argument follow the resolver \n * @return {promise} resolve the result \n */\n return function sendCallback(...args) {\n return validateAsync(args, params.params, true)\n .then(_args => {\n // @TODO check the result \n // because the validation could failed with the list of fail properties \n log(namespace, resolverName, _args)\n return actionCall(ee, namespace, resolverName, _args, _log)\n })\n .catch(err => {\n // @TODO it shouldn't be just a validation error \n // it could be server return error, so we need to check \n // what error we got back here first \n log('send error', err)\n // @TODO it might not an validation error need the finalCatch here\n ee.$call(\n createEvt(namespace, resolverName, ON_ERROR_FN_NAME),\n [new JsonqlValidationError(resolverName, err)]\n )\n })\n } \n })\n)\n","// break up the original setup resolver method here\n// import { JsonqlValidationError, finalCatch } from 'jsonql-errors'\nimport {\n ON_ERROR_FN_NAME,\n ON_MESSAGE_FN_NAME,\n ON_RESULT_FN_NAME\n} from 'jsonql-constants'\n// local \nimport { MY_NAMESPACE } from '../options/constants'\nimport { chainFns, objDefineProps, injectToFn, createEvt, isFunc } from '../utils'\nimport { respondHandler } from './respond-handler'\nimport { setupSendMethod } from './setup-send-method'\n\n/**\n * The first one in the chain, just setup a namespace prop\n * the rest are passing through\n * @param {function} fn the resolver function\n * @param {object} ee the event emitter \n * @param {string} resolverName what it said\n * @param {object} params for resolver from contract\n * @param {function} log the logger function\n * @return {array}\n */\nconst setupNamespace = (fn, ee, namespace, resolverName, params, log) => [\n injectToFn(fn, MY_NAMESPACE, namespace),\n ee,\n namespace,\n resolverName,\n params,\n log \n]\n\n/** \n * onResult handler\n */ \nconst setupOnResult = (fn, ee, namespace, resolverName, params, log) => [\n objDefineProps(fn, ON_RESULT_FN_NAME, function(resultCallback) {\n if (isFunc(resultCallback)) {\n ee.$on(\n createEvt(namespace, resolverName, ON_RESULT_FN_NAME),\n function resultHandler(result) {\n respondHandler(result, resultCallback, (error) => {\n log(`Catch error: \"${resolverName}\"`, error)\n ee.$trigger(\n createEvt(namespace, resolverName, ON_ERROR_FN_NAME), \n error\n )\n })\n }\n )\n }\n }),\n ee,\n namespace,\n resolverName,\n params,\n log\n]\n\n/** \n * we do need to add the send prop back because it's the only way to deal with\n * bi-directional data stream \n */\nconst setupOnMessage = (fn, ee, namespace, resolverName, params, log) => [\n objDefineProps(fn, ON_MESSAGE_FN_NAME, function(messageCallback) {\n // we expect this to be a function\n if (isFunc(messageCallback)) {\n // did that add to the callback\n let onMessageCallback = (args) => {\n respondHandler(args, messageCallback, (error) => {\n log(`Catch error: \"${resolverName}\"`, error)\n ee.$trigger(\n createEvt(namespace, resolverName, ON_ERROR_FN_NAME), \n error\n )\n })\n }\n // register the handler for this message event\n ee.$only(\n createEvt(namespace, resolverName, ON_MESSAGE_FN_NAME), \n onMessageCallback\n )\n }\n }),\n ee,\n namespace,\n resolverName,\n params,\n log\n]\n\n/** \n * ON_ERROR_FN_NAME handler\n */\nconst setupOnError = (fn, ee, namespace, resolverName, params, log) => [\n objDefineProps(fn, ON_ERROR_FN_NAME, function(resolverErrorHandler) {\n if (isFunc(resolverErrorHandler)) {\n // please note ON_ERROR_FN_NAME can add multiple listners\n ee.$only(\n createEvt(namespace, resolverName, ON_ERROR_FN_NAME), \n resolverErrorHandler\n )\n }\n }),\n ee,\n namespace,\n resolverName,\n params,\n log\n]\n\n/**\n * Add extra property / listeners to the resolver\n * @param {string} namespace where this belongs\n * @param {string} resolverName name as event name\n * @param {object} params from contract\n * @param {function} fn resolver function\n * @param {object} ee EventEmitter\n * @param {function} log function \n * @return {function} resolver\n */\nexport function setupResolver(namespace, resolverName, params, fn, ee, log) {\n let fns = [\n setupNamespace, \n setupOnResult, \n setupOnMessage, \n setupOnError, \n setupSendMethod\n ]\n \n // get the executor\n const executor = Reflect.apply(chainFns, null, fns)\n const args = [fn, ee, namespace, resolverName, params, log]\n\n return Reflect.apply(executor, null, args)\n}\n","// put all the resolver related methods here to make it more clear\n\n// this will be a mini client server architect\n// The reason is when the enableAuth setup - the private route\n// might not be validated, but we need the callable point is ready\n// therefore this part will always take the contract and generate\n// callable api for the developer to setup their front end\n// the only thing is - when they call they might get an error or\n// NOT_LOGIN_IN and they can react to this error accordingly\nimport { finalCatch } from 'jsonql-errors'\nimport { validateAsync } from 'jsonql-params-validator'\nimport { setupResolver } from './setup-resolver'\nimport { actionCall } from './action-call'\nimport {\n createEvt,\n objDefineProps,\n isFunc,\n injectToFn\n} from '../utils'\nimport {\n ON_ERROR_FN_NAME,\n ON_READY_FN_NAME\n} from 'jsonql-constants'\n\n/**\n * create the actual function to send message to server\n * @param {object} ee EventEmitter instance\n * @param {string} namespace this resolver end point\n * @param {string} resolverName name of resolver as event name\n * @param {object} params from contract\n * @param {function} log pass the log function\n * @return {function} resolver\n */\nfunction createResolver(ee, namespace, resolverName, params, log) {\n // note we pass the new withResult=true option\n return function resolver(...args) {\n return validateAsync(args, params.params, true)\n .then(_args => actionCall(ee, namespace, resolverName, _args, log))\n .catch(finalCatch)\n }\n}\n\n/**\n * step one get the clientmap with the namespace\n * @param {object} opts configuration\n * @param {object} ee EventEmitter\n * @param {object} nspGroup resolvers index by their namespace\n * @return {promise} resolve the clientmapped, and start the chain\n */\nexport function generateResolvers(opts, ee, nspGroup) {\n let client= {}\n let { log } = opts\n\n for (let namespace in nspGroup) {\n let list = nspGroup[namespace]\n for (let resolverName in list) {\n // resolverNames.push(resolverName)\n let params = list[resolverName]\n let fn = createResolver(ee, namespace, resolverName, params, log)\n // this should set as a getter therefore can not be overwrite by accident\n // obj[resolverName] = setupResolver(namespace, resolverName, params, fn, ee)\n client = injectToFn(\n client,\n resolverName,\n setupResolver(namespace, resolverName, params, fn, ee, log)\n )\n }\n }\n // resolve the clientto start the chain\n // chain the result to allow the chain processing\n return [ client, opts, ee, nspGroup ]\n}\n\n/**\n * The problem is the namespace can have more than one\n * and we only have on onError message\n * @param {object} clientthe client itself\n * @param {object} opts configuration\n * @param {object} ee Event Emitter\n * @param {object} nspGroup namespace keys\n * @return {array} [obj, opts, ee]\n */\nexport function createNamespaceErrorListener(client, opts, ee, nspGroup) {\n return [\n objDefineProps(\n client,\n ON_ERROR_FN_NAME,\n function namespaceErrorCallbackHandler(namespaceErrorHandler) {\n if (isFunc(namespaceErrorHandler)) {\n // please note ON_ERROR_FN_NAME can add multiple listners\n for (let namespace in nspGroup) {\n // this one is very tricky, we need to make sure the trigger is calling\n // with the namespace as well as the error\n ee.$on(createEvt(namespace, ON_ERROR_FN_NAME), namespaceErrorHandler)\n }\n }\n }\n ),\n opts,\n ee\n ]\n}\n\n/**\n * This event will fire when the socket.io.on('connection') and ws.onopen\n * @param {object} client client itself\n * @param {object} opts configuration\n * @param {object} ee Event Emitter\n * @return {array} [ obj, opts, ee ]\n */\nexport function createOnReadyListener(client, opts, ee) {\n return [\n objDefineProps(\n client,\n ON_READY_FN_NAME,\n function onReadyCallbackHandler(onReadyCallback) {\n if (isFunc(onReadyCallback)) {\n // reduce it down to just one flat level\n // @2020-03-19 only allow ONE onReady callback otherwise\n // it will get fire multiple times which is not what we want \n ee.$only(ON_READY_FN_NAME, onReadyCallback)\n }\n }\n ),\n opts,\n ee\n ]\n}\n","// this is a new method that will create several \n// intercom method also reverse listen to the server \n// such as disconnect (server issue disconnect)\nimport { injectToFn } from '../utils'\nimport { DISCONNECT_EVENT_NAME } from 'jsonql-constants'\n\n/**\n * this is the new method that setup the intercom handler \n * also this serve as the final call in the then chain to \n * output the client\n * @param {object} client the client \n * @param {object} opts configuration \n * @param {object} ee the event emitter\n * @return {object} client \n */\nexport function setupInterCom(client, opts, ee) {\n const { disconnectHandlerName } = opts\n return injectToFn(client, disconnectHandlerName, function disconnectHandler(...args) {\n ee.$trigger(DISCONNECT_EVENT_NAME, args)\n })\n} ","// The final step of the setup before it returns the client\nimport { setupInterCom } from './setup-intercom'\n// import { HELLO_FN } from 'jsonql-constants'\n\n/** \n * The final step to return the client \n * @param {object} client the client \n * @param {object} opts configuration \n * @param {object} ee the event emitter\n * @return {object} client \n */\nfunction setupFinalStep(obj, opts, ee) {\n const client = setupInterCom(obj, opts, ee)\n opts.log(`---> The final step to return the ws-client <---`)\n // add some debug functions \n client.verifyEventEmitter = () => ee.is\n // we add back the two things into the client \n // then when we do integration, we run it in reverse, \n // create the ws client first then the host client \n client.eventEmitter = opts.eventEmitter\n client.log = opts.log\n // we just inject a helloWorld method here \n // client[HELLO_FN] = \n\n return client\n}\n\n\nexport { setupFinalStep }\n\n\n","// resolvers generator\n// we change the interface to return promise from v1.0.3\n// this way we make sure the obj return is correct and timely\nimport { chainFns } from '../utils'\nimport { createAuthMethods } from './setup-auth-methods'\nimport {\n generateResolvers,\n createOnReadyListener,\n createNamespaceErrorListener\n} from './generator-methods'\nimport {\n setupFinalStep \n} from './setup-final-step'\nimport {\n NSP_GROUP\n} from 'jsonql-constants'\n\n/**\n * prepare the methods\n * @param {object} opts configuration\n * @param {object} nspMap resolvers index by their namespace\n * @param {object} ee EventEmitter\n * @return {object} of resolvers\n * @public\n */\nexport function callersGenerator(opts, nspMap, ee) {\n let fns = [\n generateResolvers,\n createOnReadyListener,\n createNamespaceErrorListener\n ]\n if (opts.enableAuth) {\n fns.push(createAuthMethods)\n } \n // we will always get back the [ obj, opts, ee ]\n // then we only return the obj (wsClient)\n fns.push(setupFinalStep)\n // run it\n const generator = Reflect.apply(chainFns, null, fns)\n\n return generator(opts, ee, nspMap[NSP_GROUP])\n}\n","// create options\nimport { \n checkConfigAsync, \n checkConfig \n} from 'jsonql-params-validator'\nimport { \n wsCoreCheckMap, \n wsCoreConstProps, \n socketCheckMap \n} from './defaults'\nimport { \n fixWss, \n getHostName, \n getEventEmitter, \n getNspInfoByConfig,\n getLogFn \n} from '../utils'\n\n/**\n * We need this to find the socket server type \n * @param {*} config \n * @return {string} the name of the socket server if any\n */\nfunction checkSocketClientType(config) {\n return checkConfig(config, socketCheckMap)\n}\n\n/**\n * Create a combine checkConfig for the creating the combine client\n * @param {*} configCheckMap \n * @param {*} constProps \n * @return {function} takes the user input config then resolve the configuration \n */\nfunction createCombineConfigCheck(configCheckMap, constProps) {\n const combineCheckMap = Object.assign({}, configCheckMap, wsCoreCheckMap)\n const combineConstProps = Object.assign({}, constProps, wsCoreConstProps)\n return config => checkConfigAsync(config, combineCheckMap, combineConstProps)\n}\n\n\n/**\n * wrapper method to check this already did the pre check\n * @param {object} config user supply config\n * @param {object} defaultOptions for checking\n * @param {object} constProps user supply const props\n * @return {promise} resolve to the checked opitons\n */\nfunction checkConfiguration(config, defaultOptions, constProps) {\n const defaultCheckMap= Object.assign(wsCoreCheckMap, defaultOptions)\n const wsConstProps = Object.assign(wsCoreConstProps, constProps)\n\n return checkConfigAsync(config, defaultCheckMap, wsConstProps)\n}\n\n/**\n * Taking the `then` part from the method below \n * @param {object} opts \n * @return {promise} opts all done\n */\nfunction postCheckInjectOpts(opts) {\n return Promise.resolve(opts)\n .then(opts => {\n if (!opts.hostname) {\n opts.hostname = getHostName()\n }\n // @TODO the contract now will supply the namespace information\n // and we need to use that to group the namespace call\n opts.wssPath = fixWss([opts.hostname, opts.namespace].join('/'), opts.serverType)\n // get the log function here\n opts.log = getLogFn(opts)\n\n opts.eventEmitter = getEventEmitter(opts)\n\n return opts\n })\n}\n\n/**\n * Don't want to make things confusing\n * Breaking up the opts process in one place \n * then generate the necessary parameter in another step \n * @param {object} opts checked --> merge --> injected \n * @return {object} {opts, nspMap, ee} \n */\nfunction createRequiredParams(opts) {\n return {\n opts,\n nspMap: getNspInfoByConfig(opts),\n ee: opts.eventEmitter \n }\n}\n\nexport {\n // properties \n wsCoreCheckMap,\n wsCoreConstProps,\n // functions \n checkConfiguration,\n postCheckInjectOpts,\n createRequiredParams,\n // this will just get export for integration \n checkSocketClientType,\n createCombineConfigCheck\n}\n","// the top level API\n// The goal is to create a generic method that will able to handle\n// any kind of clients\n// import { injectToFn } from 'jsonql-utils'\nimport { callersGenerator } from './callers'\nimport { \n checkConfiguration, \n postCheckInjectOpts,\n createRequiredParams \n} from './options'\n\n/**\n * 0.5.0 we break up the wsClientCore in two parts one without the config check \n * @param {function} socketClientListerner \n * @return {function} to actually generate the client\n */\nexport function wsClientCoreAction(socketClientListerner) {\n /** \n * This is a breaking change, to continue the onion skin design\n * @param {object} config the already checked config\n * @return {promise} resolve the client\n */ \n return (config = {}) => {\n\n return postCheckInjectOpts(config)\n // the following two moved to wsPostConfig\n .then(createRequiredParams)\n .then(\n ({opts, nspMap, ee}) => socketClientListerner(opts, nspMap, ee)\n )\n .then( // there is problem here, we wrap up the operation inside\n ({opts, nspMap, ee}) => callersGenerator(opts, nspMap, ee)\n )\n .catch(err => {\n console.error(`jsonql-ws-core-client init error`, err)\n })\n }\n}\n\n/**\n * The main interface which will generate the socket clients and map all events\n * @param {object} socketClientListerner this is the one method export by various clients\n * @param {object} [configCheckMap={}] we should do all the checking in the core instead of the client\n * @param {object} [constProps={}] add this to supply the constProps from the downstream client\n * @return {function} accept a config then return the wsClient instance with all the available API\n */\nexport function wsClientCore(socketClientListerner, configCheckMap = {}, constProps = {}) {\n // we need to inject property to this client later\n return (config = {}) => checkConfiguration(config, configCheckMap, constProps)\n .then(wsClientCoreAction(socketClientListerner))\n}\n","// this is getting too confusing \n// therefore we move it back to the framework specific \n\n/**\n * wrapper method to create a nsp without login\n * @param {string|boolean} namespace namespace url could be false\n * @param {object} opts configuration\n * @return {object} ws client instance\n */\nfunction createNspClient(namespace, opts) {\n const { hostname, wssPath, wsOptions, nspClient, log } = opts\n const url = namespace ? [hostname, namespace].join('/') : wssPath\n log(`createNspClient --> `, url)\n\n return nspClient(url, wsOptions)\n}\n\n/**\n * wrapper method to create a nsp with token auth\n * @param {string} namespace namespace url\n * @param {object} opts configuration\n * @return {object} ws client instance\n */\nfunction createNspAuthClient(namespace, opts) {\n const { hostname, wssPath, token, wsOptions, nspAuthClient, log } = opts\n const url = namespace ? [hostname, namespace].join('/') : wssPath\n \n log(`createNspAuthClient -->`, url)\n\n if (token && typeof token !== 'string') {\n throw new Error(`Expect token to be string, but got ${token}`)\n }\n \n return nspAuthClient(url, token, wsOptions)\n}\n\nexport {\n createNspClient,\n createNspAuthClient\n}\n","// this use by client-event-handler\nimport { ON_ERROR_FN_NAME } from 'jsonql-constants'\nimport { createEvt } from '../utils'\n\n/**\n * trigger errors on all the namespace onError handler\n * @param {object} ee Event Emitter\n * @param {array} namespaces nsps string\n * @param {string} message optional\n * @return {void}\n */\nexport function triggerNamespacesOnError(ee, namespaces, message) {\n namespaces.forEach( namespace => {\n ee.$trigger(\n createEvt(namespace, ON_ERROR_FN_NAME), \n [{ message, namespace }]\n )\n })\n}\n\n/**\n * Handle the onerror callback \n * @param {object} ee event emitter \n * @param {string} namespace which namespace has error \n * @param {*} err error object\n * @return {void} \n */\nexport const handleNamespaceOnError = (ee, namespace, err) => {\n ee.$trigger(createEvt(namespace, ON_ERROR_FN_NAME), [err])\n}","// NOT IN USE AT THE MOMENT JUST KEEP IT HERE FOR THE TIME BEING \nimport {\n LOGOUT_EVENT_NAME,\n NOT_LOGIN_ERR_MSG,\n ON_ERROR_FN_NAME,\n ON_RESULT_FN_NAME,\n DISCONNECT_EVENT_NAME\n} from 'jsonql-constants'\nimport { EMIT_EVT, DISCONNECTED_ERROR_MSG } from '../options/constants'\nimport { createEvt, clearMainEmitEvt } from '../utils'\nimport { triggerNamespacesOnError } from './trigger-namespaces-on-error'\n\n/**\n * Only when there is a private namespace then we bind to this event\n * @param {object} nsps the available nsp(s)\n * @param {array} namespaces available namespace \n * @param {object} ee eventEmitter \n * @param {object} opts configuration\n * @return {void}\n */\nexport const logoutEvtListener = (nsps, namespaces, ee, opts) => {\n const { log } = opts \n // this will be available regardless enableAuth\n // because the server can log the client out\n ee.$on(\n LOGOUT_EVENT_NAME, \n function logoutEvtCallback() {\n const privateNamespace = getPrivateNamespace(namespaces)\n log(`${LOGOUT_EVENT_NAME} event triggered`)\n // disconnect(nsps, opts.serverType)\n // we need to issue error to all the namespace onError Listerner\n triggerNamespacesOnError(ee, [privateNamespace], LOGOUT_EVENT_NAME)\n // rebind all of the Listerner to the fake one\n log(`logout from ${privateNamespace}`)\n\n clearMainEmitEvt(ee, privateNamespace)\n // we need to issue one more call to the server before we disconnect\n // now this is a catch 22, here we are not suppose to do anything platform specific\n // so that should fire before trigger this event\n // clear out the nsp\n nsps[privateNamespace] = null \n // add a NOT LOGIN error if call\n notLoginWsListerner(privateNamespace, ee, opts)\n }\n )\n}\n\n/**\n * A Event Listerner placeholder when it's not connect to any nsp\n * @param {string} namespace nsp\n * @param {object} ee EventEmitter\n * @param {object} opts configuration\n * @return {void}\n */\nexport const notConnectedListener = (namespace, ee, opts) => {\n const { log } = opts \n\n ee.$only(\n createEvt(namespace, EMIT_EVT),\n function disconnectedEvtCallback(resolverName, args) {\n log(`[disconnectedListerner] hijack the ws call`, namespace, resolverName, args)\n const error = {\n message: DISCONNECTED_ERROR_MSG\n }\n ee.$call(createEvt(namespace, resolverName, ON_ERROR_FN_NAME), [ error ])\n // also trigger the result Listerner, but wrap inside the error key\n ee.$call(createEvt(namespace, resolverName, ON_RESULT_FN_NAME), [{ error }])\n }\n )\n}\n\n\n/**\n * The disconnect event Listerner, now we log the client out from everything\n * @TODO now we are another problem they disconnect, how to reconnect\n * @param {object} nsps the available nsp(s)\n * @param {array} namespaces available namespace \n * @param {object} ee eventEmitter \n * @param {object} opts configuration\n * @return {void}\n */\nexport const disconnectListener = (nsps, namespaces, ee, opts) => {\n const { log } = opts \n ee.$on(\n DISCONNECT_EVENT_NAME, \n function disconnectEvtCallback() {\n triggerNamespacesOnError(ee, namespaces, DISCONNECT_EVENT_NAME)\n namespaces.forEach( namespace => { \n log(`disconnect from ${namespace}`)\n\n clearMainEmitEvt(ee, namespace)\n nsps[namespace] = null \n disconnectedListerner(namespace, ee, opts)\n })\n }\n )\n}\n\n/**\n * A Event Listerner placeholder when it's not connect to the private nsp\n * @param {string} namespace nsp\n * @param {object} ee EventEmitter\n * @param {object} opts configuration\n * @return {void}\n */\nexport const notLoginListener = (namespace, ee, opts) => {\n const { log } = opts \n\n ee.$only(\n createEvt(namespace, EMIT_EVT),\n function notLoginListernerCallback(resolverName, args) {\n log('[notLoginListerner] hijack the ws call', namespace, resolverName, args)\n const error = { message: NOT_LOGIN_ERR_MSG }\n // It should just throw error here and should not call the result\n // because that's channel for handling normal event not the fake one\n ee.$call(createEvt(namespace, resolverName, ON_ERROR_FN_NAME), [ error ])\n // also trigger the result Listerner, but wrap inside the error key\n ee.$call(createEvt(namespace, resolverName, ON_RESULT_FN_NAME), [{ error }])\n }\n )\n}","// This is share between different clients so we export it\n// @TODO port what is in the ws-main-handler\n// because all the client side call are via the ee\n// and that makes it re-usable between different client setup\n\n/*\nInside the map call but we take it out for now and until the WebSocket version is fully working\nimport { SOCKET_IO } from '../options/constants'\n // @TODO need to double check this\n if (opts.serverType === SOCKET_IO) {\n let { nspGroup } = nspMap\n args.push(nspGroup[namespace])\n }\n*/\nimport { getPrivateNamespace } from 'jsonql-utils/src/namespace'\nimport { logoutEvtListener, notLoginListener } from './event-listeners'\n\n\n/**\n * centralize all the comm in one place\n * @param {function} bindSocketEventHandler binding the ee to ws --> this is the core bit\n * @param {object} nsps namespaced nsp\n * @return {void} nothing\n */\nexport function clientEventListener(bindSocketEventListener, nsps) {\n /**\n * BREAKING CHANGE instead of one flat structure\n * we return a function to accept the two \n * @param {object} opts configuration\n * @param {object} nspMap this is not in the opts \n * @param {object} ee Event Emitter instance\n * @return {array} although we return something but this is the last step and nothing to do further\n */\n return (opts, nspMap, ee) => {\n // since all these params already in the opts\n const { log } = opts\n const { namespaces } = nspMap\n // @1.1.3 add isPrivate prop to id which namespace is the private nsp\n // then we can use this prop to determine if we need to fire the ON_LOGIN_PROP_NAME event\n const privateNamespace = getPrivateNamespace(namespaces)\n \n return namespaces.map(namespace => {\n let isPrivate = privateNamespace === namespace\n log(namespace, ` --> ${isPrivate ? 'private': 'public'} nsp --> `, nsps[namespace] !== false)\n if (nsps[namespace]) {\n log('[call bindWsHandler]', isPrivate, namespace)\n\n let args = [namespace, nsps[namespace], ee, isPrivate, opts]\n // Finally we binding everything together\n Reflect.apply(bindSocketEventListener, null, args)\n\n } else {\n log(`binding notLoginWsHandler to ${namespace}`)\n // a dummy placeholder\n // @TODO but it should be a not connect handler \n // when it's not login (or fail) this should be handle differently \n notLoginListener(namespace, ee, opts)\n }\n if (isPrivate) {\n log(`Has private and add logoutEvtHandler`)\n logoutEvtListener(nsps, namespaces, ee, opts)\n }\n // just return something its not going to get use anywhere\n return isPrivate \n })\n }\n}\n","// jsonql-ws-core takes over the check configuration\n// here we only have to supply the options that is unique to this client\n// create options\nimport { JS_WS_NAME } from 'jsonql-constants'\n// constant props\nconst wsClientConstProps = {\n version: '__PLACEHOLDER__', // will get replace\n serverType: JS_WS_NAME\n}\n\nexport { wsClientConstProps }\n","// pass the different type of ws to generate the client\n// this is where the framework specific code get injected\nimport { TOKEN_PARAM_NAME } from 'jsonql-constants'\nimport { fixWss } from '../modules'\nimport {\n createInitPing, \n extractPingResult\n} from '../modules'\n\n/**\n * Group the ping and get respond create new client in one\n * @param {object} ws \n * @param {object} WebSocket \n * @param {string} url\n * @param {function} resolver \n * @param {function} rejecter \n * @param {boolean} auth client or not\n * @return {promise} resolve the confirm client\n */\nfunction initPingAction(ws, WebSocket, url, resolver, rejecter, wsOptions) {\n // @TODO how to we id this client can issue a CSRF\n // by origin? \n ws.onopen = function onOpenCallback() {\n ws.send(createInitPing())\n }\n\n ws.onmessage = function onMessageCallback(payload) {\n try {\n const header = extractPingResult(payload.data)\n // @NOTE the break down test in ws-client-core show no problems\n // the problem was cause by malform nspInfo that time? \n setTimeout(() => { // delay or not show no different but just on the safe side\n ws.terminate()\n }, 50)\n const newWs = new WebSocket(url, Object.assign(wsOptions, header)) \n resolver(newWs) \n } catch(e) {\n rejecter(e)\n }\n }\n\n ws.onerror = function onErrorCallback(err) {\n rejecter(err)\n }\n}\n\n/**\n * less duplicated code the better \n * @param {object} WebSocket \n * @param {string} url formatted url\n * @param {object} options or not\n * @return {promise} resolve the actual verified client\n */\nfunction asyncConnect(WebSocket, url, options) {\n \n return new Promise((resolver, rejecter) => { \n \n const unconfirmClient = new WebSocket(url, options)\n \n initPingAction(unconfirmClient, WebSocket, url, resolver, rejecter, options)\n })\n}\n\n\n/**\n * The bug was in the wsOptions where ws don't need it but socket.io do\n * therefore the object was pass as second parameter!\n * @NOTE here we only return a method to create the client, it might not get call \n * @param {object} WebSocket the client or node version of ws\n * @param {boolean} auth if it's auth then 3 param or just one\n * @param {object} opts this is a breaking change we will init the client twice\n */\nfunction initWebSocketClient(WebSocket, auth, log) {\n if (auth === false) {\n /**\n * Create a non-protected client\n * @param {string} url \n * @param {object} [wsOptions={}]\n * @return {promise} resolve to the confirmed client\n */\n return function createWsClient(url, wsOptions = {}) {\n const _url = fixWss(url)\n log(`nspClient: \\n${_url}\\n`, wsOptions)\n\n return asyncConnect(WebSocket, _url, wsOptions)\n }\n }\n\n /**\n * Create a client with auth token\n * @param {string} url start with ws:// @TODO check this?\n * @param {string} token the jwt token\n * @param {object} [wsOptions={}] extra options pass to the WebSocket object\n * @return {object} ws instance\n */\n return function createWsAuthClient(url, token, wsOptions = {}) {\n const ws_url = fixWss(url)\n // console.log('what happen here?', url, ws_url, token)\n const _url = token && typeof token === 'string' ? `${ws_url}?${TOKEN_PARAM_NAME}=${token}` : ws_url\n log(`nspAuthClient: \\n${_url}\\n`, wsOptions)\n\n return asyncConnect(WebSocket, _url, wsOptions)\n }\n}\n\nexport { initWebSocketClient }","/** Used for built-in method references. */\nvar objectProto = Object.prototype;\n\n/**\n * Used to resolve the\n * [`toStringTag`](http://ecma-international.org/ecma-262/7.0/#sec-object.prototype.tostring)\n * of values.\n */\nvar nativeObjectToString = objectProto.toString;\n\n/**\n * Converts `value` to a string using `Object.prototype.toString`.\n *\n * @private\n * @param {*} value The value to convert.\n * @returns {string} Returns the converted string.\n */\nfunction objectToString(value) {\n return nativeObjectToString.call(value);\n}\n\nexport default objectToString;\n","/**\n * Creates a unary function that invokes `func` with its argument transformed.\n *\n * @private\n * @param {Function} func The function to wrap.\n * @param {Function} transform The argument transform.\n * @returns {Function} Returns the new function.\n */\nfunction overArg(func, transform) {\n return function(arg) {\n return func(transform(arg));\n };\n}\n\nexport default overArg;\n","/**\n * Checks if `value` is object-like. A value is object-like if it's not `null`\n * and has a `typeof` result of \"object\".\n *\n * @static\n * @memberOf _\n * @since 4.0.0\n * @category Lang\n * @param {*} value The value to check.\n * @returns {boolean} Returns `true` if `value` is object-like, else `false`.\n * @example\n *\n * _.isObjectLike({});\n * // => true\n *\n * _.isObjectLike([1, 2, 3]);\n * // => true\n *\n * _.isObjectLike(_.noop);\n * // => false\n *\n * _.isObjectLike(null);\n * // => false\n */\nfunction isObjectLike(value) {\n return value != null && typeof value == 'object';\n}\n\nexport default isObjectLike;\n","/**\n * Removes all key-value entries from the list cache.\n *\n * @private\n * @name clear\n * @memberOf ListCache\n */\nfunction listCacheClear() {\n this.__data__ = [];\n this.size = 0;\n}\n\nexport default listCacheClear;\n","/**\n * Performs a\n * [`SameValueZero`](http://ecma-international.org/ecma-262/7.0/#sec-samevaluezero)\n * comparison between two values to determine if they are equivalent.\n *\n * @static\n * @memberOf _\n * @since 4.0.0\n * @category Lang\n * @param {*} value The value to compare.\n * @param {*} other The other value to compare.\n * @returns {boolean} Returns `true` if the values are equivalent, else `false`.\n * @example\n *\n * var object = { 'a': 1 };\n * var other = { 'a': 1 };\n *\n * _.eq(object, object);\n * // => true\n *\n * _.eq(object, other);\n * // => false\n *\n * _.eq('a', 'a');\n * // => true\n *\n * _.eq('a', Object('a'));\n * // => false\n *\n * _.eq(NaN, NaN);\n * // => true\n */\nfunction eq(value, other) {\n return value === other || (value !== value && other !== other);\n}\n\nexport default eq;\n","/**\n * Removes `key` and its value from the stack.\n *\n * @private\n * @name delete\n * @memberOf Stack\n * @param {string} key The key of the value to remove.\n * @returns {boolean} Returns `true` if the entry was removed, else `false`.\n */\nfunction stackDelete(key) {\n var data = this.__data__,\n result = data['delete'](key);\n\n this.size = data.size;\n return result;\n}\n\nexport default stackDelete;\n","/**\n * Gets the stack value for `key`.\n *\n * @private\n * @name get\n * @memberOf Stack\n * @param {string} key The key of the value to get.\n * @returns {*} Returns the entry value.\n */\nfunction stackGet(key) {\n return this.__data__.get(key);\n}\n\nexport default stackGet;\n","/**\n * Checks if a stack value for `key` exists.\n *\n * @private\n * @name has\n * @memberOf Stack\n * @param {string} key The key of the entry to check.\n * @returns {boolean} Returns `true` if an entry for `key` exists, else `false`.\n */\nfunction stackHas(key) {\n return this.__data__.has(key);\n}\n\nexport default stackHas;\n","/**\n * Checks if `value` is the\n * [language type](http://www.ecma-international.org/ecma-262/7.0/#sec-ecmascript-language-types)\n * of `Object`. (e.g. arrays, functions, objects, regexes, `new Number(0)`, and `new String('')`)\n *\n * @static\n * @memberOf _\n * @since 0.1.0\n * @category Lang\n * @param {*} value The value to check.\n * @returns {boolean} Returns `true` if `value` is an object, else `false`.\n * @example\n *\n * _.isObject({});\n * // => true\n *\n * _.isObject([1, 2, 3]);\n * // => true\n *\n * _.isObject(_.noop);\n * // => true\n *\n * _.isObject(null);\n * // => false\n */\nfunction isObject(value) {\n var type = typeof value;\n return value != null && (type == 'object' || type == 'function');\n}\n\nexport default isObject;\n","/** Used for built-in method references. */\nvar funcProto = Function.prototype;\n\n/** Used to resolve the decompiled source of functions. */\nvar funcToString = funcProto.toString;\n\n/**\n * Converts `func` to its source code.\n *\n * @private\n * @param {Function} func The function to convert.\n * @returns {string} Returns the source code.\n */\nfunction toSource(func) {\n if (func != null) {\n try {\n return funcToString.call(func);\n } catch (e) {}\n try {\n return (func + '');\n } catch (e) {}\n }\n return '';\n}\n\nexport default toSource;\n","/**\n * Gets the value at `key` of `object`.\n *\n * @private\n * @param {Object} [object] The object to query.\n * @param {string} key The key of the property to get.\n * @returns {*} Returns the property value.\n */\nfunction getValue(object, key) {\n return object == null ? undefined : object[key];\n}\n\nexport default getValue;\n","/**\n * Removes `key` and its value from the hash.\n *\n * @private\n * @name delete\n * @memberOf Hash\n * @param {Object} hash The hash to modify.\n * @param {string} key The key of the value to remove.\n * @returns {boolean} Returns `true` if the entry was removed, else `false`.\n */\nfunction hashDelete(key) {\n var result = this.has(key) && delete this.__data__[key];\n this.size -= result ? 1 : 0;\n return result;\n}\n\nexport default hashDelete;\n","/**\n * Checks if `value` is suitable for use as unique object key.\n *\n * @private\n * @param {*} value The value to check.\n * @returns {boolean} Returns `true` if `value` is suitable, else `false`.\n */\nfunction isKeyable(value) {\n var type = typeof value;\n return (type == 'string' || type == 'number' || type == 'symbol' || type == 'boolean')\n ? (value !== '__proto__')\n : (value === null);\n}\n\nexport default isKeyable;\n","/**\n * Creates a base function for methods like `_.forIn` and `_.forOwn`.\n *\n * @private\n * @param {boolean} [fromRight] Specify iterating from right to left.\n * @returns {Function} Returns the new base function.\n */\nfunction createBaseFor(fromRight) {\n return function(object, iteratee, keysFunc) {\n var index = -1,\n iterable = Object(object),\n props = keysFunc(object),\n length = props.length;\n\n while (length--) {\n var key = props[fromRight ? length : ++index];\n if (iteratee(iterable[key], key, iterable) === false) {\n break;\n }\n }\n return object;\n };\n}\n\nexport default createBaseFor;\n","/**\n * Copies the values of `source` to `array`.\n *\n * @private\n * @param {Array} source The array to copy values from.\n * @param {Array} [array=[]] The array to copy values to.\n * @returns {Array} Returns `array`.\n */\nfunction copyArray(source, array) {\n var index = -1,\n length = source.length;\n\n array || (array = Array(length));\n while (++index < length) {\n array[index] = source[index];\n }\n return array;\n}\n\nexport default copyArray;\n","/** Used for built-in method references. */\nvar objectProto = Object.prototype;\n\n/**\n * Checks if `value` is likely a prototype object.\n *\n * @private\n * @param {*} value The value to check.\n * @returns {boolean} Returns `true` if `value` is a prototype, else `false`.\n */\nfunction isPrototype(value) {\n var Ctor = value && value.constructor,\n proto = (typeof Ctor == 'function' && Ctor.prototype) || objectProto;\n\n return value === proto;\n}\n\nexport default isPrototype;\n","/**\n * Checks if `value` is classified as an `Array` object.\n *\n * @static\n * @memberOf _\n * @since 0.1.0\n * @category Lang\n * @param {*} value The value to check.\n * @returns {boolean} Returns `true` if `value` is an array, else `false`.\n * @example\n *\n * _.isArray([1, 2, 3]);\n * // => true\n *\n * _.isArray(document.body.children);\n * // => false\n *\n * _.isArray('abc');\n * // => false\n *\n * _.isArray(_.noop);\n * // => false\n */\nvar isArray = Array.isArray;\n\nexport default isArray;\n","/** Used as references for various `Number` constants. */\nvar MAX_SAFE_INTEGER = 9007199254740991;\n\n/**\n * Checks if `value` is a valid array-like length.\n *\n * **Note:** This method is loosely based on\n * [`ToLength`](http://ecma-international.org/ecma-262/7.0/#sec-tolength).\n *\n * @static\n * @memberOf _\n * @since 4.0.0\n * @category Lang\n * @param {*} value The value to check.\n * @returns {boolean} Returns `true` if `value` is a valid length, else `false`.\n * @example\n *\n * _.isLength(3);\n * // => true\n *\n * _.isLength(Number.MIN_VALUE);\n * // => false\n *\n * _.isLength(Infinity);\n * // => false\n *\n * _.isLength('3');\n * // => false\n */\nfunction isLength(value) {\n return typeof value == 'number' &&\n value > -1 && value % 1 == 0 && value <= MAX_SAFE_INTEGER;\n}\n\nexport default isLength;\n","/**\n * This method returns `false`.\n *\n * @static\n * @memberOf _\n * @since 4.13.0\n * @category Util\n * @returns {boolean} Returns `false`.\n * @example\n *\n * _.times(2, _.stubFalse);\n * // => [false, false]\n */\nfunction stubFalse() {\n return false;\n}\n\nexport default stubFalse;\n","/**\n * The base implementation of `_.unary` without support for storing metadata.\n *\n * @private\n * @param {Function} func The function to cap arguments for.\n * @returns {Function} Returns the new capped function.\n */\nfunction baseUnary(func) {\n return function(value) {\n return func(value);\n };\n}\n\nexport default baseUnary;\n","/**\n * Gets the value at `key`, unless `key` is \"__proto__\" or \"constructor\".\n *\n * @private\n * @param {Object} object The object to query.\n * @param {string} key The key of the property to get.\n * @returns {*} Returns the property value.\n */\nfunction safeGet(object, key) {\n if (key === 'constructor' && typeof object[key] === 'function') {\n return;\n }\n\n if (key == '__proto__') {\n return;\n }\n\n return object[key];\n}\n\nexport default safeGet;\n","/**\n * The base implementation of `_.times` without support for iteratee shorthands\n * or max array length checks.\n *\n * @private\n * @param {number} n The number of times to invoke `iteratee`.\n * @param {Function} iteratee The function invoked per iteration.\n * @returns {Array} Returns the array of results.\n */\nfunction baseTimes(n, iteratee) {\n var index = -1,\n result = Array(n);\n\n while (++index < n) {\n result[index] = iteratee(index);\n }\n return result;\n}\n\nexport default baseTimes;\n","/** Used as references for various `Number` constants. */\nvar MAX_SAFE_INTEGER = 9007199254740991;\n\n/** Used to detect unsigned integer values. */\nvar reIsUint = /^(?:0|[1-9]\\d*)$/;\n\n/**\n * Checks if `value` is a valid array-like index.\n *\n * @private\n * @param {*} value The value to check.\n * @param {number} [length=MAX_SAFE_INTEGER] The upper bounds of a valid index.\n * @returns {boolean} Returns `true` if `value` is a valid index, else `false`.\n */\nfunction isIndex(value, length) {\n var type = typeof value;\n length = length == null ? MAX_SAFE_INTEGER : length;\n\n return !!length &&\n (type == 'number' ||\n (type != 'symbol' && reIsUint.test(value))) &&\n (value > -1 && value % 1 == 0 && value < length);\n}\n\nexport default isIndex;\n","/**\n * This function is like\n * [`Object.keys`](http://ecma-international.org/ecma-262/7.0/#sec-object.keys)\n * except that it includes inherited enumerable properties.\n *\n * @private\n * @param {Object} object The object to query.\n * @returns {Array} Returns the array of property names.\n */\nfunction nativeKeysIn(object) {\n var result = [];\n if (object != null) {\n for (var key in Object(object)) {\n result.push(key);\n }\n }\n return result;\n}\n\nexport default nativeKeysIn;\n","/**\n * This method returns the first argument it receives.\n *\n * @static\n * @since 0.1.0\n * @memberOf _\n * @category Util\n * @param {*} value Any value.\n * @returns {*} Returns `value`.\n * @example\n *\n * var object = { 'a': 1 };\n *\n * console.log(_.identity(object) === object);\n * // => true\n */\nfunction identity(value) {\n return value;\n}\n\nexport default identity;\n","/**\n * A faster alternative to `Function#apply`, this function invokes `func`\n * with the `this` binding of `thisArg` and the arguments of `args`.\n *\n * @private\n * @param {Function} func The function to invoke.\n * @param {*} thisArg The `this` binding of `func`.\n * @param {Array} args The arguments to invoke `func` with.\n * @returns {*} Returns the result of `func`.\n */\nfunction apply(func, thisArg, args) {\n switch (args.length) {\n case 0: return func.call(thisArg);\n case 1: return func.call(thisArg, args[0]);\n case 2: return func.call(thisArg, args[0], args[1]);\n case 3: return func.call(thisArg, args[0], args[1], args[2]);\n }\n return func.apply(thisArg, args);\n}\n\nexport default apply;\n","/**\n * Creates a function that returns `value`.\n *\n * @static\n * @memberOf _\n * @since 2.4.0\n * @category Util\n * @param {*} value The value to return from the new function.\n * @returns {Function} Returns the new constant function.\n * @example\n *\n * var objects = _.times(2, _.constant({ 'a': 1 }));\n *\n * console.log(objects);\n * // => [{ 'a': 1 }, { 'a': 1 }]\n *\n * console.log(objects[0] === objects[1]);\n * // => true\n */\nfunction constant(value) {\n return function() {\n return value;\n };\n}\n\nexport default constant;\n","/** Used to detect hot functions by number of calls within a span of milliseconds. */\nvar HOT_COUNT = 800,\n HOT_SPAN = 16;\n\n/* Built-in method references for those with the same name as other `lodash` methods. */\nvar nativeNow = Date.now;\n\n/**\n * Creates a function that'll short out and invoke `identity` instead\n * of `func` when it's called `HOT_COUNT` or more times in `HOT_SPAN`\n * milliseconds.\n *\n * @private\n * @param {Function} func The function to restrict.\n * @returns {Function} Returns the new shortable function.\n */\nfunction shortOut(func) {\n var count = 0,\n lastCalled = 0;\n\n return function() {\n var stamp = nativeNow(),\n remaining = HOT_SPAN - (stamp - lastCalled);\n\n lastCalled = stamp;\n if (remaining > 0) {\n if (++count >= HOT_COUNT) {\n return arguments[0];\n }\n } else {\n count = 0;\n }\n return func.apply(undefined, arguments);\n };\n}\n\nexport default shortOut;\n","// break it out on its own because\n// it's building from the lodash-es from scratch\n// according to this discussion https://github.com/lodash/lodash/issues/3298\nimport isPlainObject from 'lodash-es/isPlainObject'\nimport merge from 'lodash-es/merge'\n\n/**\n * previously we already make sure the order of the namespaces\n * and attach the auth client to it\n * @param {array} promises array of unresolved promises\n * @param {boolean} asObject if true then merge the result object\n * @return {object} promise resolved with the array of promises resolved results\n */\nexport function chainPromises(promises, asObject = false) {\n return promises.reduce((promiseChain, currentTask) => (\n promiseChain.then(chainResults => (\n currentTask.then(currentResult => (\n asObject === false ? [...chainResults, currentResult] : merge(chainResults, currentResult)\n ))\n ))\n ), Promise.resolve(\n asObject === false ? [] : (isPlainObject(asObject) ? asObject : {})\n ))\n}\n\n\n/**\n * This one return a different result from the chainPromises\n * it will be the same like chainFns that take one promise resolve as the next fn parameter\n * @param {function} initPromise a function that accept param and resolve result\n * @param {array} promises array of function pass that resolve promises\n * @return {promise} resolve the processed result\n */\nexport function chainProcessPromises(initPromise, ...promises) {\n return (...args) => (\n promises.reduce((promiseChain, currentTask) => (\n promiseChain.then(chainResult => (\n currentTask(chainResult)\n )\n )\n ), Reflect.apply(initPromise, null, args))\n )\n}\n","// @BUG when call disconnected \n// this keep causing an \"Disconnect call failed TypeError: Cannot read property 'readyState' of null\"\n// I think that is because it's not login then it can not be disconnect\n// how do we track this state globally\nimport { LOGIN_EVENT_NAME } from 'jsonql-constants'\nimport { clearMainEmitEvt } from '../modules'\n\n/**\n * create a login event handler \n * @param {object} opts configurations \n * @param {object} nspMap contain all the required info\n * @param {object} ee event emitter \n * @return {void}\n */\nexport function loginEventHandler(opts, nspMap, ee) {\n const { log } = opts\n const { namespaces } = nspMap\n\n ee.$only(LOGIN_EVENT_NAME, function loginEventHandlerCallback(tokenFromLoginAction) {\n \n log('createClient LOGIN_EVENT_NAME $only handler')\n\n clearMainEmitEvt(ee, namespaces)\n // console.log('LOGIN_EVENT_NAME', token)\n const newNsps = createNspAction(opts, nspMap, tokenFromLoginAction)\n // rebind it\n Reflect.apply(\n clientEventHandler, // @NOTE is this the problem that cause the hang up?\n null,\n args.concat([newNsps.namespaces, newNsps.nsps])\n )\n })\n}","// bunch of generic helpers\n\nimport isArray from 'lodash-es/isArray'\nimport isPlainObject from 'lodash-es/isPlainObject'\nimport trim from 'lodash-es/trim'\n\n/**\n * DIY in Array\n * @param {array} arr to check from\n * @param {*} value to check against\n * @return {boolean} true on found\n */\nexport const inArray = (arr, value) => !!arr.filter(a => a === value).length\n\n// quick and dirty to turn non array to array\nexport const toArray = (arg) => isArray(arg) ? arg : [arg]\n\n/**\n * parse string to json or just return the original value if error happened\n * @param {*} n input\n * @param {boolean} [t=true] or throw\n * @return {*} json object on success\n */\nexport const parseJson = function(n, t=true) {\n try {\n return JSON.parse(n)\n } catch(e) {\n if (t) {\n return n\n }\n throw new Error(e)\n }\n}\n\n/**\n * @param {object} obj for search\n * @param {string} key target\n * @return {boolean} true on success\n */\nexport const isObjectHasKey = function(obj, key) {\n try {\n const keys = Object.keys(obj)\n return inArray(keys, key)\n } catch(e) {\n // @BUG when the obj is not an OBJECT we got some weird output\n return false\n }\n}\n\n/**\n * create a event name\n * @param {string[]} args\n * @return {string} event name for use\n */\nexport const createEvt = (...args) => args.join('_')\n\n/**\n * simple util method to get the value\n * @param {string} name of the key\n * @param {object} obj to take value from\n * @return {*} the object value id by name or undefined\n */\nexport const getConfigValue = (name, obj) => (\n obj && isPlainObject(obj) ? ( (name in obj) ? obj[name] : undefined ) : undefined\n)\n\n/**\n * small util to make sure the return value is valid JSON object\n * @param {*} n input\n * @return {object} correct JSON object\n */\nexport const toJson = n => {\n if (typeof n === 'string') {\n return parseJson(n)\n }\n return parseJson(JSON.stringify(n))\n}\n\n/**\n * Check several parameter that there is something in the param\n * @param {*} param input\n * @return {boolean}\n */\nexport const isNotEmpty = function(param) {\n return param !== undefined && param !== false && param !== null && trim(param) !== ''\n}\n\n/**\n * Simple check if the prop is function\n * @param {*} prop input\n * @return {boolean} true on success\n */\nexport const isFunc = prop => {\n if (typeof prop === 'function') {\n return true;\n }\n console.error(`Expect to be Function type! Got ${typeof prop}`)\n}\n\n// generic placeholder function\nexport const nil = () => false\n","// custom validation error class\n// when validaton failed\nexport default class JsonqlValidationError extends Error {\n constructor(...args) {\n super(...args)\n\n this.message = args[0]\n this.detail = args[1]\n\n this.className = JsonqlValidationError.name;\n\n if (Error.captureStackTrace) {\n Error.captureStackTrace(this, JsonqlValidationError)\n }\n }\n\n static get name() {\n return 'JsonqlValidationError'\n }\n}\n","/**\n * @param {boolean} sec return in second or not\n * @return {number} timestamp\n */\nexport const timestamp = (sec = false) => {\n let time = Date.now()\n return sec ? Math.floor( time / 1000 ) : time\n}\n","// ported from jsonql-params-validator\n// craete several helper function to construct / extract the payload\n// and make sure they are all the same\nimport {\n PAYLOAD_PARAM_NAME,\n CONDITION_PARAM_NAME,\n RESOLVER_PARAM_NAME,\n QUERY_ARG_NAME,\n TIMESTAMP_PARAM_NAME\n} from 'jsonql-constants'\n\nimport JsonqlValidationError from 'jsonql-errors/src/validation-error'\n\nimport isArray from 'lodash-es/isArray'\nimport isString from 'lodash-es/isString'\nimport isPlainObject from 'lodash-es/isPlainObject'\n\nimport { timestamp } from './timestamp'\nimport { parseJson } from './generic'\n\n/**\n * check if the payload has a timestamp field, then append a new timestamp to it\n * @param {object} payload from the com\n * @return {array} timestamp field with an array value\n */\nexport const handleTimestamp = payload => {\n let ts = payload[TIMESTAMP_PARAM_NAME]\n if (!isArray(ts)) {\n ts = [ts]\n }\n ts.push( timestamp() )\n\n return ts\n}\n\n/**\n * make sure it's an object (it was call formatPayload but it doesn't make sense)\n * @param {*} payload the object comes in could be string based\n * @return {object} the transformed payload\n */\nexport const toPayload = payload => isString(payload) ? parseJson(payload) : payload\n\n/**\n * @param {*} args arguments to send\n *@return {object} formatted payload\n */\nexport const formatPayload = (args) => (\n { [QUERY_ARG_NAME]: args }\n)\n\n/**\n * extract the resolver name from the payload \n * @param {object} payload\n * @return {string} resolver name \n */\nexport function getResolverFromPayload(payload) {\n const keys = Object.keys(payload)\n return keys.filter(key => key !== TIMESTAMP_PARAM_NAME)[0]\n}\n\n/**\n * wrapper method to add the timestamp as well\n * @param {string} resolverName\n * @param {*} payload\n * @return {object} delierable\n */\nexport function createDeliverable(resolverName, payload) {\n return {\n [resolverName]: payload,\n [TIMESTAMP_PARAM_NAME]: [ timestamp() ]\n }\n}\n\n/**\n * @param {string} resolverName name of function\n * @param {array} [args=[]] from the ...args\n * @param {boolean} [jsonp = false] add v1.3.0 to koa\n * @return {object} formatted argument\n */\nexport function createQuery(resolverName, args = [], jsonp = false) {\n if (isString(resolverName) && isArray(args)) {\n let payload = formatPayload(args)\n if (jsonp === true) {\n return payload\n }\n return createDeliverable(resolverName, payload)\n }\n throw new JsonqlValidationError(`[createQuery] expect resolverName to be string and args to be array!`, { resolverName, args })\n}\n\n/**\n * string version of the createQuery\n * @return {string}\n */\nexport function createQueryStr(resolverName, args = [], jsonp = false) {\n return JSON.stringify(createQuery(resolverName, args, jsonp))\n}\n\n/**\n * @param {string} resolverName name of function\n * @param {*} payload to send\n * @param {object} [condition={}] for what\n * @param {boolean} [jsonp = false] add v1.3.0 to koa\n * @return {object} formatted argument\n */\nexport function createMutation(resolverName, payload, condition = {}, jsonp = false) {\n const _payload = {\n [PAYLOAD_PARAM_NAME]: payload,\n [CONDITION_PARAM_NAME]: condition\n }\n if (jsonp === true) {\n return _payload\n }\n if (isString(resolverName)) {\n return createDeliverable(resolverName, _payload)\n }\n throw new JsonqlValidationError(`[createMutation] expect resolverName to be string!`, { resolverName, payload, condition })\n}\n\n/**\n * string version of createMutation\n * @return {string}\n */\nexport function createMutationStr(resolverName, payload, condition = {}, jsonp = false) {\n return JSON.stringify(createMutation(resolverName, payload, condition, jsonp))\n}\n\n/**\n * Extract the parts from payload and format for use\n * @param {string} resolverName name of fn\n * @param {object} payload the incoming json\n * @return {object|boolean} false on failed\n */\nexport function getQueryFromArgs(resolverName, payload) {\n if (resolverName && isPlainObject(payload)) {\n const args = payload[resolverName]\n if (args[QUERY_ARG_NAME]) {\n return {\n [RESOLVER_PARAM_NAME]: resolverName,\n [QUERY_ARG_NAME]: args[QUERY_ARG_NAME],\n [TIMESTAMP_PARAM_NAME]: handleTimestamp(payload)\n }\n }\n }\n return false\n}\n\n/**\n * Share function so no repeat\n * @param {object} payload the payload from client\n * @param {function} processor the last get result method\n * @return {*} result processed result\n */\nfunction processPayload(payload, processor) {\n const p = toPayload(payload)\n const resolverName = getResolverFromPayload(p)\n return Reflect.apply(processor, null, [resolverName, p])\n}\n\n/**\n * extra the payload back\n * @param {*} payload from http call\n * @return {object} resolverName and args\n */\nexport function getQueryFromPayload(payload) {\n const result = processPayload(payload, getQueryFromArgs)\n if (result !== false) {\n return result\n }\n throw new JsonqlValidationError('[getQueryArgs] Payload is malformed!', payload)\n}\n\n/**\n * Further break down from method below for use else where\n * @param {string} resolverName name of fn\n * @param {object} payload payload\n * @return {object|boolean} false on failed\n */\nexport function getMutationFromArgs(resolverName, payload) {\n if (resolverName && isPlainObject(payload)) {\n const args = payload[resolverName]\n if (args) {\n return {\n [RESOLVER_PARAM_NAME]: resolverName,\n [PAYLOAD_PARAM_NAME]: args[PAYLOAD_PARAM_NAME],\n [CONDITION_PARAM_NAME]: args[CONDITION_PARAM_NAME],\n [TIMESTAMP_PARAM_NAME]: handleTimestamp(payload)\n }\n }\n }\n return false\n}\n\n/**\n * @param {object} payload\n * @return {object} resolverName, payload, conditon\n */\nexport function getMutationFromPayload(payload) {\n const result = processPayload(payload, getMutationFromArgs)\n\n if (result !== false) {\n return result\n }\n throw new JsonqlValidationError('[getMutationArgs] Payload is malformed!', payload)\n}\n","// There are the socket related methods ported back from \n// ws-server-core and ws-client-core \nimport {\n WS_REPLY_TYPE,\n WS_EVT_NAME,\n WS_DATA_NAME,\n TIMESTAMP_PARAM_NAME,\n ERROR_KEY,\n EMIT_REPLY_TYPE,\n ACKNOWLEDGE_REPLY_TYPE\n} from 'jsonql-constants'\nimport { JsonqlError } from 'jsonql-errors' \nimport isString from 'lodash-es/isString'\n\nimport { toJson, isObjectHasKey, nil } from './generic'\nimport { timestamp } from './timestamp'\n\nconst PAYLOAD_NOT_DECODED_ERR = 'payload can not decoded'\nconst WS_KEYS = [\n WS_REPLY_TYPE,\n WS_EVT_NAME,\n WS_DATA_NAME\n]\n\n\n/**\n * The ws doesn't have a acknowledge callback like socket.io\n * so we have to DIY one for ws and other that doesn't have it\n * @param {string} type of reply\n * @param {string} resolverName which is replying\n * @param {*} data payload\n * @param {array} [ts= []] the last received ts, if any \n * @return {string} stringify json\n */\nexport const createWsReply = (type, resolverName, data, ts = []) => {\n ts.push(timestamp())\n return JSON.stringify({\n data: {\n [WS_REPLY_TYPE]: type,\n [WS_EVT_NAME]: resolverName,\n [WS_DATA_NAME]: toJson(data)\n },\n [TIMESTAMP_PARAM_NAME]: ts \n })\n}\n\n// extended function \nexport const createReplyMsg = (resolverName, data, ts = []) => (\n createWsReply(EMIT_REPLY_TYPE, resolverName, data, ts)\n)\n\nexport const createAcknowledgeMsg = (resolverName, data, ts = []) => (\n createWsReply(ACKNOWLEDGE_REPLY_TYPE, resolverName, data, ts)\n)\n\n/**\n * @param {string|object} payload should be string when reply but could be transformed\n * @return {boolean} true is OK\n */\nexport const isWsReply = payload => {\n const json = isString(payload) ? toJson(payload) : payload\n const { data } = json\n if (data) {\n let result = WS_KEYS.filter(key => isObjectHasKey(data, key))\n return (result.length === WS_KEYS.length) ? data : false\n }\n return false\n}\n\n/**\n * @param {string|object} data received data\n * @param {function} [cb=nil] this is for extracting the TS field or when it's error\n * @return {object} false on failed\n */\nexport const extractWsPayload = (payload, cb = nil) => {\n try {\n const json = toJson(payload)\n // now handle the data\n let _data\n if ((_data = isWsReply(json)) !== false) {\n // note the ts property is on its own \n cb(TIMESTAMP_PARAM_NAME, json[TIMESTAMP_PARAM_NAME])\n \n return {\n data: toJson(_data[WS_DATA_NAME]),\n resolverName: _data[WS_EVT_NAME],\n type: _data[WS_REPLY_TYPE]\n }\n }\n throw new JsonqlError(PAYLOAD_NOT_DECODED_ERR, payload)\n } catch(e) {\n return cb(ERROR_KEY, e)\n }\n}\n","// the WebSocket main handler\nimport {\n LOGOUT_EVENT_NAME,\n ACKNOWLEDGE_REPLY_TYPE,\n EMIT_REPLY_TYPE,\n ERROR_KEY,\n\n ON_ERROR_FN_NAME,\n ON_MESSAGE_FN_NAME,\n ON_RESULT_FN_NAME,\n ON_READY_FN_NAME,\n ON_LOGIN_FN_NAME\n} from 'jsonql-constants'\nimport {\n createQueryStr,\n createEvt,\n extractWsPayload\n} from 'jsonql-utils/module'\nimport {\n handleNamespaceOnError,\n createIntercomPayload\n} from '../modules'\n\n/**\n * in some edge case we might not even have a resolverName, then\n * we issue a global error for the developer to catch it\n * @param {object} ee event emitter\n * @param {string} namespace nsp\n * @param {string} resolverName resolver\n * @param {object} json decoded payload or error object\n * @return {undefined} nothing return\n */\nconst errorTypeHandler = (ee, namespace, resolverName, json) => {\n let evt = [namespace]\n if (resolverName) {\n evt.push(resolverName)\n }\n evt.push(ON_ERROR_FN_NAME)\n let evtName = Reflect.apply(createEvt, null, evt)\n // test if there is a data field\n let payload = json.data || json\n ee.$trigger(evtName, [payload])\n}\n\n/**\n * Handle the logout event when it's enableAuth\n * @param {object} ee eventEmitter\n * @param {object} ws the WebSocket instance\n * @return {void}\n */\nconst logoutEventListener = (ee, ws) => {\n // listen to the LOGOUT_EVENT_NAME when this is a private nsp\n ee.$on(LOGOUT_EVENT_NAME, function closeEvtHandler() {\n try {\n // @TODO we need find a way to get the userdata\n ws.send(createIntercomPayload(LOGOUT_EVENT_NAME))\n log('terminate ws connection')\n ws.terminate()\n } catch(e) {\n console.error('ws.terminate error', e)\n }\n })\n}\n\n/**\n * Binding the event to socket normally\n * @param {string} namespace\n * @param {object} ws the nsp\n * @param {object} ee EventEmitter\n * @param {boolean} isPrivate to id if this namespace is private or not\n * @param {object} opts configuration\n * @return {object} promise resolve after the onopen event\n */\nexport function bindSocketEventHandler(namespace, ws, ee, isPrivate, opts) {\n const { log } = opts\n // log(`log test, isPrivate:`, isPrivate)\n // connection open\n ws.onopen = function onOpenCallback() {\n\n log('=== ws.onopen listened -->', namespace)\n // we just call the onReady\n ee.$call(ON_READY_FN_NAME)(namespace)\n // need an extra parameter here to id the private nsp\n if (isPrivate) {\n log(`isPrivate and fire the ${ON_LOGIN_FN_NAME}`)\n ee.$call(ON_LOGIN_FN_NAME)(namespace)\n }\n // add listener only after the open is called\n ee.$only(\n createEvt(namespace, EMIT_REPLY_TYPE),\n /**\n * actually send the payload to server\n * @param {string} resolverName\n * @param {array} args NEED TO CHECK HOW WE PASS THIS!\n */\n function wsMainOnEvtHandler(resolverName, args) {\n\n const payload = createQueryStr(resolverName, args)\n log('ws.onopen.send', resolverName, args, payload)\n\n ws.send(payload)\n }\n )\n }\n\n // reply\n // If we change it to the event callback style\n // then the payload will just be the payload and fucks up the extractWsPayload call @TODO\n ws.onmessage = function onMessageCallback(payload) {\n // console.log(`on.message`, typeof payload, payload)\n try {\n // log(`ws.onmessage raw payload`, payload)\n // @TODO the payload actually contain quite a few things - is that changed?\n // type: message, data: data_send_from_server\n const json = extractWsPayload(payload.data)\n const { resolverName, type } = json\n\n log('Respond from server', type, json)\n\n switch (type) {\n case EMIT_REPLY_TYPE:\n let e1 = createEvt(namespace, resolverName, ON_MESSAGE_FN_NAME)\n let r = ee.$trigger(e1, [json])\n log(`EMIT_REPLY_TYPE`, e1, r)\n break\n case ACKNOWLEDGE_REPLY_TYPE:\n let e2 = createEvt(namespace, resolverName, ON_RESULT_FN_NAME)\n let x2 = ee.$trigger(e2, [json])\n log(`ACKNOWLEDGE_REPLY_TYPE`, e2, x2)\n break\n case ERROR_KEY:\n // this is handled error and we won't throw it\n // we need to extract the error from json\n log(`ERROR_KEY`)\n errorTypeHandler(ee, namespace, resolverName, json)\n break\n // @TODO there should be an error type instead of roll into the other two types? TBC\n default:\n // if this happen then we should throw it and halt the operation all together\n log('Unhandled event!', json)\n errorTypeHandler(ee, namespace, resolverName, json)\n // let error = {error: {'message': 'Unhandled event!', type}};\n // ee.$trigger(createEvt(namespace, resolverName, ON_RESULT_FN_NAME), [error])\n }\n } catch(e) {\n console.error(`ws.onmessage error`, e)\n errorTypeHandler(ee, namespace, false, e)\n }\n }\n // when the server close the connection\n ws.onclose = function onCloseCallback() {\n log('ws.onclose callback')\n // @TODO what to do with this\n // ee.$trigger(LOGOUT_EVENT_NAME, [namespace])\n }\n // add a onerror event handler here\n ws.onerror = function onErrorCallback(err) {\n // trigger a global error event\n log(`ws.onerror`, err)\n handleNamespaceOnError(ee, namespace, err)\n }\n\n if (isPrivate) {\n logoutEventListener(ee, ws)\n }\n\n}\n","// actually binding the event client to the socket client\n\n// from the jsonql-ws-client-core\nimport { clientEventListener } from '../modules'\n// local \nimport { createNspAction } from './create-nsp-action'\nimport { loginEventHandler } from './login-event-handler'\nimport { bindSocketEventHandler } from './bind-socket-event-handler'\n\n/**\n * create the NSP(s) and determine if this require auth or not \n * @param {object} opts configuration\n * @param {object} nspMap namespace with resolvers\n * @param {object} ee EventEmitter to pass through\n * @return {object} what comes in what goes out\n */\nfunction createNsp(opts, nspMap, ee) {\n // now create the nsps\n // const { namespaces } = nspMap\n const { token } = opts\n\n return createNspAction(opts, nspMap, token)\n .then(nsps => {\n const listenerFn = clientEventListener(bindSocketEventHandler, nsps)\n // now run it\n listenerFn(opts, nspMap, ee)\n\n if (opts.enableAuth) {\n loginEventHandler(opts, nspMap, ee)\n }\n // return what input\n return { opts, nspMap, ee }\n }) \n}\n\nexport { createNsp }","// breaking up the create-nsp.js file \n// then regroup them back together here \nimport { createNsp } from './create-nsp'\n\nexport default createNsp\n","// share method to create the wsClientResolver\nimport { initWebSocketClient } from './init-websocket-client'\nimport createNsp from '../create-nsp'\nimport { NSP_CLIENT, NSP_AUTH_CLIENT } from 'jsonql-constants'\n\n/**\n * Create the framework <---> jsonql client binding\n * @param {object} frameworkModule the different WebSocket module\n * @return {function} the wsClientResolver\n */\nfunction bindFrameworkToJsonql(frameworkModule) {\n /**\n * wsClientResolver\n * @param {object} opts configuration\n * @param {object} nspMap from the contract\n * @param {object} ee instance of the eventEmitter\n * @return {object} passing the same 3 input out with additional in the opts\n */\n return function createClientBindingAction(opts, nspMap, ee) {\n const { log } = opts\n opts[NSP_CLIENT] = initWebSocketClient(frameworkModule, false, log)\n opts[NSP_AUTH_CLIENT] = initWebSocketClient(frameworkModule, true, log) \n // @1.0.7 remove later once everything fixed \n \n log(`bindFrameworkToJsonql`, ee.name, nspMap)\n // console.log(`contract`, opts.contract)\n return createNsp(opts, nspMap, ee)\n }\n}\n\nexport { bindFrameworkToJsonql }","// this will be the news style interface that will pass to the jsonql-ws-client\n// then return a function for accepting an opts to generate the final\n// client api\nimport WebSocket from 'ws'\nimport createWebSocketBinding from '../core/create-websocket-binding'\n\n/**\n * @param {object} opts configuration\n * @param {object} nspMap from the contract\n * @param {object} ee instance of the eventEmitter\n * @return {object} passing the same 3 input out with additional in the opts\n */\nexport default createWebSocketBinding(WebSocket)\n","// this is the module entry point for node client\nimport {\n wsClientCore\n} from './core/modules'\nimport { wsClientConstProps } from './options'\n\nimport nodeFrameworkSocketEngine from './node/node-framework-socket-engine'\n\n// export back the function and that's it\nexport default function wsNodeClient(config = {}, constProps = {}) {\n const initClientMethod = wsClientCore(\n nodeFrameworkSocketEngine, \n {}, \n Object.assign({}, wsClientConstProps, constProps)\n )\n return initClientMethod(config)\n}\n"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;ACAA;;;;;;;;;ACAA;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;ACAA;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;ACAA;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;"} \ No newline at end of file diff --git a/packages/@jsonql/ws/src/core/create-nsp/bind-socket-event-handler.js b/packages/@jsonql/ws/src/core/create-nsp/bind-socket-event-handler.js index b1ac42bf..0500c950 100644 --- a/packages/@jsonql/ws/src/core/create-nsp/bind-socket-event-handler.js +++ b/packages/@jsonql/ws/src/core/create-nsp/bind-socket-event-handler.js @@ -11,10 +11,10 @@ import { ON_READY_FN_NAME, ON_LOGIN_FN_NAME } from 'jsonql-constants' -import { - createQueryStr, - createEvt, - extractWsPayload +import { + createQueryStr, + createEvt, + extractWsPayload } from 'jsonql-utils/module' import { handleNamespaceOnError, @@ -52,7 +52,7 @@ const logoutEventListener = (ee, ws) => { // listen to the LOGOUT_EVENT_NAME when this is a private nsp ee.$on(LOGOUT_EVENT_NAME, function closeEvtHandler() { try { - // @TODO we need find a way to get the userdata + // @TODO we need find a way to get the userdata ws.send(createIntercomPayload(LOGOUT_EVENT_NAME)) log('terminate ws connection') ws.terminate() @@ -73,32 +73,31 @@ const logoutEventListener = (ee, ws) => { */ export function bindSocketEventHandler(namespace, ws, ee, isPrivate, opts) { const { log } = opts - - log(`log test, isPrivate:`, isPrivate) + // log(`log test, isPrivate:`, isPrivate) // connection open ws.onopen = function onOpenCallback() { - - log('ws.onopen listened') + + log('=== ws.onopen listened -->', namespace) // we just call the onReady - ee.$call(ON_READY_FN_NAME, namespace) + ee.$call(ON_READY_FN_NAME)(namespace) // need an extra parameter here to id the private nsp if (isPrivate) { log(`isPrivate and fire the ${ON_LOGIN_FN_NAME}`) - ee.$call(ON_LOGIN_FN_NAME, namespace) + ee.$call(ON_LOGIN_FN_NAME)(namespace) } // add listener only after the open is called ee.$only( createEvt(namespace, EMIT_REPLY_TYPE), /** * actually send the payload to server - * @param {string} resolverName - * @param {array} args NEED TO CHECK HOW WE PASS THIS! + * @param {string} resolverName + * @param {array} args NEED TO CHECK HOW WE PASS THIS! */ function wsMainOnEvtHandler(resolverName, args) { - + const payload = createQueryStr(resolverName, args) log('ws.onopen.send', resolverName, args, payload) - + ws.send(payload) } ) @@ -111,11 +110,11 @@ export function bindSocketEventHandler(namespace, ws, ee, isPrivate, opts) { // console.log(`on.message`, typeof payload, payload) try { // log(`ws.onmessage raw payload`, payload) - // @TODO the payload actually contain quite a few things - is that changed? + // @TODO the payload actually contain quite a few things - is that changed? // type: message, data: data_send_from_server const json = extractWsPayload(payload.data) const { resolverName, type } = json - + log('Respond from server', type, json) switch (type) { @@ -134,7 +133,7 @@ export function bindSocketEventHandler(namespace, ws, ee, isPrivate, opts) { // we need to extract the error from json log(`ERROR_KEY`) errorTypeHandler(ee, namespace, resolverName, json) - break + break // @TODO there should be an error type instead of roll into the other two types? TBC default: // if this happen then we should throw it and halt the operation all together @@ -154,9 +153,9 @@ export function bindSocketEventHandler(namespace, ws, ee, isPrivate, opts) { // @TODO what to do with this // ee.$trigger(LOGOUT_EVENT_NAME, [namespace]) } - // add a onerror event handler here + // add a onerror event handler here ws.onerror = function onErrorCallback(err) { - // trigger a global error event + // trigger a global error event log(`ws.onerror`, err) handleNamespaceOnError(ee, namespace, err) } diff --git a/packages/@jsonql/ws/tests/ws-client-auth.test.js b/packages/@jsonql/ws/tests/ws-client-auth.test.js index a44b8efe..fe12e36e 100644 --- a/packages/@jsonql/ws/tests/ws-client-auth.test.js +++ b/packages/@jsonql/ws/tests/ws-client-auth.test.js @@ -1,6 +1,6 @@ // standard ws client test without auth const test = require('ava') - +const EventClass = require('@to1source/event') const modulePath = process.env.JSONQL_DEBUG ? '../node-org' : '../main' const wsClient = require(modulePath) @@ -47,35 +47,45 @@ test.before(async t => { hostname: `ws://localhost:${port}`, contract: publicContract, enableAuth: true - }, { log: debug }) + }, { log: debug }) // debug + + t.context.evt = new EventClass() }) test.after(t => { t.context.server.close() }) -// @NOTE here might be the problem, what we might have to do is to suspend all the -// event in the queue, call login, or trigger by the host module to login +// @NOTE here might be the problem, what we might have to do is to suspend all the +// event in the queue, call login, or trigger by the host module to login // then after the login, we release the queue test.serial.cb.only(`Should able to handle multiple onMessage and one onLogin callback`, t => { t.plan(3) + const evt = t.context.evt + let ctn = 0 + evt.$on('run', function() { + ++ctn + if (ctn > 2) { + t.end() + } + }) let client = t.context.client client.onReady = function onReadyCallback(w) { localDebug('onReady -->', w) t.pass() + evt.$trigger('run', []) } client.onReady = function onReadyAgainCallback(w) { - localDebug('onReady again', w) - t.pass() + localDebug('onReady again SHOULD NOT GET FIRE', w) } client.onLogin = function onLoginCallback(n) { localDebug(`onLogin -->`, n) t.pass() - t.end() + evt.$trigger('run', []) } }) @@ -87,7 +97,7 @@ test.serial.cb('It should able to connect to the WebSocket public namespace', t client.pinging('Hello') client.pinging.onResult = res => { - + localDebug('res', res) t.is(res, 'connection established') diff --git a/packages/ws-client-core/src/callers/generator-methods.js b/packages/ws-client-core/src/callers/generator-methods.js index acb302ed..b421ac5a 100644 --- a/packages/ws-client-core/src/callers/generator-methods.js +++ b/packages/ws-client-core/src/callers/generator-methods.js @@ -11,11 +11,11 @@ import { finalCatch } from 'jsonql-errors' import { validateAsync } from 'jsonql-params-validator' import { setupResolver } from './setup-resolver' import { actionCall } from './action-call' -import { - createEvt, - objDefineProps, - isFunc, - injectToFn +import { + createEvt, + objDefineProps, + isFunc, + injectToFn } from '../utils' import { ON_ERROR_FN_NAME, @@ -28,7 +28,7 @@ import { * @param {string} namespace this resolver end point * @param {string} resolverName name of resolver as event name * @param {object} params from contract - * @param {function} log pass the log function + * @param {function} log pass the log function * @return {function} resolver */ function createResolver(ee, namespace, resolverName, params, log) { @@ -50,7 +50,7 @@ function createResolver(ee, namespace, resolverName, params, log) { export function generateResolvers(opts, ee, nspGroup) { let client= {} let { log } = opts - + for (let namespace in nspGroup) { let list = nspGroup[namespace] for (let resolverName in list) { @@ -60,8 +60,8 @@ export function generateResolvers(opts, ee, nspGroup) { // this should set as a getter therefore can not be overwrite by accident // obj[resolverName] = setupResolver(namespace, resolverName, params, fn, ee) client = injectToFn( - client, - resolverName, + client, + resolverName, setupResolver(namespace, resolverName, params, fn, ee, log) ) } @@ -78,13 +78,13 @@ export function generateResolvers(opts, ee, nspGroup) { * @param {object} opts configuration * @param {object} ee Event Emitter * @param {object} nspGroup namespace keys - * @return {array} [obj, opts, ee] + * @return {array} [obj, opts, ee] */ export function createNamespaceErrorListener(client, opts, ee, nspGroup) { return [ objDefineProps( - client, - ON_ERROR_FN_NAME, + client, + ON_ERROR_FN_NAME, function namespaceErrorCallbackHandler(namespaceErrorHandler) { if (isFunc(namespaceErrorHandler)) { // please note ON_ERROR_FN_NAME can add multiple listners @@ -111,12 +111,14 @@ export function createNamespaceErrorListener(client, opts, ee, nspGroup) { export function createOnReadyListener(client, opts, ee) { return [ objDefineProps( - client, - ON_READY_FN_NAME, + client, + ON_READY_FN_NAME, function onReadyCallbackHandler(onReadyCallback) { if (isFunc(onReadyCallback)) { // reduce it down to just one flat level - ee.$on(ON_READY_FN_NAME, onReadyCallback) + // @2020-03-19 only allow ONE onReady callback otherwise + // it will get fire multiple times which is not what we want + ee.$only(ON_READY_FN_NAME, onReadyCallback) } } ), @@ -124,7 +126,3 @@ export function createOnReadyListener(client, opts, ee) { ee ] } - - - - -- Gitee From 7144d2d39576317ad2ad0a8cc35d411a294a6ee1 Mon Sep 17 00:00:00 2001 From: joelchu Date: Thu, 19 Mar 2020 23:51:10 +0800 Subject: [PATCH 03/11] Still not able to fix the return result problem --- packages/@jsonql/ws/tests/ws-client-auth.test.js | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/packages/@jsonql/ws/tests/ws-client-auth.test.js b/packages/@jsonql/ws/tests/ws-client-auth.test.js index fe12e36e..294afd07 100644 --- a/packages/@jsonql/ws/tests/ws-client-auth.test.js +++ b/packages/@jsonql/ws/tests/ws-client-auth.test.js @@ -59,7 +59,7 @@ test.after(t => { // @NOTE here might be the problem, what we might have to do is to suspend all the // event in the queue, call login, or trigger by the host module to login // then after the login, we release the queue -test.serial.cb.only(`Should able to handle multiple onMessage and one onLogin callback`, t => { +test.serial.cb(`Should able to handle multiple onMessage and one onLogin callback`, t => { t.plan(3) const evt = t.context.evt let ctn = 0 @@ -91,24 +91,22 @@ test.serial.cb.only(`Should able to handle multiple onMessage and one onLogin ca }) -test.serial.cb('It should able to connect to the WebSocket public namespace', t => { +test.serial.cb.skip('It should able to connect to the WebSocket public namespace', t => { t.plan(2) let client = t.context.client client.pinging('Hello') client.pinging.onResult = res => { - localDebug('res', res) - t.is(res, 'connection established') - client.pinging.send = 'ping'; + client.pinging.send('ping') } // start the ping pong game client.pinging.onMessage = function(msg) { if (msg==='pong') { - client.pinging.send = 'pong'; + client.pinging.send('pong') } else { - client.pinging.send = 'giving up'; + client.pinging.send('giving up') t.is(msg, 'ping') t.end() } -- Gitee From a9805d98a9adfbebee7b8aa75b53975287fcacc5 Mon Sep 17 00:00:00 2001 From: joelchu Date: Fri, 20 Mar 2020 12:02:24 +0800 Subject: [PATCH 04/11] change the sequence how the generator run, move the final step out and add hook at the potential places where we can first suspend all the operation --- packages/ws-client-core/src/api.js | 31 +++++---- .../src/callers/callers-generator.js | 10 +-- packages/ws-client-core/src/callers/index.js | 22 +++---- .../src/callers/setup-final-step.js | 25 ++++--- packages/ws-client-core/src/options/index.js | 66 ++++++++++--------- 5 files changed, 81 insertions(+), 73 deletions(-) diff --git a/packages/ws-client-core/src/api.js b/packages/ws-client-core/src/api.js index 04106bc2..52072cd6 100644 --- a/packages/ws-client-core/src/api.js +++ b/packages/ws-client-core/src/api.js @@ -2,35 +2,40 @@ // The goal is to create a generic method that will able to handle // any kind of clients // import { injectToFn } from 'jsonql-utils' -import { callersGenerator } from './callers' -import { - checkConfiguration, +import { + callersGenerator, + setupFinalStep +} from './callers' +import { + checkConfiguration, postCheckInjectOpts, - createRequiredParams + createRequiredParams } from './options' + /** - * 0.5.0 we break up the wsClientCore in two parts one without the config check - * @param {function} socketClientListerner + * 0.5.0 we break up the wsClientCore in two parts one without the config check + * @param {function} socketClientListener * @return {function} to actually generate the client */ -export function wsClientCoreAction(socketClientListerner) { - /** +export function wsClientCoreAction(socketClientListener) { + /** * This is a breaking change, to continue the onion skin design * @param {object} config the already checked config * @return {promise} resolve the client - */ + */ return (config = {}) => { return postCheckInjectOpts(config) // the following two moved to wsPostConfig .then(createRequiredParams) .then( - ({opts, nspMap, ee}) => socketClientListerner(opts, nspMap, ee) + ({opts, nspMap, ee}) => socketClientListener(opts, nspMap, ee) ) .then( // there is problem here, we wrap up the operation inside ({opts, nspMap, ee}) => callersGenerator(opts, nspMap, ee) ) + .then(setupFinalStep) .catch(err => { console.error(`jsonql-ws-core-client init error`, err) }) @@ -44,8 +49,10 @@ export function wsClientCoreAction(socketClientListerner) { * @param {object} [constProps={}] add this to supply the constProps from the downstream client * @return {function} accept a config then return the wsClient instance with all the available API */ -export function wsClientCore(socketClientListerner, configCheckMap = {}, constProps = {}) { +export function wsClientCore(socketClientListener, configCheckMap = {}, constProps = {}) { // we need to inject property to this client later return (config = {}) => checkConfiguration(config, configCheckMap, constProps) - .then(wsClientCoreAction(socketClientListerner)) + .then( + wsClientCoreAction(socketClientListener) + ) } diff --git a/packages/ws-client-core/src/callers/callers-generator.js b/packages/ws-client-core/src/callers/callers-generator.js index 7dec6b11..7babd87f 100644 --- a/packages/ws-client-core/src/callers/callers-generator.js +++ b/packages/ws-client-core/src/callers/callers-generator.js @@ -8,9 +8,7 @@ import { createOnReadyListener, createNamespaceErrorListener } from './generator-methods' -import { - setupFinalStep -} from './setup-final-step' + import { NSP_GROUP } from 'jsonql-constants' @@ -31,10 +29,12 @@ export function callersGenerator(opts, nspMap, ee) { ] if (opts.enableAuth) { fns.push(createAuthMethods) - } + } // we will always get back the [ obj, opts, ee ] // then we only return the obj (wsClient) - fns.push(setupFinalStep) + // This has move outside of here, into the main method + // the reason is we could switch around the sequence much easier + // fns.push(setupFinalStep) // run it const generator = Reflect.apply(chainFns, null, fns) diff --git a/packages/ws-client-core/src/callers/index.js b/packages/ws-client-core/src/callers/index.js index 526e05b9..22c255fe 100644 --- a/packages/ws-client-core/src/callers/index.js +++ b/packages/ws-client-core/src/callers/index.js @@ -1,23 +1,23 @@ // just doing the import export thing here // we move the following methods from listener to callers -// because they are actually sending things out not react to anything +// because they are actually sending things out not react to anything import { - helloWorld -} from './hello' -import { - createInitPing, - extractPingResult, + createInitPing, + extractPingResult, createIntercomPayload, extractSrvPayload } from './intercom-methods' - +import { helloWorld } from './hello' import { callersGenerator } from './callers-generator' +import { setupFinalStep } from './setup-final-setup' + // just rename it -export { +export { helloWorld, - createInitPing, - extractPingResult, + createInitPing, + extractPingResult, createIntercomPayload, extractSrvPayload, - callersGenerator + callersGenerator, + setupFinalStep } diff --git a/packages/ws-client-core/src/callers/setup-final-step.js b/packages/ws-client-core/src/callers/setup-final-step.js index d7c25047..56a97821 100644 --- a/packages/ws-client-core/src/callers/setup-final-step.js +++ b/packages/ws-client-core/src/callers/setup-final-step.js @@ -1,31 +1,28 @@ // The final step of the setup before it returns the client import { setupInterCom } from './setup-intercom' -// import { HELLO_FN } from 'jsonql-constants' -/** - * The final step to return the client - * @param {object} client the client - * @param {object} opts configuration +/** + * The final step to return the client + * @param {object} client the client + * @param {object} opts configuration * @param {object} ee the event emitter - * @return {object} client + * @return {object} client */ function setupFinalStep(obj, opts, ee) { const client = setupInterCom(obj, opts, ee) opts.log(`---> The final step to return the ws-client <---`) - // add some debug functions + // add some debug functions client.verifyEventEmitter = () => ee.is - // we add back the two things into the client - // then when we do integration, we run it in reverse, - // create the ws client first then the host client + // we add back the two things into the client + // then when we do integration, we run it in reverse, + // create the ws client first then the host client client.eventEmitter = opts.eventEmitter client.log = opts.log - // we just inject a helloWorld method here - // client[HELLO_FN] = + // we just inject a helloWorld method here + // client[HELLO_FN] = return client } export { setupFinalStep } - - diff --git a/packages/ws-client-core/src/options/index.js b/packages/ws-client-core/src/options/index.js index 33676b28..a2bd7853 100644 --- a/packages/ws-client-core/src/options/index.js +++ b/packages/ws-client-core/src/options/index.js @@ -1,24 +1,24 @@ // create options -import { - checkConfigAsync, - checkConfig +import { + checkConfigAsync, + checkConfig } from 'jsonql-params-validator' -import { - wsCoreCheckMap, - wsCoreConstProps, - socketCheckMap +import { + wsCoreCheckMap, + wsCoreConstProps, + socketCheckMap } from './defaults' -import { - fixWss, - getHostName, - getEventEmitter, +import { + fixWss, + getHostName, + getEventEmitter, getNspInfoByConfig, - getLogFn + getLogFn } from '../utils' /** - * We need this to find the socket server type - * @param {*} config + * We need this to find the socket server type + * @param {*} config * @return {string} the name of the socket server if any */ function checkSocketClientType(config) { @@ -27,9 +27,9 @@ function checkSocketClientType(config) { /** * Create a combine checkConfig for the creating the combine client - * @param {*} configCheckMap - * @param {*} constProps - * @return {function} takes the user input config then resolve the configuration + * @param {*} configCheckMap + * @param {*} constProps + * @return {function} takes the user input config then resolve the configuration */ function createCombineConfigCheck(configCheckMap, constProps) { const combineCheckMap = Object.assign({}, configCheckMap, wsCoreCheckMap) @@ -53,8 +53,8 @@ function checkConfiguration(config, defaultOptions, constProps) { } /** - * Taking the `then` part from the method below - * @param {object} opts + * Taking the `then` part from the method below + * @param {object} opts * @return {promise} opts all done */ function postCheckInjectOpts(opts) { @@ -77,28 +77,32 @@ function postCheckInjectOpts(opts) { /** * Don't want to make things confusing - * Breaking up the opts process in one place - * then generate the necessary parameter in another step - * @param {object} opts checked --> merge --> injected - * @return {object} {opts, nspMap, ee} + * Breaking up the opts process in one place + * then generate the necessary parameter in another step + * @2020-3-20 here we suspend operation by it's namespace first + * Then in the framework part, after the connection establish we release + * the queue + * @param {object} opts checked --> merge --> injected + * @return {object} {opts, nspMap, ee} */ function createRequiredParams(opts) { - return { - opts, - nspMap: getNspInfoByConfig(opts), - ee: opts.eventEmitter - } + const nspMap = getNspInfoByConfig(opts) + const ee = opts.eventEmitter + // @TODO here we are going to add suspend event to the namespace related methods + + + return { opts, nspMap, ee } } export { - // properties + // properties wsCoreCheckMap, wsCoreConstProps, - // functions + // functions checkConfiguration, postCheckInjectOpts, createRequiredParams, - // this will just get export for integration + // this will just get export for integration checkSocketClientType, createCombineConfigCheck } -- Gitee From 023d9896bbfa30890a577813cc404c959cd42ec9 Mon Sep 17 00:00:00 2001 From: joelchu Date: Fri, 20 Mar 2020 14:50:11 +0800 Subject: [PATCH 05/11] Add a simpler to stop the onReady get call more than the number of namespaces available --- .../ws/src/core/create-nsp/bind-socket-event-handler.js | 7 +++++++ packages/@jsonql/ws/tests/ws-client-auth.test.js | 5 +++++ 2 files changed, 12 insertions(+) diff --git a/packages/@jsonql/ws/src/core/create-nsp/bind-socket-event-handler.js b/packages/@jsonql/ws/src/core/create-nsp/bind-socket-event-handler.js index 0500c950..780590fd 100644 --- a/packages/@jsonql/ws/src/core/create-nsp/bind-socket-event-handler.js +++ b/packages/@jsonql/ws/src/core/create-nsp/bind-socket-event-handler.js @@ -73,6 +73,7 @@ const logoutEventListener = (ee, ws) => { */ export function bindSocketEventHandler(namespace, ws, ee, isPrivate, opts) { const { log } = opts + let onReadCalls = 2 // log(`log test, isPrivate:`, isPrivate) // connection open ws.onopen = function onOpenCallback() { @@ -80,6 +81,12 @@ export function bindSocketEventHandler(namespace, ws, ee, isPrivate, opts) { log('=== ws.onopen listened -->', namespace) // we just call the onReady ee.$call(ON_READY_FN_NAME)(namespace) + // we only want to allow it get call twice (number of namespaces) + --onReadCalls + if (onReadCalls === 0) { + ee.$off(ON_READY_FN_NAME) + } + // need an extra parameter here to id the private nsp if (isPrivate) { log(`isPrivate and fire the ${ON_LOGIN_FN_NAME}`) diff --git a/packages/@jsonql/ws/tests/ws-client-auth.test.js b/packages/@jsonql/ws/tests/ws-client-auth.test.js index 294afd07..976913e0 100644 --- a/packages/@jsonql/ws/tests/ws-client-auth.test.js +++ b/packages/@jsonql/ws/tests/ws-client-auth.test.js @@ -94,6 +94,11 @@ test.serial.cb(`Should able to handle multiple onMessage and one onLogin callbac test.serial.cb.skip('It should able to connect to the WebSocket public namespace', t => { t.plan(2) let client = t.context.client + + const evt = t.context.evt + + + client.pinging('Hello') client.pinging.onResult = res => { -- Gitee From 5b782d310147a9a83e617f7af57c233fc08f7023 Mon Sep 17 00:00:00 2001 From: joelchu Date: Fri, 20 Mar 2020 14:59:34 +0800 Subject: [PATCH 06/11] update the test to use event to track the completion --- .../@jsonql/ws/tests/ws-client-auth.test.js | 34 +++++++++++++++---- 1 file changed, 28 insertions(+), 6 deletions(-) diff --git a/packages/@jsonql/ws/tests/ws-client-auth.test.js b/packages/@jsonql/ws/tests/ws-client-auth.test.js index 976913e0..23068daa 100644 --- a/packages/@jsonql/ws/tests/ws-client-auth.test.js +++ b/packages/@jsonql/ws/tests/ws-client-auth.test.js @@ -92,18 +92,27 @@ test.serial.cb(`Should able to handle multiple onMessage and one onLogin callbac test.serial.cb.skip('It should able to connect to the WebSocket public namespace', t => { - t.plan(2) + let ctn = 2 + t.plan(ctn) let client = t.context.client - + const evtName = 'run-1' const evt = t.context.evt - + evt.$on(evtName, function() { + --ctn + if (ctn === 0) { + t.end() + } + }) client.pinging('Hello') client.pinging.onResult = res => { localDebug('res', res) t.is(res, 'connection established') + + evt.$trigger(evtName, []) + client.pinging.send('ping') } // start the ping pong game @@ -113,14 +122,26 @@ test.serial.cb.skip('It should able to connect to the WebSocket public namespace } else { client.pinging.send('giving up') t.is(msg, 'ping') - t.end() + + evt.$trigger(evtName, []) } } }) test.serial.cb('It should able to connect to a WebSocket private namespace', t => { - t.plan(2) + let ctn = 2 + t.plan(ctn) + let client = t.context.client + const evtName = 'run-2' + const evt = t.context.evt + + evt.$on(evtName, function() { + --ctn + if (ctn === 0) { + t.end() + } + }) let client = t.context.client @@ -128,11 +149,12 @@ test.serial.cb('It should able to connect to a WebSocket private namespace', t = client.sendExtraMsg.onResult = function onResultCallback(result) { t.is(101, result) - t.end() + evt.$trigger(evtName, []) } client.sendExtraMsg.onMessage = function onMessageCallback(num) { t.is(102, num) + evt.$trigger(evtName, []) } }) -- Gitee From 1054c426ffde8b7cff8cba49bf31a144df22a2ed Mon Sep 17 00:00:00 2001 From: joelchu Date: Fri, 20 Mar 2020 15:10:05 +0800 Subject: [PATCH 07/11] Fix the inter com interface --- packages/@jsonql/ws/main.js | 134 ++++++++++-------- packages/@jsonql/ws/main.js.map | 2 +- .../@jsonql/ws/tests/ws-client-auth.test.js | 4 +- .../src/callers/callers-generator.js | 10 +- .../src/callers/generator-methods.js | 6 +- packages/ws-client-core/src/callers/index.js | 2 +- .../src/callers/setup-auth-methods.js | 22 +-- .../src/callers/setup-final-step.js | 11 +- .../src/callers/setup-intercom.js | 27 ++-- 9 files changed, 121 insertions(+), 97 deletions(-) diff --git a/packages/@jsonql/ws/main.js b/packages/@jsonql/ws/main.js index d757b91a..fd025a70 100644 --- a/packages/@jsonql/ws/main.js +++ b/packages/@jsonql/ws/main.js @@ -7590,6 +7590,36 @@ function createOnReadyListener(client, opts, ee) { ] } +// resolvers generator + +/** + * prepare the methods + * @param {object} opts configuration + * @param {object} nspMap resolvers index by their namespace + * @param {object} ee EventEmitter + * @return {object} of resolvers + * @public + */ +function callersGenerator(opts, nspMap, ee) { + var fns = [ + generateResolvers, + createOnReadyListener, + createNamespaceErrorListener + ]; + if (opts.enableAuth) { + fns.push(createAuthMethods); + } + // we will always get back the [ obj, opts, ee ] + // then we only return the obj (wsClient) + // This has move outside of here, into the main method + // the reason is we could switch around the sequence much easier + // fns.push(setupFinalStep) + // run it + var generator = Reflect.apply(chainFns, null, fns); + + return generator(opts, ee, nspMap[NSP_GROUP]) +} + // this is a new method that will create several /** @@ -7612,59 +7642,30 @@ function setupInterCom(client, opts, ee) { } // The final step of the setup before it returns the client -// import { HELLO_FN } from 'jsonql-constants' -/** - * The final step to return the client - * @param {object} client the client - * @param {object} opts configuration +/** + * The final step to return the client + * @param {object} client the client + * @param {object} opts configuration * @param {object} ee the event emitter - * @return {object} client + * @return {object} client */ function setupFinalStep(obj, opts, ee) { var client = setupInterCom(obj, opts, ee); opts.log("---> The final step to return the ws-client <---"); - // add some debug functions + // add some debug functions client.verifyEventEmitter = function () { return ee.is; }; - // we add back the two things into the client - // then when we do integration, we run it in reverse, - // create the ws client first then the host client + // we add back the two things into the client + // then when we do integration, we run it in reverse, + // create the ws client first then the host client client.eventEmitter = opts.eventEmitter; client.log = opts.log; - // we just inject a helloWorld method here - // client[HELLO_FN] = + // we just inject a helloWorld method here + // client[HELLO_FN] = return client } -// resolvers generator - -/** - * prepare the methods - * @param {object} opts configuration - * @param {object} nspMap resolvers index by their namespace - * @param {object} ee EventEmitter - * @return {object} of resolvers - * @public - */ -function callersGenerator(opts, nspMap, ee) { - var fns = [ - generateResolvers, - createOnReadyListener, - createNamespaceErrorListener - ]; - if (opts.enableAuth) { - fns.push(createAuthMethods); - } - // we will always get back the [ obj, opts, ee ] - // then we only return the obj (wsClient) - fns.push(setupFinalStep); - // run it - var generator = Reflect.apply(chainFns, null, fns); - - return generator(opts, ee, nspMap[NSP_GROUP]) -} - var obj, obj$1, obj$2; // import { AVAILABLE_SERVERS } from './constants' var AVAILABLE_METHODS = [ @@ -7729,8 +7730,8 @@ function checkConfiguration(config, defaultOptions, constProps) { } /** - * Taking the `then` part from the method below - * @param {object} opts + * Taking the `then` part from the method below + * @param {object} opts * @return {promise} opts all done */ function postCheckInjectOpts(opts) { @@ -7753,32 +7754,37 @@ function postCheckInjectOpts(opts) { /** * Don't want to make things confusing - * Breaking up the opts process in one place - * then generate the necessary parameter in another step - * @param {object} opts checked --> merge --> injected - * @return {object} {opts, nspMap, ee} + * Breaking up the opts process in one place + * then generate the necessary parameter in another step + * @2020-3-20 here we suspend operation by it's namespace first + * Then in the framework part, after the connection establish we release + * the queue + * @param {object} opts checked --> merge --> injected + * @return {object} {opts, nspMap, ee} */ function createRequiredParams(opts) { - return { - opts: opts, - nspMap: getNspInfoByConfig(opts), - ee: opts.eventEmitter - } + var nspMap = getNspInfoByConfig(opts); + var ee = opts.eventEmitter; + // @TODO here we are going to add suspend event to the namespace related methods + + + return { opts: opts, nspMap: nspMap, ee: ee } } // the top level API + /** - * 0.5.0 we break up the wsClientCore in two parts one without the config check - * @param {function} socketClientListerner + * 0.5.0 we break up the wsClientCore in two parts one without the config check + * @param {function} socketClientListener * @return {function} to actually generate the client */ -function wsClientCoreAction(socketClientListerner) { - /** +function wsClientCoreAction(socketClientListener) { + /** * This is a breaking change, to continue the onion skin design * @param {object} config the already checked config * @return {promise} resolve the client - */ + */ return function (config) { if ( config === void 0 ) config = {}; @@ -7792,7 +7798,7 @@ function wsClientCoreAction(socketClientListerner) { var nspMap = ref.nspMap; var ee = ref.ee; - return socketClientListerner(opts, nspMap, ee); + return socketClientListener(opts, nspMap, ee); } ) .then( // there is problem here, we wrap up the operation inside @@ -7804,6 +7810,7 @@ function wsClientCoreAction(socketClientListerner) { return callersGenerator(opts, nspMap, ee); } ) + .then(setupFinalStep) .catch(function (err) { console.error("jsonql-ws-core-client init error", err); }) @@ -7817,7 +7824,7 @@ function wsClientCoreAction(socketClientListerner) { * @param {object} [constProps={}] add this to supply the constProps from the downstream client * @return {function} accept a config then return the wsClient instance with all the available API */ -function wsClientCore(socketClientListerner, configCheckMap, constProps) { +function wsClientCore(socketClientListener, configCheckMap, constProps) { if ( configCheckMap === void 0 ) configCheckMap = {}; if ( constProps === void 0 ) constProps = {}; @@ -7826,7 +7833,9 @@ function wsClientCore(socketClientListerner, configCheckMap, constProps) { if ( config === void 0 ) config = {}; return checkConfiguration(config, configCheckMap, constProps) - .then(wsClientCoreAction(socketClientListerner)); + .then( + wsClientCoreAction(socketClientListener) + ); } } @@ -10704,6 +10713,7 @@ var logoutEventListener = function (ee, ws) { */ function bindSocketEventHandler(namespace, ws, ee, isPrivate, opts) { var log = opts.log; + var onReadCalls = 2; // log(`log test, isPrivate:`, isPrivate) // connection open ws.onopen = function onOpenCallback() { @@ -10711,6 +10721,12 @@ function bindSocketEventHandler(namespace, ws, ee, isPrivate, opts) { log('=== ws.onopen listened -->', namespace); // we just call the onReady ee.$call(ON_READY_FN_NAME$1)(namespace); + // we only want to allow it get call twice (number of namespaces) + --onReadCalls; + if (onReadCalls === 0) { + ee.$off(ON_READY_FN_NAME$1); + } + // need an extra parameter here to id the private nsp if (isPrivate) { log(("isPrivate and fire the " + ON_LOGIN_FN_NAME$1)); diff --git a/packages/@jsonql/ws/main.js.map b/packages/@jsonql/ws/main.js.map index 451bcfb7..ce7f074c 100644 --- a/packages/@jsonql/ws/main.js.map +++ b/packages/@jsonql/ws/main.js.map @@ -1 +1 @@ -{"version":3,"file":"main.js","sources":["../../ws-client-core/node_modules/lodash-es/isArray.js","node_modules/rollup-plugin-node-globals/src/global.js","../../ws-client-core/node_modules/lodash-es/_objectToString.js","../../ws-client-core/node_modules/lodash-es/_overArg.js","../../ws-client-core/node_modules/lodash-es/isObjectLike.js","../../ws-client-core/node_modules/lodash-es/_arrayMap.js","../../ws-client-core/node_modules/lodash-es/_baseSlice.js","../../ws-client-core/node_modules/lodash-es/_baseFindIndex.js","../../ws-client-core/node_modules/lodash-es/_baseIsNaN.js","../../ws-client-core/node_modules/lodash-es/_strictIndexOf.js","../../ws-client-core/node_modules/lodash-es/_asciiToArray.js","../../ws-client-core/node_modules/lodash-es/_hasUnicode.js","../../ws-client-core/node_modules/lodash-es/_unicodeToArray.js","../../ws-client-core/node_modules/jsonql-utils/src/generic.js","../../ws-client-core/node_modules/lodash-es/_listCacheClear.js","../../ws-client-core/node_modules/lodash-es/eq.js","../../ws-client-core/node_modules/lodash-es/_stackDelete.js","../../ws-client-core/node_modules/lodash-es/_stackGet.js","../../ws-client-core/node_modules/lodash-es/_stackHas.js","../../ws-client-core/node_modules/lodash-es/isObject.js","../../ws-client-core/node_modules/lodash-es/_toSource.js","../../ws-client-core/node_modules/lodash-es/_getValue.js","../../ws-client-core/node_modules/lodash-es/_hashDelete.js","../../ws-client-core/node_modules/lodash-es/_isKeyable.js","../../ws-client-core/node_modules/lodash-es/_createBaseFor.js","../../ws-client-core/node_modules/lodash-es/_copyArray.js","../../ws-client-core/node_modules/lodash-es/_isPrototype.js","../../ws-client-core/node_modules/lodash-es/isLength.js","../../ws-client-core/node_modules/lodash-es/stubFalse.js","../../ws-client-core/node_modules/lodash-es/_baseUnary.js","../../ws-client-core/node_modules/lodash-es/_safeGet.js","../../ws-client-core/node_modules/lodash-es/_baseTimes.js","../../ws-client-core/node_modules/lodash-es/_isIndex.js","../../ws-client-core/node_modules/lodash-es/_nativeKeysIn.js","../../ws-client-core/node_modules/lodash-es/identity.js","../../ws-client-core/node_modules/lodash-es/_apply.js","../../ws-client-core/node_modules/lodash-es/constant.js","../../ws-client-core/node_modules/lodash-es/_shortOut.js","../../ws-client-core/node_modules/jsonql-errors/src/enum-error.js","../../ws-client-core/node_modules/jsonql-errors/src/type-error.js","../../ws-client-core/node_modules/jsonql-errors/src/checker-error.js","../../ws-client-core/node_modules/jsonql-errors/src/validation-error.js","../../ws-client-core/node_modules/jsonql-utils/src/contract.js","../../ws-client-core/node_modules/jsonql-utils/src/timestamp.js","../../ws-client-core/node_modules/jsonql-utils/src/params-api.js","../../ws-client-core/node_modules/jsonql-utils/src/namespace.js","../../ws-client-core/node_modules/jsonql-utils/src/socket.js","../../ws-client-core/src/callers/intercom-methods.js","../../ws-client-core/node_modules/jsonql-params-validator/src/number.js","../../ws-client-core/node_modules/jsonql-params-validator/src/string.js","../../ws-client-core/node_modules/jsonql-params-validator/src/boolean.js","../../ws-client-core/node_modules/jsonql-params-validator/src/any.js","../../ws-client-core/node_modules/jsonql-params-validator/src/constants.js","../../ws-client-core/node_modules/jsonql-params-validator/src/combine.js","../../ws-client-core/node_modules/jsonql-params-validator/src/array.js","../../ws-client-core/node_modules/jsonql-params-validator/src/object.js","../../ws-client-core/node_modules/jsonql-params-validator/src/validator.js","../../ws-client-core/node_modules/lodash-es/_setCacheAdd.js","../../ws-client-core/node_modules/lodash-es/_setCacheHas.js","../../ws-client-core/node_modules/lodash-es/_arraySome.js","../../ws-client-core/node_modules/lodash-es/_cacheHas.js","../../ws-client-core/node_modules/lodash-es/_mapToArray.js","../../ws-client-core/node_modules/lodash-es/_setToArray.js","../../ws-client-core/node_modules/lodash-es/_arrayPush.js","../../ws-client-core/node_modules/lodash-es/_arrayFilter.js","../../ws-client-core/node_modules/lodash-es/stubArray.js","../../ws-client-core/node_modules/lodash-es/_matchesStrictComparable.js","../../ws-client-core/node_modules/lodash-es/_baseHasIn.js","../../ws-client-core/node_modules/lodash-es/_baseProperty.js","../../ws-client-core/node_modules/lodash-es/negate.js","../../ws-client-core/node_modules/lodash-es/_baseFindKey.js","../../ws-client-core/node_modules/jsonql-params-validator/src/is-in-array.js","../../ws-client-core/node_modules/jsonql-params-validator/src/options/run-validation.js","../../ws-client-core/node_modules/jsonql-params-validator/src/options/check-options-async.js","../../ws-client-core/node_modules/jsonql-params-validator/src/options/construct-config.js","../../ws-client-core/node_modules/jsonql-params-validator/src/options/index.js","../../ws-client-core/node_modules/jsonql-params-validator/index.js","../../ws-client-core/src/utils/get-log-fn.js","../../ws-client-core/node_modules/@to1source/event/src/constants.js","../../ws-client-core/node_modules/@to1source/event/src/store.js","../../ws-client-core/node_modules/@to1source/event/src/utils.js","../../ws-client-core/node_modules/@to1source/event/src/suspend.js","../../ws-client-core/node_modules/@to1source/event/src/store-service.js","../../ws-client-core/node_modules/@to1source/event/src/event-service.js","../../ws-client-core/node_modules/@to1source/event/index.js","../../ws-client-core/src/utils/get-event-emitter.js","../../ws-client-core/src/utils/helpers.js","../../ws-client-core/src/callers/setup-auth-methods.js","../../ws-client-core/src/options/constants.js","../../ws-client-core/src/callers/respond-handler.js","../../ws-client-core/src/callers/action-call.js","../../ws-client-core/src/callers/setup-send-method.js","../../ws-client-core/src/callers/setup-resolver.js","../../ws-client-core/src/callers/generator-methods.js","../../ws-client-core/src/callers/setup-intercom.js","../../ws-client-core/src/callers/setup-final-step.js","../../ws-client-core/src/callers/callers-generator.js","../../ws-client-core/src/options/index.js","../../ws-client-core/src/api.js","../../ws-client-core/src/listener/create-nsp-clients.js","../../ws-client-core/src/listener/trigger-namespaces-on-error.js","../../ws-client-core/src/listener/event-listeners.js","../../ws-client-core/src/listener/client-event-listener.js","src/options/index.js","src/core/create-websocket-binding/init-websocket-client.js","node_modules/lodash-es/_objectToString.js","node_modules/lodash-es/_overArg.js","node_modules/lodash-es/isObjectLike.js","node_modules/lodash-es/_listCacheClear.js","node_modules/lodash-es/eq.js","node_modules/lodash-es/_stackDelete.js","node_modules/lodash-es/_stackGet.js","node_modules/lodash-es/_stackHas.js","node_modules/lodash-es/isObject.js","node_modules/lodash-es/_toSource.js","node_modules/lodash-es/_getValue.js","node_modules/lodash-es/_hashDelete.js","node_modules/lodash-es/_isKeyable.js","node_modules/lodash-es/_createBaseFor.js","node_modules/lodash-es/_copyArray.js","node_modules/lodash-es/_isPrototype.js","node_modules/lodash-es/isArray.js","node_modules/lodash-es/isLength.js","node_modules/lodash-es/stubFalse.js","node_modules/lodash-es/_baseUnary.js","node_modules/lodash-es/_safeGet.js","node_modules/lodash-es/_baseTimes.js","node_modules/lodash-es/_isIndex.js","node_modules/lodash-es/_nativeKeysIn.js","node_modules/lodash-es/identity.js","node_modules/lodash-es/_apply.js","node_modules/lodash-es/constant.js","node_modules/lodash-es/_shortOut.js","node_modules/jsonql-utils/src/chain-promises.js","src/core/create-nsp/login-event-handler.js","node_modules/jsonql-utils/src/generic.js","node_modules/jsonql-errors/src/validation-error.js","node_modules/jsonql-utils/src/timestamp.js","node_modules/jsonql-utils/src/params-api.js","node_modules/jsonql-utils/src/socket.js","src/core/create-nsp/bind-socket-event-handler.js","src/core/create-nsp/create-nsp.js","src/core/create-nsp/index.js","src/core/create-websocket-binding/bind-framework-to-jsonql.js","src/node/node-framework-socket-engine.js","src/node-ws-client.js"],"sourcesContent":["/**\n * Checks if `value` is classified as an `Array` object.\n *\n * @static\n * @memberOf _\n * @since 0.1.0\n * @category Lang\n * @param {*} value The value to check.\n * @returns {boolean} Returns `true` if `value` is an array, else `false`.\n * @example\n *\n * _.isArray([1, 2, 3]);\n * // => true\n *\n * _.isArray(document.body.children);\n * // => false\n *\n * _.isArray('abc');\n * // => false\n *\n * _.isArray(_.noop);\n * // => false\n */\nvar isArray = Array.isArray;\n\nexport default isArray;\n","export default (typeof global !== \"undefined\" ? global :\n typeof self !== \"undefined\" ? self :\n typeof window !== \"undefined\" ? window : {});\n","/** Used for built-in method references. */\nvar objectProto = Object.prototype;\n\n/**\n * Used to resolve the\n * [`toStringTag`](http://ecma-international.org/ecma-262/7.0/#sec-object.prototype.tostring)\n * of values.\n */\nvar nativeObjectToString = objectProto.toString;\n\n/**\n * Converts `value` to a string using `Object.prototype.toString`.\n *\n * @private\n * @param {*} value The value to convert.\n * @returns {string} Returns the converted string.\n */\nfunction objectToString(value) {\n return nativeObjectToString.call(value);\n}\n\nexport default objectToString;\n","/**\n * Creates a unary function that invokes `func` with its argument transformed.\n *\n * @private\n * @param {Function} func The function to wrap.\n * @param {Function} transform The argument transform.\n * @returns {Function} Returns the new function.\n */\nfunction overArg(func, transform) {\n return function(arg) {\n return func(transform(arg));\n };\n}\n\nexport default overArg;\n","/**\n * Checks if `value` is object-like. A value is object-like if it's not `null`\n * and has a `typeof` result of \"object\".\n *\n * @static\n * @memberOf _\n * @since 4.0.0\n * @category Lang\n * @param {*} value The value to check.\n * @returns {boolean} Returns `true` if `value` is object-like, else `false`.\n * @example\n *\n * _.isObjectLike({});\n * // => true\n *\n * _.isObjectLike([1, 2, 3]);\n * // => true\n *\n * _.isObjectLike(_.noop);\n * // => false\n *\n * _.isObjectLike(null);\n * // => false\n */\nfunction isObjectLike(value) {\n return value != null && typeof value == 'object';\n}\n\nexport default isObjectLike;\n","/**\n * A specialized version of `_.map` for arrays without support for iteratee\n * shorthands.\n *\n * @private\n * @param {Array} [array] The array to iterate over.\n * @param {Function} iteratee The function invoked per iteration.\n * @returns {Array} Returns the new mapped array.\n */\nfunction arrayMap(array, iteratee) {\n var index = -1,\n length = array == null ? 0 : array.length,\n result = Array(length);\n\n while (++index < length) {\n result[index] = iteratee(array[index], index, array);\n }\n return result;\n}\n\nexport default arrayMap;\n","/**\n * The base implementation of `_.slice` without an iteratee call guard.\n *\n * @private\n * @param {Array} array The array to slice.\n * @param {number} [start=0] The start position.\n * @param {number} [end=array.length] The end position.\n * @returns {Array} Returns the slice of `array`.\n */\nfunction baseSlice(array, start, end) {\n var index = -1,\n length = array.length;\n\n if (start < 0) {\n start = -start > length ? 0 : (length + start);\n }\n end = end > length ? length : end;\n if (end < 0) {\n end += length;\n }\n length = start > end ? 0 : ((end - start) >>> 0);\n start >>>= 0;\n\n var result = Array(length);\n while (++index < length) {\n result[index] = array[index + start];\n }\n return result;\n}\n\nexport default baseSlice;\n","/**\n * The base implementation of `_.findIndex` and `_.findLastIndex` without\n * support for iteratee shorthands.\n *\n * @private\n * @param {Array} array The array to inspect.\n * @param {Function} predicate The function invoked per iteration.\n * @param {number} fromIndex The index to search from.\n * @param {boolean} [fromRight] Specify iterating from right to left.\n * @returns {number} Returns the index of the matched value, else `-1`.\n */\nfunction baseFindIndex(array, predicate, fromIndex, fromRight) {\n var length = array.length,\n index = fromIndex + (fromRight ? 1 : -1);\n\n while ((fromRight ? index-- : ++index < length)) {\n if (predicate(array[index], index, array)) {\n return index;\n }\n }\n return -1;\n}\n\nexport default baseFindIndex;\n","/**\n * The base implementation of `_.isNaN` without support for number objects.\n *\n * @private\n * @param {*} value The value to check.\n * @returns {boolean} Returns `true` if `value` is `NaN`, else `false`.\n */\nfunction baseIsNaN(value) {\n return value !== value;\n}\n\nexport default baseIsNaN;\n","/**\n * A specialized version of `_.indexOf` which performs strict equality\n * comparisons of values, i.e. `===`.\n *\n * @private\n * @param {Array} array The array to inspect.\n * @param {*} value The value to search for.\n * @param {number} fromIndex The index to search from.\n * @returns {number} Returns the index of the matched value, else `-1`.\n */\nfunction strictIndexOf(array, value, fromIndex) {\n var index = fromIndex - 1,\n length = array.length;\n\n while (++index < length) {\n if (array[index] === value) {\n return index;\n }\n }\n return -1;\n}\n\nexport default strictIndexOf;\n","/**\n * Converts an ASCII `string` to an array.\n *\n * @private\n * @param {string} string The string to convert.\n * @returns {Array} Returns the converted array.\n */\nfunction asciiToArray(string) {\n return string.split('');\n}\n\nexport default asciiToArray;\n","/** Used to compose unicode character classes. */\nvar rsAstralRange = '\\\\ud800-\\\\udfff',\n rsComboMarksRange = '\\\\u0300-\\\\u036f',\n reComboHalfMarksRange = '\\\\ufe20-\\\\ufe2f',\n rsComboSymbolsRange = '\\\\u20d0-\\\\u20ff',\n rsComboRange = rsComboMarksRange + reComboHalfMarksRange + rsComboSymbolsRange,\n rsVarRange = '\\\\ufe0e\\\\ufe0f';\n\n/** Used to compose unicode capture groups. */\nvar rsZWJ = '\\\\u200d';\n\n/** Used to detect strings with [zero-width joiners or code points from the astral planes](http://eev.ee/blog/2015/09/12/dark-corners-of-unicode/). */\nvar reHasUnicode = RegExp('[' + rsZWJ + rsAstralRange + rsComboRange + rsVarRange + ']');\n\n/**\n * Checks if `string` contains Unicode symbols.\n *\n * @private\n * @param {string} string The string to inspect.\n * @returns {boolean} Returns `true` if a symbol is found, else `false`.\n */\nfunction hasUnicode(string) {\n return reHasUnicode.test(string);\n}\n\nexport default hasUnicode;\n","/** Used to compose unicode character classes. */\nvar rsAstralRange = '\\\\ud800-\\\\udfff',\n rsComboMarksRange = '\\\\u0300-\\\\u036f',\n reComboHalfMarksRange = '\\\\ufe20-\\\\ufe2f',\n rsComboSymbolsRange = '\\\\u20d0-\\\\u20ff',\n rsComboRange = rsComboMarksRange + reComboHalfMarksRange + rsComboSymbolsRange,\n rsVarRange = '\\\\ufe0e\\\\ufe0f';\n\n/** Used to compose unicode capture groups. */\nvar rsAstral = '[' + rsAstralRange + ']',\n rsCombo = '[' + rsComboRange + ']',\n rsFitz = '\\\\ud83c[\\\\udffb-\\\\udfff]',\n rsModifier = '(?:' + rsCombo + '|' + rsFitz + ')',\n rsNonAstral = '[^' + rsAstralRange + ']',\n rsRegional = '(?:\\\\ud83c[\\\\udde6-\\\\uddff]){2}',\n rsSurrPair = '[\\\\ud800-\\\\udbff][\\\\udc00-\\\\udfff]',\n rsZWJ = '\\\\u200d';\n\n/** Used to compose unicode regexes. */\nvar reOptMod = rsModifier + '?',\n rsOptVar = '[' + rsVarRange + ']?',\n rsOptJoin = '(?:' + rsZWJ + '(?:' + [rsNonAstral, rsRegional, rsSurrPair].join('|') + ')' + rsOptVar + reOptMod + ')*',\n rsSeq = rsOptVar + reOptMod + rsOptJoin,\n rsSymbol = '(?:' + [rsNonAstral + rsCombo + '?', rsCombo, rsRegional, rsSurrPair, rsAstral].join('|') + ')';\n\n/** Used to match [string symbols](https://mathiasbynens.be/notes/javascript-unicode). */\nvar reUnicode = RegExp(rsFitz + '(?=' + rsFitz + ')|' + rsSymbol + rsSeq, 'g');\n\n/**\n * Converts a Unicode `string` to an array.\n *\n * @private\n * @param {string} string The string to convert.\n * @returns {Array} Returns the converted array.\n */\nfunction unicodeToArray(string) {\n return string.match(reUnicode) || [];\n}\n\nexport default unicodeToArray;\n","// bunch of generic helpers\n\nimport isArray from 'lodash-es/isArray'\nimport isPlainObject from 'lodash-es/isPlainObject'\nimport trim from 'lodash-es/trim'\n\n/**\n * DIY in Array\n * @param {array} arr to check from\n * @param {*} value to check against\n * @return {boolean} true on found\n */\nexport const inArray = (arr, value) => !!arr.filter(a => a === value).length\n\n// quick and dirty to turn non array to array\nexport const toArray = (arg) => isArray(arg) ? arg : [arg]\n\n/**\n * parse string to json or just return the original value if error happened\n * @param {*} n input\n * @param {boolean} [t=true] or throw\n * @return {*} json object on success\n */\nexport const parseJson = function(n, t=true) {\n try {\n return JSON.parse(n)\n } catch(e) {\n if (t) {\n return n\n }\n throw new Error(e)\n }\n}\n\n/**\n * @param {object} obj for search\n * @param {string} key target\n * @return {boolean} true on success\n */\nexport const isObjectHasKey = function(obj, key) {\n try {\n const keys = Object.keys(obj)\n return inArray(keys, key)\n } catch(e) {\n // @BUG when the obj is not an OBJECT we got some weird output\n return false\n }\n}\n\n/**\n * create a event name\n * @param {string[]} args\n * @return {string} event name for use\n */\nexport const createEvt = (...args) => args.join('_')\n\n/**\n * simple util method to get the value\n * @param {string} name of the key\n * @param {object} obj to take value from\n * @return {*} the object value id by name or undefined\n */\nexport const getConfigValue = (name, obj) => (\n obj && isPlainObject(obj) ? ( (name in obj) ? obj[name] : undefined ) : undefined\n)\n\n/**\n * small util to make sure the return value is valid JSON object\n * @param {*} n input\n * @return {object} correct JSON object\n */\nexport const toJson = n => {\n if (typeof n === 'string') {\n return parseJson(n)\n }\n return parseJson(JSON.stringify(n))\n}\n\n/**\n * Check several parameter that there is something in the param\n * @param {*} param input\n * @return {boolean}\n */\nexport const isNotEmpty = function(param) {\n return param !== undefined && param !== false && param !== null && trim(param) !== ''\n}\n\n/**\n * Simple check if the prop is function\n * @param {*} prop input\n * @return {boolean} true on success\n */\nexport const isFunc = prop => {\n if (typeof prop === 'function') {\n return true;\n }\n console.error(`Expect to be Function type! Got ${typeof prop}`)\n}\n\n/**\n * Shorthand method for Object.assign \n * @param {array} args \n * @return {object} merge together object by key \n */\nexport const assign = (...args) => Reflect.apply(Object.assign, Object, args)\n \n/** \n * generic placeholder function\n * @return {boolean} false \n */\nexport const nil = () => false\n\n/**\n * generic turn config into immutatble \n */\nexport const freeze = config => Object.freeze(config)","/**\n * Removes all key-value entries from the list cache.\n *\n * @private\n * @name clear\n * @memberOf ListCache\n */\nfunction listCacheClear() {\n this.__data__ = [];\n this.size = 0;\n}\n\nexport default listCacheClear;\n","/**\n * Performs a\n * [`SameValueZero`](http://ecma-international.org/ecma-262/7.0/#sec-samevaluezero)\n * comparison between two values to determine if they are equivalent.\n *\n * @static\n * @memberOf _\n * @since 4.0.0\n * @category Lang\n * @param {*} value The value to compare.\n * @param {*} other The other value to compare.\n * @returns {boolean} Returns `true` if the values are equivalent, else `false`.\n * @example\n *\n * var object = { 'a': 1 };\n * var other = { 'a': 1 };\n *\n * _.eq(object, object);\n * // => true\n *\n * _.eq(object, other);\n * // => false\n *\n * _.eq('a', 'a');\n * // => true\n *\n * _.eq('a', Object('a'));\n * // => false\n *\n * _.eq(NaN, NaN);\n * // => true\n */\nfunction eq(value, other) {\n return value === other || (value !== value && other !== other);\n}\n\nexport default eq;\n","/**\n * Removes `key` and its value from the stack.\n *\n * @private\n * @name delete\n * @memberOf Stack\n * @param {string} key The key of the value to remove.\n * @returns {boolean} Returns `true` if the entry was removed, else `false`.\n */\nfunction stackDelete(key) {\n var data = this.__data__,\n result = data['delete'](key);\n\n this.size = data.size;\n return result;\n}\n\nexport default stackDelete;\n","/**\n * Gets the stack value for `key`.\n *\n * @private\n * @name get\n * @memberOf Stack\n * @param {string} key The key of the value to get.\n * @returns {*} Returns the entry value.\n */\nfunction stackGet(key) {\n return this.__data__.get(key);\n}\n\nexport default stackGet;\n","/**\n * Checks if a stack value for `key` exists.\n *\n * @private\n * @name has\n * @memberOf Stack\n * @param {string} key The key of the entry to check.\n * @returns {boolean} Returns `true` if an entry for `key` exists, else `false`.\n */\nfunction stackHas(key) {\n return this.__data__.has(key);\n}\n\nexport default stackHas;\n","/**\n * Checks if `value` is the\n * [language type](http://www.ecma-international.org/ecma-262/7.0/#sec-ecmascript-language-types)\n * of `Object`. (e.g. arrays, functions, objects, regexes, `new Number(0)`, and `new String('')`)\n *\n * @static\n * @memberOf _\n * @since 0.1.0\n * @category Lang\n * @param {*} value The value to check.\n * @returns {boolean} Returns `true` if `value` is an object, else `false`.\n * @example\n *\n * _.isObject({});\n * // => true\n *\n * _.isObject([1, 2, 3]);\n * // => true\n *\n * _.isObject(_.noop);\n * // => true\n *\n * _.isObject(null);\n * // => false\n */\nfunction isObject(value) {\n var type = typeof value;\n return value != null && (type == 'object' || type == 'function');\n}\n\nexport default isObject;\n","/** Used for built-in method references. */\nvar funcProto = Function.prototype;\n\n/** Used to resolve the decompiled source of functions. */\nvar funcToString = funcProto.toString;\n\n/**\n * Converts `func` to its source code.\n *\n * @private\n * @param {Function} func The function to convert.\n * @returns {string} Returns the source code.\n */\nfunction toSource(func) {\n if (func != null) {\n try {\n return funcToString.call(func);\n } catch (e) {}\n try {\n return (func + '');\n } catch (e) {}\n }\n return '';\n}\n\nexport default toSource;\n","/**\n * Gets the value at `key` of `object`.\n *\n * @private\n * @param {Object} [object] The object to query.\n * @param {string} key The key of the property to get.\n * @returns {*} Returns the property value.\n */\nfunction getValue(object, key) {\n return object == null ? undefined : object[key];\n}\n\nexport default getValue;\n","/**\n * Removes `key` and its value from the hash.\n *\n * @private\n * @name delete\n * @memberOf Hash\n * @param {Object} hash The hash to modify.\n * @param {string} key The key of the value to remove.\n * @returns {boolean} Returns `true` if the entry was removed, else `false`.\n */\nfunction hashDelete(key) {\n var result = this.has(key) && delete this.__data__[key];\n this.size -= result ? 1 : 0;\n return result;\n}\n\nexport default hashDelete;\n","/**\n * Checks if `value` is suitable for use as unique object key.\n *\n * @private\n * @param {*} value The value to check.\n * @returns {boolean} Returns `true` if `value` is suitable, else `false`.\n */\nfunction isKeyable(value) {\n var type = typeof value;\n return (type == 'string' || type == 'number' || type == 'symbol' || type == 'boolean')\n ? (value !== '__proto__')\n : (value === null);\n}\n\nexport default isKeyable;\n","/**\n * Creates a base function for methods like `_.forIn` and `_.forOwn`.\n *\n * @private\n * @param {boolean} [fromRight] Specify iterating from right to left.\n * @returns {Function} Returns the new base function.\n */\nfunction createBaseFor(fromRight) {\n return function(object, iteratee, keysFunc) {\n var index = -1,\n iterable = Object(object),\n props = keysFunc(object),\n length = props.length;\n\n while (length--) {\n var key = props[fromRight ? length : ++index];\n if (iteratee(iterable[key], key, iterable) === false) {\n break;\n }\n }\n return object;\n };\n}\n\nexport default createBaseFor;\n","/**\n * Copies the values of `source` to `array`.\n *\n * @private\n * @param {Array} source The array to copy values from.\n * @param {Array} [array=[]] The array to copy values to.\n * @returns {Array} Returns `array`.\n */\nfunction copyArray(source, array) {\n var index = -1,\n length = source.length;\n\n array || (array = Array(length));\n while (++index < length) {\n array[index] = source[index];\n }\n return array;\n}\n\nexport default copyArray;\n","/** Used for built-in method references. */\nvar objectProto = Object.prototype;\n\n/**\n * Checks if `value` is likely a prototype object.\n *\n * @private\n * @param {*} value The value to check.\n * @returns {boolean} Returns `true` if `value` is a prototype, else `false`.\n */\nfunction isPrototype(value) {\n var Ctor = value && value.constructor,\n proto = (typeof Ctor == 'function' && Ctor.prototype) || objectProto;\n\n return value === proto;\n}\n\nexport default isPrototype;\n","/** Used as references for various `Number` constants. */\nvar MAX_SAFE_INTEGER = 9007199254740991;\n\n/**\n * Checks if `value` is a valid array-like length.\n *\n * **Note:** This method is loosely based on\n * [`ToLength`](http://ecma-international.org/ecma-262/7.0/#sec-tolength).\n *\n * @static\n * @memberOf _\n * @since 4.0.0\n * @category Lang\n * @param {*} value The value to check.\n * @returns {boolean} Returns `true` if `value` is a valid length, else `false`.\n * @example\n *\n * _.isLength(3);\n * // => true\n *\n * _.isLength(Number.MIN_VALUE);\n * // => false\n *\n * _.isLength(Infinity);\n * // => false\n *\n * _.isLength('3');\n * // => false\n */\nfunction isLength(value) {\n return typeof value == 'number' &&\n value > -1 && value % 1 == 0 && value <= MAX_SAFE_INTEGER;\n}\n\nexport default isLength;\n","/**\n * This method returns `false`.\n *\n * @static\n * @memberOf _\n * @since 4.13.0\n * @category Util\n * @returns {boolean} Returns `false`.\n * @example\n *\n * _.times(2, _.stubFalse);\n * // => [false, false]\n */\nfunction stubFalse() {\n return false;\n}\n\nexport default stubFalse;\n","/**\n * The base implementation of `_.unary` without support for storing metadata.\n *\n * @private\n * @param {Function} func The function to cap arguments for.\n * @returns {Function} Returns the new capped function.\n */\nfunction baseUnary(func) {\n return function(value) {\n return func(value);\n };\n}\n\nexport default baseUnary;\n","/**\n * Gets the value at `key`, unless `key` is \"__proto__\" or \"constructor\".\n *\n * @private\n * @param {Object} object The object to query.\n * @param {string} key The key of the property to get.\n * @returns {*} Returns the property value.\n */\nfunction safeGet(object, key) {\n if (key === 'constructor' && typeof object[key] === 'function') {\n return;\n }\n\n if (key == '__proto__') {\n return;\n }\n\n return object[key];\n}\n\nexport default safeGet;\n","/**\n * The base implementation of `_.times` without support for iteratee shorthands\n * or max array length checks.\n *\n * @private\n * @param {number} n The number of times to invoke `iteratee`.\n * @param {Function} iteratee The function invoked per iteration.\n * @returns {Array} Returns the array of results.\n */\nfunction baseTimes(n, iteratee) {\n var index = -1,\n result = Array(n);\n\n while (++index < n) {\n result[index] = iteratee(index);\n }\n return result;\n}\n\nexport default baseTimes;\n","/** Used as references for various `Number` constants. */\nvar MAX_SAFE_INTEGER = 9007199254740991;\n\n/** Used to detect unsigned integer values. */\nvar reIsUint = /^(?:0|[1-9]\\d*)$/;\n\n/**\n * Checks if `value` is a valid array-like index.\n *\n * @private\n * @param {*} value The value to check.\n * @param {number} [length=MAX_SAFE_INTEGER] The upper bounds of a valid index.\n * @returns {boolean} Returns `true` if `value` is a valid index, else `false`.\n */\nfunction isIndex(value, length) {\n var type = typeof value;\n length = length == null ? MAX_SAFE_INTEGER : length;\n\n return !!length &&\n (type == 'number' ||\n (type != 'symbol' && reIsUint.test(value))) &&\n (value > -1 && value % 1 == 0 && value < length);\n}\n\nexport default isIndex;\n","/**\n * This function is like\n * [`Object.keys`](http://ecma-international.org/ecma-262/7.0/#sec-object.keys)\n * except that it includes inherited enumerable properties.\n *\n * @private\n * @param {Object} object The object to query.\n * @returns {Array} Returns the array of property names.\n */\nfunction nativeKeysIn(object) {\n var result = [];\n if (object != null) {\n for (var key in Object(object)) {\n result.push(key);\n }\n }\n return result;\n}\n\nexport default nativeKeysIn;\n","/**\n * This method returns the first argument it receives.\n *\n * @static\n * @since 0.1.0\n * @memberOf _\n * @category Util\n * @param {*} value Any value.\n * @returns {*} Returns `value`.\n * @example\n *\n * var object = { 'a': 1 };\n *\n * console.log(_.identity(object) === object);\n * // => true\n */\nfunction identity(value) {\n return value;\n}\n\nexport default identity;\n","/**\n * A faster alternative to `Function#apply`, this function invokes `func`\n * with the `this` binding of `thisArg` and the arguments of `args`.\n *\n * @private\n * @param {Function} func The function to invoke.\n * @param {*} thisArg The `this` binding of `func`.\n * @param {Array} args The arguments to invoke `func` with.\n * @returns {*} Returns the result of `func`.\n */\nfunction apply(func, thisArg, args) {\n switch (args.length) {\n case 0: return func.call(thisArg);\n case 1: return func.call(thisArg, args[0]);\n case 2: return func.call(thisArg, args[0], args[1]);\n case 3: return func.call(thisArg, args[0], args[1], args[2]);\n }\n return func.apply(thisArg, args);\n}\n\nexport default apply;\n","/**\n * Creates a function that returns `value`.\n *\n * @static\n * @memberOf _\n * @since 2.4.0\n * @category Util\n * @param {*} value The value to return from the new function.\n * @returns {Function} Returns the new constant function.\n * @example\n *\n * var objects = _.times(2, _.constant({ 'a': 1 }));\n *\n * console.log(objects);\n * // => [{ 'a': 1 }, { 'a': 1 }]\n *\n * console.log(objects[0] === objects[1]);\n * // => true\n */\nfunction constant(value) {\n return function() {\n return value;\n };\n}\n\nexport default constant;\n","/** Used to detect hot functions by number of calls within a span of milliseconds. */\nvar HOT_COUNT = 800,\n HOT_SPAN = 16;\n\n/* Built-in method references for those with the same name as other `lodash` methods. */\nvar nativeNow = Date.now;\n\n/**\n * Creates a function that'll short out and invoke `identity` instead\n * of `func` when it's called `HOT_COUNT` or more times in `HOT_SPAN`\n * milliseconds.\n *\n * @private\n * @param {Function} func The function to restrict.\n * @returns {Function} Returns the new shortable function.\n */\nfunction shortOut(func) {\n var count = 0,\n lastCalled = 0;\n\n return function() {\n var stamp = nativeNow(),\n remaining = HOT_SPAN - (stamp - lastCalled);\n\n lastCalled = stamp;\n if (remaining > 0) {\n if (++count >= HOT_COUNT) {\n return arguments[0];\n }\n } else {\n count = 0;\n }\n return func.apply(undefined, arguments);\n };\n}\n\nexport default shortOut;\n","// this get throw from within the checkOptions when run through the enum failed\nexport default class JsonqlEnumError extends Error {\n constructor(...args) {\n super(...args)\n\n this.message = args[0]\n this.detail = args[1]\n\n this.className = JsonqlEnumError.name;\n\n if (Error.captureStackTrace) {\n Error.captureStackTrace(this, JsonqlEnumError)\n }\n }\n\n static get name() {\n return 'JsonqlEnumError'\n }\n}\n","// this will throw from inside the checkOptions\nexport default class JsonqlTypeError extends Error {\n constructor(...args) {\n super(...args)\n\n this.message = args[0]\n this.detail = args[1]\n\n this.className = JsonqlTypeError.name\n\n if (Error.captureStackTrace) {\n Error.captureStackTrace(this, JsonqlTypeError)\n }\n }\n\n static get name() {\n return 'JsonqlTypeError'\n }\n}\n","// allow supply a custom checker function\n// if that failed then we throw this error\nexport default class JsonqlCheckerError extends Error {\n constructor(...args) {\n super(...args)\n this.message = args[0]\n this.detail = args[1]\n\n this.className = JsonqlCheckerError.name;\n\n if (Error.captureStackTrace) {\n Error.captureStackTrace(this, JsonqlCheckerError)\n }\n }\n\n static get name() {\n return 'JsonqlCheckerError'\n }\n}\n","// custom validation error class\n// when validaton failed\nexport default class JsonqlValidationError extends Error {\n constructor(...args) {\n super(...args)\n\n this.message = args[0]\n this.detail = args[1]\n\n this.className = JsonqlValidationError.name;\n\n if (Error.captureStackTrace) {\n Error.captureStackTrace(this, JsonqlValidationError)\n }\n }\n\n static get name() {\n return 'JsonqlValidationError'\n }\n}\n","// split the contract into the node side and the generic side\nimport { isObjectHasKey } from './generic'\nimport isPlainObject from 'lodash-es/isPlainObject'\nimport {\n QUERY_NAME,\n MUTATION_NAME,\n SOCKET_NAME,\n QUERY_ARG_NAME,\n PAYLOAD_PARAM_NAME,\n CONDITION_PARAM_NAME\n} from 'jsonql-constants'\nimport { JsonqlError, JsonqlResolverNotFoundError } from 'jsonql-errors'\n/**\n * Check if the json is a contract file or not\n * @param {object} contract json object\n * @return {boolean} true\n */\nexport function checkIsContract(contract) {\n return isPlainObject(contract)\n && (\n isObjectHasKey(contract, QUERY_NAME)\n || isObjectHasKey(contract, MUTATION_NAME)\n || isObjectHasKey(contract, SOCKET_NAME)\n )\n}\n\n/**\n * Wrapper method that check if it's contract then return the contract or false\n * @param {object} contract the object to check\n * @return {boolean | object} false when it's not\n */\nexport function isContract(contract) {\n return checkIsContract(contract) ? contract : false\n}\n\n/**\n * Ported from jsonql-params-validator but different\n * if we don't find the socket part then return false\n * @param {object} contract the contract object\n * @return {object|boolean} false on failed\n */\nexport function extractSocketPart(contract) {\n if (isObjectHasKey(contract, SOCKET_NAME)) {\n return contract[SOCKET_NAME]\n }\n return false\n}\n\n/**\n * Extract the args from the payload\n * @param {object} payload to work with\n * @param {string} type of call\n * @return {array} args\n */\nexport function extractArgsFromPayload(payload, type) {\n switch (type) {\n case QUERY_NAME:\n return payload[QUERY_ARG_NAME]\n case MUTATION_NAME:\n return [\n payload[PAYLOAD_PARAM_NAME],\n payload[CONDITION_PARAM_NAME]\n ]\n default:\n throw new JsonqlError(`Unknown ${type} to extract argument from!`)\n }\n}\n\n/**\n * Like what the name said\n * @param {object} contract the contract json\n * @param {string} type query|mutation\n * @param {string} name of the function\n * @return {object} the params part of the contract\n */\nexport function extractParamsFromContract(contract, type, name) {\n try {\n const result = contract[type][name]\n // debug('extractParamsFromContract', result)\n if (!result) {\n // debug(name, type, contract)\n throw new JsonqlResolverNotFoundError(name, type)\n }\n return result\n } catch(e) {\n throw new JsonqlResolverNotFoundError(name, e)\n }\n}\n","/**\n * @param {boolean} sec return in second or not\n * @return {number} timestamp\n */\nexport const timestamp = (sec = false) => {\n let time = Date.now()\n return sec ? Math.floor( time / 1000 ) : time\n}\n","// ported from jsonql-params-validator\n// craete several helper function to construct / extract the payload\n// and make sure they are all the same\nimport {\n PAYLOAD_PARAM_NAME,\n CONDITION_PARAM_NAME,\n RESOLVER_PARAM_NAME,\n QUERY_ARG_NAME,\n TIMESTAMP_PARAM_NAME\n} from 'jsonql-constants'\n\nimport JsonqlValidationError from 'jsonql-errors/src/validation-error'\n\nimport isArray from 'lodash-es/isArray'\nimport isString from 'lodash-es/isString'\nimport isPlainObject from 'lodash-es/isPlainObject'\n\nimport { timestamp } from './timestamp'\nimport { parseJson } from './generic'\n\n/**\n * check if the payload has a timestamp field, then append a new timestamp to it\n * @param {object} payload from the com\n * @return {array} timestamp field with an array value\n */\nexport const handleTimestamp = payload => {\n let ts = payload[TIMESTAMP_PARAM_NAME]\n if (!isArray(ts)) {\n ts = [ts]\n }\n ts.push( timestamp() )\n\n return ts\n}\n\n/**\n * make sure it's an object (it was call formatPayload but it doesn't make sense)\n * @param {*} payload the object comes in could be string based\n * @return {object} the transformed payload\n */\nexport const toPayload = payload => isString(payload) ? parseJson(payload) : payload\n\n/**\n * @param {*} args arguments to send\n *@return {object} formatted payload\n */\nexport const formatPayload = (args) => (\n { [QUERY_ARG_NAME]: args }\n)\n\n/**\n * extract the resolver name from the payload \n * @param {object} payload\n * @return {string} resolver name \n */\nexport function getResolverFromPayload(payload) {\n const keys = Object.keys(payload)\n return keys.filter(key => key !== TIMESTAMP_PARAM_NAME)[0]\n}\n\n/**\n * wrapper method to add the timestamp as well\n * @param {string} resolverName\n * @param {*} payload\n * @return {object} delierable\n */\nexport function createDeliverable(resolverName, payload) {\n return {\n [resolverName]: payload,\n [TIMESTAMP_PARAM_NAME]: [ timestamp() ]\n }\n}\n\n/**\n * @param {string} resolverName name of function\n * @param {array} [args=[]] from the ...args\n * @param {boolean} [jsonp = false] add v1.3.0 to koa\n * @return {object} formatted argument\n */\nexport function createQuery(resolverName, args = [], jsonp = false) {\n if (isString(resolverName) && isArray(args)) {\n let payload = formatPayload(args)\n if (jsonp === true) {\n return payload\n }\n return createDeliverable(resolverName, payload)\n }\n throw new JsonqlValidationError(`[createQuery] expect resolverName to be string and args to be array!`, { resolverName, args })\n}\n\n/**\n * string version of the createQuery\n * @return {string}\n */\nexport function createQueryStr(resolverName, args = [], jsonp = false) {\n return JSON.stringify(createQuery(resolverName, args, jsonp))\n}\n\n/**\n * @param {string} resolverName name of function\n * @param {*} payload to send\n * @param {object} [condition={}] for what\n * @param {boolean} [jsonp = false] add v1.3.0 to koa\n * @return {object} formatted argument\n */\nexport function createMutation(resolverName, payload, condition = {}, jsonp = false) {\n const _payload = {\n [PAYLOAD_PARAM_NAME]: payload,\n [CONDITION_PARAM_NAME]: condition\n }\n if (jsonp === true) {\n return _payload\n }\n if (isString(resolverName)) {\n return createDeliverable(resolverName, _payload)\n }\n throw new JsonqlValidationError(`[createMutation] expect resolverName to be string!`, { resolverName, payload, condition })\n}\n\n/**\n * string version of createMutation\n * @return {string}\n */\nexport function createMutationStr(resolverName, payload, condition = {}, jsonp = false) {\n return JSON.stringify(createMutation(resolverName, payload, condition, jsonp))\n}\n\n/**\n * Extract the parts from payload and format for use\n * @param {string} resolverName name of fn\n * @param {object} payload the incoming json\n * @return {object|boolean} false on failed\n */\nexport function getQueryFromArgs(resolverName, payload) {\n if (resolverName && isPlainObject(payload)) {\n const args = payload[resolverName]\n if (args[QUERY_ARG_NAME]) {\n return {\n [RESOLVER_PARAM_NAME]: resolverName,\n [QUERY_ARG_NAME]: args[QUERY_ARG_NAME],\n [TIMESTAMP_PARAM_NAME]: handleTimestamp(payload)\n }\n }\n }\n return false\n}\n\n/**\n * Share function so no repeat\n * @param {object} payload the payload from client\n * @param {function} processor the last get result method\n * @return {*} result processed result\n */\nfunction processPayload(payload, processor) {\n const p = toPayload(payload)\n const resolverName = getResolverFromPayload(p)\n return Reflect.apply(processor, null, [resolverName, p])\n}\n\n/**\n * extra the payload back\n * @param {*} payload from http call\n * @return {object} resolverName and args\n */\nexport function getQueryFromPayload(payload) {\n const result = processPayload(payload, getQueryFromArgs)\n if (result !== false) {\n return result\n }\n throw new JsonqlValidationError('[getQueryArgs] Payload is malformed!', payload)\n}\n\n/**\n * Further break down from method below for use else where\n * @param {string} resolverName name of fn\n * @param {object} payload payload\n * @return {object|boolean} false on failed\n */\nexport function getMutationFromArgs(resolverName, payload) {\n if (resolverName && isPlainObject(payload)) {\n const args = payload[resolverName]\n if (args) {\n return {\n [RESOLVER_PARAM_NAME]: resolverName,\n [PAYLOAD_PARAM_NAME]: args[PAYLOAD_PARAM_NAME],\n [CONDITION_PARAM_NAME]: args[CONDITION_PARAM_NAME],\n [TIMESTAMP_PARAM_NAME]: handleTimestamp(payload)\n }\n }\n }\n return false\n}\n\n/**\n * @param {object} payload\n * @return {object} resolverName, payload, conditon\n */\nexport function getMutationFromPayload(payload) {\n const result = processPayload(payload, getMutationFromArgs)\n\n if (result !== false) {\n return result\n }\n throw new JsonqlValidationError('[getMutationArgs] Payload is malformed!', payload)\n}\n","// take out all the namespace related methods in one place for easy to find\nimport {\n JSONQL_PATH,\n PUBLIC_KEY,\n NSP_GROUP,\n PUBLIC_NAMESPACE\n} from 'jsonql-constants'\nimport { extractSocketPart } from './contract'\nconst SOCKET_NOT_FOUND_ERR = `socket not found in contract!`\nconst SIZE = 'size'\n\n/**\n * create the group using publicNamespace when there is only public\n * @param {object} socket from contract\n * @param {string} publicNamespace\n */\nfunction groupPublicNamespace(socket, publicNamespace) {\n let g = {}\n for (let resolverName in socket) {\n let params = socket[resolverName]\n g[resolverName] = params\n }\n return { size: 1, nspGroup: {[publicNamespace]: g}, publicNamespace}\n}\n\n\n/**\n * @BUG we should check the socket part instead of expect the downstream to read the menu!\n * We only need this when the enableAuth is true otherwise there is only one namespace\n * @param {object} contract the socket part of the contract file\n * @return {object} 1. remap the contract using the namespace --> resolvers\n * 2. the size of the object (1 all private, 2 mixed public with private)\n * 3. which namespace is public\n */\nexport function groupByNamespace(contract) {\n let socket = extractSocketPart(contract)\n if (socket === false) {\n throw new JsonqlError('groupByNamespace', SOCKET_NOT_FOUND_ERR)\n }\n let prop = {\n [NSP_GROUP]: {},\n [PUBLIC_NAMESPACE]: null,\n [SIZE]: 0 \n }\n\n for (let resolverName in socket) {\n let params = socket[resolverName]\n let { namespace } = params\n if (namespace) {\n if (!prop[NSP_GROUP][namespace]) {\n ++prop[SIZE]\n prop[NSP_GROUP][namespace] = {}\n }\n prop[NSP_GROUP][namespace][resolverName] = params\n // get the public namespace\n if (!prop[PUBLIC_NAMESPACE] && params[PUBLIC_KEY]) {\n prop[PUBLIC_NAMESPACE] = namespace\n }\n }\n }\n \n return prop \n}\n\n/**\n * @NOTE ported from jsonql-ws-client\n * Got to make sure the connection order otherwise\n * it will hang\n * @param {object} nspGroup contract\n * @param {string} publicNamespace like the name said\n * @return {array} namespaces in order\n */\nexport function getNamespaceInOrder(nspGroup, publicNamespace) {\n let names = [] // need to make sure the order!\n for (let namespace in nspGroup) {\n if (namespace === publicNamespace) {\n names[1] = namespace\n } else {\n names[0] = namespace\n }\n }\n return names\n}\n\n/**\n * @TODO this might change, what if we want to do room with ws\n * 1. there will only be max two namespace\n * 2. when it's normal we will have the stock path as namespace\n * 3. when enableAuth then we will have two, one is jsonql/public + private\n * @param {object} config options\n * @return {array} of namespace(s)\n */\nexport function getNamespace(config) {\n const base = JSONQL_PATH\n if (config.enableAuth) {\n // the public come first @1.0.1 we use the constants instead of the user supplied value\n // @1.0.4 we use the config value again, because we could control this via the post init\n return [\n [ base , config.privateNamespace ].join('/'),\n [ base , config.publicNamespace ].join('/')\n ]\n }\n return [ base ]\n}\n\n/**\n * get the private namespace\n * @param {array} namespaces array\n * @return {*} string on success\n */\nexport function getPrivateNamespace(namespaces) {\n return namespaces.length > 1 ? namespaces[0] : false\n}\n\n/**\n * Got a problem with a contract that is public only the groupByNamespace is wrong\n * which is actually not a problem when using a fallback, but to be sure things in order\n * we could combine with the config to group it\n * @param {object} config configuration\n * @return {object} nspInfo object\n */\nexport function getNspInfoByConfig(config) {\n const { contract, enableAuth } = config\n const namespaces = getNamespace(config)\n let nspInfo = enableAuth ? groupByNamespace(contract)\n : groupPublicNamespace(contract.socket, namespaces[0])\n // add the namespaces into it as well\n return Object.assign(nspInfo, { namespaces })\n}\n\n","// There are the socket related methods ported back from \n// ws-server-core and ws-client-core \nimport {\n WS_REPLY_TYPE,\n WS_EVT_NAME,\n WS_DATA_NAME,\n TIMESTAMP_PARAM_NAME,\n ERROR_KEY,\n EMIT_REPLY_TYPE,\n ACKNOWLEDGE_REPLY_TYPE\n} from 'jsonql-constants'\nimport { JsonqlError } from 'jsonql-errors' \nimport isString from 'lodash-es/isString'\n\nimport { toJson, isObjectHasKey, nil } from './generic'\nimport { timestamp } from './timestamp'\n\nconst PAYLOAD_NOT_DECODED_ERR = 'payload can not decoded'\nconst WS_KEYS = [\n WS_REPLY_TYPE,\n WS_EVT_NAME,\n WS_DATA_NAME\n]\n\n/////////////////////////////////////\n// REPLY FROM SERVER //\n/////////////////////////////////////\n\n\n/**\n * The ws doesn't have a acknowledge callback like socket.io\n * so we have to DIY one for ws and other that doesn't have it\n * @param {string} type of reply\n * @param {string} resolverName which is replying\n * @param {*} data payload\n * @param {array} [ts= []] the last received ts, if any \n * @return {string} stringify json\n */\nexport const createWsReply = (type, resolverName, data, ts = []) => {\n ts.push(timestamp())\n return JSON.stringify({\n data: {\n [WS_REPLY_TYPE]: type,\n [WS_EVT_NAME]: resolverName,\n [WS_DATA_NAME]: toJson(data)\n },\n [TIMESTAMP_PARAM_NAME]: ts \n })\n}\n\n// extended function \nexport const createReplyMsg = (resolverName, data, ts = []) => (\n createWsReply(EMIT_REPLY_TYPE, resolverName, data, ts)\n)\n\nexport const createAcknowledgeMsg = (resolverName, data, ts = []) => (\n createWsReply(ACKNOWLEDGE_REPLY_TYPE, resolverName, data, ts)\n)\n\n/**\n * @param {string|object} payload should be string when reply but could be transformed\n * @return {boolean} true is OK\n */\nexport const isWsReply = payload => {\n const json = isString(payload) ? toJson(payload) : payload\n const { data } = json\n if (data) {\n let result = WS_KEYS.filter(key => isObjectHasKey(data, key))\n return (result.length === WS_KEYS.length) ? data : false\n }\n return false\n}\n\n/**\n * @param {string|object} data received data\n * @param {function} [cb=nil] this is for extracting the TS field or when it's error\n * @return {object} false on failed\n */\nexport const extractWsPayload = (payload, cb = nil) => {\n try {\n const json = toJson(payload)\n // now handle the data\n let _data\n if ((_data = isWsReply(json)) !== false) {\n // note the ts property is on its own \n cb(TIMESTAMP_PARAM_NAME, json[TIMESTAMP_PARAM_NAME])\n \n return {\n data: toJson(_data[WS_DATA_NAME]),\n resolverName: _data[WS_EVT_NAME],\n type: _data[WS_REPLY_TYPE]\n }\n }\n throw new JsonqlError(PAYLOAD_NOT_DECODED_ERR, payload)\n } catch(e) {\n return cb(ERROR_KEY, e)\n }\n}\n","// this will be part of the init client sequence\n// as soon as we create a ws client\n// we listen to the on.connect event \n// then we send a init-ping event back to the server\n// and server issue a csrf token back to use \n// we use this token to create a new client and destroy the old one\nimport {\n INTERCOM_RESOLVER_NAME, \n SOCKET_PING_EVENT_NAME,\n HEADERS_KEY,\n DATA_KEY,\n CSRF_HEADER_KEY\n} from 'jsonql-constants'\nimport { \n createQueryStr, \n extractWsPayload,\n timestamp,\n toJson \n} from 'jsonql-utils/module'\nimport {\n JsonqlError\n} from 'jsonql-errors'\nconst CSRF_HEADER_NOT_EXIST_ERR = 'CSRF header is not in the received payload'\n\n/**\n * Util method \n * @param {string} payload return from server\n * @return {object} the useful bit \n */\nfunction extractSrvPayload(payload) {\n let json = toJson(payload)\n \n if (json && typeof json === 'object') {\n // note this method expect the json.data inside\n return extractWsPayload(json)\n }\n \n throw new JsonqlError('extractSrvPayload', json)\n}\n\n/**\n * call the server to get a csrf token \n * @return {string} formatted payload to send to the server \n */\nfunction createInitPing() {\n const ts = timestamp()\n\n return createQueryStr(INTERCOM_RESOLVER_NAME, [SOCKET_PING_EVENT_NAME, ts])\n}\n\n/**\n * Take the raw on.message result back then decoded it \n * @param {*} payload the raw result from server\n * @return {object} the csrf payload\n */\nfunction extractPingResult(payload) {\n const result = extractSrvPayload(payload)\n \n if (result && result[DATA_KEY] && result[DATA_KEY][CSRF_HEADER_KEY]) {\n return {\n [HEADERS_KEY]: result[DATA_KEY]\n }\n }\n\n throw new JsonqlError('extractPingResult', CSRF_HEADER_NOT_EXIST_ERR)\n}\n\n\n/**\n * Create a generic intercom method\n * @param {string} type the event type \n * @param {array} args if any \n * @return {string} formatted payload to send\n */\nfunction createIntercomPayload(type, ...args) {\n const ts = timestamp()\n let payload = [type].concat(args)\n payload.push(ts)\n return createQueryStr(INTERCOM_RESOLVER_NAME, payload)\n}\n\n\nexport { \n extractSrvPayload,\n createInitPing, \n extractPingResult, \n createIntercomPayload \n}","// validator numbers\n// import { NUMBER_TYPES } from './constants';\n\nimport isNaN from 'lodash-es/isNaN'\nimport isString from 'lodash-es/isString'\n/**\n * @2015-05-04 found a problem if the value is a number like string\n * it will pass, so add a chck if it's string before we pass to next\n * @param {number} value expected value\n * @return {boolean} true if OK\n */\nconst checkIsNumber = function(value) {\n return isString(value) ? false : !isNaN( parseFloat(value) )\n}\n\nexport default checkIsNumber\n","// validate string type\nimport trim from 'lodash-es/trim'\nimport isString from 'lodash-es/isString'\n/**\n * @param {string} value expected value\n * @return {boolean} true if OK\n */\nconst checkIsString = function(value) {\n return (trim(value) !== '') ? isString(value) : false\n}\n\nexport default checkIsString\n","// check for boolean\n\n/**\n * @param {boolean} value expected\n * @return {boolean} true if OK\n */\nconst checkIsBoolean = function(value) {\n return value !== null && value !== undefined && typeof value === 'boolean'\n}\n\nexport default checkIsBoolean\n","// validate any thing only check if there is something\n\nimport trim from 'lodash-es/trim'\n\n/**\n * @param {*} value the value\n * @param {boolean} [checkNull=true] strict check if there is null value\n * @return {boolean} true is OK\n */\nconst checkIsAny = function(value, checkNull = true) {\n if (value !== undefined && value !== '' && trim(value) !== '') {\n if (checkNull === false || (checkNull === true && value !== null)) {\n return true;\n }\n }\n return false;\n}\n\nexport default checkIsAny\n","// Good practice rule - No magic number\n\nconst ARGS_NOT_ARRAY_ERR = `args is not an array! You might want to do: ES6 Array.from(arguments) or ES5 Array.prototype.slice.call(arguments)`\nconst PARAMS_NOT_ARRAY_ERR = `params is not an array! Did something gone wrong when you generate the contract.json?`\nconst EXCEPTION_CASE_ERR = 'Could not understand your arguments and parameter structure!'\nconst UNUSUAL_CASE_ERR = 'This is an unusual situation where the arguments are more than the params, but not mark as spread'\n\nconst RETURNS_NAME = 'returns'\n\nimport {\n \n DEFAULT_TYPE, // this is a mistake should move back to the validation\n DATA_KEY, \n ERROR_KEY,\n\n TYPE_KEY,\n OPTIONAL_KEY,\n ENUM_KEY,\n ARGS_KEY,\n CHECKER_KEY,\n ALIAS_KEY,\n\n ARRAY_TYPE_LFT,\n ARRAY_TYPE_RGT,\n \n ARRAY_TYPE,\n OBJECT_TYPE,\n STRING_TYPE,\n BOOLEAN_TYPE,\n NUMBER_TYPE,\n KEY_WORD,\n OR_SEPERATOR\n} from 'jsonql-constants'\n\n// group all export in one \nexport {\n ARGS_NOT_ARRAY_ERR,\n PARAMS_NOT_ARRAY_ERR,\n EXCEPTION_CASE_ERR,\n UNUSUAL_CASE_ERR,\n DEFAULT_TYPE,\n ARRAY_TYPE_LFT,\n ARRAY_TYPE_RGT,\n TYPE_KEY,\n OPTIONAL_KEY,\n ENUM_KEY,\n ARGS_KEY,\n CHECKER_KEY,\n ALIAS_KEY,\n ARRAY_TYPE,\n OBJECT_TYPE,\n STRING_TYPE,\n BOOLEAN_TYPE,\n NUMBER_TYPE,\n KEY_WORD,\n OR_SEPERATOR,\n\n RETURNS_NAME,\n\n DATA_KEY, \n ERROR_KEY \n}","// primitive types\nimport checkIsNumber from './number'\nimport checkIsString from './string'\nimport checkIsBoolean from './boolean'\nimport checkIsAny from './any'\nimport { NUMBER_TYPE, STRING_TYPE, BOOLEAN_TYPE } from './constants'\n\n/**\n * this is a wrapper method to call different one based on their type\n * @param {string} type to check\n * @return {function} a function to handle the type\n */\nconst combineFn = function(type) {\n switch (type) {\n case NUMBER_TYPE:\n return checkIsNumber\n case STRING_TYPE:\n return checkIsString\n case BOOLEAN_TYPE:\n return checkIsBoolean\n default:\n return checkIsAny\n }\n}\n\nexport default combineFn\n","// validate array type\n\nimport isArray from 'lodash-es/isArray'\nimport trim from 'lodash-es/trim'\nimport combineFn from './combine'\nimport {\n ARRAY_TYPE_LFT,\n ARRAY_TYPE_RGT,\n OR_SEPERATOR\n} from './constants'\n\n/**\n * @param {array} value expected\n * @param {string} [type=''] pass the type if we encounter array. then we need to check the value as well\n * @return {boolean} true if OK\n */\nexport const checkIsArray = function(value, type='') {\n if (isArray(value)) {\n if (type === '' || trim(type)==='') {\n return true;\n }\n // we test it in reverse\n // @TODO if the type is an array (OR) then what?\n // we need to take into account this could be an array\n const c = value.filter(v => !combineFn(type)(v))\n return !(c.length > 0)\n }\n return false\n}\n\n/**\n * check if it matches the array. pattern\n * @param {string} type\n * @return {boolean|array} false means NO, always return array\n */\nexport const isArrayLike = function(type) {\n // @TODO could that have something like array<> instead of array.<>? missing the dot?\n // because type script is Array without the dot\n if (type.indexOf(ARRAY_TYPE_LFT) > -1 && type.indexOf(ARRAY_TYPE_RGT) > -1) {\n const _type = type.replace(ARRAY_TYPE_LFT, '').replace(ARRAY_TYPE_RGT, '')\n if (_type.indexOf(OR_SEPERATOR)) {\n return _type.split(OR_SEPERATOR)\n }\n return [_type]\n }\n return false\n}\n\n/**\n * we might encounter something like array. then we need to take it apart\n * @param {object} p the prepared object for processing\n * @param {string|array} type the type came from \n * @return {boolean} for the filter to operate on\n */\nexport const arrayTypeHandler = function(p, type) {\n const { arg } = p\n // need a special case to handle the OR type\n // we need to test the args instead of the type(s)\n if (type.length > 1) {\n return !arg.filter(v => (\n !(type.length > type.filter(t => !combineFn(t)(v)).length)\n )).length\n }\n // type is array so this will be or!\n return type.length > type.filter(t => !checkIsArray(arg, t)).length\n}\n","// validate object type\n\nimport isPlainObject from 'lodash-es/isPlainObject'\n// import filter from 'lodash-es/filter'\nimport combineFn from './combine'\nimport { checkIsArray, isArrayLike, arrayTypeHandler } from './array'\n/**\n * @TODO if provide with the keys then we need to check if the key:value type as well\n * @param {object} value expected\n * @param {array} [keys=null] if it has the keys array to compare as well\n * @return {boolean} true if OK\n */\nexport const checkIsObject = function(value, keys=null) {\n if (isPlainObject(value)) {\n if (!keys) {\n return true\n }\n if (checkIsArray(keys)) {\n // please note we DON'T care if some is optional\n // plese refer to the contract.json for the keys\n return !keys.filter(key => {\n let _value = value[key.name];\n return !(key.type.length > key.type.filter(type => {\n let tmp;\n if (_value !== undefined) {\n if ((tmp = isArrayLike(type)) !== false) {\n return !arrayTypeHandler({arg: _value}, tmp)\n // return tmp.filter(t => !checkIsArray(_value, t)).length;\n // @TODO there might be an object within an object with keys as well :S\n }\n return !combineFn(type)(_value)\n }\n return true\n }).length)\n }).length;\n }\n }\n return false\n}\n\n/**\n * fold this into it's own function to handler different object type\n * @param {object} p the prepared object for process\n * @return {boolean}\n */\nexport const objectTypeHandler = function(p) {\n const { arg, param } = p\n let _args = [arg]\n if (Array.isArray(param.keys) && param.keys.length) {\n _args.push(param.keys)\n }\n // just simple check\n return Reflect.apply(checkIsObject, null, _args)\n}\n","// move the index.js code here that make more sense to find where things are\n\nimport {\n checkIsArray,\n isArrayLike,\n arrayTypeHandler,\n objectTypeHandler,\n combineFn,\n notEmpty\n} from './index'\n\nimport {\n DEFAULT_TYPE,\n ARRAY_TYPE,\n OBJECT_TYPE,\n ARGS_NOT_ARRAY_ERR,\n PARAMS_NOT_ARRAY_ERR,\n EXCEPTION_CASE_ERR,\n DATA_KEY, \n ERROR_KEY \n} from './constants'\n\n\nimport JsonqlValidationError from 'jsonql-errors/src/validation-error'\nimport JsonqlError from 'jsonql-errors/src/error'\n// import debug from 'debug'\n// const debugFn = debug('jsonql-params-validator:validator')\n// also export this for use in other places\n\n/**\n * We need to handle those optional parameter without a default value\n * @param {object} params from contract.json\n * @return {boolean} for filter operation false is actually OK\n */\nconst optionalHandler = function( params ) {\n const { arg, param } = params\n if (notEmpty(arg)) {\n // debug('call optional handler', arg, params);\n // loop through the type in param\n return !(param.type.length > param.type.filter(type =>\n validateHandler(type, params)\n ).length)\n }\n return false\n}\n\n/**\n * actually picking the validator\n * @param {*} type for checking\n * @param {*} value for checking\n * @return {boolean} true on OK\n */\nconst validateHandler = function(type, value) {\n let tmp;\n switch (true) {\n case type === OBJECT_TYPE:\n // debugFn('call OBJECT_TYPE')\n return !objectTypeHandler(value)\n case type === ARRAY_TYPE:\n // debugFn('call ARRAY_TYPE')\n return !checkIsArray(value.arg)\n // @TODO when the type is not present, it always fall through here\n // so we need to find a way to actually pre-check the type first\n // AKA check the contract.json map before running here\n case (tmp = isArrayLike(type)) !== false:\n // debugFn('call ARRAY_LIKE: %O', value)\n return !arrayTypeHandler(value, tmp)\n default:\n return !combineFn(type)(value.arg)\n }\n}\n\n/**\n * it get too longer to fit in one line so break it out from the fn below\n * @param {*} arg value\n * @param {object} param config\n * @return {*} value or apply default value\n */\nconst getOptionalValue = function(arg, param) {\n if (arg !== undefined) {\n return arg\n }\n return (param.optional === true && param.defaultvalue !== undefined ? param.defaultvalue : null)\n}\n\n/**\n * padding the arguments with defaultValue if the arguments did not provide the value\n * this will be the name export\n * @param {array} args normalized arguments\n * @param {array} params from contract.json\n * @return {array} merge the two together\n */\nexport const normalizeArgs = function(args, params) {\n // first we should check if this call require a validation at all\n // there will be situation where the function doesn't need args and params\n if (!checkIsArray(params)) {\n // debugFn('params value', params)\n throw new JsonqlValidationError(PARAMS_NOT_ARRAY_ERR)\n }\n if (params.length === 0) {\n return []\n }\n if (!checkIsArray(args)) {\n throw new JsonqlValidationError(ARGS_NOT_ARRAY_ERR)\n }\n // debugFn(args, params);\n // fall through switch\n switch(true) {\n case args.length == params.length: // standard\n return args.map((arg, i) => (\n {\n arg,\n index: i,\n param: params[i]\n }\n ))\n case params[0].variable === true: // using spread syntax\n const type = params[0].type;\n return args.map((arg, i) => (\n {\n arg,\n index: i, // keep the index for reference\n param: params[i] || { type, name: '_' }\n }\n ))\n // with optional defaultValue parameters\n case args.length < params.length:\n return params.map((param, i) => (\n {\n param,\n index: i,\n arg: getOptionalValue(args[i], param),\n optional: param.optional || false\n }\n ))\n // this one pass more than it should have anything after the args.length will be cast as any type\n case args.length > params.length:\n let ctn = params.length;\n // this happens when we have those array. type\n let _type = [ DEFAULT_TYPE ]\n // we only looking at the first one, this might be a @BUG\n /*\n if ((tmp = isArrayLike(params[0].type[0])) !== false) {\n _type = tmp;\n } */\n // if we use the params as guide then the rest will get throw out\n // which is not what we want, instead, anything without the param\n // will get a any type and optional flag\n return args.map((arg, i) => {\n let optional = i >= ctn ? true : !!params[i].optional\n let param = params[i] || { type: _type, name: `_${i}` }\n return {\n arg: optional ? getOptionalValue(arg, param) : arg,\n index: i,\n param,\n optional\n }\n })\n // @TODO find out if there is more cases not cover\n default: // this should never happen\n // debugFn('args', args)\n // debugFn('params', params)\n // this is unknown therefore we just throw it!\n throw new JsonqlError(EXCEPTION_CASE_ERR, { args, params })\n }\n}\n\n// what we want is after the validaton we also get the normalized result\n// which is with the optional property if the argument didn't provide it\n/**\n * process the array of params back to their arguments\n * @param {array} result the params result\n * @return {array} arguments\n */\nconst processReturn = result => result.map(r => r.arg)\n\n/**\n * validator main interface\n * @param {array} args the arguments pass to the method call\n * @param {array} params from the contract for that method\n * @param {boolean} [withResul=false] if true then this will return the normalize result as well\n * @return {array} empty array on success, or failed parameter and reasons\n */\nexport const validateSync = function(args, params, withResult = false) {\n let cleanArgs = normalizeArgs(args, params)\n let checkResult = cleanArgs.filter(p => {\n // v1.4.4 this fixed the problem, the root level optional is from the last fn\n if (p.optional === true || p.param.optional === true) {\n return optionalHandler(p)\n }\n // because array of types means OR so if one pass means pass\n return !(p.param.type.length > p.param.type.filter(\n type => validateHandler(type, p)\n ).length)\n })\n // using the same convention we been using all this time\n return !withResult ? checkResult : {\n [ERROR_KEY]: checkResult,\n [DATA_KEY]: processReturn(cleanArgs)\n }\n}\n\n/**\n * A wrapper method that return promise\n * @param {array} args arguments\n * @param {array} params from contract.json\n * @param {boolean} [withResul=false] if true then this will return the normalize result as well\n * @return {object} promise.then or catch\n */\nexport const validateAsync = function(args, params, withResult = false) {\n return new Promise((resolver, rejecter) => {\n const result = validateSync(args, params, withResult)\n if (withResult) {\n return result[ERROR_KEY].length ? rejecter(result[ERROR_KEY])\n : resolver(result[DATA_KEY])\n }\n // the different is just in the then or catch phrase\n return result.length ? rejecter(result) : resolver([])\n })\n}\n","/** Used to stand-in for `undefined` hash values. */\nvar HASH_UNDEFINED = '__lodash_hash_undefined__';\n\n/**\n * Adds `value` to the array cache.\n *\n * @private\n * @name add\n * @memberOf SetCache\n * @alias push\n * @param {*} value The value to cache.\n * @returns {Object} Returns the cache instance.\n */\nfunction setCacheAdd(value) {\n this.__data__.set(value, HASH_UNDEFINED);\n return this;\n}\n\nexport default setCacheAdd;\n","/**\n * Checks if `value` is in the array cache.\n *\n * @private\n * @name has\n * @memberOf SetCache\n * @param {*} value The value to search for.\n * @returns {number} Returns `true` if `value` is found, else `false`.\n */\nfunction setCacheHas(value) {\n return this.__data__.has(value);\n}\n\nexport default setCacheHas;\n","/**\n * A specialized version of `_.some` for arrays without support for iteratee\n * shorthands.\n *\n * @private\n * @param {Array} [array] The array to iterate over.\n * @param {Function} predicate The function invoked per iteration.\n * @returns {boolean} Returns `true` if any element passes the predicate check,\n * else `false`.\n */\nfunction arraySome(array, predicate) {\n var index = -1,\n length = array == null ? 0 : array.length;\n\n while (++index < length) {\n if (predicate(array[index], index, array)) {\n return true;\n }\n }\n return false;\n}\n\nexport default arraySome;\n","/**\n * Checks if a `cache` value for `key` exists.\n *\n * @private\n * @param {Object} cache The cache to query.\n * @param {string} key The key of the entry to check.\n * @returns {boolean} Returns `true` if an entry for `key` exists, else `false`.\n */\nfunction cacheHas(cache, key) {\n return cache.has(key);\n}\n\nexport default cacheHas;\n","/**\n * Converts `map` to its key-value pairs.\n *\n * @private\n * @param {Object} map The map to convert.\n * @returns {Array} Returns the key-value pairs.\n */\nfunction mapToArray(map) {\n var index = -1,\n result = Array(map.size);\n\n map.forEach(function(value, key) {\n result[++index] = [key, value];\n });\n return result;\n}\n\nexport default mapToArray;\n","/**\n * Converts `set` to an array of its values.\n *\n * @private\n * @param {Object} set The set to convert.\n * @returns {Array} Returns the values.\n */\nfunction setToArray(set) {\n var index = -1,\n result = Array(set.size);\n\n set.forEach(function(value) {\n result[++index] = value;\n });\n return result;\n}\n\nexport default setToArray;\n","/**\n * Appends the elements of `values` to `array`.\n *\n * @private\n * @param {Array} array The array to modify.\n * @param {Array} values The values to append.\n * @returns {Array} Returns `array`.\n */\nfunction arrayPush(array, values) {\n var index = -1,\n length = values.length,\n offset = array.length;\n\n while (++index < length) {\n array[offset + index] = values[index];\n }\n return array;\n}\n\nexport default arrayPush;\n","/**\n * A specialized version of `_.filter` for arrays without support for\n * iteratee shorthands.\n *\n * @private\n * @param {Array} [array] The array to iterate over.\n * @param {Function} predicate The function invoked per iteration.\n * @returns {Array} Returns the new filtered array.\n */\nfunction arrayFilter(array, predicate) {\n var index = -1,\n length = array == null ? 0 : array.length,\n resIndex = 0,\n result = [];\n\n while (++index < length) {\n var value = array[index];\n if (predicate(value, index, array)) {\n result[resIndex++] = value;\n }\n }\n return result;\n}\n\nexport default arrayFilter;\n","/**\n * This method returns a new empty array.\n *\n * @static\n * @memberOf _\n * @since 4.13.0\n * @category Util\n * @returns {Array} Returns the new empty array.\n * @example\n *\n * var arrays = _.times(2, _.stubArray);\n *\n * console.log(arrays);\n * // => [[], []]\n *\n * console.log(arrays[0] === arrays[1]);\n * // => false\n */\nfunction stubArray() {\n return [];\n}\n\nexport default stubArray;\n","/**\n * A specialized version of `matchesProperty` for source values suitable\n * for strict equality comparisons, i.e. `===`.\n *\n * @private\n * @param {string} key The key of the property to get.\n * @param {*} srcValue The value to match.\n * @returns {Function} Returns the new spec function.\n */\nfunction matchesStrictComparable(key, srcValue) {\n return function(object) {\n if (object == null) {\n return false;\n }\n return object[key] === srcValue &&\n (srcValue !== undefined || (key in Object(object)));\n };\n}\n\nexport default matchesStrictComparable;\n","/**\n * The base implementation of `_.hasIn` without support for deep paths.\n *\n * @private\n * @param {Object} [object] The object to query.\n * @param {Array|string} key The key to check.\n * @returns {boolean} Returns `true` if `key` exists, else `false`.\n */\nfunction baseHasIn(object, key) {\n return object != null && key in Object(object);\n}\n\nexport default baseHasIn;\n","/**\n * The base implementation of `_.property` without support for deep paths.\n *\n * @private\n * @param {string} key The key of the property to get.\n * @returns {Function} Returns the new accessor function.\n */\nfunction baseProperty(key) {\n return function(object) {\n return object == null ? undefined : object[key];\n };\n}\n\nexport default baseProperty;\n","/** Error message constants. */\nvar FUNC_ERROR_TEXT = 'Expected a function';\n\n/**\n * Creates a function that negates the result of the predicate `func`. The\n * `func` predicate is invoked with the `this` binding and arguments of the\n * created function.\n *\n * @static\n * @memberOf _\n * @since 3.0.0\n * @category Function\n * @param {Function} predicate The predicate to negate.\n * @returns {Function} Returns the new negated function.\n * @example\n *\n * function isEven(n) {\n * return n % 2 == 0;\n * }\n *\n * _.filter([1, 2, 3, 4, 5, 6], _.negate(isEven));\n * // => [1, 3, 5]\n */\nfunction negate(predicate) {\n if (typeof predicate != 'function') {\n throw new TypeError(FUNC_ERROR_TEXT);\n }\n return function() {\n var args = arguments;\n switch (args.length) {\n case 0: return !predicate.call(this);\n case 1: return !predicate.call(this, args[0]);\n case 2: return !predicate.call(this, args[0], args[1]);\n case 3: return !predicate.call(this, args[0], args[1], args[2]);\n }\n return !predicate.apply(this, args);\n };\n}\n\nexport default negate;\n","/**\n * The base implementation of methods like `_.findKey` and `_.findLastKey`,\n * without support for iteratee shorthands, which iterates over `collection`\n * using `eachFunc`.\n *\n * @private\n * @param {Array|Object} collection The collection to inspect.\n * @param {Function} predicate The function invoked per iteration.\n * @param {Function} eachFunc The function to iterate over `collection`.\n * @returns {*} Returns the found element or its key, else `undefined`.\n */\nfunction baseFindKey(collection, predicate, eachFunc) {\n var result;\n eachFunc(collection, function(value, key, collection) {\n if (predicate(value, key, collection)) {\n result = key;\n return false;\n }\n });\n return result;\n}\n\nexport default baseFindKey;\n","/**\n * @param {array} arr Array for check\n * @param {*} value target\n * @return {boolean} true on successs\n */\nconst isInArray = function(arr, value) {\n return !!arr.filter(a => a === value).length\n}\n\nexport default isInArray\n","// breaking the whole thing up to see what cause the multiple calls issue\n\nimport isFunction from 'lodash-es/isFunction'\nimport merge from 'lodash-es/merge'\nimport mapValues from 'lodash-es/mapValues'\n\nimport JsonqlEnumError from 'jsonql-errors/src/enum-error'\nimport JsonqlTypeError from 'jsonql-errors/src/type-error'\nimport JsonqlCheckerError from 'jsonql-errors/src/checker-error'\n\nimport {\n TYPE_KEY,\n OPTIONAL_KEY,\n ENUM_KEY,\n ARGS_KEY,\n CHECKER_KEY,\n KEY_WORD\n} from '../constants'\nimport { checkIsArray } from '../array'\n\n// import debug from 'debug';\n// const debugFn = debug('jsonql-params-validator:options:validation')\n\n/**\n * just make sure it returns an array to use\n * @param {*} arg input\n * @return {array} output\n */\nconst toArray = arg => checkIsArray(arg) ? arg : [arg]\n\n/**\n * DIY in array\n * @param {array} arr to check against\n * @param {*} value to check\n * @return {boolean} true on OK\n */\nconst inArray = (arr, value) => (\n !!arr.filter(v => v === value).length\n)\n\n/**\n * break out to make the code easier to read\n * @param {object} value to process\n * @param {function} cb the validateSync\n * @return {array} empty on success\n */\nfunction validateHandler(value, cb) {\n // cb is the validateSync methods\n let args = [\n [ value[ARGS_KEY] ],\n [{\n [TYPE_KEY]: toArray(value[TYPE_KEY]),\n [OPTIONAL_KEY]: value[OPTIONAL_KEY]\n }]\n ]\n // debugFn('validateHandler', args)\n return Reflect.apply(cb, null, args)\n}\n\n/**\n * Check against the enum value if it's provided\n * @param {*} value to check\n * @param {*} enumv to check against if it's not false\n * @return {boolean} true on OK\n */\nconst enumHandler = (value, enumv) => {\n if (checkIsArray(enumv)) {\n return inArray(enumv, value)\n }\n return true\n}\n\n/**\n * Allow passing a function to check the value\n * There might be a problem here if the function is incorrect\n * and that will makes it hard to debug what is going on inside\n * @TODO there could be a few feature add to this one under different circumstance\n * @param {*} value to check\n * @param {function} checker for checking\n */\nconst checkerHandler = (value, checker) => {\n try {\n return isFunction(checker) ? checker.apply(null, [value]) : false\n } catch (e) {\n return false\n }\n}\n\n/**\n * Taken out from the runValidaton this only validate the required values\n * @param {array} args from the config2argsAction\n * @param {function} cb validateSync\n * @return {array} of configuration values\n */\nfunction runValidationAction(cb) {\n return (value, key) => {\n // debugFn('runValidationAction', key, value)\n if (value[KEY_WORD]) {\n return value[ARGS_KEY]\n }\n const check = validateHandler(value, cb)\n if (check.length) {\n // log('runValidationAction', key, value)\n throw new JsonqlTypeError(key, check)\n }\n if (value[ENUM_KEY] !== false && !enumHandler(value[ARGS_KEY], value[ENUM_KEY])) {\n // log(ENUM_KEY, value[ENUM_KEY])\n throw new JsonqlEnumError(key)\n }\n if (value[CHECKER_KEY] !== false && !checkerHandler(value[ARGS_KEY], value[CHECKER_KEY])) {\n // log(CHECKER_KEY, value[CHECKER_KEY])\n throw new JsonqlCheckerError(key)\n }\n return value[ARGS_KEY]\n }\n}\n\n/**\n * @param {object} args from the config2argsAction\n * @param {function} cb validateSync\n * @return {object} of configuration values\n */\nexport default function runValidation(args, cb) {\n const [ argsForValidate, pristineValues ] = args\n // turn the thing into an array and see what happen here\n // debugFn('_args', argsForValidate)\n const result = mapValues(argsForValidate, runValidationAction(cb))\n return merge(result, pristineValues)\n}\n","/// this is port back from the client to share across all projects\n\nimport merge from 'lodash-es/merge'\nimport { prepareArgsForValidation } from './prepare-args-for-validation'\nimport runValidation from './run-validation'\n\n// import debug from 'debug'\n// const debugFn = debug('jsonql-params-validator:check-options-async')\n\n/**\n * Quick transform\n * @param {object} config that one\n * @param {object} appProps mutation configuration options\n * @return {object} put that arg into the args\n */\nconst configToArgs = (config, appProps) => {\n return Promise.resolve(\n prepareArgsForValidation(config, appProps)\n )\n}\n\n/**\n * @param {object} config user provide configuration option\n * @param {object} appProps mutation configuration options\n * @param {object} constProps the immutable configuration options\n * @param {function} cb the validateSync method\n * @return {object} Promise resolve merge config object\n */\nexport default function(config = {}, appProps, constProps, cb) {\n return configToArgs(config, appProps)\n .then(args1 => runValidation(args1, cb))\n // next if every thing good then pass to final merging\n .then(args2 => merge({}, args2, constProps))\n}\n","// create function to construct the config entry so we don't need to keep building object\n\nimport isFunction from 'lodash-es/isFunction'\nimport isString from 'lodash-es/isString'\nimport {\n ARGS_KEY,\n TYPE_KEY,\n CHECKER_KEY,\n ENUM_KEY,\n OPTIONAL_KEY,\n ALIAS_KEY\n} from 'jsonql-constants'\n\nimport { checkIsArray } from '../array'\n// import checkIsBoolean from '../boolean'\n// import debug from 'debug';\n// const debugFn = debug('jsonql-params-validator:construct-config');\n/**\n * @param {*} args value\n * @param {string} type for value\n * @param {boolean} [optional=false]\n * @param {boolean|array} [enumv=false]\n * @param {boolean|function} [checker=false]\n * @return {object} config entry\n */\nexport default function constructConfig(args, type, optional=false, enumv=false, checker=false, alias=false) {\n let base = {\n [ARGS_KEY]: args,\n [TYPE_KEY]: type\n }\n if (optional === true) {\n base[OPTIONAL_KEY] = true\n }\n if (checkIsArray(enumv)) {\n base[ENUM_KEY] = enumv\n }\n if (isFunction(checker)) {\n base[CHECKER_KEY] = checker\n }\n if (isString(alias)) {\n base[ALIAS_KEY] = alias\n }\n return base\n}\n","// export also create wrapper methods\nimport checkOptionsAsync from './check-options-async'\nimport checkOptionsSync from './check-options-sync'\nimport constructConfigFn from './construct-config'\nimport {\n ENUM_KEY,\n CHECKER_KEY,\n ALIAS_KEY,\n OPTIONAL_KEY\n} from 'jsonql-constants'\n\n/**\n * This has a different interface\n * @param {*} value to supply\n * @param {string|array} type for checking\n * @param {object} params to map against the config check\n * @param {array} params.enumv NOT enum\n * @param {boolean} params.optional false then nothing\n * @param {function} params.checker need more work on this one later\n * @param {string} params.alias mostly for cmd\n */\nconst createConfig = (value, type, params = {}) => {\n // Note the enumv not ENUM\n // const { enumv, optional, checker, alias } = params;\n // let args = [value, type, optional, enumv, checker, alias];\n const {\n [OPTIONAL_KEY]: o,\n [ENUM_KEY]: e,\n [CHECKER_KEY]: c,\n [ALIAS_KEY]: a\n } = params;\n return constructConfigFn.apply(null, [value, type, o, e, c, a])\n}\n\n// for testing purpose\nconst JSONQL_PARAMS_VALIDATOR_INFO = '__PLACEHOLDER__'\n\n/**\n * construct the actual end user method, rename with prefix get since 1.5.2\n * @param {function} validateSync validation method\n * @return {function} for performaning the actual valdiation\n */\nconst getCheckConfigAsync = function(validateSync) {\n /**\n * We recreate the method here to avoid the circlar import\n * @param {object} config user supply configuration\n * @param {object} appProps mutation options\n * @param {object} [constantProps={}] optional: immutation options\n * @return {object} all checked configuration\n */\n return function(config, appProps, constantProps= {}) {\n return checkOptionsAsync(config, appProps, constantProps, validateSync)\n }\n}\n\n/**\n * copy of above but it's sync, rename with prefix get since 1.5.2\n * @param {function} validateSync validation method\n * @return {function} for performaning the actual valdiation\n */\nconst getCheckConfig = function(validateSync) {\n return function(config, appProps, constantProps = {}) {\n return checkOptionsSync(config, appProps, constantProps, validateSync)\n }\n}\n\n// re-export\nexport {\n createConfig,\n constructConfigFn,\n getCheckConfigAsync,\n getCheckConfig,\n JSONQL_PARAMS_VALIDATOR_INFO\n}\n","// export\nimport {\n checkIsObject,\n notEmpty,\n checkIsAny,\n checkIsString,\n checkIsBoolean,\n checkIsNumber,\n checkIsArray\n} from './src'\nimport * as validator from './src/validator'\n// configuration checking\nimport * as jsonqlOptions from './src/options'\n// the two extra functions\nimport isInArray from './src/is-in-array'\nimport isObjectHasKeyFn from './src/is-key-in-object'\n\nconst isObject = checkIsObject\nconst isAny = checkIsAny\nconst isString = checkIsString\nconst isBoolean = checkIsBoolean\nconst isNumber = checkIsNumber\nconst isArray = checkIsArray\nconst isNotEmpty = notEmpty\n\nconst normalizeArgs = validator.normalizeArgs\nconst validateSync = validator.validateSync\nconst validateAsync = validator.validateAsync\n\nconst JSONQL_PARAMS_VALIDATOR_INFO = jsonqlOptions.JSONQL_PARAMS_VALIDATOR_INFO\n\nconst createConfig = jsonqlOptions.createConfig\nconst constructConfig = jsonqlOptions.constructConfigFn\n// construct the final output 1.5.2\nconst checkConfigAsync = jsonqlOptions.getCheckConfigAsync(validator.validateSync)\nconst checkConfig = jsonqlOptions.getCheckConfig(validator.validateSync)\n\nconst inArray = isInArray\nconst isObjectHasKey = isObjectHasKeyFn\n\n// check returns methods \nimport { \n checkReturns, \n checkReturnsAsync, \n checkResolverReturns, \n checkResolverReturnsAsync \n} from './src/returns'\n\n\n// group the in one \nexport {\n JSONQL_PARAMS_VALIDATOR_INFO,\n \n isObject,\n isAny,\n isString,\n isBoolean,\n isNumber,\n isArray,\n isNotEmpty,\n \n inArray,\n isObjectHasKey,\n\n normalizeArgs,\n validateSync,\n validateAsync,\n\n createConfig,\n constructConfig,\n checkConfig,\n checkConfigAsync,\n\n checkReturns, \n checkReturnsAsync, \n checkResolverReturns, \n checkResolverReturnsAsync\n}\n\n\n\n\n\n","// move the get logger stuff here\n\n// it does nothing\nconst dummyLogger = () => {}\n\n/**\n * re-use the debugOn prop to control this log method\n * @param {object} opts configuration\n * @return {function} the log function\n */\nconst getLogger = (opts) => {\n const { debugOn } = opts \n if (debugOn) {\n return (...args) => {\n Reflect.apply(console.info, console, ['[jsonql-ws-client-core]', ...args])\n }\n }\n return dummyLogger\n}\n\n/**\n * Make sure there is a log method\n * @param {object} opts configuration\n * @return {object} opts\n */\nconst getLogFn = opts => {\n const { log } = opts // 1.3.9 if we pass a log method here then we use this\n if (!log || typeof log !== 'function') {\n return getLogger(opts)\n }\n opts.log('---> getLogFn user supplied log function <---', opts)\n return log\n}\n\nexport { getLogFn }","// group all the repetitive message here\n\nexport const TAKEN_BY_OTHER_TYPE_ERR = 'You are trying to register an event already been taken by other type:'\n","// Create two WeakMap store as a private keys\nexport const NB_EVENT_SERVICE_PRIVATE_STORE = new WeakMap()\nexport const NB_EVENT_SERVICE_PRIVATE_LAZY = new WeakMap()\n","/**\n * generate a 32bit hash based on the function.toString()\n * _from http://stackoverflow.com/questions/7616461/generate-a-hash-_from-string-in-javascript-jquery\n * @param {string} s the converted to string function\n * @return {string} the hashed function string\n */\nexport function hashCode(s) {\n\treturn s.split(\"\").reduce(function(a,b){a=((a<<5)-a)+b.charCodeAt(0);return a&a},0)\n}\n\n/**\n * wrapper to make sure it string\n * @param {*} input whatever\n * @return {string} output\n */\nexport function hashCode2Str(s) {\n return hashCode(s) + ''\n}\n\n/**\n * Just check if a pattern is an RegExp object\n * @param {*} pat whatever\n * @return {boolean} false when its not\n */\nexport function isRegExp(pat) {\n return pat instanceof RegExp\n}\n\n/**\n * check if its string\n * @param {*} arg whatever\n * @return {boolean} false when it's not\n */\nexport function isString(arg) {\n return typeof arg === 'string'\n}\n\n/**\n * Find from the array by matching the pattern\n * @param {*} pattern a string or RegExp object\n * @return {object} regex object or false when we can not id the input\n */\nexport function getRegex(pattern) {\n switch (true) {\n case isRegExp(pattern) === true:\n return pattern\n case isString(pattern) === true:\n return new RegExp(pattern)\n default:\n return false\n }\n}\n","// making all the functionality on it's own\n// import { WatchClass } from './watch'\n/*\nwe use a different way to do the same watch thing now\nthis.watch('suspend', function(value, prop, oldValue) {\n this.logger(`${prop} set from ${oldValue} to ${value}`)\n // it means it set the suspend = true then release it\n if (oldValue === true && value === false) {\n // we want this happen after the return happens\n setTimeout(() => {\n this.release()\n }, 1)\n }\n return value; // we need to return the value to store it\n})\n*/\nimport { getRegex, isRegExp } from './utils'\n\nexport default class SuspendClass {\n\n constructor() {\n // suspend, release and queue\n this.__suspend_state__ = null\n // to do this proper we don't use a new prop to hold the event name pattern\n this.__pattern__ = null\n this.queueStore = new Set()\n }\n\n /**\n * start suspend\n * @return {void}\n */\n $suspend() {\n this.logger(`---> SUSPEND ALL OPS <---`)\n this.__suspend__(true)\n }\n\n /**\n * release the queue\n * @return {void}\n */\n $release() {\n this.logger(`---> RELEASE SUSPENDED QUEUE <---`)\n this.__suspend__(false)\n }\n\n /**\n * suspend event by pattern\n * @param {string} pattern the pattern search matches the event name\n * @return {void}\n */\n $suspendEvent(pattern) {\n const regex = getRegex(pattern)\n if (isRegExp(regex)) {\n this.__pattern__ = regex\n return this.$suspend()\n }\n throw new Error(`We expect a pattern variable to be string or RegExp, but we got \"${typeof regex}\" instead`)\n }\n\n /**\n * queuing call up when it's in suspend mode\n * @param {string} evt the event name\n * @param {*} args unknown number of arguments\n * @return {boolean} true when added or false when it's not\n */\n $queue(evt, ...args) {\n this.logger('($queue) get called')\n if (this.__suspend_state__ === true) {\n if (isRegExp(this.__pattern__)) { // it's better then check if its not null\n // check the pattern and decide if we want to suspend it or not\n let found = this.__pattern__.test(evt)\n if (!found) {\n return false\n }\n }\n this.logger('($queue) added to $queue', args)\n // @TODO there shouldn't be any duplicate, but how to make sure?\n this.queueStore.add([evt].concat(args))\n // return this.queueStore.size\n }\n return !!this.__suspend_state__\n }\n\n /**\n * a getter to get all the store queue\n * @return {array} Set turn into Array before return\n */\n get $queues() {\n let size = this.queueStore.size\n this.logger('($queues)', `size: ${size}`)\n if (size > 0) {\n return Array.from(this.queueStore)\n }\n return []\n }\n\n /**\n * to set the suspend and check if it's boolean value\n * @param {boolean} value to trigger\n */\n __suspend__(value) {\n if (typeof value === 'boolean') {\n const lastValue = this.__suspend_state__\n this.__suspend_state__ = value\n this.logger(`($suspend) Change from \"${lastValue}\" --> \"${value}\"`)\n if (lastValue === true && value === false) {\n this.__release__()\n }\n } else {\n throw new Error(`$suspend only accept Boolean value! we got ${typeof value}`)\n }\n }\n\n /**\n * Release the queue\n * @return {int} size if any\n */\n __release__() {\n let size = this.queueStore.size\n let pattern = this.__pattern__\n this.__pattern__ = null\n this.logger(`(release) was called with ${size}${pattern ? ' for \"' + pattern + '\"': ''} item${size > 1 ? 's' : ''}`)\n if (size > 0) {\n const queue = Array.from(this.queueStore)\n this.queueStore.clear()\n this.logger('(release queue)', queue)\n queue.forEach(args => {\n this.logger(args)\n Reflect.apply(this.$trigger, this, args)\n })\n this.logger(`Release size ${this.queueStore.size}`)\n }\n\n return size\n }\n}\n","// break up the main file because its getting way too long\nimport {\n NB_EVENT_SERVICE_PRIVATE_STORE,\n NB_EVENT_SERVICE_PRIVATE_LAZY\n} from './store'\nimport { hashCode2Str, isString } from './utils'\nimport SuspendClass from './suspend'\n\nexport default class StoreService extends SuspendClass {\n\n constructor(config = {}) {\n super()\n if (config.logger && typeof config.logger === 'function') {\n this.logger = config.logger\n }\n this.keep = config.keep\n // for the $done setter\n this.result = config.keep ? [] : null\n // we need to init the store first otherwise it could be a lot of checking later\n this.normalStore = new Map()\n this.lazyStore = new Map()\n }\n\n /**\n * validate the event name(s)\n * @param {string[]} evt event name\n * @return {boolean} true when OK\n */\n validateEvt(...evt) {\n evt.forEach(e => {\n if (!isString(e)) {\n this.logger('(validateEvt)', e)\n throw new Error(`Event name must be string type! we got ${typeof e}`)\n }\n })\n return true\n }\n\n /**\n * Simple quick check on the two main parameters\n * @param {string} evt event name\n * @param {function} callback function to call\n * @return {boolean} true when OK\n */\n validate(evt, callback) {\n if (this.validateEvt(evt)) {\n if (typeof callback === 'function') {\n return true\n }\n }\n throw new Error(`callback required to be function type! we got ${typeof callback}`)\n }\n\n /**\n * Check if this type is correct or not added in V1.5.0\n * @param {string} type for checking\n * @return {boolean} true on OK\n */\n validateType(type) {\n this.validateEvt(type)\n const types = ['on', 'only', 'once', 'onlyOnce']\n return !!types.filter(t => type === t).length\n }\n\n /**\n * Run the callback\n * @param {function} callback function to execute\n * @param {array} payload for callback\n * @param {object} ctx context or null\n * @return {void} the result store in $done\n */\n run(callback, payload, ctx) {\n this.logger('(run) callback:', callback, 'payload:', payload, 'context:', ctx)\n this.$done = Reflect.apply(callback, ctx, this.toArray(payload))\n }\n\n /**\n * Take the content out and remove it from store id by the name\n * @param {string} evt event name\n * @param {string} [storeName = lazyStore] name of store\n * @return {object|boolean} content or false on not found\n */\n takeFromStore(evt, storeName = 'lazyStore') {\n let store = this[storeName] // it could be empty at this point\n if (store) {\n this.logger('(takeFromStore)', storeName, store)\n if (store.has(evt)) {\n let content = store.get(evt)\n this.logger(`(takeFromStore) has \"${evt}\"`, content)\n store.delete(evt)\n return content\n }\n return false\n }\n throw new Error(`\"${storeName}\" is not supported!`)\n }\n\n /**\n * This was part of the $get. We take it out\n * so we could use a regex to remove more than one event\n * @param {object} store the store to return from\n * @param {string} evt event name\n * @param {boolean} full return just the callback or everything\n * @return {array|boolean} false when not found\n */\n findFromStore(evt, store, full = false) {\n if (store.has(evt)) {\n return Array\n .from(store.get(evt))\n .map( l => {\n if (full) {\n return l\n }\n let [key, callback, ] = l\n return callback\n })\n }\n return false\n }\n\n /**\n * Similar to the findFromStore, but remove\n * @param {string} evt event name\n * @param {object} store the store to remove from\n * @return {boolean} false when not found\n */\n removeFromStore(evt, store) {\n if (store.has(evt)) {\n this.logger('($off)', evt)\n store.delete(evt)\n return true\n }\n return false\n }\n\n /**\n * The add to store step is similar so make it generic for resuse\n * @param {object} store which store to use\n * @param {string} evt event name\n * @param {spread} args because the lazy store and normal store store different things\n * @return {array} store and the size of the store\n */\n addToStore(store, evt, ...args) {\n let fnSet\n if (store.has(evt)) {\n this.logger(`(addToStore) \"${evt}\" existed`)\n fnSet = store.get(evt)\n } else {\n this.logger(`(addToStore) create new Set for \"${evt}\"`)\n // this is new\n fnSet = new Set()\n }\n // lazy only store 2 items - this is not the case in V1.6.0 anymore\n // we need to check the first parameter is string or not\n if (args.length > 2) {\n if (Array.isArray(args[0])) { // lazy store\n // check if this type of this event already register in the lazy store\n let [,,t] = args\n if (!this.checkTypeInLazyStore(evt, t)) {\n fnSet.add(args)\n }\n } else {\n if (!this.checkContentExist(args, fnSet)) {\n this.logger(`(addToStore) insert new`, args)\n fnSet.add(args)\n }\n }\n } else { // add straight to lazy store\n fnSet.add(args)\n }\n store.set(evt, fnSet)\n return [store, fnSet.size]\n }\n\n /**\n * @param {array} args for compare\n * @param {object} fnSet A Set to search from\n * @return {boolean} true on exist\n */\n checkContentExist(args, fnSet) {\n let list = Array.from(fnSet)\n return !!list.filter(li => {\n let [hash,] = li\n return hash === args[0]\n }).length\n }\n\n /**\n * get the existing type to make sure no mix type add to the same store\n * @param {string} evtName event name\n * @param {string} type the type to check\n * @return {boolean} true you can add, false then you can't add this type\n */\n checkTypeInStore(evtName, type) {\n this.validateEvt(evtName, type)\n let all = this.$get(evtName, true)\n if (all === false) {\n // pristine it means you can add\n return true\n }\n // it should only have ONE type in ONE event store\n return !all.filter(list => {\n let [ ,,,t ] = list\n return type !== t\n }).length\n }\n\n /**\n * This is checking just the lazy store because the structure is different\n * therefore we need to use a new method to check it\n */\n checkTypeInLazyStore(evtName, type) {\n this.validateEvt(evtName, type)\n let store = this.lazyStore.get(evtName)\n this.logger('(checkTypeInLazyStore)', store)\n if (store) {\n return !!Array\n .from(store)\n .filter(li => {\n let [,,t] = li\n return t !== type\n }).length\n }\n return false\n }\n\n /**\n * wrapper to re-use the addToStore,\n * V1.3.0 add extra check to see if this type can add to this evt\n * @param {string} evt event name\n * @param {string} type on or once\n * @param {function} callback function\n * @param {object} context the context the function execute in or null\n * @return {number} size of the store\n */\n addToNormalStore(evt, type, callback, context = null) {\n this.logger(`(addToNormalStore) try to add \"${type}\" --> \"${evt}\" to normal store`)\n // @TODO we need to check the existing store for the type first!\n if (this.checkTypeInStore(evt, type)) {\n this.logger('(addToNormalStore)', `\"${type}\" --> \"${evt}\" can add to normal store`)\n let key = this.hashFnToKey(callback)\n let args = [this.normalStore, evt, key, callback, context, type]\n let [_store, size] = Reflect.apply(this.addToStore, this, args)\n this.normalStore = _store\n return size\n }\n return false\n }\n\n /**\n * Add to lazy store this get calls when the callback is not register yet\n * so we only get a payload object or even nothing\n * @param {string} evt event name\n * @param {array} payload of arguments or empty if there is none\n * @param {object} [context=null] the context the callback execute in\n * @param {string} [type=false] register a type so no other type can add to this evt\n * @return {number} size of the store\n */\n addToLazyStore(evt, payload = [], context = null, type = false) {\n // this is add in V1.6.0\n // when there is type then we will need to check if this already added in lazy store\n // and no other type can add to this lazy store\n let args = [this.lazyStore, evt, this.toArray(payload), context]\n if (type) {\n args.push(type)\n }\n let [_store, size] = Reflect.apply(this.addToStore, this, args)\n this.lazyStore = _store\n this.logger(`(addToLazyStore) size: ${size}`)\n return size\n }\n\n /**\n * make sure we store the argument correctly\n * @param {*} arg could be array\n * @return {array} make sured\n */\n toArray(arg) {\n return Array.isArray(arg) ? arg : [arg]\n }\n\n /**\n * setter to store the Set in private\n * @param {object} obj a Set\n */\n set normalStore(obj) {\n NB_EVENT_SERVICE_PRIVATE_STORE.set(this, obj)\n }\n\n /**\n * @return {object} Set object\n */\n get normalStore() {\n return NB_EVENT_SERVICE_PRIVATE_STORE.get(this)\n }\n\n /**\n * setter to store the Set in lazy store\n * @param {object} obj a Set\n */\n set lazyStore(obj) {\n NB_EVENT_SERVICE_PRIVATE_LAZY.set(this , obj)\n }\n\n /**\n * @return {object} the lazy store Set\n */\n get lazyStore() {\n return NB_EVENT_SERVICE_PRIVATE_LAZY.get(this)\n }\n\n /**\n * generate a hashKey to identify the function call\n * The build-in store some how could store the same values!\n * @param {function} fn the converted to string function\n * @return {string} hashKey\n */\n hashFnToKey(fn) {\n return hashCode2Str(fn.toString())\n }\n}\n","// The top level\nimport { TAKEN_BY_OTHER_TYPE_ERR } from './constants'\nimport StoreService from './store-service'\n// export\nexport default class EventService extends StoreService {\n /**\n * class constructor\n */\n constructor(config = {}) {\n super(config)\n }\n\n /**\n * logger function for overwrite\n */\n logger() {}\n\n // for id if the instance is this class\n get $name() {\n return 'to1source-event'\n }\n\n // take this down in the next release\n get is() {\n return this.$name\n }\n\n //////////////////////////\n // PUBLIC METHODS //\n //////////////////////////\n\n /**\n * Register your evt handler, note we don't check the type here,\n * we expect you to be sensible and know what you are doing.\n * @param {string} evt name of event\n * @param {function} callback bind method --> if it's array or not\n * @param {object} [context=null] to execute this call in\n * @return {number} the size of the store\n */\n $on(evt , callback , context = null) {\n const type = 'on'\n this.validate(evt, callback)\n // first need to check if this evt is in lazy store\n let lazyStoreContent = this.takeFromStore(evt)\n // this is normal register first then call later\n if (lazyStoreContent === false) {\n this.logger(`($on) \"${evt}\" is not in lazy store`)\n // @TODO we need to check if there was other listener to this\n // event and are they the same type then we could solve that\n // register the different type to the same event name\n return this.addToNormalStore(evt, type, callback, context)\n }\n this.logger(`($on) ${evt} found in lazy store`)\n // this is when they call $trigger before register this callback\n let size = 0\n lazyStoreContent.forEach(content => {\n let [ payload, ctx, t ] = content\n if (t && t !== type) {\n throw new Error(`${TAKEN_BY_OTHER_TYPE_ERR} ${t}`)\n }\n this.logger(`($on)`, `call run \"${evt}\"`)\n this.run(callback, payload, context || ctx)\n size += this.addToNormalStore(evt, type, callback, context || ctx)\n })\n\n this.logger(`($on) return size ${size}`)\n return size\n }\n\n /**\n * once only registered it once, there is no overwrite option here\n * @NOTE change in v1.3.0 $once can add multiple listeners\n * but once the event fired, it will remove this event (see $only)\n * @param {string} evt name\n * @param {function} callback to execute\n * @param {object} [context=null] the handler execute in\n * @return {boolean} result\n */\n $once(evt , callback , context = null) {\n this.validate(evt, callback)\n const type = 'once'\n let lazyStoreContent = this.takeFromStore(evt)\n // this is normal register before call $trigger\n let nStore = this.normalStore;\n if (lazyStoreContent === false) {\n this.logger(`($once) \"${evt}\" is not in the lazy store`)\n // v1.3.0 $once now allow to add multiple listeners\n return this.addToNormalStore(evt, type, callback, context)\n } else {\n // now this is the tricky bit\n // there is a potential bug here that cause by the developer\n // if they call $trigger first, the lazy won't know it's a once call\n // so if in the middle they register any call with the same evt name\n // then this $once call will be fucked - add this to the documentation\n this.logger('($once)', lazyStoreContent)\n const list = Array.from(lazyStoreContent)\n // should never have more than 1\n const [ payload, ctx, t ] = list[0]\n if (t && t !== type) {\n throw new Error(`${TAKEN_BY_OTHER_TYPE_ERR} ${t}`)\n }\n this.logger('($once)', `call run \"${evt}\"`)\n this.run(callback, payload, context || ctx)\n // remove this evt from store\n this.$off(evt)\n }\n }\n\n /**\n * This one event can only bind one callbackback\n * @param {string} evt event name\n * @param {function} callback event handler\n * @param {object} [context=null] the context the event handler execute in\n * @return {boolean} true bind for first time, false already existed\n */\n $only(evt, callback, context = null) {\n this.validate(evt, callback)\n const type = 'only'\n let added = false\n let lazyStoreContent = this.takeFromStore(evt)\n // this is normal register before call $trigger\n let nStore = this.normalStore\n if (!nStore.has(evt)) {\n this.logger(`($only) \"${evt}\" add to normalStore`)\n added = this.addToNormalStore(evt, type, callback, context)\n }\n if (lazyStoreContent !== false) {\n // there are data store in lazy store\n this.logger(`($only) \"${evt}\" found data in lazy store to execute`)\n const list = Array.from(lazyStoreContent)\n // $only allow to trigger this multiple time on the single handler\n list.forEach( li => {\n const [ payload, ctx, t ] = li\n if (t && t !== type) {\n throw new Error(`${TAKEN_BY_OTHER_TYPE_ERR} ${t}`)\n }\n this.logger(`($only) call run \"${evt}\"`)\n this.run(callback, payload, context || ctx)\n })\n }\n return added\n }\n\n /**\n * $only + $once this is because I found a very subtile bug when we pass a\n * resolver, rejecter - and it never fire because that's OLD added in v1.4.0\n * @param {string} evt event name\n * @param {function} callback to call later\n * @param {object} [context=null] exeucte context\n * @return {void}\n */\n $onlyOnce(evt, callback, context = null) {\n this.validate(evt, callback)\n const type = 'onlyOnce'\n let added = false\n let lazyStoreContent = this.takeFromStore(evt)\n // this is normal register before call $trigger\n let nStore = this.normalStore;\n if (!nStore.has(evt)) {\n this.logger(`($onlyOnce) \"${evt}\" add to normalStore`)\n added = this.addToNormalStore(evt, type, callback, context)\n }\n if (lazyStoreContent !== false) {\n // there are data store in lazy store\n this.logger('($onlyOnce)', lazyStoreContent)\n const list = Array.from(lazyStoreContent)\n // should never have more than 1\n const [ payload, ctx, t ] = list[0]\n if (t && t !== 'onlyOnce') {\n throw new Error(`${TAKEN_BY_OTHER_TYPE_ERR} ${t}`)\n }\n this.logger(`($onlyOnce) call run \"${evt}\"`)\n this.run(callback, payload, context || ctx)\n // remove this evt from store\n this.$off(evt)\n }\n return added\n }\n\n /**\n * This is a shorthand of $off + $on added in V1.5.0\n * @param {string} evt event name\n * @param {function} callback to exeucte\n * @param {object} [context = null] or pass a string as type\n * @param {string} [type=on] what type of method to replace\n * @return {*}\n */\n $replace(evt, callback, context = null, type = 'on') {\n if (this.validateType(type)) {\n this.$off(evt)\n let method = this['$' + type]\n this.logger(`($replace)`, evt, callback)\n return Reflect.apply(method, this, [evt, callback, context])\n }\n throw new Error(`${type} is not supported!`)\n }\n\n /**\n * trigger the event\n * @param {string} evt name NOT allow array anymore!\n * @param {mixed} [payload = []] pass to fn\n * @param {object|string} [context = null] overwrite what stored\n * @param {string} [type=false] if pass this then we need to add type to store too\n * @return {number} if it has been execute how many times\n */\n $trigger(evt , payload = [] , context = null, type = false) {\n this.validateEvt(evt)\n let found = 0\n // first check the normal store\n let nStore = this.normalStore\n this.logger('($trigger) normalStore', nStore)\n if (nStore.has(evt)) {\n this.logger(`($trigger) \"${evt}\" found`)\n // @1.8.0 to add the suspend queue\n let added = this.$queue(evt, payload, context, type)\n if (added) {\n this.logger(`($trigger) Currently suspended \"${evt}\" added to queue, nothing executed. Exit now.`)\n return false // not executed\n }\n let nSet = Array.from(nStore.get(evt))\n let ctn = nSet.length\n let hasOnce = false\n let hasOnly = false\n for (let i=0; i < ctn; ++i) {\n ++found;\n // this.logger('found', found)\n let [ _, callback, ctx, type ] = nSet[i]\n this.logger(`($trigger) call run for ${evt}`)\n this.run(callback, payload, context || ctx)\n if (type === 'once' || type === 'onlyOnce') {\n hasOnce = true;\n }\n }\n if (hasOnce) {\n nStore.delete(evt)\n }\n return found\n }\n // now this is not register yet\n this.addToLazyStore(evt, payload, context, type)\n return found\n }\n\n /**\n * this is an alias to the $trigger\n * @NOTE breaking change in V1.6.0 we swap the parameter aroun\n * @NOTE breaking change: v1.9.1 it return an function to accept the params as spread\n * @param {string} evt event name\n * @param {string} type of call\n * @param {object} context what context callback execute in\n * @return {*} from $trigger\n */\n $call(evt, type = false, context = null) {\n const ctx = this\n\n return (...args) => {\n let _args = [evt, args, context, type]\n return Reflect.apply(ctx.$trigger, ctx, _args)\n }\n }\n\n /**\n * remove the evt from all the stores\n * @param {string} evt name\n * @return {boolean} true actually delete something\n */\n $off(evt) {\n // @TODO we will allow a regex pattern to mass remove event\n this.validateEvt(evt)\n let stores = [ this.lazyStore, this.normalStore ]\n\n return !!stores\n .filter(store => store.has(evt))\n .map(store => this.removeFromStore(evt, store))\n .length\n }\n\n /**\n * return all the listener bind to that event name\n * @param {string} evtName event name\n * @param {boolean} [full=false] if true then return the entire content\n * @return {array|boolean} listerner(s) or false when not found\n */\n $get(evt, full = false) {\n // @TODO should we allow the same Regex to search for all?\n this.validateEvt(evt)\n let store = this.normalStore\n return this.findFromStore(evt, store, full)\n }\n\n /**\n * store the return result from the run\n * @param {*} value whatever return from callback\n */\n set $done(value) {\n this.logger('($done) set value: ', value)\n if (this.keep) {\n this.result.push(value)\n } else {\n this.result = value\n }\n }\n\n /**\n * @TODO is there any real use with the keep prop?\n * getter for $done\n * @return {*} whatever last store result\n */\n get $done() {\n this.logger('($done) get result:', this.result)\n if (this.keep) {\n return this.result[this.result.length - 1]\n }\n return this.result\n }\n\n /**\n * Take a look inside the stores\n * @param {number|null} idx of the store, null means all\n * @return {void}\n */\n $debug(idx = null) {\n let names = ['lazyStore', 'normalStore']\n let stores = [this.lazyStore, this.normalStore]\n if (stores[idx]) {\n this.logger(names[idx], stores[idx])\n } else {\n stores.map((store, i) => {\n this.logger(names[i], store)\n })\n }\n }\n}\n","// default\nimport To1sourceEvent from './src/event-service'\n\nexport default To1sourceEvent\n","// this will generate a event emitter and will be use everywhere\nimport EventEmitterClass from '@to1source/event'\n// create a clone version so we know which one we actually is using\nclass JsonqlWsEvt extends EventEmitterClass {\n\n constructor(logger) {\n if (typeof logger !== 'function') {\n throw new Error(`Just die here the logger is not a function!`)\n }\n logger(`---> Create a new EventEmitter <---`)\n // this ee will always come with the logger\n // because we should take the ee from the configuration\n super({ logger })\n }\n\n get name() {\n return'jsonql-ws-client-core'\n }\n}\n\n/**\n * getting the event emitter\n * @param {object} opts configuration\n * @return {object} the event emitter instance\n */\nconst getEventEmitter = opts => {\n const { log, eventEmitter } = opts\n \n if (eventEmitter) {\n log(`eventEmitter is:`, eventEmitter.name)\n return eventEmitter\n }\n \n return new JsonqlWsEvt( opts.log )\n}\n\nexport { \n getEventEmitter, \n EventEmitterClass // for other module to build from \n}\n","// group all the small functions here\nimport { EMIT_REPLY_TYPE } from 'jsonql-constants'\nimport { toArray, createEvt } from 'jsonql-utils/src/generic'\nimport JsonqlValidationError from 'jsonql-errors/src/validation-error'\n\n\n/**\n * WebSocket is strict about the path, therefore we need to make sure before it goes in\n * @param {string} url input url\n * @return {string} url with correct path name\n */\nexport const fixWss = url => {\n const uri = url.toLowerCase()\n if (uri.indexOf('http') > -1) {\n if (uri.indexOf('https') > -1) {\n return uri.replace('https', 'wss')\n }\n return uri.replace('http', 'ws')\n }\n return uri\n}\n\n\n/**\n * get a stock host name from browser\n */\nexport const getHostName = () => {\n try {\n return [window.location.protocol, window.location.host].join('//')\n } catch(e) {\n throw new JsonqlValidationError(e)\n }\n}\n\n/**\n * Unbind the event\n * @param {object} ee EventEmitter\n * @param {string} namespace\n * @return {void}\n */\nexport const clearMainEmitEvt = (ee, namespace) => {\n let nsps = toArray(namespace)\n nsps.forEach(n => {\n ee.$off(createEvt(n, EMIT_REPLY_TYPE))\n })\n}\n\n\n","// take out from the resolver-methods\nimport { \n LOGIN_EVENT_NAME, \n LOGOUT_EVENT_NAME, \n ON_LOGIN_FN_NAME\n} from 'jsonql-constants'\nimport { JsonqlValidationError } from 'jsonql-errors'\nimport { injectToFn, chainFns, isString, objDefineProps, isFunc } from '../utils'\n\n\n/**\n * @TODO this is now become unnecessary because the login is a slave to the\n * http-client - but keep this for now and see what we want to do with it later\n * @UPDATE it might be better if we decoup the two http-client only emit a login event\n * Here should catch it and reload the ws client @TBC\n * break out from createAuthMethods to allow chaining call\n * @param {object} obj the main client object\n * @param {object} opts configuration\n * @param {object} ee event emitter\n * @return {array} [ obj, opts, ee ] what comes in what goes out\n */\nconst setupLoginHandler = (obj, opts, ee) => [ \n injectToFn(obj, opts.loginHandlerName, function loginHandler(token) {\n if (token && isString(token)) {\n opts.log(`Received ${LOGIN_EVENT_NAME} with ${token}`)\n // @TODO add the interceptor hook \n return ee.$trigger(LOGIN_EVENT_NAME, [token])\n }\n // should trigger a global error instead @TODO\n throw new JsonqlValidationError(opts.loginHandlerName, `Unexpected token ${token}`)\n }),\n opts,\n ee\n]\n\n\n/**\n * break out from createAuthMethods to allow chaining call - final in chain\n * @param {object} obj the main client object\n * @param {object} opts configuration\n * @param {object} ee event emitter\n * @return {array} [ obj, opts, ee ] what comes in what goes out\n */\nconst setupLogoutHandler = (obj, opts, ee) => [\n injectToFn(obj, opts.logoutHandlerName, function logoutHandler(...args) {\n ee.$trigger(LOGOUT_EVENT_NAME, args)\n }),\n opts, \n ee\n]\n\n\n/**\n * This event will fire when the socket.io.on('connection') and ws.onopen\n * Plus this will check if it's the private namespace that fired the event\n * @param {object} obj the client itself\n * @param {object} ee Event Emitter\n * @return {array} [ obj, opts, ee] what comes in what goes out\n */\nconst createOnLoginhandler = (obj, opts, ee) => [\n objDefineProps(obj, ON_LOGIN_FN_NAME, function onLoginCallbackHandler(onLoginCallback) {\n if (isFunc(onLoginCallback)) {\n // only one callback can registered with it, TBC\n ee.$only(ON_LOGIN_FN_NAME, onLoginCallback)\n }\n }),\n opts,\n ee \n]\n\n// @TODO future feature setup switch user\n\n\n/**\n * Create auth related methods\n * @param {object} obj the client itself\n * @param {object} opts configuration\n * @param {object} ee Event Emitter\n * @return {array} [ obj, opts, ee ] what comes in what goes out\n */\nexport function createAuthMethods(obj, opts, ee) {\n return chainFns(\n setupLoginHandler, \n setupLogoutHandler,\n createOnLoginhandler\n )(obj, opts, ee)\n}\n","// constants\n\nimport {\n EMIT_REPLY_TYPE,\n JS_WS_SOCKET_IO_NAME,\n JS_WS_NAME,\n ON_MESSAGE_FN_NAME,\n ON_RESULT_FN_NAME\n} from 'jsonql-constants'\n\nconst SOCKET_IO = JS_WS_SOCKET_IO_NAME\nconst WS = JS_WS_NAME\n\nconst AVAILABLE_SERVERS = [SOCKET_IO, WS]\n\nconst SOCKET_NOT_DEFINE_ERR = 'socket is not define in the contract file!'\n\nconst SERVER_NOT_SUPPORT_ERR = 'is not supported server name!'\n\nconst MISSING_PROP_ERR = 'Missing property in contract!'\n\nconst UNKNOWN_CLIENT_ERR = 'Unknown client type!'\n\nconst EMIT_EVT = EMIT_REPLY_TYPE\n\nconst NAMESPACE_KEY = 'namespaceMap'\n\nconst UNKNOWN_RESULT = 'UKNNOWN RESULT!'\n\nconst NOT_ALLOW_OP = 'This operation is not allow!'\n\nconst MY_NAMESPACE = 'myNamespace'\n\nconst CB_FN_NAME = 'on'\n// this is a socket only (for now) feature so we just put it here \nconst DISCONNECTED_ERROR_MSG = `You have disconnected from the socket server, please reconnect.`\n\nexport {\n SOCKET_IO,\n WS,\n AVAILABLE_SERVERS,\n SOCKET_NOT_DEFINE_ERR,\n SERVER_NOT_SUPPORT_ERR,\n MISSING_PROP_ERR,\n UNKNOWN_CLIENT_ERR,\n EMIT_EVT,\n ON_MESSAGE_FN_NAME,\n ON_RESULT_FN_NAME,\n NAMESPACE_KEY,\n UNKNOWN_RESULT,\n NOT_ALLOW_OP,\n MY_NAMESPACE,\n CB_FN_NAME,\n DISCONNECTED_ERROR_MSG\n}\n","// breaking it up further to share between methods\nimport { DATA_KEY, ERROR_KEY } from 'jsonql-constants'\nimport { UNKNOWN_RESULT } from '../options/constants'\nimport { isObjectHasKey } from '../utils'\n\n/**\n * break out to use in different places to handle the return from server\n * @param {object} data from server\n * @param {function} resolver NOT from promise\n * @param {function} rejecter NOT from promise\n * @return {void} nothing\n */\nexport function respondHandler(data, resolver, rejecter) {\n if (isObjectHasKey(data, ERROR_KEY)) {\n // debugFn('-- rejecter called --', data[ERROR_KEY])\n rejecter(data[ERROR_KEY])\n } else if (isObjectHasKey(data, DATA_KEY)) {\n // debugFn('-- resolver called --', data[DATA_KEY])\n resolver(data[DATA_KEY])\n } else {\n // debugFn('-- UNKNOWN_RESULT --', data)\n rejecter({message: UNKNOWN_RESULT, error: data})\n }\n}\n","// the actual trigger call method\nimport { ON_RESULT_FN_NAME, EMIT_REPLY_TYPE } from 'jsonql-constants'\nimport { createEvt, toArray } from '../utils'\nimport { respondHandler } from './respond-handler'\n\n/**\n * just wrapper\n * @param {object} ee EventEmitter\n * @param {string} namespace where this belongs\n * @param {string} resolverName resolver\n * @param {array} args arguments\n * @param {function} log function \n * @return {void} nothing\n */\nexport function actionCall(ee, namespace, resolverName, args = [], log) {\n // reply event \n const outEventName = createEvt(namespace, EMIT_REPLY_TYPE)\n\n log(`actionCall: ${outEventName} --> ${resolverName}`, args)\n // This is the out going call \n ee.$trigger(outEventName, [resolverName, toArray(args)])\n \n // then we need to listen to the event callback here as well\n return new Promise((resolver, rejecter) => {\n const inEventName = createEvt(namespace, resolverName, ON_RESULT_FN_NAME)\n // this cause the onResult got the result back first \n // and it should be the promise resolve first\n // @TODO we need to rewrote the respondHandler to change the problem stated above \n ee.$on(\n inEventName,\n function actionCallResultHandler(result) {\n log(`got the first result`, result)\n respondHandler(result, resolver, rejecter)\n }\n )\n })\n}\n","// setting up the send method \nimport { JsonqlValidationError } from 'jsonql-errors'\nimport {\n ON_ERROR_FN_NAME,\n SEND_MSG_FN_NAME\n} from 'jsonql-constants'\nimport { validateAsync } from 'jsonql-params-validator'\nimport { objDefineProps, createEvt, toArray, nil } from '../utils'\nimport { actionCall } from './action-call'\n\n/** \n * pairing with the server vesrion SEND_MSG_FN_NAME\n * last of the chain so only return the resolver (fn)\n * This is now change to a getter / setter method \n * and call like this: resolver.send(...args)\n * @param {function} fn the resolver function \n * @param {object} ee event emitter instance \n * @param {string} namespace the namespace it belongs to \n * @param {string} resolverName name of the resolver \n * @param {object} params from contract \n * @param {function} log a logger function\n * @return {function} return the resolver itself \n */ \nexport const setupSendMethod = (fn, ee, namespace, resolverName, params, log) => (\n objDefineProps(\n fn, \n SEND_MSG_FN_NAME, \n nil, \n function sendHandler() {\n // let _log = (...args) => Reflect.apply(console.info, console, ['[SEND]'].concat(args))\n /** \n * This will follow the same pattern like the resolver \n * @param {array} args list of unknown argument follow the resolver \n * @return {promise} resolve the result \n */\n return function sendCallback(...args) {\n return validateAsync(args, params.params, true)\n .then(_args => {\n // @TODO check the result \n // because the validation could failed with the list of fail properties \n log(namespace, resolverName, _args)\n return actionCall(ee, namespace, resolverName, _args, _log)\n })\n .catch(err => {\n // @TODO it shouldn't be just a validation error \n // it could be server return error, so we need to check \n // what error we got back here first \n log('send error', err)\n // @TODO it might not an validation error need the finalCatch here\n ee.$call(\n createEvt(namespace, resolverName, ON_ERROR_FN_NAME),\n [new JsonqlValidationError(resolverName, err)]\n )\n })\n } \n })\n)\n","// break up the original setup resolver method here\n// import { JsonqlValidationError, finalCatch } from 'jsonql-errors'\nimport {\n ON_ERROR_FN_NAME,\n ON_MESSAGE_FN_NAME,\n ON_RESULT_FN_NAME\n} from 'jsonql-constants'\n// local \nimport { MY_NAMESPACE } from '../options/constants'\nimport { chainFns, objDefineProps, injectToFn, createEvt, isFunc } from '../utils'\nimport { respondHandler } from './respond-handler'\nimport { setupSendMethod } from './setup-send-method'\n\n/**\n * The first one in the chain, just setup a namespace prop\n * the rest are passing through\n * @param {function} fn the resolver function\n * @param {object} ee the event emitter \n * @param {string} resolverName what it said\n * @param {object} params for resolver from contract\n * @param {function} log the logger function\n * @return {array}\n */\nconst setupNamespace = (fn, ee, namespace, resolverName, params, log) => [\n injectToFn(fn, MY_NAMESPACE, namespace),\n ee,\n namespace,\n resolverName,\n params,\n log \n]\n\n/** \n * onResult handler\n */ \nconst setupOnResult = (fn, ee, namespace, resolverName, params, log) => [\n objDefineProps(fn, ON_RESULT_FN_NAME, function(resultCallback) {\n if (isFunc(resultCallback)) {\n ee.$on(\n createEvt(namespace, resolverName, ON_RESULT_FN_NAME),\n function resultHandler(result) {\n respondHandler(result, resultCallback, (error) => {\n log(`Catch error: \"${resolverName}\"`, error)\n ee.$trigger(\n createEvt(namespace, resolverName, ON_ERROR_FN_NAME), \n error\n )\n })\n }\n )\n }\n }),\n ee,\n namespace,\n resolverName,\n params,\n log\n]\n\n/** \n * we do need to add the send prop back because it's the only way to deal with\n * bi-directional data stream \n */\nconst setupOnMessage = (fn, ee, namespace, resolverName, params, log) => [\n objDefineProps(fn, ON_MESSAGE_FN_NAME, function(messageCallback) {\n // we expect this to be a function\n if (isFunc(messageCallback)) {\n // did that add to the callback\n let onMessageCallback = (args) => {\n respondHandler(args, messageCallback, (error) => {\n log(`Catch error: \"${resolverName}\"`, error)\n ee.$trigger(\n createEvt(namespace, resolverName, ON_ERROR_FN_NAME), \n error\n )\n })\n }\n // register the handler for this message event\n ee.$only(\n createEvt(namespace, resolverName, ON_MESSAGE_FN_NAME), \n onMessageCallback\n )\n }\n }),\n ee,\n namespace,\n resolverName,\n params,\n log\n]\n\n/** \n * ON_ERROR_FN_NAME handler\n */\nconst setupOnError = (fn, ee, namespace, resolverName, params, log) => [\n objDefineProps(fn, ON_ERROR_FN_NAME, function(resolverErrorHandler) {\n if (isFunc(resolverErrorHandler)) {\n // please note ON_ERROR_FN_NAME can add multiple listners\n ee.$only(\n createEvt(namespace, resolverName, ON_ERROR_FN_NAME), \n resolverErrorHandler\n )\n }\n }),\n ee,\n namespace,\n resolverName,\n params,\n log\n]\n\n/**\n * Add extra property / listeners to the resolver\n * @param {string} namespace where this belongs\n * @param {string} resolverName name as event name\n * @param {object} params from contract\n * @param {function} fn resolver function\n * @param {object} ee EventEmitter\n * @param {function} log function \n * @return {function} resolver\n */\nexport function setupResolver(namespace, resolverName, params, fn, ee, log) {\n let fns = [\n setupNamespace, \n setupOnResult, \n setupOnMessage, \n setupOnError, \n setupSendMethod\n ]\n \n // get the executor\n const executor = Reflect.apply(chainFns, null, fns)\n const args = [fn, ee, namespace, resolverName, params, log]\n\n return Reflect.apply(executor, null, args)\n}\n","// put all the resolver related methods here to make it more clear\n\n// this will be a mini client server architect\n// The reason is when the enableAuth setup - the private route\n// might not be validated, but we need the callable point is ready\n// therefore this part will always take the contract and generate\n// callable api for the developer to setup their front end\n// the only thing is - when they call they might get an error or\n// NOT_LOGIN_IN and they can react to this error accordingly\nimport { finalCatch } from 'jsonql-errors'\nimport { validateAsync } from 'jsonql-params-validator'\nimport { setupResolver } from './setup-resolver'\nimport { actionCall } from './action-call'\nimport {\n createEvt,\n objDefineProps,\n isFunc,\n injectToFn\n} from '../utils'\nimport {\n ON_ERROR_FN_NAME,\n ON_READY_FN_NAME\n} from 'jsonql-constants'\n\n/**\n * create the actual function to send message to server\n * @param {object} ee EventEmitter instance\n * @param {string} namespace this resolver end point\n * @param {string} resolverName name of resolver as event name\n * @param {object} params from contract\n * @param {function} log pass the log function\n * @return {function} resolver\n */\nfunction createResolver(ee, namespace, resolverName, params, log) {\n // note we pass the new withResult=true option\n return function resolver(...args) {\n return validateAsync(args, params.params, true)\n .then(_args => actionCall(ee, namespace, resolverName, _args, log))\n .catch(finalCatch)\n }\n}\n\n/**\n * step one get the clientmap with the namespace\n * @param {object} opts configuration\n * @param {object} ee EventEmitter\n * @param {object} nspGroup resolvers index by their namespace\n * @return {promise} resolve the clientmapped, and start the chain\n */\nexport function generateResolvers(opts, ee, nspGroup) {\n let client= {}\n let { log } = opts\n\n for (let namespace in nspGroup) {\n let list = nspGroup[namespace]\n for (let resolverName in list) {\n // resolverNames.push(resolverName)\n let params = list[resolverName]\n let fn = createResolver(ee, namespace, resolverName, params, log)\n // this should set as a getter therefore can not be overwrite by accident\n // obj[resolverName] = setupResolver(namespace, resolverName, params, fn, ee)\n client = injectToFn(\n client,\n resolverName,\n setupResolver(namespace, resolverName, params, fn, ee, log)\n )\n }\n }\n // resolve the clientto start the chain\n // chain the result to allow the chain processing\n return [ client, opts, ee, nspGroup ]\n}\n\n/**\n * The problem is the namespace can have more than one\n * and we only have on onError message\n * @param {object} clientthe client itself\n * @param {object} opts configuration\n * @param {object} ee Event Emitter\n * @param {object} nspGroup namespace keys\n * @return {array} [obj, opts, ee]\n */\nexport function createNamespaceErrorListener(client, opts, ee, nspGroup) {\n return [\n objDefineProps(\n client,\n ON_ERROR_FN_NAME,\n function namespaceErrorCallbackHandler(namespaceErrorHandler) {\n if (isFunc(namespaceErrorHandler)) {\n // please note ON_ERROR_FN_NAME can add multiple listners\n for (let namespace in nspGroup) {\n // this one is very tricky, we need to make sure the trigger is calling\n // with the namespace as well as the error\n ee.$on(createEvt(namespace, ON_ERROR_FN_NAME), namespaceErrorHandler)\n }\n }\n }\n ),\n opts,\n ee\n ]\n}\n\n/**\n * This event will fire when the socket.io.on('connection') and ws.onopen\n * @param {object} client client itself\n * @param {object} opts configuration\n * @param {object} ee Event Emitter\n * @return {array} [ obj, opts, ee ]\n */\nexport function createOnReadyListener(client, opts, ee) {\n return [\n objDefineProps(\n client,\n ON_READY_FN_NAME,\n function onReadyCallbackHandler(onReadyCallback) {\n if (isFunc(onReadyCallback)) {\n // reduce it down to just one flat level\n // @2020-03-19 only allow ONE onReady callback otherwise\n // it will get fire multiple times which is not what we want \n ee.$only(ON_READY_FN_NAME, onReadyCallback)\n }\n }\n ),\n opts,\n ee\n ]\n}\n","// this is a new method that will create several \n// intercom method also reverse listen to the server \n// such as disconnect (server issue disconnect)\nimport { injectToFn } from '../utils'\nimport { DISCONNECT_EVENT_NAME } from 'jsonql-constants'\n\n/**\n * this is the new method that setup the intercom handler \n * also this serve as the final call in the then chain to \n * output the client\n * @param {object} client the client \n * @param {object} opts configuration \n * @param {object} ee the event emitter\n * @return {object} client \n */\nexport function setupInterCom(client, opts, ee) {\n const { disconnectHandlerName } = opts\n return injectToFn(client, disconnectHandlerName, function disconnectHandler(...args) {\n ee.$trigger(DISCONNECT_EVENT_NAME, args)\n })\n} ","// The final step of the setup before it returns the client\nimport { setupInterCom } from './setup-intercom'\n// import { HELLO_FN } from 'jsonql-constants'\n\n/** \n * The final step to return the client \n * @param {object} client the client \n * @param {object} opts configuration \n * @param {object} ee the event emitter\n * @return {object} client \n */\nfunction setupFinalStep(obj, opts, ee) {\n const client = setupInterCom(obj, opts, ee)\n opts.log(`---> The final step to return the ws-client <---`)\n // add some debug functions \n client.verifyEventEmitter = () => ee.is\n // we add back the two things into the client \n // then when we do integration, we run it in reverse, \n // create the ws client first then the host client \n client.eventEmitter = opts.eventEmitter\n client.log = opts.log\n // we just inject a helloWorld method here \n // client[HELLO_FN] = \n\n return client\n}\n\n\nexport { setupFinalStep }\n\n\n","// resolvers generator\n// we change the interface to return promise from v1.0.3\n// this way we make sure the obj return is correct and timely\nimport { chainFns } from '../utils'\nimport { createAuthMethods } from './setup-auth-methods'\nimport {\n generateResolvers,\n createOnReadyListener,\n createNamespaceErrorListener\n} from './generator-methods'\nimport {\n setupFinalStep \n} from './setup-final-step'\nimport {\n NSP_GROUP\n} from 'jsonql-constants'\n\n/**\n * prepare the methods\n * @param {object} opts configuration\n * @param {object} nspMap resolvers index by their namespace\n * @param {object} ee EventEmitter\n * @return {object} of resolvers\n * @public\n */\nexport function callersGenerator(opts, nspMap, ee) {\n let fns = [\n generateResolvers,\n createOnReadyListener,\n createNamespaceErrorListener\n ]\n if (opts.enableAuth) {\n fns.push(createAuthMethods)\n } \n // we will always get back the [ obj, opts, ee ]\n // then we only return the obj (wsClient)\n fns.push(setupFinalStep)\n // run it\n const generator = Reflect.apply(chainFns, null, fns)\n\n return generator(opts, ee, nspMap[NSP_GROUP])\n}\n","// create options\nimport { \n checkConfigAsync, \n checkConfig \n} from 'jsonql-params-validator'\nimport { \n wsCoreCheckMap, \n wsCoreConstProps, \n socketCheckMap \n} from './defaults'\nimport { \n fixWss, \n getHostName, \n getEventEmitter, \n getNspInfoByConfig,\n getLogFn \n} from '../utils'\n\n/**\n * We need this to find the socket server type \n * @param {*} config \n * @return {string} the name of the socket server if any\n */\nfunction checkSocketClientType(config) {\n return checkConfig(config, socketCheckMap)\n}\n\n/**\n * Create a combine checkConfig for the creating the combine client\n * @param {*} configCheckMap \n * @param {*} constProps \n * @return {function} takes the user input config then resolve the configuration \n */\nfunction createCombineConfigCheck(configCheckMap, constProps) {\n const combineCheckMap = Object.assign({}, configCheckMap, wsCoreCheckMap)\n const combineConstProps = Object.assign({}, constProps, wsCoreConstProps)\n return config => checkConfigAsync(config, combineCheckMap, combineConstProps)\n}\n\n\n/**\n * wrapper method to check this already did the pre check\n * @param {object} config user supply config\n * @param {object} defaultOptions for checking\n * @param {object} constProps user supply const props\n * @return {promise} resolve to the checked opitons\n */\nfunction checkConfiguration(config, defaultOptions, constProps) {\n const defaultCheckMap= Object.assign(wsCoreCheckMap, defaultOptions)\n const wsConstProps = Object.assign(wsCoreConstProps, constProps)\n\n return checkConfigAsync(config, defaultCheckMap, wsConstProps)\n}\n\n/**\n * Taking the `then` part from the method below \n * @param {object} opts \n * @return {promise} opts all done\n */\nfunction postCheckInjectOpts(opts) {\n return Promise.resolve(opts)\n .then(opts => {\n if (!opts.hostname) {\n opts.hostname = getHostName()\n }\n // @TODO the contract now will supply the namespace information\n // and we need to use that to group the namespace call\n opts.wssPath = fixWss([opts.hostname, opts.namespace].join('/'), opts.serverType)\n // get the log function here\n opts.log = getLogFn(opts)\n\n opts.eventEmitter = getEventEmitter(opts)\n\n return opts\n })\n}\n\n/**\n * Don't want to make things confusing\n * Breaking up the opts process in one place \n * then generate the necessary parameter in another step \n * @param {object} opts checked --> merge --> injected \n * @return {object} {opts, nspMap, ee} \n */\nfunction createRequiredParams(opts) {\n return {\n opts,\n nspMap: getNspInfoByConfig(opts),\n ee: opts.eventEmitter \n }\n}\n\nexport {\n // properties \n wsCoreCheckMap,\n wsCoreConstProps,\n // functions \n checkConfiguration,\n postCheckInjectOpts,\n createRequiredParams,\n // this will just get export for integration \n checkSocketClientType,\n createCombineConfigCheck\n}\n","// the top level API\n// The goal is to create a generic method that will able to handle\n// any kind of clients\n// import { injectToFn } from 'jsonql-utils'\nimport { callersGenerator } from './callers'\nimport { \n checkConfiguration, \n postCheckInjectOpts,\n createRequiredParams \n} from './options'\n\n/**\n * 0.5.0 we break up the wsClientCore in two parts one without the config check \n * @param {function} socketClientListerner \n * @return {function} to actually generate the client\n */\nexport function wsClientCoreAction(socketClientListerner) {\n /** \n * This is a breaking change, to continue the onion skin design\n * @param {object} config the already checked config\n * @return {promise} resolve the client\n */ \n return (config = {}) => {\n\n return postCheckInjectOpts(config)\n // the following two moved to wsPostConfig\n .then(createRequiredParams)\n .then(\n ({opts, nspMap, ee}) => socketClientListerner(opts, nspMap, ee)\n )\n .then( // there is problem here, we wrap up the operation inside\n ({opts, nspMap, ee}) => callersGenerator(opts, nspMap, ee)\n )\n .catch(err => {\n console.error(`jsonql-ws-core-client init error`, err)\n })\n }\n}\n\n/**\n * The main interface which will generate the socket clients and map all events\n * @param {object} socketClientListerner this is the one method export by various clients\n * @param {object} [configCheckMap={}] we should do all the checking in the core instead of the client\n * @param {object} [constProps={}] add this to supply the constProps from the downstream client\n * @return {function} accept a config then return the wsClient instance with all the available API\n */\nexport function wsClientCore(socketClientListerner, configCheckMap = {}, constProps = {}) {\n // we need to inject property to this client later\n return (config = {}) => checkConfiguration(config, configCheckMap, constProps)\n .then(wsClientCoreAction(socketClientListerner))\n}\n","// this is getting too confusing \n// therefore we move it back to the framework specific \n\n/**\n * wrapper method to create a nsp without login\n * @param {string|boolean} namespace namespace url could be false\n * @param {object} opts configuration\n * @return {object} ws client instance\n */\nfunction createNspClient(namespace, opts) {\n const { hostname, wssPath, wsOptions, nspClient, log } = opts\n const url = namespace ? [hostname, namespace].join('/') : wssPath\n log(`createNspClient --> `, url)\n\n return nspClient(url, wsOptions)\n}\n\n/**\n * wrapper method to create a nsp with token auth\n * @param {string} namespace namespace url\n * @param {object} opts configuration\n * @return {object} ws client instance\n */\nfunction createNspAuthClient(namespace, opts) {\n const { hostname, wssPath, token, wsOptions, nspAuthClient, log } = opts\n const url = namespace ? [hostname, namespace].join('/') : wssPath\n \n log(`createNspAuthClient -->`, url)\n\n if (token && typeof token !== 'string') {\n throw new Error(`Expect token to be string, but got ${token}`)\n }\n \n return nspAuthClient(url, token, wsOptions)\n}\n\nexport {\n createNspClient,\n createNspAuthClient\n}\n","// this use by client-event-handler\nimport { ON_ERROR_FN_NAME } from 'jsonql-constants'\nimport { createEvt } from '../utils'\n\n/**\n * trigger errors on all the namespace onError handler\n * @param {object} ee Event Emitter\n * @param {array} namespaces nsps string\n * @param {string} message optional\n * @return {void}\n */\nexport function triggerNamespacesOnError(ee, namespaces, message) {\n namespaces.forEach( namespace => {\n ee.$trigger(\n createEvt(namespace, ON_ERROR_FN_NAME), \n [{ message, namespace }]\n )\n })\n}\n\n/**\n * Handle the onerror callback \n * @param {object} ee event emitter \n * @param {string} namespace which namespace has error \n * @param {*} err error object\n * @return {void} \n */\nexport const handleNamespaceOnError = (ee, namespace, err) => {\n ee.$trigger(createEvt(namespace, ON_ERROR_FN_NAME), [err])\n}","// NOT IN USE AT THE MOMENT JUST KEEP IT HERE FOR THE TIME BEING \nimport {\n LOGOUT_EVENT_NAME,\n NOT_LOGIN_ERR_MSG,\n ON_ERROR_FN_NAME,\n ON_RESULT_FN_NAME,\n DISCONNECT_EVENT_NAME\n} from 'jsonql-constants'\nimport { EMIT_EVT, DISCONNECTED_ERROR_MSG } from '../options/constants'\nimport { createEvt, clearMainEmitEvt } from '../utils'\nimport { triggerNamespacesOnError } from './trigger-namespaces-on-error'\n\n/**\n * Only when there is a private namespace then we bind to this event\n * @param {object} nsps the available nsp(s)\n * @param {array} namespaces available namespace \n * @param {object} ee eventEmitter \n * @param {object} opts configuration\n * @return {void}\n */\nexport const logoutEvtListener = (nsps, namespaces, ee, opts) => {\n const { log } = opts \n // this will be available regardless enableAuth\n // because the server can log the client out\n ee.$on(\n LOGOUT_EVENT_NAME, \n function logoutEvtCallback() {\n const privateNamespace = getPrivateNamespace(namespaces)\n log(`${LOGOUT_EVENT_NAME} event triggered`)\n // disconnect(nsps, opts.serverType)\n // we need to issue error to all the namespace onError Listerner\n triggerNamespacesOnError(ee, [privateNamespace], LOGOUT_EVENT_NAME)\n // rebind all of the Listerner to the fake one\n log(`logout from ${privateNamespace}`)\n\n clearMainEmitEvt(ee, privateNamespace)\n // we need to issue one more call to the server before we disconnect\n // now this is a catch 22, here we are not suppose to do anything platform specific\n // so that should fire before trigger this event\n // clear out the nsp\n nsps[privateNamespace] = null \n // add a NOT LOGIN error if call\n notLoginWsListerner(privateNamespace, ee, opts)\n }\n )\n}\n\n/**\n * A Event Listerner placeholder when it's not connect to any nsp\n * @param {string} namespace nsp\n * @param {object} ee EventEmitter\n * @param {object} opts configuration\n * @return {void}\n */\nexport const notConnectedListener = (namespace, ee, opts) => {\n const { log } = opts \n\n ee.$only(\n createEvt(namespace, EMIT_EVT),\n function disconnectedEvtCallback(resolverName, args) {\n log(`[disconnectedListerner] hijack the ws call`, namespace, resolverName, args)\n const error = {\n message: DISCONNECTED_ERROR_MSG\n }\n ee.$call(createEvt(namespace, resolverName, ON_ERROR_FN_NAME), [ error ])\n // also trigger the result Listerner, but wrap inside the error key\n ee.$call(createEvt(namespace, resolverName, ON_RESULT_FN_NAME), [{ error }])\n }\n )\n}\n\n\n/**\n * The disconnect event Listerner, now we log the client out from everything\n * @TODO now we are another problem they disconnect, how to reconnect\n * @param {object} nsps the available nsp(s)\n * @param {array} namespaces available namespace \n * @param {object} ee eventEmitter \n * @param {object} opts configuration\n * @return {void}\n */\nexport const disconnectListener = (nsps, namespaces, ee, opts) => {\n const { log } = opts \n ee.$on(\n DISCONNECT_EVENT_NAME, \n function disconnectEvtCallback() {\n triggerNamespacesOnError(ee, namespaces, DISCONNECT_EVENT_NAME)\n namespaces.forEach( namespace => { \n log(`disconnect from ${namespace}`)\n\n clearMainEmitEvt(ee, namespace)\n nsps[namespace] = null \n disconnectedListerner(namespace, ee, opts)\n })\n }\n )\n}\n\n/**\n * A Event Listerner placeholder when it's not connect to the private nsp\n * @param {string} namespace nsp\n * @param {object} ee EventEmitter\n * @param {object} opts configuration\n * @return {void}\n */\nexport const notLoginListener = (namespace, ee, opts) => {\n const { log } = opts \n\n ee.$only(\n createEvt(namespace, EMIT_EVT),\n function notLoginListernerCallback(resolverName, args) {\n log('[notLoginListerner] hijack the ws call', namespace, resolverName, args)\n const error = { message: NOT_LOGIN_ERR_MSG }\n // It should just throw error here and should not call the result\n // because that's channel for handling normal event not the fake one\n ee.$call(createEvt(namespace, resolverName, ON_ERROR_FN_NAME), [ error ])\n // also trigger the result Listerner, but wrap inside the error key\n ee.$call(createEvt(namespace, resolverName, ON_RESULT_FN_NAME), [{ error }])\n }\n )\n}","// This is share between different clients so we export it\n// @TODO port what is in the ws-main-handler\n// because all the client side call are via the ee\n// and that makes it re-usable between different client setup\n\n/*\nInside the map call but we take it out for now and until the WebSocket version is fully working\nimport { SOCKET_IO } from '../options/constants'\n // @TODO need to double check this\n if (opts.serverType === SOCKET_IO) {\n let { nspGroup } = nspMap\n args.push(nspGroup[namespace])\n }\n*/\nimport { getPrivateNamespace } from 'jsonql-utils/src/namespace'\nimport { logoutEvtListener, notLoginListener } from './event-listeners'\n\n\n/**\n * centralize all the comm in one place\n * @param {function} bindSocketEventHandler binding the ee to ws --> this is the core bit\n * @param {object} nsps namespaced nsp\n * @return {void} nothing\n */\nexport function clientEventListener(bindSocketEventListener, nsps) {\n /**\n * BREAKING CHANGE instead of one flat structure\n * we return a function to accept the two \n * @param {object} opts configuration\n * @param {object} nspMap this is not in the opts \n * @param {object} ee Event Emitter instance\n * @return {array} although we return something but this is the last step and nothing to do further\n */\n return (opts, nspMap, ee) => {\n // since all these params already in the opts\n const { log } = opts\n const { namespaces } = nspMap\n // @1.1.3 add isPrivate prop to id which namespace is the private nsp\n // then we can use this prop to determine if we need to fire the ON_LOGIN_PROP_NAME event\n const privateNamespace = getPrivateNamespace(namespaces)\n \n return namespaces.map(namespace => {\n let isPrivate = privateNamespace === namespace\n log(namespace, ` --> ${isPrivate ? 'private': 'public'} nsp --> `, nsps[namespace] !== false)\n if (nsps[namespace]) {\n log('[call bindWsHandler]', isPrivate, namespace)\n\n let args = [namespace, nsps[namespace], ee, isPrivate, opts]\n // Finally we binding everything together\n Reflect.apply(bindSocketEventListener, null, args)\n\n } else {\n log(`binding notLoginWsHandler to ${namespace}`)\n // a dummy placeholder\n // @TODO but it should be a not connect handler \n // when it's not login (or fail) this should be handle differently \n notLoginListener(namespace, ee, opts)\n }\n if (isPrivate) {\n log(`Has private and add logoutEvtHandler`)\n logoutEvtListener(nsps, namespaces, ee, opts)\n }\n // just return something its not going to get use anywhere\n return isPrivate \n })\n }\n}\n","// jsonql-ws-core takes over the check configuration\n// here we only have to supply the options that is unique to this client\n// create options\nimport { JS_WS_NAME } from 'jsonql-constants'\n// constant props\nconst wsClientConstProps = {\n version: '__PLACEHOLDER__', // will get replace\n serverType: JS_WS_NAME\n}\n\nexport { wsClientConstProps }\n","// pass the different type of ws to generate the client\n// this is where the framework specific code get injected\nimport { TOKEN_PARAM_NAME } from 'jsonql-constants'\nimport { fixWss } from '../modules'\nimport {\n createInitPing, \n extractPingResult\n} from '../modules'\n\n/**\n * Group the ping and get respond create new client in one\n * @param {object} ws \n * @param {object} WebSocket \n * @param {string} url\n * @param {function} resolver \n * @param {function} rejecter \n * @param {boolean} auth client or not\n * @return {promise} resolve the confirm client\n */\nfunction initPingAction(ws, WebSocket, url, resolver, rejecter, wsOptions) {\n // @TODO how to we id this client can issue a CSRF\n // by origin? \n ws.onopen = function onOpenCallback() {\n ws.send(createInitPing())\n }\n\n ws.onmessage = function onMessageCallback(payload) {\n try {\n const header = extractPingResult(payload.data)\n // @NOTE the break down test in ws-client-core show no problems\n // the problem was cause by malform nspInfo that time? \n setTimeout(() => { // delay or not show no different but just on the safe side\n ws.terminate()\n }, 50)\n const newWs = new WebSocket(url, Object.assign(wsOptions, header)) \n resolver(newWs) \n } catch(e) {\n rejecter(e)\n }\n }\n\n ws.onerror = function onErrorCallback(err) {\n rejecter(err)\n }\n}\n\n/**\n * less duplicated code the better \n * @param {object} WebSocket \n * @param {string} url formatted url\n * @param {object} options or not\n * @return {promise} resolve the actual verified client\n */\nfunction asyncConnect(WebSocket, url, options) {\n \n return new Promise((resolver, rejecter) => { \n \n const unconfirmClient = new WebSocket(url, options)\n \n initPingAction(unconfirmClient, WebSocket, url, resolver, rejecter, options)\n })\n}\n\n\n/**\n * The bug was in the wsOptions where ws don't need it but socket.io do\n * therefore the object was pass as second parameter!\n * @NOTE here we only return a method to create the client, it might not get call \n * @param {object} WebSocket the client or node version of ws\n * @param {boolean} auth if it's auth then 3 param or just one\n * @param {object} opts this is a breaking change we will init the client twice\n */\nfunction initWebSocketClient(WebSocket, auth, log) {\n if (auth === false) {\n /**\n * Create a non-protected client\n * @param {string} url \n * @param {object} [wsOptions={}]\n * @return {promise} resolve to the confirmed client\n */\n return function createWsClient(url, wsOptions = {}) {\n const _url = fixWss(url)\n log(`nspClient: \\n${_url}\\n`, wsOptions)\n\n return asyncConnect(WebSocket, _url, wsOptions)\n }\n }\n\n /**\n * Create a client with auth token\n * @param {string} url start with ws:// @TODO check this?\n * @param {string} token the jwt token\n * @param {object} [wsOptions={}] extra options pass to the WebSocket object\n * @return {object} ws instance\n */\n return function createWsAuthClient(url, token, wsOptions = {}) {\n const ws_url = fixWss(url)\n // console.log('what happen here?', url, ws_url, token)\n const _url = token && typeof token === 'string' ? `${ws_url}?${TOKEN_PARAM_NAME}=${token}` : ws_url\n log(`nspAuthClient: \\n${_url}\\n`, wsOptions)\n\n return asyncConnect(WebSocket, _url, wsOptions)\n }\n}\n\nexport { initWebSocketClient }","/** Used for built-in method references. */\nvar objectProto = Object.prototype;\n\n/**\n * Used to resolve the\n * [`toStringTag`](http://ecma-international.org/ecma-262/7.0/#sec-object.prototype.tostring)\n * of values.\n */\nvar nativeObjectToString = objectProto.toString;\n\n/**\n * Converts `value` to a string using `Object.prototype.toString`.\n *\n * @private\n * @param {*} value The value to convert.\n * @returns {string} Returns the converted string.\n */\nfunction objectToString(value) {\n return nativeObjectToString.call(value);\n}\n\nexport default objectToString;\n","/**\n * Creates a unary function that invokes `func` with its argument transformed.\n *\n * @private\n * @param {Function} func The function to wrap.\n * @param {Function} transform The argument transform.\n * @returns {Function} Returns the new function.\n */\nfunction overArg(func, transform) {\n return function(arg) {\n return func(transform(arg));\n };\n}\n\nexport default overArg;\n","/**\n * Checks if `value` is object-like. A value is object-like if it's not `null`\n * and has a `typeof` result of \"object\".\n *\n * @static\n * @memberOf _\n * @since 4.0.0\n * @category Lang\n * @param {*} value The value to check.\n * @returns {boolean} Returns `true` if `value` is object-like, else `false`.\n * @example\n *\n * _.isObjectLike({});\n * // => true\n *\n * _.isObjectLike([1, 2, 3]);\n * // => true\n *\n * _.isObjectLike(_.noop);\n * // => false\n *\n * _.isObjectLike(null);\n * // => false\n */\nfunction isObjectLike(value) {\n return value != null && typeof value == 'object';\n}\n\nexport default isObjectLike;\n","/**\n * Removes all key-value entries from the list cache.\n *\n * @private\n * @name clear\n * @memberOf ListCache\n */\nfunction listCacheClear() {\n this.__data__ = [];\n this.size = 0;\n}\n\nexport default listCacheClear;\n","/**\n * Performs a\n * [`SameValueZero`](http://ecma-international.org/ecma-262/7.0/#sec-samevaluezero)\n * comparison between two values to determine if they are equivalent.\n *\n * @static\n * @memberOf _\n * @since 4.0.0\n * @category Lang\n * @param {*} value The value to compare.\n * @param {*} other The other value to compare.\n * @returns {boolean} Returns `true` if the values are equivalent, else `false`.\n * @example\n *\n * var object = { 'a': 1 };\n * var other = { 'a': 1 };\n *\n * _.eq(object, object);\n * // => true\n *\n * _.eq(object, other);\n * // => false\n *\n * _.eq('a', 'a');\n * // => true\n *\n * _.eq('a', Object('a'));\n * // => false\n *\n * _.eq(NaN, NaN);\n * // => true\n */\nfunction eq(value, other) {\n return value === other || (value !== value && other !== other);\n}\n\nexport default eq;\n","/**\n * Removes `key` and its value from the stack.\n *\n * @private\n * @name delete\n * @memberOf Stack\n * @param {string} key The key of the value to remove.\n * @returns {boolean} Returns `true` if the entry was removed, else `false`.\n */\nfunction stackDelete(key) {\n var data = this.__data__,\n result = data['delete'](key);\n\n this.size = data.size;\n return result;\n}\n\nexport default stackDelete;\n","/**\n * Gets the stack value for `key`.\n *\n * @private\n * @name get\n * @memberOf Stack\n * @param {string} key The key of the value to get.\n * @returns {*} Returns the entry value.\n */\nfunction stackGet(key) {\n return this.__data__.get(key);\n}\n\nexport default stackGet;\n","/**\n * Checks if a stack value for `key` exists.\n *\n * @private\n * @name has\n * @memberOf Stack\n * @param {string} key The key of the entry to check.\n * @returns {boolean} Returns `true` if an entry for `key` exists, else `false`.\n */\nfunction stackHas(key) {\n return this.__data__.has(key);\n}\n\nexport default stackHas;\n","/**\n * Checks if `value` is the\n * [language type](http://www.ecma-international.org/ecma-262/7.0/#sec-ecmascript-language-types)\n * of `Object`. (e.g. arrays, functions, objects, regexes, `new Number(0)`, and `new String('')`)\n *\n * @static\n * @memberOf _\n * @since 0.1.0\n * @category Lang\n * @param {*} value The value to check.\n * @returns {boolean} Returns `true` if `value` is an object, else `false`.\n * @example\n *\n * _.isObject({});\n * // => true\n *\n * _.isObject([1, 2, 3]);\n * // => true\n *\n * _.isObject(_.noop);\n * // => true\n *\n * _.isObject(null);\n * // => false\n */\nfunction isObject(value) {\n var type = typeof value;\n return value != null && (type == 'object' || type == 'function');\n}\n\nexport default isObject;\n","/** Used for built-in method references. */\nvar funcProto = Function.prototype;\n\n/** Used to resolve the decompiled source of functions. */\nvar funcToString = funcProto.toString;\n\n/**\n * Converts `func` to its source code.\n *\n * @private\n * @param {Function} func The function to convert.\n * @returns {string} Returns the source code.\n */\nfunction toSource(func) {\n if (func != null) {\n try {\n return funcToString.call(func);\n } catch (e) {}\n try {\n return (func + '');\n } catch (e) {}\n }\n return '';\n}\n\nexport default toSource;\n","/**\n * Gets the value at `key` of `object`.\n *\n * @private\n * @param {Object} [object] The object to query.\n * @param {string} key The key of the property to get.\n * @returns {*} Returns the property value.\n */\nfunction getValue(object, key) {\n return object == null ? undefined : object[key];\n}\n\nexport default getValue;\n","/**\n * Removes `key` and its value from the hash.\n *\n * @private\n * @name delete\n * @memberOf Hash\n * @param {Object} hash The hash to modify.\n * @param {string} key The key of the value to remove.\n * @returns {boolean} Returns `true` if the entry was removed, else `false`.\n */\nfunction hashDelete(key) {\n var result = this.has(key) && delete this.__data__[key];\n this.size -= result ? 1 : 0;\n return result;\n}\n\nexport default hashDelete;\n","/**\n * Checks if `value` is suitable for use as unique object key.\n *\n * @private\n * @param {*} value The value to check.\n * @returns {boolean} Returns `true` if `value` is suitable, else `false`.\n */\nfunction isKeyable(value) {\n var type = typeof value;\n return (type == 'string' || type == 'number' || type == 'symbol' || type == 'boolean')\n ? (value !== '__proto__')\n : (value === null);\n}\n\nexport default isKeyable;\n","/**\n * Creates a base function for methods like `_.forIn` and `_.forOwn`.\n *\n * @private\n * @param {boolean} [fromRight] Specify iterating from right to left.\n * @returns {Function} Returns the new base function.\n */\nfunction createBaseFor(fromRight) {\n return function(object, iteratee, keysFunc) {\n var index = -1,\n iterable = Object(object),\n props = keysFunc(object),\n length = props.length;\n\n while (length--) {\n var key = props[fromRight ? length : ++index];\n if (iteratee(iterable[key], key, iterable) === false) {\n break;\n }\n }\n return object;\n };\n}\n\nexport default createBaseFor;\n","/**\n * Copies the values of `source` to `array`.\n *\n * @private\n * @param {Array} source The array to copy values from.\n * @param {Array} [array=[]] The array to copy values to.\n * @returns {Array} Returns `array`.\n */\nfunction copyArray(source, array) {\n var index = -1,\n length = source.length;\n\n array || (array = Array(length));\n while (++index < length) {\n array[index] = source[index];\n }\n return array;\n}\n\nexport default copyArray;\n","/** Used for built-in method references. */\nvar objectProto = Object.prototype;\n\n/**\n * Checks if `value` is likely a prototype object.\n *\n * @private\n * @param {*} value The value to check.\n * @returns {boolean} Returns `true` if `value` is a prototype, else `false`.\n */\nfunction isPrototype(value) {\n var Ctor = value && value.constructor,\n proto = (typeof Ctor == 'function' && Ctor.prototype) || objectProto;\n\n return value === proto;\n}\n\nexport default isPrototype;\n","/**\n * Checks if `value` is classified as an `Array` object.\n *\n * @static\n * @memberOf _\n * @since 0.1.0\n * @category Lang\n * @param {*} value The value to check.\n * @returns {boolean} Returns `true` if `value` is an array, else `false`.\n * @example\n *\n * _.isArray([1, 2, 3]);\n * // => true\n *\n * _.isArray(document.body.children);\n * // => false\n *\n * _.isArray('abc');\n * // => false\n *\n * _.isArray(_.noop);\n * // => false\n */\nvar isArray = Array.isArray;\n\nexport default isArray;\n","/** Used as references for various `Number` constants. */\nvar MAX_SAFE_INTEGER = 9007199254740991;\n\n/**\n * Checks if `value` is a valid array-like length.\n *\n * **Note:** This method is loosely based on\n * [`ToLength`](http://ecma-international.org/ecma-262/7.0/#sec-tolength).\n *\n * @static\n * @memberOf _\n * @since 4.0.0\n * @category Lang\n * @param {*} value The value to check.\n * @returns {boolean} Returns `true` if `value` is a valid length, else `false`.\n * @example\n *\n * _.isLength(3);\n * // => true\n *\n * _.isLength(Number.MIN_VALUE);\n * // => false\n *\n * _.isLength(Infinity);\n * // => false\n *\n * _.isLength('3');\n * // => false\n */\nfunction isLength(value) {\n return typeof value == 'number' &&\n value > -1 && value % 1 == 0 && value <= MAX_SAFE_INTEGER;\n}\n\nexport default isLength;\n","/**\n * This method returns `false`.\n *\n * @static\n * @memberOf _\n * @since 4.13.0\n * @category Util\n * @returns {boolean} Returns `false`.\n * @example\n *\n * _.times(2, _.stubFalse);\n * // => [false, false]\n */\nfunction stubFalse() {\n return false;\n}\n\nexport default stubFalse;\n","/**\n * The base implementation of `_.unary` without support for storing metadata.\n *\n * @private\n * @param {Function} func The function to cap arguments for.\n * @returns {Function} Returns the new capped function.\n */\nfunction baseUnary(func) {\n return function(value) {\n return func(value);\n };\n}\n\nexport default baseUnary;\n","/**\n * Gets the value at `key`, unless `key` is \"__proto__\" or \"constructor\".\n *\n * @private\n * @param {Object} object The object to query.\n * @param {string} key The key of the property to get.\n * @returns {*} Returns the property value.\n */\nfunction safeGet(object, key) {\n if (key === 'constructor' && typeof object[key] === 'function') {\n return;\n }\n\n if (key == '__proto__') {\n return;\n }\n\n return object[key];\n}\n\nexport default safeGet;\n","/**\n * The base implementation of `_.times` without support for iteratee shorthands\n * or max array length checks.\n *\n * @private\n * @param {number} n The number of times to invoke `iteratee`.\n * @param {Function} iteratee The function invoked per iteration.\n * @returns {Array} Returns the array of results.\n */\nfunction baseTimes(n, iteratee) {\n var index = -1,\n result = Array(n);\n\n while (++index < n) {\n result[index] = iteratee(index);\n }\n return result;\n}\n\nexport default baseTimes;\n","/** Used as references for various `Number` constants. */\nvar MAX_SAFE_INTEGER = 9007199254740991;\n\n/** Used to detect unsigned integer values. */\nvar reIsUint = /^(?:0|[1-9]\\d*)$/;\n\n/**\n * Checks if `value` is a valid array-like index.\n *\n * @private\n * @param {*} value The value to check.\n * @param {number} [length=MAX_SAFE_INTEGER] The upper bounds of a valid index.\n * @returns {boolean} Returns `true` if `value` is a valid index, else `false`.\n */\nfunction isIndex(value, length) {\n var type = typeof value;\n length = length == null ? MAX_SAFE_INTEGER : length;\n\n return !!length &&\n (type == 'number' ||\n (type != 'symbol' && reIsUint.test(value))) &&\n (value > -1 && value % 1 == 0 && value < length);\n}\n\nexport default isIndex;\n","/**\n * This function is like\n * [`Object.keys`](http://ecma-international.org/ecma-262/7.0/#sec-object.keys)\n * except that it includes inherited enumerable properties.\n *\n * @private\n * @param {Object} object The object to query.\n * @returns {Array} Returns the array of property names.\n */\nfunction nativeKeysIn(object) {\n var result = [];\n if (object != null) {\n for (var key in Object(object)) {\n result.push(key);\n }\n }\n return result;\n}\n\nexport default nativeKeysIn;\n","/**\n * This method returns the first argument it receives.\n *\n * @static\n * @since 0.1.0\n * @memberOf _\n * @category Util\n * @param {*} value Any value.\n * @returns {*} Returns `value`.\n * @example\n *\n * var object = { 'a': 1 };\n *\n * console.log(_.identity(object) === object);\n * // => true\n */\nfunction identity(value) {\n return value;\n}\n\nexport default identity;\n","/**\n * A faster alternative to `Function#apply`, this function invokes `func`\n * with the `this` binding of `thisArg` and the arguments of `args`.\n *\n * @private\n * @param {Function} func The function to invoke.\n * @param {*} thisArg The `this` binding of `func`.\n * @param {Array} args The arguments to invoke `func` with.\n * @returns {*} Returns the result of `func`.\n */\nfunction apply(func, thisArg, args) {\n switch (args.length) {\n case 0: return func.call(thisArg);\n case 1: return func.call(thisArg, args[0]);\n case 2: return func.call(thisArg, args[0], args[1]);\n case 3: return func.call(thisArg, args[0], args[1], args[2]);\n }\n return func.apply(thisArg, args);\n}\n\nexport default apply;\n","/**\n * Creates a function that returns `value`.\n *\n * @static\n * @memberOf _\n * @since 2.4.0\n * @category Util\n * @param {*} value The value to return from the new function.\n * @returns {Function} Returns the new constant function.\n * @example\n *\n * var objects = _.times(2, _.constant({ 'a': 1 }));\n *\n * console.log(objects);\n * // => [{ 'a': 1 }, { 'a': 1 }]\n *\n * console.log(objects[0] === objects[1]);\n * // => true\n */\nfunction constant(value) {\n return function() {\n return value;\n };\n}\n\nexport default constant;\n","/** Used to detect hot functions by number of calls within a span of milliseconds. */\nvar HOT_COUNT = 800,\n HOT_SPAN = 16;\n\n/* Built-in method references for those with the same name as other `lodash` methods. */\nvar nativeNow = Date.now;\n\n/**\n * Creates a function that'll short out and invoke `identity` instead\n * of `func` when it's called `HOT_COUNT` or more times in `HOT_SPAN`\n * milliseconds.\n *\n * @private\n * @param {Function} func The function to restrict.\n * @returns {Function} Returns the new shortable function.\n */\nfunction shortOut(func) {\n var count = 0,\n lastCalled = 0;\n\n return function() {\n var stamp = nativeNow(),\n remaining = HOT_SPAN - (stamp - lastCalled);\n\n lastCalled = stamp;\n if (remaining > 0) {\n if (++count >= HOT_COUNT) {\n return arguments[0];\n }\n } else {\n count = 0;\n }\n return func.apply(undefined, arguments);\n };\n}\n\nexport default shortOut;\n","// break it out on its own because\n// it's building from the lodash-es from scratch\n// according to this discussion https://github.com/lodash/lodash/issues/3298\nimport isPlainObject from 'lodash-es/isPlainObject'\nimport merge from 'lodash-es/merge'\n\n/**\n * previously we already make sure the order of the namespaces\n * and attach the auth client to it\n * @param {array} promises array of unresolved promises\n * @param {boolean} asObject if true then merge the result object\n * @return {object} promise resolved with the array of promises resolved results\n */\nexport function chainPromises(promises, asObject = false) {\n return promises.reduce((promiseChain, currentTask) => (\n promiseChain.then(chainResults => (\n currentTask.then(currentResult => (\n asObject === false ? [...chainResults, currentResult] : merge(chainResults, currentResult)\n ))\n ))\n ), Promise.resolve(\n asObject === false ? [] : (isPlainObject(asObject) ? asObject : {})\n ))\n}\n\n\n/**\n * This one return a different result from the chainPromises\n * it will be the same like chainFns that take one promise resolve as the next fn parameter\n * @param {function} initPromise a function that accept param and resolve result\n * @param {array} promises array of function pass that resolve promises\n * @return {promise} resolve the processed result\n */\nexport function chainProcessPromises(initPromise, ...promises) {\n return (...args) => (\n promises.reduce((promiseChain, currentTask) => (\n promiseChain.then(chainResult => (\n currentTask(chainResult)\n )\n )\n ), Reflect.apply(initPromise, null, args))\n )\n}\n","// @BUG when call disconnected \n// this keep causing an \"Disconnect call failed TypeError: Cannot read property 'readyState' of null\"\n// I think that is because it's not login then it can not be disconnect\n// how do we track this state globally\nimport { LOGIN_EVENT_NAME } from 'jsonql-constants'\nimport { clearMainEmitEvt } from '../modules'\n\n/**\n * create a login event handler \n * @param {object} opts configurations \n * @param {object} nspMap contain all the required info\n * @param {object} ee event emitter \n * @return {void}\n */\nexport function loginEventHandler(opts, nspMap, ee) {\n const { log } = opts\n const { namespaces } = nspMap\n\n ee.$only(LOGIN_EVENT_NAME, function loginEventHandlerCallback(tokenFromLoginAction) {\n \n log('createClient LOGIN_EVENT_NAME $only handler')\n\n clearMainEmitEvt(ee, namespaces)\n // console.log('LOGIN_EVENT_NAME', token)\n const newNsps = createNspAction(opts, nspMap, tokenFromLoginAction)\n // rebind it\n Reflect.apply(\n clientEventHandler, // @NOTE is this the problem that cause the hang up?\n null,\n args.concat([newNsps.namespaces, newNsps.nsps])\n )\n })\n}","// bunch of generic helpers\n\nimport isArray from 'lodash-es/isArray'\nimport isPlainObject from 'lodash-es/isPlainObject'\nimport trim from 'lodash-es/trim'\n\n/**\n * DIY in Array\n * @param {array} arr to check from\n * @param {*} value to check against\n * @return {boolean} true on found\n */\nexport const inArray = (arr, value) => !!arr.filter(a => a === value).length\n\n// quick and dirty to turn non array to array\nexport const toArray = (arg) => isArray(arg) ? arg : [arg]\n\n/**\n * parse string to json or just return the original value if error happened\n * @param {*} n input\n * @param {boolean} [t=true] or throw\n * @return {*} json object on success\n */\nexport const parseJson = function(n, t=true) {\n try {\n return JSON.parse(n)\n } catch(e) {\n if (t) {\n return n\n }\n throw new Error(e)\n }\n}\n\n/**\n * @param {object} obj for search\n * @param {string} key target\n * @return {boolean} true on success\n */\nexport const isObjectHasKey = function(obj, key) {\n try {\n const keys = Object.keys(obj)\n return inArray(keys, key)\n } catch(e) {\n // @BUG when the obj is not an OBJECT we got some weird output\n return false\n }\n}\n\n/**\n * create a event name\n * @param {string[]} args\n * @return {string} event name for use\n */\nexport const createEvt = (...args) => args.join('_')\n\n/**\n * simple util method to get the value\n * @param {string} name of the key\n * @param {object} obj to take value from\n * @return {*} the object value id by name or undefined\n */\nexport const getConfigValue = (name, obj) => (\n obj && isPlainObject(obj) ? ( (name in obj) ? obj[name] : undefined ) : undefined\n)\n\n/**\n * small util to make sure the return value is valid JSON object\n * @param {*} n input\n * @return {object} correct JSON object\n */\nexport const toJson = n => {\n if (typeof n === 'string') {\n return parseJson(n)\n }\n return parseJson(JSON.stringify(n))\n}\n\n/**\n * Check several parameter that there is something in the param\n * @param {*} param input\n * @return {boolean}\n */\nexport const isNotEmpty = function(param) {\n return param !== undefined && param !== false && param !== null && trim(param) !== ''\n}\n\n/**\n * Simple check if the prop is function\n * @param {*} prop input\n * @return {boolean} true on success\n */\nexport const isFunc = prop => {\n if (typeof prop === 'function') {\n return true;\n }\n console.error(`Expect to be Function type! Got ${typeof prop}`)\n}\n\n// generic placeholder function\nexport const nil = () => false\n","// custom validation error class\n// when validaton failed\nexport default class JsonqlValidationError extends Error {\n constructor(...args) {\n super(...args)\n\n this.message = args[0]\n this.detail = args[1]\n\n this.className = JsonqlValidationError.name;\n\n if (Error.captureStackTrace) {\n Error.captureStackTrace(this, JsonqlValidationError)\n }\n }\n\n static get name() {\n return 'JsonqlValidationError'\n }\n}\n","/**\n * @param {boolean} sec return in second or not\n * @return {number} timestamp\n */\nexport const timestamp = (sec = false) => {\n let time = Date.now()\n return sec ? Math.floor( time / 1000 ) : time\n}\n","// ported from jsonql-params-validator\n// craete several helper function to construct / extract the payload\n// and make sure they are all the same\nimport {\n PAYLOAD_PARAM_NAME,\n CONDITION_PARAM_NAME,\n RESOLVER_PARAM_NAME,\n QUERY_ARG_NAME,\n TIMESTAMP_PARAM_NAME\n} from 'jsonql-constants'\n\nimport JsonqlValidationError from 'jsonql-errors/src/validation-error'\n\nimport isArray from 'lodash-es/isArray'\nimport isString from 'lodash-es/isString'\nimport isPlainObject from 'lodash-es/isPlainObject'\n\nimport { timestamp } from './timestamp'\nimport { parseJson } from './generic'\n\n/**\n * check if the payload has a timestamp field, then append a new timestamp to it\n * @param {object} payload from the com\n * @return {array} timestamp field with an array value\n */\nexport const handleTimestamp = payload => {\n let ts = payload[TIMESTAMP_PARAM_NAME]\n if (!isArray(ts)) {\n ts = [ts]\n }\n ts.push( timestamp() )\n\n return ts\n}\n\n/**\n * make sure it's an object (it was call formatPayload but it doesn't make sense)\n * @param {*} payload the object comes in could be string based\n * @return {object} the transformed payload\n */\nexport const toPayload = payload => isString(payload) ? parseJson(payload) : payload\n\n/**\n * @param {*} args arguments to send\n *@return {object} formatted payload\n */\nexport const formatPayload = (args) => (\n { [QUERY_ARG_NAME]: args }\n)\n\n/**\n * extract the resolver name from the payload \n * @param {object} payload\n * @return {string} resolver name \n */\nexport function getResolverFromPayload(payload) {\n const keys = Object.keys(payload)\n return keys.filter(key => key !== TIMESTAMP_PARAM_NAME)[0]\n}\n\n/**\n * wrapper method to add the timestamp as well\n * @param {string} resolverName\n * @param {*} payload\n * @return {object} delierable\n */\nexport function createDeliverable(resolverName, payload) {\n return {\n [resolverName]: payload,\n [TIMESTAMP_PARAM_NAME]: [ timestamp() ]\n }\n}\n\n/**\n * @param {string} resolverName name of function\n * @param {array} [args=[]] from the ...args\n * @param {boolean} [jsonp = false] add v1.3.0 to koa\n * @return {object} formatted argument\n */\nexport function createQuery(resolverName, args = [], jsonp = false) {\n if (isString(resolverName) && isArray(args)) {\n let payload = formatPayload(args)\n if (jsonp === true) {\n return payload\n }\n return createDeliverable(resolverName, payload)\n }\n throw new JsonqlValidationError(`[createQuery] expect resolverName to be string and args to be array!`, { resolverName, args })\n}\n\n/**\n * string version of the createQuery\n * @return {string}\n */\nexport function createQueryStr(resolverName, args = [], jsonp = false) {\n return JSON.stringify(createQuery(resolverName, args, jsonp))\n}\n\n/**\n * @param {string} resolverName name of function\n * @param {*} payload to send\n * @param {object} [condition={}] for what\n * @param {boolean} [jsonp = false] add v1.3.0 to koa\n * @return {object} formatted argument\n */\nexport function createMutation(resolverName, payload, condition = {}, jsonp = false) {\n const _payload = {\n [PAYLOAD_PARAM_NAME]: payload,\n [CONDITION_PARAM_NAME]: condition\n }\n if (jsonp === true) {\n return _payload\n }\n if (isString(resolverName)) {\n return createDeliverable(resolverName, _payload)\n }\n throw new JsonqlValidationError(`[createMutation] expect resolverName to be string!`, { resolverName, payload, condition })\n}\n\n/**\n * string version of createMutation\n * @return {string}\n */\nexport function createMutationStr(resolverName, payload, condition = {}, jsonp = false) {\n return JSON.stringify(createMutation(resolverName, payload, condition, jsonp))\n}\n\n/**\n * Extract the parts from payload and format for use\n * @param {string} resolverName name of fn\n * @param {object} payload the incoming json\n * @return {object|boolean} false on failed\n */\nexport function getQueryFromArgs(resolverName, payload) {\n if (resolverName && isPlainObject(payload)) {\n const args = payload[resolverName]\n if (args[QUERY_ARG_NAME]) {\n return {\n [RESOLVER_PARAM_NAME]: resolverName,\n [QUERY_ARG_NAME]: args[QUERY_ARG_NAME],\n [TIMESTAMP_PARAM_NAME]: handleTimestamp(payload)\n }\n }\n }\n return false\n}\n\n/**\n * Share function so no repeat\n * @param {object} payload the payload from client\n * @param {function} processor the last get result method\n * @return {*} result processed result\n */\nfunction processPayload(payload, processor) {\n const p = toPayload(payload)\n const resolverName = getResolverFromPayload(p)\n return Reflect.apply(processor, null, [resolverName, p])\n}\n\n/**\n * extra the payload back\n * @param {*} payload from http call\n * @return {object} resolverName and args\n */\nexport function getQueryFromPayload(payload) {\n const result = processPayload(payload, getQueryFromArgs)\n if (result !== false) {\n return result\n }\n throw new JsonqlValidationError('[getQueryArgs] Payload is malformed!', payload)\n}\n\n/**\n * Further break down from method below for use else where\n * @param {string} resolverName name of fn\n * @param {object} payload payload\n * @return {object|boolean} false on failed\n */\nexport function getMutationFromArgs(resolverName, payload) {\n if (resolverName && isPlainObject(payload)) {\n const args = payload[resolverName]\n if (args) {\n return {\n [RESOLVER_PARAM_NAME]: resolverName,\n [PAYLOAD_PARAM_NAME]: args[PAYLOAD_PARAM_NAME],\n [CONDITION_PARAM_NAME]: args[CONDITION_PARAM_NAME],\n [TIMESTAMP_PARAM_NAME]: handleTimestamp(payload)\n }\n }\n }\n return false\n}\n\n/**\n * @param {object} payload\n * @return {object} resolverName, payload, conditon\n */\nexport function getMutationFromPayload(payload) {\n const result = processPayload(payload, getMutationFromArgs)\n\n if (result !== false) {\n return result\n }\n throw new JsonqlValidationError('[getMutationArgs] Payload is malformed!', payload)\n}\n","// There are the socket related methods ported back from \n// ws-server-core and ws-client-core \nimport {\n WS_REPLY_TYPE,\n WS_EVT_NAME,\n WS_DATA_NAME,\n TIMESTAMP_PARAM_NAME,\n ERROR_KEY,\n EMIT_REPLY_TYPE,\n ACKNOWLEDGE_REPLY_TYPE\n} from 'jsonql-constants'\nimport { JsonqlError } from 'jsonql-errors' \nimport isString from 'lodash-es/isString'\n\nimport { toJson, isObjectHasKey, nil } from './generic'\nimport { timestamp } from './timestamp'\n\nconst PAYLOAD_NOT_DECODED_ERR = 'payload can not decoded'\nconst WS_KEYS = [\n WS_REPLY_TYPE,\n WS_EVT_NAME,\n WS_DATA_NAME\n]\n\n\n/**\n * The ws doesn't have a acknowledge callback like socket.io\n * so we have to DIY one for ws and other that doesn't have it\n * @param {string} type of reply\n * @param {string} resolverName which is replying\n * @param {*} data payload\n * @param {array} [ts= []] the last received ts, if any \n * @return {string} stringify json\n */\nexport const createWsReply = (type, resolverName, data, ts = []) => {\n ts.push(timestamp())\n return JSON.stringify({\n data: {\n [WS_REPLY_TYPE]: type,\n [WS_EVT_NAME]: resolverName,\n [WS_DATA_NAME]: toJson(data)\n },\n [TIMESTAMP_PARAM_NAME]: ts \n })\n}\n\n// extended function \nexport const createReplyMsg = (resolverName, data, ts = []) => (\n createWsReply(EMIT_REPLY_TYPE, resolverName, data, ts)\n)\n\nexport const createAcknowledgeMsg = (resolverName, data, ts = []) => (\n createWsReply(ACKNOWLEDGE_REPLY_TYPE, resolverName, data, ts)\n)\n\n/**\n * @param {string|object} payload should be string when reply but could be transformed\n * @return {boolean} true is OK\n */\nexport const isWsReply = payload => {\n const json = isString(payload) ? toJson(payload) : payload\n const { data } = json\n if (data) {\n let result = WS_KEYS.filter(key => isObjectHasKey(data, key))\n return (result.length === WS_KEYS.length) ? data : false\n }\n return false\n}\n\n/**\n * @param {string|object} data received data\n * @param {function} [cb=nil] this is for extracting the TS field or when it's error\n * @return {object} false on failed\n */\nexport const extractWsPayload = (payload, cb = nil) => {\n try {\n const json = toJson(payload)\n // now handle the data\n let _data\n if ((_data = isWsReply(json)) !== false) {\n // note the ts property is on its own \n cb(TIMESTAMP_PARAM_NAME, json[TIMESTAMP_PARAM_NAME])\n \n return {\n data: toJson(_data[WS_DATA_NAME]),\n resolverName: _data[WS_EVT_NAME],\n type: _data[WS_REPLY_TYPE]\n }\n }\n throw new JsonqlError(PAYLOAD_NOT_DECODED_ERR, payload)\n } catch(e) {\n return cb(ERROR_KEY, e)\n }\n}\n","// the WebSocket main handler\nimport {\n LOGOUT_EVENT_NAME,\n ACKNOWLEDGE_REPLY_TYPE,\n EMIT_REPLY_TYPE,\n ERROR_KEY,\n\n ON_ERROR_FN_NAME,\n ON_MESSAGE_FN_NAME,\n ON_RESULT_FN_NAME,\n ON_READY_FN_NAME,\n ON_LOGIN_FN_NAME\n} from 'jsonql-constants'\nimport {\n createQueryStr,\n createEvt,\n extractWsPayload\n} from 'jsonql-utils/module'\nimport {\n handleNamespaceOnError,\n createIntercomPayload\n} from '../modules'\n\n/**\n * in some edge case we might not even have a resolverName, then\n * we issue a global error for the developer to catch it\n * @param {object} ee event emitter\n * @param {string} namespace nsp\n * @param {string} resolverName resolver\n * @param {object} json decoded payload or error object\n * @return {undefined} nothing return\n */\nconst errorTypeHandler = (ee, namespace, resolverName, json) => {\n let evt = [namespace]\n if (resolverName) {\n evt.push(resolverName)\n }\n evt.push(ON_ERROR_FN_NAME)\n let evtName = Reflect.apply(createEvt, null, evt)\n // test if there is a data field\n let payload = json.data || json\n ee.$trigger(evtName, [payload])\n}\n\n/**\n * Handle the logout event when it's enableAuth\n * @param {object} ee eventEmitter\n * @param {object} ws the WebSocket instance\n * @return {void}\n */\nconst logoutEventListener = (ee, ws) => {\n // listen to the LOGOUT_EVENT_NAME when this is a private nsp\n ee.$on(LOGOUT_EVENT_NAME, function closeEvtHandler() {\n try {\n // @TODO we need find a way to get the userdata\n ws.send(createIntercomPayload(LOGOUT_EVENT_NAME))\n log('terminate ws connection')\n ws.terminate()\n } catch(e) {\n console.error('ws.terminate error', e)\n }\n })\n}\n\n/**\n * Binding the event to socket normally\n * @param {string} namespace\n * @param {object} ws the nsp\n * @param {object} ee EventEmitter\n * @param {boolean} isPrivate to id if this namespace is private or not\n * @param {object} opts configuration\n * @return {object} promise resolve after the onopen event\n */\nexport function bindSocketEventHandler(namespace, ws, ee, isPrivate, opts) {\n const { log } = opts\n // log(`log test, isPrivate:`, isPrivate)\n // connection open\n ws.onopen = function onOpenCallback() {\n\n log('=== ws.onopen listened -->', namespace)\n // we just call the onReady\n ee.$call(ON_READY_FN_NAME)(namespace)\n // need an extra parameter here to id the private nsp\n if (isPrivate) {\n log(`isPrivate and fire the ${ON_LOGIN_FN_NAME}`)\n ee.$call(ON_LOGIN_FN_NAME)(namespace)\n }\n // add listener only after the open is called\n ee.$only(\n createEvt(namespace, EMIT_REPLY_TYPE),\n /**\n * actually send the payload to server\n * @param {string} resolverName\n * @param {array} args NEED TO CHECK HOW WE PASS THIS!\n */\n function wsMainOnEvtHandler(resolverName, args) {\n\n const payload = createQueryStr(resolverName, args)\n log('ws.onopen.send', resolverName, args, payload)\n\n ws.send(payload)\n }\n )\n }\n\n // reply\n // If we change it to the event callback style\n // then the payload will just be the payload and fucks up the extractWsPayload call @TODO\n ws.onmessage = function onMessageCallback(payload) {\n // console.log(`on.message`, typeof payload, payload)\n try {\n // log(`ws.onmessage raw payload`, payload)\n // @TODO the payload actually contain quite a few things - is that changed?\n // type: message, data: data_send_from_server\n const json = extractWsPayload(payload.data)\n const { resolverName, type } = json\n\n log('Respond from server', type, json)\n\n switch (type) {\n case EMIT_REPLY_TYPE:\n let e1 = createEvt(namespace, resolverName, ON_MESSAGE_FN_NAME)\n let r = ee.$trigger(e1, [json])\n log(`EMIT_REPLY_TYPE`, e1, r)\n break\n case ACKNOWLEDGE_REPLY_TYPE:\n let e2 = createEvt(namespace, resolverName, ON_RESULT_FN_NAME)\n let x2 = ee.$trigger(e2, [json])\n log(`ACKNOWLEDGE_REPLY_TYPE`, e2, x2)\n break\n case ERROR_KEY:\n // this is handled error and we won't throw it\n // we need to extract the error from json\n log(`ERROR_KEY`)\n errorTypeHandler(ee, namespace, resolverName, json)\n break\n // @TODO there should be an error type instead of roll into the other two types? TBC\n default:\n // if this happen then we should throw it and halt the operation all together\n log('Unhandled event!', json)\n errorTypeHandler(ee, namespace, resolverName, json)\n // let error = {error: {'message': 'Unhandled event!', type}};\n // ee.$trigger(createEvt(namespace, resolverName, ON_RESULT_FN_NAME), [error])\n }\n } catch(e) {\n console.error(`ws.onmessage error`, e)\n errorTypeHandler(ee, namespace, false, e)\n }\n }\n // when the server close the connection\n ws.onclose = function onCloseCallback() {\n log('ws.onclose callback')\n // @TODO what to do with this\n // ee.$trigger(LOGOUT_EVENT_NAME, [namespace])\n }\n // add a onerror event handler here\n ws.onerror = function onErrorCallback(err) {\n // trigger a global error event\n log(`ws.onerror`, err)\n handleNamespaceOnError(ee, namespace, err)\n }\n\n if (isPrivate) {\n logoutEventListener(ee, ws)\n }\n\n}\n","// actually binding the event client to the socket client\n\n// from the jsonql-ws-client-core\nimport { clientEventListener } from '../modules'\n// local \nimport { createNspAction } from './create-nsp-action'\nimport { loginEventHandler } from './login-event-handler'\nimport { bindSocketEventHandler } from './bind-socket-event-handler'\n\n/**\n * create the NSP(s) and determine if this require auth or not \n * @param {object} opts configuration\n * @param {object} nspMap namespace with resolvers\n * @param {object} ee EventEmitter to pass through\n * @return {object} what comes in what goes out\n */\nfunction createNsp(opts, nspMap, ee) {\n // now create the nsps\n // const { namespaces } = nspMap\n const { token } = opts\n\n return createNspAction(opts, nspMap, token)\n .then(nsps => {\n const listenerFn = clientEventListener(bindSocketEventHandler, nsps)\n // now run it\n listenerFn(opts, nspMap, ee)\n\n if (opts.enableAuth) {\n loginEventHandler(opts, nspMap, ee)\n }\n // return what input\n return { opts, nspMap, ee }\n }) \n}\n\nexport { createNsp }","// breaking up the create-nsp.js file \n// then regroup them back together here \nimport { createNsp } from './create-nsp'\n\nexport default createNsp\n","// share method to create the wsClientResolver\nimport { initWebSocketClient } from './init-websocket-client'\nimport createNsp from '../create-nsp'\nimport { NSP_CLIENT, NSP_AUTH_CLIENT } from 'jsonql-constants'\n\n/**\n * Create the framework <---> jsonql client binding\n * @param {object} frameworkModule the different WebSocket module\n * @return {function} the wsClientResolver\n */\nfunction bindFrameworkToJsonql(frameworkModule) {\n /**\n * wsClientResolver\n * @param {object} opts configuration\n * @param {object} nspMap from the contract\n * @param {object} ee instance of the eventEmitter\n * @return {object} passing the same 3 input out with additional in the opts\n */\n return function createClientBindingAction(opts, nspMap, ee) {\n const { log } = opts\n opts[NSP_CLIENT] = initWebSocketClient(frameworkModule, false, log)\n opts[NSP_AUTH_CLIENT] = initWebSocketClient(frameworkModule, true, log) \n // @1.0.7 remove later once everything fixed \n \n log(`bindFrameworkToJsonql`, ee.name, nspMap)\n // console.log(`contract`, opts.contract)\n return createNsp(opts, nspMap, ee)\n }\n}\n\nexport { bindFrameworkToJsonql }","// this will be the news style interface that will pass to the jsonql-ws-client\n// then return a function for accepting an opts to generate the final\n// client api\nimport WebSocket from 'ws'\nimport createWebSocketBinding from '../core/create-websocket-binding'\n\n/**\n * @param {object} opts configuration\n * @param {object} nspMap from the contract\n * @param {object} ee instance of the eventEmitter\n * @return {object} passing the same 3 input out with additional in the opts\n */\nexport default createWebSocketBinding(WebSocket)\n","// this is the module entry point for node client\nimport {\n wsClientCore\n} from './core/modules'\nimport { wsClientConstProps } from './options'\n\nimport nodeFrameworkSocketEngine from './node/node-framework-socket-engine'\n\n// export back the function and that's it\nexport default function wsNodeClient(config = {}, constProps = {}) {\n const initClientMethod = wsClientCore(\n nodeFrameworkSocketEngine, \n {}, \n Object.assign({}, wsClientConstProps, constProps)\n )\n return initClientMethod(config)\n}\n"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;ACAA;;;;;;;;;ACAA;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;ACAA;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;ACAA;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;"} \ No newline at end of file +{"version":3,"file":"main.js","sources":["../../ws-client-core/node_modules/lodash-es/isArray.js","node_modules/rollup-plugin-node-globals/src/global.js","../../ws-client-core/node_modules/lodash-es/_objectToString.js","../../ws-client-core/node_modules/lodash-es/_overArg.js","../../ws-client-core/node_modules/lodash-es/isObjectLike.js","../../ws-client-core/node_modules/lodash-es/_arrayMap.js","../../ws-client-core/node_modules/lodash-es/_baseSlice.js","../../ws-client-core/node_modules/lodash-es/_baseFindIndex.js","../../ws-client-core/node_modules/lodash-es/_baseIsNaN.js","../../ws-client-core/node_modules/lodash-es/_strictIndexOf.js","../../ws-client-core/node_modules/lodash-es/_asciiToArray.js","../../ws-client-core/node_modules/lodash-es/_hasUnicode.js","../../ws-client-core/node_modules/lodash-es/_unicodeToArray.js","../../ws-client-core/node_modules/jsonql-utils/src/generic.js","../../ws-client-core/node_modules/lodash-es/_listCacheClear.js","../../ws-client-core/node_modules/lodash-es/eq.js","../../ws-client-core/node_modules/lodash-es/_stackDelete.js","../../ws-client-core/node_modules/lodash-es/_stackGet.js","../../ws-client-core/node_modules/lodash-es/_stackHas.js","../../ws-client-core/node_modules/lodash-es/isObject.js","../../ws-client-core/node_modules/lodash-es/_toSource.js","../../ws-client-core/node_modules/lodash-es/_getValue.js","../../ws-client-core/node_modules/lodash-es/_hashDelete.js","../../ws-client-core/node_modules/lodash-es/_isKeyable.js","../../ws-client-core/node_modules/lodash-es/_createBaseFor.js","../../ws-client-core/node_modules/lodash-es/_copyArray.js","../../ws-client-core/node_modules/lodash-es/_isPrototype.js","../../ws-client-core/node_modules/lodash-es/isLength.js","../../ws-client-core/node_modules/lodash-es/stubFalse.js","../../ws-client-core/node_modules/lodash-es/_baseUnary.js","../../ws-client-core/node_modules/lodash-es/_safeGet.js","../../ws-client-core/node_modules/lodash-es/_baseTimes.js","../../ws-client-core/node_modules/lodash-es/_isIndex.js","../../ws-client-core/node_modules/lodash-es/_nativeKeysIn.js","../../ws-client-core/node_modules/lodash-es/identity.js","../../ws-client-core/node_modules/lodash-es/_apply.js","../../ws-client-core/node_modules/lodash-es/constant.js","../../ws-client-core/node_modules/lodash-es/_shortOut.js","../../ws-client-core/node_modules/jsonql-errors/src/enum-error.js","../../ws-client-core/node_modules/jsonql-errors/src/type-error.js","../../ws-client-core/node_modules/jsonql-errors/src/checker-error.js","../../ws-client-core/node_modules/jsonql-errors/src/validation-error.js","../../ws-client-core/node_modules/jsonql-utils/src/contract.js","../../ws-client-core/node_modules/jsonql-utils/src/timestamp.js","../../ws-client-core/node_modules/jsonql-utils/src/params-api.js","../../ws-client-core/node_modules/jsonql-utils/src/namespace.js","../../ws-client-core/node_modules/jsonql-utils/src/socket.js","../../ws-client-core/src/callers/intercom-methods.js","../../ws-client-core/node_modules/jsonql-params-validator/src/number.js","../../ws-client-core/node_modules/jsonql-params-validator/src/string.js","../../ws-client-core/node_modules/jsonql-params-validator/src/boolean.js","../../ws-client-core/node_modules/jsonql-params-validator/src/any.js","../../ws-client-core/node_modules/jsonql-params-validator/src/constants.js","../../ws-client-core/node_modules/jsonql-params-validator/src/combine.js","../../ws-client-core/node_modules/jsonql-params-validator/src/array.js","../../ws-client-core/node_modules/jsonql-params-validator/src/object.js","../../ws-client-core/node_modules/jsonql-params-validator/src/validator.js","../../ws-client-core/node_modules/lodash-es/_setCacheAdd.js","../../ws-client-core/node_modules/lodash-es/_setCacheHas.js","../../ws-client-core/node_modules/lodash-es/_arraySome.js","../../ws-client-core/node_modules/lodash-es/_cacheHas.js","../../ws-client-core/node_modules/lodash-es/_mapToArray.js","../../ws-client-core/node_modules/lodash-es/_setToArray.js","../../ws-client-core/node_modules/lodash-es/_arrayPush.js","../../ws-client-core/node_modules/lodash-es/_arrayFilter.js","../../ws-client-core/node_modules/lodash-es/stubArray.js","../../ws-client-core/node_modules/lodash-es/_matchesStrictComparable.js","../../ws-client-core/node_modules/lodash-es/_baseHasIn.js","../../ws-client-core/node_modules/lodash-es/_baseProperty.js","../../ws-client-core/node_modules/lodash-es/negate.js","../../ws-client-core/node_modules/lodash-es/_baseFindKey.js","../../ws-client-core/node_modules/jsonql-params-validator/src/is-in-array.js","../../ws-client-core/node_modules/jsonql-params-validator/src/options/run-validation.js","../../ws-client-core/node_modules/jsonql-params-validator/src/options/check-options-async.js","../../ws-client-core/node_modules/jsonql-params-validator/src/options/construct-config.js","../../ws-client-core/node_modules/jsonql-params-validator/src/options/index.js","../../ws-client-core/node_modules/jsonql-params-validator/index.js","../../ws-client-core/src/utils/get-log-fn.js","../../ws-client-core/node_modules/@to1source/event/src/constants.js","../../ws-client-core/node_modules/@to1source/event/src/store.js","../../ws-client-core/node_modules/@to1source/event/src/utils.js","../../ws-client-core/node_modules/@to1source/event/src/suspend.js","../../ws-client-core/node_modules/@to1source/event/src/store-service.js","../../ws-client-core/node_modules/@to1source/event/src/event-service.js","../../ws-client-core/node_modules/@to1source/event/index.js","../../ws-client-core/src/utils/get-event-emitter.js","../../ws-client-core/src/utils/helpers.js","../../ws-client-core/src/callers/setup-auth-methods.js","../../ws-client-core/src/options/constants.js","../../ws-client-core/src/callers/respond-handler.js","../../ws-client-core/src/callers/action-call.js","../../ws-client-core/src/callers/setup-send-method.js","../../ws-client-core/src/callers/setup-resolver.js","../../ws-client-core/src/callers/generator-methods.js","../../ws-client-core/src/callers/callers-generator.js","../../ws-client-core/src/callers/setup-intercom.js","../../ws-client-core/src/callers/setup-final-step.js","../../ws-client-core/src/options/index.js","../../ws-client-core/src/api.js","../../ws-client-core/src/listener/create-nsp-clients.js","../../ws-client-core/src/listener/trigger-namespaces-on-error.js","../../ws-client-core/src/listener/event-listeners.js","../../ws-client-core/src/listener/client-event-listener.js","src/options/index.js","src/core/create-websocket-binding/init-websocket-client.js","node_modules/lodash-es/_objectToString.js","node_modules/lodash-es/_overArg.js","node_modules/lodash-es/isObjectLike.js","node_modules/lodash-es/_listCacheClear.js","node_modules/lodash-es/eq.js","node_modules/lodash-es/_stackDelete.js","node_modules/lodash-es/_stackGet.js","node_modules/lodash-es/_stackHas.js","node_modules/lodash-es/isObject.js","node_modules/lodash-es/_toSource.js","node_modules/lodash-es/_getValue.js","node_modules/lodash-es/_hashDelete.js","node_modules/lodash-es/_isKeyable.js","node_modules/lodash-es/_createBaseFor.js","node_modules/lodash-es/_copyArray.js","node_modules/lodash-es/_isPrototype.js","node_modules/lodash-es/isArray.js","node_modules/lodash-es/isLength.js","node_modules/lodash-es/stubFalse.js","node_modules/lodash-es/_baseUnary.js","node_modules/lodash-es/_safeGet.js","node_modules/lodash-es/_baseTimes.js","node_modules/lodash-es/_isIndex.js","node_modules/lodash-es/_nativeKeysIn.js","node_modules/lodash-es/identity.js","node_modules/lodash-es/_apply.js","node_modules/lodash-es/constant.js","node_modules/lodash-es/_shortOut.js","node_modules/jsonql-utils/src/chain-promises.js","src/core/create-nsp/login-event-handler.js","node_modules/jsonql-utils/src/generic.js","node_modules/jsonql-errors/src/validation-error.js","node_modules/jsonql-utils/src/timestamp.js","node_modules/jsonql-utils/src/params-api.js","node_modules/jsonql-utils/src/socket.js","src/core/create-nsp/bind-socket-event-handler.js","src/core/create-nsp/create-nsp.js","src/core/create-nsp/index.js","src/core/create-websocket-binding/bind-framework-to-jsonql.js","src/node/node-framework-socket-engine.js","src/node-ws-client.js"],"sourcesContent":["/**\n * Checks if `value` is classified as an `Array` object.\n *\n * @static\n * @memberOf _\n * @since 0.1.0\n * @category Lang\n * @param {*} value The value to check.\n * @returns {boolean} Returns `true` if `value` is an array, else `false`.\n * @example\n *\n * _.isArray([1, 2, 3]);\n * // => true\n *\n * _.isArray(document.body.children);\n * // => false\n *\n * _.isArray('abc');\n * // => false\n *\n * _.isArray(_.noop);\n * // => false\n */\nvar isArray = Array.isArray;\n\nexport default isArray;\n","export default (typeof global !== \"undefined\" ? global :\n typeof self !== \"undefined\" ? self :\n typeof window !== \"undefined\" ? window : {});\n","/** Used for built-in method references. */\nvar objectProto = Object.prototype;\n\n/**\n * Used to resolve the\n * [`toStringTag`](http://ecma-international.org/ecma-262/7.0/#sec-object.prototype.tostring)\n * of values.\n */\nvar nativeObjectToString = objectProto.toString;\n\n/**\n * Converts `value` to a string using `Object.prototype.toString`.\n *\n * @private\n * @param {*} value The value to convert.\n * @returns {string} Returns the converted string.\n */\nfunction objectToString(value) {\n return nativeObjectToString.call(value);\n}\n\nexport default objectToString;\n","/**\n * Creates a unary function that invokes `func` with its argument transformed.\n *\n * @private\n * @param {Function} func The function to wrap.\n * @param {Function} transform The argument transform.\n * @returns {Function} Returns the new function.\n */\nfunction overArg(func, transform) {\n return function(arg) {\n return func(transform(arg));\n };\n}\n\nexport default overArg;\n","/**\n * Checks if `value` is object-like. A value is object-like if it's not `null`\n * and has a `typeof` result of \"object\".\n *\n * @static\n * @memberOf _\n * @since 4.0.0\n * @category Lang\n * @param {*} value The value to check.\n * @returns {boolean} Returns `true` if `value` is object-like, else `false`.\n * @example\n *\n * _.isObjectLike({});\n * // => true\n *\n * _.isObjectLike([1, 2, 3]);\n * // => true\n *\n * _.isObjectLike(_.noop);\n * // => false\n *\n * _.isObjectLike(null);\n * // => false\n */\nfunction isObjectLike(value) {\n return value != null && typeof value == 'object';\n}\n\nexport default isObjectLike;\n","/**\n * A specialized version of `_.map` for arrays without support for iteratee\n * shorthands.\n *\n * @private\n * @param {Array} [array] The array to iterate over.\n * @param {Function} iteratee The function invoked per iteration.\n * @returns {Array} Returns the new mapped array.\n */\nfunction arrayMap(array, iteratee) {\n var index = -1,\n length = array == null ? 0 : array.length,\n result = Array(length);\n\n while (++index < length) {\n result[index] = iteratee(array[index], index, array);\n }\n return result;\n}\n\nexport default arrayMap;\n","/**\n * The base implementation of `_.slice` without an iteratee call guard.\n *\n * @private\n * @param {Array} array The array to slice.\n * @param {number} [start=0] The start position.\n * @param {number} [end=array.length] The end position.\n * @returns {Array} Returns the slice of `array`.\n */\nfunction baseSlice(array, start, end) {\n var index = -1,\n length = array.length;\n\n if (start < 0) {\n start = -start > length ? 0 : (length + start);\n }\n end = end > length ? length : end;\n if (end < 0) {\n end += length;\n }\n length = start > end ? 0 : ((end - start) >>> 0);\n start >>>= 0;\n\n var result = Array(length);\n while (++index < length) {\n result[index] = array[index + start];\n }\n return result;\n}\n\nexport default baseSlice;\n","/**\n * The base implementation of `_.findIndex` and `_.findLastIndex` without\n * support for iteratee shorthands.\n *\n * @private\n * @param {Array} array The array to inspect.\n * @param {Function} predicate The function invoked per iteration.\n * @param {number} fromIndex The index to search from.\n * @param {boolean} [fromRight] Specify iterating from right to left.\n * @returns {number} Returns the index of the matched value, else `-1`.\n */\nfunction baseFindIndex(array, predicate, fromIndex, fromRight) {\n var length = array.length,\n index = fromIndex + (fromRight ? 1 : -1);\n\n while ((fromRight ? index-- : ++index < length)) {\n if (predicate(array[index], index, array)) {\n return index;\n }\n }\n return -1;\n}\n\nexport default baseFindIndex;\n","/**\n * The base implementation of `_.isNaN` without support for number objects.\n *\n * @private\n * @param {*} value The value to check.\n * @returns {boolean} Returns `true` if `value` is `NaN`, else `false`.\n */\nfunction baseIsNaN(value) {\n return value !== value;\n}\n\nexport default baseIsNaN;\n","/**\n * A specialized version of `_.indexOf` which performs strict equality\n * comparisons of values, i.e. `===`.\n *\n * @private\n * @param {Array} array The array to inspect.\n * @param {*} value The value to search for.\n * @param {number} fromIndex The index to search from.\n * @returns {number} Returns the index of the matched value, else `-1`.\n */\nfunction strictIndexOf(array, value, fromIndex) {\n var index = fromIndex - 1,\n length = array.length;\n\n while (++index < length) {\n if (array[index] === value) {\n return index;\n }\n }\n return -1;\n}\n\nexport default strictIndexOf;\n","/**\n * Converts an ASCII `string` to an array.\n *\n * @private\n * @param {string} string The string to convert.\n * @returns {Array} Returns the converted array.\n */\nfunction asciiToArray(string) {\n return string.split('');\n}\n\nexport default asciiToArray;\n","/** Used to compose unicode character classes. */\nvar rsAstralRange = '\\\\ud800-\\\\udfff',\n rsComboMarksRange = '\\\\u0300-\\\\u036f',\n reComboHalfMarksRange = '\\\\ufe20-\\\\ufe2f',\n rsComboSymbolsRange = '\\\\u20d0-\\\\u20ff',\n rsComboRange = rsComboMarksRange + reComboHalfMarksRange + rsComboSymbolsRange,\n rsVarRange = '\\\\ufe0e\\\\ufe0f';\n\n/** Used to compose unicode capture groups. */\nvar rsZWJ = '\\\\u200d';\n\n/** Used to detect strings with [zero-width joiners or code points from the astral planes](http://eev.ee/blog/2015/09/12/dark-corners-of-unicode/). */\nvar reHasUnicode = RegExp('[' + rsZWJ + rsAstralRange + rsComboRange + rsVarRange + ']');\n\n/**\n * Checks if `string` contains Unicode symbols.\n *\n * @private\n * @param {string} string The string to inspect.\n * @returns {boolean} Returns `true` if a symbol is found, else `false`.\n */\nfunction hasUnicode(string) {\n return reHasUnicode.test(string);\n}\n\nexport default hasUnicode;\n","/** Used to compose unicode character classes. */\nvar rsAstralRange = '\\\\ud800-\\\\udfff',\n rsComboMarksRange = '\\\\u0300-\\\\u036f',\n reComboHalfMarksRange = '\\\\ufe20-\\\\ufe2f',\n rsComboSymbolsRange = '\\\\u20d0-\\\\u20ff',\n rsComboRange = rsComboMarksRange + reComboHalfMarksRange + rsComboSymbolsRange,\n rsVarRange = '\\\\ufe0e\\\\ufe0f';\n\n/** Used to compose unicode capture groups. */\nvar rsAstral = '[' + rsAstralRange + ']',\n rsCombo = '[' + rsComboRange + ']',\n rsFitz = '\\\\ud83c[\\\\udffb-\\\\udfff]',\n rsModifier = '(?:' + rsCombo + '|' + rsFitz + ')',\n rsNonAstral = '[^' + rsAstralRange + ']',\n rsRegional = '(?:\\\\ud83c[\\\\udde6-\\\\uddff]){2}',\n rsSurrPair = '[\\\\ud800-\\\\udbff][\\\\udc00-\\\\udfff]',\n rsZWJ = '\\\\u200d';\n\n/** Used to compose unicode regexes. */\nvar reOptMod = rsModifier + '?',\n rsOptVar = '[' + rsVarRange + ']?',\n rsOptJoin = '(?:' + rsZWJ + '(?:' + [rsNonAstral, rsRegional, rsSurrPair].join('|') + ')' + rsOptVar + reOptMod + ')*',\n rsSeq = rsOptVar + reOptMod + rsOptJoin,\n rsSymbol = '(?:' + [rsNonAstral + rsCombo + '?', rsCombo, rsRegional, rsSurrPair, rsAstral].join('|') + ')';\n\n/** Used to match [string symbols](https://mathiasbynens.be/notes/javascript-unicode). */\nvar reUnicode = RegExp(rsFitz + '(?=' + rsFitz + ')|' + rsSymbol + rsSeq, 'g');\n\n/**\n * Converts a Unicode `string` to an array.\n *\n * @private\n * @param {string} string The string to convert.\n * @returns {Array} Returns the converted array.\n */\nfunction unicodeToArray(string) {\n return string.match(reUnicode) || [];\n}\n\nexport default unicodeToArray;\n","// bunch of generic helpers\n\nimport isArray from 'lodash-es/isArray'\nimport isPlainObject from 'lodash-es/isPlainObject'\nimport trim from 'lodash-es/trim'\n\n/**\n * DIY in Array\n * @param {array} arr to check from\n * @param {*} value to check against\n * @return {boolean} true on found\n */\nexport const inArray = (arr, value) => !!arr.filter(a => a === value).length\n\n// quick and dirty to turn non array to array\nexport const toArray = (arg) => isArray(arg) ? arg : [arg]\n\n/**\n * parse string to json or just return the original value if error happened\n * @param {*} n input\n * @param {boolean} [t=true] or throw\n * @return {*} json object on success\n */\nexport const parseJson = function(n, t=true) {\n try {\n return JSON.parse(n)\n } catch(e) {\n if (t) {\n return n\n }\n throw new Error(e)\n }\n}\n\n/**\n * @param {object} obj for search\n * @param {string} key target\n * @return {boolean} true on success\n */\nexport const isObjectHasKey = function(obj, key) {\n try {\n const keys = Object.keys(obj)\n return inArray(keys, key)\n } catch(e) {\n // @BUG when the obj is not an OBJECT we got some weird output\n return false\n }\n}\n\n/**\n * create a event name\n * @param {string[]} args\n * @return {string} event name for use\n */\nexport const createEvt = (...args) => args.join('_')\n\n/**\n * simple util method to get the value\n * @param {string} name of the key\n * @param {object} obj to take value from\n * @return {*} the object value id by name or undefined\n */\nexport const getConfigValue = (name, obj) => (\n obj && isPlainObject(obj) ? ( (name in obj) ? obj[name] : undefined ) : undefined\n)\n\n/**\n * small util to make sure the return value is valid JSON object\n * @param {*} n input\n * @return {object} correct JSON object\n */\nexport const toJson = n => {\n if (typeof n === 'string') {\n return parseJson(n)\n }\n return parseJson(JSON.stringify(n))\n}\n\n/**\n * Check several parameter that there is something in the param\n * @param {*} param input\n * @return {boolean}\n */\nexport const isNotEmpty = function(param) {\n return param !== undefined && param !== false && param !== null && trim(param) !== ''\n}\n\n/**\n * Simple check if the prop is function\n * @param {*} prop input\n * @return {boolean} true on success\n */\nexport const isFunc = prop => {\n if (typeof prop === 'function') {\n return true;\n }\n console.error(`Expect to be Function type! Got ${typeof prop}`)\n}\n\n/**\n * Shorthand method for Object.assign \n * @param {array} args \n * @return {object} merge together object by key \n */\nexport const assign = (...args) => Reflect.apply(Object.assign, Object, args)\n \n/** \n * generic placeholder function\n * @return {boolean} false \n */\nexport const nil = () => false\n\n/**\n * generic turn config into immutatble \n */\nexport const freeze = config => Object.freeze(config)","/**\n * Removes all key-value entries from the list cache.\n *\n * @private\n * @name clear\n * @memberOf ListCache\n */\nfunction listCacheClear() {\n this.__data__ = [];\n this.size = 0;\n}\n\nexport default listCacheClear;\n","/**\n * Performs a\n * [`SameValueZero`](http://ecma-international.org/ecma-262/7.0/#sec-samevaluezero)\n * comparison between two values to determine if they are equivalent.\n *\n * @static\n * @memberOf _\n * @since 4.0.0\n * @category Lang\n * @param {*} value The value to compare.\n * @param {*} other The other value to compare.\n * @returns {boolean} Returns `true` if the values are equivalent, else `false`.\n * @example\n *\n * var object = { 'a': 1 };\n * var other = { 'a': 1 };\n *\n * _.eq(object, object);\n * // => true\n *\n * _.eq(object, other);\n * // => false\n *\n * _.eq('a', 'a');\n * // => true\n *\n * _.eq('a', Object('a'));\n * // => false\n *\n * _.eq(NaN, NaN);\n * // => true\n */\nfunction eq(value, other) {\n return value === other || (value !== value && other !== other);\n}\n\nexport default eq;\n","/**\n * Removes `key` and its value from the stack.\n *\n * @private\n * @name delete\n * @memberOf Stack\n * @param {string} key The key of the value to remove.\n * @returns {boolean} Returns `true` if the entry was removed, else `false`.\n */\nfunction stackDelete(key) {\n var data = this.__data__,\n result = data['delete'](key);\n\n this.size = data.size;\n return result;\n}\n\nexport default stackDelete;\n","/**\n * Gets the stack value for `key`.\n *\n * @private\n * @name get\n * @memberOf Stack\n * @param {string} key The key of the value to get.\n * @returns {*} Returns the entry value.\n */\nfunction stackGet(key) {\n return this.__data__.get(key);\n}\n\nexport default stackGet;\n","/**\n * Checks if a stack value for `key` exists.\n *\n * @private\n * @name has\n * @memberOf Stack\n * @param {string} key The key of the entry to check.\n * @returns {boolean} Returns `true` if an entry for `key` exists, else `false`.\n */\nfunction stackHas(key) {\n return this.__data__.has(key);\n}\n\nexport default stackHas;\n","/**\n * Checks if `value` is the\n * [language type](http://www.ecma-international.org/ecma-262/7.0/#sec-ecmascript-language-types)\n * of `Object`. (e.g. arrays, functions, objects, regexes, `new Number(0)`, and `new String('')`)\n *\n * @static\n * @memberOf _\n * @since 0.1.0\n * @category Lang\n * @param {*} value The value to check.\n * @returns {boolean} Returns `true` if `value` is an object, else `false`.\n * @example\n *\n * _.isObject({});\n * // => true\n *\n * _.isObject([1, 2, 3]);\n * // => true\n *\n * _.isObject(_.noop);\n * // => true\n *\n * _.isObject(null);\n * // => false\n */\nfunction isObject(value) {\n var type = typeof value;\n return value != null && (type == 'object' || type == 'function');\n}\n\nexport default isObject;\n","/** Used for built-in method references. */\nvar funcProto = Function.prototype;\n\n/** Used to resolve the decompiled source of functions. */\nvar funcToString = funcProto.toString;\n\n/**\n * Converts `func` to its source code.\n *\n * @private\n * @param {Function} func The function to convert.\n * @returns {string} Returns the source code.\n */\nfunction toSource(func) {\n if (func != null) {\n try {\n return funcToString.call(func);\n } catch (e) {}\n try {\n return (func + '');\n } catch (e) {}\n }\n return '';\n}\n\nexport default toSource;\n","/**\n * Gets the value at `key` of `object`.\n *\n * @private\n * @param {Object} [object] The object to query.\n * @param {string} key The key of the property to get.\n * @returns {*} Returns the property value.\n */\nfunction getValue(object, key) {\n return object == null ? undefined : object[key];\n}\n\nexport default getValue;\n","/**\n * Removes `key` and its value from the hash.\n *\n * @private\n * @name delete\n * @memberOf Hash\n * @param {Object} hash The hash to modify.\n * @param {string} key The key of the value to remove.\n * @returns {boolean} Returns `true` if the entry was removed, else `false`.\n */\nfunction hashDelete(key) {\n var result = this.has(key) && delete this.__data__[key];\n this.size -= result ? 1 : 0;\n return result;\n}\n\nexport default hashDelete;\n","/**\n * Checks if `value` is suitable for use as unique object key.\n *\n * @private\n * @param {*} value The value to check.\n * @returns {boolean} Returns `true` if `value` is suitable, else `false`.\n */\nfunction isKeyable(value) {\n var type = typeof value;\n return (type == 'string' || type == 'number' || type == 'symbol' || type == 'boolean')\n ? (value !== '__proto__')\n : (value === null);\n}\n\nexport default isKeyable;\n","/**\n * Creates a base function for methods like `_.forIn` and `_.forOwn`.\n *\n * @private\n * @param {boolean} [fromRight] Specify iterating from right to left.\n * @returns {Function} Returns the new base function.\n */\nfunction createBaseFor(fromRight) {\n return function(object, iteratee, keysFunc) {\n var index = -1,\n iterable = Object(object),\n props = keysFunc(object),\n length = props.length;\n\n while (length--) {\n var key = props[fromRight ? length : ++index];\n if (iteratee(iterable[key], key, iterable) === false) {\n break;\n }\n }\n return object;\n };\n}\n\nexport default createBaseFor;\n","/**\n * Copies the values of `source` to `array`.\n *\n * @private\n * @param {Array} source The array to copy values from.\n * @param {Array} [array=[]] The array to copy values to.\n * @returns {Array} Returns `array`.\n */\nfunction copyArray(source, array) {\n var index = -1,\n length = source.length;\n\n array || (array = Array(length));\n while (++index < length) {\n array[index] = source[index];\n }\n return array;\n}\n\nexport default copyArray;\n","/** Used for built-in method references. */\nvar objectProto = Object.prototype;\n\n/**\n * Checks if `value` is likely a prototype object.\n *\n * @private\n * @param {*} value The value to check.\n * @returns {boolean} Returns `true` if `value` is a prototype, else `false`.\n */\nfunction isPrototype(value) {\n var Ctor = value && value.constructor,\n proto = (typeof Ctor == 'function' && Ctor.prototype) || objectProto;\n\n return value === proto;\n}\n\nexport default isPrototype;\n","/** Used as references for various `Number` constants. */\nvar MAX_SAFE_INTEGER = 9007199254740991;\n\n/**\n * Checks if `value` is a valid array-like length.\n *\n * **Note:** This method is loosely based on\n * [`ToLength`](http://ecma-international.org/ecma-262/7.0/#sec-tolength).\n *\n * @static\n * @memberOf _\n * @since 4.0.0\n * @category Lang\n * @param {*} value The value to check.\n * @returns {boolean} Returns `true` if `value` is a valid length, else `false`.\n * @example\n *\n * _.isLength(3);\n * // => true\n *\n * _.isLength(Number.MIN_VALUE);\n * // => false\n *\n * _.isLength(Infinity);\n * // => false\n *\n * _.isLength('3');\n * // => false\n */\nfunction isLength(value) {\n return typeof value == 'number' &&\n value > -1 && value % 1 == 0 && value <= MAX_SAFE_INTEGER;\n}\n\nexport default isLength;\n","/**\n * This method returns `false`.\n *\n * @static\n * @memberOf _\n * @since 4.13.0\n * @category Util\n * @returns {boolean} Returns `false`.\n * @example\n *\n * _.times(2, _.stubFalse);\n * // => [false, false]\n */\nfunction stubFalse() {\n return false;\n}\n\nexport default stubFalse;\n","/**\n * The base implementation of `_.unary` without support for storing metadata.\n *\n * @private\n * @param {Function} func The function to cap arguments for.\n * @returns {Function} Returns the new capped function.\n */\nfunction baseUnary(func) {\n return function(value) {\n return func(value);\n };\n}\n\nexport default baseUnary;\n","/**\n * Gets the value at `key`, unless `key` is \"__proto__\" or \"constructor\".\n *\n * @private\n * @param {Object} object The object to query.\n * @param {string} key The key of the property to get.\n * @returns {*} Returns the property value.\n */\nfunction safeGet(object, key) {\n if (key === 'constructor' && typeof object[key] === 'function') {\n return;\n }\n\n if (key == '__proto__') {\n return;\n }\n\n return object[key];\n}\n\nexport default safeGet;\n","/**\n * The base implementation of `_.times` without support for iteratee shorthands\n * or max array length checks.\n *\n * @private\n * @param {number} n The number of times to invoke `iteratee`.\n * @param {Function} iteratee The function invoked per iteration.\n * @returns {Array} Returns the array of results.\n */\nfunction baseTimes(n, iteratee) {\n var index = -1,\n result = Array(n);\n\n while (++index < n) {\n result[index] = iteratee(index);\n }\n return result;\n}\n\nexport default baseTimes;\n","/** Used as references for various `Number` constants. */\nvar MAX_SAFE_INTEGER = 9007199254740991;\n\n/** Used to detect unsigned integer values. */\nvar reIsUint = /^(?:0|[1-9]\\d*)$/;\n\n/**\n * Checks if `value` is a valid array-like index.\n *\n * @private\n * @param {*} value The value to check.\n * @param {number} [length=MAX_SAFE_INTEGER] The upper bounds of a valid index.\n * @returns {boolean} Returns `true` if `value` is a valid index, else `false`.\n */\nfunction isIndex(value, length) {\n var type = typeof value;\n length = length == null ? MAX_SAFE_INTEGER : length;\n\n return !!length &&\n (type == 'number' ||\n (type != 'symbol' && reIsUint.test(value))) &&\n (value > -1 && value % 1 == 0 && value < length);\n}\n\nexport default isIndex;\n","/**\n * This function is like\n * [`Object.keys`](http://ecma-international.org/ecma-262/7.0/#sec-object.keys)\n * except that it includes inherited enumerable properties.\n *\n * @private\n * @param {Object} object The object to query.\n * @returns {Array} Returns the array of property names.\n */\nfunction nativeKeysIn(object) {\n var result = [];\n if (object != null) {\n for (var key in Object(object)) {\n result.push(key);\n }\n }\n return result;\n}\n\nexport default nativeKeysIn;\n","/**\n * This method returns the first argument it receives.\n *\n * @static\n * @since 0.1.0\n * @memberOf _\n * @category Util\n * @param {*} value Any value.\n * @returns {*} Returns `value`.\n * @example\n *\n * var object = { 'a': 1 };\n *\n * console.log(_.identity(object) === object);\n * // => true\n */\nfunction identity(value) {\n return value;\n}\n\nexport default identity;\n","/**\n * A faster alternative to `Function#apply`, this function invokes `func`\n * with the `this` binding of `thisArg` and the arguments of `args`.\n *\n * @private\n * @param {Function} func The function to invoke.\n * @param {*} thisArg The `this` binding of `func`.\n * @param {Array} args The arguments to invoke `func` with.\n * @returns {*} Returns the result of `func`.\n */\nfunction apply(func, thisArg, args) {\n switch (args.length) {\n case 0: return func.call(thisArg);\n case 1: return func.call(thisArg, args[0]);\n case 2: return func.call(thisArg, args[0], args[1]);\n case 3: return func.call(thisArg, args[0], args[1], args[2]);\n }\n return func.apply(thisArg, args);\n}\n\nexport default apply;\n","/**\n * Creates a function that returns `value`.\n *\n * @static\n * @memberOf _\n * @since 2.4.0\n * @category Util\n * @param {*} value The value to return from the new function.\n * @returns {Function} Returns the new constant function.\n * @example\n *\n * var objects = _.times(2, _.constant({ 'a': 1 }));\n *\n * console.log(objects);\n * // => [{ 'a': 1 }, { 'a': 1 }]\n *\n * console.log(objects[0] === objects[1]);\n * // => true\n */\nfunction constant(value) {\n return function() {\n return value;\n };\n}\n\nexport default constant;\n","/** Used to detect hot functions by number of calls within a span of milliseconds. */\nvar HOT_COUNT = 800,\n HOT_SPAN = 16;\n\n/* Built-in method references for those with the same name as other `lodash` methods. */\nvar nativeNow = Date.now;\n\n/**\n * Creates a function that'll short out and invoke `identity` instead\n * of `func` when it's called `HOT_COUNT` or more times in `HOT_SPAN`\n * milliseconds.\n *\n * @private\n * @param {Function} func The function to restrict.\n * @returns {Function} Returns the new shortable function.\n */\nfunction shortOut(func) {\n var count = 0,\n lastCalled = 0;\n\n return function() {\n var stamp = nativeNow(),\n remaining = HOT_SPAN - (stamp - lastCalled);\n\n lastCalled = stamp;\n if (remaining > 0) {\n if (++count >= HOT_COUNT) {\n return arguments[0];\n }\n } else {\n count = 0;\n }\n return func.apply(undefined, arguments);\n };\n}\n\nexport default shortOut;\n","// this get throw from within the checkOptions when run through the enum failed\nexport default class JsonqlEnumError extends Error {\n constructor(...args) {\n super(...args)\n\n this.message = args[0]\n this.detail = args[1]\n\n this.className = JsonqlEnumError.name;\n\n if (Error.captureStackTrace) {\n Error.captureStackTrace(this, JsonqlEnumError)\n }\n }\n\n static get name() {\n return 'JsonqlEnumError'\n }\n}\n","// this will throw from inside the checkOptions\nexport default class JsonqlTypeError extends Error {\n constructor(...args) {\n super(...args)\n\n this.message = args[0]\n this.detail = args[1]\n\n this.className = JsonqlTypeError.name\n\n if (Error.captureStackTrace) {\n Error.captureStackTrace(this, JsonqlTypeError)\n }\n }\n\n static get name() {\n return 'JsonqlTypeError'\n }\n}\n","// allow supply a custom checker function\n// if that failed then we throw this error\nexport default class JsonqlCheckerError extends Error {\n constructor(...args) {\n super(...args)\n this.message = args[0]\n this.detail = args[1]\n\n this.className = JsonqlCheckerError.name;\n\n if (Error.captureStackTrace) {\n Error.captureStackTrace(this, JsonqlCheckerError)\n }\n }\n\n static get name() {\n return 'JsonqlCheckerError'\n }\n}\n","// custom validation error class\n// when validaton failed\nexport default class JsonqlValidationError extends Error {\n constructor(...args) {\n super(...args)\n\n this.message = args[0]\n this.detail = args[1]\n\n this.className = JsonqlValidationError.name;\n\n if (Error.captureStackTrace) {\n Error.captureStackTrace(this, JsonqlValidationError)\n }\n }\n\n static get name() {\n return 'JsonqlValidationError'\n }\n}\n","// split the contract into the node side and the generic side\nimport { isObjectHasKey } from './generic'\nimport isPlainObject from 'lodash-es/isPlainObject'\nimport {\n QUERY_NAME,\n MUTATION_NAME,\n SOCKET_NAME,\n QUERY_ARG_NAME,\n PAYLOAD_PARAM_NAME,\n CONDITION_PARAM_NAME\n} from 'jsonql-constants'\nimport { JsonqlError, JsonqlResolverNotFoundError } from 'jsonql-errors'\n/**\n * Check if the json is a contract file or not\n * @param {object} contract json object\n * @return {boolean} true\n */\nexport function checkIsContract(contract) {\n return isPlainObject(contract)\n && (\n isObjectHasKey(contract, QUERY_NAME)\n || isObjectHasKey(contract, MUTATION_NAME)\n || isObjectHasKey(contract, SOCKET_NAME)\n )\n}\n\n/**\n * Wrapper method that check if it's contract then return the contract or false\n * @param {object} contract the object to check\n * @return {boolean | object} false when it's not\n */\nexport function isContract(contract) {\n return checkIsContract(contract) ? contract : false\n}\n\n/**\n * Ported from jsonql-params-validator but different\n * if we don't find the socket part then return false\n * @param {object} contract the contract object\n * @return {object|boolean} false on failed\n */\nexport function extractSocketPart(contract) {\n if (isObjectHasKey(contract, SOCKET_NAME)) {\n return contract[SOCKET_NAME]\n }\n return false\n}\n\n/**\n * Extract the args from the payload\n * @param {object} payload to work with\n * @param {string} type of call\n * @return {array} args\n */\nexport function extractArgsFromPayload(payload, type) {\n switch (type) {\n case QUERY_NAME:\n return payload[QUERY_ARG_NAME]\n case MUTATION_NAME:\n return [\n payload[PAYLOAD_PARAM_NAME],\n payload[CONDITION_PARAM_NAME]\n ]\n default:\n throw new JsonqlError(`Unknown ${type} to extract argument from!`)\n }\n}\n\n/**\n * Like what the name said\n * @param {object} contract the contract json\n * @param {string} type query|mutation\n * @param {string} name of the function\n * @return {object} the params part of the contract\n */\nexport function extractParamsFromContract(contract, type, name) {\n try {\n const result = contract[type][name]\n // debug('extractParamsFromContract', result)\n if (!result) {\n // debug(name, type, contract)\n throw new JsonqlResolverNotFoundError(name, type)\n }\n return result\n } catch(e) {\n throw new JsonqlResolverNotFoundError(name, e)\n }\n}\n","/**\n * @param {boolean} sec return in second or not\n * @return {number} timestamp\n */\nexport const timestamp = (sec = false) => {\n let time = Date.now()\n return sec ? Math.floor( time / 1000 ) : time\n}\n","// ported from jsonql-params-validator\n// craete several helper function to construct / extract the payload\n// and make sure they are all the same\nimport {\n PAYLOAD_PARAM_NAME,\n CONDITION_PARAM_NAME,\n RESOLVER_PARAM_NAME,\n QUERY_ARG_NAME,\n TIMESTAMP_PARAM_NAME\n} from 'jsonql-constants'\n\nimport JsonqlValidationError from 'jsonql-errors/src/validation-error'\n\nimport isArray from 'lodash-es/isArray'\nimport isString from 'lodash-es/isString'\nimport isPlainObject from 'lodash-es/isPlainObject'\n\nimport { timestamp } from './timestamp'\nimport { parseJson } from './generic'\n\n/**\n * check if the payload has a timestamp field, then append a new timestamp to it\n * @param {object} payload from the com\n * @return {array} timestamp field with an array value\n */\nexport const handleTimestamp = payload => {\n let ts = payload[TIMESTAMP_PARAM_NAME]\n if (!isArray(ts)) {\n ts = [ts]\n }\n ts.push( timestamp() )\n\n return ts\n}\n\n/**\n * make sure it's an object (it was call formatPayload but it doesn't make sense)\n * @param {*} payload the object comes in could be string based\n * @return {object} the transformed payload\n */\nexport const toPayload = payload => isString(payload) ? parseJson(payload) : payload\n\n/**\n * @param {*} args arguments to send\n *@return {object} formatted payload\n */\nexport const formatPayload = (args) => (\n { [QUERY_ARG_NAME]: args }\n)\n\n/**\n * extract the resolver name from the payload \n * @param {object} payload\n * @return {string} resolver name \n */\nexport function getResolverFromPayload(payload) {\n const keys = Object.keys(payload)\n return keys.filter(key => key !== TIMESTAMP_PARAM_NAME)[0]\n}\n\n/**\n * wrapper method to add the timestamp as well\n * @param {string} resolverName\n * @param {*} payload\n * @return {object} delierable\n */\nexport function createDeliverable(resolverName, payload) {\n return {\n [resolverName]: payload,\n [TIMESTAMP_PARAM_NAME]: [ timestamp() ]\n }\n}\n\n/**\n * @param {string} resolverName name of function\n * @param {array} [args=[]] from the ...args\n * @param {boolean} [jsonp = false] add v1.3.0 to koa\n * @return {object} formatted argument\n */\nexport function createQuery(resolverName, args = [], jsonp = false) {\n if (isString(resolverName) && isArray(args)) {\n let payload = formatPayload(args)\n if (jsonp === true) {\n return payload\n }\n return createDeliverable(resolverName, payload)\n }\n throw new JsonqlValidationError(`[createQuery] expect resolverName to be string and args to be array!`, { resolverName, args })\n}\n\n/**\n * string version of the createQuery\n * @return {string}\n */\nexport function createQueryStr(resolverName, args = [], jsonp = false) {\n return JSON.stringify(createQuery(resolverName, args, jsonp))\n}\n\n/**\n * @param {string} resolverName name of function\n * @param {*} payload to send\n * @param {object} [condition={}] for what\n * @param {boolean} [jsonp = false] add v1.3.0 to koa\n * @return {object} formatted argument\n */\nexport function createMutation(resolverName, payload, condition = {}, jsonp = false) {\n const _payload = {\n [PAYLOAD_PARAM_NAME]: payload,\n [CONDITION_PARAM_NAME]: condition\n }\n if (jsonp === true) {\n return _payload\n }\n if (isString(resolverName)) {\n return createDeliverable(resolverName, _payload)\n }\n throw new JsonqlValidationError(`[createMutation] expect resolverName to be string!`, { resolverName, payload, condition })\n}\n\n/**\n * string version of createMutation\n * @return {string}\n */\nexport function createMutationStr(resolverName, payload, condition = {}, jsonp = false) {\n return JSON.stringify(createMutation(resolverName, payload, condition, jsonp))\n}\n\n/**\n * Extract the parts from payload and format for use\n * @param {string} resolverName name of fn\n * @param {object} payload the incoming json\n * @return {object|boolean} false on failed\n */\nexport function getQueryFromArgs(resolverName, payload) {\n if (resolverName && isPlainObject(payload)) {\n const args = payload[resolverName]\n if (args[QUERY_ARG_NAME]) {\n return {\n [RESOLVER_PARAM_NAME]: resolverName,\n [QUERY_ARG_NAME]: args[QUERY_ARG_NAME],\n [TIMESTAMP_PARAM_NAME]: handleTimestamp(payload)\n }\n }\n }\n return false\n}\n\n/**\n * Share function so no repeat\n * @param {object} payload the payload from client\n * @param {function} processor the last get result method\n * @return {*} result processed result\n */\nfunction processPayload(payload, processor) {\n const p = toPayload(payload)\n const resolverName = getResolverFromPayload(p)\n return Reflect.apply(processor, null, [resolverName, p])\n}\n\n/**\n * extra the payload back\n * @param {*} payload from http call\n * @return {object} resolverName and args\n */\nexport function getQueryFromPayload(payload) {\n const result = processPayload(payload, getQueryFromArgs)\n if (result !== false) {\n return result\n }\n throw new JsonqlValidationError('[getQueryArgs] Payload is malformed!', payload)\n}\n\n/**\n * Further break down from method below for use else where\n * @param {string} resolverName name of fn\n * @param {object} payload payload\n * @return {object|boolean} false on failed\n */\nexport function getMutationFromArgs(resolverName, payload) {\n if (resolverName && isPlainObject(payload)) {\n const args = payload[resolverName]\n if (args) {\n return {\n [RESOLVER_PARAM_NAME]: resolverName,\n [PAYLOAD_PARAM_NAME]: args[PAYLOAD_PARAM_NAME],\n [CONDITION_PARAM_NAME]: args[CONDITION_PARAM_NAME],\n [TIMESTAMP_PARAM_NAME]: handleTimestamp(payload)\n }\n }\n }\n return false\n}\n\n/**\n * @param {object} payload\n * @return {object} resolverName, payload, conditon\n */\nexport function getMutationFromPayload(payload) {\n const result = processPayload(payload, getMutationFromArgs)\n\n if (result !== false) {\n return result\n }\n throw new JsonqlValidationError('[getMutationArgs] Payload is malformed!', payload)\n}\n","// take out all the namespace related methods in one place for easy to find\nimport {\n JSONQL_PATH,\n PUBLIC_KEY,\n NSP_GROUP,\n PUBLIC_NAMESPACE\n} from 'jsonql-constants'\nimport { extractSocketPart } from './contract'\nconst SOCKET_NOT_FOUND_ERR = `socket not found in contract!`\nconst SIZE = 'size'\n\n/**\n * create the group using publicNamespace when there is only public\n * @param {object} socket from contract\n * @param {string} publicNamespace\n */\nfunction groupPublicNamespace(socket, publicNamespace) {\n let g = {}\n for (let resolverName in socket) {\n let params = socket[resolverName]\n g[resolverName] = params\n }\n return { size: 1, nspGroup: {[publicNamespace]: g}, publicNamespace}\n}\n\n\n/**\n * @BUG we should check the socket part instead of expect the downstream to read the menu!\n * We only need this when the enableAuth is true otherwise there is only one namespace\n * @param {object} contract the socket part of the contract file\n * @return {object} 1. remap the contract using the namespace --> resolvers\n * 2. the size of the object (1 all private, 2 mixed public with private)\n * 3. which namespace is public\n */\nexport function groupByNamespace(contract) {\n let socket = extractSocketPart(contract)\n if (socket === false) {\n throw new JsonqlError('groupByNamespace', SOCKET_NOT_FOUND_ERR)\n }\n let prop = {\n [NSP_GROUP]: {},\n [PUBLIC_NAMESPACE]: null,\n [SIZE]: 0 \n }\n\n for (let resolverName in socket) {\n let params = socket[resolverName]\n let { namespace } = params\n if (namespace) {\n if (!prop[NSP_GROUP][namespace]) {\n ++prop[SIZE]\n prop[NSP_GROUP][namespace] = {}\n }\n prop[NSP_GROUP][namespace][resolverName] = params\n // get the public namespace\n if (!prop[PUBLIC_NAMESPACE] && params[PUBLIC_KEY]) {\n prop[PUBLIC_NAMESPACE] = namespace\n }\n }\n }\n \n return prop \n}\n\n/**\n * @NOTE ported from jsonql-ws-client\n * Got to make sure the connection order otherwise\n * it will hang\n * @param {object} nspGroup contract\n * @param {string} publicNamespace like the name said\n * @return {array} namespaces in order\n */\nexport function getNamespaceInOrder(nspGroup, publicNamespace) {\n let names = [] // need to make sure the order!\n for (let namespace in nspGroup) {\n if (namespace === publicNamespace) {\n names[1] = namespace\n } else {\n names[0] = namespace\n }\n }\n return names\n}\n\n/**\n * @TODO this might change, what if we want to do room with ws\n * 1. there will only be max two namespace\n * 2. when it's normal we will have the stock path as namespace\n * 3. when enableAuth then we will have two, one is jsonql/public + private\n * @param {object} config options\n * @return {array} of namespace(s)\n */\nexport function getNamespace(config) {\n const base = JSONQL_PATH\n if (config.enableAuth) {\n // the public come first @1.0.1 we use the constants instead of the user supplied value\n // @1.0.4 we use the config value again, because we could control this via the post init\n return [\n [ base , config.privateNamespace ].join('/'),\n [ base , config.publicNamespace ].join('/')\n ]\n }\n return [ base ]\n}\n\n/**\n * get the private namespace\n * @param {array} namespaces array\n * @return {*} string on success\n */\nexport function getPrivateNamespace(namespaces) {\n return namespaces.length > 1 ? namespaces[0] : false\n}\n\n/**\n * Got a problem with a contract that is public only the groupByNamespace is wrong\n * which is actually not a problem when using a fallback, but to be sure things in order\n * we could combine with the config to group it\n * @param {object} config configuration\n * @return {object} nspInfo object\n */\nexport function getNspInfoByConfig(config) {\n const { contract, enableAuth } = config\n const namespaces = getNamespace(config)\n let nspInfo = enableAuth ? groupByNamespace(contract)\n : groupPublicNamespace(contract.socket, namespaces[0])\n // add the namespaces into it as well\n return Object.assign(nspInfo, { namespaces })\n}\n\n","// There are the socket related methods ported back from \n// ws-server-core and ws-client-core \nimport {\n WS_REPLY_TYPE,\n WS_EVT_NAME,\n WS_DATA_NAME,\n TIMESTAMP_PARAM_NAME,\n ERROR_KEY,\n EMIT_REPLY_TYPE,\n ACKNOWLEDGE_REPLY_TYPE\n} from 'jsonql-constants'\nimport { JsonqlError } from 'jsonql-errors' \nimport isString from 'lodash-es/isString'\n\nimport { toJson, isObjectHasKey, nil } from './generic'\nimport { timestamp } from './timestamp'\n\nconst PAYLOAD_NOT_DECODED_ERR = 'payload can not decoded'\nconst WS_KEYS = [\n WS_REPLY_TYPE,\n WS_EVT_NAME,\n WS_DATA_NAME\n]\n\n/////////////////////////////////////\n// REPLY FROM SERVER //\n/////////////////////////////////////\n\n\n/**\n * The ws doesn't have a acknowledge callback like socket.io\n * so we have to DIY one for ws and other that doesn't have it\n * @param {string} type of reply\n * @param {string} resolverName which is replying\n * @param {*} data payload\n * @param {array} [ts= []] the last received ts, if any \n * @return {string} stringify json\n */\nexport const createWsReply = (type, resolverName, data, ts = []) => {\n ts.push(timestamp())\n return JSON.stringify({\n data: {\n [WS_REPLY_TYPE]: type,\n [WS_EVT_NAME]: resolverName,\n [WS_DATA_NAME]: toJson(data)\n },\n [TIMESTAMP_PARAM_NAME]: ts \n })\n}\n\n// extended function \nexport const createReplyMsg = (resolverName, data, ts = []) => (\n createWsReply(EMIT_REPLY_TYPE, resolverName, data, ts)\n)\n\nexport const createAcknowledgeMsg = (resolverName, data, ts = []) => (\n createWsReply(ACKNOWLEDGE_REPLY_TYPE, resolverName, data, ts)\n)\n\n/**\n * @param {string|object} payload should be string when reply but could be transformed\n * @return {boolean} true is OK\n */\nexport const isWsReply = payload => {\n const json = isString(payload) ? toJson(payload) : payload\n const { data } = json\n if (data) {\n let result = WS_KEYS.filter(key => isObjectHasKey(data, key))\n return (result.length === WS_KEYS.length) ? data : false\n }\n return false\n}\n\n/**\n * @param {string|object} data received data\n * @param {function} [cb=nil] this is for extracting the TS field or when it's error\n * @return {object} false on failed\n */\nexport const extractWsPayload = (payload, cb = nil) => {\n try {\n const json = toJson(payload)\n // now handle the data\n let _data\n if ((_data = isWsReply(json)) !== false) {\n // note the ts property is on its own \n cb(TIMESTAMP_PARAM_NAME, json[TIMESTAMP_PARAM_NAME])\n \n return {\n data: toJson(_data[WS_DATA_NAME]),\n resolverName: _data[WS_EVT_NAME],\n type: _data[WS_REPLY_TYPE]\n }\n }\n throw new JsonqlError(PAYLOAD_NOT_DECODED_ERR, payload)\n } catch(e) {\n return cb(ERROR_KEY, e)\n }\n}\n","// this will be part of the init client sequence\n// as soon as we create a ws client\n// we listen to the on.connect event \n// then we send a init-ping event back to the server\n// and server issue a csrf token back to use \n// we use this token to create a new client and destroy the old one\nimport {\n INTERCOM_RESOLVER_NAME, \n SOCKET_PING_EVENT_NAME,\n HEADERS_KEY,\n DATA_KEY,\n CSRF_HEADER_KEY\n} from 'jsonql-constants'\nimport { \n createQueryStr, \n extractWsPayload,\n timestamp,\n toJson \n} from 'jsonql-utils/module'\nimport {\n JsonqlError\n} from 'jsonql-errors'\nconst CSRF_HEADER_NOT_EXIST_ERR = 'CSRF header is not in the received payload'\n\n/**\n * Util method \n * @param {string} payload return from server\n * @return {object} the useful bit \n */\nfunction extractSrvPayload(payload) {\n let json = toJson(payload)\n \n if (json && typeof json === 'object') {\n // note this method expect the json.data inside\n return extractWsPayload(json)\n }\n \n throw new JsonqlError('extractSrvPayload', json)\n}\n\n/**\n * call the server to get a csrf token \n * @return {string} formatted payload to send to the server \n */\nfunction createInitPing() {\n const ts = timestamp()\n\n return createQueryStr(INTERCOM_RESOLVER_NAME, [SOCKET_PING_EVENT_NAME, ts])\n}\n\n/**\n * Take the raw on.message result back then decoded it \n * @param {*} payload the raw result from server\n * @return {object} the csrf payload\n */\nfunction extractPingResult(payload) {\n const result = extractSrvPayload(payload)\n \n if (result && result[DATA_KEY] && result[DATA_KEY][CSRF_HEADER_KEY]) {\n return {\n [HEADERS_KEY]: result[DATA_KEY]\n }\n }\n\n throw new JsonqlError('extractPingResult', CSRF_HEADER_NOT_EXIST_ERR)\n}\n\n\n/**\n * Create a generic intercom method\n * @param {string} type the event type \n * @param {array} args if any \n * @return {string} formatted payload to send\n */\nfunction createIntercomPayload(type, ...args) {\n const ts = timestamp()\n let payload = [type].concat(args)\n payload.push(ts)\n return createQueryStr(INTERCOM_RESOLVER_NAME, payload)\n}\n\n\nexport { \n extractSrvPayload,\n createInitPing, \n extractPingResult, \n createIntercomPayload \n}","// validator numbers\n// import { NUMBER_TYPES } from './constants';\n\nimport isNaN from 'lodash-es/isNaN'\nimport isString from 'lodash-es/isString'\n/**\n * @2015-05-04 found a problem if the value is a number like string\n * it will pass, so add a chck if it's string before we pass to next\n * @param {number} value expected value\n * @return {boolean} true if OK\n */\nconst checkIsNumber = function(value) {\n return isString(value) ? false : !isNaN( parseFloat(value) )\n}\n\nexport default checkIsNumber\n","// validate string type\nimport trim from 'lodash-es/trim'\nimport isString from 'lodash-es/isString'\n/**\n * @param {string} value expected value\n * @return {boolean} true if OK\n */\nconst checkIsString = function(value) {\n return (trim(value) !== '') ? isString(value) : false\n}\n\nexport default checkIsString\n","// check for boolean\n\n/**\n * @param {boolean} value expected\n * @return {boolean} true if OK\n */\nconst checkIsBoolean = function(value) {\n return value !== null && value !== undefined && typeof value === 'boolean'\n}\n\nexport default checkIsBoolean\n","// validate any thing only check if there is something\n\nimport trim from 'lodash-es/trim'\n\n/**\n * @param {*} value the value\n * @param {boolean} [checkNull=true] strict check if there is null value\n * @return {boolean} true is OK\n */\nconst checkIsAny = function(value, checkNull = true) {\n if (value !== undefined && value !== '' && trim(value) !== '') {\n if (checkNull === false || (checkNull === true && value !== null)) {\n return true;\n }\n }\n return false;\n}\n\nexport default checkIsAny\n","// Good practice rule - No magic number\n\nconst ARGS_NOT_ARRAY_ERR = `args is not an array! You might want to do: ES6 Array.from(arguments) or ES5 Array.prototype.slice.call(arguments)`\nconst PARAMS_NOT_ARRAY_ERR = `params is not an array! Did something gone wrong when you generate the contract.json?`\nconst EXCEPTION_CASE_ERR = 'Could not understand your arguments and parameter structure!'\nconst UNUSUAL_CASE_ERR = 'This is an unusual situation where the arguments are more than the params, but not mark as spread'\n\nconst RETURNS_NAME = 'returns'\n\nimport {\n \n DEFAULT_TYPE, // this is a mistake should move back to the validation\n DATA_KEY, \n ERROR_KEY,\n\n TYPE_KEY,\n OPTIONAL_KEY,\n ENUM_KEY,\n ARGS_KEY,\n CHECKER_KEY,\n ALIAS_KEY,\n\n ARRAY_TYPE_LFT,\n ARRAY_TYPE_RGT,\n \n ARRAY_TYPE,\n OBJECT_TYPE,\n STRING_TYPE,\n BOOLEAN_TYPE,\n NUMBER_TYPE,\n KEY_WORD,\n OR_SEPERATOR\n} from 'jsonql-constants'\n\n// group all export in one \nexport {\n ARGS_NOT_ARRAY_ERR,\n PARAMS_NOT_ARRAY_ERR,\n EXCEPTION_CASE_ERR,\n UNUSUAL_CASE_ERR,\n DEFAULT_TYPE,\n ARRAY_TYPE_LFT,\n ARRAY_TYPE_RGT,\n TYPE_KEY,\n OPTIONAL_KEY,\n ENUM_KEY,\n ARGS_KEY,\n CHECKER_KEY,\n ALIAS_KEY,\n ARRAY_TYPE,\n OBJECT_TYPE,\n STRING_TYPE,\n BOOLEAN_TYPE,\n NUMBER_TYPE,\n KEY_WORD,\n OR_SEPERATOR,\n\n RETURNS_NAME,\n\n DATA_KEY, \n ERROR_KEY \n}","// primitive types\nimport checkIsNumber from './number'\nimport checkIsString from './string'\nimport checkIsBoolean from './boolean'\nimport checkIsAny from './any'\nimport { NUMBER_TYPE, STRING_TYPE, BOOLEAN_TYPE } from './constants'\n\n/**\n * this is a wrapper method to call different one based on their type\n * @param {string} type to check\n * @return {function} a function to handle the type\n */\nconst combineFn = function(type) {\n switch (type) {\n case NUMBER_TYPE:\n return checkIsNumber\n case STRING_TYPE:\n return checkIsString\n case BOOLEAN_TYPE:\n return checkIsBoolean\n default:\n return checkIsAny\n }\n}\n\nexport default combineFn\n","// validate array type\n\nimport isArray from 'lodash-es/isArray'\nimport trim from 'lodash-es/trim'\nimport combineFn from './combine'\nimport {\n ARRAY_TYPE_LFT,\n ARRAY_TYPE_RGT,\n OR_SEPERATOR\n} from './constants'\n\n/**\n * @param {array} value expected\n * @param {string} [type=''] pass the type if we encounter array. then we need to check the value as well\n * @return {boolean} true if OK\n */\nexport const checkIsArray = function(value, type='') {\n if (isArray(value)) {\n if (type === '' || trim(type)==='') {\n return true;\n }\n // we test it in reverse\n // @TODO if the type is an array (OR) then what?\n // we need to take into account this could be an array\n const c = value.filter(v => !combineFn(type)(v))\n return !(c.length > 0)\n }\n return false\n}\n\n/**\n * check if it matches the array. pattern\n * @param {string} type\n * @return {boolean|array} false means NO, always return array\n */\nexport const isArrayLike = function(type) {\n // @TODO could that have something like array<> instead of array.<>? missing the dot?\n // because type script is Array without the dot\n if (type.indexOf(ARRAY_TYPE_LFT) > -1 && type.indexOf(ARRAY_TYPE_RGT) > -1) {\n const _type = type.replace(ARRAY_TYPE_LFT, '').replace(ARRAY_TYPE_RGT, '')\n if (_type.indexOf(OR_SEPERATOR)) {\n return _type.split(OR_SEPERATOR)\n }\n return [_type]\n }\n return false\n}\n\n/**\n * we might encounter something like array. then we need to take it apart\n * @param {object} p the prepared object for processing\n * @param {string|array} type the type came from \n * @return {boolean} for the filter to operate on\n */\nexport const arrayTypeHandler = function(p, type) {\n const { arg } = p\n // need a special case to handle the OR type\n // we need to test the args instead of the type(s)\n if (type.length > 1) {\n return !arg.filter(v => (\n !(type.length > type.filter(t => !combineFn(t)(v)).length)\n )).length\n }\n // type is array so this will be or!\n return type.length > type.filter(t => !checkIsArray(arg, t)).length\n}\n","// validate object type\n\nimport isPlainObject from 'lodash-es/isPlainObject'\n// import filter from 'lodash-es/filter'\nimport combineFn from './combine'\nimport { checkIsArray, isArrayLike, arrayTypeHandler } from './array'\n/**\n * @TODO if provide with the keys then we need to check if the key:value type as well\n * @param {object} value expected\n * @param {array} [keys=null] if it has the keys array to compare as well\n * @return {boolean} true if OK\n */\nexport const checkIsObject = function(value, keys=null) {\n if (isPlainObject(value)) {\n if (!keys) {\n return true\n }\n if (checkIsArray(keys)) {\n // please note we DON'T care if some is optional\n // plese refer to the contract.json for the keys\n return !keys.filter(key => {\n let _value = value[key.name];\n return !(key.type.length > key.type.filter(type => {\n let tmp;\n if (_value !== undefined) {\n if ((tmp = isArrayLike(type)) !== false) {\n return !arrayTypeHandler({arg: _value}, tmp)\n // return tmp.filter(t => !checkIsArray(_value, t)).length;\n // @TODO there might be an object within an object with keys as well :S\n }\n return !combineFn(type)(_value)\n }\n return true\n }).length)\n }).length;\n }\n }\n return false\n}\n\n/**\n * fold this into it's own function to handler different object type\n * @param {object} p the prepared object for process\n * @return {boolean}\n */\nexport const objectTypeHandler = function(p) {\n const { arg, param } = p\n let _args = [arg]\n if (Array.isArray(param.keys) && param.keys.length) {\n _args.push(param.keys)\n }\n // just simple check\n return Reflect.apply(checkIsObject, null, _args)\n}\n","// move the index.js code here that make more sense to find where things are\n\nimport {\n checkIsArray,\n isArrayLike,\n arrayTypeHandler,\n objectTypeHandler,\n combineFn,\n notEmpty\n} from './index'\n\nimport {\n DEFAULT_TYPE,\n ARRAY_TYPE,\n OBJECT_TYPE,\n ARGS_NOT_ARRAY_ERR,\n PARAMS_NOT_ARRAY_ERR,\n EXCEPTION_CASE_ERR,\n DATA_KEY, \n ERROR_KEY \n} from './constants'\n\n\nimport JsonqlValidationError from 'jsonql-errors/src/validation-error'\nimport JsonqlError from 'jsonql-errors/src/error'\n// import debug from 'debug'\n// const debugFn = debug('jsonql-params-validator:validator')\n// also export this for use in other places\n\n/**\n * We need to handle those optional parameter without a default value\n * @param {object} params from contract.json\n * @return {boolean} for filter operation false is actually OK\n */\nconst optionalHandler = function( params ) {\n const { arg, param } = params\n if (notEmpty(arg)) {\n // debug('call optional handler', arg, params);\n // loop through the type in param\n return !(param.type.length > param.type.filter(type =>\n validateHandler(type, params)\n ).length)\n }\n return false\n}\n\n/**\n * actually picking the validator\n * @param {*} type for checking\n * @param {*} value for checking\n * @return {boolean} true on OK\n */\nconst validateHandler = function(type, value) {\n let tmp;\n switch (true) {\n case type === OBJECT_TYPE:\n // debugFn('call OBJECT_TYPE')\n return !objectTypeHandler(value)\n case type === ARRAY_TYPE:\n // debugFn('call ARRAY_TYPE')\n return !checkIsArray(value.arg)\n // @TODO when the type is not present, it always fall through here\n // so we need to find a way to actually pre-check the type first\n // AKA check the contract.json map before running here\n case (tmp = isArrayLike(type)) !== false:\n // debugFn('call ARRAY_LIKE: %O', value)\n return !arrayTypeHandler(value, tmp)\n default:\n return !combineFn(type)(value.arg)\n }\n}\n\n/**\n * it get too longer to fit in one line so break it out from the fn below\n * @param {*} arg value\n * @param {object} param config\n * @return {*} value or apply default value\n */\nconst getOptionalValue = function(arg, param) {\n if (arg !== undefined) {\n return arg\n }\n return (param.optional === true && param.defaultvalue !== undefined ? param.defaultvalue : null)\n}\n\n/**\n * padding the arguments with defaultValue if the arguments did not provide the value\n * this will be the name export\n * @param {array} args normalized arguments\n * @param {array} params from contract.json\n * @return {array} merge the two together\n */\nexport const normalizeArgs = function(args, params) {\n // first we should check if this call require a validation at all\n // there will be situation where the function doesn't need args and params\n if (!checkIsArray(params)) {\n // debugFn('params value', params)\n throw new JsonqlValidationError(PARAMS_NOT_ARRAY_ERR)\n }\n if (params.length === 0) {\n return []\n }\n if (!checkIsArray(args)) {\n throw new JsonqlValidationError(ARGS_NOT_ARRAY_ERR)\n }\n // debugFn(args, params);\n // fall through switch\n switch(true) {\n case args.length == params.length: // standard\n return args.map((arg, i) => (\n {\n arg,\n index: i,\n param: params[i]\n }\n ))\n case params[0].variable === true: // using spread syntax\n const type = params[0].type;\n return args.map((arg, i) => (\n {\n arg,\n index: i, // keep the index for reference\n param: params[i] || { type, name: '_' }\n }\n ))\n // with optional defaultValue parameters\n case args.length < params.length:\n return params.map((param, i) => (\n {\n param,\n index: i,\n arg: getOptionalValue(args[i], param),\n optional: param.optional || false\n }\n ))\n // this one pass more than it should have anything after the args.length will be cast as any type\n case args.length > params.length:\n let ctn = params.length;\n // this happens when we have those array. type\n let _type = [ DEFAULT_TYPE ]\n // we only looking at the first one, this might be a @BUG\n /*\n if ((tmp = isArrayLike(params[0].type[0])) !== false) {\n _type = tmp;\n } */\n // if we use the params as guide then the rest will get throw out\n // which is not what we want, instead, anything without the param\n // will get a any type and optional flag\n return args.map((arg, i) => {\n let optional = i >= ctn ? true : !!params[i].optional\n let param = params[i] || { type: _type, name: `_${i}` }\n return {\n arg: optional ? getOptionalValue(arg, param) : arg,\n index: i,\n param,\n optional\n }\n })\n // @TODO find out if there is more cases not cover\n default: // this should never happen\n // debugFn('args', args)\n // debugFn('params', params)\n // this is unknown therefore we just throw it!\n throw new JsonqlError(EXCEPTION_CASE_ERR, { args, params })\n }\n}\n\n// what we want is after the validaton we also get the normalized result\n// which is with the optional property if the argument didn't provide it\n/**\n * process the array of params back to their arguments\n * @param {array} result the params result\n * @return {array} arguments\n */\nconst processReturn = result => result.map(r => r.arg)\n\n/**\n * validator main interface\n * @param {array} args the arguments pass to the method call\n * @param {array} params from the contract for that method\n * @param {boolean} [withResul=false] if true then this will return the normalize result as well\n * @return {array} empty array on success, or failed parameter and reasons\n */\nexport const validateSync = function(args, params, withResult = false) {\n let cleanArgs = normalizeArgs(args, params)\n let checkResult = cleanArgs.filter(p => {\n // v1.4.4 this fixed the problem, the root level optional is from the last fn\n if (p.optional === true || p.param.optional === true) {\n return optionalHandler(p)\n }\n // because array of types means OR so if one pass means pass\n return !(p.param.type.length > p.param.type.filter(\n type => validateHandler(type, p)\n ).length)\n })\n // using the same convention we been using all this time\n return !withResult ? checkResult : {\n [ERROR_KEY]: checkResult,\n [DATA_KEY]: processReturn(cleanArgs)\n }\n}\n\n/**\n * A wrapper method that return promise\n * @param {array} args arguments\n * @param {array} params from contract.json\n * @param {boolean} [withResul=false] if true then this will return the normalize result as well\n * @return {object} promise.then or catch\n */\nexport const validateAsync = function(args, params, withResult = false) {\n return new Promise((resolver, rejecter) => {\n const result = validateSync(args, params, withResult)\n if (withResult) {\n return result[ERROR_KEY].length ? rejecter(result[ERROR_KEY])\n : resolver(result[DATA_KEY])\n }\n // the different is just in the then or catch phrase\n return result.length ? rejecter(result) : resolver([])\n })\n}\n","/** Used to stand-in for `undefined` hash values. */\nvar HASH_UNDEFINED = '__lodash_hash_undefined__';\n\n/**\n * Adds `value` to the array cache.\n *\n * @private\n * @name add\n * @memberOf SetCache\n * @alias push\n * @param {*} value The value to cache.\n * @returns {Object} Returns the cache instance.\n */\nfunction setCacheAdd(value) {\n this.__data__.set(value, HASH_UNDEFINED);\n return this;\n}\n\nexport default setCacheAdd;\n","/**\n * Checks if `value` is in the array cache.\n *\n * @private\n * @name has\n * @memberOf SetCache\n * @param {*} value The value to search for.\n * @returns {number} Returns `true` if `value` is found, else `false`.\n */\nfunction setCacheHas(value) {\n return this.__data__.has(value);\n}\n\nexport default setCacheHas;\n","/**\n * A specialized version of `_.some` for arrays without support for iteratee\n * shorthands.\n *\n * @private\n * @param {Array} [array] The array to iterate over.\n * @param {Function} predicate The function invoked per iteration.\n * @returns {boolean} Returns `true` if any element passes the predicate check,\n * else `false`.\n */\nfunction arraySome(array, predicate) {\n var index = -1,\n length = array == null ? 0 : array.length;\n\n while (++index < length) {\n if (predicate(array[index], index, array)) {\n return true;\n }\n }\n return false;\n}\n\nexport default arraySome;\n","/**\n * Checks if a `cache` value for `key` exists.\n *\n * @private\n * @param {Object} cache The cache to query.\n * @param {string} key The key of the entry to check.\n * @returns {boolean} Returns `true` if an entry for `key` exists, else `false`.\n */\nfunction cacheHas(cache, key) {\n return cache.has(key);\n}\n\nexport default cacheHas;\n","/**\n * Converts `map` to its key-value pairs.\n *\n * @private\n * @param {Object} map The map to convert.\n * @returns {Array} Returns the key-value pairs.\n */\nfunction mapToArray(map) {\n var index = -1,\n result = Array(map.size);\n\n map.forEach(function(value, key) {\n result[++index] = [key, value];\n });\n return result;\n}\n\nexport default mapToArray;\n","/**\n * Converts `set` to an array of its values.\n *\n * @private\n * @param {Object} set The set to convert.\n * @returns {Array} Returns the values.\n */\nfunction setToArray(set) {\n var index = -1,\n result = Array(set.size);\n\n set.forEach(function(value) {\n result[++index] = value;\n });\n return result;\n}\n\nexport default setToArray;\n","/**\n * Appends the elements of `values` to `array`.\n *\n * @private\n * @param {Array} array The array to modify.\n * @param {Array} values The values to append.\n * @returns {Array} Returns `array`.\n */\nfunction arrayPush(array, values) {\n var index = -1,\n length = values.length,\n offset = array.length;\n\n while (++index < length) {\n array[offset + index] = values[index];\n }\n return array;\n}\n\nexport default arrayPush;\n","/**\n * A specialized version of `_.filter` for arrays without support for\n * iteratee shorthands.\n *\n * @private\n * @param {Array} [array] The array to iterate over.\n * @param {Function} predicate The function invoked per iteration.\n * @returns {Array} Returns the new filtered array.\n */\nfunction arrayFilter(array, predicate) {\n var index = -1,\n length = array == null ? 0 : array.length,\n resIndex = 0,\n result = [];\n\n while (++index < length) {\n var value = array[index];\n if (predicate(value, index, array)) {\n result[resIndex++] = value;\n }\n }\n return result;\n}\n\nexport default arrayFilter;\n","/**\n * This method returns a new empty array.\n *\n * @static\n * @memberOf _\n * @since 4.13.0\n * @category Util\n * @returns {Array} Returns the new empty array.\n * @example\n *\n * var arrays = _.times(2, _.stubArray);\n *\n * console.log(arrays);\n * // => [[], []]\n *\n * console.log(arrays[0] === arrays[1]);\n * // => false\n */\nfunction stubArray() {\n return [];\n}\n\nexport default stubArray;\n","/**\n * A specialized version of `matchesProperty` for source values suitable\n * for strict equality comparisons, i.e. `===`.\n *\n * @private\n * @param {string} key The key of the property to get.\n * @param {*} srcValue The value to match.\n * @returns {Function} Returns the new spec function.\n */\nfunction matchesStrictComparable(key, srcValue) {\n return function(object) {\n if (object == null) {\n return false;\n }\n return object[key] === srcValue &&\n (srcValue !== undefined || (key in Object(object)));\n };\n}\n\nexport default matchesStrictComparable;\n","/**\n * The base implementation of `_.hasIn` without support for deep paths.\n *\n * @private\n * @param {Object} [object] The object to query.\n * @param {Array|string} key The key to check.\n * @returns {boolean} Returns `true` if `key` exists, else `false`.\n */\nfunction baseHasIn(object, key) {\n return object != null && key in Object(object);\n}\n\nexport default baseHasIn;\n","/**\n * The base implementation of `_.property` without support for deep paths.\n *\n * @private\n * @param {string} key The key of the property to get.\n * @returns {Function} Returns the new accessor function.\n */\nfunction baseProperty(key) {\n return function(object) {\n return object == null ? undefined : object[key];\n };\n}\n\nexport default baseProperty;\n","/** Error message constants. */\nvar FUNC_ERROR_TEXT = 'Expected a function';\n\n/**\n * Creates a function that negates the result of the predicate `func`. The\n * `func` predicate is invoked with the `this` binding and arguments of the\n * created function.\n *\n * @static\n * @memberOf _\n * @since 3.0.0\n * @category Function\n * @param {Function} predicate The predicate to negate.\n * @returns {Function} Returns the new negated function.\n * @example\n *\n * function isEven(n) {\n * return n % 2 == 0;\n * }\n *\n * _.filter([1, 2, 3, 4, 5, 6], _.negate(isEven));\n * // => [1, 3, 5]\n */\nfunction negate(predicate) {\n if (typeof predicate != 'function') {\n throw new TypeError(FUNC_ERROR_TEXT);\n }\n return function() {\n var args = arguments;\n switch (args.length) {\n case 0: return !predicate.call(this);\n case 1: return !predicate.call(this, args[0]);\n case 2: return !predicate.call(this, args[0], args[1]);\n case 3: return !predicate.call(this, args[0], args[1], args[2]);\n }\n return !predicate.apply(this, args);\n };\n}\n\nexport default negate;\n","/**\n * The base implementation of methods like `_.findKey` and `_.findLastKey`,\n * without support for iteratee shorthands, which iterates over `collection`\n * using `eachFunc`.\n *\n * @private\n * @param {Array|Object} collection The collection to inspect.\n * @param {Function} predicate The function invoked per iteration.\n * @param {Function} eachFunc The function to iterate over `collection`.\n * @returns {*} Returns the found element or its key, else `undefined`.\n */\nfunction baseFindKey(collection, predicate, eachFunc) {\n var result;\n eachFunc(collection, function(value, key, collection) {\n if (predicate(value, key, collection)) {\n result = key;\n return false;\n }\n });\n return result;\n}\n\nexport default baseFindKey;\n","/**\n * @param {array} arr Array for check\n * @param {*} value target\n * @return {boolean} true on successs\n */\nconst isInArray = function(arr, value) {\n return !!arr.filter(a => a === value).length\n}\n\nexport default isInArray\n","// breaking the whole thing up to see what cause the multiple calls issue\n\nimport isFunction from 'lodash-es/isFunction'\nimport merge from 'lodash-es/merge'\nimport mapValues from 'lodash-es/mapValues'\n\nimport JsonqlEnumError from 'jsonql-errors/src/enum-error'\nimport JsonqlTypeError from 'jsonql-errors/src/type-error'\nimport JsonqlCheckerError from 'jsonql-errors/src/checker-error'\n\nimport {\n TYPE_KEY,\n OPTIONAL_KEY,\n ENUM_KEY,\n ARGS_KEY,\n CHECKER_KEY,\n KEY_WORD\n} from '../constants'\nimport { checkIsArray } from '../array'\n\n// import debug from 'debug';\n// const debugFn = debug('jsonql-params-validator:options:validation')\n\n/**\n * just make sure it returns an array to use\n * @param {*} arg input\n * @return {array} output\n */\nconst toArray = arg => checkIsArray(arg) ? arg : [arg]\n\n/**\n * DIY in array\n * @param {array} arr to check against\n * @param {*} value to check\n * @return {boolean} true on OK\n */\nconst inArray = (arr, value) => (\n !!arr.filter(v => v === value).length\n)\n\n/**\n * break out to make the code easier to read\n * @param {object} value to process\n * @param {function} cb the validateSync\n * @return {array} empty on success\n */\nfunction validateHandler(value, cb) {\n // cb is the validateSync methods\n let args = [\n [ value[ARGS_KEY] ],\n [{\n [TYPE_KEY]: toArray(value[TYPE_KEY]),\n [OPTIONAL_KEY]: value[OPTIONAL_KEY]\n }]\n ]\n // debugFn('validateHandler', args)\n return Reflect.apply(cb, null, args)\n}\n\n/**\n * Check against the enum value if it's provided\n * @param {*} value to check\n * @param {*} enumv to check against if it's not false\n * @return {boolean} true on OK\n */\nconst enumHandler = (value, enumv) => {\n if (checkIsArray(enumv)) {\n return inArray(enumv, value)\n }\n return true\n}\n\n/**\n * Allow passing a function to check the value\n * There might be a problem here if the function is incorrect\n * and that will makes it hard to debug what is going on inside\n * @TODO there could be a few feature add to this one under different circumstance\n * @param {*} value to check\n * @param {function} checker for checking\n */\nconst checkerHandler = (value, checker) => {\n try {\n return isFunction(checker) ? checker.apply(null, [value]) : false\n } catch (e) {\n return false\n }\n}\n\n/**\n * Taken out from the runValidaton this only validate the required values\n * @param {array} args from the config2argsAction\n * @param {function} cb validateSync\n * @return {array} of configuration values\n */\nfunction runValidationAction(cb) {\n return (value, key) => {\n // debugFn('runValidationAction', key, value)\n if (value[KEY_WORD]) {\n return value[ARGS_KEY]\n }\n const check = validateHandler(value, cb)\n if (check.length) {\n // log('runValidationAction', key, value)\n throw new JsonqlTypeError(key, check)\n }\n if (value[ENUM_KEY] !== false && !enumHandler(value[ARGS_KEY], value[ENUM_KEY])) {\n // log(ENUM_KEY, value[ENUM_KEY])\n throw new JsonqlEnumError(key)\n }\n if (value[CHECKER_KEY] !== false && !checkerHandler(value[ARGS_KEY], value[CHECKER_KEY])) {\n // log(CHECKER_KEY, value[CHECKER_KEY])\n throw new JsonqlCheckerError(key)\n }\n return value[ARGS_KEY]\n }\n}\n\n/**\n * @param {object} args from the config2argsAction\n * @param {function} cb validateSync\n * @return {object} of configuration values\n */\nexport default function runValidation(args, cb) {\n const [ argsForValidate, pristineValues ] = args\n // turn the thing into an array and see what happen here\n // debugFn('_args', argsForValidate)\n const result = mapValues(argsForValidate, runValidationAction(cb))\n return merge(result, pristineValues)\n}\n","/// this is port back from the client to share across all projects\n\nimport merge from 'lodash-es/merge'\nimport { prepareArgsForValidation } from './prepare-args-for-validation'\nimport runValidation from './run-validation'\n\n// import debug from 'debug'\n// const debugFn = debug('jsonql-params-validator:check-options-async')\n\n/**\n * Quick transform\n * @param {object} config that one\n * @param {object} appProps mutation configuration options\n * @return {object} put that arg into the args\n */\nconst configToArgs = (config, appProps) => {\n return Promise.resolve(\n prepareArgsForValidation(config, appProps)\n )\n}\n\n/**\n * @param {object} config user provide configuration option\n * @param {object} appProps mutation configuration options\n * @param {object} constProps the immutable configuration options\n * @param {function} cb the validateSync method\n * @return {object} Promise resolve merge config object\n */\nexport default function(config = {}, appProps, constProps, cb) {\n return configToArgs(config, appProps)\n .then(args1 => runValidation(args1, cb))\n // next if every thing good then pass to final merging\n .then(args2 => merge({}, args2, constProps))\n}\n","// create function to construct the config entry so we don't need to keep building object\n\nimport isFunction from 'lodash-es/isFunction'\nimport isString from 'lodash-es/isString'\nimport {\n ARGS_KEY,\n TYPE_KEY,\n CHECKER_KEY,\n ENUM_KEY,\n OPTIONAL_KEY,\n ALIAS_KEY\n} from 'jsonql-constants'\n\nimport { checkIsArray } from '../array'\n// import checkIsBoolean from '../boolean'\n// import debug from 'debug';\n// const debugFn = debug('jsonql-params-validator:construct-config');\n/**\n * @param {*} args value\n * @param {string} type for value\n * @param {boolean} [optional=false]\n * @param {boolean|array} [enumv=false]\n * @param {boolean|function} [checker=false]\n * @return {object} config entry\n */\nexport default function constructConfig(args, type, optional=false, enumv=false, checker=false, alias=false) {\n let base = {\n [ARGS_KEY]: args,\n [TYPE_KEY]: type\n }\n if (optional === true) {\n base[OPTIONAL_KEY] = true\n }\n if (checkIsArray(enumv)) {\n base[ENUM_KEY] = enumv\n }\n if (isFunction(checker)) {\n base[CHECKER_KEY] = checker\n }\n if (isString(alias)) {\n base[ALIAS_KEY] = alias\n }\n return base\n}\n","// export also create wrapper methods\nimport checkOptionsAsync from './check-options-async'\nimport checkOptionsSync from './check-options-sync'\nimport constructConfigFn from './construct-config'\nimport {\n ENUM_KEY,\n CHECKER_KEY,\n ALIAS_KEY,\n OPTIONAL_KEY\n} from 'jsonql-constants'\n\n/**\n * This has a different interface\n * @param {*} value to supply\n * @param {string|array} type for checking\n * @param {object} params to map against the config check\n * @param {array} params.enumv NOT enum\n * @param {boolean} params.optional false then nothing\n * @param {function} params.checker need more work on this one later\n * @param {string} params.alias mostly for cmd\n */\nconst createConfig = (value, type, params = {}) => {\n // Note the enumv not ENUM\n // const { enumv, optional, checker, alias } = params;\n // let args = [value, type, optional, enumv, checker, alias];\n const {\n [OPTIONAL_KEY]: o,\n [ENUM_KEY]: e,\n [CHECKER_KEY]: c,\n [ALIAS_KEY]: a\n } = params;\n return constructConfigFn.apply(null, [value, type, o, e, c, a])\n}\n\n// for testing purpose\nconst JSONQL_PARAMS_VALIDATOR_INFO = '__PLACEHOLDER__'\n\n/**\n * construct the actual end user method, rename with prefix get since 1.5.2\n * @param {function} validateSync validation method\n * @return {function} for performaning the actual valdiation\n */\nconst getCheckConfigAsync = function(validateSync) {\n /**\n * We recreate the method here to avoid the circlar import\n * @param {object} config user supply configuration\n * @param {object} appProps mutation options\n * @param {object} [constantProps={}] optional: immutation options\n * @return {object} all checked configuration\n */\n return function(config, appProps, constantProps= {}) {\n return checkOptionsAsync(config, appProps, constantProps, validateSync)\n }\n}\n\n/**\n * copy of above but it's sync, rename with prefix get since 1.5.2\n * @param {function} validateSync validation method\n * @return {function} for performaning the actual valdiation\n */\nconst getCheckConfig = function(validateSync) {\n return function(config, appProps, constantProps = {}) {\n return checkOptionsSync(config, appProps, constantProps, validateSync)\n }\n}\n\n// re-export\nexport {\n createConfig,\n constructConfigFn,\n getCheckConfigAsync,\n getCheckConfig,\n JSONQL_PARAMS_VALIDATOR_INFO\n}\n","// export\nimport {\n checkIsObject,\n notEmpty,\n checkIsAny,\n checkIsString,\n checkIsBoolean,\n checkIsNumber,\n checkIsArray\n} from './src'\nimport * as validator from './src/validator'\n// configuration checking\nimport * as jsonqlOptions from './src/options'\n// the two extra functions\nimport isInArray from './src/is-in-array'\nimport isObjectHasKeyFn from './src/is-key-in-object'\n\nconst isObject = checkIsObject\nconst isAny = checkIsAny\nconst isString = checkIsString\nconst isBoolean = checkIsBoolean\nconst isNumber = checkIsNumber\nconst isArray = checkIsArray\nconst isNotEmpty = notEmpty\n\nconst normalizeArgs = validator.normalizeArgs\nconst validateSync = validator.validateSync\nconst validateAsync = validator.validateAsync\n\nconst JSONQL_PARAMS_VALIDATOR_INFO = jsonqlOptions.JSONQL_PARAMS_VALIDATOR_INFO\n\nconst createConfig = jsonqlOptions.createConfig\nconst constructConfig = jsonqlOptions.constructConfigFn\n// construct the final output 1.5.2\nconst checkConfigAsync = jsonqlOptions.getCheckConfigAsync(validator.validateSync)\nconst checkConfig = jsonqlOptions.getCheckConfig(validator.validateSync)\n\nconst inArray = isInArray\nconst isObjectHasKey = isObjectHasKeyFn\n\n// check returns methods \nimport { \n checkReturns, \n checkReturnsAsync, \n checkResolverReturns, \n checkResolverReturnsAsync \n} from './src/returns'\n\n\n// group the in one \nexport {\n JSONQL_PARAMS_VALIDATOR_INFO,\n \n isObject,\n isAny,\n isString,\n isBoolean,\n isNumber,\n isArray,\n isNotEmpty,\n \n inArray,\n isObjectHasKey,\n\n normalizeArgs,\n validateSync,\n validateAsync,\n\n createConfig,\n constructConfig,\n checkConfig,\n checkConfigAsync,\n\n checkReturns, \n checkReturnsAsync, \n checkResolverReturns, \n checkResolverReturnsAsync\n}\n\n\n\n\n\n","// move the get logger stuff here\n\n// it does nothing\nconst dummyLogger = () => {}\n\n/**\n * re-use the debugOn prop to control this log method\n * @param {object} opts configuration\n * @return {function} the log function\n */\nconst getLogger = (opts) => {\n const { debugOn } = opts \n if (debugOn) {\n return (...args) => {\n Reflect.apply(console.info, console, ['[jsonql-ws-client-core]', ...args])\n }\n }\n return dummyLogger\n}\n\n/**\n * Make sure there is a log method\n * @param {object} opts configuration\n * @return {object} opts\n */\nconst getLogFn = opts => {\n const { log } = opts // 1.3.9 if we pass a log method here then we use this\n if (!log || typeof log !== 'function') {\n return getLogger(opts)\n }\n opts.log('---> getLogFn user supplied log function <---', opts)\n return log\n}\n\nexport { getLogFn }","// group all the repetitive message here\n\nexport const TAKEN_BY_OTHER_TYPE_ERR = 'You are trying to register an event already been taken by other type:'\n","// Create two WeakMap store as a private keys\nexport const NB_EVENT_SERVICE_PRIVATE_STORE = new WeakMap()\nexport const NB_EVENT_SERVICE_PRIVATE_LAZY = new WeakMap()\n","/**\n * generate a 32bit hash based on the function.toString()\n * _from http://stackoverflow.com/questions/7616461/generate-a-hash-_from-string-in-javascript-jquery\n * @param {string} s the converted to string function\n * @return {string} the hashed function string\n */\nexport function hashCode(s) {\n\treturn s.split(\"\").reduce(function(a,b){a=((a<<5)-a)+b.charCodeAt(0);return a&a},0)\n}\n\n/**\n * wrapper to make sure it string\n * @param {*} input whatever\n * @return {string} output\n */\nexport function hashCode2Str(s) {\n return hashCode(s) + ''\n}\n\n/**\n * Just check if a pattern is an RegExp object\n * @param {*} pat whatever\n * @return {boolean} false when its not\n */\nexport function isRegExp(pat) {\n return pat instanceof RegExp\n}\n\n/**\n * check if its string\n * @param {*} arg whatever\n * @return {boolean} false when it's not\n */\nexport function isString(arg) {\n return typeof arg === 'string'\n}\n\n/**\n * Find from the array by matching the pattern\n * @param {*} pattern a string or RegExp object\n * @return {object} regex object or false when we can not id the input\n */\nexport function getRegex(pattern) {\n switch (true) {\n case isRegExp(pattern) === true:\n return pattern\n case isString(pattern) === true:\n return new RegExp(pattern)\n default:\n return false\n }\n}\n","// making all the functionality on it's own\n// import { WatchClass } from './watch'\n/*\nwe use a different way to do the same watch thing now\nthis.watch('suspend', function(value, prop, oldValue) {\n this.logger(`${prop} set from ${oldValue} to ${value}`)\n // it means it set the suspend = true then release it\n if (oldValue === true && value === false) {\n // we want this happen after the return happens\n setTimeout(() => {\n this.release()\n }, 1)\n }\n return value; // we need to return the value to store it\n})\n*/\nimport { getRegex, isRegExp } from './utils'\n\nexport default class SuspendClass {\n\n constructor() {\n // suspend, release and queue\n this.__suspend_state__ = null\n // to do this proper we don't use a new prop to hold the event name pattern\n this.__pattern__ = null\n this.queueStore = new Set()\n }\n\n /**\n * start suspend\n * @return {void}\n */\n $suspend() {\n this.logger(`---> SUSPEND ALL OPS <---`)\n this.__suspend__(true)\n }\n\n /**\n * release the queue\n * @return {void}\n */\n $release() {\n this.logger(`---> RELEASE SUSPENDED QUEUE <---`)\n this.__suspend__(false)\n }\n\n /**\n * suspend event by pattern\n * @param {string} pattern the pattern search matches the event name\n * @return {void}\n */\n $suspendEvent(pattern) {\n const regex = getRegex(pattern)\n if (isRegExp(regex)) {\n this.__pattern__ = regex\n return this.$suspend()\n }\n throw new Error(`We expect a pattern variable to be string or RegExp, but we got \"${typeof regex}\" instead`)\n }\n\n /**\n * queuing call up when it's in suspend mode\n * @param {string} evt the event name\n * @param {*} args unknown number of arguments\n * @return {boolean} true when added or false when it's not\n */\n $queue(evt, ...args) {\n this.logger('($queue) get called')\n if (this.__suspend_state__ === true) {\n if (isRegExp(this.__pattern__)) { // it's better then check if its not null\n // check the pattern and decide if we want to suspend it or not\n let found = this.__pattern__.test(evt)\n if (!found) {\n return false\n }\n }\n this.logger('($queue) added to $queue', args)\n // @TODO there shouldn't be any duplicate, but how to make sure?\n this.queueStore.add([evt].concat(args))\n // return this.queueStore.size\n }\n return !!this.__suspend_state__\n }\n\n /**\n * a getter to get all the store queue\n * @return {array} Set turn into Array before return\n */\n get $queues() {\n let size = this.queueStore.size\n this.logger('($queues)', `size: ${size}`)\n if (size > 0) {\n return Array.from(this.queueStore)\n }\n return []\n }\n\n /**\n * to set the suspend and check if it's boolean value\n * @param {boolean} value to trigger\n */\n __suspend__(value) {\n if (typeof value === 'boolean') {\n const lastValue = this.__suspend_state__\n this.__suspend_state__ = value\n this.logger(`($suspend) Change from \"${lastValue}\" --> \"${value}\"`)\n if (lastValue === true && value === false) {\n this.__release__()\n }\n } else {\n throw new Error(`$suspend only accept Boolean value! we got ${typeof value}`)\n }\n }\n\n /**\n * Release the queue\n * @return {int} size if any\n */\n __release__() {\n let size = this.queueStore.size\n let pattern = this.__pattern__\n this.__pattern__ = null\n this.logger(`(release) was called with ${size}${pattern ? ' for \"' + pattern + '\"': ''} item${size > 1 ? 's' : ''}`)\n if (size > 0) {\n const queue = Array.from(this.queueStore)\n this.queueStore.clear()\n this.logger('(release queue)', queue)\n queue.forEach(args => {\n this.logger(args)\n Reflect.apply(this.$trigger, this, args)\n })\n this.logger(`Release size ${this.queueStore.size}`)\n }\n\n return size\n }\n}\n","// break up the main file because its getting way too long\nimport {\n NB_EVENT_SERVICE_PRIVATE_STORE,\n NB_EVENT_SERVICE_PRIVATE_LAZY\n} from './store'\nimport { hashCode2Str, isString } from './utils'\nimport SuspendClass from './suspend'\n\nexport default class StoreService extends SuspendClass {\n\n constructor(config = {}) {\n super()\n if (config.logger && typeof config.logger === 'function') {\n this.logger = config.logger\n }\n this.keep = config.keep\n // for the $done setter\n this.result = config.keep ? [] : null\n // we need to init the store first otherwise it could be a lot of checking later\n this.normalStore = new Map()\n this.lazyStore = new Map()\n }\n\n /**\n * validate the event name(s)\n * @param {string[]} evt event name\n * @return {boolean} true when OK\n */\n validateEvt(...evt) {\n evt.forEach(e => {\n if (!isString(e)) {\n this.logger('(validateEvt)', e)\n throw new Error(`Event name must be string type! we got ${typeof e}`)\n }\n })\n return true\n }\n\n /**\n * Simple quick check on the two main parameters\n * @param {string} evt event name\n * @param {function} callback function to call\n * @return {boolean} true when OK\n */\n validate(evt, callback) {\n if (this.validateEvt(evt)) {\n if (typeof callback === 'function') {\n return true\n }\n }\n throw new Error(`callback required to be function type! we got ${typeof callback}`)\n }\n\n /**\n * Check if this type is correct or not added in V1.5.0\n * @param {string} type for checking\n * @return {boolean} true on OK\n */\n validateType(type) {\n this.validateEvt(type)\n const types = ['on', 'only', 'once', 'onlyOnce']\n return !!types.filter(t => type === t).length\n }\n\n /**\n * Run the callback\n * @param {function} callback function to execute\n * @param {array} payload for callback\n * @param {object} ctx context or null\n * @return {void} the result store in $done\n */\n run(callback, payload, ctx) {\n this.logger('(run) callback:', callback, 'payload:', payload, 'context:', ctx)\n this.$done = Reflect.apply(callback, ctx, this.toArray(payload))\n }\n\n /**\n * Take the content out and remove it from store id by the name\n * @param {string} evt event name\n * @param {string} [storeName = lazyStore] name of store\n * @return {object|boolean} content or false on not found\n */\n takeFromStore(evt, storeName = 'lazyStore') {\n let store = this[storeName] // it could be empty at this point\n if (store) {\n this.logger('(takeFromStore)', storeName, store)\n if (store.has(evt)) {\n let content = store.get(evt)\n this.logger(`(takeFromStore) has \"${evt}\"`, content)\n store.delete(evt)\n return content\n }\n return false\n }\n throw new Error(`\"${storeName}\" is not supported!`)\n }\n\n /**\n * This was part of the $get. We take it out\n * so we could use a regex to remove more than one event\n * @param {object} store the store to return from\n * @param {string} evt event name\n * @param {boolean} full return just the callback or everything\n * @return {array|boolean} false when not found\n */\n findFromStore(evt, store, full = false) {\n if (store.has(evt)) {\n return Array\n .from(store.get(evt))\n .map( l => {\n if (full) {\n return l\n }\n let [key, callback, ] = l\n return callback\n })\n }\n return false\n }\n\n /**\n * Similar to the findFromStore, but remove\n * @param {string} evt event name\n * @param {object} store the store to remove from\n * @return {boolean} false when not found\n */\n removeFromStore(evt, store) {\n if (store.has(evt)) {\n this.logger('($off)', evt)\n store.delete(evt)\n return true\n }\n return false\n }\n\n /**\n * The add to store step is similar so make it generic for resuse\n * @param {object} store which store to use\n * @param {string} evt event name\n * @param {spread} args because the lazy store and normal store store different things\n * @return {array} store and the size of the store\n */\n addToStore(store, evt, ...args) {\n let fnSet\n if (store.has(evt)) {\n this.logger(`(addToStore) \"${evt}\" existed`)\n fnSet = store.get(evt)\n } else {\n this.logger(`(addToStore) create new Set for \"${evt}\"`)\n // this is new\n fnSet = new Set()\n }\n // lazy only store 2 items - this is not the case in V1.6.0 anymore\n // we need to check the first parameter is string or not\n if (args.length > 2) {\n if (Array.isArray(args[0])) { // lazy store\n // check if this type of this event already register in the lazy store\n let [,,t] = args\n if (!this.checkTypeInLazyStore(evt, t)) {\n fnSet.add(args)\n }\n } else {\n if (!this.checkContentExist(args, fnSet)) {\n this.logger(`(addToStore) insert new`, args)\n fnSet.add(args)\n }\n }\n } else { // add straight to lazy store\n fnSet.add(args)\n }\n store.set(evt, fnSet)\n return [store, fnSet.size]\n }\n\n /**\n * @param {array} args for compare\n * @param {object} fnSet A Set to search from\n * @return {boolean} true on exist\n */\n checkContentExist(args, fnSet) {\n let list = Array.from(fnSet)\n return !!list.filter(li => {\n let [hash,] = li\n return hash === args[0]\n }).length\n }\n\n /**\n * get the existing type to make sure no mix type add to the same store\n * @param {string} evtName event name\n * @param {string} type the type to check\n * @return {boolean} true you can add, false then you can't add this type\n */\n checkTypeInStore(evtName, type) {\n this.validateEvt(evtName, type)\n let all = this.$get(evtName, true)\n if (all === false) {\n // pristine it means you can add\n return true\n }\n // it should only have ONE type in ONE event store\n return !all.filter(list => {\n let [ ,,,t ] = list\n return type !== t\n }).length\n }\n\n /**\n * This is checking just the lazy store because the structure is different\n * therefore we need to use a new method to check it\n */\n checkTypeInLazyStore(evtName, type) {\n this.validateEvt(evtName, type)\n let store = this.lazyStore.get(evtName)\n this.logger('(checkTypeInLazyStore)', store)\n if (store) {\n return !!Array\n .from(store)\n .filter(li => {\n let [,,t] = li\n return t !== type\n }).length\n }\n return false\n }\n\n /**\n * wrapper to re-use the addToStore,\n * V1.3.0 add extra check to see if this type can add to this evt\n * @param {string} evt event name\n * @param {string} type on or once\n * @param {function} callback function\n * @param {object} context the context the function execute in or null\n * @return {number} size of the store\n */\n addToNormalStore(evt, type, callback, context = null) {\n this.logger(`(addToNormalStore) try to add \"${type}\" --> \"${evt}\" to normal store`)\n // @TODO we need to check the existing store for the type first!\n if (this.checkTypeInStore(evt, type)) {\n this.logger('(addToNormalStore)', `\"${type}\" --> \"${evt}\" can add to normal store`)\n let key = this.hashFnToKey(callback)\n let args = [this.normalStore, evt, key, callback, context, type]\n let [_store, size] = Reflect.apply(this.addToStore, this, args)\n this.normalStore = _store\n return size\n }\n return false\n }\n\n /**\n * Add to lazy store this get calls when the callback is not register yet\n * so we only get a payload object or even nothing\n * @param {string} evt event name\n * @param {array} payload of arguments or empty if there is none\n * @param {object} [context=null] the context the callback execute in\n * @param {string} [type=false] register a type so no other type can add to this evt\n * @return {number} size of the store\n */\n addToLazyStore(evt, payload = [], context = null, type = false) {\n // this is add in V1.6.0\n // when there is type then we will need to check if this already added in lazy store\n // and no other type can add to this lazy store\n let args = [this.lazyStore, evt, this.toArray(payload), context]\n if (type) {\n args.push(type)\n }\n let [_store, size] = Reflect.apply(this.addToStore, this, args)\n this.lazyStore = _store\n this.logger(`(addToLazyStore) size: ${size}`)\n return size\n }\n\n /**\n * make sure we store the argument correctly\n * @param {*} arg could be array\n * @return {array} make sured\n */\n toArray(arg) {\n return Array.isArray(arg) ? arg : [arg]\n }\n\n /**\n * setter to store the Set in private\n * @param {object} obj a Set\n */\n set normalStore(obj) {\n NB_EVENT_SERVICE_PRIVATE_STORE.set(this, obj)\n }\n\n /**\n * @return {object} Set object\n */\n get normalStore() {\n return NB_EVENT_SERVICE_PRIVATE_STORE.get(this)\n }\n\n /**\n * setter to store the Set in lazy store\n * @param {object} obj a Set\n */\n set lazyStore(obj) {\n NB_EVENT_SERVICE_PRIVATE_LAZY.set(this , obj)\n }\n\n /**\n * @return {object} the lazy store Set\n */\n get lazyStore() {\n return NB_EVENT_SERVICE_PRIVATE_LAZY.get(this)\n }\n\n /**\n * generate a hashKey to identify the function call\n * The build-in store some how could store the same values!\n * @param {function} fn the converted to string function\n * @return {string} hashKey\n */\n hashFnToKey(fn) {\n return hashCode2Str(fn.toString())\n }\n}\n","// The top level\nimport { TAKEN_BY_OTHER_TYPE_ERR } from './constants'\nimport StoreService from './store-service'\n// export\nexport default class EventService extends StoreService {\n /**\n * class constructor\n */\n constructor(config = {}) {\n super(config)\n }\n\n /**\n * logger function for overwrite\n */\n logger() {}\n\n // for id if the instance is this class\n get $name() {\n return 'to1source-event'\n }\n\n // take this down in the next release\n get is() {\n return this.$name\n }\n\n //////////////////////////\n // PUBLIC METHODS //\n //////////////////////////\n\n /**\n * Register your evt handler, note we don't check the type here,\n * we expect you to be sensible and know what you are doing.\n * @param {string} evt name of event\n * @param {function} callback bind method --> if it's array or not\n * @param {object} [context=null] to execute this call in\n * @return {number} the size of the store\n */\n $on(evt , callback , context = null) {\n const type = 'on'\n this.validate(evt, callback)\n // first need to check if this evt is in lazy store\n let lazyStoreContent = this.takeFromStore(evt)\n // this is normal register first then call later\n if (lazyStoreContent === false) {\n this.logger(`($on) \"${evt}\" is not in lazy store`)\n // @TODO we need to check if there was other listener to this\n // event and are they the same type then we could solve that\n // register the different type to the same event name\n return this.addToNormalStore(evt, type, callback, context)\n }\n this.logger(`($on) ${evt} found in lazy store`)\n // this is when they call $trigger before register this callback\n let size = 0\n lazyStoreContent.forEach(content => {\n let [ payload, ctx, t ] = content\n if (t && t !== type) {\n throw new Error(`${TAKEN_BY_OTHER_TYPE_ERR} ${t}`)\n }\n this.logger(`($on)`, `call run \"${evt}\"`)\n this.run(callback, payload, context || ctx)\n size += this.addToNormalStore(evt, type, callback, context || ctx)\n })\n\n this.logger(`($on) return size ${size}`)\n return size\n }\n\n /**\n * once only registered it once, there is no overwrite option here\n * @NOTE change in v1.3.0 $once can add multiple listeners\n * but once the event fired, it will remove this event (see $only)\n * @param {string} evt name\n * @param {function} callback to execute\n * @param {object} [context=null] the handler execute in\n * @return {boolean} result\n */\n $once(evt , callback , context = null) {\n this.validate(evt, callback)\n const type = 'once'\n let lazyStoreContent = this.takeFromStore(evt)\n // this is normal register before call $trigger\n let nStore = this.normalStore;\n if (lazyStoreContent === false) {\n this.logger(`($once) \"${evt}\" is not in the lazy store`)\n // v1.3.0 $once now allow to add multiple listeners\n return this.addToNormalStore(evt, type, callback, context)\n } else {\n // now this is the tricky bit\n // there is a potential bug here that cause by the developer\n // if they call $trigger first, the lazy won't know it's a once call\n // so if in the middle they register any call with the same evt name\n // then this $once call will be fucked - add this to the documentation\n this.logger('($once)', lazyStoreContent)\n const list = Array.from(lazyStoreContent)\n // should never have more than 1\n const [ payload, ctx, t ] = list[0]\n if (t && t !== type) {\n throw new Error(`${TAKEN_BY_OTHER_TYPE_ERR} ${t}`)\n }\n this.logger('($once)', `call run \"${evt}\"`)\n this.run(callback, payload, context || ctx)\n // remove this evt from store\n this.$off(evt)\n }\n }\n\n /**\n * This one event can only bind one callbackback\n * @param {string} evt event name\n * @param {function} callback event handler\n * @param {object} [context=null] the context the event handler execute in\n * @return {boolean} true bind for first time, false already existed\n */\n $only(evt, callback, context = null) {\n this.validate(evt, callback)\n const type = 'only'\n let added = false\n let lazyStoreContent = this.takeFromStore(evt)\n // this is normal register before call $trigger\n let nStore = this.normalStore\n if (!nStore.has(evt)) {\n this.logger(`($only) \"${evt}\" add to normalStore`)\n added = this.addToNormalStore(evt, type, callback, context)\n }\n if (lazyStoreContent !== false) {\n // there are data store in lazy store\n this.logger(`($only) \"${evt}\" found data in lazy store to execute`)\n const list = Array.from(lazyStoreContent)\n // $only allow to trigger this multiple time on the single handler\n list.forEach( li => {\n const [ payload, ctx, t ] = li\n if (t && t !== type) {\n throw new Error(`${TAKEN_BY_OTHER_TYPE_ERR} ${t}`)\n }\n this.logger(`($only) call run \"${evt}\"`)\n this.run(callback, payload, context || ctx)\n })\n }\n return added\n }\n\n /**\n * $only + $once this is because I found a very subtile bug when we pass a\n * resolver, rejecter - and it never fire because that's OLD added in v1.4.0\n * @param {string} evt event name\n * @param {function} callback to call later\n * @param {object} [context=null] exeucte context\n * @return {void}\n */\n $onlyOnce(evt, callback, context = null) {\n this.validate(evt, callback)\n const type = 'onlyOnce'\n let added = false\n let lazyStoreContent = this.takeFromStore(evt)\n // this is normal register before call $trigger\n let nStore = this.normalStore;\n if (!nStore.has(evt)) {\n this.logger(`($onlyOnce) \"${evt}\" add to normalStore`)\n added = this.addToNormalStore(evt, type, callback, context)\n }\n if (lazyStoreContent !== false) {\n // there are data store in lazy store\n this.logger('($onlyOnce)', lazyStoreContent)\n const list = Array.from(lazyStoreContent)\n // should never have more than 1\n const [ payload, ctx, t ] = list[0]\n if (t && t !== 'onlyOnce') {\n throw new Error(`${TAKEN_BY_OTHER_TYPE_ERR} ${t}`)\n }\n this.logger(`($onlyOnce) call run \"${evt}\"`)\n this.run(callback, payload, context || ctx)\n // remove this evt from store\n this.$off(evt)\n }\n return added\n }\n\n /**\n * This is a shorthand of $off + $on added in V1.5.0\n * @param {string} evt event name\n * @param {function} callback to exeucte\n * @param {object} [context = null] or pass a string as type\n * @param {string} [type=on] what type of method to replace\n * @return {*}\n */\n $replace(evt, callback, context = null, type = 'on') {\n if (this.validateType(type)) {\n this.$off(evt)\n let method = this['$' + type]\n this.logger(`($replace)`, evt, callback)\n return Reflect.apply(method, this, [evt, callback, context])\n }\n throw new Error(`${type} is not supported!`)\n }\n\n /**\n * trigger the event\n * @param {string} evt name NOT allow array anymore!\n * @param {mixed} [payload = []] pass to fn\n * @param {object|string} [context = null] overwrite what stored\n * @param {string} [type=false] if pass this then we need to add type to store too\n * @return {number} if it has been execute how many times\n */\n $trigger(evt , payload = [] , context = null, type = false) {\n this.validateEvt(evt)\n let found = 0\n // first check the normal store\n let nStore = this.normalStore\n this.logger('($trigger) normalStore', nStore)\n if (nStore.has(evt)) {\n this.logger(`($trigger) \"${evt}\" found`)\n // @1.8.0 to add the suspend queue\n let added = this.$queue(evt, payload, context, type)\n if (added) {\n this.logger(`($trigger) Currently suspended \"${evt}\" added to queue, nothing executed. Exit now.`)\n return false // not executed\n }\n let nSet = Array.from(nStore.get(evt))\n let ctn = nSet.length\n let hasOnce = false\n let hasOnly = false\n for (let i=0; i < ctn; ++i) {\n ++found;\n // this.logger('found', found)\n let [ _, callback, ctx, type ] = nSet[i]\n this.logger(`($trigger) call run for ${evt}`)\n this.run(callback, payload, context || ctx)\n if (type === 'once' || type === 'onlyOnce') {\n hasOnce = true;\n }\n }\n if (hasOnce) {\n nStore.delete(evt)\n }\n return found\n }\n // now this is not register yet\n this.addToLazyStore(evt, payload, context, type)\n return found\n }\n\n /**\n * this is an alias to the $trigger\n * @NOTE breaking change in V1.6.0 we swap the parameter aroun\n * @NOTE breaking change: v1.9.1 it return an function to accept the params as spread\n * @param {string} evt event name\n * @param {string} type of call\n * @param {object} context what context callback execute in\n * @return {*} from $trigger\n */\n $call(evt, type = false, context = null) {\n const ctx = this\n\n return (...args) => {\n let _args = [evt, args, context, type]\n return Reflect.apply(ctx.$trigger, ctx, _args)\n }\n }\n\n /**\n * remove the evt from all the stores\n * @param {string} evt name\n * @return {boolean} true actually delete something\n */\n $off(evt) {\n // @TODO we will allow a regex pattern to mass remove event\n this.validateEvt(evt)\n let stores = [ this.lazyStore, this.normalStore ]\n\n return !!stores\n .filter(store => store.has(evt))\n .map(store => this.removeFromStore(evt, store))\n .length\n }\n\n /**\n * return all the listener bind to that event name\n * @param {string} evtName event name\n * @param {boolean} [full=false] if true then return the entire content\n * @return {array|boolean} listerner(s) or false when not found\n */\n $get(evt, full = false) {\n // @TODO should we allow the same Regex to search for all?\n this.validateEvt(evt)\n let store = this.normalStore\n return this.findFromStore(evt, store, full)\n }\n\n /**\n * store the return result from the run\n * @param {*} value whatever return from callback\n */\n set $done(value) {\n this.logger('($done) set value: ', value)\n if (this.keep) {\n this.result.push(value)\n } else {\n this.result = value\n }\n }\n\n /**\n * @TODO is there any real use with the keep prop?\n * getter for $done\n * @return {*} whatever last store result\n */\n get $done() {\n this.logger('($done) get result:', this.result)\n if (this.keep) {\n return this.result[this.result.length - 1]\n }\n return this.result\n }\n\n /**\n * Take a look inside the stores\n * @param {number|null} idx of the store, null means all\n * @return {void}\n */\n $debug(idx = null) {\n let names = ['lazyStore', 'normalStore']\n let stores = [this.lazyStore, this.normalStore]\n if (stores[idx]) {\n this.logger(names[idx], stores[idx])\n } else {\n stores.map((store, i) => {\n this.logger(names[i], store)\n })\n }\n }\n}\n","// default\nimport To1sourceEvent from './src/event-service'\n\nexport default To1sourceEvent\n","// this will generate a event emitter and will be use everywhere\nimport EventEmitterClass from '@to1source/event'\n// create a clone version so we know which one we actually is using\nclass JsonqlWsEvt extends EventEmitterClass {\n\n constructor(logger) {\n if (typeof logger !== 'function') {\n throw new Error(`Just die here the logger is not a function!`)\n }\n logger(`---> Create a new EventEmitter <---`)\n // this ee will always come with the logger\n // because we should take the ee from the configuration\n super({ logger })\n }\n\n get name() {\n return'jsonql-ws-client-core'\n }\n}\n\n/**\n * getting the event emitter\n * @param {object} opts configuration\n * @return {object} the event emitter instance\n */\nconst getEventEmitter = opts => {\n const { log, eventEmitter } = opts\n \n if (eventEmitter) {\n log(`eventEmitter is:`, eventEmitter.name)\n return eventEmitter\n }\n \n return new JsonqlWsEvt( opts.log )\n}\n\nexport { \n getEventEmitter, \n EventEmitterClass // for other module to build from \n}\n","// group all the small functions here\nimport { EMIT_REPLY_TYPE } from 'jsonql-constants'\nimport { toArray, createEvt } from 'jsonql-utils/src/generic'\nimport JsonqlValidationError from 'jsonql-errors/src/validation-error'\n\n\n/**\n * WebSocket is strict about the path, therefore we need to make sure before it goes in\n * @param {string} url input url\n * @return {string} url with correct path name\n */\nexport const fixWss = url => {\n const uri = url.toLowerCase()\n if (uri.indexOf('http') > -1) {\n if (uri.indexOf('https') > -1) {\n return uri.replace('https', 'wss')\n }\n return uri.replace('http', 'ws')\n }\n return uri\n}\n\n\n/**\n * get a stock host name from browser\n */\nexport const getHostName = () => {\n try {\n return [window.location.protocol, window.location.host].join('//')\n } catch(e) {\n throw new JsonqlValidationError(e)\n }\n}\n\n/**\n * Unbind the event\n * @param {object} ee EventEmitter\n * @param {string} namespace\n * @return {void}\n */\nexport const clearMainEmitEvt = (ee, namespace) => {\n let nsps = toArray(namespace)\n nsps.forEach(n => {\n ee.$off(createEvt(n, EMIT_REPLY_TYPE))\n })\n}\n\n\n","// take out from the resolver-methods\nimport { \n LOGIN_EVENT_NAME, \n LOGOUT_EVENT_NAME, \n ON_LOGIN_FN_NAME\n} from 'jsonql-constants'\nimport { JsonqlValidationError } from 'jsonql-errors'\nimport { injectToFn, chainFns, isString, objDefineProps, isFunc } from '../utils'\n\n\n/**\n * @TODO this is now become unnecessary because the login is a slave to the\n * http-client - but keep this for now and see what we want to do with it later\n * @UPDATE it might be better if we decoup the two http-client only emit a login event\n * Here should catch it and reload the ws client @TBC\n * break out from createAuthMethods to allow chaining call\n * @param {object} obj the main client object\n * @param {object} opts configuration\n * @param {object} ee event emitter\n * @return {array} [ obj, opts, ee ] what comes in what goes out\n */\nconst setupLoginHandler = (obj, opts, ee) => [ \n injectToFn(obj, opts.loginHandlerName, function loginHandler(token) {\n if (token && isString(token)) {\n opts.log(`Received ${LOGIN_EVENT_NAME} with ${token}`)\n // @TODO add the interceptor hook \n return ee.$trigger(LOGIN_EVENT_NAME, [token])\n }\n // should trigger a global error instead @TODO\n throw new JsonqlValidationError(opts.loginHandlerName, `Unexpected token ${token}`)\n }),\n opts,\n ee\n]\n\n\n/**\n * break out from createAuthMethods to allow chaining call - final in chain\n * @param {object} obj the main client object\n * @param {object} opts configuration\n * @param {object} ee event emitter\n * @return {array} [ obj, opts, ee ] what comes in what goes out\n */\nconst setupLogoutHandler = (obj, opts, ee) => [\n injectToFn(obj, opts.logoutHandlerName, function logoutHandler(...args) {\n ee.$trigger(LOGOUT_EVENT_NAME, args)\n }),\n opts, \n ee\n]\n\n\n/**\n * This event will fire when the socket.io.on('connection') and ws.onopen\n * Plus this will check if it's the private namespace that fired the event\n * @param {object} obj the client itself\n * @param {object} ee Event Emitter\n * @return {array} [ obj, opts, ee] what comes in what goes out\n */\nconst createOnLoginhandler = (obj, opts, ee) => [\n objDefineProps(obj, ON_LOGIN_FN_NAME, function onLoginCallbackHandler(onLoginCallback) {\n if (isFunc(onLoginCallback)) {\n // only one callback can registered with it, TBC\n ee.$only(ON_LOGIN_FN_NAME, onLoginCallback)\n }\n }),\n opts,\n ee \n]\n\n// @TODO future feature setup switch user\n\n\n/**\n * Create auth related methods\n * @param {object} obj the client itself\n * @param {object} opts configuration\n * @param {object} ee Event Emitter\n * @return {array} [ obj, opts, ee ] what comes in what goes out\n */\nexport function createAuthMethods(obj, opts, ee) {\n return chainFns(\n setupLoginHandler, \n setupLogoutHandler,\n createOnLoginhandler\n )(obj, opts, ee)\n}\n","// constants\n\nimport {\n EMIT_REPLY_TYPE,\n JS_WS_SOCKET_IO_NAME,\n JS_WS_NAME,\n ON_MESSAGE_FN_NAME,\n ON_RESULT_FN_NAME\n} from 'jsonql-constants'\n\nconst SOCKET_IO = JS_WS_SOCKET_IO_NAME\nconst WS = JS_WS_NAME\n\nconst AVAILABLE_SERVERS = [SOCKET_IO, WS]\n\nconst SOCKET_NOT_DEFINE_ERR = 'socket is not define in the contract file!'\n\nconst SERVER_NOT_SUPPORT_ERR = 'is not supported server name!'\n\nconst MISSING_PROP_ERR = 'Missing property in contract!'\n\nconst UNKNOWN_CLIENT_ERR = 'Unknown client type!'\n\nconst EMIT_EVT = EMIT_REPLY_TYPE\n\nconst NAMESPACE_KEY = 'namespaceMap'\n\nconst UNKNOWN_RESULT = 'UKNNOWN RESULT!'\n\nconst NOT_ALLOW_OP = 'This operation is not allow!'\n\nconst MY_NAMESPACE = 'myNamespace'\n\nconst CB_FN_NAME = 'on'\n// this is a socket only (for now) feature so we just put it here \nconst DISCONNECTED_ERROR_MSG = `You have disconnected from the socket server, please reconnect.`\n\nexport {\n SOCKET_IO,\n WS,\n AVAILABLE_SERVERS,\n SOCKET_NOT_DEFINE_ERR,\n SERVER_NOT_SUPPORT_ERR,\n MISSING_PROP_ERR,\n UNKNOWN_CLIENT_ERR,\n EMIT_EVT,\n ON_MESSAGE_FN_NAME,\n ON_RESULT_FN_NAME,\n NAMESPACE_KEY,\n UNKNOWN_RESULT,\n NOT_ALLOW_OP,\n MY_NAMESPACE,\n CB_FN_NAME,\n DISCONNECTED_ERROR_MSG\n}\n","// breaking it up further to share between methods\nimport { DATA_KEY, ERROR_KEY } from 'jsonql-constants'\nimport { UNKNOWN_RESULT } from '../options/constants'\nimport { isObjectHasKey } from '../utils'\n\n/**\n * break out to use in different places to handle the return from server\n * @param {object} data from server\n * @param {function} resolver NOT from promise\n * @param {function} rejecter NOT from promise\n * @return {void} nothing\n */\nexport function respondHandler(data, resolver, rejecter) {\n if (isObjectHasKey(data, ERROR_KEY)) {\n // debugFn('-- rejecter called --', data[ERROR_KEY])\n rejecter(data[ERROR_KEY])\n } else if (isObjectHasKey(data, DATA_KEY)) {\n // debugFn('-- resolver called --', data[DATA_KEY])\n resolver(data[DATA_KEY])\n } else {\n // debugFn('-- UNKNOWN_RESULT --', data)\n rejecter({message: UNKNOWN_RESULT, error: data})\n }\n}\n","// the actual trigger call method\nimport { ON_RESULT_FN_NAME, EMIT_REPLY_TYPE } from 'jsonql-constants'\nimport { createEvt, toArray } from '../utils'\nimport { respondHandler } from './respond-handler'\n\n/**\n * just wrapper\n * @param {object} ee EventEmitter\n * @param {string} namespace where this belongs\n * @param {string} resolverName resolver\n * @param {array} args arguments\n * @param {function} log function \n * @return {void} nothing\n */\nexport function actionCall(ee, namespace, resolverName, args = [], log) {\n // reply event \n const outEventName = createEvt(namespace, EMIT_REPLY_TYPE)\n\n log(`actionCall: ${outEventName} --> ${resolverName}`, args)\n // This is the out going call \n ee.$trigger(outEventName, [resolverName, toArray(args)])\n \n // then we need to listen to the event callback here as well\n return new Promise((resolver, rejecter) => {\n const inEventName = createEvt(namespace, resolverName, ON_RESULT_FN_NAME)\n // this cause the onResult got the result back first \n // and it should be the promise resolve first\n // @TODO we need to rewrote the respondHandler to change the problem stated above \n ee.$on(\n inEventName,\n function actionCallResultHandler(result) {\n log(`got the first result`, result)\n respondHandler(result, resolver, rejecter)\n }\n )\n })\n}\n","// setting up the send method \nimport { JsonqlValidationError } from 'jsonql-errors'\nimport {\n ON_ERROR_FN_NAME,\n SEND_MSG_FN_NAME\n} from 'jsonql-constants'\nimport { validateAsync } from 'jsonql-params-validator'\nimport { objDefineProps, createEvt, toArray, nil } from '../utils'\nimport { actionCall } from './action-call'\n\n/** \n * pairing with the server vesrion SEND_MSG_FN_NAME\n * last of the chain so only return the resolver (fn)\n * This is now change to a getter / setter method \n * and call like this: resolver.send(...args)\n * @param {function} fn the resolver function \n * @param {object} ee event emitter instance \n * @param {string} namespace the namespace it belongs to \n * @param {string} resolverName name of the resolver \n * @param {object} params from contract \n * @param {function} log a logger function\n * @return {function} return the resolver itself \n */ \nexport const setupSendMethod = (fn, ee, namespace, resolverName, params, log) => (\n objDefineProps(\n fn, \n SEND_MSG_FN_NAME, \n nil, \n function sendHandler() {\n // let _log = (...args) => Reflect.apply(console.info, console, ['[SEND]'].concat(args))\n /** \n * This will follow the same pattern like the resolver \n * @param {array} args list of unknown argument follow the resolver \n * @return {promise} resolve the result \n */\n return function sendCallback(...args) {\n return validateAsync(args, params.params, true)\n .then(_args => {\n // @TODO check the result \n // because the validation could failed with the list of fail properties \n log(namespace, resolverName, _args)\n return actionCall(ee, namespace, resolverName, _args, _log)\n })\n .catch(err => {\n // @TODO it shouldn't be just a validation error \n // it could be server return error, so we need to check \n // what error we got back here first \n log('send error', err)\n // @TODO it might not an validation error need the finalCatch here\n ee.$call(\n createEvt(namespace, resolverName, ON_ERROR_FN_NAME),\n [new JsonqlValidationError(resolverName, err)]\n )\n })\n } \n })\n)\n","// break up the original setup resolver method here\n// import { JsonqlValidationError, finalCatch } from 'jsonql-errors'\nimport {\n ON_ERROR_FN_NAME,\n ON_MESSAGE_FN_NAME,\n ON_RESULT_FN_NAME\n} from 'jsonql-constants'\n// local \nimport { MY_NAMESPACE } from '../options/constants'\nimport { chainFns, objDefineProps, injectToFn, createEvt, isFunc } from '../utils'\nimport { respondHandler } from './respond-handler'\nimport { setupSendMethod } from './setup-send-method'\n\n/**\n * The first one in the chain, just setup a namespace prop\n * the rest are passing through\n * @param {function} fn the resolver function\n * @param {object} ee the event emitter \n * @param {string} resolverName what it said\n * @param {object} params for resolver from contract\n * @param {function} log the logger function\n * @return {array}\n */\nconst setupNamespace = (fn, ee, namespace, resolverName, params, log) => [\n injectToFn(fn, MY_NAMESPACE, namespace),\n ee,\n namespace,\n resolverName,\n params,\n log \n]\n\n/** \n * onResult handler\n */ \nconst setupOnResult = (fn, ee, namespace, resolverName, params, log) => [\n objDefineProps(fn, ON_RESULT_FN_NAME, function(resultCallback) {\n if (isFunc(resultCallback)) {\n ee.$on(\n createEvt(namespace, resolverName, ON_RESULT_FN_NAME),\n function resultHandler(result) {\n respondHandler(result, resultCallback, (error) => {\n log(`Catch error: \"${resolverName}\"`, error)\n ee.$trigger(\n createEvt(namespace, resolverName, ON_ERROR_FN_NAME), \n error\n )\n })\n }\n )\n }\n }),\n ee,\n namespace,\n resolverName,\n params,\n log\n]\n\n/** \n * we do need to add the send prop back because it's the only way to deal with\n * bi-directional data stream \n */\nconst setupOnMessage = (fn, ee, namespace, resolverName, params, log) => [\n objDefineProps(fn, ON_MESSAGE_FN_NAME, function(messageCallback) {\n // we expect this to be a function\n if (isFunc(messageCallback)) {\n // did that add to the callback\n let onMessageCallback = (args) => {\n respondHandler(args, messageCallback, (error) => {\n log(`Catch error: \"${resolverName}\"`, error)\n ee.$trigger(\n createEvt(namespace, resolverName, ON_ERROR_FN_NAME), \n error\n )\n })\n }\n // register the handler for this message event\n ee.$only(\n createEvt(namespace, resolverName, ON_MESSAGE_FN_NAME), \n onMessageCallback\n )\n }\n }),\n ee,\n namespace,\n resolverName,\n params,\n log\n]\n\n/** \n * ON_ERROR_FN_NAME handler\n */\nconst setupOnError = (fn, ee, namespace, resolverName, params, log) => [\n objDefineProps(fn, ON_ERROR_FN_NAME, function(resolverErrorHandler) {\n if (isFunc(resolverErrorHandler)) {\n // please note ON_ERROR_FN_NAME can add multiple listners\n ee.$only(\n createEvt(namespace, resolverName, ON_ERROR_FN_NAME), \n resolverErrorHandler\n )\n }\n }),\n ee,\n namespace,\n resolverName,\n params,\n log\n]\n\n/**\n * Add extra property / listeners to the resolver\n * @param {string} namespace where this belongs\n * @param {string} resolverName name as event name\n * @param {object} params from contract\n * @param {function} fn resolver function\n * @param {object} ee EventEmitter\n * @param {function} log function \n * @return {function} resolver\n */\nexport function setupResolver(namespace, resolverName, params, fn, ee, log) {\n let fns = [\n setupNamespace, \n setupOnResult, \n setupOnMessage, \n setupOnError, \n setupSendMethod\n ]\n \n // get the executor\n const executor = Reflect.apply(chainFns, null, fns)\n const args = [fn, ee, namespace, resolverName, params, log]\n\n return Reflect.apply(executor, null, args)\n}\n","// put all the resolver related methods here to make it more clear\n\n// this will be a mini client server architect\n// The reason is when the enableAuth setup - the private route\n// might not be validated, but we need the callable point is ready\n// therefore this part will always take the contract and generate\n// callable api for the developer to setup their front end\n// the only thing is - when they call they might get an error or\n// NOT_LOGIN_IN and they can react to this error accordingly\nimport { finalCatch } from 'jsonql-errors'\nimport { validateAsync } from 'jsonql-params-validator'\nimport { setupResolver } from './setup-resolver'\nimport { actionCall } from './action-call'\nimport {\n createEvt,\n objDefineProps,\n isFunc,\n injectToFn\n} from '../utils'\nimport {\n ON_ERROR_FN_NAME,\n ON_READY_FN_NAME\n} from 'jsonql-constants'\n\n/**\n * create the actual function to send message to server\n * @param {object} ee EventEmitter instance\n * @param {string} namespace this resolver end point\n * @param {string} resolverName name of resolver as event name\n * @param {object} params from contract\n * @param {function} log pass the log function\n * @return {function} resolver\n */\nfunction createResolver(ee, namespace, resolverName, params, log) {\n // note we pass the new withResult=true option\n return function resolver(...args) {\n return validateAsync(args, params.params, true)\n .then(_args => actionCall(ee, namespace, resolverName, _args, log))\n .catch(finalCatch)\n }\n}\n\n/**\n * step one get the clientmap with the namespace\n * @param {object} opts configuration\n * @param {object} ee EventEmitter\n * @param {object} nspGroup resolvers index by their namespace\n * @return {promise} resolve the clientmapped, and start the chain\n */\nexport function generateResolvers(opts, ee, nspGroup) {\n let client= {}\n let { log } = opts\n\n for (let namespace in nspGroup) {\n let list = nspGroup[namespace]\n for (let resolverName in list) {\n // resolverNames.push(resolverName)\n let params = list[resolverName]\n let fn = createResolver(ee, namespace, resolverName, params, log)\n // this should set as a getter therefore can not be overwrite by accident\n // obj[resolverName] = setupResolver(namespace, resolverName, params, fn, ee)\n client = injectToFn(\n client,\n resolverName,\n setupResolver(namespace, resolverName, params, fn, ee, log)\n )\n }\n }\n // resolve the clientto start the chain\n // chain the result to allow the chain processing\n return [ client, opts, ee, nspGroup ]\n}\n\n/**\n * The problem is the namespace can have more than one\n * and we only have on onError message\n * @param {object} clientthe client itself\n * @param {object} opts configuration\n * @param {object} ee Event Emitter\n * @param {object} nspGroup namespace keys\n * @return {array} [obj, opts, ee]\n */\nexport function createNamespaceErrorListener(client, opts, ee, nspGroup) {\n return [\n objDefineProps(\n client,\n ON_ERROR_FN_NAME,\n function namespaceErrorCallbackHandler(namespaceErrorHandler) {\n if (isFunc(namespaceErrorHandler)) {\n // please note ON_ERROR_FN_NAME can add multiple listners\n for (let namespace in nspGroup) {\n // this one is very tricky, we need to make sure the trigger is calling\n // with the namespace as well as the error\n ee.$on(createEvt(namespace, ON_ERROR_FN_NAME), namespaceErrorHandler)\n }\n }\n }\n ),\n opts,\n ee\n ]\n}\n\n/**\n * This event will fire when the socket.io.on('connection') and ws.onopen\n * @param {object} client client itself\n * @param {object} opts configuration\n * @param {object} ee Event Emitter\n * @return {array} [ obj, opts, ee ]\n */\nexport function createOnReadyListener(client, opts, ee) {\n return [\n objDefineProps(\n client,\n ON_READY_FN_NAME,\n function onReadyCallbackHandler(onReadyCallback) {\n if (isFunc(onReadyCallback)) {\n // reduce it down to just one flat level\n // @2020-03-19 only allow ONE onReady callback otherwise\n // it will get fire multiple times which is not what we want \n ee.$only(ON_READY_FN_NAME, onReadyCallback)\n }\n }\n ),\n opts,\n ee\n ]\n}\n","// resolvers generator\n// we change the interface to return promise from v1.0.3\n// this way we make sure the obj return is correct and timely\nimport { chainFns } from '../utils'\nimport { createAuthMethods } from './setup-auth-methods'\nimport {\n generateResolvers,\n createOnReadyListener,\n createNamespaceErrorListener\n} from './generator-methods'\n\nimport {\n NSP_GROUP\n} from 'jsonql-constants'\n\n/**\n * prepare the methods\n * @param {object} opts configuration\n * @param {object} nspMap resolvers index by their namespace\n * @param {object} ee EventEmitter\n * @return {object} of resolvers\n * @public\n */\nexport function callersGenerator(opts, nspMap, ee) {\n let fns = [\n generateResolvers,\n createOnReadyListener,\n createNamespaceErrorListener\n ]\n if (opts.enableAuth) {\n fns.push(createAuthMethods)\n }\n // we will always get back the [ obj, opts, ee ]\n // then we only return the obj (wsClient)\n // This has move outside of here, into the main method\n // the reason is we could switch around the sequence much easier\n // fns.push(setupFinalStep)\n // run it\n const generator = Reflect.apply(chainFns, null, fns)\n\n return generator(opts, ee, nspMap[NSP_GROUP])\n}\n","// this is a new method that will create several \n// intercom method also reverse listen to the server \n// such as disconnect (server issue disconnect)\nimport { injectToFn } from '../utils'\nimport { DISCONNECT_EVENT_NAME } from 'jsonql-constants'\n\n/**\n * this is the new method that setup the intercom handler \n * also this serve as the final call in the then chain to \n * output the client\n * @param {object} client the client \n * @param {object} opts configuration \n * @param {object} ee the event emitter\n * @return {object} client \n */\nexport function setupInterCom(client, opts, ee) {\n const { disconnectHandlerName } = opts\n return injectToFn(client, disconnectHandlerName, function disconnectHandler(...args) {\n ee.$trigger(DISCONNECT_EVENT_NAME, args)\n })\n} ","// The final step of the setup before it returns the client\nimport { setupInterCom } from './setup-intercom'\n\n/**\n * The final step to return the client\n * @param {object} client the client\n * @param {object} opts configuration\n * @param {object} ee the event emitter\n * @return {object} client\n */\nfunction setupFinalStep(obj, opts, ee) {\n const client = setupInterCom(obj, opts, ee)\n opts.log(`---> The final step to return the ws-client <---`)\n // add some debug functions\n client.verifyEventEmitter = () => ee.is\n // we add back the two things into the client\n // then when we do integration, we run it in reverse,\n // create the ws client first then the host client\n client.eventEmitter = opts.eventEmitter\n client.log = opts.log\n // we just inject a helloWorld method here\n // client[HELLO_FN] =\n\n return client\n}\n\n\nexport { setupFinalStep }\n","// create options\nimport {\n checkConfigAsync,\n checkConfig\n} from 'jsonql-params-validator'\nimport {\n wsCoreCheckMap,\n wsCoreConstProps,\n socketCheckMap\n} from './defaults'\nimport {\n fixWss,\n getHostName,\n getEventEmitter,\n getNspInfoByConfig,\n getLogFn\n} from '../utils'\n\n/**\n * We need this to find the socket server type\n * @param {*} config\n * @return {string} the name of the socket server if any\n */\nfunction checkSocketClientType(config) {\n return checkConfig(config, socketCheckMap)\n}\n\n/**\n * Create a combine checkConfig for the creating the combine client\n * @param {*} configCheckMap\n * @param {*} constProps\n * @return {function} takes the user input config then resolve the configuration\n */\nfunction createCombineConfigCheck(configCheckMap, constProps) {\n const combineCheckMap = Object.assign({}, configCheckMap, wsCoreCheckMap)\n const combineConstProps = Object.assign({}, constProps, wsCoreConstProps)\n return config => checkConfigAsync(config, combineCheckMap, combineConstProps)\n}\n\n\n/**\n * wrapper method to check this already did the pre check\n * @param {object} config user supply config\n * @param {object} defaultOptions for checking\n * @param {object} constProps user supply const props\n * @return {promise} resolve to the checked opitons\n */\nfunction checkConfiguration(config, defaultOptions, constProps) {\n const defaultCheckMap= Object.assign(wsCoreCheckMap, defaultOptions)\n const wsConstProps = Object.assign(wsCoreConstProps, constProps)\n\n return checkConfigAsync(config, defaultCheckMap, wsConstProps)\n}\n\n/**\n * Taking the `then` part from the method below\n * @param {object} opts\n * @return {promise} opts all done\n */\nfunction postCheckInjectOpts(opts) {\n return Promise.resolve(opts)\n .then(opts => {\n if (!opts.hostname) {\n opts.hostname = getHostName()\n }\n // @TODO the contract now will supply the namespace information\n // and we need to use that to group the namespace call\n opts.wssPath = fixWss([opts.hostname, opts.namespace].join('/'), opts.serverType)\n // get the log function here\n opts.log = getLogFn(opts)\n\n opts.eventEmitter = getEventEmitter(opts)\n\n return opts\n })\n}\n\n/**\n * Don't want to make things confusing\n * Breaking up the opts process in one place\n * then generate the necessary parameter in another step\n * @2020-3-20 here we suspend operation by it's namespace first\n * Then in the framework part, after the connection establish we release\n * the queue\n * @param {object} opts checked --> merge --> injected\n * @return {object} {opts, nspMap, ee}\n */\nfunction createRequiredParams(opts) {\n const nspMap = getNspInfoByConfig(opts)\n const ee = opts.eventEmitter\n // @TODO here we are going to add suspend event to the namespace related methods\n \n\n return { opts, nspMap, ee }\n}\n\nexport {\n // properties\n wsCoreCheckMap,\n wsCoreConstProps,\n // functions\n checkConfiguration,\n postCheckInjectOpts,\n createRequiredParams,\n // this will just get export for integration\n checkSocketClientType,\n createCombineConfigCheck\n}\n","// the top level API\n// The goal is to create a generic method that will able to handle\n// any kind of clients\n// import { injectToFn } from 'jsonql-utils'\nimport {\n callersGenerator,\n setupFinalStep\n} from './callers'\nimport {\n checkConfiguration,\n postCheckInjectOpts,\n createRequiredParams\n} from './options'\n\n\n/**\n * 0.5.0 we break up the wsClientCore in two parts one without the config check\n * @param {function} socketClientListener\n * @return {function} to actually generate the client\n */\nexport function wsClientCoreAction(socketClientListener) {\n /**\n * This is a breaking change, to continue the onion skin design\n * @param {object} config the already checked config\n * @return {promise} resolve the client\n */\n return (config = {}) => {\n\n return postCheckInjectOpts(config)\n // the following two moved to wsPostConfig\n .then(createRequiredParams)\n .then(\n ({opts, nspMap, ee}) => socketClientListener(opts, nspMap, ee)\n )\n .then( // there is problem here, we wrap up the operation inside\n ({opts, nspMap, ee}) => callersGenerator(opts, nspMap, ee)\n )\n .then(setupFinalStep)\n .catch(err => {\n console.error(`jsonql-ws-core-client init error`, err)\n })\n }\n}\n\n/**\n * The main interface which will generate the socket clients and map all events\n * @param {object} socketClientListerner this is the one method export by various clients\n * @param {object} [configCheckMap={}] we should do all the checking in the core instead of the client\n * @param {object} [constProps={}] add this to supply the constProps from the downstream client\n * @return {function} accept a config then return the wsClient instance with all the available API\n */\nexport function wsClientCore(socketClientListener, configCheckMap = {}, constProps = {}) {\n // we need to inject property to this client later\n return (config = {}) => checkConfiguration(config, configCheckMap, constProps)\n .then(\n wsClientCoreAction(socketClientListener)\n )\n}\n","// this is getting too confusing \n// therefore we move it back to the framework specific \n\n/**\n * wrapper method to create a nsp without login\n * @param {string|boolean} namespace namespace url could be false\n * @param {object} opts configuration\n * @return {object} ws client instance\n */\nfunction createNspClient(namespace, opts) {\n const { hostname, wssPath, wsOptions, nspClient, log } = opts\n const url = namespace ? [hostname, namespace].join('/') : wssPath\n log(`createNspClient --> `, url)\n\n return nspClient(url, wsOptions)\n}\n\n/**\n * wrapper method to create a nsp with token auth\n * @param {string} namespace namespace url\n * @param {object} opts configuration\n * @return {object} ws client instance\n */\nfunction createNspAuthClient(namespace, opts) {\n const { hostname, wssPath, token, wsOptions, nspAuthClient, log } = opts\n const url = namespace ? [hostname, namespace].join('/') : wssPath\n \n log(`createNspAuthClient -->`, url)\n\n if (token && typeof token !== 'string') {\n throw new Error(`Expect token to be string, but got ${token}`)\n }\n \n return nspAuthClient(url, token, wsOptions)\n}\n\nexport {\n createNspClient,\n createNspAuthClient\n}\n","// this use by client-event-handler\nimport { ON_ERROR_FN_NAME } from 'jsonql-constants'\nimport { createEvt } from '../utils'\n\n/**\n * trigger errors on all the namespace onError handler\n * @param {object} ee Event Emitter\n * @param {array} namespaces nsps string\n * @param {string} message optional\n * @return {void}\n */\nexport function triggerNamespacesOnError(ee, namespaces, message) {\n namespaces.forEach( namespace => {\n ee.$trigger(\n createEvt(namespace, ON_ERROR_FN_NAME), \n [{ message, namespace }]\n )\n })\n}\n\n/**\n * Handle the onerror callback \n * @param {object} ee event emitter \n * @param {string} namespace which namespace has error \n * @param {*} err error object\n * @return {void} \n */\nexport const handleNamespaceOnError = (ee, namespace, err) => {\n ee.$trigger(createEvt(namespace, ON_ERROR_FN_NAME), [err])\n}","// NOT IN USE AT THE MOMENT JUST KEEP IT HERE FOR THE TIME BEING \nimport {\n LOGOUT_EVENT_NAME,\n NOT_LOGIN_ERR_MSG,\n ON_ERROR_FN_NAME,\n ON_RESULT_FN_NAME,\n DISCONNECT_EVENT_NAME\n} from 'jsonql-constants'\nimport { EMIT_EVT, DISCONNECTED_ERROR_MSG } from '../options/constants'\nimport { createEvt, clearMainEmitEvt } from '../utils'\nimport { triggerNamespacesOnError } from './trigger-namespaces-on-error'\n\n/**\n * Only when there is a private namespace then we bind to this event\n * @param {object} nsps the available nsp(s)\n * @param {array} namespaces available namespace \n * @param {object} ee eventEmitter \n * @param {object} opts configuration\n * @return {void}\n */\nexport const logoutEvtListener = (nsps, namespaces, ee, opts) => {\n const { log } = opts \n // this will be available regardless enableAuth\n // because the server can log the client out\n ee.$on(\n LOGOUT_EVENT_NAME, \n function logoutEvtCallback() {\n const privateNamespace = getPrivateNamespace(namespaces)\n log(`${LOGOUT_EVENT_NAME} event triggered`)\n // disconnect(nsps, opts.serverType)\n // we need to issue error to all the namespace onError Listerner\n triggerNamespacesOnError(ee, [privateNamespace], LOGOUT_EVENT_NAME)\n // rebind all of the Listerner to the fake one\n log(`logout from ${privateNamespace}`)\n\n clearMainEmitEvt(ee, privateNamespace)\n // we need to issue one more call to the server before we disconnect\n // now this is a catch 22, here we are not suppose to do anything platform specific\n // so that should fire before trigger this event\n // clear out the nsp\n nsps[privateNamespace] = null \n // add a NOT LOGIN error if call\n notLoginWsListerner(privateNamespace, ee, opts)\n }\n )\n}\n\n/**\n * A Event Listerner placeholder when it's not connect to any nsp\n * @param {string} namespace nsp\n * @param {object} ee EventEmitter\n * @param {object} opts configuration\n * @return {void}\n */\nexport const notConnectedListener = (namespace, ee, opts) => {\n const { log } = opts \n\n ee.$only(\n createEvt(namespace, EMIT_EVT),\n function disconnectedEvtCallback(resolverName, args) {\n log(`[disconnectedListerner] hijack the ws call`, namespace, resolverName, args)\n const error = {\n message: DISCONNECTED_ERROR_MSG\n }\n ee.$call(createEvt(namespace, resolverName, ON_ERROR_FN_NAME), [ error ])\n // also trigger the result Listerner, but wrap inside the error key\n ee.$call(createEvt(namespace, resolverName, ON_RESULT_FN_NAME), [{ error }])\n }\n )\n}\n\n\n/**\n * The disconnect event Listerner, now we log the client out from everything\n * @TODO now we are another problem they disconnect, how to reconnect\n * @param {object} nsps the available nsp(s)\n * @param {array} namespaces available namespace \n * @param {object} ee eventEmitter \n * @param {object} opts configuration\n * @return {void}\n */\nexport const disconnectListener = (nsps, namespaces, ee, opts) => {\n const { log } = opts \n ee.$on(\n DISCONNECT_EVENT_NAME, \n function disconnectEvtCallback() {\n triggerNamespacesOnError(ee, namespaces, DISCONNECT_EVENT_NAME)\n namespaces.forEach( namespace => { \n log(`disconnect from ${namespace}`)\n\n clearMainEmitEvt(ee, namespace)\n nsps[namespace] = null \n disconnectedListerner(namespace, ee, opts)\n })\n }\n )\n}\n\n/**\n * A Event Listerner placeholder when it's not connect to the private nsp\n * @param {string} namespace nsp\n * @param {object} ee EventEmitter\n * @param {object} opts configuration\n * @return {void}\n */\nexport const notLoginListener = (namespace, ee, opts) => {\n const { log } = opts \n\n ee.$only(\n createEvt(namespace, EMIT_EVT),\n function notLoginListernerCallback(resolverName, args) {\n log('[notLoginListerner] hijack the ws call', namespace, resolverName, args)\n const error = { message: NOT_LOGIN_ERR_MSG }\n // It should just throw error here and should not call the result\n // because that's channel for handling normal event not the fake one\n ee.$call(createEvt(namespace, resolverName, ON_ERROR_FN_NAME), [ error ])\n // also trigger the result Listerner, but wrap inside the error key\n ee.$call(createEvt(namespace, resolverName, ON_RESULT_FN_NAME), [{ error }])\n }\n )\n}","// This is share between different clients so we export it\n// @TODO port what is in the ws-main-handler\n// because all the client side call are via the ee\n// and that makes it re-usable between different client setup\n\n/*\nInside the map call but we take it out for now and until the WebSocket version is fully working\nimport { SOCKET_IO } from '../options/constants'\n // @TODO need to double check this\n if (opts.serverType === SOCKET_IO) {\n let { nspGroup } = nspMap\n args.push(nspGroup[namespace])\n }\n*/\nimport { getPrivateNamespace } from 'jsonql-utils/src/namespace'\nimport { logoutEvtListener, notLoginListener } from './event-listeners'\n\n\n/**\n * centralize all the comm in one place\n * @param {function} bindSocketEventHandler binding the ee to ws --> this is the core bit\n * @param {object} nsps namespaced nsp\n * @return {void} nothing\n */\nexport function clientEventListener(bindSocketEventListener, nsps) {\n /**\n * BREAKING CHANGE instead of one flat structure\n * we return a function to accept the two \n * @param {object} opts configuration\n * @param {object} nspMap this is not in the opts \n * @param {object} ee Event Emitter instance\n * @return {array} although we return something but this is the last step and nothing to do further\n */\n return (opts, nspMap, ee) => {\n // since all these params already in the opts\n const { log } = opts\n const { namespaces } = nspMap\n // @1.1.3 add isPrivate prop to id which namespace is the private nsp\n // then we can use this prop to determine if we need to fire the ON_LOGIN_PROP_NAME event\n const privateNamespace = getPrivateNamespace(namespaces)\n \n return namespaces.map(namespace => {\n let isPrivate = privateNamespace === namespace\n log(namespace, ` --> ${isPrivate ? 'private': 'public'} nsp --> `, nsps[namespace] !== false)\n if (nsps[namespace]) {\n log('[call bindWsHandler]', isPrivate, namespace)\n\n let args = [namespace, nsps[namespace], ee, isPrivate, opts]\n // Finally we binding everything together\n Reflect.apply(bindSocketEventListener, null, args)\n\n } else {\n log(`binding notLoginWsHandler to ${namespace}`)\n // a dummy placeholder\n // @TODO but it should be a not connect handler \n // when it's not login (or fail) this should be handle differently \n notLoginListener(namespace, ee, opts)\n }\n if (isPrivate) {\n log(`Has private and add logoutEvtHandler`)\n logoutEvtListener(nsps, namespaces, ee, opts)\n }\n // just return something its not going to get use anywhere\n return isPrivate \n })\n }\n}\n","// jsonql-ws-core takes over the check configuration\n// here we only have to supply the options that is unique to this client\n// create options\nimport { JS_WS_NAME } from 'jsonql-constants'\n// constant props\nconst wsClientConstProps = {\n version: '__PLACEHOLDER__', // will get replace\n serverType: JS_WS_NAME\n}\n\nexport { wsClientConstProps }\n","// pass the different type of ws to generate the client\n// this is where the framework specific code get injected\nimport { TOKEN_PARAM_NAME } from 'jsonql-constants'\nimport { fixWss } from '../modules'\nimport {\n createInitPing, \n extractPingResult\n} from '../modules'\n\n/**\n * Group the ping and get respond create new client in one\n * @param {object} ws \n * @param {object} WebSocket \n * @param {string} url\n * @param {function} resolver \n * @param {function} rejecter \n * @param {boolean} auth client or not\n * @return {promise} resolve the confirm client\n */\nfunction initPingAction(ws, WebSocket, url, resolver, rejecter, wsOptions) {\n // @TODO how to we id this client can issue a CSRF\n // by origin? \n ws.onopen = function onOpenCallback() {\n ws.send(createInitPing())\n }\n\n ws.onmessage = function onMessageCallback(payload) {\n try {\n const header = extractPingResult(payload.data)\n // @NOTE the break down test in ws-client-core show no problems\n // the problem was cause by malform nspInfo that time? \n setTimeout(() => { // delay or not show no different but just on the safe side\n ws.terminate()\n }, 50)\n const newWs = new WebSocket(url, Object.assign(wsOptions, header)) \n resolver(newWs) \n } catch(e) {\n rejecter(e)\n }\n }\n\n ws.onerror = function onErrorCallback(err) {\n rejecter(err)\n }\n}\n\n/**\n * less duplicated code the better \n * @param {object} WebSocket \n * @param {string} url formatted url\n * @param {object} options or not\n * @return {promise} resolve the actual verified client\n */\nfunction asyncConnect(WebSocket, url, options) {\n \n return new Promise((resolver, rejecter) => { \n \n const unconfirmClient = new WebSocket(url, options)\n \n initPingAction(unconfirmClient, WebSocket, url, resolver, rejecter, options)\n })\n}\n\n\n/**\n * The bug was in the wsOptions where ws don't need it but socket.io do\n * therefore the object was pass as second parameter!\n * @NOTE here we only return a method to create the client, it might not get call \n * @param {object} WebSocket the client or node version of ws\n * @param {boolean} auth if it's auth then 3 param or just one\n * @param {object} opts this is a breaking change we will init the client twice\n */\nfunction initWebSocketClient(WebSocket, auth, log) {\n if (auth === false) {\n /**\n * Create a non-protected client\n * @param {string} url \n * @param {object} [wsOptions={}]\n * @return {promise} resolve to the confirmed client\n */\n return function createWsClient(url, wsOptions = {}) {\n const _url = fixWss(url)\n log(`nspClient: \\n${_url}\\n`, wsOptions)\n\n return asyncConnect(WebSocket, _url, wsOptions)\n }\n }\n\n /**\n * Create a client with auth token\n * @param {string} url start with ws:// @TODO check this?\n * @param {string} token the jwt token\n * @param {object} [wsOptions={}] extra options pass to the WebSocket object\n * @return {object} ws instance\n */\n return function createWsAuthClient(url, token, wsOptions = {}) {\n const ws_url = fixWss(url)\n // console.log('what happen here?', url, ws_url, token)\n const _url = token && typeof token === 'string' ? `${ws_url}?${TOKEN_PARAM_NAME}=${token}` : ws_url\n log(`nspAuthClient: \\n${_url}\\n`, wsOptions)\n\n return asyncConnect(WebSocket, _url, wsOptions)\n }\n}\n\nexport { initWebSocketClient }","/** Used for built-in method references. */\nvar objectProto = Object.prototype;\n\n/**\n * Used to resolve the\n * [`toStringTag`](http://ecma-international.org/ecma-262/7.0/#sec-object.prototype.tostring)\n * of values.\n */\nvar nativeObjectToString = objectProto.toString;\n\n/**\n * Converts `value` to a string using `Object.prototype.toString`.\n *\n * @private\n * @param {*} value The value to convert.\n * @returns {string} Returns the converted string.\n */\nfunction objectToString(value) {\n return nativeObjectToString.call(value);\n}\n\nexport default objectToString;\n","/**\n * Creates a unary function that invokes `func` with its argument transformed.\n *\n * @private\n * @param {Function} func The function to wrap.\n * @param {Function} transform The argument transform.\n * @returns {Function} Returns the new function.\n */\nfunction overArg(func, transform) {\n return function(arg) {\n return func(transform(arg));\n };\n}\n\nexport default overArg;\n","/**\n * Checks if `value` is object-like. A value is object-like if it's not `null`\n * and has a `typeof` result of \"object\".\n *\n * @static\n * @memberOf _\n * @since 4.0.0\n * @category Lang\n * @param {*} value The value to check.\n * @returns {boolean} Returns `true` if `value` is object-like, else `false`.\n * @example\n *\n * _.isObjectLike({});\n * // => true\n *\n * _.isObjectLike([1, 2, 3]);\n * // => true\n *\n * _.isObjectLike(_.noop);\n * // => false\n *\n * _.isObjectLike(null);\n * // => false\n */\nfunction isObjectLike(value) {\n return value != null && typeof value == 'object';\n}\n\nexport default isObjectLike;\n","/**\n * Removes all key-value entries from the list cache.\n *\n * @private\n * @name clear\n * @memberOf ListCache\n */\nfunction listCacheClear() {\n this.__data__ = [];\n this.size = 0;\n}\n\nexport default listCacheClear;\n","/**\n * Performs a\n * [`SameValueZero`](http://ecma-international.org/ecma-262/7.0/#sec-samevaluezero)\n * comparison between two values to determine if they are equivalent.\n *\n * @static\n * @memberOf _\n * @since 4.0.0\n * @category Lang\n * @param {*} value The value to compare.\n * @param {*} other The other value to compare.\n * @returns {boolean} Returns `true` if the values are equivalent, else `false`.\n * @example\n *\n * var object = { 'a': 1 };\n * var other = { 'a': 1 };\n *\n * _.eq(object, object);\n * // => true\n *\n * _.eq(object, other);\n * // => false\n *\n * _.eq('a', 'a');\n * // => true\n *\n * _.eq('a', Object('a'));\n * // => false\n *\n * _.eq(NaN, NaN);\n * // => true\n */\nfunction eq(value, other) {\n return value === other || (value !== value && other !== other);\n}\n\nexport default eq;\n","/**\n * Removes `key` and its value from the stack.\n *\n * @private\n * @name delete\n * @memberOf Stack\n * @param {string} key The key of the value to remove.\n * @returns {boolean} Returns `true` if the entry was removed, else `false`.\n */\nfunction stackDelete(key) {\n var data = this.__data__,\n result = data['delete'](key);\n\n this.size = data.size;\n return result;\n}\n\nexport default stackDelete;\n","/**\n * Gets the stack value for `key`.\n *\n * @private\n * @name get\n * @memberOf Stack\n * @param {string} key The key of the value to get.\n * @returns {*} Returns the entry value.\n */\nfunction stackGet(key) {\n return this.__data__.get(key);\n}\n\nexport default stackGet;\n","/**\n * Checks if a stack value for `key` exists.\n *\n * @private\n * @name has\n * @memberOf Stack\n * @param {string} key The key of the entry to check.\n * @returns {boolean} Returns `true` if an entry for `key` exists, else `false`.\n */\nfunction stackHas(key) {\n return this.__data__.has(key);\n}\n\nexport default stackHas;\n","/**\n * Checks if `value` is the\n * [language type](http://www.ecma-international.org/ecma-262/7.0/#sec-ecmascript-language-types)\n * of `Object`. (e.g. arrays, functions, objects, regexes, `new Number(0)`, and `new String('')`)\n *\n * @static\n * @memberOf _\n * @since 0.1.0\n * @category Lang\n * @param {*} value The value to check.\n * @returns {boolean} Returns `true` if `value` is an object, else `false`.\n * @example\n *\n * _.isObject({});\n * // => true\n *\n * _.isObject([1, 2, 3]);\n * // => true\n *\n * _.isObject(_.noop);\n * // => true\n *\n * _.isObject(null);\n * // => false\n */\nfunction isObject(value) {\n var type = typeof value;\n return value != null && (type == 'object' || type == 'function');\n}\n\nexport default isObject;\n","/** Used for built-in method references. */\nvar funcProto = Function.prototype;\n\n/** Used to resolve the decompiled source of functions. */\nvar funcToString = funcProto.toString;\n\n/**\n * Converts `func` to its source code.\n *\n * @private\n * @param {Function} func The function to convert.\n * @returns {string} Returns the source code.\n */\nfunction toSource(func) {\n if (func != null) {\n try {\n return funcToString.call(func);\n } catch (e) {}\n try {\n return (func + '');\n } catch (e) {}\n }\n return '';\n}\n\nexport default toSource;\n","/**\n * Gets the value at `key` of `object`.\n *\n * @private\n * @param {Object} [object] The object to query.\n * @param {string} key The key of the property to get.\n * @returns {*} Returns the property value.\n */\nfunction getValue(object, key) {\n return object == null ? undefined : object[key];\n}\n\nexport default getValue;\n","/**\n * Removes `key` and its value from the hash.\n *\n * @private\n * @name delete\n * @memberOf Hash\n * @param {Object} hash The hash to modify.\n * @param {string} key The key of the value to remove.\n * @returns {boolean} Returns `true` if the entry was removed, else `false`.\n */\nfunction hashDelete(key) {\n var result = this.has(key) && delete this.__data__[key];\n this.size -= result ? 1 : 0;\n return result;\n}\n\nexport default hashDelete;\n","/**\n * Checks if `value` is suitable for use as unique object key.\n *\n * @private\n * @param {*} value The value to check.\n * @returns {boolean} Returns `true` if `value` is suitable, else `false`.\n */\nfunction isKeyable(value) {\n var type = typeof value;\n return (type == 'string' || type == 'number' || type == 'symbol' || type == 'boolean')\n ? (value !== '__proto__')\n : (value === null);\n}\n\nexport default isKeyable;\n","/**\n * Creates a base function for methods like `_.forIn` and `_.forOwn`.\n *\n * @private\n * @param {boolean} [fromRight] Specify iterating from right to left.\n * @returns {Function} Returns the new base function.\n */\nfunction createBaseFor(fromRight) {\n return function(object, iteratee, keysFunc) {\n var index = -1,\n iterable = Object(object),\n props = keysFunc(object),\n length = props.length;\n\n while (length--) {\n var key = props[fromRight ? length : ++index];\n if (iteratee(iterable[key], key, iterable) === false) {\n break;\n }\n }\n return object;\n };\n}\n\nexport default createBaseFor;\n","/**\n * Copies the values of `source` to `array`.\n *\n * @private\n * @param {Array} source The array to copy values from.\n * @param {Array} [array=[]] The array to copy values to.\n * @returns {Array} Returns `array`.\n */\nfunction copyArray(source, array) {\n var index = -1,\n length = source.length;\n\n array || (array = Array(length));\n while (++index < length) {\n array[index] = source[index];\n }\n return array;\n}\n\nexport default copyArray;\n","/** Used for built-in method references. */\nvar objectProto = Object.prototype;\n\n/**\n * Checks if `value` is likely a prototype object.\n *\n * @private\n * @param {*} value The value to check.\n * @returns {boolean} Returns `true` if `value` is a prototype, else `false`.\n */\nfunction isPrototype(value) {\n var Ctor = value && value.constructor,\n proto = (typeof Ctor == 'function' && Ctor.prototype) || objectProto;\n\n return value === proto;\n}\n\nexport default isPrototype;\n","/**\n * Checks if `value` is classified as an `Array` object.\n *\n * @static\n * @memberOf _\n * @since 0.1.0\n * @category Lang\n * @param {*} value The value to check.\n * @returns {boolean} Returns `true` if `value` is an array, else `false`.\n * @example\n *\n * _.isArray([1, 2, 3]);\n * // => true\n *\n * _.isArray(document.body.children);\n * // => false\n *\n * _.isArray('abc');\n * // => false\n *\n * _.isArray(_.noop);\n * // => false\n */\nvar isArray = Array.isArray;\n\nexport default isArray;\n","/** Used as references for various `Number` constants. */\nvar MAX_SAFE_INTEGER = 9007199254740991;\n\n/**\n * Checks if `value` is a valid array-like length.\n *\n * **Note:** This method is loosely based on\n * [`ToLength`](http://ecma-international.org/ecma-262/7.0/#sec-tolength).\n *\n * @static\n * @memberOf _\n * @since 4.0.0\n * @category Lang\n * @param {*} value The value to check.\n * @returns {boolean} Returns `true` if `value` is a valid length, else `false`.\n * @example\n *\n * _.isLength(3);\n * // => true\n *\n * _.isLength(Number.MIN_VALUE);\n * // => false\n *\n * _.isLength(Infinity);\n * // => false\n *\n * _.isLength('3');\n * // => false\n */\nfunction isLength(value) {\n return typeof value == 'number' &&\n value > -1 && value % 1 == 0 && value <= MAX_SAFE_INTEGER;\n}\n\nexport default isLength;\n","/**\n * This method returns `false`.\n *\n * @static\n * @memberOf _\n * @since 4.13.0\n * @category Util\n * @returns {boolean} Returns `false`.\n * @example\n *\n * _.times(2, _.stubFalse);\n * // => [false, false]\n */\nfunction stubFalse() {\n return false;\n}\n\nexport default stubFalse;\n","/**\n * The base implementation of `_.unary` without support for storing metadata.\n *\n * @private\n * @param {Function} func The function to cap arguments for.\n * @returns {Function} Returns the new capped function.\n */\nfunction baseUnary(func) {\n return function(value) {\n return func(value);\n };\n}\n\nexport default baseUnary;\n","/**\n * Gets the value at `key`, unless `key` is \"__proto__\" or \"constructor\".\n *\n * @private\n * @param {Object} object The object to query.\n * @param {string} key The key of the property to get.\n * @returns {*} Returns the property value.\n */\nfunction safeGet(object, key) {\n if (key === 'constructor' && typeof object[key] === 'function') {\n return;\n }\n\n if (key == '__proto__') {\n return;\n }\n\n return object[key];\n}\n\nexport default safeGet;\n","/**\n * The base implementation of `_.times` without support for iteratee shorthands\n * or max array length checks.\n *\n * @private\n * @param {number} n The number of times to invoke `iteratee`.\n * @param {Function} iteratee The function invoked per iteration.\n * @returns {Array} Returns the array of results.\n */\nfunction baseTimes(n, iteratee) {\n var index = -1,\n result = Array(n);\n\n while (++index < n) {\n result[index] = iteratee(index);\n }\n return result;\n}\n\nexport default baseTimes;\n","/** Used as references for various `Number` constants. */\nvar MAX_SAFE_INTEGER = 9007199254740991;\n\n/** Used to detect unsigned integer values. */\nvar reIsUint = /^(?:0|[1-9]\\d*)$/;\n\n/**\n * Checks if `value` is a valid array-like index.\n *\n * @private\n * @param {*} value The value to check.\n * @param {number} [length=MAX_SAFE_INTEGER] The upper bounds of a valid index.\n * @returns {boolean} Returns `true` if `value` is a valid index, else `false`.\n */\nfunction isIndex(value, length) {\n var type = typeof value;\n length = length == null ? MAX_SAFE_INTEGER : length;\n\n return !!length &&\n (type == 'number' ||\n (type != 'symbol' && reIsUint.test(value))) &&\n (value > -1 && value % 1 == 0 && value < length);\n}\n\nexport default isIndex;\n","/**\n * This function is like\n * [`Object.keys`](http://ecma-international.org/ecma-262/7.0/#sec-object.keys)\n * except that it includes inherited enumerable properties.\n *\n * @private\n * @param {Object} object The object to query.\n * @returns {Array} Returns the array of property names.\n */\nfunction nativeKeysIn(object) {\n var result = [];\n if (object != null) {\n for (var key in Object(object)) {\n result.push(key);\n }\n }\n return result;\n}\n\nexport default nativeKeysIn;\n","/**\n * This method returns the first argument it receives.\n *\n * @static\n * @since 0.1.0\n * @memberOf _\n * @category Util\n * @param {*} value Any value.\n * @returns {*} Returns `value`.\n * @example\n *\n * var object = { 'a': 1 };\n *\n * console.log(_.identity(object) === object);\n * // => true\n */\nfunction identity(value) {\n return value;\n}\n\nexport default identity;\n","/**\n * A faster alternative to `Function#apply`, this function invokes `func`\n * with the `this` binding of `thisArg` and the arguments of `args`.\n *\n * @private\n * @param {Function} func The function to invoke.\n * @param {*} thisArg The `this` binding of `func`.\n * @param {Array} args The arguments to invoke `func` with.\n * @returns {*} Returns the result of `func`.\n */\nfunction apply(func, thisArg, args) {\n switch (args.length) {\n case 0: return func.call(thisArg);\n case 1: return func.call(thisArg, args[0]);\n case 2: return func.call(thisArg, args[0], args[1]);\n case 3: return func.call(thisArg, args[0], args[1], args[2]);\n }\n return func.apply(thisArg, args);\n}\n\nexport default apply;\n","/**\n * Creates a function that returns `value`.\n *\n * @static\n * @memberOf _\n * @since 2.4.0\n * @category Util\n * @param {*} value The value to return from the new function.\n * @returns {Function} Returns the new constant function.\n * @example\n *\n * var objects = _.times(2, _.constant({ 'a': 1 }));\n *\n * console.log(objects);\n * // => [{ 'a': 1 }, { 'a': 1 }]\n *\n * console.log(objects[0] === objects[1]);\n * // => true\n */\nfunction constant(value) {\n return function() {\n return value;\n };\n}\n\nexport default constant;\n","/** Used to detect hot functions by number of calls within a span of milliseconds. */\nvar HOT_COUNT = 800,\n HOT_SPAN = 16;\n\n/* Built-in method references for those with the same name as other `lodash` methods. */\nvar nativeNow = Date.now;\n\n/**\n * Creates a function that'll short out and invoke `identity` instead\n * of `func` when it's called `HOT_COUNT` or more times in `HOT_SPAN`\n * milliseconds.\n *\n * @private\n * @param {Function} func The function to restrict.\n * @returns {Function} Returns the new shortable function.\n */\nfunction shortOut(func) {\n var count = 0,\n lastCalled = 0;\n\n return function() {\n var stamp = nativeNow(),\n remaining = HOT_SPAN - (stamp - lastCalled);\n\n lastCalled = stamp;\n if (remaining > 0) {\n if (++count >= HOT_COUNT) {\n return arguments[0];\n }\n } else {\n count = 0;\n }\n return func.apply(undefined, arguments);\n };\n}\n\nexport default shortOut;\n","// break it out on its own because\n// it's building from the lodash-es from scratch\n// according to this discussion https://github.com/lodash/lodash/issues/3298\nimport isPlainObject from 'lodash-es/isPlainObject'\nimport merge from 'lodash-es/merge'\n\n/**\n * previously we already make sure the order of the namespaces\n * and attach the auth client to it\n * @param {array} promises array of unresolved promises\n * @param {boolean} asObject if true then merge the result object\n * @return {object} promise resolved with the array of promises resolved results\n */\nexport function chainPromises(promises, asObject = false) {\n return promises.reduce((promiseChain, currentTask) => (\n promiseChain.then(chainResults => (\n currentTask.then(currentResult => (\n asObject === false ? [...chainResults, currentResult] : merge(chainResults, currentResult)\n ))\n ))\n ), Promise.resolve(\n asObject === false ? [] : (isPlainObject(asObject) ? asObject : {})\n ))\n}\n\n\n/**\n * This one return a different result from the chainPromises\n * it will be the same like chainFns that take one promise resolve as the next fn parameter\n * @param {function} initPromise a function that accept param and resolve result\n * @param {array} promises array of function pass that resolve promises\n * @return {promise} resolve the processed result\n */\nexport function chainProcessPromises(initPromise, ...promises) {\n return (...args) => (\n promises.reduce((promiseChain, currentTask) => (\n promiseChain.then(chainResult => (\n currentTask(chainResult)\n )\n )\n ), Reflect.apply(initPromise, null, args))\n )\n}\n","// @BUG when call disconnected \n// this keep causing an \"Disconnect call failed TypeError: Cannot read property 'readyState' of null\"\n// I think that is because it's not login then it can not be disconnect\n// how do we track this state globally\nimport { LOGIN_EVENT_NAME } from 'jsonql-constants'\nimport { clearMainEmitEvt } from '../modules'\n\n/**\n * create a login event handler \n * @param {object} opts configurations \n * @param {object} nspMap contain all the required info\n * @param {object} ee event emitter \n * @return {void}\n */\nexport function loginEventHandler(opts, nspMap, ee) {\n const { log } = opts\n const { namespaces } = nspMap\n\n ee.$only(LOGIN_EVENT_NAME, function loginEventHandlerCallback(tokenFromLoginAction) {\n \n log('createClient LOGIN_EVENT_NAME $only handler')\n\n clearMainEmitEvt(ee, namespaces)\n // console.log('LOGIN_EVENT_NAME', token)\n const newNsps = createNspAction(opts, nspMap, tokenFromLoginAction)\n // rebind it\n Reflect.apply(\n clientEventHandler, // @NOTE is this the problem that cause the hang up?\n null,\n args.concat([newNsps.namespaces, newNsps.nsps])\n )\n })\n}","// bunch of generic helpers\n\nimport isArray from 'lodash-es/isArray'\nimport isPlainObject from 'lodash-es/isPlainObject'\nimport trim from 'lodash-es/trim'\n\n/**\n * DIY in Array\n * @param {array} arr to check from\n * @param {*} value to check against\n * @return {boolean} true on found\n */\nexport const inArray = (arr, value) => !!arr.filter(a => a === value).length\n\n// quick and dirty to turn non array to array\nexport const toArray = (arg) => isArray(arg) ? arg : [arg]\n\n/**\n * parse string to json or just return the original value if error happened\n * @param {*} n input\n * @param {boolean} [t=true] or throw\n * @return {*} json object on success\n */\nexport const parseJson = function(n, t=true) {\n try {\n return JSON.parse(n)\n } catch(e) {\n if (t) {\n return n\n }\n throw new Error(e)\n }\n}\n\n/**\n * @param {object} obj for search\n * @param {string} key target\n * @return {boolean} true on success\n */\nexport const isObjectHasKey = function(obj, key) {\n try {\n const keys = Object.keys(obj)\n return inArray(keys, key)\n } catch(e) {\n // @BUG when the obj is not an OBJECT we got some weird output\n return false\n }\n}\n\n/**\n * create a event name\n * @param {string[]} args\n * @return {string} event name for use\n */\nexport const createEvt = (...args) => args.join('_')\n\n/**\n * simple util method to get the value\n * @param {string} name of the key\n * @param {object} obj to take value from\n * @return {*} the object value id by name or undefined\n */\nexport const getConfigValue = (name, obj) => (\n obj && isPlainObject(obj) ? ( (name in obj) ? obj[name] : undefined ) : undefined\n)\n\n/**\n * small util to make sure the return value is valid JSON object\n * @param {*} n input\n * @return {object} correct JSON object\n */\nexport const toJson = n => {\n if (typeof n === 'string') {\n return parseJson(n)\n }\n return parseJson(JSON.stringify(n))\n}\n\n/**\n * Check several parameter that there is something in the param\n * @param {*} param input\n * @return {boolean}\n */\nexport const isNotEmpty = function(param) {\n return param !== undefined && param !== false && param !== null && trim(param) !== ''\n}\n\n/**\n * Simple check if the prop is function\n * @param {*} prop input\n * @return {boolean} true on success\n */\nexport const isFunc = prop => {\n if (typeof prop === 'function') {\n return true;\n }\n console.error(`Expect to be Function type! Got ${typeof prop}`)\n}\n\n// generic placeholder function\nexport const nil = () => false\n","// custom validation error class\n// when validaton failed\nexport default class JsonqlValidationError extends Error {\n constructor(...args) {\n super(...args)\n\n this.message = args[0]\n this.detail = args[1]\n\n this.className = JsonqlValidationError.name;\n\n if (Error.captureStackTrace) {\n Error.captureStackTrace(this, JsonqlValidationError)\n }\n }\n\n static get name() {\n return 'JsonqlValidationError'\n }\n}\n","/**\n * @param {boolean} sec return in second or not\n * @return {number} timestamp\n */\nexport const timestamp = (sec = false) => {\n let time = Date.now()\n return sec ? Math.floor( time / 1000 ) : time\n}\n","// ported from jsonql-params-validator\n// craete several helper function to construct / extract the payload\n// and make sure they are all the same\nimport {\n PAYLOAD_PARAM_NAME,\n CONDITION_PARAM_NAME,\n RESOLVER_PARAM_NAME,\n QUERY_ARG_NAME,\n TIMESTAMP_PARAM_NAME\n} from 'jsonql-constants'\n\nimport JsonqlValidationError from 'jsonql-errors/src/validation-error'\n\nimport isArray from 'lodash-es/isArray'\nimport isString from 'lodash-es/isString'\nimport isPlainObject from 'lodash-es/isPlainObject'\n\nimport { timestamp } from './timestamp'\nimport { parseJson } from './generic'\n\n/**\n * check if the payload has a timestamp field, then append a new timestamp to it\n * @param {object} payload from the com\n * @return {array} timestamp field with an array value\n */\nexport const handleTimestamp = payload => {\n let ts = payload[TIMESTAMP_PARAM_NAME]\n if (!isArray(ts)) {\n ts = [ts]\n }\n ts.push( timestamp() )\n\n return ts\n}\n\n/**\n * make sure it's an object (it was call formatPayload but it doesn't make sense)\n * @param {*} payload the object comes in could be string based\n * @return {object} the transformed payload\n */\nexport const toPayload = payload => isString(payload) ? parseJson(payload) : payload\n\n/**\n * @param {*} args arguments to send\n *@return {object} formatted payload\n */\nexport const formatPayload = (args) => (\n { [QUERY_ARG_NAME]: args }\n)\n\n/**\n * extract the resolver name from the payload \n * @param {object} payload\n * @return {string} resolver name \n */\nexport function getResolverFromPayload(payload) {\n const keys = Object.keys(payload)\n return keys.filter(key => key !== TIMESTAMP_PARAM_NAME)[0]\n}\n\n/**\n * wrapper method to add the timestamp as well\n * @param {string} resolverName\n * @param {*} payload\n * @return {object} delierable\n */\nexport function createDeliverable(resolverName, payload) {\n return {\n [resolverName]: payload,\n [TIMESTAMP_PARAM_NAME]: [ timestamp() ]\n }\n}\n\n/**\n * @param {string} resolverName name of function\n * @param {array} [args=[]] from the ...args\n * @param {boolean} [jsonp = false] add v1.3.0 to koa\n * @return {object} formatted argument\n */\nexport function createQuery(resolverName, args = [], jsonp = false) {\n if (isString(resolverName) && isArray(args)) {\n let payload = formatPayload(args)\n if (jsonp === true) {\n return payload\n }\n return createDeliverable(resolverName, payload)\n }\n throw new JsonqlValidationError(`[createQuery] expect resolverName to be string and args to be array!`, { resolverName, args })\n}\n\n/**\n * string version of the createQuery\n * @return {string}\n */\nexport function createQueryStr(resolverName, args = [], jsonp = false) {\n return JSON.stringify(createQuery(resolverName, args, jsonp))\n}\n\n/**\n * @param {string} resolverName name of function\n * @param {*} payload to send\n * @param {object} [condition={}] for what\n * @param {boolean} [jsonp = false] add v1.3.0 to koa\n * @return {object} formatted argument\n */\nexport function createMutation(resolverName, payload, condition = {}, jsonp = false) {\n const _payload = {\n [PAYLOAD_PARAM_NAME]: payload,\n [CONDITION_PARAM_NAME]: condition\n }\n if (jsonp === true) {\n return _payload\n }\n if (isString(resolverName)) {\n return createDeliverable(resolverName, _payload)\n }\n throw new JsonqlValidationError(`[createMutation] expect resolverName to be string!`, { resolverName, payload, condition })\n}\n\n/**\n * string version of createMutation\n * @return {string}\n */\nexport function createMutationStr(resolverName, payload, condition = {}, jsonp = false) {\n return JSON.stringify(createMutation(resolverName, payload, condition, jsonp))\n}\n\n/**\n * Extract the parts from payload and format for use\n * @param {string} resolverName name of fn\n * @param {object} payload the incoming json\n * @return {object|boolean} false on failed\n */\nexport function getQueryFromArgs(resolverName, payload) {\n if (resolverName && isPlainObject(payload)) {\n const args = payload[resolverName]\n if (args[QUERY_ARG_NAME]) {\n return {\n [RESOLVER_PARAM_NAME]: resolverName,\n [QUERY_ARG_NAME]: args[QUERY_ARG_NAME],\n [TIMESTAMP_PARAM_NAME]: handleTimestamp(payload)\n }\n }\n }\n return false\n}\n\n/**\n * Share function so no repeat\n * @param {object} payload the payload from client\n * @param {function} processor the last get result method\n * @return {*} result processed result\n */\nfunction processPayload(payload, processor) {\n const p = toPayload(payload)\n const resolverName = getResolverFromPayload(p)\n return Reflect.apply(processor, null, [resolverName, p])\n}\n\n/**\n * extra the payload back\n * @param {*} payload from http call\n * @return {object} resolverName and args\n */\nexport function getQueryFromPayload(payload) {\n const result = processPayload(payload, getQueryFromArgs)\n if (result !== false) {\n return result\n }\n throw new JsonqlValidationError('[getQueryArgs] Payload is malformed!', payload)\n}\n\n/**\n * Further break down from method below for use else where\n * @param {string} resolverName name of fn\n * @param {object} payload payload\n * @return {object|boolean} false on failed\n */\nexport function getMutationFromArgs(resolverName, payload) {\n if (resolverName && isPlainObject(payload)) {\n const args = payload[resolverName]\n if (args) {\n return {\n [RESOLVER_PARAM_NAME]: resolverName,\n [PAYLOAD_PARAM_NAME]: args[PAYLOAD_PARAM_NAME],\n [CONDITION_PARAM_NAME]: args[CONDITION_PARAM_NAME],\n [TIMESTAMP_PARAM_NAME]: handleTimestamp(payload)\n }\n }\n }\n return false\n}\n\n/**\n * @param {object} payload\n * @return {object} resolverName, payload, conditon\n */\nexport function getMutationFromPayload(payload) {\n const result = processPayload(payload, getMutationFromArgs)\n\n if (result !== false) {\n return result\n }\n throw new JsonqlValidationError('[getMutationArgs] Payload is malformed!', payload)\n}\n","// There are the socket related methods ported back from \n// ws-server-core and ws-client-core \nimport {\n WS_REPLY_TYPE,\n WS_EVT_NAME,\n WS_DATA_NAME,\n TIMESTAMP_PARAM_NAME,\n ERROR_KEY,\n EMIT_REPLY_TYPE,\n ACKNOWLEDGE_REPLY_TYPE\n} from 'jsonql-constants'\nimport { JsonqlError } from 'jsonql-errors' \nimport isString from 'lodash-es/isString'\n\nimport { toJson, isObjectHasKey, nil } from './generic'\nimport { timestamp } from './timestamp'\n\nconst PAYLOAD_NOT_DECODED_ERR = 'payload can not decoded'\nconst WS_KEYS = [\n WS_REPLY_TYPE,\n WS_EVT_NAME,\n WS_DATA_NAME\n]\n\n\n/**\n * The ws doesn't have a acknowledge callback like socket.io\n * so we have to DIY one for ws and other that doesn't have it\n * @param {string} type of reply\n * @param {string} resolverName which is replying\n * @param {*} data payload\n * @param {array} [ts= []] the last received ts, if any \n * @return {string} stringify json\n */\nexport const createWsReply = (type, resolverName, data, ts = []) => {\n ts.push(timestamp())\n return JSON.stringify({\n data: {\n [WS_REPLY_TYPE]: type,\n [WS_EVT_NAME]: resolverName,\n [WS_DATA_NAME]: toJson(data)\n },\n [TIMESTAMP_PARAM_NAME]: ts \n })\n}\n\n// extended function \nexport const createReplyMsg = (resolverName, data, ts = []) => (\n createWsReply(EMIT_REPLY_TYPE, resolverName, data, ts)\n)\n\nexport const createAcknowledgeMsg = (resolverName, data, ts = []) => (\n createWsReply(ACKNOWLEDGE_REPLY_TYPE, resolverName, data, ts)\n)\n\n/**\n * @param {string|object} payload should be string when reply but could be transformed\n * @return {boolean} true is OK\n */\nexport const isWsReply = payload => {\n const json = isString(payload) ? toJson(payload) : payload\n const { data } = json\n if (data) {\n let result = WS_KEYS.filter(key => isObjectHasKey(data, key))\n return (result.length === WS_KEYS.length) ? data : false\n }\n return false\n}\n\n/**\n * @param {string|object} data received data\n * @param {function} [cb=nil] this is for extracting the TS field or when it's error\n * @return {object} false on failed\n */\nexport const extractWsPayload = (payload, cb = nil) => {\n try {\n const json = toJson(payload)\n // now handle the data\n let _data\n if ((_data = isWsReply(json)) !== false) {\n // note the ts property is on its own \n cb(TIMESTAMP_PARAM_NAME, json[TIMESTAMP_PARAM_NAME])\n \n return {\n data: toJson(_data[WS_DATA_NAME]),\n resolverName: _data[WS_EVT_NAME],\n type: _data[WS_REPLY_TYPE]\n }\n }\n throw new JsonqlError(PAYLOAD_NOT_DECODED_ERR, payload)\n } catch(e) {\n return cb(ERROR_KEY, e)\n }\n}\n","// the WebSocket main handler\nimport {\n LOGOUT_EVENT_NAME,\n ACKNOWLEDGE_REPLY_TYPE,\n EMIT_REPLY_TYPE,\n ERROR_KEY,\n\n ON_ERROR_FN_NAME,\n ON_MESSAGE_FN_NAME,\n ON_RESULT_FN_NAME,\n ON_READY_FN_NAME,\n ON_LOGIN_FN_NAME\n} from 'jsonql-constants'\nimport {\n createQueryStr,\n createEvt,\n extractWsPayload\n} from 'jsonql-utils/module'\nimport {\n handleNamespaceOnError,\n createIntercomPayload\n} from '../modules'\n\n/**\n * in some edge case we might not even have a resolverName, then\n * we issue a global error for the developer to catch it\n * @param {object} ee event emitter\n * @param {string} namespace nsp\n * @param {string} resolverName resolver\n * @param {object} json decoded payload or error object\n * @return {undefined} nothing return\n */\nconst errorTypeHandler = (ee, namespace, resolverName, json) => {\n let evt = [namespace]\n if (resolverName) {\n evt.push(resolverName)\n }\n evt.push(ON_ERROR_FN_NAME)\n let evtName = Reflect.apply(createEvt, null, evt)\n // test if there is a data field\n let payload = json.data || json\n ee.$trigger(evtName, [payload])\n}\n\n/**\n * Handle the logout event when it's enableAuth\n * @param {object} ee eventEmitter\n * @param {object} ws the WebSocket instance\n * @return {void}\n */\nconst logoutEventListener = (ee, ws) => {\n // listen to the LOGOUT_EVENT_NAME when this is a private nsp\n ee.$on(LOGOUT_EVENT_NAME, function closeEvtHandler() {\n try {\n // @TODO we need find a way to get the userdata\n ws.send(createIntercomPayload(LOGOUT_EVENT_NAME))\n log('terminate ws connection')\n ws.terminate()\n } catch(e) {\n console.error('ws.terminate error', e)\n }\n })\n}\n\n/**\n * Binding the event to socket normally\n * @param {string} namespace\n * @param {object} ws the nsp\n * @param {object} ee EventEmitter\n * @param {boolean} isPrivate to id if this namespace is private or not\n * @param {object} opts configuration\n * @return {object} promise resolve after the onopen event\n */\nexport function bindSocketEventHandler(namespace, ws, ee, isPrivate, opts) {\n const { log } = opts\n let onReadCalls = 2\n // log(`log test, isPrivate:`, isPrivate)\n // connection open\n ws.onopen = function onOpenCallback() {\n\n log('=== ws.onopen listened -->', namespace)\n // we just call the onReady\n ee.$call(ON_READY_FN_NAME)(namespace)\n // we only want to allow it get call twice (number of namespaces)\n --onReadCalls\n if (onReadCalls === 0) {\n ee.$off(ON_READY_FN_NAME)\n }\n\n // need an extra parameter here to id the private nsp\n if (isPrivate) {\n log(`isPrivate and fire the ${ON_LOGIN_FN_NAME}`)\n ee.$call(ON_LOGIN_FN_NAME)(namespace)\n }\n // add listener only after the open is called\n ee.$only(\n createEvt(namespace, EMIT_REPLY_TYPE),\n /**\n * actually send the payload to server\n * @param {string} resolverName\n * @param {array} args NEED TO CHECK HOW WE PASS THIS!\n */\n function wsMainOnEvtHandler(resolverName, args) {\n\n const payload = createQueryStr(resolverName, args)\n log('ws.onopen.send', resolverName, args, payload)\n\n ws.send(payload)\n }\n )\n }\n\n // reply\n // If we change it to the event callback style\n // then the payload will just be the payload and fucks up the extractWsPayload call @TODO\n ws.onmessage = function onMessageCallback(payload) {\n // console.log(`on.message`, typeof payload, payload)\n try {\n // log(`ws.onmessage raw payload`, payload)\n // @TODO the payload actually contain quite a few things - is that changed?\n // type: message, data: data_send_from_server\n const json = extractWsPayload(payload.data)\n const { resolverName, type } = json\n\n log('Respond from server', type, json)\n\n switch (type) {\n case EMIT_REPLY_TYPE:\n let e1 = createEvt(namespace, resolverName, ON_MESSAGE_FN_NAME)\n let r = ee.$trigger(e1, [json])\n log(`EMIT_REPLY_TYPE`, e1, r)\n break\n case ACKNOWLEDGE_REPLY_TYPE:\n let e2 = createEvt(namespace, resolverName, ON_RESULT_FN_NAME)\n let x2 = ee.$trigger(e2, [json])\n log(`ACKNOWLEDGE_REPLY_TYPE`, e2, x2)\n break\n case ERROR_KEY:\n // this is handled error and we won't throw it\n // we need to extract the error from json\n log(`ERROR_KEY`)\n errorTypeHandler(ee, namespace, resolverName, json)\n break\n // @TODO there should be an error type instead of roll into the other two types? TBC\n default:\n // if this happen then we should throw it and halt the operation all together\n log('Unhandled event!', json)\n errorTypeHandler(ee, namespace, resolverName, json)\n // let error = {error: {'message': 'Unhandled event!', type}};\n // ee.$trigger(createEvt(namespace, resolverName, ON_RESULT_FN_NAME), [error])\n }\n } catch(e) {\n console.error(`ws.onmessage error`, e)\n errorTypeHandler(ee, namespace, false, e)\n }\n }\n // when the server close the connection\n ws.onclose = function onCloseCallback() {\n log('ws.onclose callback')\n // @TODO what to do with this\n // ee.$trigger(LOGOUT_EVENT_NAME, [namespace])\n }\n // add a onerror event handler here\n ws.onerror = function onErrorCallback(err) {\n // trigger a global error event\n log(`ws.onerror`, err)\n handleNamespaceOnError(ee, namespace, err)\n }\n\n if (isPrivate) {\n logoutEventListener(ee, ws)\n }\n\n}\n","// actually binding the event client to the socket client\n\n// from the jsonql-ws-client-core\nimport { clientEventListener } from '../modules'\n// local \nimport { createNspAction } from './create-nsp-action'\nimport { loginEventHandler } from './login-event-handler'\nimport { bindSocketEventHandler } from './bind-socket-event-handler'\n\n/**\n * create the NSP(s) and determine if this require auth or not \n * @param {object} opts configuration\n * @param {object} nspMap namespace with resolvers\n * @param {object} ee EventEmitter to pass through\n * @return {object} what comes in what goes out\n */\nfunction createNsp(opts, nspMap, ee) {\n // now create the nsps\n // const { namespaces } = nspMap\n const { token } = opts\n\n return createNspAction(opts, nspMap, token)\n .then(nsps => {\n const listenerFn = clientEventListener(bindSocketEventHandler, nsps)\n // now run it\n listenerFn(opts, nspMap, ee)\n\n if (opts.enableAuth) {\n loginEventHandler(opts, nspMap, ee)\n }\n // return what input\n return { opts, nspMap, ee }\n }) \n}\n\nexport { createNsp }","// breaking up the create-nsp.js file \n// then regroup them back together here \nimport { createNsp } from './create-nsp'\n\nexport default createNsp\n","// share method to create the wsClientResolver\nimport { initWebSocketClient } from './init-websocket-client'\nimport createNsp from '../create-nsp'\nimport { NSP_CLIENT, NSP_AUTH_CLIENT } from 'jsonql-constants'\n\n/**\n * Create the framework <---> jsonql client binding\n * @param {object} frameworkModule the different WebSocket module\n * @return {function} the wsClientResolver\n */\nfunction bindFrameworkToJsonql(frameworkModule) {\n /**\n * wsClientResolver\n * @param {object} opts configuration\n * @param {object} nspMap from the contract\n * @param {object} ee instance of the eventEmitter\n * @return {object} passing the same 3 input out with additional in the opts\n */\n return function createClientBindingAction(opts, nspMap, ee) {\n const { log } = opts\n opts[NSP_CLIENT] = initWebSocketClient(frameworkModule, false, log)\n opts[NSP_AUTH_CLIENT] = initWebSocketClient(frameworkModule, true, log) \n // @1.0.7 remove later once everything fixed \n \n log(`bindFrameworkToJsonql`, ee.name, nspMap)\n // console.log(`contract`, opts.contract)\n return createNsp(opts, nspMap, ee)\n }\n}\n\nexport { bindFrameworkToJsonql }","// this will be the news style interface that will pass to the jsonql-ws-client\n// then return a function for accepting an opts to generate the final\n// client api\nimport WebSocket from 'ws'\nimport createWebSocketBinding from '../core/create-websocket-binding'\n\n/**\n * @param {object} opts configuration\n * @param {object} nspMap from the contract\n * @param {object} ee instance of the eventEmitter\n * @return {object} passing the same 3 input out with additional in the opts\n */\nexport default createWebSocketBinding(WebSocket)\n","// this is the module entry point for node client\nimport {\n wsClientCore\n} from './core/modules'\nimport { wsClientConstProps } from './options'\n\nimport nodeFrameworkSocketEngine from './node/node-framework-socket-engine'\n\n// export back the function and that's it\nexport default function wsNodeClient(config = {}, constProps = {}) {\n const initClientMethod = wsClientCore(\n nodeFrameworkSocketEngine, \n {}, \n Object.assign({}, wsClientConstProps, constProps)\n )\n return initClientMethod(config)\n}\n"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;ACAA;;;;;;;;;ACAA;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;ACAA;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;ACAA;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;"} \ No newline at end of file diff --git a/packages/@jsonql/ws/tests/ws-client-auth.test.js b/packages/@jsonql/ws/tests/ws-client-auth.test.js index 23068daa..78987ebd 100644 --- a/packages/@jsonql/ws/tests/ws-client-auth.test.js +++ b/packages/@jsonql/ws/tests/ws-client-auth.test.js @@ -59,7 +59,7 @@ test.after(t => { // @NOTE here might be the problem, what we might have to do is to suspend all the // event in the queue, call login, or trigger by the host module to login // then after the login, we release the queue -test.serial.cb(`Should able to handle multiple onMessage and one onLogin callback`, t => { +test.serial.cb.skip(`Should able to handle multiple onMessage and one onLogin callback`, t => { t.plan(3) const evt = t.context.evt let ctn = 0 @@ -143,7 +143,7 @@ test.serial.cb('It should able to connect to a WebSocket private namespace', t = } }) - let client = t.context.client + // run test client.sendExtraMsg(100) diff --git a/packages/ws-client-core/src/callers/callers-generator.js b/packages/ws-client-core/src/callers/callers-generator.js index 7babd87f..683e3eb9 100644 --- a/packages/ws-client-core/src/callers/callers-generator.js +++ b/packages/ws-client-core/src/callers/callers-generator.js @@ -2,11 +2,11 @@ // we change the interface to return promise from v1.0.3 // this way we make sure the obj return is correct and timely import { chainFns } from '../utils' -import { createAuthMethods } from './setup-auth-methods' +import { setupAuthMethods } from './setup-auth-methods' import { generateResolvers, - createOnReadyListener, - createNamespaceErrorListener + setupOnReadyListener, + setupNamespaceErrorListener } from './generator-methods' import { @@ -24,8 +24,8 @@ import { export function callersGenerator(opts, nspMap, ee) { let fns = [ generateResolvers, - createOnReadyListener, - createNamespaceErrorListener + setupOnReadyListener, + setupNamespaceErrorListener ] if (opts.enableAuth) { fns.push(createAuthMethods) diff --git a/packages/ws-client-core/src/callers/generator-methods.js b/packages/ws-client-core/src/callers/generator-methods.js index b421ac5a..9e8ea5fc 100644 --- a/packages/ws-client-core/src/callers/generator-methods.js +++ b/packages/ws-client-core/src/callers/generator-methods.js @@ -80,7 +80,7 @@ export function generateResolvers(opts, ee, nspGroup) { * @param {object} nspGroup namespace keys * @return {array} [obj, opts, ee] */ -export function createNamespaceErrorListener(client, opts, ee, nspGroup) { +export function setupNamespaceErrorListener(client, opts, ee, nspGroup) { return [ objDefineProps( client, @@ -108,7 +108,7 @@ export function createNamespaceErrorListener(client, opts, ee, nspGroup) { * @param {object} ee Event Emitter * @return {array} [ obj, opts, ee ] */ -export function createOnReadyListener(client, opts, ee) { +export function setupOnReadyListener(client, opts, ee) { return [ objDefineProps( client, @@ -117,7 +117,7 @@ export function createOnReadyListener(client, opts, ee) { if (isFunc(onReadyCallback)) { // reduce it down to just one flat level // @2020-03-19 only allow ONE onReady callback otherwise - // it will get fire multiple times which is not what we want + // it will get fire multiple times which is not what we want ee.$only(ON_READY_FN_NAME, onReadyCallback) } } diff --git a/packages/ws-client-core/src/callers/index.js b/packages/ws-client-core/src/callers/index.js index 22c255fe..eeeabac4 100644 --- a/packages/ws-client-core/src/callers/index.js +++ b/packages/ws-client-core/src/callers/index.js @@ -9,7 +9,7 @@ import { } from './intercom-methods' import { helloWorld } from './hello' import { callersGenerator } from './callers-generator' -import { setupFinalStep } from './setup-final-setup' +import { setupFinalStep } from './setup-final-step' // just rename it export { diff --git a/packages/ws-client-core/src/callers/setup-auth-methods.js b/packages/ws-client-core/src/callers/setup-auth-methods.js index 4fac3bf1..df44196b 100644 --- a/packages/ws-client-core/src/callers/setup-auth-methods.js +++ b/packages/ws-client-core/src/callers/setup-auth-methods.js @@ -1,7 +1,7 @@ // take out from the resolver-methods -import { - LOGIN_EVENT_NAME, - LOGOUT_EVENT_NAME, +import { + LOGIN_EVENT_NAME, + LOGOUT_EVENT_NAME, ON_LOGIN_FN_NAME } from 'jsonql-constants' import { JsonqlValidationError } from 'jsonql-errors' @@ -19,11 +19,11 @@ import { injectToFn, chainFns, isString, objDefineProps, isFunc } from '../utils * @param {object} ee event emitter * @return {array} [ obj, opts, ee ] what comes in what goes out */ -const setupLoginHandler = (obj, opts, ee) => [ +const setupLoginHandler = (obj, opts, ee) => [ injectToFn(obj, opts.loginHandlerName, function loginHandler(token) { if (token && isString(token)) { opts.log(`Received ${LOGIN_EVENT_NAME} with ${token}`) - // @TODO add the interceptor hook + // @TODO add the interceptor hook return ee.$trigger(LOGIN_EVENT_NAME, [token]) } // should trigger a global error instead @TODO @@ -45,7 +45,7 @@ const setupLogoutHandler = (obj, opts, ee) => [ injectToFn(obj, opts.logoutHandlerName, function logoutHandler(...args) { ee.$trigger(LOGOUT_EVENT_NAME, args) }), - opts, + opts, ee ] @@ -57,7 +57,7 @@ const setupLogoutHandler = (obj, opts, ee) => [ * @param {object} ee Event Emitter * @return {array} [ obj, opts, ee] what comes in what goes out */ -const createOnLoginhandler = (obj, opts, ee) => [ +const setupOnLoginhandler = (obj, opts, ee) => [ objDefineProps(obj, ON_LOGIN_FN_NAME, function onLoginCallbackHandler(onLoginCallback) { if (isFunc(onLoginCallback)) { // only one callback can registered with it, TBC @@ -65,7 +65,7 @@ const createOnLoginhandler = (obj, opts, ee) => [ } }), opts, - ee + ee ] // @TODO future feature setup switch user @@ -78,10 +78,10 @@ const createOnLoginhandler = (obj, opts, ee) => [ * @param {object} ee Event Emitter * @return {array} [ obj, opts, ee ] what comes in what goes out */ -export function createAuthMethods(obj, opts, ee) { +export function setupAuthMethods(obj, opts, ee) { return chainFns( - setupLoginHandler, + setupLoginHandler, setupLogoutHandler, - createOnLoginhandler + setupOnLoginhandler )(obj, opts, ee) } diff --git a/packages/ws-client-core/src/callers/setup-final-step.js b/packages/ws-client-core/src/callers/setup-final-step.js index 56a97821..3f84c491 100644 --- a/packages/ws-client-core/src/callers/setup-final-step.js +++ b/packages/ws-client-core/src/callers/setup-final-step.js @@ -3,13 +3,16 @@ import { setupInterCom } from './setup-intercom' /** * The final step to return the client - * @param {object} client the client - * @param {object} opts configuration - * @param {object} ee the event emitter + * @param {object} params wrapper object to call the result forward + * @param {object} params.client the client + * @param {object} params.opts configuration + * @param {object} params.ee the event emitter * @return {object} client */ -function setupFinalStep(obj, opts, ee) { +function setupFinalStep({ obj, opts, ee }) { + const client = setupInterCom(obj, opts, ee) + opts.log(`---> The final step to return the ws-client <---`) // add some debug functions client.verifyEventEmitter = () => ee.is diff --git a/packages/ws-client-core/src/callers/setup-intercom.js b/packages/ws-client-core/src/callers/setup-intercom.js index b6033088..73b5d155 100644 --- a/packages/ws-client-core/src/callers/setup-intercom.js +++ b/packages/ws-client-core/src/callers/setup-intercom.js @@ -1,21 +1,26 @@ -// this is a new method that will create several -// intercom method also reverse listen to the server +// this is a new method that will create several +// intercom method also reverse listen to the server // such as disconnect (server issue disconnect) import { injectToFn } from '../utils' import { DISCONNECT_EVENT_NAME } from 'jsonql-constants' /** - * this is the new method that setup the intercom handler - * also this serve as the final call in the then chain to + * this is the new method that setup the intercom handler + * also this serve as the final call in the then chain to * output the client - * @param {object} client the client - * @param {object} opts configuration + * @param {object} client the client + * @param {object} opts configuration * @param {object} ee the event emitter - * @return {object} client + * @return {object} client */ export function setupInterCom(client, opts, ee) { const { disconnectHandlerName } = opts - return injectToFn(client, disconnectHandlerName, function disconnectHandler(...args) { - ee.$trigger(DISCONNECT_EVENT_NAME, args) - }) -} \ No newline at end of file + + return injectToFn( + client, + disconnectHandlerName, + function disconnectHandler(...args) { + ee.$trigger(DISCONNECT_EVENT_NAME, args) + } + ) +} -- Gitee From 3a5be1b426269c7f42f76fdd261176686114e119 Mon Sep 17 00:00:00 2001 From: joelchu Date: Fri, 20 Mar 2020 15:12:22 +0800 Subject: [PATCH 08/11] Fix the wrong naming pass to the argument --- packages/@jsonql/ws/main.js | 161 +++++------------- packages/@jsonql/ws/main.js.map | 2 +- .../src/callers/callers-generator.js | 2 +- 3 files changed, 45 insertions(+), 120 deletions(-) diff --git a/packages/@jsonql/ws/main.js b/packages/@jsonql/ws/main.js index fd025a70..ba6520ee 100644 --- a/packages/@jsonql/ws/main.js +++ b/packages/@jsonql/ws/main.js @@ -73,7 +73,6 @@ var TOKEN_PROP_KEY = 'token'; // also it makes the other module easiler to id what they are importing // use throughout the clients var SOCKET_PING_EVENT_NAME = '__ping__'; // when init connection do a ping -var LOGIN_EVENT_NAME = '__login__'; var LOGOUT_EVENT_NAME = '__logout__'; var DISCONNECT_EVENT_NAME = '__disconnect__'; // instead of using an event name in place of resolverName in the param @@ -89,7 +88,6 @@ var ON_MESSAGE_FN_NAME = 'onMessage'; var ON_RESULT_FN_NAME = 'onResult'; var ON_ERROR_FN_NAME = 'onError'; var ON_READY_FN_NAME = 'onReady'; -var ON_LOGIN_FN_NAME = 'onLogin'; // new @1.8.6 // the actual method name client.resolverName.send var SEND_MSG_FN_NAME = 'send'; @@ -6093,7 +6091,6 @@ var getCheckConfigAsync = function(validateSync) { }; // export -var isString$1 = checkIsString; var validateAsync$1 = validateAsync; var createConfig$1 = createConfig; @@ -6178,7 +6175,7 @@ function isRegExp(pat) { * @param {*} arg whatever * @return {boolean} false when it's not */ -function isString$2(arg) { +function isString$1(arg) { return typeof arg === 'string' } @@ -6191,7 +6188,7 @@ function getRegex(pattern) { switch (true) { case isRegExp(pattern) === true: return pattern - case isString$2(pattern) === true: + case isString$1(pattern) === true: return new RegExp(pattern) default: return false @@ -6361,7 +6358,7 @@ var StoreService = /*@__PURE__*/(function (SuspendClass) { while ( len-- ) evt[ len ] = arguments[ len ]; evt.forEach(function (e) { - if (!isString$2(e)) { + if (!isString$1(e)) { this$1.logger('(validateEvt)', e); throw new Error(("Event name must be string type! we got " + (typeof e))) } @@ -7150,90 +7147,6 @@ var clearMainEmitEvt = function (ee, namespace) { }); }; -// take out from the resolver-methods - - -/** - * @TODO this is now become unnecessary because the login is a slave to the - * http-client - but keep this for now and see what we want to do with it later - * @UPDATE it might be better if we decoup the two http-client only emit a login event - * Here should catch it and reload the ws client @TBC - * break out from createAuthMethods to allow chaining call - * @param {object} obj the main client object - * @param {object} opts configuration - * @param {object} ee event emitter - * @return {array} [ obj, opts, ee ] what comes in what goes out - */ -var setupLoginHandler = function (obj, opts, ee) { return [ - injectToFn(obj, opts.loginHandlerName, function loginHandler(token) { - if (token && isString$1(token)) { - opts.log(("Received " + LOGIN_EVENT_NAME + " with " + token)); - // @TODO add the interceptor hook - return ee.$trigger(LOGIN_EVENT_NAME, [token]) - } - // should trigger a global error instead @TODO - throw new JsonqlValidationError(opts.loginHandlerName, ("Unexpected token " + token)) - }), - opts, - ee -]; }; - - -/** - * break out from createAuthMethods to allow chaining call - final in chain - * @param {object} obj the main client object - * @param {object} opts configuration - * @param {object} ee event emitter - * @return {array} [ obj, opts, ee ] what comes in what goes out - */ -var setupLogoutHandler = function (obj, opts, ee) { return [ - injectToFn(obj, opts.logoutHandlerName, function logoutHandler() { - var args = [], len = arguments.length; - while ( len-- ) args[ len ] = arguments[ len ]; - - ee.$trigger(LOGOUT_EVENT_NAME, args); - }), - opts, - ee -]; }; - - -/** - * This event will fire when the socket.io.on('connection') and ws.onopen - * Plus this will check if it's the private namespace that fired the event - * @param {object} obj the client itself - * @param {object} ee Event Emitter - * @return {array} [ obj, opts, ee] what comes in what goes out - */ -var createOnLoginhandler = function (obj, opts, ee) { return [ - objDefineProps(obj, ON_LOGIN_FN_NAME, function onLoginCallbackHandler(onLoginCallback) { - if (isFunc(onLoginCallback)) { - // only one callback can registered with it, TBC - ee.$only(ON_LOGIN_FN_NAME, onLoginCallback); - } - }), - opts, - ee -]; }; - -// @TODO future feature setup switch user - - -/** - * Create auth related methods - * @param {object} obj the client itself - * @param {object} opts configuration - * @param {object} ee Event Emitter - * @return {array} [ obj, opts, ee ] what comes in what goes out - */ -function createAuthMethods(obj, opts, ee) { - return chainFns( - setupLoginHandler, - setupLogoutHandler, - createOnLoginhandler - )(obj, opts, ee) -} - // constants var EMIT_EVT = EMIT_REPLY_TYPE; @@ -7543,7 +7456,7 @@ function generateResolvers(opts, ee, nspGroup) { * @param {object} nspGroup namespace keys * @return {array} [obj, opts, ee] */ -function createNamespaceErrorListener(client, opts, ee, nspGroup) { +function setupNamespaceErrorListener(client, opts, ee, nspGroup) { return [ objDefineProps( client, @@ -7571,7 +7484,7 @@ function createNamespaceErrorListener(client, opts, ee, nspGroup) { * @param {object} ee Event Emitter * @return {array} [ obj, opts, ee ] */ -function createOnReadyListener(client, opts, ee) { +function setupOnReadyListener(client, opts, ee) { return [ objDefineProps( client, @@ -7580,7 +7493,7 @@ function createOnReadyListener(client, opts, ee) { if (isFunc(onReadyCallback)) { // reduce it down to just one flat level // @2020-03-19 only allow ONE onReady callback otherwise - // it will get fire multiple times which is not what we want + // it will get fire multiple times which is not what we want ee.$only(ON_READY_FN_NAME, onReadyCallback); } } @@ -7603,8 +7516,8 @@ function createOnReadyListener(client, opts, ee) { function callersGenerator(opts, nspMap, ee) { var fns = [ generateResolvers, - createOnReadyListener, - createNamespaceErrorListener + setupOnReadyListener, + setupNamespaceErrorListener ]; if (opts.enableAuth) { fns.push(createAuthMethods); @@ -7620,38 +7533,50 @@ function callersGenerator(opts, nspMap, ee) { return generator(opts, ee, nspMap[NSP_GROUP]) } -// this is a new method that will create several +// this is a new method that will create several /** - * this is the new method that setup the intercom handler - * also this serve as the final call in the then chain to + * this is the new method that setup the intercom handler + * also this serve as the final call in the then chain to * output the client - * @param {object} client the client - * @param {object} opts configuration + * @param {object} client the client + * @param {object} opts configuration * @param {object} ee the event emitter - * @return {object} client + * @return {object} client */ function setupInterCom(client, opts, ee) { var disconnectHandlerName = opts.disconnectHandlerName; - return injectToFn(client, disconnectHandlerName, function disconnectHandler() { - var args = [], len = arguments.length; - while ( len-- ) args[ len ] = arguments[ len ]; - ee.$trigger(DISCONNECT_EVENT_NAME, args); - }) + return injectToFn( + client, + disconnectHandlerName, + function disconnectHandler() { + var args = [], len = arguments.length; + while ( len-- ) args[ len ] = arguments[ len ]; + + ee.$trigger(DISCONNECT_EVENT_NAME, args); + } + ) } // The final step of the setup before it returns the client /** * The final step to return the client - * @param {object} client the client - * @param {object} opts configuration - * @param {object} ee the event emitter + * @param {object} params wrapper object to call the result forward + * @param {object} params.client the client + * @param {object} params.opts configuration + * @param {object} params.ee the event emitter * @return {object} client */ -function setupFinalStep(obj, opts, ee) { +function setupFinalStep(ref) { + var obj = ref.obj; + var opts = ref.opts; + var ee = ref.ee; + + var client = setupInterCom(obj, opts, ee); + opts.log("---> The final step to return the ws-client <---"); // add some debug functions client.verifyEventEmitter = function () { return ee.is; }; @@ -8031,7 +7956,7 @@ function clientEventListener(bindSocketEventListener, nsps) { var ERROR_KEY$1 = 'error'; var QUERY_ARG_NAME$1 = 'args'; var TIMESTAMP_PARAM_NAME$1 = 'TS'; -var LOGIN_EVENT_NAME$1 = '__login__'; +var LOGIN_EVENT_NAME = '__login__'; var LOGOUT_EVENT_NAME$1 = '__logout__'; // for ws servers var WS_REPLY_TYPE$1 = '__reply__'; @@ -8043,7 +7968,7 @@ var ON_MESSAGE_FN_NAME$1 = 'onMessage'; var ON_RESULT_FN_NAME$1 = 'onResult'; var ON_ERROR_FN_NAME$1 = 'onError'; var ON_READY_FN_NAME$1 = 'onReady'; -var ON_LOGIN_FN_NAME$1 = 'onLogin'; // new @1.8.6 +var ON_LOGIN_FN_NAME = 'onLogin'; // new @1.8.6 // this is somewhat vague about what is suppose to do var EMIT_REPLY_TYPE$1 = 'emit_reply'; @@ -10349,7 +10274,7 @@ function loginEventHandler(opts, nspMap, ee) { var log = opts.log; var namespaces = nspMap.namespaces; - ee.$only(LOGIN_EVENT_NAME$1, function loginEventHandlerCallback(tokenFromLoginAction) { + ee.$only(LOGIN_EVENT_NAME, function loginEventHandlerCallback(tokenFromLoginAction) { log('createClient LOGIN_EVENT_NAME $only handler'); @@ -10546,7 +10471,7 @@ var stringTag$4 = '[object String]'; * _.isString(1); * // => false */ -function isString$3(value) { +function isString$2(value) { return typeof value == 'string' || (!isArray$1(value) && isObjectLike$1(value) && baseGetTag$1(value) == stringTag$4); } @@ -10587,7 +10512,7 @@ function createQuery$1(resolverName, args, jsonp) { if ( args === void 0 ) args = []; if ( jsonp === void 0 ) jsonp = false; - if (isString$3(resolverName) && isArray$1(args)) { + if (isString$2(resolverName) && isArray$1(args)) { var payload = formatPayload$1(args); if (jsonp === true) { return payload @@ -10622,7 +10547,7 @@ var WS_KEYS$1 = [ * @return {boolean} true is OK */ var isWsReply$1 = function (payload) { - var json = isString$3(payload) ? toJson$1(payload) : payload; + var json = isString$2(payload) ? toJson$1(payload) : payload; var data = json.data; if (data) { var result = WS_KEYS$1.filter(function (key) { return isObjectHasKey$2(data, key); }); @@ -10729,8 +10654,8 @@ function bindSocketEventHandler(namespace, ws, ee, isPrivate, opts) { // need an extra parameter here to id the private nsp if (isPrivate) { - log(("isPrivate and fire the " + ON_LOGIN_FN_NAME$1)); - ee.$call(ON_LOGIN_FN_NAME$1)(namespace); + log(("isPrivate and fire the " + ON_LOGIN_FN_NAME)); + ee.$call(ON_LOGIN_FN_NAME)(namespace); } // add listener only after the open is called ee.$only( diff --git a/packages/@jsonql/ws/main.js.map b/packages/@jsonql/ws/main.js.map index ce7f074c..6275e275 100644 --- a/packages/@jsonql/ws/main.js.map +++ b/packages/@jsonql/ws/main.js.map @@ -1 +1 @@ -{"version":3,"file":"main.js","sources":["../../ws-client-core/node_modules/lodash-es/isArray.js","node_modules/rollup-plugin-node-globals/src/global.js","../../ws-client-core/node_modules/lodash-es/_objectToString.js","../../ws-client-core/node_modules/lodash-es/_overArg.js","../../ws-client-core/node_modules/lodash-es/isObjectLike.js","../../ws-client-core/node_modules/lodash-es/_arrayMap.js","../../ws-client-core/node_modules/lodash-es/_baseSlice.js","../../ws-client-core/node_modules/lodash-es/_baseFindIndex.js","../../ws-client-core/node_modules/lodash-es/_baseIsNaN.js","../../ws-client-core/node_modules/lodash-es/_strictIndexOf.js","../../ws-client-core/node_modules/lodash-es/_asciiToArray.js","../../ws-client-core/node_modules/lodash-es/_hasUnicode.js","../../ws-client-core/node_modules/lodash-es/_unicodeToArray.js","../../ws-client-core/node_modules/jsonql-utils/src/generic.js","../../ws-client-core/node_modules/lodash-es/_listCacheClear.js","../../ws-client-core/node_modules/lodash-es/eq.js","../../ws-client-core/node_modules/lodash-es/_stackDelete.js","../../ws-client-core/node_modules/lodash-es/_stackGet.js","../../ws-client-core/node_modules/lodash-es/_stackHas.js","../../ws-client-core/node_modules/lodash-es/isObject.js","../../ws-client-core/node_modules/lodash-es/_toSource.js","../../ws-client-core/node_modules/lodash-es/_getValue.js","../../ws-client-core/node_modules/lodash-es/_hashDelete.js","../../ws-client-core/node_modules/lodash-es/_isKeyable.js","../../ws-client-core/node_modules/lodash-es/_createBaseFor.js","../../ws-client-core/node_modules/lodash-es/_copyArray.js","../../ws-client-core/node_modules/lodash-es/_isPrototype.js","../../ws-client-core/node_modules/lodash-es/isLength.js","../../ws-client-core/node_modules/lodash-es/stubFalse.js","../../ws-client-core/node_modules/lodash-es/_baseUnary.js","../../ws-client-core/node_modules/lodash-es/_safeGet.js","../../ws-client-core/node_modules/lodash-es/_baseTimes.js","../../ws-client-core/node_modules/lodash-es/_isIndex.js","../../ws-client-core/node_modules/lodash-es/_nativeKeysIn.js","../../ws-client-core/node_modules/lodash-es/identity.js","../../ws-client-core/node_modules/lodash-es/_apply.js","../../ws-client-core/node_modules/lodash-es/constant.js","../../ws-client-core/node_modules/lodash-es/_shortOut.js","../../ws-client-core/node_modules/jsonql-errors/src/enum-error.js","../../ws-client-core/node_modules/jsonql-errors/src/type-error.js","../../ws-client-core/node_modules/jsonql-errors/src/checker-error.js","../../ws-client-core/node_modules/jsonql-errors/src/validation-error.js","../../ws-client-core/node_modules/jsonql-utils/src/contract.js","../../ws-client-core/node_modules/jsonql-utils/src/timestamp.js","../../ws-client-core/node_modules/jsonql-utils/src/params-api.js","../../ws-client-core/node_modules/jsonql-utils/src/namespace.js","../../ws-client-core/node_modules/jsonql-utils/src/socket.js","../../ws-client-core/src/callers/intercom-methods.js","../../ws-client-core/node_modules/jsonql-params-validator/src/number.js","../../ws-client-core/node_modules/jsonql-params-validator/src/string.js","../../ws-client-core/node_modules/jsonql-params-validator/src/boolean.js","../../ws-client-core/node_modules/jsonql-params-validator/src/any.js","../../ws-client-core/node_modules/jsonql-params-validator/src/constants.js","../../ws-client-core/node_modules/jsonql-params-validator/src/combine.js","../../ws-client-core/node_modules/jsonql-params-validator/src/array.js","../../ws-client-core/node_modules/jsonql-params-validator/src/object.js","../../ws-client-core/node_modules/jsonql-params-validator/src/validator.js","../../ws-client-core/node_modules/lodash-es/_setCacheAdd.js","../../ws-client-core/node_modules/lodash-es/_setCacheHas.js","../../ws-client-core/node_modules/lodash-es/_arraySome.js","../../ws-client-core/node_modules/lodash-es/_cacheHas.js","../../ws-client-core/node_modules/lodash-es/_mapToArray.js","../../ws-client-core/node_modules/lodash-es/_setToArray.js","../../ws-client-core/node_modules/lodash-es/_arrayPush.js","../../ws-client-core/node_modules/lodash-es/_arrayFilter.js","../../ws-client-core/node_modules/lodash-es/stubArray.js","../../ws-client-core/node_modules/lodash-es/_matchesStrictComparable.js","../../ws-client-core/node_modules/lodash-es/_baseHasIn.js","../../ws-client-core/node_modules/lodash-es/_baseProperty.js","../../ws-client-core/node_modules/lodash-es/negate.js","../../ws-client-core/node_modules/lodash-es/_baseFindKey.js","../../ws-client-core/node_modules/jsonql-params-validator/src/is-in-array.js","../../ws-client-core/node_modules/jsonql-params-validator/src/options/run-validation.js","../../ws-client-core/node_modules/jsonql-params-validator/src/options/check-options-async.js","../../ws-client-core/node_modules/jsonql-params-validator/src/options/construct-config.js","../../ws-client-core/node_modules/jsonql-params-validator/src/options/index.js","../../ws-client-core/node_modules/jsonql-params-validator/index.js","../../ws-client-core/src/utils/get-log-fn.js","../../ws-client-core/node_modules/@to1source/event/src/constants.js","../../ws-client-core/node_modules/@to1source/event/src/store.js","../../ws-client-core/node_modules/@to1source/event/src/utils.js","../../ws-client-core/node_modules/@to1source/event/src/suspend.js","../../ws-client-core/node_modules/@to1source/event/src/store-service.js","../../ws-client-core/node_modules/@to1source/event/src/event-service.js","../../ws-client-core/node_modules/@to1source/event/index.js","../../ws-client-core/src/utils/get-event-emitter.js","../../ws-client-core/src/utils/helpers.js","../../ws-client-core/src/callers/setup-auth-methods.js","../../ws-client-core/src/options/constants.js","../../ws-client-core/src/callers/respond-handler.js","../../ws-client-core/src/callers/action-call.js","../../ws-client-core/src/callers/setup-send-method.js","../../ws-client-core/src/callers/setup-resolver.js","../../ws-client-core/src/callers/generator-methods.js","../../ws-client-core/src/callers/callers-generator.js","../../ws-client-core/src/callers/setup-intercom.js","../../ws-client-core/src/callers/setup-final-step.js","../../ws-client-core/src/options/index.js","../../ws-client-core/src/api.js","../../ws-client-core/src/listener/create-nsp-clients.js","../../ws-client-core/src/listener/trigger-namespaces-on-error.js","../../ws-client-core/src/listener/event-listeners.js","../../ws-client-core/src/listener/client-event-listener.js","src/options/index.js","src/core/create-websocket-binding/init-websocket-client.js","node_modules/lodash-es/_objectToString.js","node_modules/lodash-es/_overArg.js","node_modules/lodash-es/isObjectLike.js","node_modules/lodash-es/_listCacheClear.js","node_modules/lodash-es/eq.js","node_modules/lodash-es/_stackDelete.js","node_modules/lodash-es/_stackGet.js","node_modules/lodash-es/_stackHas.js","node_modules/lodash-es/isObject.js","node_modules/lodash-es/_toSource.js","node_modules/lodash-es/_getValue.js","node_modules/lodash-es/_hashDelete.js","node_modules/lodash-es/_isKeyable.js","node_modules/lodash-es/_createBaseFor.js","node_modules/lodash-es/_copyArray.js","node_modules/lodash-es/_isPrototype.js","node_modules/lodash-es/isArray.js","node_modules/lodash-es/isLength.js","node_modules/lodash-es/stubFalse.js","node_modules/lodash-es/_baseUnary.js","node_modules/lodash-es/_safeGet.js","node_modules/lodash-es/_baseTimes.js","node_modules/lodash-es/_isIndex.js","node_modules/lodash-es/_nativeKeysIn.js","node_modules/lodash-es/identity.js","node_modules/lodash-es/_apply.js","node_modules/lodash-es/constant.js","node_modules/lodash-es/_shortOut.js","node_modules/jsonql-utils/src/chain-promises.js","src/core/create-nsp/login-event-handler.js","node_modules/jsonql-utils/src/generic.js","node_modules/jsonql-errors/src/validation-error.js","node_modules/jsonql-utils/src/timestamp.js","node_modules/jsonql-utils/src/params-api.js","node_modules/jsonql-utils/src/socket.js","src/core/create-nsp/bind-socket-event-handler.js","src/core/create-nsp/create-nsp.js","src/core/create-nsp/index.js","src/core/create-websocket-binding/bind-framework-to-jsonql.js","src/node/node-framework-socket-engine.js","src/node-ws-client.js"],"sourcesContent":["/**\n * Checks if `value` is classified as an `Array` object.\n *\n * @static\n * @memberOf _\n * @since 0.1.0\n * @category Lang\n * @param {*} value The value to check.\n * @returns {boolean} Returns `true` if `value` is an array, else `false`.\n * @example\n *\n * _.isArray([1, 2, 3]);\n * // => true\n *\n * _.isArray(document.body.children);\n * // => false\n *\n * _.isArray('abc');\n * // => false\n *\n * _.isArray(_.noop);\n * // => false\n */\nvar isArray = Array.isArray;\n\nexport default isArray;\n","export default (typeof global !== \"undefined\" ? global :\n typeof self !== \"undefined\" ? self :\n typeof window !== \"undefined\" ? window : {});\n","/** Used for built-in method references. */\nvar objectProto = Object.prototype;\n\n/**\n * Used to resolve the\n * [`toStringTag`](http://ecma-international.org/ecma-262/7.0/#sec-object.prototype.tostring)\n * of values.\n */\nvar nativeObjectToString = objectProto.toString;\n\n/**\n * Converts `value` to a string using `Object.prototype.toString`.\n *\n * @private\n * @param {*} value The value to convert.\n * @returns {string} Returns the converted string.\n */\nfunction objectToString(value) {\n return nativeObjectToString.call(value);\n}\n\nexport default objectToString;\n","/**\n * Creates a unary function that invokes `func` with its argument transformed.\n *\n * @private\n * @param {Function} func The function to wrap.\n * @param {Function} transform The argument transform.\n * @returns {Function} Returns the new function.\n */\nfunction overArg(func, transform) {\n return function(arg) {\n return func(transform(arg));\n };\n}\n\nexport default overArg;\n","/**\n * Checks if `value` is object-like. A value is object-like if it's not `null`\n * and has a `typeof` result of \"object\".\n *\n * @static\n * @memberOf _\n * @since 4.0.0\n * @category Lang\n * @param {*} value The value to check.\n * @returns {boolean} Returns `true` if `value` is object-like, else `false`.\n * @example\n *\n * _.isObjectLike({});\n * // => true\n *\n * _.isObjectLike([1, 2, 3]);\n * // => true\n *\n * _.isObjectLike(_.noop);\n * // => false\n *\n * _.isObjectLike(null);\n * // => false\n */\nfunction isObjectLike(value) {\n return value != null && typeof value == 'object';\n}\n\nexport default isObjectLike;\n","/**\n * A specialized version of `_.map` for arrays without support for iteratee\n * shorthands.\n *\n * @private\n * @param {Array} [array] The array to iterate over.\n * @param {Function} iteratee The function invoked per iteration.\n * @returns {Array} Returns the new mapped array.\n */\nfunction arrayMap(array, iteratee) {\n var index = -1,\n length = array == null ? 0 : array.length,\n result = Array(length);\n\n while (++index < length) {\n result[index] = iteratee(array[index], index, array);\n }\n return result;\n}\n\nexport default arrayMap;\n","/**\n * The base implementation of `_.slice` without an iteratee call guard.\n *\n * @private\n * @param {Array} array The array to slice.\n * @param {number} [start=0] The start position.\n * @param {number} [end=array.length] The end position.\n * @returns {Array} Returns the slice of `array`.\n */\nfunction baseSlice(array, start, end) {\n var index = -1,\n length = array.length;\n\n if (start < 0) {\n start = -start > length ? 0 : (length + start);\n }\n end = end > length ? length : end;\n if (end < 0) {\n end += length;\n }\n length = start > end ? 0 : ((end - start) >>> 0);\n start >>>= 0;\n\n var result = Array(length);\n while (++index < length) {\n result[index] = array[index + start];\n }\n return result;\n}\n\nexport default baseSlice;\n","/**\n * The base implementation of `_.findIndex` and `_.findLastIndex` without\n * support for iteratee shorthands.\n *\n * @private\n * @param {Array} array The array to inspect.\n * @param {Function} predicate The function invoked per iteration.\n * @param {number} fromIndex The index to search from.\n * @param {boolean} [fromRight] Specify iterating from right to left.\n * @returns {number} Returns the index of the matched value, else `-1`.\n */\nfunction baseFindIndex(array, predicate, fromIndex, fromRight) {\n var length = array.length,\n index = fromIndex + (fromRight ? 1 : -1);\n\n while ((fromRight ? index-- : ++index < length)) {\n if (predicate(array[index], index, array)) {\n return index;\n }\n }\n return -1;\n}\n\nexport default baseFindIndex;\n","/**\n * The base implementation of `_.isNaN` without support for number objects.\n *\n * @private\n * @param {*} value The value to check.\n * @returns {boolean} Returns `true` if `value` is `NaN`, else `false`.\n */\nfunction baseIsNaN(value) {\n return value !== value;\n}\n\nexport default baseIsNaN;\n","/**\n * A specialized version of `_.indexOf` which performs strict equality\n * comparisons of values, i.e. `===`.\n *\n * @private\n * @param {Array} array The array to inspect.\n * @param {*} value The value to search for.\n * @param {number} fromIndex The index to search from.\n * @returns {number} Returns the index of the matched value, else `-1`.\n */\nfunction strictIndexOf(array, value, fromIndex) {\n var index = fromIndex - 1,\n length = array.length;\n\n while (++index < length) {\n if (array[index] === value) {\n return index;\n }\n }\n return -1;\n}\n\nexport default strictIndexOf;\n","/**\n * Converts an ASCII `string` to an array.\n *\n * @private\n * @param {string} string The string to convert.\n * @returns {Array} Returns the converted array.\n */\nfunction asciiToArray(string) {\n return string.split('');\n}\n\nexport default asciiToArray;\n","/** Used to compose unicode character classes. */\nvar rsAstralRange = '\\\\ud800-\\\\udfff',\n rsComboMarksRange = '\\\\u0300-\\\\u036f',\n reComboHalfMarksRange = '\\\\ufe20-\\\\ufe2f',\n rsComboSymbolsRange = '\\\\u20d0-\\\\u20ff',\n rsComboRange = rsComboMarksRange + reComboHalfMarksRange + rsComboSymbolsRange,\n rsVarRange = '\\\\ufe0e\\\\ufe0f';\n\n/** Used to compose unicode capture groups. */\nvar rsZWJ = '\\\\u200d';\n\n/** Used to detect strings with [zero-width joiners or code points from the astral planes](http://eev.ee/blog/2015/09/12/dark-corners-of-unicode/). */\nvar reHasUnicode = RegExp('[' + rsZWJ + rsAstralRange + rsComboRange + rsVarRange + ']');\n\n/**\n * Checks if `string` contains Unicode symbols.\n *\n * @private\n * @param {string} string The string to inspect.\n * @returns {boolean} Returns `true` if a symbol is found, else `false`.\n */\nfunction hasUnicode(string) {\n return reHasUnicode.test(string);\n}\n\nexport default hasUnicode;\n","/** Used to compose unicode character classes. */\nvar rsAstralRange = '\\\\ud800-\\\\udfff',\n rsComboMarksRange = '\\\\u0300-\\\\u036f',\n reComboHalfMarksRange = '\\\\ufe20-\\\\ufe2f',\n rsComboSymbolsRange = '\\\\u20d0-\\\\u20ff',\n rsComboRange = rsComboMarksRange + reComboHalfMarksRange + rsComboSymbolsRange,\n rsVarRange = '\\\\ufe0e\\\\ufe0f';\n\n/** Used to compose unicode capture groups. */\nvar rsAstral = '[' + rsAstralRange + ']',\n rsCombo = '[' + rsComboRange + ']',\n rsFitz = '\\\\ud83c[\\\\udffb-\\\\udfff]',\n rsModifier = '(?:' + rsCombo + '|' + rsFitz + ')',\n rsNonAstral = '[^' + rsAstralRange + ']',\n rsRegional = '(?:\\\\ud83c[\\\\udde6-\\\\uddff]){2}',\n rsSurrPair = '[\\\\ud800-\\\\udbff][\\\\udc00-\\\\udfff]',\n rsZWJ = '\\\\u200d';\n\n/** Used to compose unicode regexes. */\nvar reOptMod = rsModifier + '?',\n rsOptVar = '[' + rsVarRange + ']?',\n rsOptJoin = '(?:' + rsZWJ + '(?:' + [rsNonAstral, rsRegional, rsSurrPair].join('|') + ')' + rsOptVar + reOptMod + ')*',\n rsSeq = rsOptVar + reOptMod + rsOptJoin,\n rsSymbol = '(?:' + [rsNonAstral + rsCombo + '?', rsCombo, rsRegional, rsSurrPair, rsAstral].join('|') + ')';\n\n/** Used to match [string symbols](https://mathiasbynens.be/notes/javascript-unicode). */\nvar reUnicode = RegExp(rsFitz + '(?=' + rsFitz + ')|' + rsSymbol + rsSeq, 'g');\n\n/**\n * Converts a Unicode `string` to an array.\n *\n * @private\n * @param {string} string The string to convert.\n * @returns {Array} Returns the converted array.\n */\nfunction unicodeToArray(string) {\n return string.match(reUnicode) || [];\n}\n\nexport default unicodeToArray;\n","// bunch of generic helpers\n\nimport isArray from 'lodash-es/isArray'\nimport isPlainObject from 'lodash-es/isPlainObject'\nimport trim from 'lodash-es/trim'\n\n/**\n * DIY in Array\n * @param {array} arr to check from\n * @param {*} value to check against\n * @return {boolean} true on found\n */\nexport const inArray = (arr, value) => !!arr.filter(a => a === value).length\n\n// quick and dirty to turn non array to array\nexport const toArray = (arg) => isArray(arg) ? arg : [arg]\n\n/**\n * parse string to json or just return the original value if error happened\n * @param {*} n input\n * @param {boolean} [t=true] or throw\n * @return {*} json object on success\n */\nexport const parseJson = function(n, t=true) {\n try {\n return JSON.parse(n)\n } catch(e) {\n if (t) {\n return n\n }\n throw new Error(e)\n }\n}\n\n/**\n * @param {object} obj for search\n * @param {string} key target\n * @return {boolean} true on success\n */\nexport const isObjectHasKey = function(obj, key) {\n try {\n const keys = Object.keys(obj)\n return inArray(keys, key)\n } catch(e) {\n // @BUG when the obj is not an OBJECT we got some weird output\n return false\n }\n}\n\n/**\n * create a event name\n * @param {string[]} args\n * @return {string} event name for use\n */\nexport const createEvt = (...args) => args.join('_')\n\n/**\n * simple util method to get the value\n * @param {string} name of the key\n * @param {object} obj to take value from\n * @return {*} the object value id by name or undefined\n */\nexport const getConfigValue = (name, obj) => (\n obj && isPlainObject(obj) ? ( (name in obj) ? obj[name] : undefined ) : undefined\n)\n\n/**\n * small util to make sure the return value is valid JSON object\n * @param {*} n input\n * @return {object} correct JSON object\n */\nexport const toJson = n => {\n if (typeof n === 'string') {\n return parseJson(n)\n }\n return parseJson(JSON.stringify(n))\n}\n\n/**\n * Check several parameter that there is something in the param\n * @param {*} param input\n * @return {boolean}\n */\nexport const isNotEmpty = function(param) {\n return param !== undefined && param !== false && param !== null && trim(param) !== ''\n}\n\n/**\n * Simple check if the prop is function\n * @param {*} prop input\n * @return {boolean} true on success\n */\nexport const isFunc = prop => {\n if (typeof prop === 'function') {\n return true;\n }\n console.error(`Expect to be Function type! Got ${typeof prop}`)\n}\n\n/**\n * Shorthand method for Object.assign \n * @param {array} args \n * @return {object} merge together object by key \n */\nexport const assign = (...args) => Reflect.apply(Object.assign, Object, args)\n \n/** \n * generic placeholder function\n * @return {boolean} false \n */\nexport const nil = () => false\n\n/**\n * generic turn config into immutatble \n */\nexport const freeze = config => Object.freeze(config)","/**\n * Removes all key-value entries from the list cache.\n *\n * @private\n * @name clear\n * @memberOf ListCache\n */\nfunction listCacheClear() {\n this.__data__ = [];\n this.size = 0;\n}\n\nexport default listCacheClear;\n","/**\n * Performs a\n * [`SameValueZero`](http://ecma-international.org/ecma-262/7.0/#sec-samevaluezero)\n * comparison between two values to determine if they are equivalent.\n *\n * @static\n * @memberOf _\n * @since 4.0.0\n * @category Lang\n * @param {*} value The value to compare.\n * @param {*} other The other value to compare.\n * @returns {boolean} Returns `true` if the values are equivalent, else `false`.\n * @example\n *\n * var object = { 'a': 1 };\n * var other = { 'a': 1 };\n *\n * _.eq(object, object);\n * // => true\n *\n * _.eq(object, other);\n * // => false\n *\n * _.eq('a', 'a');\n * // => true\n *\n * _.eq('a', Object('a'));\n * // => false\n *\n * _.eq(NaN, NaN);\n * // => true\n */\nfunction eq(value, other) {\n return value === other || (value !== value && other !== other);\n}\n\nexport default eq;\n","/**\n * Removes `key` and its value from the stack.\n *\n * @private\n * @name delete\n * @memberOf Stack\n * @param {string} key The key of the value to remove.\n * @returns {boolean} Returns `true` if the entry was removed, else `false`.\n */\nfunction stackDelete(key) {\n var data = this.__data__,\n result = data['delete'](key);\n\n this.size = data.size;\n return result;\n}\n\nexport default stackDelete;\n","/**\n * Gets the stack value for `key`.\n *\n * @private\n * @name get\n * @memberOf Stack\n * @param {string} key The key of the value to get.\n * @returns {*} Returns the entry value.\n */\nfunction stackGet(key) {\n return this.__data__.get(key);\n}\n\nexport default stackGet;\n","/**\n * Checks if a stack value for `key` exists.\n *\n * @private\n * @name has\n * @memberOf Stack\n * @param {string} key The key of the entry to check.\n * @returns {boolean} Returns `true` if an entry for `key` exists, else `false`.\n */\nfunction stackHas(key) {\n return this.__data__.has(key);\n}\n\nexport default stackHas;\n","/**\n * Checks if `value` is the\n * [language type](http://www.ecma-international.org/ecma-262/7.0/#sec-ecmascript-language-types)\n * of `Object`. (e.g. arrays, functions, objects, regexes, `new Number(0)`, and `new String('')`)\n *\n * @static\n * @memberOf _\n * @since 0.1.0\n * @category Lang\n * @param {*} value The value to check.\n * @returns {boolean} Returns `true` if `value` is an object, else `false`.\n * @example\n *\n * _.isObject({});\n * // => true\n *\n * _.isObject([1, 2, 3]);\n * // => true\n *\n * _.isObject(_.noop);\n * // => true\n *\n * _.isObject(null);\n * // => false\n */\nfunction isObject(value) {\n var type = typeof value;\n return value != null && (type == 'object' || type == 'function');\n}\n\nexport default isObject;\n","/** Used for built-in method references. */\nvar funcProto = Function.prototype;\n\n/** Used to resolve the decompiled source of functions. */\nvar funcToString = funcProto.toString;\n\n/**\n * Converts `func` to its source code.\n *\n * @private\n * @param {Function} func The function to convert.\n * @returns {string} Returns the source code.\n */\nfunction toSource(func) {\n if (func != null) {\n try {\n return funcToString.call(func);\n } catch (e) {}\n try {\n return (func + '');\n } catch (e) {}\n }\n return '';\n}\n\nexport default toSource;\n","/**\n * Gets the value at `key` of `object`.\n *\n * @private\n * @param {Object} [object] The object to query.\n * @param {string} key The key of the property to get.\n * @returns {*} Returns the property value.\n */\nfunction getValue(object, key) {\n return object == null ? undefined : object[key];\n}\n\nexport default getValue;\n","/**\n * Removes `key` and its value from the hash.\n *\n * @private\n * @name delete\n * @memberOf Hash\n * @param {Object} hash The hash to modify.\n * @param {string} key The key of the value to remove.\n * @returns {boolean} Returns `true` if the entry was removed, else `false`.\n */\nfunction hashDelete(key) {\n var result = this.has(key) && delete this.__data__[key];\n this.size -= result ? 1 : 0;\n return result;\n}\n\nexport default hashDelete;\n","/**\n * Checks if `value` is suitable for use as unique object key.\n *\n * @private\n * @param {*} value The value to check.\n * @returns {boolean} Returns `true` if `value` is suitable, else `false`.\n */\nfunction isKeyable(value) {\n var type = typeof value;\n return (type == 'string' || type == 'number' || type == 'symbol' || type == 'boolean')\n ? (value !== '__proto__')\n : (value === null);\n}\n\nexport default isKeyable;\n","/**\n * Creates a base function for methods like `_.forIn` and `_.forOwn`.\n *\n * @private\n * @param {boolean} [fromRight] Specify iterating from right to left.\n * @returns {Function} Returns the new base function.\n */\nfunction createBaseFor(fromRight) {\n return function(object, iteratee, keysFunc) {\n var index = -1,\n iterable = Object(object),\n props = keysFunc(object),\n length = props.length;\n\n while (length--) {\n var key = props[fromRight ? length : ++index];\n if (iteratee(iterable[key], key, iterable) === false) {\n break;\n }\n }\n return object;\n };\n}\n\nexport default createBaseFor;\n","/**\n * Copies the values of `source` to `array`.\n *\n * @private\n * @param {Array} source The array to copy values from.\n * @param {Array} [array=[]] The array to copy values to.\n * @returns {Array} Returns `array`.\n */\nfunction copyArray(source, array) {\n var index = -1,\n length = source.length;\n\n array || (array = Array(length));\n while (++index < length) {\n array[index] = source[index];\n }\n return array;\n}\n\nexport default copyArray;\n","/** Used for built-in method references. */\nvar objectProto = Object.prototype;\n\n/**\n * Checks if `value` is likely a prototype object.\n *\n * @private\n * @param {*} value The value to check.\n * @returns {boolean} Returns `true` if `value` is a prototype, else `false`.\n */\nfunction isPrototype(value) {\n var Ctor = value && value.constructor,\n proto = (typeof Ctor == 'function' && Ctor.prototype) || objectProto;\n\n return value === proto;\n}\n\nexport default isPrototype;\n","/** Used as references for various `Number` constants. */\nvar MAX_SAFE_INTEGER = 9007199254740991;\n\n/**\n * Checks if `value` is a valid array-like length.\n *\n * **Note:** This method is loosely based on\n * [`ToLength`](http://ecma-international.org/ecma-262/7.0/#sec-tolength).\n *\n * @static\n * @memberOf _\n * @since 4.0.0\n * @category Lang\n * @param {*} value The value to check.\n * @returns {boolean} Returns `true` if `value` is a valid length, else `false`.\n * @example\n *\n * _.isLength(3);\n * // => true\n *\n * _.isLength(Number.MIN_VALUE);\n * // => false\n *\n * _.isLength(Infinity);\n * // => false\n *\n * _.isLength('3');\n * // => false\n */\nfunction isLength(value) {\n return typeof value == 'number' &&\n value > -1 && value % 1 == 0 && value <= MAX_SAFE_INTEGER;\n}\n\nexport default isLength;\n","/**\n * This method returns `false`.\n *\n * @static\n * @memberOf _\n * @since 4.13.0\n * @category Util\n * @returns {boolean} Returns `false`.\n * @example\n *\n * _.times(2, _.stubFalse);\n * // => [false, false]\n */\nfunction stubFalse() {\n return false;\n}\n\nexport default stubFalse;\n","/**\n * The base implementation of `_.unary` without support for storing metadata.\n *\n * @private\n * @param {Function} func The function to cap arguments for.\n * @returns {Function} Returns the new capped function.\n */\nfunction baseUnary(func) {\n return function(value) {\n return func(value);\n };\n}\n\nexport default baseUnary;\n","/**\n * Gets the value at `key`, unless `key` is \"__proto__\" or \"constructor\".\n *\n * @private\n * @param {Object} object The object to query.\n * @param {string} key The key of the property to get.\n * @returns {*} Returns the property value.\n */\nfunction safeGet(object, key) {\n if (key === 'constructor' && typeof object[key] === 'function') {\n return;\n }\n\n if (key == '__proto__') {\n return;\n }\n\n return object[key];\n}\n\nexport default safeGet;\n","/**\n * The base implementation of `_.times` without support for iteratee shorthands\n * or max array length checks.\n *\n * @private\n * @param {number} n The number of times to invoke `iteratee`.\n * @param {Function} iteratee The function invoked per iteration.\n * @returns {Array} Returns the array of results.\n */\nfunction baseTimes(n, iteratee) {\n var index = -1,\n result = Array(n);\n\n while (++index < n) {\n result[index] = iteratee(index);\n }\n return result;\n}\n\nexport default baseTimes;\n","/** Used as references for various `Number` constants. */\nvar MAX_SAFE_INTEGER = 9007199254740991;\n\n/** Used to detect unsigned integer values. */\nvar reIsUint = /^(?:0|[1-9]\\d*)$/;\n\n/**\n * Checks if `value` is a valid array-like index.\n *\n * @private\n * @param {*} value The value to check.\n * @param {number} [length=MAX_SAFE_INTEGER] The upper bounds of a valid index.\n * @returns {boolean} Returns `true` if `value` is a valid index, else `false`.\n */\nfunction isIndex(value, length) {\n var type = typeof value;\n length = length == null ? MAX_SAFE_INTEGER : length;\n\n return !!length &&\n (type == 'number' ||\n (type != 'symbol' && reIsUint.test(value))) &&\n (value > -1 && value % 1 == 0 && value < length);\n}\n\nexport default isIndex;\n","/**\n * This function is like\n * [`Object.keys`](http://ecma-international.org/ecma-262/7.0/#sec-object.keys)\n * except that it includes inherited enumerable properties.\n *\n * @private\n * @param {Object} object The object to query.\n * @returns {Array} Returns the array of property names.\n */\nfunction nativeKeysIn(object) {\n var result = [];\n if (object != null) {\n for (var key in Object(object)) {\n result.push(key);\n }\n }\n return result;\n}\n\nexport default nativeKeysIn;\n","/**\n * This method returns the first argument it receives.\n *\n * @static\n * @since 0.1.0\n * @memberOf _\n * @category Util\n * @param {*} value Any value.\n * @returns {*} Returns `value`.\n * @example\n *\n * var object = { 'a': 1 };\n *\n * console.log(_.identity(object) === object);\n * // => true\n */\nfunction identity(value) {\n return value;\n}\n\nexport default identity;\n","/**\n * A faster alternative to `Function#apply`, this function invokes `func`\n * with the `this` binding of `thisArg` and the arguments of `args`.\n *\n * @private\n * @param {Function} func The function to invoke.\n * @param {*} thisArg The `this` binding of `func`.\n * @param {Array} args The arguments to invoke `func` with.\n * @returns {*} Returns the result of `func`.\n */\nfunction apply(func, thisArg, args) {\n switch (args.length) {\n case 0: return func.call(thisArg);\n case 1: return func.call(thisArg, args[0]);\n case 2: return func.call(thisArg, args[0], args[1]);\n case 3: return func.call(thisArg, args[0], args[1], args[2]);\n }\n return func.apply(thisArg, args);\n}\n\nexport default apply;\n","/**\n * Creates a function that returns `value`.\n *\n * @static\n * @memberOf _\n * @since 2.4.0\n * @category Util\n * @param {*} value The value to return from the new function.\n * @returns {Function} Returns the new constant function.\n * @example\n *\n * var objects = _.times(2, _.constant({ 'a': 1 }));\n *\n * console.log(objects);\n * // => [{ 'a': 1 }, { 'a': 1 }]\n *\n * console.log(objects[0] === objects[1]);\n * // => true\n */\nfunction constant(value) {\n return function() {\n return value;\n };\n}\n\nexport default constant;\n","/** Used to detect hot functions by number of calls within a span of milliseconds. */\nvar HOT_COUNT = 800,\n HOT_SPAN = 16;\n\n/* Built-in method references for those with the same name as other `lodash` methods. */\nvar nativeNow = Date.now;\n\n/**\n * Creates a function that'll short out and invoke `identity` instead\n * of `func` when it's called `HOT_COUNT` or more times in `HOT_SPAN`\n * milliseconds.\n *\n * @private\n * @param {Function} func The function to restrict.\n * @returns {Function} Returns the new shortable function.\n */\nfunction shortOut(func) {\n var count = 0,\n lastCalled = 0;\n\n return function() {\n var stamp = nativeNow(),\n remaining = HOT_SPAN - (stamp - lastCalled);\n\n lastCalled = stamp;\n if (remaining > 0) {\n if (++count >= HOT_COUNT) {\n return arguments[0];\n }\n } else {\n count = 0;\n }\n return func.apply(undefined, arguments);\n };\n}\n\nexport default shortOut;\n","// this get throw from within the checkOptions when run through the enum failed\nexport default class JsonqlEnumError extends Error {\n constructor(...args) {\n super(...args)\n\n this.message = args[0]\n this.detail = args[1]\n\n this.className = JsonqlEnumError.name;\n\n if (Error.captureStackTrace) {\n Error.captureStackTrace(this, JsonqlEnumError)\n }\n }\n\n static get name() {\n return 'JsonqlEnumError'\n }\n}\n","// this will throw from inside the checkOptions\nexport default class JsonqlTypeError extends Error {\n constructor(...args) {\n super(...args)\n\n this.message = args[0]\n this.detail = args[1]\n\n this.className = JsonqlTypeError.name\n\n if (Error.captureStackTrace) {\n Error.captureStackTrace(this, JsonqlTypeError)\n }\n }\n\n static get name() {\n return 'JsonqlTypeError'\n }\n}\n","// allow supply a custom checker function\n// if that failed then we throw this error\nexport default class JsonqlCheckerError extends Error {\n constructor(...args) {\n super(...args)\n this.message = args[0]\n this.detail = args[1]\n\n this.className = JsonqlCheckerError.name;\n\n if (Error.captureStackTrace) {\n Error.captureStackTrace(this, JsonqlCheckerError)\n }\n }\n\n static get name() {\n return 'JsonqlCheckerError'\n }\n}\n","// custom validation error class\n// when validaton failed\nexport default class JsonqlValidationError extends Error {\n constructor(...args) {\n super(...args)\n\n this.message = args[0]\n this.detail = args[1]\n\n this.className = JsonqlValidationError.name;\n\n if (Error.captureStackTrace) {\n Error.captureStackTrace(this, JsonqlValidationError)\n }\n }\n\n static get name() {\n return 'JsonqlValidationError'\n }\n}\n","// split the contract into the node side and the generic side\nimport { isObjectHasKey } from './generic'\nimport isPlainObject from 'lodash-es/isPlainObject'\nimport {\n QUERY_NAME,\n MUTATION_NAME,\n SOCKET_NAME,\n QUERY_ARG_NAME,\n PAYLOAD_PARAM_NAME,\n CONDITION_PARAM_NAME\n} from 'jsonql-constants'\nimport { JsonqlError, JsonqlResolverNotFoundError } from 'jsonql-errors'\n/**\n * Check if the json is a contract file or not\n * @param {object} contract json object\n * @return {boolean} true\n */\nexport function checkIsContract(contract) {\n return isPlainObject(contract)\n && (\n isObjectHasKey(contract, QUERY_NAME)\n || isObjectHasKey(contract, MUTATION_NAME)\n || isObjectHasKey(contract, SOCKET_NAME)\n )\n}\n\n/**\n * Wrapper method that check if it's contract then return the contract or false\n * @param {object} contract the object to check\n * @return {boolean | object} false when it's not\n */\nexport function isContract(contract) {\n return checkIsContract(contract) ? contract : false\n}\n\n/**\n * Ported from jsonql-params-validator but different\n * if we don't find the socket part then return false\n * @param {object} contract the contract object\n * @return {object|boolean} false on failed\n */\nexport function extractSocketPart(contract) {\n if (isObjectHasKey(contract, SOCKET_NAME)) {\n return contract[SOCKET_NAME]\n }\n return false\n}\n\n/**\n * Extract the args from the payload\n * @param {object} payload to work with\n * @param {string} type of call\n * @return {array} args\n */\nexport function extractArgsFromPayload(payload, type) {\n switch (type) {\n case QUERY_NAME:\n return payload[QUERY_ARG_NAME]\n case MUTATION_NAME:\n return [\n payload[PAYLOAD_PARAM_NAME],\n payload[CONDITION_PARAM_NAME]\n ]\n default:\n throw new JsonqlError(`Unknown ${type} to extract argument from!`)\n }\n}\n\n/**\n * Like what the name said\n * @param {object} contract the contract json\n * @param {string} type query|mutation\n * @param {string} name of the function\n * @return {object} the params part of the contract\n */\nexport function extractParamsFromContract(contract, type, name) {\n try {\n const result = contract[type][name]\n // debug('extractParamsFromContract', result)\n if (!result) {\n // debug(name, type, contract)\n throw new JsonqlResolverNotFoundError(name, type)\n }\n return result\n } catch(e) {\n throw new JsonqlResolverNotFoundError(name, e)\n }\n}\n","/**\n * @param {boolean} sec return in second or not\n * @return {number} timestamp\n */\nexport const timestamp = (sec = false) => {\n let time = Date.now()\n return sec ? Math.floor( time / 1000 ) : time\n}\n","// ported from jsonql-params-validator\n// craete several helper function to construct / extract the payload\n// and make sure they are all the same\nimport {\n PAYLOAD_PARAM_NAME,\n CONDITION_PARAM_NAME,\n RESOLVER_PARAM_NAME,\n QUERY_ARG_NAME,\n TIMESTAMP_PARAM_NAME\n} from 'jsonql-constants'\n\nimport JsonqlValidationError from 'jsonql-errors/src/validation-error'\n\nimport isArray from 'lodash-es/isArray'\nimport isString from 'lodash-es/isString'\nimport isPlainObject from 'lodash-es/isPlainObject'\n\nimport { timestamp } from './timestamp'\nimport { parseJson } from './generic'\n\n/**\n * check if the payload has a timestamp field, then append a new timestamp to it\n * @param {object} payload from the com\n * @return {array} timestamp field with an array value\n */\nexport const handleTimestamp = payload => {\n let ts = payload[TIMESTAMP_PARAM_NAME]\n if (!isArray(ts)) {\n ts = [ts]\n }\n ts.push( timestamp() )\n\n return ts\n}\n\n/**\n * make sure it's an object (it was call formatPayload but it doesn't make sense)\n * @param {*} payload the object comes in could be string based\n * @return {object} the transformed payload\n */\nexport const toPayload = payload => isString(payload) ? parseJson(payload) : payload\n\n/**\n * @param {*} args arguments to send\n *@return {object} formatted payload\n */\nexport const formatPayload = (args) => (\n { [QUERY_ARG_NAME]: args }\n)\n\n/**\n * extract the resolver name from the payload \n * @param {object} payload\n * @return {string} resolver name \n */\nexport function getResolverFromPayload(payload) {\n const keys = Object.keys(payload)\n return keys.filter(key => key !== TIMESTAMP_PARAM_NAME)[0]\n}\n\n/**\n * wrapper method to add the timestamp as well\n * @param {string} resolverName\n * @param {*} payload\n * @return {object} delierable\n */\nexport function createDeliverable(resolverName, payload) {\n return {\n [resolverName]: payload,\n [TIMESTAMP_PARAM_NAME]: [ timestamp() ]\n }\n}\n\n/**\n * @param {string} resolverName name of function\n * @param {array} [args=[]] from the ...args\n * @param {boolean} [jsonp = false] add v1.3.0 to koa\n * @return {object} formatted argument\n */\nexport function createQuery(resolverName, args = [], jsonp = false) {\n if (isString(resolverName) && isArray(args)) {\n let payload = formatPayload(args)\n if (jsonp === true) {\n return payload\n }\n return createDeliverable(resolverName, payload)\n }\n throw new JsonqlValidationError(`[createQuery] expect resolverName to be string and args to be array!`, { resolverName, args })\n}\n\n/**\n * string version of the createQuery\n * @return {string}\n */\nexport function createQueryStr(resolverName, args = [], jsonp = false) {\n return JSON.stringify(createQuery(resolverName, args, jsonp))\n}\n\n/**\n * @param {string} resolverName name of function\n * @param {*} payload to send\n * @param {object} [condition={}] for what\n * @param {boolean} [jsonp = false] add v1.3.0 to koa\n * @return {object} formatted argument\n */\nexport function createMutation(resolverName, payload, condition = {}, jsonp = false) {\n const _payload = {\n [PAYLOAD_PARAM_NAME]: payload,\n [CONDITION_PARAM_NAME]: condition\n }\n if (jsonp === true) {\n return _payload\n }\n if (isString(resolverName)) {\n return createDeliverable(resolverName, _payload)\n }\n throw new JsonqlValidationError(`[createMutation] expect resolverName to be string!`, { resolverName, payload, condition })\n}\n\n/**\n * string version of createMutation\n * @return {string}\n */\nexport function createMutationStr(resolverName, payload, condition = {}, jsonp = false) {\n return JSON.stringify(createMutation(resolverName, payload, condition, jsonp))\n}\n\n/**\n * Extract the parts from payload and format for use\n * @param {string} resolverName name of fn\n * @param {object} payload the incoming json\n * @return {object|boolean} false on failed\n */\nexport function getQueryFromArgs(resolverName, payload) {\n if (resolverName && isPlainObject(payload)) {\n const args = payload[resolverName]\n if (args[QUERY_ARG_NAME]) {\n return {\n [RESOLVER_PARAM_NAME]: resolverName,\n [QUERY_ARG_NAME]: args[QUERY_ARG_NAME],\n [TIMESTAMP_PARAM_NAME]: handleTimestamp(payload)\n }\n }\n }\n return false\n}\n\n/**\n * Share function so no repeat\n * @param {object} payload the payload from client\n * @param {function} processor the last get result method\n * @return {*} result processed result\n */\nfunction processPayload(payload, processor) {\n const p = toPayload(payload)\n const resolverName = getResolverFromPayload(p)\n return Reflect.apply(processor, null, [resolverName, p])\n}\n\n/**\n * extra the payload back\n * @param {*} payload from http call\n * @return {object} resolverName and args\n */\nexport function getQueryFromPayload(payload) {\n const result = processPayload(payload, getQueryFromArgs)\n if (result !== false) {\n return result\n }\n throw new JsonqlValidationError('[getQueryArgs] Payload is malformed!', payload)\n}\n\n/**\n * Further break down from method below for use else where\n * @param {string} resolverName name of fn\n * @param {object} payload payload\n * @return {object|boolean} false on failed\n */\nexport function getMutationFromArgs(resolverName, payload) {\n if (resolverName && isPlainObject(payload)) {\n const args = payload[resolverName]\n if (args) {\n return {\n [RESOLVER_PARAM_NAME]: resolverName,\n [PAYLOAD_PARAM_NAME]: args[PAYLOAD_PARAM_NAME],\n [CONDITION_PARAM_NAME]: args[CONDITION_PARAM_NAME],\n [TIMESTAMP_PARAM_NAME]: handleTimestamp(payload)\n }\n }\n }\n return false\n}\n\n/**\n * @param {object} payload\n * @return {object} resolverName, payload, conditon\n */\nexport function getMutationFromPayload(payload) {\n const result = processPayload(payload, getMutationFromArgs)\n\n if (result !== false) {\n return result\n }\n throw new JsonqlValidationError('[getMutationArgs] Payload is malformed!', payload)\n}\n","// take out all the namespace related methods in one place for easy to find\nimport {\n JSONQL_PATH,\n PUBLIC_KEY,\n NSP_GROUP,\n PUBLIC_NAMESPACE\n} from 'jsonql-constants'\nimport { extractSocketPart } from './contract'\nconst SOCKET_NOT_FOUND_ERR = `socket not found in contract!`\nconst SIZE = 'size'\n\n/**\n * create the group using publicNamespace when there is only public\n * @param {object} socket from contract\n * @param {string} publicNamespace\n */\nfunction groupPublicNamespace(socket, publicNamespace) {\n let g = {}\n for (let resolverName in socket) {\n let params = socket[resolverName]\n g[resolverName] = params\n }\n return { size: 1, nspGroup: {[publicNamespace]: g}, publicNamespace}\n}\n\n\n/**\n * @BUG we should check the socket part instead of expect the downstream to read the menu!\n * We only need this when the enableAuth is true otherwise there is only one namespace\n * @param {object} contract the socket part of the contract file\n * @return {object} 1. remap the contract using the namespace --> resolvers\n * 2. the size of the object (1 all private, 2 mixed public with private)\n * 3. which namespace is public\n */\nexport function groupByNamespace(contract) {\n let socket = extractSocketPart(contract)\n if (socket === false) {\n throw new JsonqlError('groupByNamespace', SOCKET_NOT_FOUND_ERR)\n }\n let prop = {\n [NSP_GROUP]: {},\n [PUBLIC_NAMESPACE]: null,\n [SIZE]: 0 \n }\n\n for (let resolverName in socket) {\n let params = socket[resolverName]\n let { namespace } = params\n if (namespace) {\n if (!prop[NSP_GROUP][namespace]) {\n ++prop[SIZE]\n prop[NSP_GROUP][namespace] = {}\n }\n prop[NSP_GROUP][namespace][resolverName] = params\n // get the public namespace\n if (!prop[PUBLIC_NAMESPACE] && params[PUBLIC_KEY]) {\n prop[PUBLIC_NAMESPACE] = namespace\n }\n }\n }\n \n return prop \n}\n\n/**\n * @NOTE ported from jsonql-ws-client\n * Got to make sure the connection order otherwise\n * it will hang\n * @param {object} nspGroup contract\n * @param {string} publicNamespace like the name said\n * @return {array} namespaces in order\n */\nexport function getNamespaceInOrder(nspGroup, publicNamespace) {\n let names = [] // need to make sure the order!\n for (let namespace in nspGroup) {\n if (namespace === publicNamespace) {\n names[1] = namespace\n } else {\n names[0] = namespace\n }\n }\n return names\n}\n\n/**\n * @TODO this might change, what if we want to do room with ws\n * 1. there will only be max two namespace\n * 2. when it's normal we will have the stock path as namespace\n * 3. when enableAuth then we will have two, one is jsonql/public + private\n * @param {object} config options\n * @return {array} of namespace(s)\n */\nexport function getNamespace(config) {\n const base = JSONQL_PATH\n if (config.enableAuth) {\n // the public come first @1.0.1 we use the constants instead of the user supplied value\n // @1.0.4 we use the config value again, because we could control this via the post init\n return [\n [ base , config.privateNamespace ].join('/'),\n [ base , config.publicNamespace ].join('/')\n ]\n }\n return [ base ]\n}\n\n/**\n * get the private namespace\n * @param {array} namespaces array\n * @return {*} string on success\n */\nexport function getPrivateNamespace(namespaces) {\n return namespaces.length > 1 ? namespaces[0] : false\n}\n\n/**\n * Got a problem with a contract that is public only the groupByNamespace is wrong\n * which is actually not a problem when using a fallback, but to be sure things in order\n * we could combine with the config to group it\n * @param {object} config configuration\n * @return {object} nspInfo object\n */\nexport function getNspInfoByConfig(config) {\n const { contract, enableAuth } = config\n const namespaces = getNamespace(config)\n let nspInfo = enableAuth ? groupByNamespace(contract)\n : groupPublicNamespace(contract.socket, namespaces[0])\n // add the namespaces into it as well\n return Object.assign(nspInfo, { namespaces })\n}\n\n","// There are the socket related methods ported back from \n// ws-server-core and ws-client-core \nimport {\n WS_REPLY_TYPE,\n WS_EVT_NAME,\n WS_DATA_NAME,\n TIMESTAMP_PARAM_NAME,\n ERROR_KEY,\n EMIT_REPLY_TYPE,\n ACKNOWLEDGE_REPLY_TYPE\n} from 'jsonql-constants'\nimport { JsonqlError } from 'jsonql-errors' \nimport isString from 'lodash-es/isString'\n\nimport { toJson, isObjectHasKey, nil } from './generic'\nimport { timestamp } from './timestamp'\n\nconst PAYLOAD_NOT_DECODED_ERR = 'payload can not decoded'\nconst WS_KEYS = [\n WS_REPLY_TYPE,\n WS_EVT_NAME,\n WS_DATA_NAME\n]\n\n/////////////////////////////////////\n// REPLY FROM SERVER //\n/////////////////////////////////////\n\n\n/**\n * The ws doesn't have a acknowledge callback like socket.io\n * so we have to DIY one for ws and other that doesn't have it\n * @param {string} type of reply\n * @param {string} resolverName which is replying\n * @param {*} data payload\n * @param {array} [ts= []] the last received ts, if any \n * @return {string} stringify json\n */\nexport const createWsReply = (type, resolverName, data, ts = []) => {\n ts.push(timestamp())\n return JSON.stringify({\n data: {\n [WS_REPLY_TYPE]: type,\n [WS_EVT_NAME]: resolverName,\n [WS_DATA_NAME]: toJson(data)\n },\n [TIMESTAMP_PARAM_NAME]: ts \n })\n}\n\n// extended function \nexport const createReplyMsg = (resolverName, data, ts = []) => (\n createWsReply(EMIT_REPLY_TYPE, resolverName, data, ts)\n)\n\nexport const createAcknowledgeMsg = (resolverName, data, ts = []) => (\n createWsReply(ACKNOWLEDGE_REPLY_TYPE, resolverName, data, ts)\n)\n\n/**\n * @param {string|object} payload should be string when reply but could be transformed\n * @return {boolean} true is OK\n */\nexport const isWsReply = payload => {\n const json = isString(payload) ? toJson(payload) : payload\n const { data } = json\n if (data) {\n let result = WS_KEYS.filter(key => isObjectHasKey(data, key))\n return (result.length === WS_KEYS.length) ? data : false\n }\n return false\n}\n\n/**\n * @param {string|object} data received data\n * @param {function} [cb=nil] this is for extracting the TS field or when it's error\n * @return {object} false on failed\n */\nexport const extractWsPayload = (payload, cb = nil) => {\n try {\n const json = toJson(payload)\n // now handle the data\n let _data\n if ((_data = isWsReply(json)) !== false) {\n // note the ts property is on its own \n cb(TIMESTAMP_PARAM_NAME, json[TIMESTAMP_PARAM_NAME])\n \n return {\n data: toJson(_data[WS_DATA_NAME]),\n resolverName: _data[WS_EVT_NAME],\n type: _data[WS_REPLY_TYPE]\n }\n }\n throw new JsonqlError(PAYLOAD_NOT_DECODED_ERR, payload)\n } catch(e) {\n return cb(ERROR_KEY, e)\n }\n}\n","// this will be part of the init client sequence\n// as soon as we create a ws client\n// we listen to the on.connect event \n// then we send a init-ping event back to the server\n// and server issue a csrf token back to use \n// we use this token to create a new client and destroy the old one\nimport {\n INTERCOM_RESOLVER_NAME, \n SOCKET_PING_EVENT_NAME,\n HEADERS_KEY,\n DATA_KEY,\n CSRF_HEADER_KEY\n} from 'jsonql-constants'\nimport { \n createQueryStr, \n extractWsPayload,\n timestamp,\n toJson \n} from 'jsonql-utils/module'\nimport {\n JsonqlError\n} from 'jsonql-errors'\nconst CSRF_HEADER_NOT_EXIST_ERR = 'CSRF header is not in the received payload'\n\n/**\n * Util method \n * @param {string} payload return from server\n * @return {object} the useful bit \n */\nfunction extractSrvPayload(payload) {\n let json = toJson(payload)\n \n if (json && typeof json === 'object') {\n // note this method expect the json.data inside\n return extractWsPayload(json)\n }\n \n throw new JsonqlError('extractSrvPayload', json)\n}\n\n/**\n * call the server to get a csrf token \n * @return {string} formatted payload to send to the server \n */\nfunction createInitPing() {\n const ts = timestamp()\n\n return createQueryStr(INTERCOM_RESOLVER_NAME, [SOCKET_PING_EVENT_NAME, ts])\n}\n\n/**\n * Take the raw on.message result back then decoded it \n * @param {*} payload the raw result from server\n * @return {object} the csrf payload\n */\nfunction extractPingResult(payload) {\n const result = extractSrvPayload(payload)\n \n if (result && result[DATA_KEY] && result[DATA_KEY][CSRF_HEADER_KEY]) {\n return {\n [HEADERS_KEY]: result[DATA_KEY]\n }\n }\n\n throw new JsonqlError('extractPingResult', CSRF_HEADER_NOT_EXIST_ERR)\n}\n\n\n/**\n * Create a generic intercom method\n * @param {string} type the event type \n * @param {array} args if any \n * @return {string} formatted payload to send\n */\nfunction createIntercomPayload(type, ...args) {\n const ts = timestamp()\n let payload = [type].concat(args)\n payload.push(ts)\n return createQueryStr(INTERCOM_RESOLVER_NAME, payload)\n}\n\n\nexport { \n extractSrvPayload,\n createInitPing, \n extractPingResult, \n createIntercomPayload \n}","// validator numbers\n// import { NUMBER_TYPES } from './constants';\n\nimport isNaN from 'lodash-es/isNaN'\nimport isString from 'lodash-es/isString'\n/**\n * @2015-05-04 found a problem if the value is a number like string\n * it will pass, so add a chck if it's string before we pass to next\n * @param {number} value expected value\n * @return {boolean} true if OK\n */\nconst checkIsNumber = function(value) {\n return isString(value) ? false : !isNaN( parseFloat(value) )\n}\n\nexport default checkIsNumber\n","// validate string type\nimport trim from 'lodash-es/trim'\nimport isString from 'lodash-es/isString'\n/**\n * @param {string} value expected value\n * @return {boolean} true if OK\n */\nconst checkIsString = function(value) {\n return (trim(value) !== '') ? isString(value) : false\n}\n\nexport default checkIsString\n","// check for boolean\n\n/**\n * @param {boolean} value expected\n * @return {boolean} true if OK\n */\nconst checkIsBoolean = function(value) {\n return value !== null && value !== undefined && typeof value === 'boolean'\n}\n\nexport default checkIsBoolean\n","// validate any thing only check if there is something\n\nimport trim from 'lodash-es/trim'\n\n/**\n * @param {*} value the value\n * @param {boolean} [checkNull=true] strict check if there is null value\n * @return {boolean} true is OK\n */\nconst checkIsAny = function(value, checkNull = true) {\n if (value !== undefined && value !== '' && trim(value) !== '') {\n if (checkNull === false || (checkNull === true && value !== null)) {\n return true;\n }\n }\n return false;\n}\n\nexport default checkIsAny\n","// Good practice rule - No magic number\n\nconst ARGS_NOT_ARRAY_ERR = `args is not an array! You might want to do: ES6 Array.from(arguments) or ES5 Array.prototype.slice.call(arguments)`\nconst PARAMS_NOT_ARRAY_ERR = `params is not an array! Did something gone wrong when you generate the contract.json?`\nconst EXCEPTION_CASE_ERR = 'Could not understand your arguments and parameter structure!'\nconst UNUSUAL_CASE_ERR = 'This is an unusual situation where the arguments are more than the params, but not mark as spread'\n\nconst RETURNS_NAME = 'returns'\n\nimport {\n \n DEFAULT_TYPE, // this is a mistake should move back to the validation\n DATA_KEY, \n ERROR_KEY,\n\n TYPE_KEY,\n OPTIONAL_KEY,\n ENUM_KEY,\n ARGS_KEY,\n CHECKER_KEY,\n ALIAS_KEY,\n\n ARRAY_TYPE_LFT,\n ARRAY_TYPE_RGT,\n \n ARRAY_TYPE,\n OBJECT_TYPE,\n STRING_TYPE,\n BOOLEAN_TYPE,\n NUMBER_TYPE,\n KEY_WORD,\n OR_SEPERATOR\n} from 'jsonql-constants'\n\n// group all export in one \nexport {\n ARGS_NOT_ARRAY_ERR,\n PARAMS_NOT_ARRAY_ERR,\n EXCEPTION_CASE_ERR,\n UNUSUAL_CASE_ERR,\n DEFAULT_TYPE,\n ARRAY_TYPE_LFT,\n ARRAY_TYPE_RGT,\n TYPE_KEY,\n OPTIONAL_KEY,\n ENUM_KEY,\n ARGS_KEY,\n CHECKER_KEY,\n ALIAS_KEY,\n ARRAY_TYPE,\n OBJECT_TYPE,\n STRING_TYPE,\n BOOLEAN_TYPE,\n NUMBER_TYPE,\n KEY_WORD,\n OR_SEPERATOR,\n\n RETURNS_NAME,\n\n DATA_KEY, \n ERROR_KEY \n}","// primitive types\nimport checkIsNumber from './number'\nimport checkIsString from './string'\nimport checkIsBoolean from './boolean'\nimport checkIsAny from './any'\nimport { NUMBER_TYPE, STRING_TYPE, BOOLEAN_TYPE } from './constants'\n\n/**\n * this is a wrapper method to call different one based on their type\n * @param {string} type to check\n * @return {function} a function to handle the type\n */\nconst combineFn = function(type) {\n switch (type) {\n case NUMBER_TYPE:\n return checkIsNumber\n case STRING_TYPE:\n return checkIsString\n case BOOLEAN_TYPE:\n return checkIsBoolean\n default:\n return checkIsAny\n }\n}\n\nexport default combineFn\n","// validate array type\n\nimport isArray from 'lodash-es/isArray'\nimport trim from 'lodash-es/trim'\nimport combineFn from './combine'\nimport {\n ARRAY_TYPE_LFT,\n ARRAY_TYPE_RGT,\n OR_SEPERATOR\n} from './constants'\n\n/**\n * @param {array} value expected\n * @param {string} [type=''] pass the type if we encounter array. then we need to check the value as well\n * @return {boolean} true if OK\n */\nexport const checkIsArray = function(value, type='') {\n if (isArray(value)) {\n if (type === '' || trim(type)==='') {\n return true;\n }\n // we test it in reverse\n // @TODO if the type is an array (OR) then what?\n // we need to take into account this could be an array\n const c = value.filter(v => !combineFn(type)(v))\n return !(c.length > 0)\n }\n return false\n}\n\n/**\n * check if it matches the array. pattern\n * @param {string} type\n * @return {boolean|array} false means NO, always return array\n */\nexport const isArrayLike = function(type) {\n // @TODO could that have something like array<> instead of array.<>? missing the dot?\n // because type script is Array without the dot\n if (type.indexOf(ARRAY_TYPE_LFT) > -1 && type.indexOf(ARRAY_TYPE_RGT) > -1) {\n const _type = type.replace(ARRAY_TYPE_LFT, '').replace(ARRAY_TYPE_RGT, '')\n if (_type.indexOf(OR_SEPERATOR)) {\n return _type.split(OR_SEPERATOR)\n }\n return [_type]\n }\n return false\n}\n\n/**\n * we might encounter something like array. then we need to take it apart\n * @param {object} p the prepared object for processing\n * @param {string|array} type the type came from \n * @return {boolean} for the filter to operate on\n */\nexport const arrayTypeHandler = function(p, type) {\n const { arg } = p\n // need a special case to handle the OR type\n // we need to test the args instead of the type(s)\n if (type.length > 1) {\n return !arg.filter(v => (\n !(type.length > type.filter(t => !combineFn(t)(v)).length)\n )).length\n }\n // type is array so this will be or!\n return type.length > type.filter(t => !checkIsArray(arg, t)).length\n}\n","// validate object type\n\nimport isPlainObject from 'lodash-es/isPlainObject'\n// import filter from 'lodash-es/filter'\nimport combineFn from './combine'\nimport { checkIsArray, isArrayLike, arrayTypeHandler } from './array'\n/**\n * @TODO if provide with the keys then we need to check if the key:value type as well\n * @param {object} value expected\n * @param {array} [keys=null] if it has the keys array to compare as well\n * @return {boolean} true if OK\n */\nexport const checkIsObject = function(value, keys=null) {\n if (isPlainObject(value)) {\n if (!keys) {\n return true\n }\n if (checkIsArray(keys)) {\n // please note we DON'T care if some is optional\n // plese refer to the contract.json for the keys\n return !keys.filter(key => {\n let _value = value[key.name];\n return !(key.type.length > key.type.filter(type => {\n let tmp;\n if (_value !== undefined) {\n if ((tmp = isArrayLike(type)) !== false) {\n return !arrayTypeHandler({arg: _value}, tmp)\n // return tmp.filter(t => !checkIsArray(_value, t)).length;\n // @TODO there might be an object within an object with keys as well :S\n }\n return !combineFn(type)(_value)\n }\n return true\n }).length)\n }).length;\n }\n }\n return false\n}\n\n/**\n * fold this into it's own function to handler different object type\n * @param {object} p the prepared object for process\n * @return {boolean}\n */\nexport const objectTypeHandler = function(p) {\n const { arg, param } = p\n let _args = [arg]\n if (Array.isArray(param.keys) && param.keys.length) {\n _args.push(param.keys)\n }\n // just simple check\n return Reflect.apply(checkIsObject, null, _args)\n}\n","// move the index.js code here that make more sense to find where things are\n\nimport {\n checkIsArray,\n isArrayLike,\n arrayTypeHandler,\n objectTypeHandler,\n combineFn,\n notEmpty\n} from './index'\n\nimport {\n DEFAULT_TYPE,\n ARRAY_TYPE,\n OBJECT_TYPE,\n ARGS_NOT_ARRAY_ERR,\n PARAMS_NOT_ARRAY_ERR,\n EXCEPTION_CASE_ERR,\n DATA_KEY, \n ERROR_KEY \n} from './constants'\n\n\nimport JsonqlValidationError from 'jsonql-errors/src/validation-error'\nimport JsonqlError from 'jsonql-errors/src/error'\n// import debug from 'debug'\n// const debugFn = debug('jsonql-params-validator:validator')\n// also export this for use in other places\n\n/**\n * We need to handle those optional parameter without a default value\n * @param {object} params from contract.json\n * @return {boolean} for filter operation false is actually OK\n */\nconst optionalHandler = function( params ) {\n const { arg, param } = params\n if (notEmpty(arg)) {\n // debug('call optional handler', arg, params);\n // loop through the type in param\n return !(param.type.length > param.type.filter(type =>\n validateHandler(type, params)\n ).length)\n }\n return false\n}\n\n/**\n * actually picking the validator\n * @param {*} type for checking\n * @param {*} value for checking\n * @return {boolean} true on OK\n */\nconst validateHandler = function(type, value) {\n let tmp;\n switch (true) {\n case type === OBJECT_TYPE:\n // debugFn('call OBJECT_TYPE')\n return !objectTypeHandler(value)\n case type === ARRAY_TYPE:\n // debugFn('call ARRAY_TYPE')\n return !checkIsArray(value.arg)\n // @TODO when the type is not present, it always fall through here\n // so we need to find a way to actually pre-check the type first\n // AKA check the contract.json map before running here\n case (tmp = isArrayLike(type)) !== false:\n // debugFn('call ARRAY_LIKE: %O', value)\n return !arrayTypeHandler(value, tmp)\n default:\n return !combineFn(type)(value.arg)\n }\n}\n\n/**\n * it get too longer to fit in one line so break it out from the fn below\n * @param {*} arg value\n * @param {object} param config\n * @return {*} value or apply default value\n */\nconst getOptionalValue = function(arg, param) {\n if (arg !== undefined) {\n return arg\n }\n return (param.optional === true && param.defaultvalue !== undefined ? param.defaultvalue : null)\n}\n\n/**\n * padding the arguments with defaultValue if the arguments did not provide the value\n * this will be the name export\n * @param {array} args normalized arguments\n * @param {array} params from contract.json\n * @return {array} merge the two together\n */\nexport const normalizeArgs = function(args, params) {\n // first we should check if this call require a validation at all\n // there will be situation where the function doesn't need args and params\n if (!checkIsArray(params)) {\n // debugFn('params value', params)\n throw new JsonqlValidationError(PARAMS_NOT_ARRAY_ERR)\n }\n if (params.length === 0) {\n return []\n }\n if (!checkIsArray(args)) {\n throw new JsonqlValidationError(ARGS_NOT_ARRAY_ERR)\n }\n // debugFn(args, params);\n // fall through switch\n switch(true) {\n case args.length == params.length: // standard\n return args.map((arg, i) => (\n {\n arg,\n index: i,\n param: params[i]\n }\n ))\n case params[0].variable === true: // using spread syntax\n const type = params[0].type;\n return args.map((arg, i) => (\n {\n arg,\n index: i, // keep the index for reference\n param: params[i] || { type, name: '_' }\n }\n ))\n // with optional defaultValue parameters\n case args.length < params.length:\n return params.map((param, i) => (\n {\n param,\n index: i,\n arg: getOptionalValue(args[i], param),\n optional: param.optional || false\n }\n ))\n // this one pass more than it should have anything after the args.length will be cast as any type\n case args.length > params.length:\n let ctn = params.length;\n // this happens when we have those array. type\n let _type = [ DEFAULT_TYPE ]\n // we only looking at the first one, this might be a @BUG\n /*\n if ((tmp = isArrayLike(params[0].type[0])) !== false) {\n _type = tmp;\n } */\n // if we use the params as guide then the rest will get throw out\n // which is not what we want, instead, anything without the param\n // will get a any type and optional flag\n return args.map((arg, i) => {\n let optional = i >= ctn ? true : !!params[i].optional\n let param = params[i] || { type: _type, name: `_${i}` }\n return {\n arg: optional ? getOptionalValue(arg, param) : arg,\n index: i,\n param,\n optional\n }\n })\n // @TODO find out if there is more cases not cover\n default: // this should never happen\n // debugFn('args', args)\n // debugFn('params', params)\n // this is unknown therefore we just throw it!\n throw new JsonqlError(EXCEPTION_CASE_ERR, { args, params })\n }\n}\n\n// what we want is after the validaton we also get the normalized result\n// which is with the optional property if the argument didn't provide it\n/**\n * process the array of params back to their arguments\n * @param {array} result the params result\n * @return {array} arguments\n */\nconst processReturn = result => result.map(r => r.arg)\n\n/**\n * validator main interface\n * @param {array} args the arguments pass to the method call\n * @param {array} params from the contract for that method\n * @param {boolean} [withResul=false] if true then this will return the normalize result as well\n * @return {array} empty array on success, or failed parameter and reasons\n */\nexport const validateSync = function(args, params, withResult = false) {\n let cleanArgs = normalizeArgs(args, params)\n let checkResult = cleanArgs.filter(p => {\n // v1.4.4 this fixed the problem, the root level optional is from the last fn\n if (p.optional === true || p.param.optional === true) {\n return optionalHandler(p)\n }\n // because array of types means OR so if one pass means pass\n return !(p.param.type.length > p.param.type.filter(\n type => validateHandler(type, p)\n ).length)\n })\n // using the same convention we been using all this time\n return !withResult ? checkResult : {\n [ERROR_KEY]: checkResult,\n [DATA_KEY]: processReturn(cleanArgs)\n }\n}\n\n/**\n * A wrapper method that return promise\n * @param {array} args arguments\n * @param {array} params from contract.json\n * @param {boolean} [withResul=false] if true then this will return the normalize result as well\n * @return {object} promise.then or catch\n */\nexport const validateAsync = function(args, params, withResult = false) {\n return new Promise((resolver, rejecter) => {\n const result = validateSync(args, params, withResult)\n if (withResult) {\n return result[ERROR_KEY].length ? rejecter(result[ERROR_KEY])\n : resolver(result[DATA_KEY])\n }\n // the different is just in the then or catch phrase\n return result.length ? rejecter(result) : resolver([])\n })\n}\n","/** Used to stand-in for `undefined` hash values. */\nvar HASH_UNDEFINED = '__lodash_hash_undefined__';\n\n/**\n * Adds `value` to the array cache.\n *\n * @private\n * @name add\n * @memberOf SetCache\n * @alias push\n * @param {*} value The value to cache.\n * @returns {Object} Returns the cache instance.\n */\nfunction setCacheAdd(value) {\n this.__data__.set(value, HASH_UNDEFINED);\n return this;\n}\n\nexport default setCacheAdd;\n","/**\n * Checks if `value` is in the array cache.\n *\n * @private\n * @name has\n * @memberOf SetCache\n * @param {*} value The value to search for.\n * @returns {number} Returns `true` if `value` is found, else `false`.\n */\nfunction setCacheHas(value) {\n return this.__data__.has(value);\n}\n\nexport default setCacheHas;\n","/**\n * A specialized version of `_.some` for arrays without support for iteratee\n * shorthands.\n *\n * @private\n * @param {Array} [array] The array to iterate over.\n * @param {Function} predicate The function invoked per iteration.\n * @returns {boolean} Returns `true` if any element passes the predicate check,\n * else `false`.\n */\nfunction arraySome(array, predicate) {\n var index = -1,\n length = array == null ? 0 : array.length;\n\n while (++index < length) {\n if (predicate(array[index], index, array)) {\n return true;\n }\n }\n return false;\n}\n\nexport default arraySome;\n","/**\n * Checks if a `cache` value for `key` exists.\n *\n * @private\n * @param {Object} cache The cache to query.\n * @param {string} key The key of the entry to check.\n * @returns {boolean} Returns `true` if an entry for `key` exists, else `false`.\n */\nfunction cacheHas(cache, key) {\n return cache.has(key);\n}\n\nexport default cacheHas;\n","/**\n * Converts `map` to its key-value pairs.\n *\n * @private\n * @param {Object} map The map to convert.\n * @returns {Array} Returns the key-value pairs.\n */\nfunction mapToArray(map) {\n var index = -1,\n result = Array(map.size);\n\n map.forEach(function(value, key) {\n result[++index] = [key, value];\n });\n return result;\n}\n\nexport default mapToArray;\n","/**\n * Converts `set` to an array of its values.\n *\n * @private\n * @param {Object} set The set to convert.\n * @returns {Array} Returns the values.\n */\nfunction setToArray(set) {\n var index = -1,\n result = Array(set.size);\n\n set.forEach(function(value) {\n result[++index] = value;\n });\n return result;\n}\n\nexport default setToArray;\n","/**\n * Appends the elements of `values` to `array`.\n *\n * @private\n * @param {Array} array The array to modify.\n * @param {Array} values The values to append.\n * @returns {Array} Returns `array`.\n */\nfunction arrayPush(array, values) {\n var index = -1,\n length = values.length,\n offset = array.length;\n\n while (++index < length) {\n array[offset + index] = values[index];\n }\n return array;\n}\n\nexport default arrayPush;\n","/**\n * A specialized version of `_.filter` for arrays without support for\n * iteratee shorthands.\n *\n * @private\n * @param {Array} [array] The array to iterate over.\n * @param {Function} predicate The function invoked per iteration.\n * @returns {Array} Returns the new filtered array.\n */\nfunction arrayFilter(array, predicate) {\n var index = -1,\n length = array == null ? 0 : array.length,\n resIndex = 0,\n result = [];\n\n while (++index < length) {\n var value = array[index];\n if (predicate(value, index, array)) {\n result[resIndex++] = value;\n }\n }\n return result;\n}\n\nexport default arrayFilter;\n","/**\n * This method returns a new empty array.\n *\n * @static\n * @memberOf _\n * @since 4.13.0\n * @category Util\n * @returns {Array} Returns the new empty array.\n * @example\n *\n * var arrays = _.times(2, _.stubArray);\n *\n * console.log(arrays);\n * // => [[], []]\n *\n * console.log(arrays[0] === arrays[1]);\n * // => false\n */\nfunction stubArray() {\n return [];\n}\n\nexport default stubArray;\n","/**\n * A specialized version of `matchesProperty` for source values suitable\n * for strict equality comparisons, i.e. `===`.\n *\n * @private\n * @param {string} key The key of the property to get.\n * @param {*} srcValue The value to match.\n * @returns {Function} Returns the new spec function.\n */\nfunction matchesStrictComparable(key, srcValue) {\n return function(object) {\n if (object == null) {\n return false;\n }\n return object[key] === srcValue &&\n (srcValue !== undefined || (key in Object(object)));\n };\n}\n\nexport default matchesStrictComparable;\n","/**\n * The base implementation of `_.hasIn` without support for deep paths.\n *\n * @private\n * @param {Object} [object] The object to query.\n * @param {Array|string} key The key to check.\n * @returns {boolean} Returns `true` if `key` exists, else `false`.\n */\nfunction baseHasIn(object, key) {\n return object != null && key in Object(object);\n}\n\nexport default baseHasIn;\n","/**\n * The base implementation of `_.property` without support for deep paths.\n *\n * @private\n * @param {string} key The key of the property to get.\n * @returns {Function} Returns the new accessor function.\n */\nfunction baseProperty(key) {\n return function(object) {\n return object == null ? undefined : object[key];\n };\n}\n\nexport default baseProperty;\n","/** Error message constants. */\nvar FUNC_ERROR_TEXT = 'Expected a function';\n\n/**\n * Creates a function that negates the result of the predicate `func`. The\n * `func` predicate is invoked with the `this` binding and arguments of the\n * created function.\n *\n * @static\n * @memberOf _\n * @since 3.0.0\n * @category Function\n * @param {Function} predicate The predicate to negate.\n * @returns {Function} Returns the new negated function.\n * @example\n *\n * function isEven(n) {\n * return n % 2 == 0;\n * }\n *\n * _.filter([1, 2, 3, 4, 5, 6], _.negate(isEven));\n * // => [1, 3, 5]\n */\nfunction negate(predicate) {\n if (typeof predicate != 'function') {\n throw new TypeError(FUNC_ERROR_TEXT);\n }\n return function() {\n var args = arguments;\n switch (args.length) {\n case 0: return !predicate.call(this);\n case 1: return !predicate.call(this, args[0]);\n case 2: return !predicate.call(this, args[0], args[1]);\n case 3: return !predicate.call(this, args[0], args[1], args[2]);\n }\n return !predicate.apply(this, args);\n };\n}\n\nexport default negate;\n","/**\n * The base implementation of methods like `_.findKey` and `_.findLastKey`,\n * without support for iteratee shorthands, which iterates over `collection`\n * using `eachFunc`.\n *\n * @private\n * @param {Array|Object} collection The collection to inspect.\n * @param {Function} predicate The function invoked per iteration.\n * @param {Function} eachFunc The function to iterate over `collection`.\n * @returns {*} Returns the found element or its key, else `undefined`.\n */\nfunction baseFindKey(collection, predicate, eachFunc) {\n var result;\n eachFunc(collection, function(value, key, collection) {\n if (predicate(value, key, collection)) {\n result = key;\n return false;\n }\n });\n return result;\n}\n\nexport default baseFindKey;\n","/**\n * @param {array} arr Array for check\n * @param {*} value target\n * @return {boolean} true on successs\n */\nconst isInArray = function(arr, value) {\n return !!arr.filter(a => a === value).length\n}\n\nexport default isInArray\n","// breaking the whole thing up to see what cause the multiple calls issue\n\nimport isFunction from 'lodash-es/isFunction'\nimport merge from 'lodash-es/merge'\nimport mapValues from 'lodash-es/mapValues'\n\nimport JsonqlEnumError from 'jsonql-errors/src/enum-error'\nimport JsonqlTypeError from 'jsonql-errors/src/type-error'\nimport JsonqlCheckerError from 'jsonql-errors/src/checker-error'\n\nimport {\n TYPE_KEY,\n OPTIONAL_KEY,\n ENUM_KEY,\n ARGS_KEY,\n CHECKER_KEY,\n KEY_WORD\n} from '../constants'\nimport { checkIsArray } from '../array'\n\n// import debug from 'debug';\n// const debugFn = debug('jsonql-params-validator:options:validation')\n\n/**\n * just make sure it returns an array to use\n * @param {*} arg input\n * @return {array} output\n */\nconst toArray = arg => checkIsArray(arg) ? arg : [arg]\n\n/**\n * DIY in array\n * @param {array} arr to check against\n * @param {*} value to check\n * @return {boolean} true on OK\n */\nconst inArray = (arr, value) => (\n !!arr.filter(v => v === value).length\n)\n\n/**\n * break out to make the code easier to read\n * @param {object} value to process\n * @param {function} cb the validateSync\n * @return {array} empty on success\n */\nfunction validateHandler(value, cb) {\n // cb is the validateSync methods\n let args = [\n [ value[ARGS_KEY] ],\n [{\n [TYPE_KEY]: toArray(value[TYPE_KEY]),\n [OPTIONAL_KEY]: value[OPTIONAL_KEY]\n }]\n ]\n // debugFn('validateHandler', args)\n return Reflect.apply(cb, null, args)\n}\n\n/**\n * Check against the enum value if it's provided\n * @param {*} value to check\n * @param {*} enumv to check against if it's not false\n * @return {boolean} true on OK\n */\nconst enumHandler = (value, enumv) => {\n if (checkIsArray(enumv)) {\n return inArray(enumv, value)\n }\n return true\n}\n\n/**\n * Allow passing a function to check the value\n * There might be a problem here if the function is incorrect\n * and that will makes it hard to debug what is going on inside\n * @TODO there could be a few feature add to this one under different circumstance\n * @param {*} value to check\n * @param {function} checker for checking\n */\nconst checkerHandler = (value, checker) => {\n try {\n return isFunction(checker) ? checker.apply(null, [value]) : false\n } catch (e) {\n return false\n }\n}\n\n/**\n * Taken out from the runValidaton this only validate the required values\n * @param {array} args from the config2argsAction\n * @param {function} cb validateSync\n * @return {array} of configuration values\n */\nfunction runValidationAction(cb) {\n return (value, key) => {\n // debugFn('runValidationAction', key, value)\n if (value[KEY_WORD]) {\n return value[ARGS_KEY]\n }\n const check = validateHandler(value, cb)\n if (check.length) {\n // log('runValidationAction', key, value)\n throw new JsonqlTypeError(key, check)\n }\n if (value[ENUM_KEY] !== false && !enumHandler(value[ARGS_KEY], value[ENUM_KEY])) {\n // log(ENUM_KEY, value[ENUM_KEY])\n throw new JsonqlEnumError(key)\n }\n if (value[CHECKER_KEY] !== false && !checkerHandler(value[ARGS_KEY], value[CHECKER_KEY])) {\n // log(CHECKER_KEY, value[CHECKER_KEY])\n throw new JsonqlCheckerError(key)\n }\n return value[ARGS_KEY]\n }\n}\n\n/**\n * @param {object} args from the config2argsAction\n * @param {function} cb validateSync\n * @return {object} of configuration values\n */\nexport default function runValidation(args, cb) {\n const [ argsForValidate, pristineValues ] = args\n // turn the thing into an array and see what happen here\n // debugFn('_args', argsForValidate)\n const result = mapValues(argsForValidate, runValidationAction(cb))\n return merge(result, pristineValues)\n}\n","/// this is port back from the client to share across all projects\n\nimport merge from 'lodash-es/merge'\nimport { prepareArgsForValidation } from './prepare-args-for-validation'\nimport runValidation from './run-validation'\n\n// import debug from 'debug'\n// const debugFn = debug('jsonql-params-validator:check-options-async')\n\n/**\n * Quick transform\n * @param {object} config that one\n * @param {object} appProps mutation configuration options\n * @return {object} put that arg into the args\n */\nconst configToArgs = (config, appProps) => {\n return Promise.resolve(\n prepareArgsForValidation(config, appProps)\n )\n}\n\n/**\n * @param {object} config user provide configuration option\n * @param {object} appProps mutation configuration options\n * @param {object} constProps the immutable configuration options\n * @param {function} cb the validateSync method\n * @return {object} Promise resolve merge config object\n */\nexport default function(config = {}, appProps, constProps, cb) {\n return configToArgs(config, appProps)\n .then(args1 => runValidation(args1, cb))\n // next if every thing good then pass to final merging\n .then(args2 => merge({}, args2, constProps))\n}\n","// create function to construct the config entry so we don't need to keep building object\n\nimport isFunction from 'lodash-es/isFunction'\nimport isString from 'lodash-es/isString'\nimport {\n ARGS_KEY,\n TYPE_KEY,\n CHECKER_KEY,\n ENUM_KEY,\n OPTIONAL_KEY,\n ALIAS_KEY\n} from 'jsonql-constants'\n\nimport { checkIsArray } from '../array'\n// import checkIsBoolean from '../boolean'\n// import debug from 'debug';\n// const debugFn = debug('jsonql-params-validator:construct-config');\n/**\n * @param {*} args value\n * @param {string} type for value\n * @param {boolean} [optional=false]\n * @param {boolean|array} [enumv=false]\n * @param {boolean|function} [checker=false]\n * @return {object} config entry\n */\nexport default function constructConfig(args, type, optional=false, enumv=false, checker=false, alias=false) {\n let base = {\n [ARGS_KEY]: args,\n [TYPE_KEY]: type\n }\n if (optional === true) {\n base[OPTIONAL_KEY] = true\n }\n if (checkIsArray(enumv)) {\n base[ENUM_KEY] = enumv\n }\n if (isFunction(checker)) {\n base[CHECKER_KEY] = checker\n }\n if (isString(alias)) {\n base[ALIAS_KEY] = alias\n }\n return base\n}\n","// export also create wrapper methods\nimport checkOptionsAsync from './check-options-async'\nimport checkOptionsSync from './check-options-sync'\nimport constructConfigFn from './construct-config'\nimport {\n ENUM_KEY,\n CHECKER_KEY,\n ALIAS_KEY,\n OPTIONAL_KEY\n} from 'jsonql-constants'\n\n/**\n * This has a different interface\n * @param {*} value to supply\n * @param {string|array} type for checking\n * @param {object} params to map against the config check\n * @param {array} params.enumv NOT enum\n * @param {boolean} params.optional false then nothing\n * @param {function} params.checker need more work on this one later\n * @param {string} params.alias mostly for cmd\n */\nconst createConfig = (value, type, params = {}) => {\n // Note the enumv not ENUM\n // const { enumv, optional, checker, alias } = params;\n // let args = [value, type, optional, enumv, checker, alias];\n const {\n [OPTIONAL_KEY]: o,\n [ENUM_KEY]: e,\n [CHECKER_KEY]: c,\n [ALIAS_KEY]: a\n } = params;\n return constructConfigFn.apply(null, [value, type, o, e, c, a])\n}\n\n// for testing purpose\nconst JSONQL_PARAMS_VALIDATOR_INFO = '__PLACEHOLDER__'\n\n/**\n * construct the actual end user method, rename with prefix get since 1.5.2\n * @param {function} validateSync validation method\n * @return {function} for performaning the actual valdiation\n */\nconst getCheckConfigAsync = function(validateSync) {\n /**\n * We recreate the method here to avoid the circlar import\n * @param {object} config user supply configuration\n * @param {object} appProps mutation options\n * @param {object} [constantProps={}] optional: immutation options\n * @return {object} all checked configuration\n */\n return function(config, appProps, constantProps= {}) {\n return checkOptionsAsync(config, appProps, constantProps, validateSync)\n }\n}\n\n/**\n * copy of above but it's sync, rename with prefix get since 1.5.2\n * @param {function} validateSync validation method\n * @return {function} for performaning the actual valdiation\n */\nconst getCheckConfig = function(validateSync) {\n return function(config, appProps, constantProps = {}) {\n return checkOptionsSync(config, appProps, constantProps, validateSync)\n }\n}\n\n// re-export\nexport {\n createConfig,\n constructConfigFn,\n getCheckConfigAsync,\n getCheckConfig,\n JSONQL_PARAMS_VALIDATOR_INFO\n}\n","// export\nimport {\n checkIsObject,\n notEmpty,\n checkIsAny,\n checkIsString,\n checkIsBoolean,\n checkIsNumber,\n checkIsArray\n} from './src'\nimport * as validator from './src/validator'\n// configuration checking\nimport * as jsonqlOptions from './src/options'\n// the two extra functions\nimport isInArray from './src/is-in-array'\nimport isObjectHasKeyFn from './src/is-key-in-object'\n\nconst isObject = checkIsObject\nconst isAny = checkIsAny\nconst isString = checkIsString\nconst isBoolean = checkIsBoolean\nconst isNumber = checkIsNumber\nconst isArray = checkIsArray\nconst isNotEmpty = notEmpty\n\nconst normalizeArgs = validator.normalizeArgs\nconst validateSync = validator.validateSync\nconst validateAsync = validator.validateAsync\n\nconst JSONQL_PARAMS_VALIDATOR_INFO = jsonqlOptions.JSONQL_PARAMS_VALIDATOR_INFO\n\nconst createConfig = jsonqlOptions.createConfig\nconst constructConfig = jsonqlOptions.constructConfigFn\n// construct the final output 1.5.2\nconst checkConfigAsync = jsonqlOptions.getCheckConfigAsync(validator.validateSync)\nconst checkConfig = jsonqlOptions.getCheckConfig(validator.validateSync)\n\nconst inArray = isInArray\nconst isObjectHasKey = isObjectHasKeyFn\n\n// check returns methods \nimport { \n checkReturns, \n checkReturnsAsync, \n checkResolverReturns, \n checkResolverReturnsAsync \n} from './src/returns'\n\n\n// group the in one \nexport {\n JSONQL_PARAMS_VALIDATOR_INFO,\n \n isObject,\n isAny,\n isString,\n isBoolean,\n isNumber,\n isArray,\n isNotEmpty,\n \n inArray,\n isObjectHasKey,\n\n normalizeArgs,\n validateSync,\n validateAsync,\n\n createConfig,\n constructConfig,\n checkConfig,\n checkConfigAsync,\n\n checkReturns, \n checkReturnsAsync, \n checkResolverReturns, \n checkResolverReturnsAsync\n}\n\n\n\n\n\n","// move the get logger stuff here\n\n// it does nothing\nconst dummyLogger = () => {}\n\n/**\n * re-use the debugOn prop to control this log method\n * @param {object} opts configuration\n * @return {function} the log function\n */\nconst getLogger = (opts) => {\n const { debugOn } = opts \n if (debugOn) {\n return (...args) => {\n Reflect.apply(console.info, console, ['[jsonql-ws-client-core]', ...args])\n }\n }\n return dummyLogger\n}\n\n/**\n * Make sure there is a log method\n * @param {object} opts configuration\n * @return {object} opts\n */\nconst getLogFn = opts => {\n const { log } = opts // 1.3.9 if we pass a log method here then we use this\n if (!log || typeof log !== 'function') {\n return getLogger(opts)\n }\n opts.log('---> getLogFn user supplied log function <---', opts)\n return log\n}\n\nexport { getLogFn }","// group all the repetitive message here\n\nexport const TAKEN_BY_OTHER_TYPE_ERR = 'You are trying to register an event already been taken by other type:'\n","// Create two WeakMap store as a private keys\nexport const NB_EVENT_SERVICE_PRIVATE_STORE = new WeakMap()\nexport const NB_EVENT_SERVICE_PRIVATE_LAZY = new WeakMap()\n","/**\n * generate a 32bit hash based on the function.toString()\n * _from http://stackoverflow.com/questions/7616461/generate-a-hash-_from-string-in-javascript-jquery\n * @param {string} s the converted to string function\n * @return {string} the hashed function string\n */\nexport function hashCode(s) {\n\treturn s.split(\"\").reduce(function(a,b){a=((a<<5)-a)+b.charCodeAt(0);return a&a},0)\n}\n\n/**\n * wrapper to make sure it string\n * @param {*} input whatever\n * @return {string} output\n */\nexport function hashCode2Str(s) {\n return hashCode(s) + ''\n}\n\n/**\n * Just check if a pattern is an RegExp object\n * @param {*} pat whatever\n * @return {boolean} false when its not\n */\nexport function isRegExp(pat) {\n return pat instanceof RegExp\n}\n\n/**\n * check if its string\n * @param {*} arg whatever\n * @return {boolean} false when it's not\n */\nexport function isString(arg) {\n return typeof arg === 'string'\n}\n\n/**\n * Find from the array by matching the pattern\n * @param {*} pattern a string or RegExp object\n * @return {object} regex object or false when we can not id the input\n */\nexport function getRegex(pattern) {\n switch (true) {\n case isRegExp(pattern) === true:\n return pattern\n case isString(pattern) === true:\n return new RegExp(pattern)\n default:\n return false\n }\n}\n","// making all the functionality on it's own\n// import { WatchClass } from './watch'\n/*\nwe use a different way to do the same watch thing now\nthis.watch('suspend', function(value, prop, oldValue) {\n this.logger(`${prop} set from ${oldValue} to ${value}`)\n // it means it set the suspend = true then release it\n if (oldValue === true && value === false) {\n // we want this happen after the return happens\n setTimeout(() => {\n this.release()\n }, 1)\n }\n return value; // we need to return the value to store it\n})\n*/\nimport { getRegex, isRegExp } from './utils'\n\nexport default class SuspendClass {\n\n constructor() {\n // suspend, release and queue\n this.__suspend_state__ = null\n // to do this proper we don't use a new prop to hold the event name pattern\n this.__pattern__ = null\n this.queueStore = new Set()\n }\n\n /**\n * start suspend\n * @return {void}\n */\n $suspend() {\n this.logger(`---> SUSPEND ALL OPS <---`)\n this.__suspend__(true)\n }\n\n /**\n * release the queue\n * @return {void}\n */\n $release() {\n this.logger(`---> RELEASE SUSPENDED QUEUE <---`)\n this.__suspend__(false)\n }\n\n /**\n * suspend event by pattern\n * @param {string} pattern the pattern search matches the event name\n * @return {void}\n */\n $suspendEvent(pattern) {\n const regex = getRegex(pattern)\n if (isRegExp(regex)) {\n this.__pattern__ = regex\n return this.$suspend()\n }\n throw new Error(`We expect a pattern variable to be string or RegExp, but we got \"${typeof regex}\" instead`)\n }\n\n /**\n * queuing call up when it's in suspend mode\n * @param {string} evt the event name\n * @param {*} args unknown number of arguments\n * @return {boolean} true when added or false when it's not\n */\n $queue(evt, ...args) {\n this.logger('($queue) get called')\n if (this.__suspend_state__ === true) {\n if (isRegExp(this.__pattern__)) { // it's better then check if its not null\n // check the pattern and decide if we want to suspend it or not\n let found = this.__pattern__.test(evt)\n if (!found) {\n return false\n }\n }\n this.logger('($queue) added to $queue', args)\n // @TODO there shouldn't be any duplicate, but how to make sure?\n this.queueStore.add([evt].concat(args))\n // return this.queueStore.size\n }\n return !!this.__suspend_state__\n }\n\n /**\n * a getter to get all the store queue\n * @return {array} Set turn into Array before return\n */\n get $queues() {\n let size = this.queueStore.size\n this.logger('($queues)', `size: ${size}`)\n if (size > 0) {\n return Array.from(this.queueStore)\n }\n return []\n }\n\n /**\n * to set the suspend and check if it's boolean value\n * @param {boolean} value to trigger\n */\n __suspend__(value) {\n if (typeof value === 'boolean') {\n const lastValue = this.__suspend_state__\n this.__suspend_state__ = value\n this.logger(`($suspend) Change from \"${lastValue}\" --> \"${value}\"`)\n if (lastValue === true && value === false) {\n this.__release__()\n }\n } else {\n throw new Error(`$suspend only accept Boolean value! we got ${typeof value}`)\n }\n }\n\n /**\n * Release the queue\n * @return {int} size if any\n */\n __release__() {\n let size = this.queueStore.size\n let pattern = this.__pattern__\n this.__pattern__ = null\n this.logger(`(release) was called with ${size}${pattern ? ' for \"' + pattern + '\"': ''} item${size > 1 ? 's' : ''}`)\n if (size > 0) {\n const queue = Array.from(this.queueStore)\n this.queueStore.clear()\n this.logger('(release queue)', queue)\n queue.forEach(args => {\n this.logger(args)\n Reflect.apply(this.$trigger, this, args)\n })\n this.logger(`Release size ${this.queueStore.size}`)\n }\n\n return size\n }\n}\n","// break up the main file because its getting way too long\nimport {\n NB_EVENT_SERVICE_PRIVATE_STORE,\n NB_EVENT_SERVICE_PRIVATE_LAZY\n} from './store'\nimport { hashCode2Str, isString } from './utils'\nimport SuspendClass from './suspend'\n\nexport default class StoreService extends SuspendClass {\n\n constructor(config = {}) {\n super()\n if (config.logger && typeof config.logger === 'function') {\n this.logger = config.logger\n }\n this.keep = config.keep\n // for the $done setter\n this.result = config.keep ? [] : null\n // we need to init the store first otherwise it could be a lot of checking later\n this.normalStore = new Map()\n this.lazyStore = new Map()\n }\n\n /**\n * validate the event name(s)\n * @param {string[]} evt event name\n * @return {boolean} true when OK\n */\n validateEvt(...evt) {\n evt.forEach(e => {\n if (!isString(e)) {\n this.logger('(validateEvt)', e)\n throw new Error(`Event name must be string type! we got ${typeof e}`)\n }\n })\n return true\n }\n\n /**\n * Simple quick check on the two main parameters\n * @param {string} evt event name\n * @param {function} callback function to call\n * @return {boolean} true when OK\n */\n validate(evt, callback) {\n if (this.validateEvt(evt)) {\n if (typeof callback === 'function') {\n return true\n }\n }\n throw new Error(`callback required to be function type! we got ${typeof callback}`)\n }\n\n /**\n * Check if this type is correct or not added in V1.5.0\n * @param {string} type for checking\n * @return {boolean} true on OK\n */\n validateType(type) {\n this.validateEvt(type)\n const types = ['on', 'only', 'once', 'onlyOnce']\n return !!types.filter(t => type === t).length\n }\n\n /**\n * Run the callback\n * @param {function} callback function to execute\n * @param {array} payload for callback\n * @param {object} ctx context or null\n * @return {void} the result store in $done\n */\n run(callback, payload, ctx) {\n this.logger('(run) callback:', callback, 'payload:', payload, 'context:', ctx)\n this.$done = Reflect.apply(callback, ctx, this.toArray(payload))\n }\n\n /**\n * Take the content out and remove it from store id by the name\n * @param {string} evt event name\n * @param {string} [storeName = lazyStore] name of store\n * @return {object|boolean} content or false on not found\n */\n takeFromStore(evt, storeName = 'lazyStore') {\n let store = this[storeName] // it could be empty at this point\n if (store) {\n this.logger('(takeFromStore)', storeName, store)\n if (store.has(evt)) {\n let content = store.get(evt)\n this.logger(`(takeFromStore) has \"${evt}\"`, content)\n store.delete(evt)\n return content\n }\n return false\n }\n throw new Error(`\"${storeName}\" is not supported!`)\n }\n\n /**\n * This was part of the $get. We take it out\n * so we could use a regex to remove more than one event\n * @param {object} store the store to return from\n * @param {string} evt event name\n * @param {boolean} full return just the callback or everything\n * @return {array|boolean} false when not found\n */\n findFromStore(evt, store, full = false) {\n if (store.has(evt)) {\n return Array\n .from(store.get(evt))\n .map( l => {\n if (full) {\n return l\n }\n let [key, callback, ] = l\n return callback\n })\n }\n return false\n }\n\n /**\n * Similar to the findFromStore, but remove\n * @param {string} evt event name\n * @param {object} store the store to remove from\n * @return {boolean} false when not found\n */\n removeFromStore(evt, store) {\n if (store.has(evt)) {\n this.logger('($off)', evt)\n store.delete(evt)\n return true\n }\n return false\n }\n\n /**\n * The add to store step is similar so make it generic for resuse\n * @param {object} store which store to use\n * @param {string} evt event name\n * @param {spread} args because the lazy store and normal store store different things\n * @return {array} store and the size of the store\n */\n addToStore(store, evt, ...args) {\n let fnSet\n if (store.has(evt)) {\n this.logger(`(addToStore) \"${evt}\" existed`)\n fnSet = store.get(evt)\n } else {\n this.logger(`(addToStore) create new Set for \"${evt}\"`)\n // this is new\n fnSet = new Set()\n }\n // lazy only store 2 items - this is not the case in V1.6.0 anymore\n // we need to check the first parameter is string or not\n if (args.length > 2) {\n if (Array.isArray(args[0])) { // lazy store\n // check if this type of this event already register in the lazy store\n let [,,t] = args\n if (!this.checkTypeInLazyStore(evt, t)) {\n fnSet.add(args)\n }\n } else {\n if (!this.checkContentExist(args, fnSet)) {\n this.logger(`(addToStore) insert new`, args)\n fnSet.add(args)\n }\n }\n } else { // add straight to lazy store\n fnSet.add(args)\n }\n store.set(evt, fnSet)\n return [store, fnSet.size]\n }\n\n /**\n * @param {array} args for compare\n * @param {object} fnSet A Set to search from\n * @return {boolean} true on exist\n */\n checkContentExist(args, fnSet) {\n let list = Array.from(fnSet)\n return !!list.filter(li => {\n let [hash,] = li\n return hash === args[0]\n }).length\n }\n\n /**\n * get the existing type to make sure no mix type add to the same store\n * @param {string} evtName event name\n * @param {string} type the type to check\n * @return {boolean} true you can add, false then you can't add this type\n */\n checkTypeInStore(evtName, type) {\n this.validateEvt(evtName, type)\n let all = this.$get(evtName, true)\n if (all === false) {\n // pristine it means you can add\n return true\n }\n // it should only have ONE type in ONE event store\n return !all.filter(list => {\n let [ ,,,t ] = list\n return type !== t\n }).length\n }\n\n /**\n * This is checking just the lazy store because the structure is different\n * therefore we need to use a new method to check it\n */\n checkTypeInLazyStore(evtName, type) {\n this.validateEvt(evtName, type)\n let store = this.lazyStore.get(evtName)\n this.logger('(checkTypeInLazyStore)', store)\n if (store) {\n return !!Array\n .from(store)\n .filter(li => {\n let [,,t] = li\n return t !== type\n }).length\n }\n return false\n }\n\n /**\n * wrapper to re-use the addToStore,\n * V1.3.0 add extra check to see if this type can add to this evt\n * @param {string} evt event name\n * @param {string} type on or once\n * @param {function} callback function\n * @param {object} context the context the function execute in or null\n * @return {number} size of the store\n */\n addToNormalStore(evt, type, callback, context = null) {\n this.logger(`(addToNormalStore) try to add \"${type}\" --> \"${evt}\" to normal store`)\n // @TODO we need to check the existing store for the type first!\n if (this.checkTypeInStore(evt, type)) {\n this.logger('(addToNormalStore)', `\"${type}\" --> \"${evt}\" can add to normal store`)\n let key = this.hashFnToKey(callback)\n let args = [this.normalStore, evt, key, callback, context, type]\n let [_store, size] = Reflect.apply(this.addToStore, this, args)\n this.normalStore = _store\n return size\n }\n return false\n }\n\n /**\n * Add to lazy store this get calls when the callback is not register yet\n * so we only get a payload object or even nothing\n * @param {string} evt event name\n * @param {array} payload of arguments or empty if there is none\n * @param {object} [context=null] the context the callback execute in\n * @param {string} [type=false] register a type so no other type can add to this evt\n * @return {number} size of the store\n */\n addToLazyStore(evt, payload = [], context = null, type = false) {\n // this is add in V1.6.0\n // when there is type then we will need to check if this already added in lazy store\n // and no other type can add to this lazy store\n let args = [this.lazyStore, evt, this.toArray(payload), context]\n if (type) {\n args.push(type)\n }\n let [_store, size] = Reflect.apply(this.addToStore, this, args)\n this.lazyStore = _store\n this.logger(`(addToLazyStore) size: ${size}`)\n return size\n }\n\n /**\n * make sure we store the argument correctly\n * @param {*} arg could be array\n * @return {array} make sured\n */\n toArray(arg) {\n return Array.isArray(arg) ? arg : [arg]\n }\n\n /**\n * setter to store the Set in private\n * @param {object} obj a Set\n */\n set normalStore(obj) {\n NB_EVENT_SERVICE_PRIVATE_STORE.set(this, obj)\n }\n\n /**\n * @return {object} Set object\n */\n get normalStore() {\n return NB_EVENT_SERVICE_PRIVATE_STORE.get(this)\n }\n\n /**\n * setter to store the Set in lazy store\n * @param {object} obj a Set\n */\n set lazyStore(obj) {\n NB_EVENT_SERVICE_PRIVATE_LAZY.set(this , obj)\n }\n\n /**\n * @return {object} the lazy store Set\n */\n get lazyStore() {\n return NB_EVENT_SERVICE_PRIVATE_LAZY.get(this)\n }\n\n /**\n * generate a hashKey to identify the function call\n * The build-in store some how could store the same values!\n * @param {function} fn the converted to string function\n * @return {string} hashKey\n */\n hashFnToKey(fn) {\n return hashCode2Str(fn.toString())\n }\n}\n","// The top level\nimport { TAKEN_BY_OTHER_TYPE_ERR } from './constants'\nimport StoreService from './store-service'\n// export\nexport default class EventService extends StoreService {\n /**\n * class constructor\n */\n constructor(config = {}) {\n super(config)\n }\n\n /**\n * logger function for overwrite\n */\n logger() {}\n\n // for id if the instance is this class\n get $name() {\n return 'to1source-event'\n }\n\n // take this down in the next release\n get is() {\n return this.$name\n }\n\n //////////////////////////\n // PUBLIC METHODS //\n //////////////////////////\n\n /**\n * Register your evt handler, note we don't check the type here,\n * we expect you to be sensible and know what you are doing.\n * @param {string} evt name of event\n * @param {function} callback bind method --> if it's array or not\n * @param {object} [context=null] to execute this call in\n * @return {number} the size of the store\n */\n $on(evt , callback , context = null) {\n const type = 'on'\n this.validate(evt, callback)\n // first need to check if this evt is in lazy store\n let lazyStoreContent = this.takeFromStore(evt)\n // this is normal register first then call later\n if (lazyStoreContent === false) {\n this.logger(`($on) \"${evt}\" is not in lazy store`)\n // @TODO we need to check if there was other listener to this\n // event and are they the same type then we could solve that\n // register the different type to the same event name\n return this.addToNormalStore(evt, type, callback, context)\n }\n this.logger(`($on) ${evt} found in lazy store`)\n // this is when they call $trigger before register this callback\n let size = 0\n lazyStoreContent.forEach(content => {\n let [ payload, ctx, t ] = content\n if (t && t !== type) {\n throw new Error(`${TAKEN_BY_OTHER_TYPE_ERR} ${t}`)\n }\n this.logger(`($on)`, `call run \"${evt}\"`)\n this.run(callback, payload, context || ctx)\n size += this.addToNormalStore(evt, type, callback, context || ctx)\n })\n\n this.logger(`($on) return size ${size}`)\n return size\n }\n\n /**\n * once only registered it once, there is no overwrite option here\n * @NOTE change in v1.3.0 $once can add multiple listeners\n * but once the event fired, it will remove this event (see $only)\n * @param {string} evt name\n * @param {function} callback to execute\n * @param {object} [context=null] the handler execute in\n * @return {boolean} result\n */\n $once(evt , callback , context = null) {\n this.validate(evt, callback)\n const type = 'once'\n let lazyStoreContent = this.takeFromStore(evt)\n // this is normal register before call $trigger\n let nStore = this.normalStore;\n if (lazyStoreContent === false) {\n this.logger(`($once) \"${evt}\" is not in the lazy store`)\n // v1.3.0 $once now allow to add multiple listeners\n return this.addToNormalStore(evt, type, callback, context)\n } else {\n // now this is the tricky bit\n // there is a potential bug here that cause by the developer\n // if they call $trigger first, the lazy won't know it's a once call\n // so if in the middle they register any call with the same evt name\n // then this $once call will be fucked - add this to the documentation\n this.logger('($once)', lazyStoreContent)\n const list = Array.from(lazyStoreContent)\n // should never have more than 1\n const [ payload, ctx, t ] = list[0]\n if (t && t !== type) {\n throw new Error(`${TAKEN_BY_OTHER_TYPE_ERR} ${t}`)\n }\n this.logger('($once)', `call run \"${evt}\"`)\n this.run(callback, payload, context || ctx)\n // remove this evt from store\n this.$off(evt)\n }\n }\n\n /**\n * This one event can only bind one callbackback\n * @param {string} evt event name\n * @param {function} callback event handler\n * @param {object} [context=null] the context the event handler execute in\n * @return {boolean} true bind for first time, false already existed\n */\n $only(evt, callback, context = null) {\n this.validate(evt, callback)\n const type = 'only'\n let added = false\n let lazyStoreContent = this.takeFromStore(evt)\n // this is normal register before call $trigger\n let nStore = this.normalStore\n if (!nStore.has(evt)) {\n this.logger(`($only) \"${evt}\" add to normalStore`)\n added = this.addToNormalStore(evt, type, callback, context)\n }\n if (lazyStoreContent !== false) {\n // there are data store in lazy store\n this.logger(`($only) \"${evt}\" found data in lazy store to execute`)\n const list = Array.from(lazyStoreContent)\n // $only allow to trigger this multiple time on the single handler\n list.forEach( li => {\n const [ payload, ctx, t ] = li\n if (t && t !== type) {\n throw new Error(`${TAKEN_BY_OTHER_TYPE_ERR} ${t}`)\n }\n this.logger(`($only) call run \"${evt}\"`)\n this.run(callback, payload, context || ctx)\n })\n }\n return added\n }\n\n /**\n * $only + $once this is because I found a very subtile bug when we pass a\n * resolver, rejecter - and it never fire because that's OLD added in v1.4.0\n * @param {string} evt event name\n * @param {function} callback to call later\n * @param {object} [context=null] exeucte context\n * @return {void}\n */\n $onlyOnce(evt, callback, context = null) {\n this.validate(evt, callback)\n const type = 'onlyOnce'\n let added = false\n let lazyStoreContent = this.takeFromStore(evt)\n // this is normal register before call $trigger\n let nStore = this.normalStore;\n if (!nStore.has(evt)) {\n this.logger(`($onlyOnce) \"${evt}\" add to normalStore`)\n added = this.addToNormalStore(evt, type, callback, context)\n }\n if (lazyStoreContent !== false) {\n // there are data store in lazy store\n this.logger('($onlyOnce)', lazyStoreContent)\n const list = Array.from(lazyStoreContent)\n // should never have more than 1\n const [ payload, ctx, t ] = list[0]\n if (t && t !== 'onlyOnce') {\n throw new Error(`${TAKEN_BY_OTHER_TYPE_ERR} ${t}`)\n }\n this.logger(`($onlyOnce) call run \"${evt}\"`)\n this.run(callback, payload, context || ctx)\n // remove this evt from store\n this.$off(evt)\n }\n return added\n }\n\n /**\n * This is a shorthand of $off + $on added in V1.5.0\n * @param {string} evt event name\n * @param {function} callback to exeucte\n * @param {object} [context = null] or pass a string as type\n * @param {string} [type=on] what type of method to replace\n * @return {*}\n */\n $replace(evt, callback, context = null, type = 'on') {\n if (this.validateType(type)) {\n this.$off(evt)\n let method = this['$' + type]\n this.logger(`($replace)`, evt, callback)\n return Reflect.apply(method, this, [evt, callback, context])\n }\n throw new Error(`${type} is not supported!`)\n }\n\n /**\n * trigger the event\n * @param {string} evt name NOT allow array anymore!\n * @param {mixed} [payload = []] pass to fn\n * @param {object|string} [context = null] overwrite what stored\n * @param {string} [type=false] if pass this then we need to add type to store too\n * @return {number} if it has been execute how many times\n */\n $trigger(evt , payload = [] , context = null, type = false) {\n this.validateEvt(evt)\n let found = 0\n // first check the normal store\n let nStore = this.normalStore\n this.logger('($trigger) normalStore', nStore)\n if (nStore.has(evt)) {\n this.logger(`($trigger) \"${evt}\" found`)\n // @1.8.0 to add the suspend queue\n let added = this.$queue(evt, payload, context, type)\n if (added) {\n this.logger(`($trigger) Currently suspended \"${evt}\" added to queue, nothing executed. Exit now.`)\n return false // not executed\n }\n let nSet = Array.from(nStore.get(evt))\n let ctn = nSet.length\n let hasOnce = false\n let hasOnly = false\n for (let i=0; i < ctn; ++i) {\n ++found;\n // this.logger('found', found)\n let [ _, callback, ctx, type ] = nSet[i]\n this.logger(`($trigger) call run for ${evt}`)\n this.run(callback, payload, context || ctx)\n if (type === 'once' || type === 'onlyOnce') {\n hasOnce = true;\n }\n }\n if (hasOnce) {\n nStore.delete(evt)\n }\n return found\n }\n // now this is not register yet\n this.addToLazyStore(evt, payload, context, type)\n return found\n }\n\n /**\n * this is an alias to the $trigger\n * @NOTE breaking change in V1.6.0 we swap the parameter aroun\n * @NOTE breaking change: v1.9.1 it return an function to accept the params as spread\n * @param {string} evt event name\n * @param {string} type of call\n * @param {object} context what context callback execute in\n * @return {*} from $trigger\n */\n $call(evt, type = false, context = null) {\n const ctx = this\n\n return (...args) => {\n let _args = [evt, args, context, type]\n return Reflect.apply(ctx.$trigger, ctx, _args)\n }\n }\n\n /**\n * remove the evt from all the stores\n * @param {string} evt name\n * @return {boolean} true actually delete something\n */\n $off(evt) {\n // @TODO we will allow a regex pattern to mass remove event\n this.validateEvt(evt)\n let stores = [ this.lazyStore, this.normalStore ]\n\n return !!stores\n .filter(store => store.has(evt))\n .map(store => this.removeFromStore(evt, store))\n .length\n }\n\n /**\n * return all the listener bind to that event name\n * @param {string} evtName event name\n * @param {boolean} [full=false] if true then return the entire content\n * @return {array|boolean} listerner(s) or false when not found\n */\n $get(evt, full = false) {\n // @TODO should we allow the same Regex to search for all?\n this.validateEvt(evt)\n let store = this.normalStore\n return this.findFromStore(evt, store, full)\n }\n\n /**\n * store the return result from the run\n * @param {*} value whatever return from callback\n */\n set $done(value) {\n this.logger('($done) set value: ', value)\n if (this.keep) {\n this.result.push(value)\n } else {\n this.result = value\n }\n }\n\n /**\n * @TODO is there any real use with the keep prop?\n * getter for $done\n * @return {*} whatever last store result\n */\n get $done() {\n this.logger('($done) get result:', this.result)\n if (this.keep) {\n return this.result[this.result.length - 1]\n }\n return this.result\n }\n\n /**\n * Take a look inside the stores\n * @param {number|null} idx of the store, null means all\n * @return {void}\n */\n $debug(idx = null) {\n let names = ['lazyStore', 'normalStore']\n let stores = [this.lazyStore, this.normalStore]\n if (stores[idx]) {\n this.logger(names[idx], stores[idx])\n } else {\n stores.map((store, i) => {\n this.logger(names[i], store)\n })\n }\n }\n}\n","// default\nimport To1sourceEvent from './src/event-service'\n\nexport default To1sourceEvent\n","// this will generate a event emitter and will be use everywhere\nimport EventEmitterClass from '@to1source/event'\n// create a clone version so we know which one we actually is using\nclass JsonqlWsEvt extends EventEmitterClass {\n\n constructor(logger) {\n if (typeof logger !== 'function') {\n throw new Error(`Just die here the logger is not a function!`)\n }\n logger(`---> Create a new EventEmitter <---`)\n // this ee will always come with the logger\n // because we should take the ee from the configuration\n super({ logger })\n }\n\n get name() {\n return'jsonql-ws-client-core'\n }\n}\n\n/**\n * getting the event emitter\n * @param {object} opts configuration\n * @return {object} the event emitter instance\n */\nconst getEventEmitter = opts => {\n const { log, eventEmitter } = opts\n \n if (eventEmitter) {\n log(`eventEmitter is:`, eventEmitter.name)\n return eventEmitter\n }\n \n return new JsonqlWsEvt( opts.log )\n}\n\nexport { \n getEventEmitter, \n EventEmitterClass // for other module to build from \n}\n","// group all the small functions here\nimport { EMIT_REPLY_TYPE } from 'jsonql-constants'\nimport { toArray, createEvt } from 'jsonql-utils/src/generic'\nimport JsonqlValidationError from 'jsonql-errors/src/validation-error'\n\n\n/**\n * WebSocket is strict about the path, therefore we need to make sure before it goes in\n * @param {string} url input url\n * @return {string} url with correct path name\n */\nexport const fixWss = url => {\n const uri = url.toLowerCase()\n if (uri.indexOf('http') > -1) {\n if (uri.indexOf('https') > -1) {\n return uri.replace('https', 'wss')\n }\n return uri.replace('http', 'ws')\n }\n return uri\n}\n\n\n/**\n * get a stock host name from browser\n */\nexport const getHostName = () => {\n try {\n return [window.location.protocol, window.location.host].join('//')\n } catch(e) {\n throw new JsonqlValidationError(e)\n }\n}\n\n/**\n * Unbind the event\n * @param {object} ee EventEmitter\n * @param {string} namespace\n * @return {void}\n */\nexport const clearMainEmitEvt = (ee, namespace) => {\n let nsps = toArray(namespace)\n nsps.forEach(n => {\n ee.$off(createEvt(n, EMIT_REPLY_TYPE))\n })\n}\n\n\n","// take out from the resolver-methods\nimport { \n LOGIN_EVENT_NAME, \n LOGOUT_EVENT_NAME, \n ON_LOGIN_FN_NAME\n} from 'jsonql-constants'\nimport { JsonqlValidationError } from 'jsonql-errors'\nimport { injectToFn, chainFns, isString, objDefineProps, isFunc } from '../utils'\n\n\n/**\n * @TODO this is now become unnecessary because the login is a slave to the\n * http-client - but keep this for now and see what we want to do with it later\n * @UPDATE it might be better if we decoup the two http-client only emit a login event\n * Here should catch it and reload the ws client @TBC\n * break out from createAuthMethods to allow chaining call\n * @param {object} obj the main client object\n * @param {object} opts configuration\n * @param {object} ee event emitter\n * @return {array} [ obj, opts, ee ] what comes in what goes out\n */\nconst setupLoginHandler = (obj, opts, ee) => [ \n injectToFn(obj, opts.loginHandlerName, function loginHandler(token) {\n if (token && isString(token)) {\n opts.log(`Received ${LOGIN_EVENT_NAME} with ${token}`)\n // @TODO add the interceptor hook \n return ee.$trigger(LOGIN_EVENT_NAME, [token])\n }\n // should trigger a global error instead @TODO\n throw new JsonqlValidationError(opts.loginHandlerName, `Unexpected token ${token}`)\n }),\n opts,\n ee\n]\n\n\n/**\n * break out from createAuthMethods to allow chaining call - final in chain\n * @param {object} obj the main client object\n * @param {object} opts configuration\n * @param {object} ee event emitter\n * @return {array} [ obj, opts, ee ] what comes in what goes out\n */\nconst setupLogoutHandler = (obj, opts, ee) => [\n injectToFn(obj, opts.logoutHandlerName, function logoutHandler(...args) {\n ee.$trigger(LOGOUT_EVENT_NAME, args)\n }),\n opts, \n ee\n]\n\n\n/**\n * This event will fire when the socket.io.on('connection') and ws.onopen\n * Plus this will check if it's the private namespace that fired the event\n * @param {object} obj the client itself\n * @param {object} ee Event Emitter\n * @return {array} [ obj, opts, ee] what comes in what goes out\n */\nconst createOnLoginhandler = (obj, opts, ee) => [\n objDefineProps(obj, ON_LOGIN_FN_NAME, function onLoginCallbackHandler(onLoginCallback) {\n if (isFunc(onLoginCallback)) {\n // only one callback can registered with it, TBC\n ee.$only(ON_LOGIN_FN_NAME, onLoginCallback)\n }\n }),\n opts,\n ee \n]\n\n// @TODO future feature setup switch user\n\n\n/**\n * Create auth related methods\n * @param {object} obj the client itself\n * @param {object} opts configuration\n * @param {object} ee Event Emitter\n * @return {array} [ obj, opts, ee ] what comes in what goes out\n */\nexport function createAuthMethods(obj, opts, ee) {\n return chainFns(\n setupLoginHandler, \n setupLogoutHandler,\n createOnLoginhandler\n )(obj, opts, ee)\n}\n","// constants\n\nimport {\n EMIT_REPLY_TYPE,\n JS_WS_SOCKET_IO_NAME,\n JS_WS_NAME,\n ON_MESSAGE_FN_NAME,\n ON_RESULT_FN_NAME\n} from 'jsonql-constants'\n\nconst SOCKET_IO = JS_WS_SOCKET_IO_NAME\nconst WS = JS_WS_NAME\n\nconst AVAILABLE_SERVERS = [SOCKET_IO, WS]\n\nconst SOCKET_NOT_DEFINE_ERR = 'socket is not define in the contract file!'\n\nconst SERVER_NOT_SUPPORT_ERR = 'is not supported server name!'\n\nconst MISSING_PROP_ERR = 'Missing property in contract!'\n\nconst UNKNOWN_CLIENT_ERR = 'Unknown client type!'\n\nconst EMIT_EVT = EMIT_REPLY_TYPE\n\nconst NAMESPACE_KEY = 'namespaceMap'\n\nconst UNKNOWN_RESULT = 'UKNNOWN RESULT!'\n\nconst NOT_ALLOW_OP = 'This operation is not allow!'\n\nconst MY_NAMESPACE = 'myNamespace'\n\nconst CB_FN_NAME = 'on'\n// this is a socket only (for now) feature so we just put it here \nconst DISCONNECTED_ERROR_MSG = `You have disconnected from the socket server, please reconnect.`\n\nexport {\n SOCKET_IO,\n WS,\n AVAILABLE_SERVERS,\n SOCKET_NOT_DEFINE_ERR,\n SERVER_NOT_SUPPORT_ERR,\n MISSING_PROP_ERR,\n UNKNOWN_CLIENT_ERR,\n EMIT_EVT,\n ON_MESSAGE_FN_NAME,\n ON_RESULT_FN_NAME,\n NAMESPACE_KEY,\n UNKNOWN_RESULT,\n NOT_ALLOW_OP,\n MY_NAMESPACE,\n CB_FN_NAME,\n DISCONNECTED_ERROR_MSG\n}\n","// breaking it up further to share between methods\nimport { DATA_KEY, ERROR_KEY } from 'jsonql-constants'\nimport { UNKNOWN_RESULT } from '../options/constants'\nimport { isObjectHasKey } from '../utils'\n\n/**\n * break out to use in different places to handle the return from server\n * @param {object} data from server\n * @param {function} resolver NOT from promise\n * @param {function} rejecter NOT from promise\n * @return {void} nothing\n */\nexport function respondHandler(data, resolver, rejecter) {\n if (isObjectHasKey(data, ERROR_KEY)) {\n // debugFn('-- rejecter called --', data[ERROR_KEY])\n rejecter(data[ERROR_KEY])\n } else if (isObjectHasKey(data, DATA_KEY)) {\n // debugFn('-- resolver called --', data[DATA_KEY])\n resolver(data[DATA_KEY])\n } else {\n // debugFn('-- UNKNOWN_RESULT --', data)\n rejecter({message: UNKNOWN_RESULT, error: data})\n }\n}\n","// the actual trigger call method\nimport { ON_RESULT_FN_NAME, EMIT_REPLY_TYPE } from 'jsonql-constants'\nimport { createEvt, toArray } from '../utils'\nimport { respondHandler } from './respond-handler'\n\n/**\n * just wrapper\n * @param {object} ee EventEmitter\n * @param {string} namespace where this belongs\n * @param {string} resolverName resolver\n * @param {array} args arguments\n * @param {function} log function \n * @return {void} nothing\n */\nexport function actionCall(ee, namespace, resolverName, args = [], log) {\n // reply event \n const outEventName = createEvt(namespace, EMIT_REPLY_TYPE)\n\n log(`actionCall: ${outEventName} --> ${resolverName}`, args)\n // This is the out going call \n ee.$trigger(outEventName, [resolverName, toArray(args)])\n \n // then we need to listen to the event callback here as well\n return new Promise((resolver, rejecter) => {\n const inEventName = createEvt(namespace, resolverName, ON_RESULT_FN_NAME)\n // this cause the onResult got the result back first \n // and it should be the promise resolve first\n // @TODO we need to rewrote the respondHandler to change the problem stated above \n ee.$on(\n inEventName,\n function actionCallResultHandler(result) {\n log(`got the first result`, result)\n respondHandler(result, resolver, rejecter)\n }\n )\n })\n}\n","// setting up the send method \nimport { JsonqlValidationError } from 'jsonql-errors'\nimport {\n ON_ERROR_FN_NAME,\n SEND_MSG_FN_NAME\n} from 'jsonql-constants'\nimport { validateAsync } from 'jsonql-params-validator'\nimport { objDefineProps, createEvt, toArray, nil } from '../utils'\nimport { actionCall } from './action-call'\n\n/** \n * pairing with the server vesrion SEND_MSG_FN_NAME\n * last of the chain so only return the resolver (fn)\n * This is now change to a getter / setter method \n * and call like this: resolver.send(...args)\n * @param {function} fn the resolver function \n * @param {object} ee event emitter instance \n * @param {string} namespace the namespace it belongs to \n * @param {string} resolverName name of the resolver \n * @param {object} params from contract \n * @param {function} log a logger function\n * @return {function} return the resolver itself \n */ \nexport const setupSendMethod = (fn, ee, namespace, resolverName, params, log) => (\n objDefineProps(\n fn, \n SEND_MSG_FN_NAME, \n nil, \n function sendHandler() {\n // let _log = (...args) => Reflect.apply(console.info, console, ['[SEND]'].concat(args))\n /** \n * This will follow the same pattern like the resolver \n * @param {array} args list of unknown argument follow the resolver \n * @return {promise} resolve the result \n */\n return function sendCallback(...args) {\n return validateAsync(args, params.params, true)\n .then(_args => {\n // @TODO check the result \n // because the validation could failed with the list of fail properties \n log(namespace, resolverName, _args)\n return actionCall(ee, namespace, resolverName, _args, _log)\n })\n .catch(err => {\n // @TODO it shouldn't be just a validation error \n // it could be server return error, so we need to check \n // what error we got back here first \n log('send error', err)\n // @TODO it might not an validation error need the finalCatch here\n ee.$call(\n createEvt(namespace, resolverName, ON_ERROR_FN_NAME),\n [new JsonqlValidationError(resolverName, err)]\n )\n })\n } \n })\n)\n","// break up the original setup resolver method here\n// import { JsonqlValidationError, finalCatch } from 'jsonql-errors'\nimport {\n ON_ERROR_FN_NAME,\n ON_MESSAGE_FN_NAME,\n ON_RESULT_FN_NAME\n} from 'jsonql-constants'\n// local \nimport { MY_NAMESPACE } from '../options/constants'\nimport { chainFns, objDefineProps, injectToFn, createEvt, isFunc } from '../utils'\nimport { respondHandler } from './respond-handler'\nimport { setupSendMethod } from './setup-send-method'\n\n/**\n * The first one in the chain, just setup a namespace prop\n * the rest are passing through\n * @param {function} fn the resolver function\n * @param {object} ee the event emitter \n * @param {string} resolverName what it said\n * @param {object} params for resolver from contract\n * @param {function} log the logger function\n * @return {array}\n */\nconst setupNamespace = (fn, ee, namespace, resolverName, params, log) => [\n injectToFn(fn, MY_NAMESPACE, namespace),\n ee,\n namespace,\n resolverName,\n params,\n log \n]\n\n/** \n * onResult handler\n */ \nconst setupOnResult = (fn, ee, namespace, resolverName, params, log) => [\n objDefineProps(fn, ON_RESULT_FN_NAME, function(resultCallback) {\n if (isFunc(resultCallback)) {\n ee.$on(\n createEvt(namespace, resolverName, ON_RESULT_FN_NAME),\n function resultHandler(result) {\n respondHandler(result, resultCallback, (error) => {\n log(`Catch error: \"${resolverName}\"`, error)\n ee.$trigger(\n createEvt(namespace, resolverName, ON_ERROR_FN_NAME), \n error\n )\n })\n }\n )\n }\n }),\n ee,\n namespace,\n resolverName,\n params,\n log\n]\n\n/** \n * we do need to add the send prop back because it's the only way to deal with\n * bi-directional data stream \n */\nconst setupOnMessage = (fn, ee, namespace, resolverName, params, log) => [\n objDefineProps(fn, ON_MESSAGE_FN_NAME, function(messageCallback) {\n // we expect this to be a function\n if (isFunc(messageCallback)) {\n // did that add to the callback\n let onMessageCallback = (args) => {\n respondHandler(args, messageCallback, (error) => {\n log(`Catch error: \"${resolverName}\"`, error)\n ee.$trigger(\n createEvt(namespace, resolverName, ON_ERROR_FN_NAME), \n error\n )\n })\n }\n // register the handler for this message event\n ee.$only(\n createEvt(namespace, resolverName, ON_MESSAGE_FN_NAME), \n onMessageCallback\n )\n }\n }),\n ee,\n namespace,\n resolverName,\n params,\n log\n]\n\n/** \n * ON_ERROR_FN_NAME handler\n */\nconst setupOnError = (fn, ee, namespace, resolverName, params, log) => [\n objDefineProps(fn, ON_ERROR_FN_NAME, function(resolverErrorHandler) {\n if (isFunc(resolverErrorHandler)) {\n // please note ON_ERROR_FN_NAME can add multiple listners\n ee.$only(\n createEvt(namespace, resolverName, ON_ERROR_FN_NAME), \n resolverErrorHandler\n )\n }\n }),\n ee,\n namespace,\n resolverName,\n params,\n log\n]\n\n/**\n * Add extra property / listeners to the resolver\n * @param {string} namespace where this belongs\n * @param {string} resolverName name as event name\n * @param {object} params from contract\n * @param {function} fn resolver function\n * @param {object} ee EventEmitter\n * @param {function} log function \n * @return {function} resolver\n */\nexport function setupResolver(namespace, resolverName, params, fn, ee, log) {\n let fns = [\n setupNamespace, \n setupOnResult, \n setupOnMessage, \n setupOnError, \n setupSendMethod\n ]\n \n // get the executor\n const executor = Reflect.apply(chainFns, null, fns)\n const args = [fn, ee, namespace, resolverName, params, log]\n\n return Reflect.apply(executor, null, args)\n}\n","// put all the resolver related methods here to make it more clear\n\n// this will be a mini client server architect\n// The reason is when the enableAuth setup - the private route\n// might not be validated, but we need the callable point is ready\n// therefore this part will always take the contract and generate\n// callable api for the developer to setup their front end\n// the only thing is - when they call they might get an error or\n// NOT_LOGIN_IN and they can react to this error accordingly\nimport { finalCatch } from 'jsonql-errors'\nimport { validateAsync } from 'jsonql-params-validator'\nimport { setupResolver } from './setup-resolver'\nimport { actionCall } from './action-call'\nimport {\n createEvt,\n objDefineProps,\n isFunc,\n injectToFn\n} from '../utils'\nimport {\n ON_ERROR_FN_NAME,\n ON_READY_FN_NAME\n} from 'jsonql-constants'\n\n/**\n * create the actual function to send message to server\n * @param {object} ee EventEmitter instance\n * @param {string} namespace this resolver end point\n * @param {string} resolverName name of resolver as event name\n * @param {object} params from contract\n * @param {function} log pass the log function\n * @return {function} resolver\n */\nfunction createResolver(ee, namespace, resolverName, params, log) {\n // note we pass the new withResult=true option\n return function resolver(...args) {\n return validateAsync(args, params.params, true)\n .then(_args => actionCall(ee, namespace, resolverName, _args, log))\n .catch(finalCatch)\n }\n}\n\n/**\n * step one get the clientmap with the namespace\n * @param {object} opts configuration\n * @param {object} ee EventEmitter\n * @param {object} nspGroup resolvers index by their namespace\n * @return {promise} resolve the clientmapped, and start the chain\n */\nexport function generateResolvers(opts, ee, nspGroup) {\n let client= {}\n let { log } = opts\n\n for (let namespace in nspGroup) {\n let list = nspGroup[namespace]\n for (let resolverName in list) {\n // resolverNames.push(resolverName)\n let params = list[resolverName]\n let fn = createResolver(ee, namespace, resolverName, params, log)\n // this should set as a getter therefore can not be overwrite by accident\n // obj[resolverName] = setupResolver(namespace, resolverName, params, fn, ee)\n client = injectToFn(\n client,\n resolverName,\n setupResolver(namespace, resolverName, params, fn, ee, log)\n )\n }\n }\n // resolve the clientto start the chain\n // chain the result to allow the chain processing\n return [ client, opts, ee, nspGroup ]\n}\n\n/**\n * The problem is the namespace can have more than one\n * and we only have on onError message\n * @param {object} clientthe client itself\n * @param {object} opts configuration\n * @param {object} ee Event Emitter\n * @param {object} nspGroup namespace keys\n * @return {array} [obj, opts, ee]\n */\nexport function createNamespaceErrorListener(client, opts, ee, nspGroup) {\n return [\n objDefineProps(\n client,\n ON_ERROR_FN_NAME,\n function namespaceErrorCallbackHandler(namespaceErrorHandler) {\n if (isFunc(namespaceErrorHandler)) {\n // please note ON_ERROR_FN_NAME can add multiple listners\n for (let namespace in nspGroup) {\n // this one is very tricky, we need to make sure the trigger is calling\n // with the namespace as well as the error\n ee.$on(createEvt(namespace, ON_ERROR_FN_NAME), namespaceErrorHandler)\n }\n }\n }\n ),\n opts,\n ee\n ]\n}\n\n/**\n * This event will fire when the socket.io.on('connection') and ws.onopen\n * @param {object} client client itself\n * @param {object} opts configuration\n * @param {object} ee Event Emitter\n * @return {array} [ obj, opts, ee ]\n */\nexport function createOnReadyListener(client, opts, ee) {\n return [\n objDefineProps(\n client,\n ON_READY_FN_NAME,\n function onReadyCallbackHandler(onReadyCallback) {\n if (isFunc(onReadyCallback)) {\n // reduce it down to just one flat level\n // @2020-03-19 only allow ONE onReady callback otherwise\n // it will get fire multiple times which is not what we want \n ee.$only(ON_READY_FN_NAME, onReadyCallback)\n }\n }\n ),\n opts,\n ee\n ]\n}\n","// resolvers generator\n// we change the interface to return promise from v1.0.3\n// this way we make sure the obj return is correct and timely\nimport { chainFns } from '../utils'\nimport { createAuthMethods } from './setup-auth-methods'\nimport {\n generateResolvers,\n createOnReadyListener,\n createNamespaceErrorListener\n} from './generator-methods'\n\nimport {\n NSP_GROUP\n} from 'jsonql-constants'\n\n/**\n * prepare the methods\n * @param {object} opts configuration\n * @param {object} nspMap resolvers index by their namespace\n * @param {object} ee EventEmitter\n * @return {object} of resolvers\n * @public\n */\nexport function callersGenerator(opts, nspMap, ee) {\n let fns = [\n generateResolvers,\n createOnReadyListener,\n createNamespaceErrorListener\n ]\n if (opts.enableAuth) {\n fns.push(createAuthMethods)\n }\n // we will always get back the [ obj, opts, ee ]\n // then we only return the obj (wsClient)\n // This has move outside of here, into the main method\n // the reason is we could switch around the sequence much easier\n // fns.push(setupFinalStep)\n // run it\n const generator = Reflect.apply(chainFns, null, fns)\n\n return generator(opts, ee, nspMap[NSP_GROUP])\n}\n","// this is a new method that will create several \n// intercom method also reverse listen to the server \n// such as disconnect (server issue disconnect)\nimport { injectToFn } from '../utils'\nimport { DISCONNECT_EVENT_NAME } from 'jsonql-constants'\n\n/**\n * this is the new method that setup the intercom handler \n * also this serve as the final call in the then chain to \n * output the client\n * @param {object} client the client \n * @param {object} opts configuration \n * @param {object} ee the event emitter\n * @return {object} client \n */\nexport function setupInterCom(client, opts, ee) {\n const { disconnectHandlerName } = opts\n return injectToFn(client, disconnectHandlerName, function disconnectHandler(...args) {\n ee.$trigger(DISCONNECT_EVENT_NAME, args)\n })\n} ","// The final step of the setup before it returns the client\nimport { setupInterCom } from './setup-intercom'\n\n/**\n * The final step to return the client\n * @param {object} client the client\n * @param {object} opts configuration\n * @param {object} ee the event emitter\n * @return {object} client\n */\nfunction setupFinalStep(obj, opts, ee) {\n const client = setupInterCom(obj, opts, ee)\n opts.log(`---> The final step to return the ws-client <---`)\n // add some debug functions\n client.verifyEventEmitter = () => ee.is\n // we add back the two things into the client\n // then when we do integration, we run it in reverse,\n // create the ws client first then the host client\n client.eventEmitter = opts.eventEmitter\n client.log = opts.log\n // we just inject a helloWorld method here\n // client[HELLO_FN] =\n\n return client\n}\n\n\nexport { setupFinalStep }\n","// create options\nimport {\n checkConfigAsync,\n checkConfig\n} from 'jsonql-params-validator'\nimport {\n wsCoreCheckMap,\n wsCoreConstProps,\n socketCheckMap\n} from './defaults'\nimport {\n fixWss,\n getHostName,\n getEventEmitter,\n getNspInfoByConfig,\n getLogFn\n} from '../utils'\n\n/**\n * We need this to find the socket server type\n * @param {*} config\n * @return {string} the name of the socket server if any\n */\nfunction checkSocketClientType(config) {\n return checkConfig(config, socketCheckMap)\n}\n\n/**\n * Create a combine checkConfig for the creating the combine client\n * @param {*} configCheckMap\n * @param {*} constProps\n * @return {function} takes the user input config then resolve the configuration\n */\nfunction createCombineConfigCheck(configCheckMap, constProps) {\n const combineCheckMap = Object.assign({}, configCheckMap, wsCoreCheckMap)\n const combineConstProps = Object.assign({}, constProps, wsCoreConstProps)\n return config => checkConfigAsync(config, combineCheckMap, combineConstProps)\n}\n\n\n/**\n * wrapper method to check this already did the pre check\n * @param {object} config user supply config\n * @param {object} defaultOptions for checking\n * @param {object} constProps user supply const props\n * @return {promise} resolve to the checked opitons\n */\nfunction checkConfiguration(config, defaultOptions, constProps) {\n const defaultCheckMap= Object.assign(wsCoreCheckMap, defaultOptions)\n const wsConstProps = Object.assign(wsCoreConstProps, constProps)\n\n return checkConfigAsync(config, defaultCheckMap, wsConstProps)\n}\n\n/**\n * Taking the `then` part from the method below\n * @param {object} opts\n * @return {promise} opts all done\n */\nfunction postCheckInjectOpts(opts) {\n return Promise.resolve(opts)\n .then(opts => {\n if (!opts.hostname) {\n opts.hostname = getHostName()\n }\n // @TODO the contract now will supply the namespace information\n // and we need to use that to group the namespace call\n opts.wssPath = fixWss([opts.hostname, opts.namespace].join('/'), opts.serverType)\n // get the log function here\n opts.log = getLogFn(opts)\n\n opts.eventEmitter = getEventEmitter(opts)\n\n return opts\n })\n}\n\n/**\n * Don't want to make things confusing\n * Breaking up the opts process in one place\n * then generate the necessary parameter in another step\n * @2020-3-20 here we suspend operation by it's namespace first\n * Then in the framework part, after the connection establish we release\n * the queue\n * @param {object} opts checked --> merge --> injected\n * @return {object} {opts, nspMap, ee}\n */\nfunction createRequiredParams(opts) {\n const nspMap = getNspInfoByConfig(opts)\n const ee = opts.eventEmitter\n // @TODO here we are going to add suspend event to the namespace related methods\n \n\n return { opts, nspMap, ee }\n}\n\nexport {\n // properties\n wsCoreCheckMap,\n wsCoreConstProps,\n // functions\n checkConfiguration,\n postCheckInjectOpts,\n createRequiredParams,\n // this will just get export for integration\n checkSocketClientType,\n createCombineConfigCheck\n}\n","// the top level API\n// The goal is to create a generic method that will able to handle\n// any kind of clients\n// import { injectToFn } from 'jsonql-utils'\nimport {\n callersGenerator,\n setupFinalStep\n} from './callers'\nimport {\n checkConfiguration,\n postCheckInjectOpts,\n createRequiredParams\n} from './options'\n\n\n/**\n * 0.5.0 we break up the wsClientCore in two parts one without the config check\n * @param {function} socketClientListener\n * @return {function} to actually generate the client\n */\nexport function wsClientCoreAction(socketClientListener) {\n /**\n * This is a breaking change, to continue the onion skin design\n * @param {object} config the already checked config\n * @return {promise} resolve the client\n */\n return (config = {}) => {\n\n return postCheckInjectOpts(config)\n // the following two moved to wsPostConfig\n .then(createRequiredParams)\n .then(\n ({opts, nspMap, ee}) => socketClientListener(opts, nspMap, ee)\n )\n .then( // there is problem here, we wrap up the operation inside\n ({opts, nspMap, ee}) => callersGenerator(opts, nspMap, ee)\n )\n .then(setupFinalStep)\n .catch(err => {\n console.error(`jsonql-ws-core-client init error`, err)\n })\n }\n}\n\n/**\n * The main interface which will generate the socket clients and map all events\n * @param {object} socketClientListerner this is the one method export by various clients\n * @param {object} [configCheckMap={}] we should do all the checking in the core instead of the client\n * @param {object} [constProps={}] add this to supply the constProps from the downstream client\n * @return {function} accept a config then return the wsClient instance with all the available API\n */\nexport function wsClientCore(socketClientListener, configCheckMap = {}, constProps = {}) {\n // we need to inject property to this client later\n return (config = {}) => checkConfiguration(config, configCheckMap, constProps)\n .then(\n wsClientCoreAction(socketClientListener)\n )\n}\n","// this is getting too confusing \n// therefore we move it back to the framework specific \n\n/**\n * wrapper method to create a nsp without login\n * @param {string|boolean} namespace namespace url could be false\n * @param {object} opts configuration\n * @return {object} ws client instance\n */\nfunction createNspClient(namespace, opts) {\n const { hostname, wssPath, wsOptions, nspClient, log } = opts\n const url = namespace ? [hostname, namespace].join('/') : wssPath\n log(`createNspClient --> `, url)\n\n return nspClient(url, wsOptions)\n}\n\n/**\n * wrapper method to create a nsp with token auth\n * @param {string} namespace namespace url\n * @param {object} opts configuration\n * @return {object} ws client instance\n */\nfunction createNspAuthClient(namespace, opts) {\n const { hostname, wssPath, token, wsOptions, nspAuthClient, log } = opts\n const url = namespace ? [hostname, namespace].join('/') : wssPath\n \n log(`createNspAuthClient -->`, url)\n\n if (token && typeof token !== 'string') {\n throw new Error(`Expect token to be string, but got ${token}`)\n }\n \n return nspAuthClient(url, token, wsOptions)\n}\n\nexport {\n createNspClient,\n createNspAuthClient\n}\n","// this use by client-event-handler\nimport { ON_ERROR_FN_NAME } from 'jsonql-constants'\nimport { createEvt } from '../utils'\n\n/**\n * trigger errors on all the namespace onError handler\n * @param {object} ee Event Emitter\n * @param {array} namespaces nsps string\n * @param {string} message optional\n * @return {void}\n */\nexport function triggerNamespacesOnError(ee, namespaces, message) {\n namespaces.forEach( namespace => {\n ee.$trigger(\n createEvt(namespace, ON_ERROR_FN_NAME), \n [{ message, namespace }]\n )\n })\n}\n\n/**\n * Handle the onerror callback \n * @param {object} ee event emitter \n * @param {string} namespace which namespace has error \n * @param {*} err error object\n * @return {void} \n */\nexport const handleNamespaceOnError = (ee, namespace, err) => {\n ee.$trigger(createEvt(namespace, ON_ERROR_FN_NAME), [err])\n}","// NOT IN USE AT THE MOMENT JUST KEEP IT HERE FOR THE TIME BEING \nimport {\n LOGOUT_EVENT_NAME,\n NOT_LOGIN_ERR_MSG,\n ON_ERROR_FN_NAME,\n ON_RESULT_FN_NAME,\n DISCONNECT_EVENT_NAME\n} from 'jsonql-constants'\nimport { EMIT_EVT, DISCONNECTED_ERROR_MSG } from '../options/constants'\nimport { createEvt, clearMainEmitEvt } from '../utils'\nimport { triggerNamespacesOnError } from './trigger-namespaces-on-error'\n\n/**\n * Only when there is a private namespace then we bind to this event\n * @param {object} nsps the available nsp(s)\n * @param {array} namespaces available namespace \n * @param {object} ee eventEmitter \n * @param {object} opts configuration\n * @return {void}\n */\nexport const logoutEvtListener = (nsps, namespaces, ee, opts) => {\n const { log } = opts \n // this will be available regardless enableAuth\n // because the server can log the client out\n ee.$on(\n LOGOUT_EVENT_NAME, \n function logoutEvtCallback() {\n const privateNamespace = getPrivateNamespace(namespaces)\n log(`${LOGOUT_EVENT_NAME} event triggered`)\n // disconnect(nsps, opts.serverType)\n // we need to issue error to all the namespace onError Listerner\n triggerNamespacesOnError(ee, [privateNamespace], LOGOUT_EVENT_NAME)\n // rebind all of the Listerner to the fake one\n log(`logout from ${privateNamespace}`)\n\n clearMainEmitEvt(ee, privateNamespace)\n // we need to issue one more call to the server before we disconnect\n // now this is a catch 22, here we are not suppose to do anything platform specific\n // so that should fire before trigger this event\n // clear out the nsp\n nsps[privateNamespace] = null \n // add a NOT LOGIN error if call\n notLoginWsListerner(privateNamespace, ee, opts)\n }\n )\n}\n\n/**\n * A Event Listerner placeholder when it's not connect to any nsp\n * @param {string} namespace nsp\n * @param {object} ee EventEmitter\n * @param {object} opts configuration\n * @return {void}\n */\nexport const notConnectedListener = (namespace, ee, opts) => {\n const { log } = opts \n\n ee.$only(\n createEvt(namespace, EMIT_EVT),\n function disconnectedEvtCallback(resolverName, args) {\n log(`[disconnectedListerner] hijack the ws call`, namespace, resolverName, args)\n const error = {\n message: DISCONNECTED_ERROR_MSG\n }\n ee.$call(createEvt(namespace, resolverName, ON_ERROR_FN_NAME), [ error ])\n // also trigger the result Listerner, but wrap inside the error key\n ee.$call(createEvt(namespace, resolverName, ON_RESULT_FN_NAME), [{ error }])\n }\n )\n}\n\n\n/**\n * The disconnect event Listerner, now we log the client out from everything\n * @TODO now we are another problem they disconnect, how to reconnect\n * @param {object} nsps the available nsp(s)\n * @param {array} namespaces available namespace \n * @param {object} ee eventEmitter \n * @param {object} opts configuration\n * @return {void}\n */\nexport const disconnectListener = (nsps, namespaces, ee, opts) => {\n const { log } = opts \n ee.$on(\n DISCONNECT_EVENT_NAME, \n function disconnectEvtCallback() {\n triggerNamespacesOnError(ee, namespaces, DISCONNECT_EVENT_NAME)\n namespaces.forEach( namespace => { \n log(`disconnect from ${namespace}`)\n\n clearMainEmitEvt(ee, namespace)\n nsps[namespace] = null \n disconnectedListerner(namespace, ee, opts)\n })\n }\n )\n}\n\n/**\n * A Event Listerner placeholder when it's not connect to the private nsp\n * @param {string} namespace nsp\n * @param {object} ee EventEmitter\n * @param {object} opts configuration\n * @return {void}\n */\nexport const notLoginListener = (namespace, ee, opts) => {\n const { log } = opts \n\n ee.$only(\n createEvt(namespace, EMIT_EVT),\n function notLoginListernerCallback(resolverName, args) {\n log('[notLoginListerner] hijack the ws call', namespace, resolverName, args)\n const error = { message: NOT_LOGIN_ERR_MSG }\n // It should just throw error here and should not call the result\n // because that's channel for handling normal event not the fake one\n ee.$call(createEvt(namespace, resolverName, ON_ERROR_FN_NAME), [ error ])\n // also trigger the result Listerner, but wrap inside the error key\n ee.$call(createEvt(namespace, resolverName, ON_RESULT_FN_NAME), [{ error }])\n }\n )\n}","// This is share between different clients so we export it\n// @TODO port what is in the ws-main-handler\n// because all the client side call are via the ee\n// and that makes it re-usable between different client setup\n\n/*\nInside the map call but we take it out for now and until the WebSocket version is fully working\nimport { SOCKET_IO } from '../options/constants'\n // @TODO need to double check this\n if (opts.serverType === SOCKET_IO) {\n let { nspGroup } = nspMap\n args.push(nspGroup[namespace])\n }\n*/\nimport { getPrivateNamespace } from 'jsonql-utils/src/namespace'\nimport { logoutEvtListener, notLoginListener } from './event-listeners'\n\n\n/**\n * centralize all the comm in one place\n * @param {function} bindSocketEventHandler binding the ee to ws --> this is the core bit\n * @param {object} nsps namespaced nsp\n * @return {void} nothing\n */\nexport function clientEventListener(bindSocketEventListener, nsps) {\n /**\n * BREAKING CHANGE instead of one flat structure\n * we return a function to accept the two \n * @param {object} opts configuration\n * @param {object} nspMap this is not in the opts \n * @param {object} ee Event Emitter instance\n * @return {array} although we return something but this is the last step and nothing to do further\n */\n return (opts, nspMap, ee) => {\n // since all these params already in the opts\n const { log } = opts\n const { namespaces } = nspMap\n // @1.1.3 add isPrivate prop to id which namespace is the private nsp\n // then we can use this prop to determine if we need to fire the ON_LOGIN_PROP_NAME event\n const privateNamespace = getPrivateNamespace(namespaces)\n \n return namespaces.map(namespace => {\n let isPrivate = privateNamespace === namespace\n log(namespace, ` --> ${isPrivate ? 'private': 'public'} nsp --> `, nsps[namespace] !== false)\n if (nsps[namespace]) {\n log('[call bindWsHandler]', isPrivate, namespace)\n\n let args = [namespace, nsps[namespace], ee, isPrivate, opts]\n // Finally we binding everything together\n Reflect.apply(bindSocketEventListener, null, args)\n\n } else {\n log(`binding notLoginWsHandler to ${namespace}`)\n // a dummy placeholder\n // @TODO but it should be a not connect handler \n // when it's not login (or fail) this should be handle differently \n notLoginListener(namespace, ee, opts)\n }\n if (isPrivate) {\n log(`Has private and add logoutEvtHandler`)\n logoutEvtListener(nsps, namespaces, ee, opts)\n }\n // just return something its not going to get use anywhere\n return isPrivate \n })\n }\n}\n","// jsonql-ws-core takes over the check configuration\n// here we only have to supply the options that is unique to this client\n// create options\nimport { JS_WS_NAME } from 'jsonql-constants'\n// constant props\nconst wsClientConstProps = {\n version: '__PLACEHOLDER__', // will get replace\n serverType: JS_WS_NAME\n}\n\nexport { wsClientConstProps }\n","// pass the different type of ws to generate the client\n// this is where the framework specific code get injected\nimport { TOKEN_PARAM_NAME } from 'jsonql-constants'\nimport { fixWss } from '../modules'\nimport {\n createInitPing, \n extractPingResult\n} from '../modules'\n\n/**\n * Group the ping and get respond create new client in one\n * @param {object} ws \n * @param {object} WebSocket \n * @param {string} url\n * @param {function} resolver \n * @param {function} rejecter \n * @param {boolean} auth client or not\n * @return {promise} resolve the confirm client\n */\nfunction initPingAction(ws, WebSocket, url, resolver, rejecter, wsOptions) {\n // @TODO how to we id this client can issue a CSRF\n // by origin? \n ws.onopen = function onOpenCallback() {\n ws.send(createInitPing())\n }\n\n ws.onmessage = function onMessageCallback(payload) {\n try {\n const header = extractPingResult(payload.data)\n // @NOTE the break down test in ws-client-core show no problems\n // the problem was cause by malform nspInfo that time? \n setTimeout(() => { // delay or not show no different but just on the safe side\n ws.terminate()\n }, 50)\n const newWs = new WebSocket(url, Object.assign(wsOptions, header)) \n resolver(newWs) \n } catch(e) {\n rejecter(e)\n }\n }\n\n ws.onerror = function onErrorCallback(err) {\n rejecter(err)\n }\n}\n\n/**\n * less duplicated code the better \n * @param {object} WebSocket \n * @param {string} url formatted url\n * @param {object} options or not\n * @return {promise} resolve the actual verified client\n */\nfunction asyncConnect(WebSocket, url, options) {\n \n return new Promise((resolver, rejecter) => { \n \n const unconfirmClient = new WebSocket(url, options)\n \n initPingAction(unconfirmClient, WebSocket, url, resolver, rejecter, options)\n })\n}\n\n\n/**\n * The bug was in the wsOptions where ws don't need it but socket.io do\n * therefore the object was pass as second parameter!\n * @NOTE here we only return a method to create the client, it might not get call \n * @param {object} WebSocket the client or node version of ws\n * @param {boolean} auth if it's auth then 3 param or just one\n * @param {object} opts this is a breaking change we will init the client twice\n */\nfunction initWebSocketClient(WebSocket, auth, log) {\n if (auth === false) {\n /**\n * Create a non-protected client\n * @param {string} url \n * @param {object} [wsOptions={}]\n * @return {promise} resolve to the confirmed client\n */\n return function createWsClient(url, wsOptions = {}) {\n const _url = fixWss(url)\n log(`nspClient: \\n${_url}\\n`, wsOptions)\n\n return asyncConnect(WebSocket, _url, wsOptions)\n }\n }\n\n /**\n * Create a client with auth token\n * @param {string} url start with ws:// @TODO check this?\n * @param {string} token the jwt token\n * @param {object} [wsOptions={}] extra options pass to the WebSocket object\n * @return {object} ws instance\n */\n return function createWsAuthClient(url, token, wsOptions = {}) {\n const ws_url = fixWss(url)\n // console.log('what happen here?', url, ws_url, token)\n const _url = token && typeof token === 'string' ? `${ws_url}?${TOKEN_PARAM_NAME}=${token}` : ws_url\n log(`nspAuthClient: \\n${_url}\\n`, wsOptions)\n\n return asyncConnect(WebSocket, _url, wsOptions)\n }\n}\n\nexport { initWebSocketClient }","/** Used for built-in method references. */\nvar objectProto = Object.prototype;\n\n/**\n * Used to resolve the\n * [`toStringTag`](http://ecma-international.org/ecma-262/7.0/#sec-object.prototype.tostring)\n * of values.\n */\nvar nativeObjectToString = objectProto.toString;\n\n/**\n * Converts `value` to a string using `Object.prototype.toString`.\n *\n * @private\n * @param {*} value The value to convert.\n * @returns {string} Returns the converted string.\n */\nfunction objectToString(value) {\n return nativeObjectToString.call(value);\n}\n\nexport default objectToString;\n","/**\n * Creates a unary function that invokes `func` with its argument transformed.\n *\n * @private\n * @param {Function} func The function to wrap.\n * @param {Function} transform The argument transform.\n * @returns {Function} Returns the new function.\n */\nfunction overArg(func, transform) {\n return function(arg) {\n return func(transform(arg));\n };\n}\n\nexport default overArg;\n","/**\n * Checks if `value` is object-like. A value is object-like if it's not `null`\n * and has a `typeof` result of \"object\".\n *\n * @static\n * @memberOf _\n * @since 4.0.0\n * @category Lang\n * @param {*} value The value to check.\n * @returns {boolean} Returns `true` if `value` is object-like, else `false`.\n * @example\n *\n * _.isObjectLike({});\n * // => true\n *\n * _.isObjectLike([1, 2, 3]);\n * // => true\n *\n * _.isObjectLike(_.noop);\n * // => false\n *\n * _.isObjectLike(null);\n * // => false\n */\nfunction isObjectLike(value) {\n return value != null && typeof value == 'object';\n}\n\nexport default isObjectLike;\n","/**\n * Removes all key-value entries from the list cache.\n *\n * @private\n * @name clear\n * @memberOf ListCache\n */\nfunction listCacheClear() {\n this.__data__ = [];\n this.size = 0;\n}\n\nexport default listCacheClear;\n","/**\n * Performs a\n * [`SameValueZero`](http://ecma-international.org/ecma-262/7.0/#sec-samevaluezero)\n * comparison between two values to determine if they are equivalent.\n *\n * @static\n * @memberOf _\n * @since 4.0.0\n * @category Lang\n * @param {*} value The value to compare.\n * @param {*} other The other value to compare.\n * @returns {boolean} Returns `true` if the values are equivalent, else `false`.\n * @example\n *\n * var object = { 'a': 1 };\n * var other = { 'a': 1 };\n *\n * _.eq(object, object);\n * // => true\n *\n * _.eq(object, other);\n * // => false\n *\n * _.eq('a', 'a');\n * // => true\n *\n * _.eq('a', Object('a'));\n * // => false\n *\n * _.eq(NaN, NaN);\n * // => true\n */\nfunction eq(value, other) {\n return value === other || (value !== value && other !== other);\n}\n\nexport default eq;\n","/**\n * Removes `key` and its value from the stack.\n *\n * @private\n * @name delete\n * @memberOf Stack\n * @param {string} key The key of the value to remove.\n * @returns {boolean} Returns `true` if the entry was removed, else `false`.\n */\nfunction stackDelete(key) {\n var data = this.__data__,\n result = data['delete'](key);\n\n this.size = data.size;\n return result;\n}\n\nexport default stackDelete;\n","/**\n * Gets the stack value for `key`.\n *\n * @private\n * @name get\n * @memberOf Stack\n * @param {string} key The key of the value to get.\n * @returns {*} Returns the entry value.\n */\nfunction stackGet(key) {\n return this.__data__.get(key);\n}\n\nexport default stackGet;\n","/**\n * Checks if a stack value for `key` exists.\n *\n * @private\n * @name has\n * @memberOf Stack\n * @param {string} key The key of the entry to check.\n * @returns {boolean} Returns `true` if an entry for `key` exists, else `false`.\n */\nfunction stackHas(key) {\n return this.__data__.has(key);\n}\n\nexport default stackHas;\n","/**\n * Checks if `value` is the\n * [language type](http://www.ecma-international.org/ecma-262/7.0/#sec-ecmascript-language-types)\n * of `Object`. (e.g. arrays, functions, objects, regexes, `new Number(0)`, and `new String('')`)\n *\n * @static\n * @memberOf _\n * @since 0.1.0\n * @category Lang\n * @param {*} value The value to check.\n * @returns {boolean} Returns `true` if `value` is an object, else `false`.\n * @example\n *\n * _.isObject({});\n * // => true\n *\n * _.isObject([1, 2, 3]);\n * // => true\n *\n * _.isObject(_.noop);\n * // => true\n *\n * _.isObject(null);\n * // => false\n */\nfunction isObject(value) {\n var type = typeof value;\n return value != null && (type == 'object' || type == 'function');\n}\n\nexport default isObject;\n","/** Used for built-in method references. */\nvar funcProto = Function.prototype;\n\n/** Used to resolve the decompiled source of functions. */\nvar funcToString = funcProto.toString;\n\n/**\n * Converts `func` to its source code.\n *\n * @private\n * @param {Function} func The function to convert.\n * @returns {string} Returns the source code.\n */\nfunction toSource(func) {\n if (func != null) {\n try {\n return funcToString.call(func);\n } catch (e) {}\n try {\n return (func + '');\n } catch (e) {}\n }\n return '';\n}\n\nexport default toSource;\n","/**\n * Gets the value at `key` of `object`.\n *\n * @private\n * @param {Object} [object] The object to query.\n * @param {string} key The key of the property to get.\n * @returns {*} Returns the property value.\n */\nfunction getValue(object, key) {\n return object == null ? undefined : object[key];\n}\n\nexport default getValue;\n","/**\n * Removes `key` and its value from the hash.\n *\n * @private\n * @name delete\n * @memberOf Hash\n * @param {Object} hash The hash to modify.\n * @param {string} key The key of the value to remove.\n * @returns {boolean} Returns `true` if the entry was removed, else `false`.\n */\nfunction hashDelete(key) {\n var result = this.has(key) && delete this.__data__[key];\n this.size -= result ? 1 : 0;\n return result;\n}\n\nexport default hashDelete;\n","/**\n * Checks if `value` is suitable for use as unique object key.\n *\n * @private\n * @param {*} value The value to check.\n * @returns {boolean} Returns `true` if `value` is suitable, else `false`.\n */\nfunction isKeyable(value) {\n var type = typeof value;\n return (type == 'string' || type == 'number' || type == 'symbol' || type == 'boolean')\n ? (value !== '__proto__')\n : (value === null);\n}\n\nexport default isKeyable;\n","/**\n * Creates a base function for methods like `_.forIn` and `_.forOwn`.\n *\n * @private\n * @param {boolean} [fromRight] Specify iterating from right to left.\n * @returns {Function} Returns the new base function.\n */\nfunction createBaseFor(fromRight) {\n return function(object, iteratee, keysFunc) {\n var index = -1,\n iterable = Object(object),\n props = keysFunc(object),\n length = props.length;\n\n while (length--) {\n var key = props[fromRight ? length : ++index];\n if (iteratee(iterable[key], key, iterable) === false) {\n break;\n }\n }\n return object;\n };\n}\n\nexport default createBaseFor;\n","/**\n * Copies the values of `source` to `array`.\n *\n * @private\n * @param {Array} source The array to copy values from.\n * @param {Array} [array=[]] The array to copy values to.\n * @returns {Array} Returns `array`.\n */\nfunction copyArray(source, array) {\n var index = -1,\n length = source.length;\n\n array || (array = Array(length));\n while (++index < length) {\n array[index] = source[index];\n }\n return array;\n}\n\nexport default copyArray;\n","/** Used for built-in method references. */\nvar objectProto = Object.prototype;\n\n/**\n * Checks if `value` is likely a prototype object.\n *\n * @private\n * @param {*} value The value to check.\n * @returns {boolean} Returns `true` if `value` is a prototype, else `false`.\n */\nfunction isPrototype(value) {\n var Ctor = value && value.constructor,\n proto = (typeof Ctor == 'function' && Ctor.prototype) || objectProto;\n\n return value === proto;\n}\n\nexport default isPrototype;\n","/**\n * Checks if `value` is classified as an `Array` object.\n *\n * @static\n * @memberOf _\n * @since 0.1.0\n * @category Lang\n * @param {*} value The value to check.\n * @returns {boolean} Returns `true` if `value` is an array, else `false`.\n * @example\n *\n * _.isArray([1, 2, 3]);\n * // => true\n *\n * _.isArray(document.body.children);\n * // => false\n *\n * _.isArray('abc');\n * // => false\n *\n * _.isArray(_.noop);\n * // => false\n */\nvar isArray = Array.isArray;\n\nexport default isArray;\n","/** Used as references for various `Number` constants. */\nvar MAX_SAFE_INTEGER = 9007199254740991;\n\n/**\n * Checks if `value` is a valid array-like length.\n *\n * **Note:** This method is loosely based on\n * [`ToLength`](http://ecma-international.org/ecma-262/7.0/#sec-tolength).\n *\n * @static\n * @memberOf _\n * @since 4.0.0\n * @category Lang\n * @param {*} value The value to check.\n * @returns {boolean} Returns `true` if `value` is a valid length, else `false`.\n * @example\n *\n * _.isLength(3);\n * // => true\n *\n * _.isLength(Number.MIN_VALUE);\n * // => false\n *\n * _.isLength(Infinity);\n * // => false\n *\n * _.isLength('3');\n * // => false\n */\nfunction isLength(value) {\n return typeof value == 'number' &&\n value > -1 && value % 1 == 0 && value <= MAX_SAFE_INTEGER;\n}\n\nexport default isLength;\n","/**\n * This method returns `false`.\n *\n * @static\n * @memberOf _\n * @since 4.13.0\n * @category Util\n * @returns {boolean} Returns `false`.\n * @example\n *\n * _.times(2, _.stubFalse);\n * // => [false, false]\n */\nfunction stubFalse() {\n return false;\n}\n\nexport default stubFalse;\n","/**\n * The base implementation of `_.unary` without support for storing metadata.\n *\n * @private\n * @param {Function} func The function to cap arguments for.\n * @returns {Function} Returns the new capped function.\n */\nfunction baseUnary(func) {\n return function(value) {\n return func(value);\n };\n}\n\nexport default baseUnary;\n","/**\n * Gets the value at `key`, unless `key` is \"__proto__\" or \"constructor\".\n *\n * @private\n * @param {Object} object The object to query.\n * @param {string} key The key of the property to get.\n * @returns {*} Returns the property value.\n */\nfunction safeGet(object, key) {\n if (key === 'constructor' && typeof object[key] === 'function') {\n return;\n }\n\n if (key == '__proto__') {\n return;\n }\n\n return object[key];\n}\n\nexport default safeGet;\n","/**\n * The base implementation of `_.times` without support for iteratee shorthands\n * or max array length checks.\n *\n * @private\n * @param {number} n The number of times to invoke `iteratee`.\n * @param {Function} iteratee The function invoked per iteration.\n * @returns {Array} Returns the array of results.\n */\nfunction baseTimes(n, iteratee) {\n var index = -1,\n result = Array(n);\n\n while (++index < n) {\n result[index] = iteratee(index);\n }\n return result;\n}\n\nexport default baseTimes;\n","/** Used as references for various `Number` constants. */\nvar MAX_SAFE_INTEGER = 9007199254740991;\n\n/** Used to detect unsigned integer values. */\nvar reIsUint = /^(?:0|[1-9]\\d*)$/;\n\n/**\n * Checks if `value` is a valid array-like index.\n *\n * @private\n * @param {*} value The value to check.\n * @param {number} [length=MAX_SAFE_INTEGER] The upper bounds of a valid index.\n * @returns {boolean} Returns `true` if `value` is a valid index, else `false`.\n */\nfunction isIndex(value, length) {\n var type = typeof value;\n length = length == null ? MAX_SAFE_INTEGER : length;\n\n return !!length &&\n (type == 'number' ||\n (type != 'symbol' && reIsUint.test(value))) &&\n (value > -1 && value % 1 == 0 && value < length);\n}\n\nexport default isIndex;\n","/**\n * This function is like\n * [`Object.keys`](http://ecma-international.org/ecma-262/7.0/#sec-object.keys)\n * except that it includes inherited enumerable properties.\n *\n * @private\n * @param {Object} object The object to query.\n * @returns {Array} Returns the array of property names.\n */\nfunction nativeKeysIn(object) {\n var result = [];\n if (object != null) {\n for (var key in Object(object)) {\n result.push(key);\n }\n }\n return result;\n}\n\nexport default nativeKeysIn;\n","/**\n * This method returns the first argument it receives.\n *\n * @static\n * @since 0.1.0\n * @memberOf _\n * @category Util\n * @param {*} value Any value.\n * @returns {*} Returns `value`.\n * @example\n *\n * var object = { 'a': 1 };\n *\n * console.log(_.identity(object) === object);\n * // => true\n */\nfunction identity(value) {\n return value;\n}\n\nexport default identity;\n","/**\n * A faster alternative to `Function#apply`, this function invokes `func`\n * with the `this` binding of `thisArg` and the arguments of `args`.\n *\n * @private\n * @param {Function} func The function to invoke.\n * @param {*} thisArg The `this` binding of `func`.\n * @param {Array} args The arguments to invoke `func` with.\n * @returns {*} Returns the result of `func`.\n */\nfunction apply(func, thisArg, args) {\n switch (args.length) {\n case 0: return func.call(thisArg);\n case 1: return func.call(thisArg, args[0]);\n case 2: return func.call(thisArg, args[0], args[1]);\n case 3: return func.call(thisArg, args[0], args[1], args[2]);\n }\n return func.apply(thisArg, args);\n}\n\nexport default apply;\n","/**\n * Creates a function that returns `value`.\n *\n * @static\n * @memberOf _\n * @since 2.4.0\n * @category Util\n * @param {*} value The value to return from the new function.\n * @returns {Function} Returns the new constant function.\n * @example\n *\n * var objects = _.times(2, _.constant({ 'a': 1 }));\n *\n * console.log(objects);\n * // => [{ 'a': 1 }, { 'a': 1 }]\n *\n * console.log(objects[0] === objects[1]);\n * // => true\n */\nfunction constant(value) {\n return function() {\n return value;\n };\n}\n\nexport default constant;\n","/** Used to detect hot functions by number of calls within a span of milliseconds. */\nvar HOT_COUNT = 800,\n HOT_SPAN = 16;\n\n/* Built-in method references for those with the same name as other `lodash` methods. */\nvar nativeNow = Date.now;\n\n/**\n * Creates a function that'll short out and invoke `identity` instead\n * of `func` when it's called `HOT_COUNT` or more times in `HOT_SPAN`\n * milliseconds.\n *\n * @private\n * @param {Function} func The function to restrict.\n * @returns {Function} Returns the new shortable function.\n */\nfunction shortOut(func) {\n var count = 0,\n lastCalled = 0;\n\n return function() {\n var stamp = nativeNow(),\n remaining = HOT_SPAN - (stamp - lastCalled);\n\n lastCalled = stamp;\n if (remaining > 0) {\n if (++count >= HOT_COUNT) {\n return arguments[0];\n }\n } else {\n count = 0;\n }\n return func.apply(undefined, arguments);\n };\n}\n\nexport default shortOut;\n","// break it out on its own because\n// it's building from the lodash-es from scratch\n// according to this discussion https://github.com/lodash/lodash/issues/3298\nimport isPlainObject from 'lodash-es/isPlainObject'\nimport merge from 'lodash-es/merge'\n\n/**\n * previously we already make sure the order of the namespaces\n * and attach the auth client to it\n * @param {array} promises array of unresolved promises\n * @param {boolean} asObject if true then merge the result object\n * @return {object} promise resolved with the array of promises resolved results\n */\nexport function chainPromises(promises, asObject = false) {\n return promises.reduce((promiseChain, currentTask) => (\n promiseChain.then(chainResults => (\n currentTask.then(currentResult => (\n asObject === false ? [...chainResults, currentResult] : merge(chainResults, currentResult)\n ))\n ))\n ), Promise.resolve(\n asObject === false ? [] : (isPlainObject(asObject) ? asObject : {})\n ))\n}\n\n\n/**\n * This one return a different result from the chainPromises\n * it will be the same like chainFns that take one promise resolve as the next fn parameter\n * @param {function} initPromise a function that accept param and resolve result\n * @param {array} promises array of function pass that resolve promises\n * @return {promise} resolve the processed result\n */\nexport function chainProcessPromises(initPromise, ...promises) {\n return (...args) => (\n promises.reduce((promiseChain, currentTask) => (\n promiseChain.then(chainResult => (\n currentTask(chainResult)\n )\n )\n ), Reflect.apply(initPromise, null, args))\n )\n}\n","// @BUG when call disconnected \n// this keep causing an \"Disconnect call failed TypeError: Cannot read property 'readyState' of null\"\n// I think that is because it's not login then it can not be disconnect\n// how do we track this state globally\nimport { LOGIN_EVENT_NAME } from 'jsonql-constants'\nimport { clearMainEmitEvt } from '../modules'\n\n/**\n * create a login event handler \n * @param {object} opts configurations \n * @param {object} nspMap contain all the required info\n * @param {object} ee event emitter \n * @return {void}\n */\nexport function loginEventHandler(opts, nspMap, ee) {\n const { log } = opts\n const { namespaces } = nspMap\n\n ee.$only(LOGIN_EVENT_NAME, function loginEventHandlerCallback(tokenFromLoginAction) {\n \n log('createClient LOGIN_EVENT_NAME $only handler')\n\n clearMainEmitEvt(ee, namespaces)\n // console.log('LOGIN_EVENT_NAME', token)\n const newNsps = createNspAction(opts, nspMap, tokenFromLoginAction)\n // rebind it\n Reflect.apply(\n clientEventHandler, // @NOTE is this the problem that cause the hang up?\n null,\n args.concat([newNsps.namespaces, newNsps.nsps])\n )\n })\n}","// bunch of generic helpers\n\nimport isArray from 'lodash-es/isArray'\nimport isPlainObject from 'lodash-es/isPlainObject'\nimport trim from 'lodash-es/trim'\n\n/**\n * DIY in Array\n * @param {array} arr to check from\n * @param {*} value to check against\n * @return {boolean} true on found\n */\nexport const inArray = (arr, value) => !!arr.filter(a => a === value).length\n\n// quick and dirty to turn non array to array\nexport const toArray = (arg) => isArray(arg) ? arg : [arg]\n\n/**\n * parse string to json or just return the original value if error happened\n * @param {*} n input\n * @param {boolean} [t=true] or throw\n * @return {*} json object on success\n */\nexport const parseJson = function(n, t=true) {\n try {\n return JSON.parse(n)\n } catch(e) {\n if (t) {\n return n\n }\n throw new Error(e)\n }\n}\n\n/**\n * @param {object} obj for search\n * @param {string} key target\n * @return {boolean} true on success\n */\nexport const isObjectHasKey = function(obj, key) {\n try {\n const keys = Object.keys(obj)\n return inArray(keys, key)\n } catch(e) {\n // @BUG when the obj is not an OBJECT we got some weird output\n return false\n }\n}\n\n/**\n * create a event name\n * @param {string[]} args\n * @return {string} event name for use\n */\nexport const createEvt = (...args) => args.join('_')\n\n/**\n * simple util method to get the value\n * @param {string} name of the key\n * @param {object} obj to take value from\n * @return {*} the object value id by name or undefined\n */\nexport const getConfigValue = (name, obj) => (\n obj && isPlainObject(obj) ? ( (name in obj) ? obj[name] : undefined ) : undefined\n)\n\n/**\n * small util to make sure the return value is valid JSON object\n * @param {*} n input\n * @return {object} correct JSON object\n */\nexport const toJson = n => {\n if (typeof n === 'string') {\n return parseJson(n)\n }\n return parseJson(JSON.stringify(n))\n}\n\n/**\n * Check several parameter that there is something in the param\n * @param {*} param input\n * @return {boolean}\n */\nexport const isNotEmpty = function(param) {\n return param !== undefined && param !== false && param !== null && trim(param) !== ''\n}\n\n/**\n * Simple check if the prop is function\n * @param {*} prop input\n * @return {boolean} true on success\n */\nexport const isFunc = prop => {\n if (typeof prop === 'function') {\n return true;\n }\n console.error(`Expect to be Function type! Got ${typeof prop}`)\n}\n\n// generic placeholder function\nexport const nil = () => false\n","// custom validation error class\n// when validaton failed\nexport default class JsonqlValidationError extends Error {\n constructor(...args) {\n super(...args)\n\n this.message = args[0]\n this.detail = args[1]\n\n this.className = JsonqlValidationError.name;\n\n if (Error.captureStackTrace) {\n Error.captureStackTrace(this, JsonqlValidationError)\n }\n }\n\n static get name() {\n return 'JsonqlValidationError'\n }\n}\n","/**\n * @param {boolean} sec return in second or not\n * @return {number} timestamp\n */\nexport const timestamp = (sec = false) => {\n let time = Date.now()\n return sec ? Math.floor( time / 1000 ) : time\n}\n","// ported from jsonql-params-validator\n// craete several helper function to construct / extract the payload\n// and make sure they are all the same\nimport {\n PAYLOAD_PARAM_NAME,\n CONDITION_PARAM_NAME,\n RESOLVER_PARAM_NAME,\n QUERY_ARG_NAME,\n TIMESTAMP_PARAM_NAME\n} from 'jsonql-constants'\n\nimport JsonqlValidationError from 'jsonql-errors/src/validation-error'\n\nimport isArray from 'lodash-es/isArray'\nimport isString from 'lodash-es/isString'\nimport isPlainObject from 'lodash-es/isPlainObject'\n\nimport { timestamp } from './timestamp'\nimport { parseJson } from './generic'\n\n/**\n * check if the payload has a timestamp field, then append a new timestamp to it\n * @param {object} payload from the com\n * @return {array} timestamp field with an array value\n */\nexport const handleTimestamp = payload => {\n let ts = payload[TIMESTAMP_PARAM_NAME]\n if (!isArray(ts)) {\n ts = [ts]\n }\n ts.push( timestamp() )\n\n return ts\n}\n\n/**\n * make sure it's an object (it was call formatPayload but it doesn't make sense)\n * @param {*} payload the object comes in could be string based\n * @return {object} the transformed payload\n */\nexport const toPayload = payload => isString(payload) ? parseJson(payload) : payload\n\n/**\n * @param {*} args arguments to send\n *@return {object} formatted payload\n */\nexport const formatPayload = (args) => (\n { [QUERY_ARG_NAME]: args }\n)\n\n/**\n * extract the resolver name from the payload \n * @param {object} payload\n * @return {string} resolver name \n */\nexport function getResolverFromPayload(payload) {\n const keys = Object.keys(payload)\n return keys.filter(key => key !== TIMESTAMP_PARAM_NAME)[0]\n}\n\n/**\n * wrapper method to add the timestamp as well\n * @param {string} resolverName\n * @param {*} payload\n * @return {object} delierable\n */\nexport function createDeliverable(resolverName, payload) {\n return {\n [resolverName]: payload,\n [TIMESTAMP_PARAM_NAME]: [ timestamp() ]\n }\n}\n\n/**\n * @param {string} resolverName name of function\n * @param {array} [args=[]] from the ...args\n * @param {boolean} [jsonp = false] add v1.3.0 to koa\n * @return {object} formatted argument\n */\nexport function createQuery(resolverName, args = [], jsonp = false) {\n if (isString(resolverName) && isArray(args)) {\n let payload = formatPayload(args)\n if (jsonp === true) {\n return payload\n }\n return createDeliverable(resolverName, payload)\n }\n throw new JsonqlValidationError(`[createQuery] expect resolverName to be string and args to be array!`, { resolverName, args })\n}\n\n/**\n * string version of the createQuery\n * @return {string}\n */\nexport function createQueryStr(resolverName, args = [], jsonp = false) {\n return JSON.stringify(createQuery(resolverName, args, jsonp))\n}\n\n/**\n * @param {string} resolverName name of function\n * @param {*} payload to send\n * @param {object} [condition={}] for what\n * @param {boolean} [jsonp = false] add v1.3.0 to koa\n * @return {object} formatted argument\n */\nexport function createMutation(resolverName, payload, condition = {}, jsonp = false) {\n const _payload = {\n [PAYLOAD_PARAM_NAME]: payload,\n [CONDITION_PARAM_NAME]: condition\n }\n if (jsonp === true) {\n return _payload\n }\n if (isString(resolverName)) {\n return createDeliverable(resolverName, _payload)\n }\n throw new JsonqlValidationError(`[createMutation] expect resolverName to be string!`, { resolverName, payload, condition })\n}\n\n/**\n * string version of createMutation\n * @return {string}\n */\nexport function createMutationStr(resolverName, payload, condition = {}, jsonp = false) {\n return JSON.stringify(createMutation(resolverName, payload, condition, jsonp))\n}\n\n/**\n * Extract the parts from payload and format for use\n * @param {string} resolverName name of fn\n * @param {object} payload the incoming json\n * @return {object|boolean} false on failed\n */\nexport function getQueryFromArgs(resolverName, payload) {\n if (resolverName && isPlainObject(payload)) {\n const args = payload[resolverName]\n if (args[QUERY_ARG_NAME]) {\n return {\n [RESOLVER_PARAM_NAME]: resolverName,\n [QUERY_ARG_NAME]: args[QUERY_ARG_NAME],\n [TIMESTAMP_PARAM_NAME]: handleTimestamp(payload)\n }\n }\n }\n return false\n}\n\n/**\n * Share function so no repeat\n * @param {object} payload the payload from client\n * @param {function} processor the last get result method\n * @return {*} result processed result\n */\nfunction processPayload(payload, processor) {\n const p = toPayload(payload)\n const resolverName = getResolverFromPayload(p)\n return Reflect.apply(processor, null, [resolverName, p])\n}\n\n/**\n * extra the payload back\n * @param {*} payload from http call\n * @return {object} resolverName and args\n */\nexport function getQueryFromPayload(payload) {\n const result = processPayload(payload, getQueryFromArgs)\n if (result !== false) {\n return result\n }\n throw new JsonqlValidationError('[getQueryArgs] Payload is malformed!', payload)\n}\n\n/**\n * Further break down from method below for use else where\n * @param {string} resolverName name of fn\n * @param {object} payload payload\n * @return {object|boolean} false on failed\n */\nexport function getMutationFromArgs(resolverName, payload) {\n if (resolverName && isPlainObject(payload)) {\n const args = payload[resolverName]\n if (args) {\n return {\n [RESOLVER_PARAM_NAME]: resolverName,\n [PAYLOAD_PARAM_NAME]: args[PAYLOAD_PARAM_NAME],\n [CONDITION_PARAM_NAME]: args[CONDITION_PARAM_NAME],\n [TIMESTAMP_PARAM_NAME]: handleTimestamp(payload)\n }\n }\n }\n return false\n}\n\n/**\n * @param {object} payload\n * @return {object} resolverName, payload, conditon\n */\nexport function getMutationFromPayload(payload) {\n const result = processPayload(payload, getMutationFromArgs)\n\n if (result !== false) {\n return result\n }\n throw new JsonqlValidationError('[getMutationArgs] Payload is malformed!', payload)\n}\n","// There are the socket related methods ported back from \n// ws-server-core and ws-client-core \nimport {\n WS_REPLY_TYPE,\n WS_EVT_NAME,\n WS_DATA_NAME,\n TIMESTAMP_PARAM_NAME,\n ERROR_KEY,\n EMIT_REPLY_TYPE,\n ACKNOWLEDGE_REPLY_TYPE\n} from 'jsonql-constants'\nimport { JsonqlError } from 'jsonql-errors' \nimport isString from 'lodash-es/isString'\n\nimport { toJson, isObjectHasKey, nil } from './generic'\nimport { timestamp } from './timestamp'\n\nconst PAYLOAD_NOT_DECODED_ERR = 'payload can not decoded'\nconst WS_KEYS = [\n WS_REPLY_TYPE,\n WS_EVT_NAME,\n WS_DATA_NAME\n]\n\n\n/**\n * The ws doesn't have a acknowledge callback like socket.io\n * so we have to DIY one for ws and other that doesn't have it\n * @param {string} type of reply\n * @param {string} resolverName which is replying\n * @param {*} data payload\n * @param {array} [ts= []] the last received ts, if any \n * @return {string} stringify json\n */\nexport const createWsReply = (type, resolverName, data, ts = []) => {\n ts.push(timestamp())\n return JSON.stringify({\n data: {\n [WS_REPLY_TYPE]: type,\n [WS_EVT_NAME]: resolverName,\n [WS_DATA_NAME]: toJson(data)\n },\n [TIMESTAMP_PARAM_NAME]: ts \n })\n}\n\n// extended function \nexport const createReplyMsg = (resolverName, data, ts = []) => (\n createWsReply(EMIT_REPLY_TYPE, resolverName, data, ts)\n)\n\nexport const createAcknowledgeMsg = (resolverName, data, ts = []) => (\n createWsReply(ACKNOWLEDGE_REPLY_TYPE, resolverName, data, ts)\n)\n\n/**\n * @param {string|object} payload should be string when reply but could be transformed\n * @return {boolean} true is OK\n */\nexport const isWsReply = payload => {\n const json = isString(payload) ? toJson(payload) : payload\n const { data } = json\n if (data) {\n let result = WS_KEYS.filter(key => isObjectHasKey(data, key))\n return (result.length === WS_KEYS.length) ? data : false\n }\n return false\n}\n\n/**\n * @param {string|object} data received data\n * @param {function} [cb=nil] this is for extracting the TS field or when it's error\n * @return {object} false on failed\n */\nexport const extractWsPayload = (payload, cb = nil) => {\n try {\n const json = toJson(payload)\n // now handle the data\n let _data\n if ((_data = isWsReply(json)) !== false) {\n // note the ts property is on its own \n cb(TIMESTAMP_PARAM_NAME, json[TIMESTAMP_PARAM_NAME])\n \n return {\n data: toJson(_data[WS_DATA_NAME]),\n resolverName: _data[WS_EVT_NAME],\n type: _data[WS_REPLY_TYPE]\n }\n }\n throw new JsonqlError(PAYLOAD_NOT_DECODED_ERR, payload)\n } catch(e) {\n return cb(ERROR_KEY, e)\n }\n}\n","// the WebSocket main handler\nimport {\n LOGOUT_EVENT_NAME,\n ACKNOWLEDGE_REPLY_TYPE,\n EMIT_REPLY_TYPE,\n ERROR_KEY,\n\n ON_ERROR_FN_NAME,\n ON_MESSAGE_FN_NAME,\n ON_RESULT_FN_NAME,\n ON_READY_FN_NAME,\n ON_LOGIN_FN_NAME\n} from 'jsonql-constants'\nimport {\n createQueryStr,\n createEvt,\n extractWsPayload\n} from 'jsonql-utils/module'\nimport {\n handleNamespaceOnError,\n createIntercomPayload\n} from '../modules'\n\n/**\n * in some edge case we might not even have a resolverName, then\n * we issue a global error for the developer to catch it\n * @param {object} ee event emitter\n * @param {string} namespace nsp\n * @param {string} resolverName resolver\n * @param {object} json decoded payload or error object\n * @return {undefined} nothing return\n */\nconst errorTypeHandler = (ee, namespace, resolverName, json) => {\n let evt = [namespace]\n if (resolverName) {\n evt.push(resolverName)\n }\n evt.push(ON_ERROR_FN_NAME)\n let evtName = Reflect.apply(createEvt, null, evt)\n // test if there is a data field\n let payload = json.data || json\n ee.$trigger(evtName, [payload])\n}\n\n/**\n * Handle the logout event when it's enableAuth\n * @param {object} ee eventEmitter\n * @param {object} ws the WebSocket instance\n * @return {void}\n */\nconst logoutEventListener = (ee, ws) => {\n // listen to the LOGOUT_EVENT_NAME when this is a private nsp\n ee.$on(LOGOUT_EVENT_NAME, function closeEvtHandler() {\n try {\n // @TODO we need find a way to get the userdata\n ws.send(createIntercomPayload(LOGOUT_EVENT_NAME))\n log('terminate ws connection')\n ws.terminate()\n } catch(e) {\n console.error('ws.terminate error', e)\n }\n })\n}\n\n/**\n * Binding the event to socket normally\n * @param {string} namespace\n * @param {object} ws the nsp\n * @param {object} ee EventEmitter\n * @param {boolean} isPrivate to id if this namespace is private or not\n * @param {object} opts configuration\n * @return {object} promise resolve after the onopen event\n */\nexport function bindSocketEventHandler(namespace, ws, ee, isPrivate, opts) {\n const { log } = opts\n let onReadCalls = 2\n // log(`log test, isPrivate:`, isPrivate)\n // connection open\n ws.onopen = function onOpenCallback() {\n\n log('=== ws.onopen listened -->', namespace)\n // we just call the onReady\n ee.$call(ON_READY_FN_NAME)(namespace)\n // we only want to allow it get call twice (number of namespaces)\n --onReadCalls\n if (onReadCalls === 0) {\n ee.$off(ON_READY_FN_NAME)\n }\n\n // need an extra parameter here to id the private nsp\n if (isPrivate) {\n log(`isPrivate and fire the ${ON_LOGIN_FN_NAME}`)\n ee.$call(ON_LOGIN_FN_NAME)(namespace)\n }\n // add listener only after the open is called\n ee.$only(\n createEvt(namespace, EMIT_REPLY_TYPE),\n /**\n * actually send the payload to server\n * @param {string} resolverName\n * @param {array} args NEED TO CHECK HOW WE PASS THIS!\n */\n function wsMainOnEvtHandler(resolverName, args) {\n\n const payload = createQueryStr(resolverName, args)\n log('ws.onopen.send', resolverName, args, payload)\n\n ws.send(payload)\n }\n )\n }\n\n // reply\n // If we change it to the event callback style\n // then the payload will just be the payload and fucks up the extractWsPayload call @TODO\n ws.onmessage = function onMessageCallback(payload) {\n // console.log(`on.message`, typeof payload, payload)\n try {\n // log(`ws.onmessage raw payload`, payload)\n // @TODO the payload actually contain quite a few things - is that changed?\n // type: message, data: data_send_from_server\n const json = extractWsPayload(payload.data)\n const { resolverName, type } = json\n\n log('Respond from server', type, json)\n\n switch (type) {\n case EMIT_REPLY_TYPE:\n let e1 = createEvt(namespace, resolverName, ON_MESSAGE_FN_NAME)\n let r = ee.$trigger(e1, [json])\n log(`EMIT_REPLY_TYPE`, e1, r)\n break\n case ACKNOWLEDGE_REPLY_TYPE:\n let e2 = createEvt(namespace, resolverName, ON_RESULT_FN_NAME)\n let x2 = ee.$trigger(e2, [json])\n log(`ACKNOWLEDGE_REPLY_TYPE`, e2, x2)\n break\n case ERROR_KEY:\n // this is handled error and we won't throw it\n // we need to extract the error from json\n log(`ERROR_KEY`)\n errorTypeHandler(ee, namespace, resolverName, json)\n break\n // @TODO there should be an error type instead of roll into the other two types? TBC\n default:\n // if this happen then we should throw it and halt the operation all together\n log('Unhandled event!', json)\n errorTypeHandler(ee, namespace, resolverName, json)\n // let error = {error: {'message': 'Unhandled event!', type}};\n // ee.$trigger(createEvt(namespace, resolverName, ON_RESULT_FN_NAME), [error])\n }\n } catch(e) {\n console.error(`ws.onmessage error`, e)\n errorTypeHandler(ee, namespace, false, e)\n }\n }\n // when the server close the connection\n ws.onclose = function onCloseCallback() {\n log('ws.onclose callback')\n // @TODO what to do with this\n // ee.$trigger(LOGOUT_EVENT_NAME, [namespace])\n }\n // add a onerror event handler here\n ws.onerror = function onErrorCallback(err) {\n // trigger a global error event\n log(`ws.onerror`, err)\n handleNamespaceOnError(ee, namespace, err)\n }\n\n if (isPrivate) {\n logoutEventListener(ee, ws)\n }\n\n}\n","// actually binding the event client to the socket client\n\n// from the jsonql-ws-client-core\nimport { clientEventListener } from '../modules'\n// local \nimport { createNspAction } from './create-nsp-action'\nimport { loginEventHandler } from './login-event-handler'\nimport { bindSocketEventHandler } from './bind-socket-event-handler'\n\n/**\n * create the NSP(s) and determine if this require auth or not \n * @param {object} opts configuration\n * @param {object} nspMap namespace with resolvers\n * @param {object} ee EventEmitter to pass through\n * @return {object} what comes in what goes out\n */\nfunction createNsp(opts, nspMap, ee) {\n // now create the nsps\n // const { namespaces } = nspMap\n const { token } = opts\n\n return createNspAction(opts, nspMap, token)\n .then(nsps => {\n const listenerFn = clientEventListener(bindSocketEventHandler, nsps)\n // now run it\n listenerFn(opts, nspMap, ee)\n\n if (opts.enableAuth) {\n loginEventHandler(opts, nspMap, ee)\n }\n // return what input\n return { opts, nspMap, ee }\n }) \n}\n\nexport { createNsp }","// breaking up the create-nsp.js file \n// then regroup them back together here \nimport { createNsp } from './create-nsp'\n\nexport default createNsp\n","// share method to create the wsClientResolver\nimport { initWebSocketClient } from './init-websocket-client'\nimport createNsp from '../create-nsp'\nimport { NSP_CLIENT, NSP_AUTH_CLIENT } from 'jsonql-constants'\n\n/**\n * Create the framework <---> jsonql client binding\n * @param {object} frameworkModule the different WebSocket module\n * @return {function} the wsClientResolver\n */\nfunction bindFrameworkToJsonql(frameworkModule) {\n /**\n * wsClientResolver\n * @param {object} opts configuration\n * @param {object} nspMap from the contract\n * @param {object} ee instance of the eventEmitter\n * @return {object} passing the same 3 input out with additional in the opts\n */\n return function createClientBindingAction(opts, nspMap, ee) {\n const { log } = opts\n opts[NSP_CLIENT] = initWebSocketClient(frameworkModule, false, log)\n opts[NSP_AUTH_CLIENT] = initWebSocketClient(frameworkModule, true, log) \n // @1.0.7 remove later once everything fixed \n \n log(`bindFrameworkToJsonql`, ee.name, nspMap)\n // console.log(`contract`, opts.contract)\n return createNsp(opts, nspMap, ee)\n }\n}\n\nexport { bindFrameworkToJsonql }","// this will be the news style interface that will pass to the jsonql-ws-client\n// then return a function for accepting an opts to generate the final\n// client api\nimport WebSocket from 'ws'\nimport createWebSocketBinding from '../core/create-websocket-binding'\n\n/**\n * @param {object} opts configuration\n * @param {object} nspMap from the contract\n * @param {object} ee instance of the eventEmitter\n * @return {object} passing the same 3 input out with additional in the opts\n */\nexport default createWebSocketBinding(WebSocket)\n","// this is the module entry point for node client\nimport {\n wsClientCore\n} from './core/modules'\nimport { wsClientConstProps } from './options'\n\nimport nodeFrameworkSocketEngine from './node/node-framework-socket-engine'\n\n// export back the function and that's it\nexport default function wsNodeClient(config = {}, constProps = {}) {\n const initClientMethod = wsClientCore(\n nodeFrameworkSocketEngine, \n {}, \n Object.assign({}, wsClientConstProps, constProps)\n )\n return initClientMethod(config)\n}\n"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;ACAA;;;;;;;;;ACAA;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;ACAA;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;ACAA;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;"} \ No newline at end of file +{"version":3,"file":"main.js","sources":["../../ws-client-core/node_modules/lodash-es/isArray.js","node_modules/rollup-plugin-node-globals/src/global.js","../../ws-client-core/node_modules/lodash-es/_objectToString.js","../../ws-client-core/node_modules/lodash-es/_overArg.js","../../ws-client-core/node_modules/lodash-es/isObjectLike.js","../../ws-client-core/node_modules/lodash-es/_arrayMap.js","../../ws-client-core/node_modules/lodash-es/_baseSlice.js","../../ws-client-core/node_modules/lodash-es/_baseFindIndex.js","../../ws-client-core/node_modules/lodash-es/_baseIsNaN.js","../../ws-client-core/node_modules/lodash-es/_strictIndexOf.js","../../ws-client-core/node_modules/lodash-es/_asciiToArray.js","../../ws-client-core/node_modules/lodash-es/_hasUnicode.js","../../ws-client-core/node_modules/lodash-es/_unicodeToArray.js","../../ws-client-core/node_modules/jsonql-utils/src/generic.js","../../ws-client-core/node_modules/lodash-es/_listCacheClear.js","../../ws-client-core/node_modules/lodash-es/eq.js","../../ws-client-core/node_modules/lodash-es/_stackDelete.js","../../ws-client-core/node_modules/lodash-es/_stackGet.js","../../ws-client-core/node_modules/lodash-es/_stackHas.js","../../ws-client-core/node_modules/lodash-es/isObject.js","../../ws-client-core/node_modules/lodash-es/_toSource.js","../../ws-client-core/node_modules/lodash-es/_getValue.js","../../ws-client-core/node_modules/lodash-es/_hashDelete.js","../../ws-client-core/node_modules/lodash-es/_isKeyable.js","../../ws-client-core/node_modules/lodash-es/_createBaseFor.js","../../ws-client-core/node_modules/lodash-es/_copyArray.js","../../ws-client-core/node_modules/lodash-es/_isPrototype.js","../../ws-client-core/node_modules/lodash-es/isLength.js","../../ws-client-core/node_modules/lodash-es/stubFalse.js","../../ws-client-core/node_modules/lodash-es/_baseUnary.js","../../ws-client-core/node_modules/lodash-es/_safeGet.js","../../ws-client-core/node_modules/lodash-es/_baseTimes.js","../../ws-client-core/node_modules/lodash-es/_isIndex.js","../../ws-client-core/node_modules/lodash-es/_nativeKeysIn.js","../../ws-client-core/node_modules/lodash-es/identity.js","../../ws-client-core/node_modules/lodash-es/_apply.js","../../ws-client-core/node_modules/lodash-es/constant.js","../../ws-client-core/node_modules/lodash-es/_shortOut.js","../../ws-client-core/node_modules/jsonql-errors/src/enum-error.js","../../ws-client-core/node_modules/jsonql-errors/src/type-error.js","../../ws-client-core/node_modules/jsonql-errors/src/checker-error.js","../../ws-client-core/node_modules/jsonql-errors/src/validation-error.js","../../ws-client-core/node_modules/jsonql-utils/src/contract.js","../../ws-client-core/node_modules/jsonql-utils/src/timestamp.js","../../ws-client-core/node_modules/jsonql-utils/src/params-api.js","../../ws-client-core/node_modules/jsonql-utils/src/namespace.js","../../ws-client-core/node_modules/jsonql-utils/src/socket.js","../../ws-client-core/src/callers/intercom-methods.js","../../ws-client-core/node_modules/jsonql-params-validator/src/number.js","../../ws-client-core/node_modules/jsonql-params-validator/src/string.js","../../ws-client-core/node_modules/jsonql-params-validator/src/boolean.js","../../ws-client-core/node_modules/jsonql-params-validator/src/any.js","../../ws-client-core/node_modules/jsonql-params-validator/src/constants.js","../../ws-client-core/node_modules/jsonql-params-validator/src/combine.js","../../ws-client-core/node_modules/jsonql-params-validator/src/array.js","../../ws-client-core/node_modules/jsonql-params-validator/src/object.js","../../ws-client-core/node_modules/jsonql-params-validator/src/validator.js","../../ws-client-core/node_modules/lodash-es/_setCacheAdd.js","../../ws-client-core/node_modules/lodash-es/_setCacheHas.js","../../ws-client-core/node_modules/lodash-es/_arraySome.js","../../ws-client-core/node_modules/lodash-es/_cacheHas.js","../../ws-client-core/node_modules/lodash-es/_mapToArray.js","../../ws-client-core/node_modules/lodash-es/_setToArray.js","../../ws-client-core/node_modules/lodash-es/_arrayPush.js","../../ws-client-core/node_modules/lodash-es/_arrayFilter.js","../../ws-client-core/node_modules/lodash-es/stubArray.js","../../ws-client-core/node_modules/lodash-es/_matchesStrictComparable.js","../../ws-client-core/node_modules/lodash-es/_baseHasIn.js","../../ws-client-core/node_modules/lodash-es/_baseProperty.js","../../ws-client-core/node_modules/lodash-es/negate.js","../../ws-client-core/node_modules/lodash-es/_baseFindKey.js","../../ws-client-core/node_modules/jsonql-params-validator/src/is-in-array.js","../../ws-client-core/node_modules/jsonql-params-validator/src/options/run-validation.js","../../ws-client-core/node_modules/jsonql-params-validator/src/options/check-options-async.js","../../ws-client-core/node_modules/jsonql-params-validator/src/options/construct-config.js","../../ws-client-core/node_modules/jsonql-params-validator/src/options/index.js","../../ws-client-core/node_modules/jsonql-params-validator/index.js","../../ws-client-core/src/utils/get-log-fn.js","../../ws-client-core/node_modules/@to1source/event/src/constants.js","../../ws-client-core/node_modules/@to1source/event/src/store.js","../../ws-client-core/node_modules/@to1source/event/src/utils.js","../../ws-client-core/node_modules/@to1source/event/src/suspend.js","../../ws-client-core/node_modules/@to1source/event/src/store-service.js","../../ws-client-core/node_modules/@to1source/event/src/event-service.js","../../ws-client-core/node_modules/@to1source/event/index.js","../../ws-client-core/src/utils/get-event-emitter.js","../../ws-client-core/src/utils/helpers.js","../../ws-client-core/src/options/constants.js","../../ws-client-core/src/callers/respond-handler.js","../../ws-client-core/src/callers/action-call.js","../../ws-client-core/src/callers/setup-send-method.js","../../ws-client-core/src/callers/setup-resolver.js","../../ws-client-core/src/callers/generator-methods.js","../../ws-client-core/src/callers/callers-generator.js","../../ws-client-core/src/callers/setup-intercom.js","../../ws-client-core/src/callers/setup-final-step.js","../../ws-client-core/src/options/index.js","../../ws-client-core/src/api.js","../../ws-client-core/src/listener/create-nsp-clients.js","../../ws-client-core/src/listener/trigger-namespaces-on-error.js","../../ws-client-core/src/listener/event-listeners.js","../../ws-client-core/src/listener/client-event-listener.js","src/options/index.js","src/core/create-websocket-binding/init-websocket-client.js","node_modules/lodash-es/_objectToString.js","node_modules/lodash-es/_overArg.js","node_modules/lodash-es/isObjectLike.js","node_modules/lodash-es/_listCacheClear.js","node_modules/lodash-es/eq.js","node_modules/lodash-es/_stackDelete.js","node_modules/lodash-es/_stackGet.js","node_modules/lodash-es/_stackHas.js","node_modules/lodash-es/isObject.js","node_modules/lodash-es/_toSource.js","node_modules/lodash-es/_getValue.js","node_modules/lodash-es/_hashDelete.js","node_modules/lodash-es/_isKeyable.js","node_modules/lodash-es/_createBaseFor.js","node_modules/lodash-es/_copyArray.js","node_modules/lodash-es/_isPrototype.js","node_modules/lodash-es/isArray.js","node_modules/lodash-es/isLength.js","node_modules/lodash-es/stubFalse.js","node_modules/lodash-es/_baseUnary.js","node_modules/lodash-es/_safeGet.js","node_modules/lodash-es/_baseTimes.js","node_modules/lodash-es/_isIndex.js","node_modules/lodash-es/_nativeKeysIn.js","node_modules/lodash-es/identity.js","node_modules/lodash-es/_apply.js","node_modules/lodash-es/constant.js","node_modules/lodash-es/_shortOut.js","node_modules/jsonql-utils/src/chain-promises.js","src/core/create-nsp/login-event-handler.js","node_modules/jsonql-utils/src/generic.js","node_modules/jsonql-errors/src/validation-error.js","node_modules/jsonql-utils/src/timestamp.js","node_modules/jsonql-utils/src/params-api.js","node_modules/jsonql-utils/src/socket.js","src/core/create-nsp/bind-socket-event-handler.js","src/core/create-nsp/create-nsp.js","src/core/create-nsp/index.js","src/core/create-websocket-binding/bind-framework-to-jsonql.js","src/node/node-framework-socket-engine.js","src/node-ws-client.js"],"sourcesContent":["/**\n * Checks if `value` is classified as an `Array` object.\n *\n * @static\n * @memberOf _\n * @since 0.1.0\n * @category Lang\n * @param {*} value The value to check.\n * @returns {boolean} Returns `true` if `value` is an array, else `false`.\n * @example\n *\n * _.isArray([1, 2, 3]);\n * // => true\n *\n * _.isArray(document.body.children);\n * // => false\n *\n * _.isArray('abc');\n * // => false\n *\n * _.isArray(_.noop);\n * // => false\n */\nvar isArray = Array.isArray;\n\nexport default isArray;\n","export default (typeof global !== \"undefined\" ? global :\n typeof self !== \"undefined\" ? self :\n typeof window !== \"undefined\" ? window : {});\n","/** Used for built-in method references. */\nvar objectProto = Object.prototype;\n\n/**\n * Used to resolve the\n * [`toStringTag`](http://ecma-international.org/ecma-262/7.0/#sec-object.prototype.tostring)\n * of values.\n */\nvar nativeObjectToString = objectProto.toString;\n\n/**\n * Converts `value` to a string using `Object.prototype.toString`.\n *\n * @private\n * @param {*} value The value to convert.\n * @returns {string} Returns the converted string.\n */\nfunction objectToString(value) {\n return nativeObjectToString.call(value);\n}\n\nexport default objectToString;\n","/**\n * Creates a unary function that invokes `func` with its argument transformed.\n *\n * @private\n * @param {Function} func The function to wrap.\n * @param {Function} transform The argument transform.\n * @returns {Function} Returns the new function.\n */\nfunction overArg(func, transform) {\n return function(arg) {\n return func(transform(arg));\n };\n}\n\nexport default overArg;\n","/**\n * Checks if `value` is object-like. A value is object-like if it's not `null`\n * and has a `typeof` result of \"object\".\n *\n * @static\n * @memberOf _\n * @since 4.0.0\n * @category Lang\n * @param {*} value The value to check.\n * @returns {boolean} Returns `true` if `value` is object-like, else `false`.\n * @example\n *\n * _.isObjectLike({});\n * // => true\n *\n * _.isObjectLike([1, 2, 3]);\n * // => true\n *\n * _.isObjectLike(_.noop);\n * // => false\n *\n * _.isObjectLike(null);\n * // => false\n */\nfunction isObjectLike(value) {\n return value != null && typeof value == 'object';\n}\n\nexport default isObjectLike;\n","/**\n * A specialized version of `_.map` for arrays without support for iteratee\n * shorthands.\n *\n * @private\n * @param {Array} [array] The array to iterate over.\n * @param {Function} iteratee The function invoked per iteration.\n * @returns {Array} Returns the new mapped array.\n */\nfunction arrayMap(array, iteratee) {\n var index = -1,\n length = array == null ? 0 : array.length,\n result = Array(length);\n\n while (++index < length) {\n result[index] = iteratee(array[index], index, array);\n }\n return result;\n}\n\nexport default arrayMap;\n","/**\n * The base implementation of `_.slice` without an iteratee call guard.\n *\n * @private\n * @param {Array} array The array to slice.\n * @param {number} [start=0] The start position.\n * @param {number} [end=array.length] The end position.\n * @returns {Array} Returns the slice of `array`.\n */\nfunction baseSlice(array, start, end) {\n var index = -1,\n length = array.length;\n\n if (start < 0) {\n start = -start > length ? 0 : (length + start);\n }\n end = end > length ? length : end;\n if (end < 0) {\n end += length;\n }\n length = start > end ? 0 : ((end - start) >>> 0);\n start >>>= 0;\n\n var result = Array(length);\n while (++index < length) {\n result[index] = array[index + start];\n }\n return result;\n}\n\nexport default baseSlice;\n","/**\n * The base implementation of `_.findIndex` and `_.findLastIndex` without\n * support for iteratee shorthands.\n *\n * @private\n * @param {Array} array The array to inspect.\n * @param {Function} predicate The function invoked per iteration.\n * @param {number} fromIndex The index to search from.\n * @param {boolean} [fromRight] Specify iterating from right to left.\n * @returns {number} Returns the index of the matched value, else `-1`.\n */\nfunction baseFindIndex(array, predicate, fromIndex, fromRight) {\n var length = array.length,\n index = fromIndex + (fromRight ? 1 : -1);\n\n while ((fromRight ? index-- : ++index < length)) {\n if (predicate(array[index], index, array)) {\n return index;\n }\n }\n return -1;\n}\n\nexport default baseFindIndex;\n","/**\n * The base implementation of `_.isNaN` without support for number objects.\n *\n * @private\n * @param {*} value The value to check.\n * @returns {boolean} Returns `true` if `value` is `NaN`, else `false`.\n */\nfunction baseIsNaN(value) {\n return value !== value;\n}\n\nexport default baseIsNaN;\n","/**\n * A specialized version of `_.indexOf` which performs strict equality\n * comparisons of values, i.e. `===`.\n *\n * @private\n * @param {Array} array The array to inspect.\n * @param {*} value The value to search for.\n * @param {number} fromIndex The index to search from.\n * @returns {number} Returns the index of the matched value, else `-1`.\n */\nfunction strictIndexOf(array, value, fromIndex) {\n var index = fromIndex - 1,\n length = array.length;\n\n while (++index < length) {\n if (array[index] === value) {\n return index;\n }\n }\n return -1;\n}\n\nexport default strictIndexOf;\n","/**\n * Converts an ASCII `string` to an array.\n *\n * @private\n * @param {string} string The string to convert.\n * @returns {Array} Returns the converted array.\n */\nfunction asciiToArray(string) {\n return string.split('');\n}\n\nexport default asciiToArray;\n","/** Used to compose unicode character classes. */\nvar rsAstralRange = '\\\\ud800-\\\\udfff',\n rsComboMarksRange = '\\\\u0300-\\\\u036f',\n reComboHalfMarksRange = '\\\\ufe20-\\\\ufe2f',\n rsComboSymbolsRange = '\\\\u20d0-\\\\u20ff',\n rsComboRange = rsComboMarksRange + reComboHalfMarksRange + rsComboSymbolsRange,\n rsVarRange = '\\\\ufe0e\\\\ufe0f';\n\n/** Used to compose unicode capture groups. */\nvar rsZWJ = '\\\\u200d';\n\n/** Used to detect strings with [zero-width joiners or code points from the astral planes](http://eev.ee/blog/2015/09/12/dark-corners-of-unicode/). */\nvar reHasUnicode = RegExp('[' + rsZWJ + rsAstralRange + rsComboRange + rsVarRange + ']');\n\n/**\n * Checks if `string` contains Unicode symbols.\n *\n * @private\n * @param {string} string The string to inspect.\n * @returns {boolean} Returns `true` if a symbol is found, else `false`.\n */\nfunction hasUnicode(string) {\n return reHasUnicode.test(string);\n}\n\nexport default hasUnicode;\n","/** Used to compose unicode character classes. */\nvar rsAstralRange = '\\\\ud800-\\\\udfff',\n rsComboMarksRange = '\\\\u0300-\\\\u036f',\n reComboHalfMarksRange = '\\\\ufe20-\\\\ufe2f',\n rsComboSymbolsRange = '\\\\u20d0-\\\\u20ff',\n rsComboRange = rsComboMarksRange + reComboHalfMarksRange + rsComboSymbolsRange,\n rsVarRange = '\\\\ufe0e\\\\ufe0f';\n\n/** Used to compose unicode capture groups. */\nvar rsAstral = '[' + rsAstralRange + ']',\n rsCombo = '[' + rsComboRange + ']',\n rsFitz = '\\\\ud83c[\\\\udffb-\\\\udfff]',\n rsModifier = '(?:' + rsCombo + '|' + rsFitz + ')',\n rsNonAstral = '[^' + rsAstralRange + ']',\n rsRegional = '(?:\\\\ud83c[\\\\udde6-\\\\uddff]){2}',\n rsSurrPair = '[\\\\ud800-\\\\udbff][\\\\udc00-\\\\udfff]',\n rsZWJ = '\\\\u200d';\n\n/** Used to compose unicode regexes. */\nvar reOptMod = rsModifier + '?',\n rsOptVar = '[' + rsVarRange + ']?',\n rsOptJoin = '(?:' + rsZWJ + '(?:' + [rsNonAstral, rsRegional, rsSurrPair].join('|') + ')' + rsOptVar + reOptMod + ')*',\n rsSeq = rsOptVar + reOptMod + rsOptJoin,\n rsSymbol = '(?:' + [rsNonAstral + rsCombo + '?', rsCombo, rsRegional, rsSurrPair, rsAstral].join('|') + ')';\n\n/** Used to match [string symbols](https://mathiasbynens.be/notes/javascript-unicode). */\nvar reUnicode = RegExp(rsFitz + '(?=' + rsFitz + ')|' + rsSymbol + rsSeq, 'g');\n\n/**\n * Converts a Unicode `string` to an array.\n *\n * @private\n * @param {string} string The string to convert.\n * @returns {Array} Returns the converted array.\n */\nfunction unicodeToArray(string) {\n return string.match(reUnicode) || [];\n}\n\nexport default unicodeToArray;\n","// bunch of generic helpers\n\nimport isArray from 'lodash-es/isArray'\nimport isPlainObject from 'lodash-es/isPlainObject'\nimport trim from 'lodash-es/trim'\n\n/**\n * DIY in Array\n * @param {array} arr to check from\n * @param {*} value to check against\n * @return {boolean} true on found\n */\nexport const inArray = (arr, value) => !!arr.filter(a => a === value).length\n\n// quick and dirty to turn non array to array\nexport const toArray = (arg) => isArray(arg) ? arg : [arg]\n\n/**\n * parse string to json or just return the original value if error happened\n * @param {*} n input\n * @param {boolean} [t=true] or throw\n * @return {*} json object on success\n */\nexport const parseJson = function(n, t=true) {\n try {\n return JSON.parse(n)\n } catch(e) {\n if (t) {\n return n\n }\n throw new Error(e)\n }\n}\n\n/**\n * @param {object} obj for search\n * @param {string} key target\n * @return {boolean} true on success\n */\nexport const isObjectHasKey = function(obj, key) {\n try {\n const keys = Object.keys(obj)\n return inArray(keys, key)\n } catch(e) {\n // @BUG when the obj is not an OBJECT we got some weird output\n return false\n }\n}\n\n/**\n * create a event name\n * @param {string[]} args\n * @return {string} event name for use\n */\nexport const createEvt = (...args) => args.join('_')\n\n/**\n * simple util method to get the value\n * @param {string} name of the key\n * @param {object} obj to take value from\n * @return {*} the object value id by name or undefined\n */\nexport const getConfigValue = (name, obj) => (\n obj && isPlainObject(obj) ? ( (name in obj) ? obj[name] : undefined ) : undefined\n)\n\n/**\n * small util to make sure the return value is valid JSON object\n * @param {*} n input\n * @return {object} correct JSON object\n */\nexport const toJson = n => {\n if (typeof n === 'string') {\n return parseJson(n)\n }\n return parseJson(JSON.stringify(n))\n}\n\n/**\n * Check several parameter that there is something in the param\n * @param {*} param input\n * @return {boolean}\n */\nexport const isNotEmpty = function(param) {\n return param !== undefined && param !== false && param !== null && trim(param) !== ''\n}\n\n/**\n * Simple check if the prop is function\n * @param {*} prop input\n * @return {boolean} true on success\n */\nexport const isFunc = prop => {\n if (typeof prop === 'function') {\n return true;\n }\n console.error(`Expect to be Function type! Got ${typeof prop}`)\n}\n\n/**\n * Shorthand method for Object.assign \n * @param {array} args \n * @return {object} merge together object by key \n */\nexport const assign = (...args) => Reflect.apply(Object.assign, Object, args)\n \n/** \n * generic placeholder function\n * @return {boolean} false \n */\nexport const nil = () => false\n\n/**\n * generic turn config into immutatble \n */\nexport const freeze = config => Object.freeze(config)","/**\n * Removes all key-value entries from the list cache.\n *\n * @private\n * @name clear\n * @memberOf ListCache\n */\nfunction listCacheClear() {\n this.__data__ = [];\n this.size = 0;\n}\n\nexport default listCacheClear;\n","/**\n * Performs a\n * [`SameValueZero`](http://ecma-international.org/ecma-262/7.0/#sec-samevaluezero)\n * comparison between two values to determine if they are equivalent.\n *\n * @static\n * @memberOf _\n * @since 4.0.0\n * @category Lang\n * @param {*} value The value to compare.\n * @param {*} other The other value to compare.\n * @returns {boolean} Returns `true` if the values are equivalent, else `false`.\n * @example\n *\n * var object = { 'a': 1 };\n * var other = { 'a': 1 };\n *\n * _.eq(object, object);\n * // => true\n *\n * _.eq(object, other);\n * // => false\n *\n * _.eq('a', 'a');\n * // => true\n *\n * _.eq('a', Object('a'));\n * // => false\n *\n * _.eq(NaN, NaN);\n * // => true\n */\nfunction eq(value, other) {\n return value === other || (value !== value && other !== other);\n}\n\nexport default eq;\n","/**\n * Removes `key` and its value from the stack.\n *\n * @private\n * @name delete\n * @memberOf Stack\n * @param {string} key The key of the value to remove.\n * @returns {boolean} Returns `true` if the entry was removed, else `false`.\n */\nfunction stackDelete(key) {\n var data = this.__data__,\n result = data['delete'](key);\n\n this.size = data.size;\n return result;\n}\n\nexport default stackDelete;\n","/**\n * Gets the stack value for `key`.\n *\n * @private\n * @name get\n * @memberOf Stack\n * @param {string} key The key of the value to get.\n * @returns {*} Returns the entry value.\n */\nfunction stackGet(key) {\n return this.__data__.get(key);\n}\n\nexport default stackGet;\n","/**\n * Checks if a stack value for `key` exists.\n *\n * @private\n * @name has\n * @memberOf Stack\n * @param {string} key The key of the entry to check.\n * @returns {boolean} Returns `true` if an entry for `key` exists, else `false`.\n */\nfunction stackHas(key) {\n return this.__data__.has(key);\n}\n\nexport default stackHas;\n","/**\n * Checks if `value` is the\n * [language type](http://www.ecma-international.org/ecma-262/7.0/#sec-ecmascript-language-types)\n * of `Object`. (e.g. arrays, functions, objects, regexes, `new Number(0)`, and `new String('')`)\n *\n * @static\n * @memberOf _\n * @since 0.1.0\n * @category Lang\n * @param {*} value The value to check.\n * @returns {boolean} Returns `true` if `value` is an object, else `false`.\n * @example\n *\n * _.isObject({});\n * // => true\n *\n * _.isObject([1, 2, 3]);\n * // => true\n *\n * _.isObject(_.noop);\n * // => true\n *\n * _.isObject(null);\n * // => false\n */\nfunction isObject(value) {\n var type = typeof value;\n return value != null && (type == 'object' || type == 'function');\n}\n\nexport default isObject;\n","/** Used for built-in method references. */\nvar funcProto = Function.prototype;\n\n/** Used to resolve the decompiled source of functions. */\nvar funcToString = funcProto.toString;\n\n/**\n * Converts `func` to its source code.\n *\n * @private\n * @param {Function} func The function to convert.\n * @returns {string} Returns the source code.\n */\nfunction toSource(func) {\n if (func != null) {\n try {\n return funcToString.call(func);\n } catch (e) {}\n try {\n return (func + '');\n } catch (e) {}\n }\n return '';\n}\n\nexport default toSource;\n","/**\n * Gets the value at `key` of `object`.\n *\n * @private\n * @param {Object} [object] The object to query.\n * @param {string} key The key of the property to get.\n * @returns {*} Returns the property value.\n */\nfunction getValue(object, key) {\n return object == null ? undefined : object[key];\n}\n\nexport default getValue;\n","/**\n * Removes `key` and its value from the hash.\n *\n * @private\n * @name delete\n * @memberOf Hash\n * @param {Object} hash The hash to modify.\n * @param {string} key The key of the value to remove.\n * @returns {boolean} Returns `true` if the entry was removed, else `false`.\n */\nfunction hashDelete(key) {\n var result = this.has(key) && delete this.__data__[key];\n this.size -= result ? 1 : 0;\n return result;\n}\n\nexport default hashDelete;\n","/**\n * Checks if `value` is suitable for use as unique object key.\n *\n * @private\n * @param {*} value The value to check.\n * @returns {boolean} Returns `true` if `value` is suitable, else `false`.\n */\nfunction isKeyable(value) {\n var type = typeof value;\n return (type == 'string' || type == 'number' || type == 'symbol' || type == 'boolean')\n ? (value !== '__proto__')\n : (value === null);\n}\n\nexport default isKeyable;\n","/**\n * Creates a base function for methods like `_.forIn` and `_.forOwn`.\n *\n * @private\n * @param {boolean} [fromRight] Specify iterating from right to left.\n * @returns {Function} Returns the new base function.\n */\nfunction createBaseFor(fromRight) {\n return function(object, iteratee, keysFunc) {\n var index = -1,\n iterable = Object(object),\n props = keysFunc(object),\n length = props.length;\n\n while (length--) {\n var key = props[fromRight ? length : ++index];\n if (iteratee(iterable[key], key, iterable) === false) {\n break;\n }\n }\n return object;\n };\n}\n\nexport default createBaseFor;\n","/**\n * Copies the values of `source` to `array`.\n *\n * @private\n * @param {Array} source The array to copy values from.\n * @param {Array} [array=[]] The array to copy values to.\n * @returns {Array} Returns `array`.\n */\nfunction copyArray(source, array) {\n var index = -1,\n length = source.length;\n\n array || (array = Array(length));\n while (++index < length) {\n array[index] = source[index];\n }\n return array;\n}\n\nexport default copyArray;\n","/** Used for built-in method references. */\nvar objectProto = Object.prototype;\n\n/**\n * Checks if `value` is likely a prototype object.\n *\n * @private\n * @param {*} value The value to check.\n * @returns {boolean} Returns `true` if `value` is a prototype, else `false`.\n */\nfunction isPrototype(value) {\n var Ctor = value && value.constructor,\n proto = (typeof Ctor == 'function' && Ctor.prototype) || objectProto;\n\n return value === proto;\n}\n\nexport default isPrototype;\n","/** Used as references for various `Number` constants. */\nvar MAX_SAFE_INTEGER = 9007199254740991;\n\n/**\n * Checks if `value` is a valid array-like length.\n *\n * **Note:** This method is loosely based on\n * [`ToLength`](http://ecma-international.org/ecma-262/7.0/#sec-tolength).\n *\n * @static\n * @memberOf _\n * @since 4.0.0\n * @category Lang\n * @param {*} value The value to check.\n * @returns {boolean} Returns `true` if `value` is a valid length, else `false`.\n * @example\n *\n * _.isLength(3);\n * // => true\n *\n * _.isLength(Number.MIN_VALUE);\n * // => false\n *\n * _.isLength(Infinity);\n * // => false\n *\n * _.isLength('3');\n * // => false\n */\nfunction isLength(value) {\n return typeof value == 'number' &&\n value > -1 && value % 1 == 0 && value <= MAX_SAFE_INTEGER;\n}\n\nexport default isLength;\n","/**\n * This method returns `false`.\n *\n * @static\n * @memberOf _\n * @since 4.13.0\n * @category Util\n * @returns {boolean} Returns `false`.\n * @example\n *\n * _.times(2, _.stubFalse);\n * // => [false, false]\n */\nfunction stubFalse() {\n return false;\n}\n\nexport default stubFalse;\n","/**\n * The base implementation of `_.unary` without support for storing metadata.\n *\n * @private\n * @param {Function} func The function to cap arguments for.\n * @returns {Function} Returns the new capped function.\n */\nfunction baseUnary(func) {\n return function(value) {\n return func(value);\n };\n}\n\nexport default baseUnary;\n","/**\n * Gets the value at `key`, unless `key` is \"__proto__\" or \"constructor\".\n *\n * @private\n * @param {Object} object The object to query.\n * @param {string} key The key of the property to get.\n * @returns {*} Returns the property value.\n */\nfunction safeGet(object, key) {\n if (key === 'constructor' && typeof object[key] === 'function') {\n return;\n }\n\n if (key == '__proto__') {\n return;\n }\n\n return object[key];\n}\n\nexport default safeGet;\n","/**\n * The base implementation of `_.times` without support for iteratee shorthands\n * or max array length checks.\n *\n * @private\n * @param {number} n The number of times to invoke `iteratee`.\n * @param {Function} iteratee The function invoked per iteration.\n * @returns {Array} Returns the array of results.\n */\nfunction baseTimes(n, iteratee) {\n var index = -1,\n result = Array(n);\n\n while (++index < n) {\n result[index] = iteratee(index);\n }\n return result;\n}\n\nexport default baseTimes;\n","/** Used as references for various `Number` constants. */\nvar MAX_SAFE_INTEGER = 9007199254740991;\n\n/** Used to detect unsigned integer values. */\nvar reIsUint = /^(?:0|[1-9]\\d*)$/;\n\n/**\n * Checks if `value` is a valid array-like index.\n *\n * @private\n * @param {*} value The value to check.\n * @param {number} [length=MAX_SAFE_INTEGER] The upper bounds of a valid index.\n * @returns {boolean} Returns `true` if `value` is a valid index, else `false`.\n */\nfunction isIndex(value, length) {\n var type = typeof value;\n length = length == null ? MAX_SAFE_INTEGER : length;\n\n return !!length &&\n (type == 'number' ||\n (type != 'symbol' && reIsUint.test(value))) &&\n (value > -1 && value % 1 == 0 && value < length);\n}\n\nexport default isIndex;\n","/**\n * This function is like\n * [`Object.keys`](http://ecma-international.org/ecma-262/7.0/#sec-object.keys)\n * except that it includes inherited enumerable properties.\n *\n * @private\n * @param {Object} object The object to query.\n * @returns {Array} Returns the array of property names.\n */\nfunction nativeKeysIn(object) {\n var result = [];\n if (object != null) {\n for (var key in Object(object)) {\n result.push(key);\n }\n }\n return result;\n}\n\nexport default nativeKeysIn;\n","/**\n * This method returns the first argument it receives.\n *\n * @static\n * @since 0.1.0\n * @memberOf _\n * @category Util\n * @param {*} value Any value.\n * @returns {*} Returns `value`.\n * @example\n *\n * var object = { 'a': 1 };\n *\n * console.log(_.identity(object) === object);\n * // => true\n */\nfunction identity(value) {\n return value;\n}\n\nexport default identity;\n","/**\n * A faster alternative to `Function#apply`, this function invokes `func`\n * with the `this` binding of `thisArg` and the arguments of `args`.\n *\n * @private\n * @param {Function} func The function to invoke.\n * @param {*} thisArg The `this` binding of `func`.\n * @param {Array} args The arguments to invoke `func` with.\n * @returns {*} Returns the result of `func`.\n */\nfunction apply(func, thisArg, args) {\n switch (args.length) {\n case 0: return func.call(thisArg);\n case 1: return func.call(thisArg, args[0]);\n case 2: return func.call(thisArg, args[0], args[1]);\n case 3: return func.call(thisArg, args[0], args[1], args[2]);\n }\n return func.apply(thisArg, args);\n}\n\nexport default apply;\n","/**\n * Creates a function that returns `value`.\n *\n * @static\n * @memberOf _\n * @since 2.4.0\n * @category Util\n * @param {*} value The value to return from the new function.\n * @returns {Function} Returns the new constant function.\n * @example\n *\n * var objects = _.times(2, _.constant({ 'a': 1 }));\n *\n * console.log(objects);\n * // => [{ 'a': 1 }, { 'a': 1 }]\n *\n * console.log(objects[0] === objects[1]);\n * // => true\n */\nfunction constant(value) {\n return function() {\n return value;\n };\n}\n\nexport default constant;\n","/** Used to detect hot functions by number of calls within a span of milliseconds. */\nvar HOT_COUNT = 800,\n HOT_SPAN = 16;\n\n/* Built-in method references for those with the same name as other `lodash` methods. */\nvar nativeNow = Date.now;\n\n/**\n * Creates a function that'll short out and invoke `identity` instead\n * of `func` when it's called `HOT_COUNT` or more times in `HOT_SPAN`\n * milliseconds.\n *\n * @private\n * @param {Function} func The function to restrict.\n * @returns {Function} Returns the new shortable function.\n */\nfunction shortOut(func) {\n var count = 0,\n lastCalled = 0;\n\n return function() {\n var stamp = nativeNow(),\n remaining = HOT_SPAN - (stamp - lastCalled);\n\n lastCalled = stamp;\n if (remaining > 0) {\n if (++count >= HOT_COUNT) {\n return arguments[0];\n }\n } else {\n count = 0;\n }\n return func.apply(undefined, arguments);\n };\n}\n\nexport default shortOut;\n","// this get throw from within the checkOptions when run through the enum failed\nexport default class JsonqlEnumError extends Error {\n constructor(...args) {\n super(...args)\n\n this.message = args[0]\n this.detail = args[1]\n\n this.className = JsonqlEnumError.name;\n\n if (Error.captureStackTrace) {\n Error.captureStackTrace(this, JsonqlEnumError)\n }\n }\n\n static get name() {\n return 'JsonqlEnumError'\n }\n}\n","// this will throw from inside the checkOptions\nexport default class JsonqlTypeError extends Error {\n constructor(...args) {\n super(...args)\n\n this.message = args[0]\n this.detail = args[1]\n\n this.className = JsonqlTypeError.name\n\n if (Error.captureStackTrace) {\n Error.captureStackTrace(this, JsonqlTypeError)\n }\n }\n\n static get name() {\n return 'JsonqlTypeError'\n }\n}\n","// allow supply a custom checker function\n// if that failed then we throw this error\nexport default class JsonqlCheckerError extends Error {\n constructor(...args) {\n super(...args)\n this.message = args[0]\n this.detail = args[1]\n\n this.className = JsonqlCheckerError.name;\n\n if (Error.captureStackTrace) {\n Error.captureStackTrace(this, JsonqlCheckerError)\n }\n }\n\n static get name() {\n return 'JsonqlCheckerError'\n }\n}\n","// custom validation error class\n// when validaton failed\nexport default class JsonqlValidationError extends Error {\n constructor(...args) {\n super(...args)\n\n this.message = args[0]\n this.detail = args[1]\n\n this.className = JsonqlValidationError.name;\n\n if (Error.captureStackTrace) {\n Error.captureStackTrace(this, JsonqlValidationError)\n }\n }\n\n static get name() {\n return 'JsonqlValidationError'\n }\n}\n","// split the contract into the node side and the generic side\nimport { isObjectHasKey } from './generic'\nimport isPlainObject from 'lodash-es/isPlainObject'\nimport {\n QUERY_NAME,\n MUTATION_NAME,\n SOCKET_NAME,\n QUERY_ARG_NAME,\n PAYLOAD_PARAM_NAME,\n CONDITION_PARAM_NAME\n} from 'jsonql-constants'\nimport { JsonqlError, JsonqlResolverNotFoundError } from 'jsonql-errors'\n/**\n * Check if the json is a contract file or not\n * @param {object} contract json object\n * @return {boolean} true\n */\nexport function checkIsContract(contract) {\n return isPlainObject(contract)\n && (\n isObjectHasKey(contract, QUERY_NAME)\n || isObjectHasKey(contract, MUTATION_NAME)\n || isObjectHasKey(contract, SOCKET_NAME)\n )\n}\n\n/**\n * Wrapper method that check if it's contract then return the contract or false\n * @param {object} contract the object to check\n * @return {boolean | object} false when it's not\n */\nexport function isContract(contract) {\n return checkIsContract(contract) ? contract : false\n}\n\n/**\n * Ported from jsonql-params-validator but different\n * if we don't find the socket part then return false\n * @param {object} contract the contract object\n * @return {object|boolean} false on failed\n */\nexport function extractSocketPart(contract) {\n if (isObjectHasKey(contract, SOCKET_NAME)) {\n return contract[SOCKET_NAME]\n }\n return false\n}\n\n/**\n * Extract the args from the payload\n * @param {object} payload to work with\n * @param {string} type of call\n * @return {array} args\n */\nexport function extractArgsFromPayload(payload, type) {\n switch (type) {\n case QUERY_NAME:\n return payload[QUERY_ARG_NAME]\n case MUTATION_NAME:\n return [\n payload[PAYLOAD_PARAM_NAME],\n payload[CONDITION_PARAM_NAME]\n ]\n default:\n throw new JsonqlError(`Unknown ${type} to extract argument from!`)\n }\n}\n\n/**\n * Like what the name said\n * @param {object} contract the contract json\n * @param {string} type query|mutation\n * @param {string} name of the function\n * @return {object} the params part of the contract\n */\nexport function extractParamsFromContract(contract, type, name) {\n try {\n const result = contract[type][name]\n // debug('extractParamsFromContract', result)\n if (!result) {\n // debug(name, type, contract)\n throw new JsonqlResolverNotFoundError(name, type)\n }\n return result\n } catch(e) {\n throw new JsonqlResolverNotFoundError(name, e)\n }\n}\n","/**\n * @param {boolean} sec return in second or not\n * @return {number} timestamp\n */\nexport const timestamp = (sec = false) => {\n let time = Date.now()\n return sec ? Math.floor( time / 1000 ) : time\n}\n","// ported from jsonql-params-validator\n// craete several helper function to construct / extract the payload\n// and make sure they are all the same\nimport {\n PAYLOAD_PARAM_NAME,\n CONDITION_PARAM_NAME,\n RESOLVER_PARAM_NAME,\n QUERY_ARG_NAME,\n TIMESTAMP_PARAM_NAME\n} from 'jsonql-constants'\n\nimport JsonqlValidationError from 'jsonql-errors/src/validation-error'\n\nimport isArray from 'lodash-es/isArray'\nimport isString from 'lodash-es/isString'\nimport isPlainObject from 'lodash-es/isPlainObject'\n\nimport { timestamp } from './timestamp'\nimport { parseJson } from './generic'\n\n/**\n * check if the payload has a timestamp field, then append a new timestamp to it\n * @param {object} payload from the com\n * @return {array} timestamp field with an array value\n */\nexport const handleTimestamp = payload => {\n let ts = payload[TIMESTAMP_PARAM_NAME]\n if (!isArray(ts)) {\n ts = [ts]\n }\n ts.push( timestamp() )\n\n return ts\n}\n\n/**\n * make sure it's an object (it was call formatPayload but it doesn't make sense)\n * @param {*} payload the object comes in could be string based\n * @return {object} the transformed payload\n */\nexport const toPayload = payload => isString(payload) ? parseJson(payload) : payload\n\n/**\n * @param {*} args arguments to send\n *@return {object} formatted payload\n */\nexport const formatPayload = (args) => (\n { [QUERY_ARG_NAME]: args }\n)\n\n/**\n * extract the resolver name from the payload \n * @param {object} payload\n * @return {string} resolver name \n */\nexport function getResolverFromPayload(payload) {\n const keys = Object.keys(payload)\n return keys.filter(key => key !== TIMESTAMP_PARAM_NAME)[0]\n}\n\n/**\n * wrapper method to add the timestamp as well\n * @param {string} resolverName\n * @param {*} payload\n * @return {object} delierable\n */\nexport function createDeliverable(resolverName, payload) {\n return {\n [resolverName]: payload,\n [TIMESTAMP_PARAM_NAME]: [ timestamp() ]\n }\n}\n\n/**\n * @param {string} resolverName name of function\n * @param {array} [args=[]] from the ...args\n * @param {boolean} [jsonp = false] add v1.3.0 to koa\n * @return {object} formatted argument\n */\nexport function createQuery(resolverName, args = [], jsonp = false) {\n if (isString(resolverName) && isArray(args)) {\n let payload = formatPayload(args)\n if (jsonp === true) {\n return payload\n }\n return createDeliverable(resolverName, payload)\n }\n throw new JsonqlValidationError(`[createQuery] expect resolverName to be string and args to be array!`, { resolverName, args })\n}\n\n/**\n * string version of the createQuery\n * @return {string}\n */\nexport function createQueryStr(resolverName, args = [], jsonp = false) {\n return JSON.stringify(createQuery(resolverName, args, jsonp))\n}\n\n/**\n * @param {string} resolverName name of function\n * @param {*} payload to send\n * @param {object} [condition={}] for what\n * @param {boolean} [jsonp = false] add v1.3.0 to koa\n * @return {object} formatted argument\n */\nexport function createMutation(resolverName, payload, condition = {}, jsonp = false) {\n const _payload = {\n [PAYLOAD_PARAM_NAME]: payload,\n [CONDITION_PARAM_NAME]: condition\n }\n if (jsonp === true) {\n return _payload\n }\n if (isString(resolverName)) {\n return createDeliverable(resolverName, _payload)\n }\n throw new JsonqlValidationError(`[createMutation] expect resolverName to be string!`, { resolverName, payload, condition })\n}\n\n/**\n * string version of createMutation\n * @return {string}\n */\nexport function createMutationStr(resolverName, payload, condition = {}, jsonp = false) {\n return JSON.stringify(createMutation(resolverName, payload, condition, jsonp))\n}\n\n/**\n * Extract the parts from payload and format for use\n * @param {string} resolverName name of fn\n * @param {object} payload the incoming json\n * @return {object|boolean} false on failed\n */\nexport function getQueryFromArgs(resolverName, payload) {\n if (resolverName && isPlainObject(payload)) {\n const args = payload[resolverName]\n if (args[QUERY_ARG_NAME]) {\n return {\n [RESOLVER_PARAM_NAME]: resolverName,\n [QUERY_ARG_NAME]: args[QUERY_ARG_NAME],\n [TIMESTAMP_PARAM_NAME]: handleTimestamp(payload)\n }\n }\n }\n return false\n}\n\n/**\n * Share function so no repeat\n * @param {object} payload the payload from client\n * @param {function} processor the last get result method\n * @return {*} result processed result\n */\nfunction processPayload(payload, processor) {\n const p = toPayload(payload)\n const resolverName = getResolverFromPayload(p)\n return Reflect.apply(processor, null, [resolverName, p])\n}\n\n/**\n * extra the payload back\n * @param {*} payload from http call\n * @return {object} resolverName and args\n */\nexport function getQueryFromPayload(payload) {\n const result = processPayload(payload, getQueryFromArgs)\n if (result !== false) {\n return result\n }\n throw new JsonqlValidationError('[getQueryArgs] Payload is malformed!', payload)\n}\n\n/**\n * Further break down from method below for use else where\n * @param {string} resolverName name of fn\n * @param {object} payload payload\n * @return {object|boolean} false on failed\n */\nexport function getMutationFromArgs(resolverName, payload) {\n if (resolverName && isPlainObject(payload)) {\n const args = payload[resolverName]\n if (args) {\n return {\n [RESOLVER_PARAM_NAME]: resolverName,\n [PAYLOAD_PARAM_NAME]: args[PAYLOAD_PARAM_NAME],\n [CONDITION_PARAM_NAME]: args[CONDITION_PARAM_NAME],\n [TIMESTAMP_PARAM_NAME]: handleTimestamp(payload)\n }\n }\n }\n return false\n}\n\n/**\n * @param {object} payload\n * @return {object} resolverName, payload, conditon\n */\nexport function getMutationFromPayload(payload) {\n const result = processPayload(payload, getMutationFromArgs)\n\n if (result !== false) {\n return result\n }\n throw new JsonqlValidationError('[getMutationArgs] Payload is malformed!', payload)\n}\n","// take out all the namespace related methods in one place for easy to find\nimport {\n JSONQL_PATH,\n PUBLIC_KEY,\n NSP_GROUP,\n PUBLIC_NAMESPACE\n} from 'jsonql-constants'\nimport { extractSocketPart } from './contract'\nconst SOCKET_NOT_FOUND_ERR = `socket not found in contract!`\nconst SIZE = 'size'\n\n/**\n * create the group using publicNamespace when there is only public\n * @param {object} socket from contract\n * @param {string} publicNamespace\n */\nfunction groupPublicNamespace(socket, publicNamespace) {\n let g = {}\n for (let resolverName in socket) {\n let params = socket[resolverName]\n g[resolverName] = params\n }\n return { size: 1, nspGroup: {[publicNamespace]: g}, publicNamespace}\n}\n\n\n/**\n * @BUG we should check the socket part instead of expect the downstream to read the menu!\n * We only need this when the enableAuth is true otherwise there is only one namespace\n * @param {object} contract the socket part of the contract file\n * @return {object} 1. remap the contract using the namespace --> resolvers\n * 2. the size of the object (1 all private, 2 mixed public with private)\n * 3. which namespace is public\n */\nexport function groupByNamespace(contract) {\n let socket = extractSocketPart(contract)\n if (socket === false) {\n throw new JsonqlError('groupByNamespace', SOCKET_NOT_FOUND_ERR)\n }\n let prop = {\n [NSP_GROUP]: {},\n [PUBLIC_NAMESPACE]: null,\n [SIZE]: 0 \n }\n\n for (let resolverName in socket) {\n let params = socket[resolverName]\n let { namespace } = params\n if (namespace) {\n if (!prop[NSP_GROUP][namespace]) {\n ++prop[SIZE]\n prop[NSP_GROUP][namespace] = {}\n }\n prop[NSP_GROUP][namespace][resolverName] = params\n // get the public namespace\n if (!prop[PUBLIC_NAMESPACE] && params[PUBLIC_KEY]) {\n prop[PUBLIC_NAMESPACE] = namespace\n }\n }\n }\n \n return prop \n}\n\n/**\n * @NOTE ported from jsonql-ws-client\n * Got to make sure the connection order otherwise\n * it will hang\n * @param {object} nspGroup contract\n * @param {string} publicNamespace like the name said\n * @return {array} namespaces in order\n */\nexport function getNamespaceInOrder(nspGroup, publicNamespace) {\n let names = [] // need to make sure the order!\n for (let namespace in nspGroup) {\n if (namespace === publicNamespace) {\n names[1] = namespace\n } else {\n names[0] = namespace\n }\n }\n return names\n}\n\n/**\n * @TODO this might change, what if we want to do room with ws\n * 1. there will only be max two namespace\n * 2. when it's normal we will have the stock path as namespace\n * 3. when enableAuth then we will have two, one is jsonql/public + private\n * @param {object} config options\n * @return {array} of namespace(s)\n */\nexport function getNamespace(config) {\n const base = JSONQL_PATH\n if (config.enableAuth) {\n // the public come first @1.0.1 we use the constants instead of the user supplied value\n // @1.0.4 we use the config value again, because we could control this via the post init\n return [\n [ base , config.privateNamespace ].join('/'),\n [ base , config.publicNamespace ].join('/')\n ]\n }\n return [ base ]\n}\n\n/**\n * get the private namespace\n * @param {array} namespaces array\n * @return {*} string on success\n */\nexport function getPrivateNamespace(namespaces) {\n return namespaces.length > 1 ? namespaces[0] : false\n}\n\n/**\n * Got a problem with a contract that is public only the groupByNamespace is wrong\n * which is actually not a problem when using a fallback, but to be sure things in order\n * we could combine with the config to group it\n * @param {object} config configuration\n * @return {object} nspInfo object\n */\nexport function getNspInfoByConfig(config) {\n const { contract, enableAuth } = config\n const namespaces = getNamespace(config)\n let nspInfo = enableAuth ? groupByNamespace(contract)\n : groupPublicNamespace(contract.socket, namespaces[0])\n // add the namespaces into it as well\n return Object.assign(nspInfo, { namespaces })\n}\n\n","// There are the socket related methods ported back from \n// ws-server-core and ws-client-core \nimport {\n WS_REPLY_TYPE,\n WS_EVT_NAME,\n WS_DATA_NAME,\n TIMESTAMP_PARAM_NAME,\n ERROR_KEY,\n EMIT_REPLY_TYPE,\n ACKNOWLEDGE_REPLY_TYPE\n} from 'jsonql-constants'\nimport { JsonqlError } from 'jsonql-errors' \nimport isString from 'lodash-es/isString'\n\nimport { toJson, isObjectHasKey, nil } from './generic'\nimport { timestamp } from './timestamp'\n\nconst PAYLOAD_NOT_DECODED_ERR = 'payload can not decoded'\nconst WS_KEYS = [\n WS_REPLY_TYPE,\n WS_EVT_NAME,\n WS_DATA_NAME\n]\n\n/////////////////////////////////////\n// REPLY FROM SERVER //\n/////////////////////////////////////\n\n\n/**\n * The ws doesn't have a acknowledge callback like socket.io\n * so we have to DIY one for ws and other that doesn't have it\n * @param {string} type of reply\n * @param {string} resolverName which is replying\n * @param {*} data payload\n * @param {array} [ts= []] the last received ts, if any \n * @return {string} stringify json\n */\nexport const createWsReply = (type, resolverName, data, ts = []) => {\n ts.push(timestamp())\n return JSON.stringify({\n data: {\n [WS_REPLY_TYPE]: type,\n [WS_EVT_NAME]: resolverName,\n [WS_DATA_NAME]: toJson(data)\n },\n [TIMESTAMP_PARAM_NAME]: ts \n })\n}\n\n// extended function \nexport const createReplyMsg = (resolverName, data, ts = []) => (\n createWsReply(EMIT_REPLY_TYPE, resolverName, data, ts)\n)\n\nexport const createAcknowledgeMsg = (resolverName, data, ts = []) => (\n createWsReply(ACKNOWLEDGE_REPLY_TYPE, resolverName, data, ts)\n)\n\n/**\n * @param {string|object} payload should be string when reply but could be transformed\n * @return {boolean} true is OK\n */\nexport const isWsReply = payload => {\n const json = isString(payload) ? toJson(payload) : payload\n const { data } = json\n if (data) {\n let result = WS_KEYS.filter(key => isObjectHasKey(data, key))\n return (result.length === WS_KEYS.length) ? data : false\n }\n return false\n}\n\n/**\n * @param {string|object} data received data\n * @param {function} [cb=nil] this is for extracting the TS field or when it's error\n * @return {object} false on failed\n */\nexport const extractWsPayload = (payload, cb = nil) => {\n try {\n const json = toJson(payload)\n // now handle the data\n let _data\n if ((_data = isWsReply(json)) !== false) {\n // note the ts property is on its own \n cb(TIMESTAMP_PARAM_NAME, json[TIMESTAMP_PARAM_NAME])\n \n return {\n data: toJson(_data[WS_DATA_NAME]),\n resolverName: _data[WS_EVT_NAME],\n type: _data[WS_REPLY_TYPE]\n }\n }\n throw new JsonqlError(PAYLOAD_NOT_DECODED_ERR, payload)\n } catch(e) {\n return cb(ERROR_KEY, e)\n }\n}\n","// this will be part of the init client sequence\n// as soon as we create a ws client\n// we listen to the on.connect event \n// then we send a init-ping event back to the server\n// and server issue a csrf token back to use \n// we use this token to create a new client and destroy the old one\nimport {\n INTERCOM_RESOLVER_NAME, \n SOCKET_PING_EVENT_NAME,\n HEADERS_KEY,\n DATA_KEY,\n CSRF_HEADER_KEY\n} from 'jsonql-constants'\nimport { \n createQueryStr, \n extractWsPayload,\n timestamp,\n toJson \n} from 'jsonql-utils/module'\nimport {\n JsonqlError\n} from 'jsonql-errors'\nconst CSRF_HEADER_NOT_EXIST_ERR = 'CSRF header is not in the received payload'\n\n/**\n * Util method \n * @param {string} payload return from server\n * @return {object} the useful bit \n */\nfunction extractSrvPayload(payload) {\n let json = toJson(payload)\n \n if (json && typeof json === 'object') {\n // note this method expect the json.data inside\n return extractWsPayload(json)\n }\n \n throw new JsonqlError('extractSrvPayload', json)\n}\n\n/**\n * call the server to get a csrf token \n * @return {string} formatted payload to send to the server \n */\nfunction createInitPing() {\n const ts = timestamp()\n\n return createQueryStr(INTERCOM_RESOLVER_NAME, [SOCKET_PING_EVENT_NAME, ts])\n}\n\n/**\n * Take the raw on.message result back then decoded it \n * @param {*} payload the raw result from server\n * @return {object} the csrf payload\n */\nfunction extractPingResult(payload) {\n const result = extractSrvPayload(payload)\n \n if (result && result[DATA_KEY] && result[DATA_KEY][CSRF_HEADER_KEY]) {\n return {\n [HEADERS_KEY]: result[DATA_KEY]\n }\n }\n\n throw new JsonqlError('extractPingResult', CSRF_HEADER_NOT_EXIST_ERR)\n}\n\n\n/**\n * Create a generic intercom method\n * @param {string} type the event type \n * @param {array} args if any \n * @return {string} formatted payload to send\n */\nfunction createIntercomPayload(type, ...args) {\n const ts = timestamp()\n let payload = [type].concat(args)\n payload.push(ts)\n return createQueryStr(INTERCOM_RESOLVER_NAME, payload)\n}\n\n\nexport { \n extractSrvPayload,\n createInitPing, \n extractPingResult, \n createIntercomPayload \n}","// validator numbers\n// import { NUMBER_TYPES } from './constants';\n\nimport isNaN from 'lodash-es/isNaN'\nimport isString from 'lodash-es/isString'\n/**\n * @2015-05-04 found a problem if the value is a number like string\n * it will pass, so add a chck if it's string before we pass to next\n * @param {number} value expected value\n * @return {boolean} true if OK\n */\nconst checkIsNumber = function(value) {\n return isString(value) ? false : !isNaN( parseFloat(value) )\n}\n\nexport default checkIsNumber\n","// validate string type\nimport trim from 'lodash-es/trim'\nimport isString from 'lodash-es/isString'\n/**\n * @param {string} value expected value\n * @return {boolean} true if OK\n */\nconst checkIsString = function(value) {\n return (trim(value) !== '') ? isString(value) : false\n}\n\nexport default checkIsString\n","// check for boolean\n\n/**\n * @param {boolean} value expected\n * @return {boolean} true if OK\n */\nconst checkIsBoolean = function(value) {\n return value !== null && value !== undefined && typeof value === 'boolean'\n}\n\nexport default checkIsBoolean\n","// validate any thing only check if there is something\n\nimport trim from 'lodash-es/trim'\n\n/**\n * @param {*} value the value\n * @param {boolean} [checkNull=true] strict check if there is null value\n * @return {boolean} true is OK\n */\nconst checkIsAny = function(value, checkNull = true) {\n if (value !== undefined && value !== '' && trim(value) !== '') {\n if (checkNull === false || (checkNull === true && value !== null)) {\n return true;\n }\n }\n return false;\n}\n\nexport default checkIsAny\n","// Good practice rule - No magic number\n\nconst ARGS_NOT_ARRAY_ERR = `args is not an array! You might want to do: ES6 Array.from(arguments) or ES5 Array.prototype.slice.call(arguments)`\nconst PARAMS_NOT_ARRAY_ERR = `params is not an array! Did something gone wrong when you generate the contract.json?`\nconst EXCEPTION_CASE_ERR = 'Could not understand your arguments and parameter structure!'\nconst UNUSUAL_CASE_ERR = 'This is an unusual situation where the arguments are more than the params, but not mark as spread'\n\nconst RETURNS_NAME = 'returns'\n\nimport {\n \n DEFAULT_TYPE, // this is a mistake should move back to the validation\n DATA_KEY, \n ERROR_KEY,\n\n TYPE_KEY,\n OPTIONAL_KEY,\n ENUM_KEY,\n ARGS_KEY,\n CHECKER_KEY,\n ALIAS_KEY,\n\n ARRAY_TYPE_LFT,\n ARRAY_TYPE_RGT,\n \n ARRAY_TYPE,\n OBJECT_TYPE,\n STRING_TYPE,\n BOOLEAN_TYPE,\n NUMBER_TYPE,\n KEY_WORD,\n OR_SEPERATOR\n} from 'jsonql-constants'\n\n// group all export in one \nexport {\n ARGS_NOT_ARRAY_ERR,\n PARAMS_NOT_ARRAY_ERR,\n EXCEPTION_CASE_ERR,\n UNUSUAL_CASE_ERR,\n DEFAULT_TYPE,\n ARRAY_TYPE_LFT,\n ARRAY_TYPE_RGT,\n TYPE_KEY,\n OPTIONAL_KEY,\n ENUM_KEY,\n ARGS_KEY,\n CHECKER_KEY,\n ALIAS_KEY,\n ARRAY_TYPE,\n OBJECT_TYPE,\n STRING_TYPE,\n BOOLEAN_TYPE,\n NUMBER_TYPE,\n KEY_WORD,\n OR_SEPERATOR,\n\n RETURNS_NAME,\n\n DATA_KEY, \n ERROR_KEY \n}","// primitive types\nimport checkIsNumber from './number'\nimport checkIsString from './string'\nimport checkIsBoolean from './boolean'\nimport checkIsAny from './any'\nimport { NUMBER_TYPE, STRING_TYPE, BOOLEAN_TYPE } from './constants'\n\n/**\n * this is a wrapper method to call different one based on their type\n * @param {string} type to check\n * @return {function} a function to handle the type\n */\nconst combineFn = function(type) {\n switch (type) {\n case NUMBER_TYPE:\n return checkIsNumber\n case STRING_TYPE:\n return checkIsString\n case BOOLEAN_TYPE:\n return checkIsBoolean\n default:\n return checkIsAny\n }\n}\n\nexport default combineFn\n","// validate array type\n\nimport isArray from 'lodash-es/isArray'\nimport trim from 'lodash-es/trim'\nimport combineFn from './combine'\nimport {\n ARRAY_TYPE_LFT,\n ARRAY_TYPE_RGT,\n OR_SEPERATOR\n} from './constants'\n\n/**\n * @param {array} value expected\n * @param {string} [type=''] pass the type if we encounter array. then we need to check the value as well\n * @return {boolean} true if OK\n */\nexport const checkIsArray = function(value, type='') {\n if (isArray(value)) {\n if (type === '' || trim(type)==='') {\n return true;\n }\n // we test it in reverse\n // @TODO if the type is an array (OR) then what?\n // we need to take into account this could be an array\n const c = value.filter(v => !combineFn(type)(v))\n return !(c.length > 0)\n }\n return false\n}\n\n/**\n * check if it matches the array. pattern\n * @param {string} type\n * @return {boolean|array} false means NO, always return array\n */\nexport const isArrayLike = function(type) {\n // @TODO could that have something like array<> instead of array.<>? missing the dot?\n // because type script is Array without the dot\n if (type.indexOf(ARRAY_TYPE_LFT) > -1 && type.indexOf(ARRAY_TYPE_RGT) > -1) {\n const _type = type.replace(ARRAY_TYPE_LFT, '').replace(ARRAY_TYPE_RGT, '')\n if (_type.indexOf(OR_SEPERATOR)) {\n return _type.split(OR_SEPERATOR)\n }\n return [_type]\n }\n return false\n}\n\n/**\n * we might encounter something like array. then we need to take it apart\n * @param {object} p the prepared object for processing\n * @param {string|array} type the type came from \n * @return {boolean} for the filter to operate on\n */\nexport const arrayTypeHandler = function(p, type) {\n const { arg } = p\n // need a special case to handle the OR type\n // we need to test the args instead of the type(s)\n if (type.length > 1) {\n return !arg.filter(v => (\n !(type.length > type.filter(t => !combineFn(t)(v)).length)\n )).length\n }\n // type is array so this will be or!\n return type.length > type.filter(t => !checkIsArray(arg, t)).length\n}\n","// validate object type\n\nimport isPlainObject from 'lodash-es/isPlainObject'\n// import filter from 'lodash-es/filter'\nimport combineFn from './combine'\nimport { checkIsArray, isArrayLike, arrayTypeHandler } from './array'\n/**\n * @TODO if provide with the keys then we need to check if the key:value type as well\n * @param {object} value expected\n * @param {array} [keys=null] if it has the keys array to compare as well\n * @return {boolean} true if OK\n */\nexport const checkIsObject = function(value, keys=null) {\n if (isPlainObject(value)) {\n if (!keys) {\n return true\n }\n if (checkIsArray(keys)) {\n // please note we DON'T care if some is optional\n // plese refer to the contract.json for the keys\n return !keys.filter(key => {\n let _value = value[key.name];\n return !(key.type.length > key.type.filter(type => {\n let tmp;\n if (_value !== undefined) {\n if ((tmp = isArrayLike(type)) !== false) {\n return !arrayTypeHandler({arg: _value}, tmp)\n // return tmp.filter(t => !checkIsArray(_value, t)).length;\n // @TODO there might be an object within an object with keys as well :S\n }\n return !combineFn(type)(_value)\n }\n return true\n }).length)\n }).length;\n }\n }\n return false\n}\n\n/**\n * fold this into it's own function to handler different object type\n * @param {object} p the prepared object for process\n * @return {boolean}\n */\nexport const objectTypeHandler = function(p) {\n const { arg, param } = p\n let _args = [arg]\n if (Array.isArray(param.keys) && param.keys.length) {\n _args.push(param.keys)\n }\n // just simple check\n return Reflect.apply(checkIsObject, null, _args)\n}\n","// move the index.js code here that make more sense to find where things are\n\nimport {\n checkIsArray,\n isArrayLike,\n arrayTypeHandler,\n objectTypeHandler,\n combineFn,\n notEmpty\n} from './index'\n\nimport {\n DEFAULT_TYPE,\n ARRAY_TYPE,\n OBJECT_TYPE,\n ARGS_NOT_ARRAY_ERR,\n PARAMS_NOT_ARRAY_ERR,\n EXCEPTION_CASE_ERR,\n DATA_KEY, \n ERROR_KEY \n} from './constants'\n\n\nimport JsonqlValidationError from 'jsonql-errors/src/validation-error'\nimport JsonqlError from 'jsonql-errors/src/error'\n// import debug from 'debug'\n// const debugFn = debug('jsonql-params-validator:validator')\n// also export this for use in other places\n\n/**\n * We need to handle those optional parameter without a default value\n * @param {object} params from contract.json\n * @return {boolean} for filter operation false is actually OK\n */\nconst optionalHandler = function( params ) {\n const { arg, param } = params\n if (notEmpty(arg)) {\n // debug('call optional handler', arg, params);\n // loop through the type in param\n return !(param.type.length > param.type.filter(type =>\n validateHandler(type, params)\n ).length)\n }\n return false\n}\n\n/**\n * actually picking the validator\n * @param {*} type for checking\n * @param {*} value for checking\n * @return {boolean} true on OK\n */\nconst validateHandler = function(type, value) {\n let tmp;\n switch (true) {\n case type === OBJECT_TYPE:\n // debugFn('call OBJECT_TYPE')\n return !objectTypeHandler(value)\n case type === ARRAY_TYPE:\n // debugFn('call ARRAY_TYPE')\n return !checkIsArray(value.arg)\n // @TODO when the type is not present, it always fall through here\n // so we need to find a way to actually pre-check the type first\n // AKA check the contract.json map before running here\n case (tmp = isArrayLike(type)) !== false:\n // debugFn('call ARRAY_LIKE: %O', value)\n return !arrayTypeHandler(value, tmp)\n default:\n return !combineFn(type)(value.arg)\n }\n}\n\n/**\n * it get too longer to fit in one line so break it out from the fn below\n * @param {*} arg value\n * @param {object} param config\n * @return {*} value or apply default value\n */\nconst getOptionalValue = function(arg, param) {\n if (arg !== undefined) {\n return arg\n }\n return (param.optional === true && param.defaultvalue !== undefined ? param.defaultvalue : null)\n}\n\n/**\n * padding the arguments with defaultValue if the arguments did not provide the value\n * this will be the name export\n * @param {array} args normalized arguments\n * @param {array} params from contract.json\n * @return {array} merge the two together\n */\nexport const normalizeArgs = function(args, params) {\n // first we should check if this call require a validation at all\n // there will be situation where the function doesn't need args and params\n if (!checkIsArray(params)) {\n // debugFn('params value', params)\n throw new JsonqlValidationError(PARAMS_NOT_ARRAY_ERR)\n }\n if (params.length === 0) {\n return []\n }\n if (!checkIsArray(args)) {\n throw new JsonqlValidationError(ARGS_NOT_ARRAY_ERR)\n }\n // debugFn(args, params);\n // fall through switch\n switch(true) {\n case args.length == params.length: // standard\n return args.map((arg, i) => (\n {\n arg,\n index: i,\n param: params[i]\n }\n ))\n case params[0].variable === true: // using spread syntax\n const type = params[0].type;\n return args.map((arg, i) => (\n {\n arg,\n index: i, // keep the index for reference\n param: params[i] || { type, name: '_' }\n }\n ))\n // with optional defaultValue parameters\n case args.length < params.length:\n return params.map((param, i) => (\n {\n param,\n index: i,\n arg: getOptionalValue(args[i], param),\n optional: param.optional || false\n }\n ))\n // this one pass more than it should have anything after the args.length will be cast as any type\n case args.length > params.length:\n let ctn = params.length;\n // this happens when we have those array. type\n let _type = [ DEFAULT_TYPE ]\n // we only looking at the first one, this might be a @BUG\n /*\n if ((tmp = isArrayLike(params[0].type[0])) !== false) {\n _type = tmp;\n } */\n // if we use the params as guide then the rest will get throw out\n // which is not what we want, instead, anything without the param\n // will get a any type and optional flag\n return args.map((arg, i) => {\n let optional = i >= ctn ? true : !!params[i].optional\n let param = params[i] || { type: _type, name: `_${i}` }\n return {\n arg: optional ? getOptionalValue(arg, param) : arg,\n index: i,\n param,\n optional\n }\n })\n // @TODO find out if there is more cases not cover\n default: // this should never happen\n // debugFn('args', args)\n // debugFn('params', params)\n // this is unknown therefore we just throw it!\n throw new JsonqlError(EXCEPTION_CASE_ERR, { args, params })\n }\n}\n\n// what we want is after the validaton we also get the normalized result\n// which is with the optional property if the argument didn't provide it\n/**\n * process the array of params back to their arguments\n * @param {array} result the params result\n * @return {array} arguments\n */\nconst processReturn = result => result.map(r => r.arg)\n\n/**\n * validator main interface\n * @param {array} args the arguments pass to the method call\n * @param {array} params from the contract for that method\n * @param {boolean} [withResul=false] if true then this will return the normalize result as well\n * @return {array} empty array on success, or failed parameter and reasons\n */\nexport const validateSync = function(args, params, withResult = false) {\n let cleanArgs = normalizeArgs(args, params)\n let checkResult = cleanArgs.filter(p => {\n // v1.4.4 this fixed the problem, the root level optional is from the last fn\n if (p.optional === true || p.param.optional === true) {\n return optionalHandler(p)\n }\n // because array of types means OR so if one pass means pass\n return !(p.param.type.length > p.param.type.filter(\n type => validateHandler(type, p)\n ).length)\n })\n // using the same convention we been using all this time\n return !withResult ? checkResult : {\n [ERROR_KEY]: checkResult,\n [DATA_KEY]: processReturn(cleanArgs)\n }\n}\n\n/**\n * A wrapper method that return promise\n * @param {array} args arguments\n * @param {array} params from contract.json\n * @param {boolean} [withResul=false] if true then this will return the normalize result as well\n * @return {object} promise.then or catch\n */\nexport const validateAsync = function(args, params, withResult = false) {\n return new Promise((resolver, rejecter) => {\n const result = validateSync(args, params, withResult)\n if (withResult) {\n return result[ERROR_KEY].length ? rejecter(result[ERROR_KEY])\n : resolver(result[DATA_KEY])\n }\n // the different is just in the then or catch phrase\n return result.length ? rejecter(result) : resolver([])\n })\n}\n","/** Used to stand-in for `undefined` hash values. */\nvar HASH_UNDEFINED = '__lodash_hash_undefined__';\n\n/**\n * Adds `value` to the array cache.\n *\n * @private\n * @name add\n * @memberOf SetCache\n * @alias push\n * @param {*} value The value to cache.\n * @returns {Object} Returns the cache instance.\n */\nfunction setCacheAdd(value) {\n this.__data__.set(value, HASH_UNDEFINED);\n return this;\n}\n\nexport default setCacheAdd;\n","/**\n * Checks if `value` is in the array cache.\n *\n * @private\n * @name has\n * @memberOf SetCache\n * @param {*} value The value to search for.\n * @returns {number} Returns `true` if `value` is found, else `false`.\n */\nfunction setCacheHas(value) {\n return this.__data__.has(value);\n}\n\nexport default setCacheHas;\n","/**\n * A specialized version of `_.some` for arrays without support for iteratee\n * shorthands.\n *\n * @private\n * @param {Array} [array] The array to iterate over.\n * @param {Function} predicate The function invoked per iteration.\n * @returns {boolean} Returns `true` if any element passes the predicate check,\n * else `false`.\n */\nfunction arraySome(array, predicate) {\n var index = -1,\n length = array == null ? 0 : array.length;\n\n while (++index < length) {\n if (predicate(array[index], index, array)) {\n return true;\n }\n }\n return false;\n}\n\nexport default arraySome;\n","/**\n * Checks if a `cache` value for `key` exists.\n *\n * @private\n * @param {Object} cache The cache to query.\n * @param {string} key The key of the entry to check.\n * @returns {boolean} Returns `true` if an entry for `key` exists, else `false`.\n */\nfunction cacheHas(cache, key) {\n return cache.has(key);\n}\n\nexport default cacheHas;\n","/**\n * Converts `map` to its key-value pairs.\n *\n * @private\n * @param {Object} map The map to convert.\n * @returns {Array} Returns the key-value pairs.\n */\nfunction mapToArray(map) {\n var index = -1,\n result = Array(map.size);\n\n map.forEach(function(value, key) {\n result[++index] = [key, value];\n });\n return result;\n}\n\nexport default mapToArray;\n","/**\n * Converts `set` to an array of its values.\n *\n * @private\n * @param {Object} set The set to convert.\n * @returns {Array} Returns the values.\n */\nfunction setToArray(set) {\n var index = -1,\n result = Array(set.size);\n\n set.forEach(function(value) {\n result[++index] = value;\n });\n return result;\n}\n\nexport default setToArray;\n","/**\n * Appends the elements of `values` to `array`.\n *\n * @private\n * @param {Array} array The array to modify.\n * @param {Array} values The values to append.\n * @returns {Array} Returns `array`.\n */\nfunction arrayPush(array, values) {\n var index = -1,\n length = values.length,\n offset = array.length;\n\n while (++index < length) {\n array[offset + index] = values[index];\n }\n return array;\n}\n\nexport default arrayPush;\n","/**\n * A specialized version of `_.filter` for arrays without support for\n * iteratee shorthands.\n *\n * @private\n * @param {Array} [array] The array to iterate over.\n * @param {Function} predicate The function invoked per iteration.\n * @returns {Array} Returns the new filtered array.\n */\nfunction arrayFilter(array, predicate) {\n var index = -1,\n length = array == null ? 0 : array.length,\n resIndex = 0,\n result = [];\n\n while (++index < length) {\n var value = array[index];\n if (predicate(value, index, array)) {\n result[resIndex++] = value;\n }\n }\n return result;\n}\n\nexport default arrayFilter;\n","/**\n * This method returns a new empty array.\n *\n * @static\n * @memberOf _\n * @since 4.13.0\n * @category Util\n * @returns {Array} Returns the new empty array.\n * @example\n *\n * var arrays = _.times(2, _.stubArray);\n *\n * console.log(arrays);\n * // => [[], []]\n *\n * console.log(arrays[0] === arrays[1]);\n * // => false\n */\nfunction stubArray() {\n return [];\n}\n\nexport default stubArray;\n","/**\n * A specialized version of `matchesProperty` for source values suitable\n * for strict equality comparisons, i.e. `===`.\n *\n * @private\n * @param {string} key The key of the property to get.\n * @param {*} srcValue The value to match.\n * @returns {Function} Returns the new spec function.\n */\nfunction matchesStrictComparable(key, srcValue) {\n return function(object) {\n if (object == null) {\n return false;\n }\n return object[key] === srcValue &&\n (srcValue !== undefined || (key in Object(object)));\n };\n}\n\nexport default matchesStrictComparable;\n","/**\n * The base implementation of `_.hasIn` without support for deep paths.\n *\n * @private\n * @param {Object} [object] The object to query.\n * @param {Array|string} key The key to check.\n * @returns {boolean} Returns `true` if `key` exists, else `false`.\n */\nfunction baseHasIn(object, key) {\n return object != null && key in Object(object);\n}\n\nexport default baseHasIn;\n","/**\n * The base implementation of `_.property` without support for deep paths.\n *\n * @private\n * @param {string} key The key of the property to get.\n * @returns {Function} Returns the new accessor function.\n */\nfunction baseProperty(key) {\n return function(object) {\n return object == null ? undefined : object[key];\n };\n}\n\nexport default baseProperty;\n","/** Error message constants. */\nvar FUNC_ERROR_TEXT = 'Expected a function';\n\n/**\n * Creates a function that negates the result of the predicate `func`. The\n * `func` predicate is invoked with the `this` binding and arguments of the\n * created function.\n *\n * @static\n * @memberOf _\n * @since 3.0.0\n * @category Function\n * @param {Function} predicate The predicate to negate.\n * @returns {Function} Returns the new negated function.\n * @example\n *\n * function isEven(n) {\n * return n % 2 == 0;\n * }\n *\n * _.filter([1, 2, 3, 4, 5, 6], _.negate(isEven));\n * // => [1, 3, 5]\n */\nfunction negate(predicate) {\n if (typeof predicate != 'function') {\n throw new TypeError(FUNC_ERROR_TEXT);\n }\n return function() {\n var args = arguments;\n switch (args.length) {\n case 0: return !predicate.call(this);\n case 1: return !predicate.call(this, args[0]);\n case 2: return !predicate.call(this, args[0], args[1]);\n case 3: return !predicate.call(this, args[0], args[1], args[2]);\n }\n return !predicate.apply(this, args);\n };\n}\n\nexport default negate;\n","/**\n * The base implementation of methods like `_.findKey` and `_.findLastKey`,\n * without support for iteratee shorthands, which iterates over `collection`\n * using `eachFunc`.\n *\n * @private\n * @param {Array|Object} collection The collection to inspect.\n * @param {Function} predicate The function invoked per iteration.\n * @param {Function} eachFunc The function to iterate over `collection`.\n * @returns {*} Returns the found element or its key, else `undefined`.\n */\nfunction baseFindKey(collection, predicate, eachFunc) {\n var result;\n eachFunc(collection, function(value, key, collection) {\n if (predicate(value, key, collection)) {\n result = key;\n return false;\n }\n });\n return result;\n}\n\nexport default baseFindKey;\n","/**\n * @param {array} arr Array for check\n * @param {*} value target\n * @return {boolean} true on successs\n */\nconst isInArray = function(arr, value) {\n return !!arr.filter(a => a === value).length\n}\n\nexport default isInArray\n","// breaking the whole thing up to see what cause the multiple calls issue\n\nimport isFunction from 'lodash-es/isFunction'\nimport merge from 'lodash-es/merge'\nimport mapValues from 'lodash-es/mapValues'\n\nimport JsonqlEnumError from 'jsonql-errors/src/enum-error'\nimport JsonqlTypeError from 'jsonql-errors/src/type-error'\nimport JsonqlCheckerError from 'jsonql-errors/src/checker-error'\n\nimport {\n TYPE_KEY,\n OPTIONAL_KEY,\n ENUM_KEY,\n ARGS_KEY,\n CHECKER_KEY,\n KEY_WORD\n} from '../constants'\nimport { checkIsArray } from '../array'\n\n// import debug from 'debug';\n// const debugFn = debug('jsonql-params-validator:options:validation')\n\n/**\n * just make sure it returns an array to use\n * @param {*} arg input\n * @return {array} output\n */\nconst toArray = arg => checkIsArray(arg) ? arg : [arg]\n\n/**\n * DIY in array\n * @param {array} arr to check against\n * @param {*} value to check\n * @return {boolean} true on OK\n */\nconst inArray = (arr, value) => (\n !!arr.filter(v => v === value).length\n)\n\n/**\n * break out to make the code easier to read\n * @param {object} value to process\n * @param {function} cb the validateSync\n * @return {array} empty on success\n */\nfunction validateHandler(value, cb) {\n // cb is the validateSync methods\n let args = [\n [ value[ARGS_KEY] ],\n [{\n [TYPE_KEY]: toArray(value[TYPE_KEY]),\n [OPTIONAL_KEY]: value[OPTIONAL_KEY]\n }]\n ]\n // debugFn('validateHandler', args)\n return Reflect.apply(cb, null, args)\n}\n\n/**\n * Check against the enum value if it's provided\n * @param {*} value to check\n * @param {*} enumv to check against if it's not false\n * @return {boolean} true on OK\n */\nconst enumHandler = (value, enumv) => {\n if (checkIsArray(enumv)) {\n return inArray(enumv, value)\n }\n return true\n}\n\n/**\n * Allow passing a function to check the value\n * There might be a problem here if the function is incorrect\n * and that will makes it hard to debug what is going on inside\n * @TODO there could be a few feature add to this one under different circumstance\n * @param {*} value to check\n * @param {function} checker for checking\n */\nconst checkerHandler = (value, checker) => {\n try {\n return isFunction(checker) ? checker.apply(null, [value]) : false\n } catch (e) {\n return false\n }\n}\n\n/**\n * Taken out from the runValidaton this only validate the required values\n * @param {array} args from the config2argsAction\n * @param {function} cb validateSync\n * @return {array} of configuration values\n */\nfunction runValidationAction(cb) {\n return (value, key) => {\n // debugFn('runValidationAction', key, value)\n if (value[KEY_WORD]) {\n return value[ARGS_KEY]\n }\n const check = validateHandler(value, cb)\n if (check.length) {\n // log('runValidationAction', key, value)\n throw new JsonqlTypeError(key, check)\n }\n if (value[ENUM_KEY] !== false && !enumHandler(value[ARGS_KEY], value[ENUM_KEY])) {\n // log(ENUM_KEY, value[ENUM_KEY])\n throw new JsonqlEnumError(key)\n }\n if (value[CHECKER_KEY] !== false && !checkerHandler(value[ARGS_KEY], value[CHECKER_KEY])) {\n // log(CHECKER_KEY, value[CHECKER_KEY])\n throw new JsonqlCheckerError(key)\n }\n return value[ARGS_KEY]\n }\n}\n\n/**\n * @param {object} args from the config2argsAction\n * @param {function} cb validateSync\n * @return {object} of configuration values\n */\nexport default function runValidation(args, cb) {\n const [ argsForValidate, pristineValues ] = args\n // turn the thing into an array and see what happen here\n // debugFn('_args', argsForValidate)\n const result = mapValues(argsForValidate, runValidationAction(cb))\n return merge(result, pristineValues)\n}\n","/// this is port back from the client to share across all projects\n\nimport merge from 'lodash-es/merge'\nimport { prepareArgsForValidation } from './prepare-args-for-validation'\nimport runValidation from './run-validation'\n\n// import debug from 'debug'\n// const debugFn = debug('jsonql-params-validator:check-options-async')\n\n/**\n * Quick transform\n * @param {object} config that one\n * @param {object} appProps mutation configuration options\n * @return {object} put that arg into the args\n */\nconst configToArgs = (config, appProps) => {\n return Promise.resolve(\n prepareArgsForValidation(config, appProps)\n )\n}\n\n/**\n * @param {object} config user provide configuration option\n * @param {object} appProps mutation configuration options\n * @param {object} constProps the immutable configuration options\n * @param {function} cb the validateSync method\n * @return {object} Promise resolve merge config object\n */\nexport default function(config = {}, appProps, constProps, cb) {\n return configToArgs(config, appProps)\n .then(args1 => runValidation(args1, cb))\n // next if every thing good then pass to final merging\n .then(args2 => merge({}, args2, constProps))\n}\n","// create function to construct the config entry so we don't need to keep building object\n\nimport isFunction from 'lodash-es/isFunction'\nimport isString from 'lodash-es/isString'\nimport {\n ARGS_KEY,\n TYPE_KEY,\n CHECKER_KEY,\n ENUM_KEY,\n OPTIONAL_KEY,\n ALIAS_KEY\n} from 'jsonql-constants'\n\nimport { checkIsArray } from '../array'\n// import checkIsBoolean from '../boolean'\n// import debug from 'debug';\n// const debugFn = debug('jsonql-params-validator:construct-config');\n/**\n * @param {*} args value\n * @param {string} type for value\n * @param {boolean} [optional=false]\n * @param {boolean|array} [enumv=false]\n * @param {boolean|function} [checker=false]\n * @return {object} config entry\n */\nexport default function constructConfig(args, type, optional=false, enumv=false, checker=false, alias=false) {\n let base = {\n [ARGS_KEY]: args,\n [TYPE_KEY]: type\n }\n if (optional === true) {\n base[OPTIONAL_KEY] = true\n }\n if (checkIsArray(enumv)) {\n base[ENUM_KEY] = enumv\n }\n if (isFunction(checker)) {\n base[CHECKER_KEY] = checker\n }\n if (isString(alias)) {\n base[ALIAS_KEY] = alias\n }\n return base\n}\n","// export also create wrapper methods\nimport checkOptionsAsync from './check-options-async'\nimport checkOptionsSync from './check-options-sync'\nimport constructConfigFn from './construct-config'\nimport {\n ENUM_KEY,\n CHECKER_KEY,\n ALIAS_KEY,\n OPTIONAL_KEY\n} from 'jsonql-constants'\n\n/**\n * This has a different interface\n * @param {*} value to supply\n * @param {string|array} type for checking\n * @param {object} params to map against the config check\n * @param {array} params.enumv NOT enum\n * @param {boolean} params.optional false then nothing\n * @param {function} params.checker need more work on this one later\n * @param {string} params.alias mostly for cmd\n */\nconst createConfig = (value, type, params = {}) => {\n // Note the enumv not ENUM\n // const { enumv, optional, checker, alias } = params;\n // let args = [value, type, optional, enumv, checker, alias];\n const {\n [OPTIONAL_KEY]: o,\n [ENUM_KEY]: e,\n [CHECKER_KEY]: c,\n [ALIAS_KEY]: a\n } = params;\n return constructConfigFn.apply(null, [value, type, o, e, c, a])\n}\n\n// for testing purpose\nconst JSONQL_PARAMS_VALIDATOR_INFO = '__PLACEHOLDER__'\n\n/**\n * construct the actual end user method, rename with prefix get since 1.5.2\n * @param {function} validateSync validation method\n * @return {function} for performaning the actual valdiation\n */\nconst getCheckConfigAsync = function(validateSync) {\n /**\n * We recreate the method here to avoid the circlar import\n * @param {object} config user supply configuration\n * @param {object} appProps mutation options\n * @param {object} [constantProps={}] optional: immutation options\n * @return {object} all checked configuration\n */\n return function(config, appProps, constantProps= {}) {\n return checkOptionsAsync(config, appProps, constantProps, validateSync)\n }\n}\n\n/**\n * copy of above but it's sync, rename with prefix get since 1.5.2\n * @param {function} validateSync validation method\n * @return {function} for performaning the actual valdiation\n */\nconst getCheckConfig = function(validateSync) {\n return function(config, appProps, constantProps = {}) {\n return checkOptionsSync(config, appProps, constantProps, validateSync)\n }\n}\n\n// re-export\nexport {\n createConfig,\n constructConfigFn,\n getCheckConfigAsync,\n getCheckConfig,\n JSONQL_PARAMS_VALIDATOR_INFO\n}\n","// export\nimport {\n checkIsObject,\n notEmpty,\n checkIsAny,\n checkIsString,\n checkIsBoolean,\n checkIsNumber,\n checkIsArray\n} from './src'\nimport * as validator from './src/validator'\n// configuration checking\nimport * as jsonqlOptions from './src/options'\n// the two extra functions\nimport isInArray from './src/is-in-array'\nimport isObjectHasKeyFn from './src/is-key-in-object'\n\nconst isObject = checkIsObject\nconst isAny = checkIsAny\nconst isString = checkIsString\nconst isBoolean = checkIsBoolean\nconst isNumber = checkIsNumber\nconst isArray = checkIsArray\nconst isNotEmpty = notEmpty\n\nconst normalizeArgs = validator.normalizeArgs\nconst validateSync = validator.validateSync\nconst validateAsync = validator.validateAsync\n\nconst JSONQL_PARAMS_VALIDATOR_INFO = jsonqlOptions.JSONQL_PARAMS_VALIDATOR_INFO\n\nconst createConfig = jsonqlOptions.createConfig\nconst constructConfig = jsonqlOptions.constructConfigFn\n// construct the final output 1.5.2\nconst checkConfigAsync = jsonqlOptions.getCheckConfigAsync(validator.validateSync)\nconst checkConfig = jsonqlOptions.getCheckConfig(validator.validateSync)\n\nconst inArray = isInArray\nconst isObjectHasKey = isObjectHasKeyFn\n\n// check returns methods \nimport { \n checkReturns, \n checkReturnsAsync, \n checkResolverReturns, \n checkResolverReturnsAsync \n} from './src/returns'\n\n\n// group the in one \nexport {\n JSONQL_PARAMS_VALIDATOR_INFO,\n \n isObject,\n isAny,\n isString,\n isBoolean,\n isNumber,\n isArray,\n isNotEmpty,\n \n inArray,\n isObjectHasKey,\n\n normalizeArgs,\n validateSync,\n validateAsync,\n\n createConfig,\n constructConfig,\n checkConfig,\n checkConfigAsync,\n\n checkReturns, \n checkReturnsAsync, \n checkResolverReturns, \n checkResolverReturnsAsync\n}\n\n\n\n\n\n","// move the get logger stuff here\n\n// it does nothing\nconst dummyLogger = () => {}\n\n/**\n * re-use the debugOn prop to control this log method\n * @param {object} opts configuration\n * @return {function} the log function\n */\nconst getLogger = (opts) => {\n const { debugOn } = opts \n if (debugOn) {\n return (...args) => {\n Reflect.apply(console.info, console, ['[jsonql-ws-client-core]', ...args])\n }\n }\n return dummyLogger\n}\n\n/**\n * Make sure there is a log method\n * @param {object} opts configuration\n * @return {object} opts\n */\nconst getLogFn = opts => {\n const { log } = opts // 1.3.9 if we pass a log method here then we use this\n if (!log || typeof log !== 'function') {\n return getLogger(opts)\n }\n opts.log('---> getLogFn user supplied log function <---', opts)\n return log\n}\n\nexport { getLogFn }","// group all the repetitive message here\n\nexport const TAKEN_BY_OTHER_TYPE_ERR = 'You are trying to register an event already been taken by other type:'\n","// Create two WeakMap store as a private keys\nexport const NB_EVENT_SERVICE_PRIVATE_STORE = new WeakMap()\nexport const NB_EVENT_SERVICE_PRIVATE_LAZY = new WeakMap()\n","/**\n * generate a 32bit hash based on the function.toString()\n * _from http://stackoverflow.com/questions/7616461/generate-a-hash-_from-string-in-javascript-jquery\n * @param {string} s the converted to string function\n * @return {string} the hashed function string\n */\nexport function hashCode(s) {\n\treturn s.split(\"\").reduce(function(a,b){a=((a<<5)-a)+b.charCodeAt(0);return a&a},0)\n}\n\n/**\n * wrapper to make sure it string\n * @param {*} input whatever\n * @return {string} output\n */\nexport function hashCode2Str(s) {\n return hashCode(s) + ''\n}\n\n/**\n * Just check if a pattern is an RegExp object\n * @param {*} pat whatever\n * @return {boolean} false when its not\n */\nexport function isRegExp(pat) {\n return pat instanceof RegExp\n}\n\n/**\n * check if its string\n * @param {*} arg whatever\n * @return {boolean} false when it's not\n */\nexport function isString(arg) {\n return typeof arg === 'string'\n}\n\n/**\n * Find from the array by matching the pattern\n * @param {*} pattern a string or RegExp object\n * @return {object} regex object or false when we can not id the input\n */\nexport function getRegex(pattern) {\n switch (true) {\n case isRegExp(pattern) === true:\n return pattern\n case isString(pattern) === true:\n return new RegExp(pattern)\n default:\n return false\n }\n}\n","// making all the functionality on it's own\n// import { WatchClass } from './watch'\n/*\nwe use a different way to do the same watch thing now\nthis.watch('suspend', function(value, prop, oldValue) {\n this.logger(`${prop} set from ${oldValue} to ${value}`)\n // it means it set the suspend = true then release it\n if (oldValue === true && value === false) {\n // we want this happen after the return happens\n setTimeout(() => {\n this.release()\n }, 1)\n }\n return value; // we need to return the value to store it\n})\n*/\nimport { getRegex, isRegExp } from './utils'\n\nexport default class SuspendClass {\n\n constructor() {\n // suspend, release and queue\n this.__suspend_state__ = null\n // to do this proper we don't use a new prop to hold the event name pattern\n this.__pattern__ = null\n this.queueStore = new Set()\n }\n\n /**\n * start suspend\n * @return {void}\n */\n $suspend() {\n this.logger(`---> SUSPEND ALL OPS <---`)\n this.__suspend__(true)\n }\n\n /**\n * release the queue\n * @return {void}\n */\n $release() {\n this.logger(`---> RELEASE SUSPENDED QUEUE <---`)\n this.__suspend__(false)\n }\n\n /**\n * suspend event by pattern\n * @param {string} pattern the pattern search matches the event name\n * @return {void}\n */\n $suspendEvent(pattern) {\n const regex = getRegex(pattern)\n if (isRegExp(regex)) {\n this.__pattern__ = regex\n return this.$suspend()\n }\n throw new Error(`We expect a pattern variable to be string or RegExp, but we got \"${typeof regex}\" instead`)\n }\n\n /**\n * queuing call up when it's in suspend mode\n * @param {string} evt the event name\n * @param {*} args unknown number of arguments\n * @return {boolean} true when added or false when it's not\n */\n $queue(evt, ...args) {\n this.logger('($queue) get called')\n if (this.__suspend_state__ === true) {\n if (isRegExp(this.__pattern__)) { // it's better then check if its not null\n // check the pattern and decide if we want to suspend it or not\n let found = this.__pattern__.test(evt)\n if (!found) {\n return false\n }\n }\n this.logger('($queue) added to $queue', args)\n // @TODO there shouldn't be any duplicate, but how to make sure?\n this.queueStore.add([evt].concat(args))\n // return this.queueStore.size\n }\n return !!this.__suspend_state__\n }\n\n /**\n * a getter to get all the store queue\n * @return {array} Set turn into Array before return\n */\n get $queues() {\n let size = this.queueStore.size\n this.logger('($queues)', `size: ${size}`)\n if (size > 0) {\n return Array.from(this.queueStore)\n }\n return []\n }\n\n /**\n * to set the suspend and check if it's boolean value\n * @param {boolean} value to trigger\n */\n __suspend__(value) {\n if (typeof value === 'boolean') {\n const lastValue = this.__suspend_state__\n this.__suspend_state__ = value\n this.logger(`($suspend) Change from \"${lastValue}\" --> \"${value}\"`)\n if (lastValue === true && value === false) {\n this.__release__()\n }\n } else {\n throw new Error(`$suspend only accept Boolean value! we got ${typeof value}`)\n }\n }\n\n /**\n * Release the queue\n * @return {int} size if any\n */\n __release__() {\n let size = this.queueStore.size\n let pattern = this.__pattern__\n this.__pattern__ = null\n this.logger(`(release) was called with ${size}${pattern ? ' for \"' + pattern + '\"': ''} item${size > 1 ? 's' : ''}`)\n if (size > 0) {\n const queue = Array.from(this.queueStore)\n this.queueStore.clear()\n this.logger('(release queue)', queue)\n queue.forEach(args => {\n this.logger(args)\n Reflect.apply(this.$trigger, this, args)\n })\n this.logger(`Release size ${this.queueStore.size}`)\n }\n\n return size\n }\n}\n","// break up the main file because its getting way too long\nimport {\n NB_EVENT_SERVICE_PRIVATE_STORE,\n NB_EVENT_SERVICE_PRIVATE_LAZY\n} from './store'\nimport { hashCode2Str, isString } from './utils'\nimport SuspendClass from './suspend'\n\nexport default class StoreService extends SuspendClass {\n\n constructor(config = {}) {\n super()\n if (config.logger && typeof config.logger === 'function') {\n this.logger = config.logger\n }\n this.keep = config.keep\n // for the $done setter\n this.result = config.keep ? [] : null\n // we need to init the store first otherwise it could be a lot of checking later\n this.normalStore = new Map()\n this.lazyStore = new Map()\n }\n\n /**\n * validate the event name(s)\n * @param {string[]} evt event name\n * @return {boolean} true when OK\n */\n validateEvt(...evt) {\n evt.forEach(e => {\n if (!isString(e)) {\n this.logger('(validateEvt)', e)\n throw new Error(`Event name must be string type! we got ${typeof e}`)\n }\n })\n return true\n }\n\n /**\n * Simple quick check on the two main parameters\n * @param {string} evt event name\n * @param {function} callback function to call\n * @return {boolean} true when OK\n */\n validate(evt, callback) {\n if (this.validateEvt(evt)) {\n if (typeof callback === 'function') {\n return true\n }\n }\n throw new Error(`callback required to be function type! we got ${typeof callback}`)\n }\n\n /**\n * Check if this type is correct or not added in V1.5.0\n * @param {string} type for checking\n * @return {boolean} true on OK\n */\n validateType(type) {\n this.validateEvt(type)\n const types = ['on', 'only', 'once', 'onlyOnce']\n return !!types.filter(t => type === t).length\n }\n\n /**\n * Run the callback\n * @param {function} callback function to execute\n * @param {array} payload for callback\n * @param {object} ctx context or null\n * @return {void} the result store in $done\n */\n run(callback, payload, ctx) {\n this.logger('(run) callback:', callback, 'payload:', payload, 'context:', ctx)\n this.$done = Reflect.apply(callback, ctx, this.toArray(payload))\n }\n\n /**\n * Take the content out and remove it from store id by the name\n * @param {string} evt event name\n * @param {string} [storeName = lazyStore] name of store\n * @return {object|boolean} content or false on not found\n */\n takeFromStore(evt, storeName = 'lazyStore') {\n let store = this[storeName] // it could be empty at this point\n if (store) {\n this.logger('(takeFromStore)', storeName, store)\n if (store.has(evt)) {\n let content = store.get(evt)\n this.logger(`(takeFromStore) has \"${evt}\"`, content)\n store.delete(evt)\n return content\n }\n return false\n }\n throw new Error(`\"${storeName}\" is not supported!`)\n }\n\n /**\n * This was part of the $get. We take it out\n * so we could use a regex to remove more than one event\n * @param {object} store the store to return from\n * @param {string} evt event name\n * @param {boolean} full return just the callback or everything\n * @return {array|boolean} false when not found\n */\n findFromStore(evt, store, full = false) {\n if (store.has(evt)) {\n return Array\n .from(store.get(evt))\n .map( l => {\n if (full) {\n return l\n }\n let [key, callback, ] = l\n return callback\n })\n }\n return false\n }\n\n /**\n * Similar to the findFromStore, but remove\n * @param {string} evt event name\n * @param {object} store the store to remove from\n * @return {boolean} false when not found\n */\n removeFromStore(evt, store) {\n if (store.has(evt)) {\n this.logger('($off)', evt)\n store.delete(evt)\n return true\n }\n return false\n }\n\n /**\n * The add to store step is similar so make it generic for resuse\n * @param {object} store which store to use\n * @param {string} evt event name\n * @param {spread} args because the lazy store and normal store store different things\n * @return {array} store and the size of the store\n */\n addToStore(store, evt, ...args) {\n let fnSet\n if (store.has(evt)) {\n this.logger(`(addToStore) \"${evt}\" existed`)\n fnSet = store.get(evt)\n } else {\n this.logger(`(addToStore) create new Set for \"${evt}\"`)\n // this is new\n fnSet = new Set()\n }\n // lazy only store 2 items - this is not the case in V1.6.0 anymore\n // we need to check the first parameter is string or not\n if (args.length > 2) {\n if (Array.isArray(args[0])) { // lazy store\n // check if this type of this event already register in the lazy store\n let [,,t] = args\n if (!this.checkTypeInLazyStore(evt, t)) {\n fnSet.add(args)\n }\n } else {\n if (!this.checkContentExist(args, fnSet)) {\n this.logger(`(addToStore) insert new`, args)\n fnSet.add(args)\n }\n }\n } else { // add straight to lazy store\n fnSet.add(args)\n }\n store.set(evt, fnSet)\n return [store, fnSet.size]\n }\n\n /**\n * @param {array} args for compare\n * @param {object} fnSet A Set to search from\n * @return {boolean} true on exist\n */\n checkContentExist(args, fnSet) {\n let list = Array.from(fnSet)\n return !!list.filter(li => {\n let [hash,] = li\n return hash === args[0]\n }).length\n }\n\n /**\n * get the existing type to make sure no mix type add to the same store\n * @param {string} evtName event name\n * @param {string} type the type to check\n * @return {boolean} true you can add, false then you can't add this type\n */\n checkTypeInStore(evtName, type) {\n this.validateEvt(evtName, type)\n let all = this.$get(evtName, true)\n if (all === false) {\n // pristine it means you can add\n return true\n }\n // it should only have ONE type in ONE event store\n return !all.filter(list => {\n let [ ,,,t ] = list\n return type !== t\n }).length\n }\n\n /**\n * This is checking just the lazy store because the structure is different\n * therefore we need to use a new method to check it\n */\n checkTypeInLazyStore(evtName, type) {\n this.validateEvt(evtName, type)\n let store = this.lazyStore.get(evtName)\n this.logger('(checkTypeInLazyStore)', store)\n if (store) {\n return !!Array\n .from(store)\n .filter(li => {\n let [,,t] = li\n return t !== type\n }).length\n }\n return false\n }\n\n /**\n * wrapper to re-use the addToStore,\n * V1.3.0 add extra check to see if this type can add to this evt\n * @param {string} evt event name\n * @param {string} type on or once\n * @param {function} callback function\n * @param {object} context the context the function execute in or null\n * @return {number} size of the store\n */\n addToNormalStore(evt, type, callback, context = null) {\n this.logger(`(addToNormalStore) try to add \"${type}\" --> \"${evt}\" to normal store`)\n // @TODO we need to check the existing store for the type first!\n if (this.checkTypeInStore(evt, type)) {\n this.logger('(addToNormalStore)', `\"${type}\" --> \"${evt}\" can add to normal store`)\n let key = this.hashFnToKey(callback)\n let args = [this.normalStore, evt, key, callback, context, type]\n let [_store, size] = Reflect.apply(this.addToStore, this, args)\n this.normalStore = _store\n return size\n }\n return false\n }\n\n /**\n * Add to lazy store this get calls when the callback is not register yet\n * so we only get a payload object or even nothing\n * @param {string} evt event name\n * @param {array} payload of arguments or empty if there is none\n * @param {object} [context=null] the context the callback execute in\n * @param {string} [type=false] register a type so no other type can add to this evt\n * @return {number} size of the store\n */\n addToLazyStore(evt, payload = [], context = null, type = false) {\n // this is add in V1.6.0\n // when there is type then we will need to check if this already added in lazy store\n // and no other type can add to this lazy store\n let args = [this.lazyStore, evt, this.toArray(payload), context]\n if (type) {\n args.push(type)\n }\n let [_store, size] = Reflect.apply(this.addToStore, this, args)\n this.lazyStore = _store\n this.logger(`(addToLazyStore) size: ${size}`)\n return size\n }\n\n /**\n * make sure we store the argument correctly\n * @param {*} arg could be array\n * @return {array} make sured\n */\n toArray(arg) {\n return Array.isArray(arg) ? arg : [arg]\n }\n\n /**\n * setter to store the Set in private\n * @param {object} obj a Set\n */\n set normalStore(obj) {\n NB_EVENT_SERVICE_PRIVATE_STORE.set(this, obj)\n }\n\n /**\n * @return {object} Set object\n */\n get normalStore() {\n return NB_EVENT_SERVICE_PRIVATE_STORE.get(this)\n }\n\n /**\n * setter to store the Set in lazy store\n * @param {object} obj a Set\n */\n set lazyStore(obj) {\n NB_EVENT_SERVICE_PRIVATE_LAZY.set(this , obj)\n }\n\n /**\n * @return {object} the lazy store Set\n */\n get lazyStore() {\n return NB_EVENT_SERVICE_PRIVATE_LAZY.get(this)\n }\n\n /**\n * generate a hashKey to identify the function call\n * The build-in store some how could store the same values!\n * @param {function} fn the converted to string function\n * @return {string} hashKey\n */\n hashFnToKey(fn) {\n return hashCode2Str(fn.toString())\n }\n}\n","// The top level\nimport { TAKEN_BY_OTHER_TYPE_ERR } from './constants'\nimport StoreService from './store-service'\n// export\nexport default class EventService extends StoreService {\n /**\n * class constructor\n */\n constructor(config = {}) {\n super(config)\n }\n\n /**\n * logger function for overwrite\n */\n logger() {}\n\n // for id if the instance is this class\n get $name() {\n return 'to1source-event'\n }\n\n // take this down in the next release\n get is() {\n return this.$name\n }\n\n //////////////////////////\n // PUBLIC METHODS //\n //////////////////////////\n\n /**\n * Register your evt handler, note we don't check the type here,\n * we expect you to be sensible and know what you are doing.\n * @param {string} evt name of event\n * @param {function} callback bind method --> if it's array or not\n * @param {object} [context=null] to execute this call in\n * @return {number} the size of the store\n */\n $on(evt , callback , context = null) {\n const type = 'on'\n this.validate(evt, callback)\n // first need to check if this evt is in lazy store\n let lazyStoreContent = this.takeFromStore(evt)\n // this is normal register first then call later\n if (lazyStoreContent === false) {\n this.logger(`($on) \"${evt}\" is not in lazy store`)\n // @TODO we need to check if there was other listener to this\n // event and are they the same type then we could solve that\n // register the different type to the same event name\n return this.addToNormalStore(evt, type, callback, context)\n }\n this.logger(`($on) ${evt} found in lazy store`)\n // this is when they call $trigger before register this callback\n let size = 0\n lazyStoreContent.forEach(content => {\n let [ payload, ctx, t ] = content\n if (t && t !== type) {\n throw new Error(`${TAKEN_BY_OTHER_TYPE_ERR} ${t}`)\n }\n this.logger(`($on)`, `call run \"${evt}\"`)\n this.run(callback, payload, context || ctx)\n size += this.addToNormalStore(evt, type, callback, context || ctx)\n })\n\n this.logger(`($on) return size ${size}`)\n return size\n }\n\n /**\n * once only registered it once, there is no overwrite option here\n * @NOTE change in v1.3.0 $once can add multiple listeners\n * but once the event fired, it will remove this event (see $only)\n * @param {string} evt name\n * @param {function} callback to execute\n * @param {object} [context=null] the handler execute in\n * @return {boolean} result\n */\n $once(evt , callback , context = null) {\n this.validate(evt, callback)\n const type = 'once'\n let lazyStoreContent = this.takeFromStore(evt)\n // this is normal register before call $trigger\n let nStore = this.normalStore;\n if (lazyStoreContent === false) {\n this.logger(`($once) \"${evt}\" is not in the lazy store`)\n // v1.3.0 $once now allow to add multiple listeners\n return this.addToNormalStore(evt, type, callback, context)\n } else {\n // now this is the tricky bit\n // there is a potential bug here that cause by the developer\n // if they call $trigger first, the lazy won't know it's a once call\n // so if in the middle they register any call with the same evt name\n // then this $once call will be fucked - add this to the documentation\n this.logger('($once)', lazyStoreContent)\n const list = Array.from(lazyStoreContent)\n // should never have more than 1\n const [ payload, ctx, t ] = list[0]\n if (t && t !== type) {\n throw new Error(`${TAKEN_BY_OTHER_TYPE_ERR} ${t}`)\n }\n this.logger('($once)', `call run \"${evt}\"`)\n this.run(callback, payload, context || ctx)\n // remove this evt from store\n this.$off(evt)\n }\n }\n\n /**\n * This one event can only bind one callbackback\n * @param {string} evt event name\n * @param {function} callback event handler\n * @param {object} [context=null] the context the event handler execute in\n * @return {boolean} true bind for first time, false already existed\n */\n $only(evt, callback, context = null) {\n this.validate(evt, callback)\n const type = 'only'\n let added = false\n let lazyStoreContent = this.takeFromStore(evt)\n // this is normal register before call $trigger\n let nStore = this.normalStore\n if (!nStore.has(evt)) {\n this.logger(`($only) \"${evt}\" add to normalStore`)\n added = this.addToNormalStore(evt, type, callback, context)\n }\n if (lazyStoreContent !== false) {\n // there are data store in lazy store\n this.logger(`($only) \"${evt}\" found data in lazy store to execute`)\n const list = Array.from(lazyStoreContent)\n // $only allow to trigger this multiple time on the single handler\n list.forEach( li => {\n const [ payload, ctx, t ] = li\n if (t && t !== type) {\n throw new Error(`${TAKEN_BY_OTHER_TYPE_ERR} ${t}`)\n }\n this.logger(`($only) call run \"${evt}\"`)\n this.run(callback, payload, context || ctx)\n })\n }\n return added\n }\n\n /**\n * $only + $once this is because I found a very subtile bug when we pass a\n * resolver, rejecter - and it never fire because that's OLD added in v1.4.0\n * @param {string} evt event name\n * @param {function} callback to call later\n * @param {object} [context=null] exeucte context\n * @return {void}\n */\n $onlyOnce(evt, callback, context = null) {\n this.validate(evt, callback)\n const type = 'onlyOnce'\n let added = false\n let lazyStoreContent = this.takeFromStore(evt)\n // this is normal register before call $trigger\n let nStore = this.normalStore;\n if (!nStore.has(evt)) {\n this.logger(`($onlyOnce) \"${evt}\" add to normalStore`)\n added = this.addToNormalStore(evt, type, callback, context)\n }\n if (lazyStoreContent !== false) {\n // there are data store in lazy store\n this.logger('($onlyOnce)', lazyStoreContent)\n const list = Array.from(lazyStoreContent)\n // should never have more than 1\n const [ payload, ctx, t ] = list[0]\n if (t && t !== 'onlyOnce') {\n throw new Error(`${TAKEN_BY_OTHER_TYPE_ERR} ${t}`)\n }\n this.logger(`($onlyOnce) call run \"${evt}\"`)\n this.run(callback, payload, context || ctx)\n // remove this evt from store\n this.$off(evt)\n }\n return added\n }\n\n /**\n * This is a shorthand of $off + $on added in V1.5.0\n * @param {string} evt event name\n * @param {function} callback to exeucte\n * @param {object} [context = null] or pass a string as type\n * @param {string} [type=on] what type of method to replace\n * @return {*}\n */\n $replace(evt, callback, context = null, type = 'on') {\n if (this.validateType(type)) {\n this.$off(evt)\n let method = this['$' + type]\n this.logger(`($replace)`, evt, callback)\n return Reflect.apply(method, this, [evt, callback, context])\n }\n throw new Error(`${type} is not supported!`)\n }\n\n /**\n * trigger the event\n * @param {string} evt name NOT allow array anymore!\n * @param {mixed} [payload = []] pass to fn\n * @param {object|string} [context = null] overwrite what stored\n * @param {string} [type=false] if pass this then we need to add type to store too\n * @return {number} if it has been execute how many times\n */\n $trigger(evt , payload = [] , context = null, type = false) {\n this.validateEvt(evt)\n let found = 0\n // first check the normal store\n let nStore = this.normalStore\n this.logger('($trigger) normalStore', nStore)\n if (nStore.has(evt)) {\n this.logger(`($trigger) \"${evt}\" found`)\n // @1.8.0 to add the suspend queue\n let added = this.$queue(evt, payload, context, type)\n if (added) {\n this.logger(`($trigger) Currently suspended \"${evt}\" added to queue, nothing executed. Exit now.`)\n return false // not executed\n }\n let nSet = Array.from(nStore.get(evt))\n let ctn = nSet.length\n let hasOnce = false\n let hasOnly = false\n for (let i=0; i < ctn; ++i) {\n ++found;\n // this.logger('found', found)\n let [ _, callback, ctx, type ] = nSet[i]\n this.logger(`($trigger) call run for ${evt}`)\n this.run(callback, payload, context || ctx)\n if (type === 'once' || type === 'onlyOnce') {\n hasOnce = true;\n }\n }\n if (hasOnce) {\n nStore.delete(evt)\n }\n return found\n }\n // now this is not register yet\n this.addToLazyStore(evt, payload, context, type)\n return found\n }\n\n /**\n * this is an alias to the $trigger\n * @NOTE breaking change in V1.6.0 we swap the parameter aroun\n * @NOTE breaking change: v1.9.1 it return an function to accept the params as spread\n * @param {string} evt event name\n * @param {string} type of call\n * @param {object} context what context callback execute in\n * @return {*} from $trigger\n */\n $call(evt, type = false, context = null) {\n const ctx = this\n\n return (...args) => {\n let _args = [evt, args, context, type]\n return Reflect.apply(ctx.$trigger, ctx, _args)\n }\n }\n\n /**\n * remove the evt from all the stores\n * @param {string} evt name\n * @return {boolean} true actually delete something\n */\n $off(evt) {\n // @TODO we will allow a regex pattern to mass remove event\n this.validateEvt(evt)\n let stores = [ this.lazyStore, this.normalStore ]\n\n return !!stores\n .filter(store => store.has(evt))\n .map(store => this.removeFromStore(evt, store))\n .length\n }\n\n /**\n * return all the listener bind to that event name\n * @param {string} evtName event name\n * @param {boolean} [full=false] if true then return the entire content\n * @return {array|boolean} listerner(s) or false when not found\n */\n $get(evt, full = false) {\n // @TODO should we allow the same Regex to search for all?\n this.validateEvt(evt)\n let store = this.normalStore\n return this.findFromStore(evt, store, full)\n }\n\n /**\n * store the return result from the run\n * @param {*} value whatever return from callback\n */\n set $done(value) {\n this.logger('($done) set value: ', value)\n if (this.keep) {\n this.result.push(value)\n } else {\n this.result = value\n }\n }\n\n /**\n * @TODO is there any real use with the keep prop?\n * getter for $done\n * @return {*} whatever last store result\n */\n get $done() {\n this.logger('($done) get result:', this.result)\n if (this.keep) {\n return this.result[this.result.length - 1]\n }\n return this.result\n }\n\n /**\n * Take a look inside the stores\n * @param {number|null} idx of the store, null means all\n * @return {void}\n */\n $debug(idx = null) {\n let names = ['lazyStore', 'normalStore']\n let stores = [this.lazyStore, this.normalStore]\n if (stores[idx]) {\n this.logger(names[idx], stores[idx])\n } else {\n stores.map((store, i) => {\n this.logger(names[i], store)\n })\n }\n }\n}\n","// default\nimport To1sourceEvent from './src/event-service'\n\nexport default To1sourceEvent\n","// this will generate a event emitter and will be use everywhere\nimport EventEmitterClass from '@to1source/event'\n// create a clone version so we know which one we actually is using\nclass JsonqlWsEvt extends EventEmitterClass {\n\n constructor(logger) {\n if (typeof logger !== 'function') {\n throw new Error(`Just die here the logger is not a function!`)\n }\n logger(`---> Create a new EventEmitter <---`)\n // this ee will always come with the logger\n // because we should take the ee from the configuration\n super({ logger })\n }\n\n get name() {\n return'jsonql-ws-client-core'\n }\n}\n\n/**\n * getting the event emitter\n * @param {object} opts configuration\n * @return {object} the event emitter instance\n */\nconst getEventEmitter = opts => {\n const { log, eventEmitter } = opts\n \n if (eventEmitter) {\n log(`eventEmitter is:`, eventEmitter.name)\n return eventEmitter\n }\n \n return new JsonqlWsEvt( opts.log )\n}\n\nexport { \n getEventEmitter, \n EventEmitterClass // for other module to build from \n}\n","// group all the small functions here\nimport { EMIT_REPLY_TYPE } from 'jsonql-constants'\nimport { toArray, createEvt } from 'jsonql-utils/src/generic'\nimport JsonqlValidationError from 'jsonql-errors/src/validation-error'\n\n\n/**\n * WebSocket is strict about the path, therefore we need to make sure before it goes in\n * @param {string} url input url\n * @return {string} url with correct path name\n */\nexport const fixWss = url => {\n const uri = url.toLowerCase()\n if (uri.indexOf('http') > -1) {\n if (uri.indexOf('https') > -1) {\n return uri.replace('https', 'wss')\n }\n return uri.replace('http', 'ws')\n }\n return uri\n}\n\n\n/**\n * get a stock host name from browser\n */\nexport const getHostName = () => {\n try {\n return [window.location.protocol, window.location.host].join('//')\n } catch(e) {\n throw new JsonqlValidationError(e)\n }\n}\n\n/**\n * Unbind the event\n * @param {object} ee EventEmitter\n * @param {string} namespace\n * @return {void}\n */\nexport const clearMainEmitEvt = (ee, namespace) => {\n let nsps = toArray(namespace)\n nsps.forEach(n => {\n ee.$off(createEvt(n, EMIT_REPLY_TYPE))\n })\n}\n\n\n","// constants\n\nimport {\n EMIT_REPLY_TYPE,\n JS_WS_SOCKET_IO_NAME,\n JS_WS_NAME,\n ON_MESSAGE_FN_NAME,\n ON_RESULT_FN_NAME\n} from 'jsonql-constants'\n\nconst SOCKET_IO = JS_WS_SOCKET_IO_NAME\nconst WS = JS_WS_NAME\n\nconst AVAILABLE_SERVERS = [SOCKET_IO, WS]\n\nconst SOCKET_NOT_DEFINE_ERR = 'socket is not define in the contract file!'\n\nconst SERVER_NOT_SUPPORT_ERR = 'is not supported server name!'\n\nconst MISSING_PROP_ERR = 'Missing property in contract!'\n\nconst UNKNOWN_CLIENT_ERR = 'Unknown client type!'\n\nconst EMIT_EVT = EMIT_REPLY_TYPE\n\nconst NAMESPACE_KEY = 'namespaceMap'\n\nconst UNKNOWN_RESULT = 'UKNNOWN RESULT!'\n\nconst NOT_ALLOW_OP = 'This operation is not allow!'\n\nconst MY_NAMESPACE = 'myNamespace'\n\nconst CB_FN_NAME = 'on'\n// this is a socket only (for now) feature so we just put it here \nconst DISCONNECTED_ERROR_MSG = `You have disconnected from the socket server, please reconnect.`\n\nexport {\n SOCKET_IO,\n WS,\n AVAILABLE_SERVERS,\n SOCKET_NOT_DEFINE_ERR,\n SERVER_NOT_SUPPORT_ERR,\n MISSING_PROP_ERR,\n UNKNOWN_CLIENT_ERR,\n EMIT_EVT,\n ON_MESSAGE_FN_NAME,\n ON_RESULT_FN_NAME,\n NAMESPACE_KEY,\n UNKNOWN_RESULT,\n NOT_ALLOW_OP,\n MY_NAMESPACE,\n CB_FN_NAME,\n DISCONNECTED_ERROR_MSG\n}\n","// breaking it up further to share between methods\nimport { DATA_KEY, ERROR_KEY } from 'jsonql-constants'\nimport { UNKNOWN_RESULT } from '../options/constants'\nimport { isObjectHasKey } from '../utils'\n\n/**\n * break out to use in different places to handle the return from server\n * @param {object} data from server\n * @param {function} resolver NOT from promise\n * @param {function} rejecter NOT from promise\n * @return {void} nothing\n */\nexport function respondHandler(data, resolver, rejecter) {\n if (isObjectHasKey(data, ERROR_KEY)) {\n // debugFn('-- rejecter called --', data[ERROR_KEY])\n rejecter(data[ERROR_KEY])\n } else if (isObjectHasKey(data, DATA_KEY)) {\n // debugFn('-- resolver called --', data[DATA_KEY])\n resolver(data[DATA_KEY])\n } else {\n // debugFn('-- UNKNOWN_RESULT --', data)\n rejecter({message: UNKNOWN_RESULT, error: data})\n }\n}\n","// the actual trigger call method\nimport { ON_RESULT_FN_NAME, EMIT_REPLY_TYPE } from 'jsonql-constants'\nimport { createEvt, toArray } from '../utils'\nimport { respondHandler } from './respond-handler'\n\n/**\n * just wrapper\n * @param {object} ee EventEmitter\n * @param {string} namespace where this belongs\n * @param {string} resolverName resolver\n * @param {array} args arguments\n * @param {function} log function \n * @return {void} nothing\n */\nexport function actionCall(ee, namespace, resolverName, args = [], log) {\n // reply event \n const outEventName = createEvt(namespace, EMIT_REPLY_TYPE)\n\n log(`actionCall: ${outEventName} --> ${resolverName}`, args)\n // This is the out going call \n ee.$trigger(outEventName, [resolverName, toArray(args)])\n \n // then we need to listen to the event callback here as well\n return new Promise((resolver, rejecter) => {\n const inEventName = createEvt(namespace, resolverName, ON_RESULT_FN_NAME)\n // this cause the onResult got the result back first \n // and it should be the promise resolve first\n // @TODO we need to rewrote the respondHandler to change the problem stated above \n ee.$on(\n inEventName,\n function actionCallResultHandler(result) {\n log(`got the first result`, result)\n respondHandler(result, resolver, rejecter)\n }\n )\n })\n}\n","// setting up the send method \nimport { JsonqlValidationError } from 'jsonql-errors'\nimport {\n ON_ERROR_FN_NAME,\n SEND_MSG_FN_NAME\n} from 'jsonql-constants'\nimport { validateAsync } from 'jsonql-params-validator'\nimport { objDefineProps, createEvt, toArray, nil } from '../utils'\nimport { actionCall } from './action-call'\n\n/** \n * pairing with the server vesrion SEND_MSG_FN_NAME\n * last of the chain so only return the resolver (fn)\n * This is now change to a getter / setter method \n * and call like this: resolver.send(...args)\n * @param {function} fn the resolver function \n * @param {object} ee event emitter instance \n * @param {string} namespace the namespace it belongs to \n * @param {string} resolverName name of the resolver \n * @param {object} params from contract \n * @param {function} log a logger function\n * @return {function} return the resolver itself \n */ \nexport const setupSendMethod = (fn, ee, namespace, resolverName, params, log) => (\n objDefineProps(\n fn, \n SEND_MSG_FN_NAME, \n nil, \n function sendHandler() {\n // let _log = (...args) => Reflect.apply(console.info, console, ['[SEND]'].concat(args))\n /** \n * This will follow the same pattern like the resolver \n * @param {array} args list of unknown argument follow the resolver \n * @return {promise} resolve the result \n */\n return function sendCallback(...args) {\n return validateAsync(args, params.params, true)\n .then(_args => {\n // @TODO check the result \n // because the validation could failed with the list of fail properties \n log(namespace, resolverName, _args)\n return actionCall(ee, namespace, resolverName, _args, _log)\n })\n .catch(err => {\n // @TODO it shouldn't be just a validation error \n // it could be server return error, so we need to check \n // what error we got back here first \n log('send error', err)\n // @TODO it might not an validation error need the finalCatch here\n ee.$call(\n createEvt(namespace, resolverName, ON_ERROR_FN_NAME),\n [new JsonqlValidationError(resolverName, err)]\n )\n })\n } \n })\n)\n","// break up the original setup resolver method here\n// import { JsonqlValidationError, finalCatch } from 'jsonql-errors'\nimport {\n ON_ERROR_FN_NAME,\n ON_MESSAGE_FN_NAME,\n ON_RESULT_FN_NAME\n} from 'jsonql-constants'\n// local \nimport { MY_NAMESPACE } from '../options/constants'\nimport { chainFns, objDefineProps, injectToFn, createEvt, isFunc } from '../utils'\nimport { respondHandler } from './respond-handler'\nimport { setupSendMethod } from './setup-send-method'\n\n/**\n * The first one in the chain, just setup a namespace prop\n * the rest are passing through\n * @param {function} fn the resolver function\n * @param {object} ee the event emitter \n * @param {string} resolverName what it said\n * @param {object} params for resolver from contract\n * @param {function} log the logger function\n * @return {array}\n */\nconst setupNamespace = (fn, ee, namespace, resolverName, params, log) => [\n injectToFn(fn, MY_NAMESPACE, namespace),\n ee,\n namespace,\n resolverName,\n params,\n log \n]\n\n/** \n * onResult handler\n */ \nconst setupOnResult = (fn, ee, namespace, resolverName, params, log) => [\n objDefineProps(fn, ON_RESULT_FN_NAME, function(resultCallback) {\n if (isFunc(resultCallback)) {\n ee.$on(\n createEvt(namespace, resolverName, ON_RESULT_FN_NAME),\n function resultHandler(result) {\n respondHandler(result, resultCallback, (error) => {\n log(`Catch error: \"${resolverName}\"`, error)\n ee.$trigger(\n createEvt(namespace, resolverName, ON_ERROR_FN_NAME), \n error\n )\n })\n }\n )\n }\n }),\n ee,\n namespace,\n resolverName,\n params,\n log\n]\n\n/** \n * we do need to add the send prop back because it's the only way to deal with\n * bi-directional data stream \n */\nconst setupOnMessage = (fn, ee, namespace, resolverName, params, log) => [\n objDefineProps(fn, ON_MESSAGE_FN_NAME, function(messageCallback) {\n // we expect this to be a function\n if (isFunc(messageCallback)) {\n // did that add to the callback\n let onMessageCallback = (args) => {\n respondHandler(args, messageCallback, (error) => {\n log(`Catch error: \"${resolverName}\"`, error)\n ee.$trigger(\n createEvt(namespace, resolverName, ON_ERROR_FN_NAME), \n error\n )\n })\n }\n // register the handler for this message event\n ee.$only(\n createEvt(namespace, resolverName, ON_MESSAGE_FN_NAME), \n onMessageCallback\n )\n }\n }),\n ee,\n namespace,\n resolverName,\n params,\n log\n]\n\n/** \n * ON_ERROR_FN_NAME handler\n */\nconst setupOnError = (fn, ee, namespace, resolverName, params, log) => [\n objDefineProps(fn, ON_ERROR_FN_NAME, function(resolverErrorHandler) {\n if (isFunc(resolverErrorHandler)) {\n // please note ON_ERROR_FN_NAME can add multiple listners\n ee.$only(\n createEvt(namespace, resolverName, ON_ERROR_FN_NAME), \n resolverErrorHandler\n )\n }\n }),\n ee,\n namespace,\n resolverName,\n params,\n log\n]\n\n/**\n * Add extra property / listeners to the resolver\n * @param {string} namespace where this belongs\n * @param {string} resolverName name as event name\n * @param {object} params from contract\n * @param {function} fn resolver function\n * @param {object} ee EventEmitter\n * @param {function} log function \n * @return {function} resolver\n */\nexport function setupResolver(namespace, resolverName, params, fn, ee, log) {\n let fns = [\n setupNamespace, \n setupOnResult, \n setupOnMessage, \n setupOnError, \n setupSendMethod\n ]\n \n // get the executor\n const executor = Reflect.apply(chainFns, null, fns)\n const args = [fn, ee, namespace, resolverName, params, log]\n\n return Reflect.apply(executor, null, args)\n}\n","// put all the resolver related methods here to make it more clear\n\n// this will be a mini client server architect\n// The reason is when the enableAuth setup - the private route\n// might not be validated, but we need the callable point is ready\n// therefore this part will always take the contract and generate\n// callable api for the developer to setup their front end\n// the only thing is - when they call they might get an error or\n// NOT_LOGIN_IN and they can react to this error accordingly\nimport { finalCatch } from 'jsonql-errors'\nimport { validateAsync } from 'jsonql-params-validator'\nimport { setupResolver } from './setup-resolver'\nimport { actionCall } from './action-call'\nimport {\n createEvt,\n objDefineProps,\n isFunc,\n injectToFn\n} from '../utils'\nimport {\n ON_ERROR_FN_NAME,\n ON_READY_FN_NAME\n} from 'jsonql-constants'\n\n/**\n * create the actual function to send message to server\n * @param {object} ee EventEmitter instance\n * @param {string} namespace this resolver end point\n * @param {string} resolverName name of resolver as event name\n * @param {object} params from contract\n * @param {function} log pass the log function\n * @return {function} resolver\n */\nfunction createResolver(ee, namespace, resolverName, params, log) {\n // note we pass the new withResult=true option\n return function resolver(...args) {\n return validateAsync(args, params.params, true)\n .then(_args => actionCall(ee, namespace, resolverName, _args, log))\n .catch(finalCatch)\n }\n}\n\n/**\n * step one get the clientmap with the namespace\n * @param {object} opts configuration\n * @param {object} ee EventEmitter\n * @param {object} nspGroup resolvers index by their namespace\n * @return {promise} resolve the clientmapped, and start the chain\n */\nexport function generateResolvers(opts, ee, nspGroup) {\n let client= {}\n let { log } = opts\n\n for (let namespace in nspGroup) {\n let list = nspGroup[namespace]\n for (let resolverName in list) {\n // resolverNames.push(resolverName)\n let params = list[resolverName]\n let fn = createResolver(ee, namespace, resolverName, params, log)\n // this should set as a getter therefore can not be overwrite by accident\n // obj[resolverName] = setupResolver(namespace, resolverName, params, fn, ee)\n client = injectToFn(\n client,\n resolverName,\n setupResolver(namespace, resolverName, params, fn, ee, log)\n )\n }\n }\n // resolve the clientto start the chain\n // chain the result to allow the chain processing\n return [ client, opts, ee, nspGroup ]\n}\n\n/**\n * The problem is the namespace can have more than one\n * and we only have on onError message\n * @param {object} clientthe client itself\n * @param {object} opts configuration\n * @param {object} ee Event Emitter\n * @param {object} nspGroup namespace keys\n * @return {array} [obj, opts, ee]\n */\nexport function setupNamespaceErrorListener(client, opts, ee, nspGroup) {\n return [\n objDefineProps(\n client,\n ON_ERROR_FN_NAME,\n function namespaceErrorCallbackHandler(namespaceErrorHandler) {\n if (isFunc(namespaceErrorHandler)) {\n // please note ON_ERROR_FN_NAME can add multiple listners\n for (let namespace in nspGroup) {\n // this one is very tricky, we need to make sure the trigger is calling\n // with the namespace as well as the error\n ee.$on(createEvt(namespace, ON_ERROR_FN_NAME), namespaceErrorHandler)\n }\n }\n }\n ),\n opts,\n ee\n ]\n}\n\n/**\n * This event will fire when the socket.io.on('connection') and ws.onopen\n * @param {object} client client itself\n * @param {object} opts configuration\n * @param {object} ee Event Emitter\n * @return {array} [ obj, opts, ee ]\n */\nexport function setupOnReadyListener(client, opts, ee) {\n return [\n objDefineProps(\n client,\n ON_READY_FN_NAME,\n function onReadyCallbackHandler(onReadyCallback) {\n if (isFunc(onReadyCallback)) {\n // reduce it down to just one flat level\n // @2020-03-19 only allow ONE onReady callback otherwise\n // it will get fire multiple times which is not what we want\n ee.$only(ON_READY_FN_NAME, onReadyCallback)\n }\n }\n ),\n opts,\n ee\n ]\n}\n","// resolvers generator\n// we change the interface to return promise from v1.0.3\n// this way we make sure the obj return is correct and timely\nimport { chainFns } from '../utils'\nimport { setupAuthMethods } from './setup-auth-methods'\nimport {\n generateResolvers,\n setupOnReadyListener,\n setupNamespaceErrorListener\n} from './generator-methods'\n\nimport {\n NSP_GROUP\n} from 'jsonql-constants'\n\n/**\n * prepare the methods\n * @param {object} opts configuration\n * @param {object} nspMap resolvers index by their namespace\n * @param {object} ee EventEmitter\n * @return {object} of resolvers\n * @public\n */\nexport function callersGenerator(opts, nspMap, ee) {\n let fns = [\n generateResolvers,\n setupOnReadyListener,\n setupNamespaceErrorListener\n ]\n if (opts.enableAuth) {\n fns.push(createAuthMethods)\n }\n // we will always get back the [ obj, opts, ee ]\n // then we only return the obj (wsClient)\n // This has move outside of here, into the main method\n // the reason is we could switch around the sequence much easier\n // fns.push(setupFinalStep)\n // run it\n const generator = Reflect.apply(chainFns, null, fns)\n\n return generator(opts, ee, nspMap[NSP_GROUP])\n}\n","// this is a new method that will create several\n// intercom method also reverse listen to the server\n// such as disconnect (server issue disconnect)\nimport { injectToFn } from '../utils'\nimport { DISCONNECT_EVENT_NAME } from 'jsonql-constants'\n\n/**\n * this is the new method that setup the intercom handler\n * also this serve as the final call in the then chain to\n * output the client\n * @param {object} client the client\n * @param {object} opts configuration\n * @param {object} ee the event emitter\n * @return {object} client\n */\nexport function setupInterCom(client, opts, ee) {\n const { disconnectHandlerName } = opts\n\n return injectToFn(\n client,\n disconnectHandlerName,\n function disconnectHandler(...args) {\n ee.$trigger(DISCONNECT_EVENT_NAME, args)\n }\n )\n}\n","// The final step of the setup before it returns the client\nimport { setupInterCom } from './setup-intercom'\n\n/**\n * The final step to return the client\n * @param {object} params wrapper object to call the result forward \n * @param {object} params.client the client\n * @param {object} params.opts configuration\n * @param {object} params.ee the event emitter\n * @return {object} client\n */\nfunction setupFinalStep({ obj, opts, ee }) {\n\n const client = setupInterCom(obj, opts, ee)\n\n opts.log(`---> The final step to return the ws-client <---`)\n // add some debug functions\n client.verifyEventEmitter = () => ee.is\n // we add back the two things into the client\n // then when we do integration, we run it in reverse,\n // create the ws client first then the host client\n client.eventEmitter = opts.eventEmitter\n client.log = opts.log\n // we just inject a helloWorld method here\n // client[HELLO_FN] =\n\n return client\n}\n\n\nexport { setupFinalStep }\n","// create options\nimport {\n checkConfigAsync,\n checkConfig\n} from 'jsonql-params-validator'\nimport {\n wsCoreCheckMap,\n wsCoreConstProps,\n socketCheckMap\n} from './defaults'\nimport {\n fixWss,\n getHostName,\n getEventEmitter,\n getNspInfoByConfig,\n getLogFn\n} from '../utils'\n\n/**\n * We need this to find the socket server type\n * @param {*} config\n * @return {string} the name of the socket server if any\n */\nfunction checkSocketClientType(config) {\n return checkConfig(config, socketCheckMap)\n}\n\n/**\n * Create a combine checkConfig for the creating the combine client\n * @param {*} configCheckMap\n * @param {*} constProps\n * @return {function} takes the user input config then resolve the configuration\n */\nfunction createCombineConfigCheck(configCheckMap, constProps) {\n const combineCheckMap = Object.assign({}, configCheckMap, wsCoreCheckMap)\n const combineConstProps = Object.assign({}, constProps, wsCoreConstProps)\n return config => checkConfigAsync(config, combineCheckMap, combineConstProps)\n}\n\n\n/**\n * wrapper method to check this already did the pre check\n * @param {object} config user supply config\n * @param {object} defaultOptions for checking\n * @param {object} constProps user supply const props\n * @return {promise} resolve to the checked opitons\n */\nfunction checkConfiguration(config, defaultOptions, constProps) {\n const defaultCheckMap= Object.assign(wsCoreCheckMap, defaultOptions)\n const wsConstProps = Object.assign(wsCoreConstProps, constProps)\n\n return checkConfigAsync(config, defaultCheckMap, wsConstProps)\n}\n\n/**\n * Taking the `then` part from the method below\n * @param {object} opts\n * @return {promise} opts all done\n */\nfunction postCheckInjectOpts(opts) {\n return Promise.resolve(opts)\n .then(opts => {\n if (!opts.hostname) {\n opts.hostname = getHostName()\n }\n // @TODO the contract now will supply the namespace information\n // and we need to use that to group the namespace call\n opts.wssPath = fixWss([opts.hostname, opts.namespace].join('/'), opts.serverType)\n // get the log function here\n opts.log = getLogFn(opts)\n\n opts.eventEmitter = getEventEmitter(opts)\n\n return opts\n })\n}\n\n/**\n * Don't want to make things confusing\n * Breaking up the opts process in one place\n * then generate the necessary parameter in another step\n * @2020-3-20 here we suspend operation by it's namespace first\n * Then in the framework part, after the connection establish we release\n * the queue\n * @param {object} opts checked --> merge --> injected\n * @return {object} {opts, nspMap, ee}\n */\nfunction createRequiredParams(opts) {\n const nspMap = getNspInfoByConfig(opts)\n const ee = opts.eventEmitter\n // @TODO here we are going to add suspend event to the namespace related methods\n \n\n return { opts, nspMap, ee }\n}\n\nexport {\n // properties\n wsCoreCheckMap,\n wsCoreConstProps,\n // functions\n checkConfiguration,\n postCheckInjectOpts,\n createRequiredParams,\n // this will just get export for integration\n checkSocketClientType,\n createCombineConfigCheck\n}\n","// the top level API\n// The goal is to create a generic method that will able to handle\n// any kind of clients\n// import { injectToFn } from 'jsonql-utils'\nimport {\n callersGenerator,\n setupFinalStep\n} from './callers'\nimport {\n checkConfiguration,\n postCheckInjectOpts,\n createRequiredParams\n} from './options'\n\n\n/**\n * 0.5.0 we break up the wsClientCore in two parts one without the config check\n * @param {function} socketClientListener\n * @return {function} to actually generate the client\n */\nexport function wsClientCoreAction(socketClientListener) {\n /**\n * This is a breaking change, to continue the onion skin design\n * @param {object} config the already checked config\n * @return {promise} resolve the client\n */\n return (config = {}) => {\n\n return postCheckInjectOpts(config)\n // the following two moved to wsPostConfig\n .then(createRequiredParams)\n .then(\n ({opts, nspMap, ee}) => socketClientListener(opts, nspMap, ee)\n )\n .then( // there is problem here, we wrap up the operation inside\n ({opts, nspMap, ee}) => callersGenerator(opts, nspMap, ee)\n )\n .then(setupFinalStep)\n .catch(err => {\n console.error(`jsonql-ws-core-client init error`, err)\n })\n }\n}\n\n/**\n * The main interface which will generate the socket clients and map all events\n * @param {object} socketClientListerner this is the one method export by various clients\n * @param {object} [configCheckMap={}] we should do all the checking in the core instead of the client\n * @param {object} [constProps={}] add this to supply the constProps from the downstream client\n * @return {function} accept a config then return the wsClient instance with all the available API\n */\nexport function wsClientCore(socketClientListener, configCheckMap = {}, constProps = {}) {\n // we need to inject property to this client later\n return (config = {}) => checkConfiguration(config, configCheckMap, constProps)\n .then(\n wsClientCoreAction(socketClientListener)\n )\n}\n","// this is getting too confusing \n// therefore we move it back to the framework specific \n\n/**\n * wrapper method to create a nsp without login\n * @param {string|boolean} namespace namespace url could be false\n * @param {object} opts configuration\n * @return {object} ws client instance\n */\nfunction createNspClient(namespace, opts) {\n const { hostname, wssPath, wsOptions, nspClient, log } = opts\n const url = namespace ? [hostname, namespace].join('/') : wssPath\n log(`createNspClient --> `, url)\n\n return nspClient(url, wsOptions)\n}\n\n/**\n * wrapper method to create a nsp with token auth\n * @param {string} namespace namespace url\n * @param {object} opts configuration\n * @return {object} ws client instance\n */\nfunction createNspAuthClient(namespace, opts) {\n const { hostname, wssPath, token, wsOptions, nspAuthClient, log } = opts\n const url = namespace ? [hostname, namespace].join('/') : wssPath\n \n log(`createNspAuthClient -->`, url)\n\n if (token && typeof token !== 'string') {\n throw new Error(`Expect token to be string, but got ${token}`)\n }\n \n return nspAuthClient(url, token, wsOptions)\n}\n\nexport {\n createNspClient,\n createNspAuthClient\n}\n","// this use by client-event-handler\nimport { ON_ERROR_FN_NAME } from 'jsonql-constants'\nimport { createEvt } from '../utils'\n\n/**\n * trigger errors on all the namespace onError handler\n * @param {object} ee Event Emitter\n * @param {array} namespaces nsps string\n * @param {string} message optional\n * @return {void}\n */\nexport function triggerNamespacesOnError(ee, namespaces, message) {\n namespaces.forEach( namespace => {\n ee.$trigger(\n createEvt(namespace, ON_ERROR_FN_NAME), \n [{ message, namespace }]\n )\n })\n}\n\n/**\n * Handle the onerror callback \n * @param {object} ee event emitter \n * @param {string} namespace which namespace has error \n * @param {*} err error object\n * @return {void} \n */\nexport const handleNamespaceOnError = (ee, namespace, err) => {\n ee.$trigger(createEvt(namespace, ON_ERROR_FN_NAME), [err])\n}","// NOT IN USE AT THE MOMENT JUST KEEP IT HERE FOR THE TIME BEING \nimport {\n LOGOUT_EVENT_NAME,\n NOT_LOGIN_ERR_MSG,\n ON_ERROR_FN_NAME,\n ON_RESULT_FN_NAME,\n DISCONNECT_EVENT_NAME\n} from 'jsonql-constants'\nimport { EMIT_EVT, DISCONNECTED_ERROR_MSG } from '../options/constants'\nimport { createEvt, clearMainEmitEvt } from '../utils'\nimport { triggerNamespacesOnError } from './trigger-namespaces-on-error'\n\n/**\n * Only when there is a private namespace then we bind to this event\n * @param {object} nsps the available nsp(s)\n * @param {array} namespaces available namespace \n * @param {object} ee eventEmitter \n * @param {object} opts configuration\n * @return {void}\n */\nexport const logoutEvtListener = (nsps, namespaces, ee, opts) => {\n const { log } = opts \n // this will be available regardless enableAuth\n // because the server can log the client out\n ee.$on(\n LOGOUT_EVENT_NAME, \n function logoutEvtCallback() {\n const privateNamespace = getPrivateNamespace(namespaces)\n log(`${LOGOUT_EVENT_NAME} event triggered`)\n // disconnect(nsps, opts.serverType)\n // we need to issue error to all the namespace onError Listerner\n triggerNamespacesOnError(ee, [privateNamespace], LOGOUT_EVENT_NAME)\n // rebind all of the Listerner to the fake one\n log(`logout from ${privateNamespace}`)\n\n clearMainEmitEvt(ee, privateNamespace)\n // we need to issue one more call to the server before we disconnect\n // now this is a catch 22, here we are not suppose to do anything platform specific\n // so that should fire before trigger this event\n // clear out the nsp\n nsps[privateNamespace] = null \n // add a NOT LOGIN error if call\n notLoginWsListerner(privateNamespace, ee, opts)\n }\n )\n}\n\n/**\n * A Event Listerner placeholder when it's not connect to any nsp\n * @param {string} namespace nsp\n * @param {object} ee EventEmitter\n * @param {object} opts configuration\n * @return {void}\n */\nexport const notConnectedListener = (namespace, ee, opts) => {\n const { log } = opts \n\n ee.$only(\n createEvt(namespace, EMIT_EVT),\n function disconnectedEvtCallback(resolverName, args) {\n log(`[disconnectedListerner] hijack the ws call`, namespace, resolverName, args)\n const error = {\n message: DISCONNECTED_ERROR_MSG\n }\n ee.$call(createEvt(namespace, resolverName, ON_ERROR_FN_NAME), [ error ])\n // also trigger the result Listerner, but wrap inside the error key\n ee.$call(createEvt(namespace, resolverName, ON_RESULT_FN_NAME), [{ error }])\n }\n )\n}\n\n\n/**\n * The disconnect event Listerner, now we log the client out from everything\n * @TODO now we are another problem they disconnect, how to reconnect\n * @param {object} nsps the available nsp(s)\n * @param {array} namespaces available namespace \n * @param {object} ee eventEmitter \n * @param {object} opts configuration\n * @return {void}\n */\nexport const disconnectListener = (nsps, namespaces, ee, opts) => {\n const { log } = opts \n ee.$on(\n DISCONNECT_EVENT_NAME, \n function disconnectEvtCallback() {\n triggerNamespacesOnError(ee, namespaces, DISCONNECT_EVENT_NAME)\n namespaces.forEach( namespace => { \n log(`disconnect from ${namespace}`)\n\n clearMainEmitEvt(ee, namespace)\n nsps[namespace] = null \n disconnectedListerner(namespace, ee, opts)\n })\n }\n )\n}\n\n/**\n * A Event Listerner placeholder when it's not connect to the private nsp\n * @param {string} namespace nsp\n * @param {object} ee EventEmitter\n * @param {object} opts configuration\n * @return {void}\n */\nexport const notLoginListener = (namespace, ee, opts) => {\n const { log } = opts \n\n ee.$only(\n createEvt(namespace, EMIT_EVT),\n function notLoginListernerCallback(resolverName, args) {\n log('[notLoginListerner] hijack the ws call', namespace, resolverName, args)\n const error = { message: NOT_LOGIN_ERR_MSG }\n // It should just throw error here and should not call the result\n // because that's channel for handling normal event not the fake one\n ee.$call(createEvt(namespace, resolverName, ON_ERROR_FN_NAME), [ error ])\n // also trigger the result Listerner, but wrap inside the error key\n ee.$call(createEvt(namespace, resolverName, ON_RESULT_FN_NAME), [{ error }])\n }\n )\n}","// This is share between different clients so we export it\n// @TODO port what is in the ws-main-handler\n// because all the client side call are via the ee\n// and that makes it re-usable between different client setup\n\n/*\nInside the map call but we take it out for now and until the WebSocket version is fully working\nimport { SOCKET_IO } from '../options/constants'\n // @TODO need to double check this\n if (opts.serverType === SOCKET_IO) {\n let { nspGroup } = nspMap\n args.push(nspGroup[namespace])\n }\n*/\nimport { getPrivateNamespace } from 'jsonql-utils/src/namespace'\nimport { logoutEvtListener, notLoginListener } from './event-listeners'\n\n\n/**\n * centralize all the comm in one place\n * @param {function} bindSocketEventHandler binding the ee to ws --> this is the core bit\n * @param {object} nsps namespaced nsp\n * @return {void} nothing\n */\nexport function clientEventListener(bindSocketEventListener, nsps) {\n /**\n * BREAKING CHANGE instead of one flat structure\n * we return a function to accept the two \n * @param {object} opts configuration\n * @param {object} nspMap this is not in the opts \n * @param {object} ee Event Emitter instance\n * @return {array} although we return something but this is the last step and nothing to do further\n */\n return (opts, nspMap, ee) => {\n // since all these params already in the opts\n const { log } = opts\n const { namespaces } = nspMap\n // @1.1.3 add isPrivate prop to id which namespace is the private nsp\n // then we can use this prop to determine if we need to fire the ON_LOGIN_PROP_NAME event\n const privateNamespace = getPrivateNamespace(namespaces)\n \n return namespaces.map(namespace => {\n let isPrivate = privateNamespace === namespace\n log(namespace, ` --> ${isPrivate ? 'private': 'public'} nsp --> `, nsps[namespace] !== false)\n if (nsps[namespace]) {\n log('[call bindWsHandler]', isPrivate, namespace)\n\n let args = [namespace, nsps[namespace], ee, isPrivate, opts]\n // Finally we binding everything together\n Reflect.apply(bindSocketEventListener, null, args)\n\n } else {\n log(`binding notLoginWsHandler to ${namespace}`)\n // a dummy placeholder\n // @TODO but it should be a not connect handler \n // when it's not login (or fail) this should be handle differently \n notLoginListener(namespace, ee, opts)\n }\n if (isPrivate) {\n log(`Has private and add logoutEvtHandler`)\n logoutEvtListener(nsps, namespaces, ee, opts)\n }\n // just return something its not going to get use anywhere\n return isPrivate \n })\n }\n}\n","// jsonql-ws-core takes over the check configuration\n// here we only have to supply the options that is unique to this client\n// create options\nimport { JS_WS_NAME } from 'jsonql-constants'\n// constant props\nconst wsClientConstProps = {\n version: '__PLACEHOLDER__', // will get replace\n serverType: JS_WS_NAME\n}\n\nexport { wsClientConstProps }\n","// pass the different type of ws to generate the client\n// this is where the framework specific code get injected\nimport { TOKEN_PARAM_NAME } from 'jsonql-constants'\nimport { fixWss } from '../modules'\nimport {\n createInitPing, \n extractPingResult\n} from '../modules'\n\n/**\n * Group the ping and get respond create new client in one\n * @param {object} ws \n * @param {object} WebSocket \n * @param {string} url\n * @param {function} resolver \n * @param {function} rejecter \n * @param {boolean} auth client or not\n * @return {promise} resolve the confirm client\n */\nfunction initPingAction(ws, WebSocket, url, resolver, rejecter, wsOptions) {\n // @TODO how to we id this client can issue a CSRF\n // by origin? \n ws.onopen = function onOpenCallback() {\n ws.send(createInitPing())\n }\n\n ws.onmessage = function onMessageCallback(payload) {\n try {\n const header = extractPingResult(payload.data)\n // @NOTE the break down test in ws-client-core show no problems\n // the problem was cause by malform nspInfo that time? \n setTimeout(() => { // delay or not show no different but just on the safe side\n ws.terminate()\n }, 50)\n const newWs = new WebSocket(url, Object.assign(wsOptions, header)) \n resolver(newWs) \n } catch(e) {\n rejecter(e)\n }\n }\n\n ws.onerror = function onErrorCallback(err) {\n rejecter(err)\n }\n}\n\n/**\n * less duplicated code the better \n * @param {object} WebSocket \n * @param {string} url formatted url\n * @param {object} options or not\n * @return {promise} resolve the actual verified client\n */\nfunction asyncConnect(WebSocket, url, options) {\n \n return new Promise((resolver, rejecter) => { \n \n const unconfirmClient = new WebSocket(url, options)\n \n initPingAction(unconfirmClient, WebSocket, url, resolver, rejecter, options)\n })\n}\n\n\n/**\n * The bug was in the wsOptions where ws don't need it but socket.io do\n * therefore the object was pass as second parameter!\n * @NOTE here we only return a method to create the client, it might not get call \n * @param {object} WebSocket the client or node version of ws\n * @param {boolean} auth if it's auth then 3 param or just one\n * @param {object} opts this is a breaking change we will init the client twice\n */\nfunction initWebSocketClient(WebSocket, auth, log) {\n if (auth === false) {\n /**\n * Create a non-protected client\n * @param {string} url \n * @param {object} [wsOptions={}]\n * @return {promise} resolve to the confirmed client\n */\n return function createWsClient(url, wsOptions = {}) {\n const _url = fixWss(url)\n log(`nspClient: \\n${_url}\\n`, wsOptions)\n\n return asyncConnect(WebSocket, _url, wsOptions)\n }\n }\n\n /**\n * Create a client with auth token\n * @param {string} url start with ws:// @TODO check this?\n * @param {string} token the jwt token\n * @param {object} [wsOptions={}] extra options pass to the WebSocket object\n * @return {object} ws instance\n */\n return function createWsAuthClient(url, token, wsOptions = {}) {\n const ws_url = fixWss(url)\n // console.log('what happen here?', url, ws_url, token)\n const _url = token && typeof token === 'string' ? `${ws_url}?${TOKEN_PARAM_NAME}=${token}` : ws_url\n log(`nspAuthClient: \\n${_url}\\n`, wsOptions)\n\n return asyncConnect(WebSocket, _url, wsOptions)\n }\n}\n\nexport { initWebSocketClient }","/** Used for built-in method references. */\nvar objectProto = Object.prototype;\n\n/**\n * Used to resolve the\n * [`toStringTag`](http://ecma-international.org/ecma-262/7.0/#sec-object.prototype.tostring)\n * of values.\n */\nvar nativeObjectToString = objectProto.toString;\n\n/**\n * Converts `value` to a string using `Object.prototype.toString`.\n *\n * @private\n * @param {*} value The value to convert.\n * @returns {string} Returns the converted string.\n */\nfunction objectToString(value) {\n return nativeObjectToString.call(value);\n}\n\nexport default objectToString;\n","/**\n * Creates a unary function that invokes `func` with its argument transformed.\n *\n * @private\n * @param {Function} func The function to wrap.\n * @param {Function} transform The argument transform.\n * @returns {Function} Returns the new function.\n */\nfunction overArg(func, transform) {\n return function(arg) {\n return func(transform(arg));\n };\n}\n\nexport default overArg;\n","/**\n * Checks if `value` is object-like. A value is object-like if it's not `null`\n * and has a `typeof` result of \"object\".\n *\n * @static\n * @memberOf _\n * @since 4.0.0\n * @category Lang\n * @param {*} value The value to check.\n * @returns {boolean} Returns `true` if `value` is object-like, else `false`.\n * @example\n *\n * _.isObjectLike({});\n * // => true\n *\n * _.isObjectLike([1, 2, 3]);\n * // => true\n *\n * _.isObjectLike(_.noop);\n * // => false\n *\n * _.isObjectLike(null);\n * // => false\n */\nfunction isObjectLike(value) {\n return value != null && typeof value == 'object';\n}\n\nexport default isObjectLike;\n","/**\n * Removes all key-value entries from the list cache.\n *\n * @private\n * @name clear\n * @memberOf ListCache\n */\nfunction listCacheClear() {\n this.__data__ = [];\n this.size = 0;\n}\n\nexport default listCacheClear;\n","/**\n * Performs a\n * [`SameValueZero`](http://ecma-international.org/ecma-262/7.0/#sec-samevaluezero)\n * comparison between two values to determine if they are equivalent.\n *\n * @static\n * @memberOf _\n * @since 4.0.0\n * @category Lang\n * @param {*} value The value to compare.\n * @param {*} other The other value to compare.\n * @returns {boolean} Returns `true` if the values are equivalent, else `false`.\n * @example\n *\n * var object = { 'a': 1 };\n * var other = { 'a': 1 };\n *\n * _.eq(object, object);\n * // => true\n *\n * _.eq(object, other);\n * // => false\n *\n * _.eq('a', 'a');\n * // => true\n *\n * _.eq('a', Object('a'));\n * // => false\n *\n * _.eq(NaN, NaN);\n * // => true\n */\nfunction eq(value, other) {\n return value === other || (value !== value && other !== other);\n}\n\nexport default eq;\n","/**\n * Removes `key` and its value from the stack.\n *\n * @private\n * @name delete\n * @memberOf Stack\n * @param {string} key The key of the value to remove.\n * @returns {boolean} Returns `true` if the entry was removed, else `false`.\n */\nfunction stackDelete(key) {\n var data = this.__data__,\n result = data['delete'](key);\n\n this.size = data.size;\n return result;\n}\n\nexport default stackDelete;\n","/**\n * Gets the stack value for `key`.\n *\n * @private\n * @name get\n * @memberOf Stack\n * @param {string} key The key of the value to get.\n * @returns {*} Returns the entry value.\n */\nfunction stackGet(key) {\n return this.__data__.get(key);\n}\n\nexport default stackGet;\n","/**\n * Checks if a stack value for `key` exists.\n *\n * @private\n * @name has\n * @memberOf Stack\n * @param {string} key The key of the entry to check.\n * @returns {boolean} Returns `true` if an entry for `key` exists, else `false`.\n */\nfunction stackHas(key) {\n return this.__data__.has(key);\n}\n\nexport default stackHas;\n","/**\n * Checks if `value` is the\n * [language type](http://www.ecma-international.org/ecma-262/7.0/#sec-ecmascript-language-types)\n * of `Object`. (e.g. arrays, functions, objects, regexes, `new Number(0)`, and `new String('')`)\n *\n * @static\n * @memberOf _\n * @since 0.1.0\n * @category Lang\n * @param {*} value The value to check.\n * @returns {boolean} Returns `true` if `value` is an object, else `false`.\n * @example\n *\n * _.isObject({});\n * // => true\n *\n * _.isObject([1, 2, 3]);\n * // => true\n *\n * _.isObject(_.noop);\n * // => true\n *\n * _.isObject(null);\n * // => false\n */\nfunction isObject(value) {\n var type = typeof value;\n return value != null && (type == 'object' || type == 'function');\n}\n\nexport default isObject;\n","/** Used for built-in method references. */\nvar funcProto = Function.prototype;\n\n/** Used to resolve the decompiled source of functions. */\nvar funcToString = funcProto.toString;\n\n/**\n * Converts `func` to its source code.\n *\n * @private\n * @param {Function} func The function to convert.\n * @returns {string} Returns the source code.\n */\nfunction toSource(func) {\n if (func != null) {\n try {\n return funcToString.call(func);\n } catch (e) {}\n try {\n return (func + '');\n } catch (e) {}\n }\n return '';\n}\n\nexport default toSource;\n","/**\n * Gets the value at `key` of `object`.\n *\n * @private\n * @param {Object} [object] The object to query.\n * @param {string} key The key of the property to get.\n * @returns {*} Returns the property value.\n */\nfunction getValue(object, key) {\n return object == null ? undefined : object[key];\n}\n\nexport default getValue;\n","/**\n * Removes `key` and its value from the hash.\n *\n * @private\n * @name delete\n * @memberOf Hash\n * @param {Object} hash The hash to modify.\n * @param {string} key The key of the value to remove.\n * @returns {boolean} Returns `true` if the entry was removed, else `false`.\n */\nfunction hashDelete(key) {\n var result = this.has(key) && delete this.__data__[key];\n this.size -= result ? 1 : 0;\n return result;\n}\n\nexport default hashDelete;\n","/**\n * Checks if `value` is suitable for use as unique object key.\n *\n * @private\n * @param {*} value The value to check.\n * @returns {boolean} Returns `true` if `value` is suitable, else `false`.\n */\nfunction isKeyable(value) {\n var type = typeof value;\n return (type == 'string' || type == 'number' || type == 'symbol' || type == 'boolean')\n ? (value !== '__proto__')\n : (value === null);\n}\n\nexport default isKeyable;\n","/**\n * Creates a base function for methods like `_.forIn` and `_.forOwn`.\n *\n * @private\n * @param {boolean} [fromRight] Specify iterating from right to left.\n * @returns {Function} Returns the new base function.\n */\nfunction createBaseFor(fromRight) {\n return function(object, iteratee, keysFunc) {\n var index = -1,\n iterable = Object(object),\n props = keysFunc(object),\n length = props.length;\n\n while (length--) {\n var key = props[fromRight ? length : ++index];\n if (iteratee(iterable[key], key, iterable) === false) {\n break;\n }\n }\n return object;\n };\n}\n\nexport default createBaseFor;\n","/**\n * Copies the values of `source` to `array`.\n *\n * @private\n * @param {Array} source The array to copy values from.\n * @param {Array} [array=[]] The array to copy values to.\n * @returns {Array} Returns `array`.\n */\nfunction copyArray(source, array) {\n var index = -1,\n length = source.length;\n\n array || (array = Array(length));\n while (++index < length) {\n array[index] = source[index];\n }\n return array;\n}\n\nexport default copyArray;\n","/** Used for built-in method references. */\nvar objectProto = Object.prototype;\n\n/**\n * Checks if `value` is likely a prototype object.\n *\n * @private\n * @param {*} value The value to check.\n * @returns {boolean} Returns `true` if `value` is a prototype, else `false`.\n */\nfunction isPrototype(value) {\n var Ctor = value && value.constructor,\n proto = (typeof Ctor == 'function' && Ctor.prototype) || objectProto;\n\n return value === proto;\n}\n\nexport default isPrototype;\n","/**\n * Checks if `value` is classified as an `Array` object.\n *\n * @static\n * @memberOf _\n * @since 0.1.0\n * @category Lang\n * @param {*} value The value to check.\n * @returns {boolean} Returns `true` if `value` is an array, else `false`.\n * @example\n *\n * _.isArray([1, 2, 3]);\n * // => true\n *\n * _.isArray(document.body.children);\n * // => false\n *\n * _.isArray('abc');\n * // => false\n *\n * _.isArray(_.noop);\n * // => false\n */\nvar isArray = Array.isArray;\n\nexport default isArray;\n","/** Used as references for various `Number` constants. */\nvar MAX_SAFE_INTEGER = 9007199254740991;\n\n/**\n * Checks if `value` is a valid array-like length.\n *\n * **Note:** This method is loosely based on\n * [`ToLength`](http://ecma-international.org/ecma-262/7.0/#sec-tolength).\n *\n * @static\n * @memberOf _\n * @since 4.0.0\n * @category Lang\n * @param {*} value The value to check.\n * @returns {boolean} Returns `true` if `value` is a valid length, else `false`.\n * @example\n *\n * _.isLength(3);\n * // => true\n *\n * _.isLength(Number.MIN_VALUE);\n * // => false\n *\n * _.isLength(Infinity);\n * // => false\n *\n * _.isLength('3');\n * // => false\n */\nfunction isLength(value) {\n return typeof value == 'number' &&\n value > -1 && value % 1 == 0 && value <= MAX_SAFE_INTEGER;\n}\n\nexport default isLength;\n","/**\n * This method returns `false`.\n *\n * @static\n * @memberOf _\n * @since 4.13.0\n * @category Util\n * @returns {boolean} Returns `false`.\n * @example\n *\n * _.times(2, _.stubFalse);\n * // => [false, false]\n */\nfunction stubFalse() {\n return false;\n}\n\nexport default stubFalse;\n","/**\n * The base implementation of `_.unary` without support for storing metadata.\n *\n * @private\n * @param {Function} func The function to cap arguments for.\n * @returns {Function} Returns the new capped function.\n */\nfunction baseUnary(func) {\n return function(value) {\n return func(value);\n };\n}\n\nexport default baseUnary;\n","/**\n * Gets the value at `key`, unless `key` is \"__proto__\" or \"constructor\".\n *\n * @private\n * @param {Object} object The object to query.\n * @param {string} key The key of the property to get.\n * @returns {*} Returns the property value.\n */\nfunction safeGet(object, key) {\n if (key === 'constructor' && typeof object[key] === 'function') {\n return;\n }\n\n if (key == '__proto__') {\n return;\n }\n\n return object[key];\n}\n\nexport default safeGet;\n","/**\n * The base implementation of `_.times` without support for iteratee shorthands\n * or max array length checks.\n *\n * @private\n * @param {number} n The number of times to invoke `iteratee`.\n * @param {Function} iteratee The function invoked per iteration.\n * @returns {Array} Returns the array of results.\n */\nfunction baseTimes(n, iteratee) {\n var index = -1,\n result = Array(n);\n\n while (++index < n) {\n result[index] = iteratee(index);\n }\n return result;\n}\n\nexport default baseTimes;\n","/** Used as references for various `Number` constants. */\nvar MAX_SAFE_INTEGER = 9007199254740991;\n\n/** Used to detect unsigned integer values. */\nvar reIsUint = /^(?:0|[1-9]\\d*)$/;\n\n/**\n * Checks if `value` is a valid array-like index.\n *\n * @private\n * @param {*} value The value to check.\n * @param {number} [length=MAX_SAFE_INTEGER] The upper bounds of a valid index.\n * @returns {boolean} Returns `true` if `value` is a valid index, else `false`.\n */\nfunction isIndex(value, length) {\n var type = typeof value;\n length = length == null ? MAX_SAFE_INTEGER : length;\n\n return !!length &&\n (type == 'number' ||\n (type != 'symbol' && reIsUint.test(value))) &&\n (value > -1 && value % 1 == 0 && value < length);\n}\n\nexport default isIndex;\n","/**\n * This function is like\n * [`Object.keys`](http://ecma-international.org/ecma-262/7.0/#sec-object.keys)\n * except that it includes inherited enumerable properties.\n *\n * @private\n * @param {Object} object The object to query.\n * @returns {Array} Returns the array of property names.\n */\nfunction nativeKeysIn(object) {\n var result = [];\n if (object != null) {\n for (var key in Object(object)) {\n result.push(key);\n }\n }\n return result;\n}\n\nexport default nativeKeysIn;\n","/**\n * This method returns the first argument it receives.\n *\n * @static\n * @since 0.1.0\n * @memberOf _\n * @category Util\n * @param {*} value Any value.\n * @returns {*} Returns `value`.\n * @example\n *\n * var object = { 'a': 1 };\n *\n * console.log(_.identity(object) === object);\n * // => true\n */\nfunction identity(value) {\n return value;\n}\n\nexport default identity;\n","/**\n * A faster alternative to `Function#apply`, this function invokes `func`\n * with the `this` binding of `thisArg` and the arguments of `args`.\n *\n * @private\n * @param {Function} func The function to invoke.\n * @param {*} thisArg The `this` binding of `func`.\n * @param {Array} args The arguments to invoke `func` with.\n * @returns {*} Returns the result of `func`.\n */\nfunction apply(func, thisArg, args) {\n switch (args.length) {\n case 0: return func.call(thisArg);\n case 1: return func.call(thisArg, args[0]);\n case 2: return func.call(thisArg, args[0], args[1]);\n case 3: return func.call(thisArg, args[0], args[1], args[2]);\n }\n return func.apply(thisArg, args);\n}\n\nexport default apply;\n","/**\n * Creates a function that returns `value`.\n *\n * @static\n * @memberOf _\n * @since 2.4.0\n * @category Util\n * @param {*} value The value to return from the new function.\n * @returns {Function} Returns the new constant function.\n * @example\n *\n * var objects = _.times(2, _.constant({ 'a': 1 }));\n *\n * console.log(objects);\n * // => [{ 'a': 1 }, { 'a': 1 }]\n *\n * console.log(objects[0] === objects[1]);\n * // => true\n */\nfunction constant(value) {\n return function() {\n return value;\n };\n}\n\nexport default constant;\n","/** Used to detect hot functions by number of calls within a span of milliseconds. */\nvar HOT_COUNT = 800,\n HOT_SPAN = 16;\n\n/* Built-in method references for those with the same name as other `lodash` methods. */\nvar nativeNow = Date.now;\n\n/**\n * Creates a function that'll short out and invoke `identity` instead\n * of `func` when it's called `HOT_COUNT` or more times in `HOT_SPAN`\n * milliseconds.\n *\n * @private\n * @param {Function} func The function to restrict.\n * @returns {Function} Returns the new shortable function.\n */\nfunction shortOut(func) {\n var count = 0,\n lastCalled = 0;\n\n return function() {\n var stamp = nativeNow(),\n remaining = HOT_SPAN - (stamp - lastCalled);\n\n lastCalled = stamp;\n if (remaining > 0) {\n if (++count >= HOT_COUNT) {\n return arguments[0];\n }\n } else {\n count = 0;\n }\n return func.apply(undefined, arguments);\n };\n}\n\nexport default shortOut;\n","// break it out on its own because\n// it's building from the lodash-es from scratch\n// according to this discussion https://github.com/lodash/lodash/issues/3298\nimport isPlainObject from 'lodash-es/isPlainObject'\nimport merge from 'lodash-es/merge'\n\n/**\n * previously we already make sure the order of the namespaces\n * and attach the auth client to it\n * @param {array} promises array of unresolved promises\n * @param {boolean} asObject if true then merge the result object\n * @return {object} promise resolved with the array of promises resolved results\n */\nexport function chainPromises(promises, asObject = false) {\n return promises.reduce((promiseChain, currentTask) => (\n promiseChain.then(chainResults => (\n currentTask.then(currentResult => (\n asObject === false ? [...chainResults, currentResult] : merge(chainResults, currentResult)\n ))\n ))\n ), Promise.resolve(\n asObject === false ? [] : (isPlainObject(asObject) ? asObject : {})\n ))\n}\n\n\n/**\n * This one return a different result from the chainPromises\n * it will be the same like chainFns that take one promise resolve as the next fn parameter\n * @param {function} initPromise a function that accept param and resolve result\n * @param {array} promises array of function pass that resolve promises\n * @return {promise} resolve the processed result\n */\nexport function chainProcessPromises(initPromise, ...promises) {\n return (...args) => (\n promises.reduce((promiseChain, currentTask) => (\n promiseChain.then(chainResult => (\n currentTask(chainResult)\n )\n )\n ), Reflect.apply(initPromise, null, args))\n )\n}\n","// @BUG when call disconnected \n// this keep causing an \"Disconnect call failed TypeError: Cannot read property 'readyState' of null\"\n// I think that is because it's not login then it can not be disconnect\n// how do we track this state globally\nimport { LOGIN_EVENT_NAME } from 'jsonql-constants'\nimport { clearMainEmitEvt } from '../modules'\n\n/**\n * create a login event handler \n * @param {object} opts configurations \n * @param {object} nspMap contain all the required info\n * @param {object} ee event emitter \n * @return {void}\n */\nexport function loginEventHandler(opts, nspMap, ee) {\n const { log } = opts\n const { namespaces } = nspMap\n\n ee.$only(LOGIN_EVENT_NAME, function loginEventHandlerCallback(tokenFromLoginAction) {\n \n log('createClient LOGIN_EVENT_NAME $only handler')\n\n clearMainEmitEvt(ee, namespaces)\n // console.log('LOGIN_EVENT_NAME', token)\n const newNsps = createNspAction(opts, nspMap, tokenFromLoginAction)\n // rebind it\n Reflect.apply(\n clientEventHandler, // @NOTE is this the problem that cause the hang up?\n null,\n args.concat([newNsps.namespaces, newNsps.nsps])\n )\n })\n}","// bunch of generic helpers\n\nimport isArray from 'lodash-es/isArray'\nimport isPlainObject from 'lodash-es/isPlainObject'\nimport trim from 'lodash-es/trim'\n\n/**\n * DIY in Array\n * @param {array} arr to check from\n * @param {*} value to check against\n * @return {boolean} true on found\n */\nexport const inArray = (arr, value) => !!arr.filter(a => a === value).length\n\n// quick and dirty to turn non array to array\nexport const toArray = (arg) => isArray(arg) ? arg : [arg]\n\n/**\n * parse string to json or just return the original value if error happened\n * @param {*} n input\n * @param {boolean} [t=true] or throw\n * @return {*} json object on success\n */\nexport const parseJson = function(n, t=true) {\n try {\n return JSON.parse(n)\n } catch(e) {\n if (t) {\n return n\n }\n throw new Error(e)\n }\n}\n\n/**\n * @param {object} obj for search\n * @param {string} key target\n * @return {boolean} true on success\n */\nexport const isObjectHasKey = function(obj, key) {\n try {\n const keys = Object.keys(obj)\n return inArray(keys, key)\n } catch(e) {\n // @BUG when the obj is not an OBJECT we got some weird output\n return false\n }\n}\n\n/**\n * create a event name\n * @param {string[]} args\n * @return {string} event name for use\n */\nexport const createEvt = (...args) => args.join('_')\n\n/**\n * simple util method to get the value\n * @param {string} name of the key\n * @param {object} obj to take value from\n * @return {*} the object value id by name or undefined\n */\nexport const getConfigValue = (name, obj) => (\n obj && isPlainObject(obj) ? ( (name in obj) ? obj[name] : undefined ) : undefined\n)\n\n/**\n * small util to make sure the return value is valid JSON object\n * @param {*} n input\n * @return {object} correct JSON object\n */\nexport const toJson = n => {\n if (typeof n === 'string') {\n return parseJson(n)\n }\n return parseJson(JSON.stringify(n))\n}\n\n/**\n * Check several parameter that there is something in the param\n * @param {*} param input\n * @return {boolean}\n */\nexport const isNotEmpty = function(param) {\n return param !== undefined && param !== false && param !== null && trim(param) !== ''\n}\n\n/**\n * Simple check if the prop is function\n * @param {*} prop input\n * @return {boolean} true on success\n */\nexport const isFunc = prop => {\n if (typeof prop === 'function') {\n return true;\n }\n console.error(`Expect to be Function type! Got ${typeof prop}`)\n}\n\n// generic placeholder function\nexport const nil = () => false\n","// custom validation error class\n// when validaton failed\nexport default class JsonqlValidationError extends Error {\n constructor(...args) {\n super(...args)\n\n this.message = args[0]\n this.detail = args[1]\n\n this.className = JsonqlValidationError.name;\n\n if (Error.captureStackTrace) {\n Error.captureStackTrace(this, JsonqlValidationError)\n }\n }\n\n static get name() {\n return 'JsonqlValidationError'\n }\n}\n","/**\n * @param {boolean} sec return in second or not\n * @return {number} timestamp\n */\nexport const timestamp = (sec = false) => {\n let time = Date.now()\n return sec ? Math.floor( time / 1000 ) : time\n}\n","// ported from jsonql-params-validator\n// craete several helper function to construct / extract the payload\n// and make sure they are all the same\nimport {\n PAYLOAD_PARAM_NAME,\n CONDITION_PARAM_NAME,\n RESOLVER_PARAM_NAME,\n QUERY_ARG_NAME,\n TIMESTAMP_PARAM_NAME\n} from 'jsonql-constants'\n\nimport JsonqlValidationError from 'jsonql-errors/src/validation-error'\n\nimport isArray from 'lodash-es/isArray'\nimport isString from 'lodash-es/isString'\nimport isPlainObject from 'lodash-es/isPlainObject'\n\nimport { timestamp } from './timestamp'\nimport { parseJson } from './generic'\n\n/**\n * check if the payload has a timestamp field, then append a new timestamp to it\n * @param {object} payload from the com\n * @return {array} timestamp field with an array value\n */\nexport const handleTimestamp = payload => {\n let ts = payload[TIMESTAMP_PARAM_NAME]\n if (!isArray(ts)) {\n ts = [ts]\n }\n ts.push( timestamp() )\n\n return ts\n}\n\n/**\n * make sure it's an object (it was call formatPayload but it doesn't make sense)\n * @param {*} payload the object comes in could be string based\n * @return {object} the transformed payload\n */\nexport const toPayload = payload => isString(payload) ? parseJson(payload) : payload\n\n/**\n * @param {*} args arguments to send\n *@return {object} formatted payload\n */\nexport const formatPayload = (args) => (\n { [QUERY_ARG_NAME]: args }\n)\n\n/**\n * extract the resolver name from the payload \n * @param {object} payload\n * @return {string} resolver name \n */\nexport function getResolverFromPayload(payload) {\n const keys = Object.keys(payload)\n return keys.filter(key => key !== TIMESTAMP_PARAM_NAME)[0]\n}\n\n/**\n * wrapper method to add the timestamp as well\n * @param {string} resolverName\n * @param {*} payload\n * @return {object} delierable\n */\nexport function createDeliverable(resolverName, payload) {\n return {\n [resolverName]: payload,\n [TIMESTAMP_PARAM_NAME]: [ timestamp() ]\n }\n}\n\n/**\n * @param {string} resolverName name of function\n * @param {array} [args=[]] from the ...args\n * @param {boolean} [jsonp = false] add v1.3.0 to koa\n * @return {object} formatted argument\n */\nexport function createQuery(resolverName, args = [], jsonp = false) {\n if (isString(resolverName) && isArray(args)) {\n let payload = formatPayload(args)\n if (jsonp === true) {\n return payload\n }\n return createDeliverable(resolverName, payload)\n }\n throw new JsonqlValidationError(`[createQuery] expect resolverName to be string and args to be array!`, { resolverName, args })\n}\n\n/**\n * string version of the createQuery\n * @return {string}\n */\nexport function createQueryStr(resolverName, args = [], jsonp = false) {\n return JSON.stringify(createQuery(resolverName, args, jsonp))\n}\n\n/**\n * @param {string} resolverName name of function\n * @param {*} payload to send\n * @param {object} [condition={}] for what\n * @param {boolean} [jsonp = false] add v1.3.0 to koa\n * @return {object} formatted argument\n */\nexport function createMutation(resolverName, payload, condition = {}, jsonp = false) {\n const _payload = {\n [PAYLOAD_PARAM_NAME]: payload,\n [CONDITION_PARAM_NAME]: condition\n }\n if (jsonp === true) {\n return _payload\n }\n if (isString(resolverName)) {\n return createDeliverable(resolverName, _payload)\n }\n throw new JsonqlValidationError(`[createMutation] expect resolverName to be string!`, { resolverName, payload, condition })\n}\n\n/**\n * string version of createMutation\n * @return {string}\n */\nexport function createMutationStr(resolverName, payload, condition = {}, jsonp = false) {\n return JSON.stringify(createMutation(resolverName, payload, condition, jsonp))\n}\n\n/**\n * Extract the parts from payload and format for use\n * @param {string} resolverName name of fn\n * @param {object} payload the incoming json\n * @return {object|boolean} false on failed\n */\nexport function getQueryFromArgs(resolverName, payload) {\n if (resolverName && isPlainObject(payload)) {\n const args = payload[resolverName]\n if (args[QUERY_ARG_NAME]) {\n return {\n [RESOLVER_PARAM_NAME]: resolverName,\n [QUERY_ARG_NAME]: args[QUERY_ARG_NAME],\n [TIMESTAMP_PARAM_NAME]: handleTimestamp(payload)\n }\n }\n }\n return false\n}\n\n/**\n * Share function so no repeat\n * @param {object} payload the payload from client\n * @param {function} processor the last get result method\n * @return {*} result processed result\n */\nfunction processPayload(payload, processor) {\n const p = toPayload(payload)\n const resolverName = getResolverFromPayload(p)\n return Reflect.apply(processor, null, [resolverName, p])\n}\n\n/**\n * extra the payload back\n * @param {*} payload from http call\n * @return {object} resolverName and args\n */\nexport function getQueryFromPayload(payload) {\n const result = processPayload(payload, getQueryFromArgs)\n if (result !== false) {\n return result\n }\n throw new JsonqlValidationError('[getQueryArgs] Payload is malformed!', payload)\n}\n\n/**\n * Further break down from method below for use else where\n * @param {string} resolverName name of fn\n * @param {object} payload payload\n * @return {object|boolean} false on failed\n */\nexport function getMutationFromArgs(resolverName, payload) {\n if (resolverName && isPlainObject(payload)) {\n const args = payload[resolverName]\n if (args) {\n return {\n [RESOLVER_PARAM_NAME]: resolverName,\n [PAYLOAD_PARAM_NAME]: args[PAYLOAD_PARAM_NAME],\n [CONDITION_PARAM_NAME]: args[CONDITION_PARAM_NAME],\n [TIMESTAMP_PARAM_NAME]: handleTimestamp(payload)\n }\n }\n }\n return false\n}\n\n/**\n * @param {object} payload\n * @return {object} resolverName, payload, conditon\n */\nexport function getMutationFromPayload(payload) {\n const result = processPayload(payload, getMutationFromArgs)\n\n if (result !== false) {\n return result\n }\n throw new JsonqlValidationError('[getMutationArgs] Payload is malformed!', payload)\n}\n","// There are the socket related methods ported back from \n// ws-server-core and ws-client-core \nimport {\n WS_REPLY_TYPE,\n WS_EVT_NAME,\n WS_DATA_NAME,\n TIMESTAMP_PARAM_NAME,\n ERROR_KEY,\n EMIT_REPLY_TYPE,\n ACKNOWLEDGE_REPLY_TYPE\n} from 'jsonql-constants'\nimport { JsonqlError } from 'jsonql-errors' \nimport isString from 'lodash-es/isString'\n\nimport { toJson, isObjectHasKey, nil } from './generic'\nimport { timestamp } from './timestamp'\n\nconst PAYLOAD_NOT_DECODED_ERR = 'payload can not decoded'\nconst WS_KEYS = [\n WS_REPLY_TYPE,\n WS_EVT_NAME,\n WS_DATA_NAME\n]\n\n\n/**\n * The ws doesn't have a acknowledge callback like socket.io\n * so we have to DIY one for ws and other that doesn't have it\n * @param {string} type of reply\n * @param {string} resolverName which is replying\n * @param {*} data payload\n * @param {array} [ts= []] the last received ts, if any \n * @return {string} stringify json\n */\nexport const createWsReply = (type, resolverName, data, ts = []) => {\n ts.push(timestamp())\n return JSON.stringify({\n data: {\n [WS_REPLY_TYPE]: type,\n [WS_EVT_NAME]: resolverName,\n [WS_DATA_NAME]: toJson(data)\n },\n [TIMESTAMP_PARAM_NAME]: ts \n })\n}\n\n// extended function \nexport const createReplyMsg = (resolverName, data, ts = []) => (\n createWsReply(EMIT_REPLY_TYPE, resolverName, data, ts)\n)\n\nexport const createAcknowledgeMsg = (resolverName, data, ts = []) => (\n createWsReply(ACKNOWLEDGE_REPLY_TYPE, resolverName, data, ts)\n)\n\n/**\n * @param {string|object} payload should be string when reply but could be transformed\n * @return {boolean} true is OK\n */\nexport const isWsReply = payload => {\n const json = isString(payload) ? toJson(payload) : payload\n const { data } = json\n if (data) {\n let result = WS_KEYS.filter(key => isObjectHasKey(data, key))\n return (result.length === WS_KEYS.length) ? data : false\n }\n return false\n}\n\n/**\n * @param {string|object} data received data\n * @param {function} [cb=nil] this is for extracting the TS field or when it's error\n * @return {object} false on failed\n */\nexport const extractWsPayload = (payload, cb = nil) => {\n try {\n const json = toJson(payload)\n // now handle the data\n let _data\n if ((_data = isWsReply(json)) !== false) {\n // note the ts property is on its own \n cb(TIMESTAMP_PARAM_NAME, json[TIMESTAMP_PARAM_NAME])\n \n return {\n data: toJson(_data[WS_DATA_NAME]),\n resolverName: _data[WS_EVT_NAME],\n type: _data[WS_REPLY_TYPE]\n }\n }\n throw new JsonqlError(PAYLOAD_NOT_DECODED_ERR, payload)\n } catch(e) {\n return cb(ERROR_KEY, e)\n }\n}\n","// the WebSocket main handler\nimport {\n LOGOUT_EVENT_NAME,\n ACKNOWLEDGE_REPLY_TYPE,\n EMIT_REPLY_TYPE,\n ERROR_KEY,\n\n ON_ERROR_FN_NAME,\n ON_MESSAGE_FN_NAME,\n ON_RESULT_FN_NAME,\n ON_READY_FN_NAME,\n ON_LOGIN_FN_NAME\n} from 'jsonql-constants'\nimport {\n createQueryStr,\n createEvt,\n extractWsPayload\n} from 'jsonql-utils/module'\nimport {\n handleNamespaceOnError,\n createIntercomPayload\n} from '../modules'\n\n/**\n * in some edge case we might not even have a resolverName, then\n * we issue a global error for the developer to catch it\n * @param {object} ee event emitter\n * @param {string} namespace nsp\n * @param {string} resolverName resolver\n * @param {object} json decoded payload or error object\n * @return {undefined} nothing return\n */\nconst errorTypeHandler = (ee, namespace, resolverName, json) => {\n let evt = [namespace]\n if (resolverName) {\n evt.push(resolverName)\n }\n evt.push(ON_ERROR_FN_NAME)\n let evtName = Reflect.apply(createEvt, null, evt)\n // test if there is a data field\n let payload = json.data || json\n ee.$trigger(evtName, [payload])\n}\n\n/**\n * Handle the logout event when it's enableAuth\n * @param {object} ee eventEmitter\n * @param {object} ws the WebSocket instance\n * @return {void}\n */\nconst logoutEventListener = (ee, ws) => {\n // listen to the LOGOUT_EVENT_NAME when this is a private nsp\n ee.$on(LOGOUT_EVENT_NAME, function closeEvtHandler() {\n try {\n // @TODO we need find a way to get the userdata\n ws.send(createIntercomPayload(LOGOUT_EVENT_NAME))\n log('terminate ws connection')\n ws.terminate()\n } catch(e) {\n console.error('ws.terminate error', e)\n }\n })\n}\n\n/**\n * Binding the event to socket normally\n * @param {string} namespace\n * @param {object} ws the nsp\n * @param {object} ee EventEmitter\n * @param {boolean} isPrivate to id if this namespace is private or not\n * @param {object} opts configuration\n * @return {object} promise resolve after the onopen event\n */\nexport function bindSocketEventHandler(namespace, ws, ee, isPrivate, opts) {\n const { log } = opts\n let onReadCalls = 2\n // log(`log test, isPrivate:`, isPrivate)\n // connection open\n ws.onopen = function onOpenCallback() {\n\n log('=== ws.onopen listened -->', namespace)\n // we just call the onReady\n ee.$call(ON_READY_FN_NAME)(namespace)\n // we only want to allow it get call twice (number of namespaces)\n --onReadCalls\n if (onReadCalls === 0) {\n ee.$off(ON_READY_FN_NAME)\n }\n\n // need an extra parameter here to id the private nsp\n if (isPrivate) {\n log(`isPrivate and fire the ${ON_LOGIN_FN_NAME}`)\n ee.$call(ON_LOGIN_FN_NAME)(namespace)\n }\n // add listener only after the open is called\n ee.$only(\n createEvt(namespace, EMIT_REPLY_TYPE),\n /**\n * actually send the payload to server\n * @param {string} resolverName\n * @param {array} args NEED TO CHECK HOW WE PASS THIS!\n */\n function wsMainOnEvtHandler(resolverName, args) {\n\n const payload = createQueryStr(resolverName, args)\n log('ws.onopen.send', resolverName, args, payload)\n\n ws.send(payload)\n }\n )\n }\n\n // reply\n // If we change it to the event callback style\n // then the payload will just be the payload and fucks up the extractWsPayload call @TODO\n ws.onmessage = function onMessageCallback(payload) {\n // console.log(`on.message`, typeof payload, payload)\n try {\n // log(`ws.onmessage raw payload`, payload)\n // @TODO the payload actually contain quite a few things - is that changed?\n // type: message, data: data_send_from_server\n const json = extractWsPayload(payload.data)\n const { resolverName, type } = json\n\n log('Respond from server', type, json)\n\n switch (type) {\n case EMIT_REPLY_TYPE:\n let e1 = createEvt(namespace, resolverName, ON_MESSAGE_FN_NAME)\n let r = ee.$trigger(e1, [json])\n log(`EMIT_REPLY_TYPE`, e1, r)\n break\n case ACKNOWLEDGE_REPLY_TYPE:\n let e2 = createEvt(namespace, resolverName, ON_RESULT_FN_NAME)\n let x2 = ee.$trigger(e2, [json])\n log(`ACKNOWLEDGE_REPLY_TYPE`, e2, x2)\n break\n case ERROR_KEY:\n // this is handled error and we won't throw it\n // we need to extract the error from json\n log(`ERROR_KEY`)\n errorTypeHandler(ee, namespace, resolverName, json)\n break\n // @TODO there should be an error type instead of roll into the other two types? TBC\n default:\n // if this happen then we should throw it and halt the operation all together\n log('Unhandled event!', json)\n errorTypeHandler(ee, namespace, resolverName, json)\n // let error = {error: {'message': 'Unhandled event!', type}};\n // ee.$trigger(createEvt(namespace, resolverName, ON_RESULT_FN_NAME), [error])\n }\n } catch(e) {\n console.error(`ws.onmessage error`, e)\n errorTypeHandler(ee, namespace, false, e)\n }\n }\n // when the server close the connection\n ws.onclose = function onCloseCallback() {\n log('ws.onclose callback')\n // @TODO what to do with this\n // ee.$trigger(LOGOUT_EVENT_NAME, [namespace])\n }\n // add a onerror event handler here\n ws.onerror = function onErrorCallback(err) {\n // trigger a global error event\n log(`ws.onerror`, err)\n handleNamespaceOnError(ee, namespace, err)\n }\n\n if (isPrivate) {\n logoutEventListener(ee, ws)\n }\n\n}\n","// actually binding the event client to the socket client\n\n// from the jsonql-ws-client-core\nimport { clientEventListener } from '../modules'\n// local \nimport { createNspAction } from './create-nsp-action'\nimport { loginEventHandler } from './login-event-handler'\nimport { bindSocketEventHandler } from './bind-socket-event-handler'\n\n/**\n * create the NSP(s) and determine if this require auth or not \n * @param {object} opts configuration\n * @param {object} nspMap namespace with resolvers\n * @param {object} ee EventEmitter to pass through\n * @return {object} what comes in what goes out\n */\nfunction createNsp(opts, nspMap, ee) {\n // now create the nsps\n // const { namespaces } = nspMap\n const { token } = opts\n\n return createNspAction(opts, nspMap, token)\n .then(nsps => {\n const listenerFn = clientEventListener(bindSocketEventHandler, nsps)\n // now run it\n listenerFn(opts, nspMap, ee)\n\n if (opts.enableAuth) {\n loginEventHandler(opts, nspMap, ee)\n }\n // return what input\n return { opts, nspMap, ee }\n }) \n}\n\nexport { createNsp }","// breaking up the create-nsp.js file \n// then regroup them back together here \nimport { createNsp } from './create-nsp'\n\nexport default createNsp\n","// share method to create the wsClientResolver\nimport { initWebSocketClient } from './init-websocket-client'\nimport createNsp from '../create-nsp'\nimport { NSP_CLIENT, NSP_AUTH_CLIENT } from 'jsonql-constants'\n\n/**\n * Create the framework <---> jsonql client binding\n * @param {object} frameworkModule the different WebSocket module\n * @return {function} the wsClientResolver\n */\nfunction bindFrameworkToJsonql(frameworkModule) {\n /**\n * wsClientResolver\n * @param {object} opts configuration\n * @param {object} nspMap from the contract\n * @param {object} ee instance of the eventEmitter\n * @return {object} passing the same 3 input out with additional in the opts\n */\n return function createClientBindingAction(opts, nspMap, ee) {\n const { log } = opts\n opts[NSP_CLIENT] = initWebSocketClient(frameworkModule, false, log)\n opts[NSP_AUTH_CLIENT] = initWebSocketClient(frameworkModule, true, log) \n // @1.0.7 remove later once everything fixed \n \n log(`bindFrameworkToJsonql`, ee.name, nspMap)\n // console.log(`contract`, opts.contract)\n return createNsp(opts, nspMap, ee)\n }\n}\n\nexport { bindFrameworkToJsonql }","// this will be the news style interface that will pass to the jsonql-ws-client\n// then return a function for accepting an opts to generate the final\n// client api\nimport WebSocket from 'ws'\nimport createWebSocketBinding from '../core/create-websocket-binding'\n\n/**\n * @param {object} opts configuration\n * @param {object} nspMap from the contract\n * @param {object} ee instance of the eventEmitter\n * @return {object} passing the same 3 input out with additional in the opts\n */\nexport default createWebSocketBinding(WebSocket)\n","// this is the module entry point for node client\nimport {\n wsClientCore\n} from './core/modules'\nimport { wsClientConstProps } from './options'\n\nimport nodeFrameworkSocketEngine from './node/node-framework-socket-engine'\n\n// export back the function and that's it\nexport default function wsNodeClient(config = {}, constProps = {}) {\n const initClientMethod = wsClientCore(\n nodeFrameworkSocketEngine, \n {}, \n Object.assign({}, wsClientConstProps, constProps)\n )\n return initClientMethod(config)\n}\n"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;ACAA;;;;;;;;;ACAA;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;ACAA;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;ACAA;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;"} \ No newline at end of file diff --git a/packages/ws-client-core/src/callers/callers-generator.js b/packages/ws-client-core/src/callers/callers-generator.js index 683e3eb9..814078e7 100644 --- a/packages/ws-client-core/src/callers/callers-generator.js +++ b/packages/ws-client-core/src/callers/callers-generator.js @@ -28,7 +28,7 @@ export function callersGenerator(opts, nspMap, ee) { setupNamespaceErrorListener ] if (opts.enableAuth) { - fns.push(createAuthMethods) + fns.push(setupAuthMethods) } // we will always get back the [ obj, opts, ee ] // then we only return the obj (wsClient) -- Gitee From 77ef0f00f7429fbab49d52d38407bdb3f386cacb Mon Sep 17 00:00:00 2001 From: joelchu Date: Fri, 20 Mar 2020 15:43:16 +0800 Subject: [PATCH 09/11] Found a strange method from now where --- packages/@jsonql/ws/main.js | 129 ++++++++++++++---- packages/@jsonql/ws/main.js.map | 2 +- .../ws/src/core/create-nsp/create-nsp.js | 10 +- ...ent-handler.js => login-event-listener.js} | 14 +- packages/ws-client-core/src/api.js | 5 +- .../src/callers/callers-generator.js | 2 + .../src/callers/setup-final-step.js | 9 +- .../src/listener/client-event-listener.js | 13 +- 8 files changed, 134 insertions(+), 50 deletions(-) rename packages/@jsonql/ws/src/core/create-nsp/{login-event-handler.js => login-event-listener.js} (82%) diff --git a/packages/@jsonql/ws/main.js b/packages/@jsonql/ws/main.js index ba6520ee..ea7a4061 100644 --- a/packages/@jsonql/ws/main.js +++ b/packages/@jsonql/ws/main.js @@ -73,6 +73,7 @@ var TOKEN_PROP_KEY = 'token'; // also it makes the other module easiler to id what they are importing // use throughout the clients var SOCKET_PING_EVENT_NAME = '__ping__'; // when init connection do a ping +var LOGIN_EVENT_NAME = '__login__'; var LOGOUT_EVENT_NAME = '__logout__'; var DISCONNECT_EVENT_NAME = '__disconnect__'; // instead of using an event name in place of resolverName in the param @@ -88,6 +89,7 @@ var ON_MESSAGE_FN_NAME = 'onMessage'; var ON_RESULT_FN_NAME = 'onResult'; var ON_ERROR_FN_NAME = 'onError'; var ON_READY_FN_NAME = 'onReady'; +var ON_LOGIN_FN_NAME = 'onLogin'; // new @1.8.6 // the actual method name client.resolverName.send var SEND_MSG_FN_NAME = 'send'; @@ -6091,6 +6093,7 @@ var getCheckConfigAsync = function(validateSync) { }; // export +var isString$1 = checkIsString; var validateAsync$1 = validateAsync; var createConfig$1 = createConfig; @@ -6175,7 +6178,7 @@ function isRegExp(pat) { * @param {*} arg whatever * @return {boolean} false when it's not */ -function isString$1(arg) { +function isString$2(arg) { return typeof arg === 'string' } @@ -6188,7 +6191,7 @@ function getRegex(pattern) { switch (true) { case isRegExp(pattern) === true: return pattern - case isString$1(pattern) === true: + case isString$2(pattern) === true: return new RegExp(pattern) default: return false @@ -6358,7 +6361,7 @@ var StoreService = /*@__PURE__*/(function (SuspendClass) { while ( len-- ) evt[ len ] = arguments[ len ]; evt.forEach(function (e) { - if (!isString$1(e)) { + if (!isString$2(e)) { this$1.logger('(validateEvt)', e); throw new Error(("Event name must be string type! we got " + (typeof e))) } @@ -7147,6 +7150,90 @@ var clearMainEmitEvt = function (ee, namespace) { }); }; +// take out from the resolver-methods + + +/** + * @TODO this is now become unnecessary because the login is a slave to the + * http-client - but keep this for now and see what we want to do with it later + * @UPDATE it might be better if we decoup the two http-client only emit a login event + * Here should catch it and reload the ws client @TBC + * break out from createAuthMethods to allow chaining call + * @param {object} obj the main client object + * @param {object} opts configuration + * @param {object} ee event emitter + * @return {array} [ obj, opts, ee ] what comes in what goes out + */ +var setupLoginHandler = function (obj, opts, ee) { return [ + injectToFn(obj, opts.loginHandlerName, function loginHandler(token) { + if (token && isString$1(token)) { + opts.log(("Received " + LOGIN_EVENT_NAME + " with " + token)); + // @TODO add the interceptor hook + return ee.$trigger(LOGIN_EVENT_NAME, [token]) + } + // should trigger a global error instead @TODO + throw new JsonqlValidationError(opts.loginHandlerName, ("Unexpected token " + token)) + }), + opts, + ee +]; }; + + +/** + * break out from createAuthMethods to allow chaining call - final in chain + * @param {object} obj the main client object + * @param {object} opts configuration + * @param {object} ee event emitter + * @return {array} [ obj, opts, ee ] what comes in what goes out + */ +var setupLogoutHandler = function (obj, opts, ee) { return [ + injectToFn(obj, opts.logoutHandlerName, function logoutHandler() { + var args = [], len = arguments.length; + while ( len-- ) args[ len ] = arguments[ len ]; + + ee.$trigger(LOGOUT_EVENT_NAME, args); + }), + opts, + ee +]; }; + + +/** + * This event will fire when the socket.io.on('connection') and ws.onopen + * Plus this will check if it's the private namespace that fired the event + * @param {object} obj the client itself + * @param {object} ee Event Emitter + * @return {array} [ obj, opts, ee] what comes in what goes out + */ +var setupOnLoginhandler = function (obj, opts, ee) { return [ + objDefineProps(obj, ON_LOGIN_FN_NAME, function onLoginCallbackHandler(onLoginCallback) { + if (isFunc(onLoginCallback)) { + // only one callback can registered with it, TBC + ee.$only(ON_LOGIN_FN_NAME, onLoginCallback); + } + }), + opts, + ee +]; }; + +// @TODO future feature setup switch user + + +/** + * Create auth related methods + * @param {object} obj the client itself + * @param {object} opts configuration + * @param {object} ee Event Emitter + * @return {array} [ obj, opts, ee ] what comes in what goes out + */ +function setupAuthMethods(obj, opts, ee) { + return chainFns( + setupLoginHandler, + setupLogoutHandler, + setupOnLoginhandler + )(obj, opts, ee) +} + // constants var EMIT_EVT = EMIT_REPLY_TYPE; @@ -7520,7 +7607,7 @@ function callersGenerator(opts, nspMap, ee) { setupNamespaceErrorListener ]; if (opts.enableAuth) { - fns.push(createAuthMethods); + fns.push(setupAuthMethods); } // we will always get back the [ obj, opts, ee ] // then we only return the obj (wsClient) @@ -7563,17 +7650,12 @@ function setupInterCom(client, opts, ee) { /** * The final step to return the client - * @param {object} params wrapper object to call the result forward - * @param {object} params.client the client - * @param {object} params.opts configuration - * @param {object} params.ee the event emitter + * @param {object} obj the client + * @param {object} opts configuration + * @param {object} ee the event emitter * @return {object} client */ -function setupFinalStep(ref) { - var obj = ref.obj; - var opts = ref.opts; - var ee = ref.ee; - +function setupFinalStep(obj, opts, ee) { var client = setupInterCom(obj, opts, ee); @@ -7726,7 +7808,7 @@ function wsClientCoreAction(socketClientListener) { return socketClientListener(opts, nspMap, ee); } ) - .then( // there is problem here, we wrap up the operation inside + .then( function (ref) { var opts = ref.opts; var nspMap = ref.nspMap; @@ -7735,7 +7817,8 @@ function wsClientCoreAction(socketClientListener) { return callersGenerator(opts, nspMap, ee); } ) - .then(setupFinalStep) + // because it returns as an array of params + .then(function (result) { return Reflect.apply(setupFinalStep, null, result); }) .catch(function (err) { console.error("jsonql-ws-core-client init error", err); }) @@ -7956,7 +8039,7 @@ function clientEventListener(bindSocketEventListener, nsps) { var ERROR_KEY$1 = 'error'; var QUERY_ARG_NAME$1 = 'args'; var TIMESTAMP_PARAM_NAME$1 = 'TS'; -var LOGIN_EVENT_NAME = '__login__'; +var LOGIN_EVENT_NAME$1 = '__login__'; var LOGOUT_EVENT_NAME$1 = '__logout__'; // for ws servers var WS_REPLY_TYPE$1 = '__reply__'; @@ -7968,7 +8051,7 @@ var ON_MESSAGE_FN_NAME$1 = 'onMessage'; var ON_RESULT_FN_NAME$1 = 'onResult'; var ON_ERROR_FN_NAME$1 = 'onError'; var ON_READY_FN_NAME$1 = 'onReady'; -var ON_LOGIN_FN_NAME = 'onLogin'; // new @1.8.6 +var ON_LOGIN_FN_NAME$1 = 'onLogin'; // new @1.8.6 // this is somewhat vague about what is suppose to do var EMIT_REPLY_TYPE$1 = 'emit_reply'; @@ -10274,7 +10357,7 @@ function loginEventHandler(opts, nspMap, ee) { var log = opts.log; var namespaces = nspMap.namespaces; - ee.$only(LOGIN_EVENT_NAME, function loginEventHandlerCallback(tokenFromLoginAction) { + ee.$only(LOGIN_EVENT_NAME$1, function loginEventHandlerCallback(tokenFromLoginAction) { log('createClient LOGIN_EVENT_NAME $only handler'); @@ -10471,7 +10554,7 @@ var stringTag$4 = '[object String]'; * _.isString(1); * // => false */ -function isString$2(value) { +function isString$3(value) { return typeof value == 'string' || (!isArray$1(value) && isObjectLike$1(value) && baseGetTag$1(value) == stringTag$4); } @@ -10512,7 +10595,7 @@ function createQuery$1(resolverName, args, jsonp) { if ( args === void 0 ) args = []; if ( jsonp === void 0 ) jsonp = false; - if (isString$2(resolverName) && isArray$1(args)) { + if (isString$3(resolverName) && isArray$1(args)) { var payload = formatPayload$1(args); if (jsonp === true) { return payload @@ -10547,7 +10630,7 @@ var WS_KEYS$1 = [ * @return {boolean} true is OK */ var isWsReply$1 = function (payload) { - var json = isString$2(payload) ? toJson$1(payload) : payload; + var json = isString$3(payload) ? toJson$1(payload) : payload; var data = json.data; if (data) { var result = WS_KEYS$1.filter(function (key) { return isObjectHasKey$2(data, key); }); @@ -10654,8 +10737,8 @@ function bindSocketEventHandler(namespace, ws, ee, isPrivate, opts) { // need an extra parameter here to id the private nsp if (isPrivate) { - log(("isPrivate and fire the " + ON_LOGIN_FN_NAME)); - ee.$call(ON_LOGIN_FN_NAME)(namespace); + log(("isPrivate and fire the " + ON_LOGIN_FN_NAME$1)); + ee.$call(ON_LOGIN_FN_NAME$1)(namespace); } // add listener only after the open is called ee.$only( diff --git a/packages/@jsonql/ws/main.js.map b/packages/@jsonql/ws/main.js.map index 6275e275..57fb7ec0 100644 --- a/packages/@jsonql/ws/main.js.map +++ b/packages/@jsonql/ws/main.js.map @@ -1 +1 @@ -{"version":3,"file":"main.js","sources":["../../ws-client-core/node_modules/lodash-es/isArray.js","node_modules/rollup-plugin-node-globals/src/global.js","../../ws-client-core/node_modules/lodash-es/_objectToString.js","../../ws-client-core/node_modules/lodash-es/_overArg.js","../../ws-client-core/node_modules/lodash-es/isObjectLike.js","../../ws-client-core/node_modules/lodash-es/_arrayMap.js","../../ws-client-core/node_modules/lodash-es/_baseSlice.js","../../ws-client-core/node_modules/lodash-es/_baseFindIndex.js","../../ws-client-core/node_modules/lodash-es/_baseIsNaN.js","../../ws-client-core/node_modules/lodash-es/_strictIndexOf.js","../../ws-client-core/node_modules/lodash-es/_asciiToArray.js","../../ws-client-core/node_modules/lodash-es/_hasUnicode.js","../../ws-client-core/node_modules/lodash-es/_unicodeToArray.js","../../ws-client-core/node_modules/jsonql-utils/src/generic.js","../../ws-client-core/node_modules/lodash-es/_listCacheClear.js","../../ws-client-core/node_modules/lodash-es/eq.js","../../ws-client-core/node_modules/lodash-es/_stackDelete.js","../../ws-client-core/node_modules/lodash-es/_stackGet.js","../../ws-client-core/node_modules/lodash-es/_stackHas.js","../../ws-client-core/node_modules/lodash-es/isObject.js","../../ws-client-core/node_modules/lodash-es/_toSource.js","../../ws-client-core/node_modules/lodash-es/_getValue.js","../../ws-client-core/node_modules/lodash-es/_hashDelete.js","../../ws-client-core/node_modules/lodash-es/_isKeyable.js","../../ws-client-core/node_modules/lodash-es/_createBaseFor.js","../../ws-client-core/node_modules/lodash-es/_copyArray.js","../../ws-client-core/node_modules/lodash-es/_isPrototype.js","../../ws-client-core/node_modules/lodash-es/isLength.js","../../ws-client-core/node_modules/lodash-es/stubFalse.js","../../ws-client-core/node_modules/lodash-es/_baseUnary.js","../../ws-client-core/node_modules/lodash-es/_safeGet.js","../../ws-client-core/node_modules/lodash-es/_baseTimes.js","../../ws-client-core/node_modules/lodash-es/_isIndex.js","../../ws-client-core/node_modules/lodash-es/_nativeKeysIn.js","../../ws-client-core/node_modules/lodash-es/identity.js","../../ws-client-core/node_modules/lodash-es/_apply.js","../../ws-client-core/node_modules/lodash-es/constant.js","../../ws-client-core/node_modules/lodash-es/_shortOut.js","../../ws-client-core/node_modules/jsonql-errors/src/enum-error.js","../../ws-client-core/node_modules/jsonql-errors/src/type-error.js","../../ws-client-core/node_modules/jsonql-errors/src/checker-error.js","../../ws-client-core/node_modules/jsonql-errors/src/validation-error.js","../../ws-client-core/node_modules/jsonql-utils/src/contract.js","../../ws-client-core/node_modules/jsonql-utils/src/timestamp.js","../../ws-client-core/node_modules/jsonql-utils/src/params-api.js","../../ws-client-core/node_modules/jsonql-utils/src/namespace.js","../../ws-client-core/node_modules/jsonql-utils/src/socket.js","../../ws-client-core/src/callers/intercom-methods.js","../../ws-client-core/node_modules/jsonql-params-validator/src/number.js","../../ws-client-core/node_modules/jsonql-params-validator/src/string.js","../../ws-client-core/node_modules/jsonql-params-validator/src/boolean.js","../../ws-client-core/node_modules/jsonql-params-validator/src/any.js","../../ws-client-core/node_modules/jsonql-params-validator/src/constants.js","../../ws-client-core/node_modules/jsonql-params-validator/src/combine.js","../../ws-client-core/node_modules/jsonql-params-validator/src/array.js","../../ws-client-core/node_modules/jsonql-params-validator/src/object.js","../../ws-client-core/node_modules/jsonql-params-validator/src/validator.js","../../ws-client-core/node_modules/lodash-es/_setCacheAdd.js","../../ws-client-core/node_modules/lodash-es/_setCacheHas.js","../../ws-client-core/node_modules/lodash-es/_arraySome.js","../../ws-client-core/node_modules/lodash-es/_cacheHas.js","../../ws-client-core/node_modules/lodash-es/_mapToArray.js","../../ws-client-core/node_modules/lodash-es/_setToArray.js","../../ws-client-core/node_modules/lodash-es/_arrayPush.js","../../ws-client-core/node_modules/lodash-es/_arrayFilter.js","../../ws-client-core/node_modules/lodash-es/stubArray.js","../../ws-client-core/node_modules/lodash-es/_matchesStrictComparable.js","../../ws-client-core/node_modules/lodash-es/_baseHasIn.js","../../ws-client-core/node_modules/lodash-es/_baseProperty.js","../../ws-client-core/node_modules/lodash-es/negate.js","../../ws-client-core/node_modules/lodash-es/_baseFindKey.js","../../ws-client-core/node_modules/jsonql-params-validator/src/is-in-array.js","../../ws-client-core/node_modules/jsonql-params-validator/src/options/run-validation.js","../../ws-client-core/node_modules/jsonql-params-validator/src/options/check-options-async.js","../../ws-client-core/node_modules/jsonql-params-validator/src/options/construct-config.js","../../ws-client-core/node_modules/jsonql-params-validator/src/options/index.js","../../ws-client-core/node_modules/jsonql-params-validator/index.js","../../ws-client-core/src/utils/get-log-fn.js","../../ws-client-core/node_modules/@to1source/event/src/constants.js","../../ws-client-core/node_modules/@to1source/event/src/store.js","../../ws-client-core/node_modules/@to1source/event/src/utils.js","../../ws-client-core/node_modules/@to1source/event/src/suspend.js","../../ws-client-core/node_modules/@to1source/event/src/store-service.js","../../ws-client-core/node_modules/@to1source/event/src/event-service.js","../../ws-client-core/node_modules/@to1source/event/index.js","../../ws-client-core/src/utils/get-event-emitter.js","../../ws-client-core/src/utils/helpers.js","../../ws-client-core/src/options/constants.js","../../ws-client-core/src/callers/respond-handler.js","../../ws-client-core/src/callers/action-call.js","../../ws-client-core/src/callers/setup-send-method.js","../../ws-client-core/src/callers/setup-resolver.js","../../ws-client-core/src/callers/generator-methods.js","../../ws-client-core/src/callers/callers-generator.js","../../ws-client-core/src/callers/setup-intercom.js","../../ws-client-core/src/callers/setup-final-step.js","../../ws-client-core/src/options/index.js","../../ws-client-core/src/api.js","../../ws-client-core/src/listener/create-nsp-clients.js","../../ws-client-core/src/listener/trigger-namespaces-on-error.js","../../ws-client-core/src/listener/event-listeners.js","../../ws-client-core/src/listener/client-event-listener.js","src/options/index.js","src/core/create-websocket-binding/init-websocket-client.js","node_modules/lodash-es/_objectToString.js","node_modules/lodash-es/_overArg.js","node_modules/lodash-es/isObjectLike.js","node_modules/lodash-es/_listCacheClear.js","node_modules/lodash-es/eq.js","node_modules/lodash-es/_stackDelete.js","node_modules/lodash-es/_stackGet.js","node_modules/lodash-es/_stackHas.js","node_modules/lodash-es/isObject.js","node_modules/lodash-es/_toSource.js","node_modules/lodash-es/_getValue.js","node_modules/lodash-es/_hashDelete.js","node_modules/lodash-es/_isKeyable.js","node_modules/lodash-es/_createBaseFor.js","node_modules/lodash-es/_copyArray.js","node_modules/lodash-es/_isPrototype.js","node_modules/lodash-es/isArray.js","node_modules/lodash-es/isLength.js","node_modules/lodash-es/stubFalse.js","node_modules/lodash-es/_baseUnary.js","node_modules/lodash-es/_safeGet.js","node_modules/lodash-es/_baseTimes.js","node_modules/lodash-es/_isIndex.js","node_modules/lodash-es/_nativeKeysIn.js","node_modules/lodash-es/identity.js","node_modules/lodash-es/_apply.js","node_modules/lodash-es/constant.js","node_modules/lodash-es/_shortOut.js","node_modules/jsonql-utils/src/chain-promises.js","src/core/create-nsp/login-event-handler.js","node_modules/jsonql-utils/src/generic.js","node_modules/jsonql-errors/src/validation-error.js","node_modules/jsonql-utils/src/timestamp.js","node_modules/jsonql-utils/src/params-api.js","node_modules/jsonql-utils/src/socket.js","src/core/create-nsp/bind-socket-event-handler.js","src/core/create-nsp/create-nsp.js","src/core/create-nsp/index.js","src/core/create-websocket-binding/bind-framework-to-jsonql.js","src/node/node-framework-socket-engine.js","src/node-ws-client.js"],"sourcesContent":["/**\n * Checks if `value` is classified as an `Array` object.\n *\n * @static\n * @memberOf _\n * @since 0.1.0\n * @category Lang\n * @param {*} value The value to check.\n * @returns {boolean} Returns `true` if `value` is an array, else `false`.\n * @example\n *\n * _.isArray([1, 2, 3]);\n * // => true\n *\n * _.isArray(document.body.children);\n * // => false\n *\n * _.isArray('abc');\n * // => false\n *\n * _.isArray(_.noop);\n * // => false\n */\nvar isArray = Array.isArray;\n\nexport default isArray;\n","export default (typeof global !== \"undefined\" ? global :\n typeof self !== \"undefined\" ? self :\n typeof window !== \"undefined\" ? window : {});\n","/** Used for built-in method references. */\nvar objectProto = Object.prototype;\n\n/**\n * Used to resolve the\n * [`toStringTag`](http://ecma-international.org/ecma-262/7.0/#sec-object.prototype.tostring)\n * of values.\n */\nvar nativeObjectToString = objectProto.toString;\n\n/**\n * Converts `value` to a string using `Object.prototype.toString`.\n *\n * @private\n * @param {*} value The value to convert.\n * @returns {string} Returns the converted string.\n */\nfunction objectToString(value) {\n return nativeObjectToString.call(value);\n}\n\nexport default objectToString;\n","/**\n * Creates a unary function that invokes `func` with its argument transformed.\n *\n * @private\n * @param {Function} func The function to wrap.\n * @param {Function} transform The argument transform.\n * @returns {Function} Returns the new function.\n */\nfunction overArg(func, transform) {\n return function(arg) {\n return func(transform(arg));\n };\n}\n\nexport default overArg;\n","/**\n * Checks if `value` is object-like. A value is object-like if it's not `null`\n * and has a `typeof` result of \"object\".\n *\n * @static\n * @memberOf _\n * @since 4.0.0\n * @category Lang\n * @param {*} value The value to check.\n * @returns {boolean} Returns `true` if `value` is object-like, else `false`.\n * @example\n *\n * _.isObjectLike({});\n * // => true\n *\n * _.isObjectLike([1, 2, 3]);\n * // => true\n *\n * _.isObjectLike(_.noop);\n * // => false\n *\n * _.isObjectLike(null);\n * // => false\n */\nfunction isObjectLike(value) {\n return value != null && typeof value == 'object';\n}\n\nexport default isObjectLike;\n","/**\n * A specialized version of `_.map` for arrays without support for iteratee\n * shorthands.\n *\n * @private\n * @param {Array} [array] The array to iterate over.\n * @param {Function} iteratee The function invoked per iteration.\n * @returns {Array} Returns the new mapped array.\n */\nfunction arrayMap(array, iteratee) {\n var index = -1,\n length = array == null ? 0 : array.length,\n result = Array(length);\n\n while (++index < length) {\n result[index] = iteratee(array[index], index, array);\n }\n return result;\n}\n\nexport default arrayMap;\n","/**\n * The base implementation of `_.slice` without an iteratee call guard.\n *\n * @private\n * @param {Array} array The array to slice.\n * @param {number} [start=0] The start position.\n * @param {number} [end=array.length] The end position.\n * @returns {Array} Returns the slice of `array`.\n */\nfunction baseSlice(array, start, end) {\n var index = -1,\n length = array.length;\n\n if (start < 0) {\n start = -start > length ? 0 : (length + start);\n }\n end = end > length ? length : end;\n if (end < 0) {\n end += length;\n }\n length = start > end ? 0 : ((end - start) >>> 0);\n start >>>= 0;\n\n var result = Array(length);\n while (++index < length) {\n result[index] = array[index + start];\n }\n return result;\n}\n\nexport default baseSlice;\n","/**\n * The base implementation of `_.findIndex` and `_.findLastIndex` without\n * support for iteratee shorthands.\n *\n * @private\n * @param {Array} array The array to inspect.\n * @param {Function} predicate The function invoked per iteration.\n * @param {number} fromIndex The index to search from.\n * @param {boolean} [fromRight] Specify iterating from right to left.\n * @returns {number} Returns the index of the matched value, else `-1`.\n */\nfunction baseFindIndex(array, predicate, fromIndex, fromRight) {\n var length = array.length,\n index = fromIndex + (fromRight ? 1 : -1);\n\n while ((fromRight ? index-- : ++index < length)) {\n if (predicate(array[index], index, array)) {\n return index;\n }\n }\n return -1;\n}\n\nexport default baseFindIndex;\n","/**\n * The base implementation of `_.isNaN` without support for number objects.\n *\n * @private\n * @param {*} value The value to check.\n * @returns {boolean} Returns `true` if `value` is `NaN`, else `false`.\n */\nfunction baseIsNaN(value) {\n return value !== value;\n}\n\nexport default baseIsNaN;\n","/**\n * A specialized version of `_.indexOf` which performs strict equality\n * comparisons of values, i.e. `===`.\n *\n * @private\n * @param {Array} array The array to inspect.\n * @param {*} value The value to search for.\n * @param {number} fromIndex The index to search from.\n * @returns {number} Returns the index of the matched value, else `-1`.\n */\nfunction strictIndexOf(array, value, fromIndex) {\n var index = fromIndex - 1,\n length = array.length;\n\n while (++index < length) {\n if (array[index] === value) {\n return index;\n }\n }\n return -1;\n}\n\nexport default strictIndexOf;\n","/**\n * Converts an ASCII `string` to an array.\n *\n * @private\n * @param {string} string The string to convert.\n * @returns {Array} Returns the converted array.\n */\nfunction asciiToArray(string) {\n return string.split('');\n}\n\nexport default asciiToArray;\n","/** Used to compose unicode character classes. */\nvar rsAstralRange = '\\\\ud800-\\\\udfff',\n rsComboMarksRange = '\\\\u0300-\\\\u036f',\n reComboHalfMarksRange = '\\\\ufe20-\\\\ufe2f',\n rsComboSymbolsRange = '\\\\u20d0-\\\\u20ff',\n rsComboRange = rsComboMarksRange + reComboHalfMarksRange + rsComboSymbolsRange,\n rsVarRange = '\\\\ufe0e\\\\ufe0f';\n\n/** Used to compose unicode capture groups. */\nvar rsZWJ = '\\\\u200d';\n\n/** Used to detect strings with [zero-width joiners or code points from the astral planes](http://eev.ee/blog/2015/09/12/dark-corners-of-unicode/). */\nvar reHasUnicode = RegExp('[' + rsZWJ + rsAstralRange + rsComboRange + rsVarRange + ']');\n\n/**\n * Checks if `string` contains Unicode symbols.\n *\n * @private\n * @param {string} string The string to inspect.\n * @returns {boolean} Returns `true` if a symbol is found, else `false`.\n */\nfunction hasUnicode(string) {\n return reHasUnicode.test(string);\n}\n\nexport default hasUnicode;\n","/** Used to compose unicode character classes. */\nvar rsAstralRange = '\\\\ud800-\\\\udfff',\n rsComboMarksRange = '\\\\u0300-\\\\u036f',\n reComboHalfMarksRange = '\\\\ufe20-\\\\ufe2f',\n rsComboSymbolsRange = '\\\\u20d0-\\\\u20ff',\n rsComboRange = rsComboMarksRange + reComboHalfMarksRange + rsComboSymbolsRange,\n rsVarRange = '\\\\ufe0e\\\\ufe0f';\n\n/** Used to compose unicode capture groups. */\nvar rsAstral = '[' + rsAstralRange + ']',\n rsCombo = '[' + rsComboRange + ']',\n rsFitz = '\\\\ud83c[\\\\udffb-\\\\udfff]',\n rsModifier = '(?:' + rsCombo + '|' + rsFitz + ')',\n rsNonAstral = '[^' + rsAstralRange + ']',\n rsRegional = '(?:\\\\ud83c[\\\\udde6-\\\\uddff]){2}',\n rsSurrPair = '[\\\\ud800-\\\\udbff][\\\\udc00-\\\\udfff]',\n rsZWJ = '\\\\u200d';\n\n/** Used to compose unicode regexes. */\nvar reOptMod = rsModifier + '?',\n rsOptVar = '[' + rsVarRange + ']?',\n rsOptJoin = '(?:' + rsZWJ + '(?:' + [rsNonAstral, rsRegional, rsSurrPair].join('|') + ')' + rsOptVar + reOptMod + ')*',\n rsSeq = rsOptVar + reOptMod + rsOptJoin,\n rsSymbol = '(?:' + [rsNonAstral + rsCombo + '?', rsCombo, rsRegional, rsSurrPair, rsAstral].join('|') + ')';\n\n/** Used to match [string symbols](https://mathiasbynens.be/notes/javascript-unicode). */\nvar reUnicode = RegExp(rsFitz + '(?=' + rsFitz + ')|' + rsSymbol + rsSeq, 'g');\n\n/**\n * Converts a Unicode `string` to an array.\n *\n * @private\n * @param {string} string The string to convert.\n * @returns {Array} Returns the converted array.\n */\nfunction unicodeToArray(string) {\n return string.match(reUnicode) || [];\n}\n\nexport default unicodeToArray;\n","// bunch of generic helpers\n\nimport isArray from 'lodash-es/isArray'\nimport isPlainObject from 'lodash-es/isPlainObject'\nimport trim from 'lodash-es/trim'\n\n/**\n * DIY in Array\n * @param {array} arr to check from\n * @param {*} value to check against\n * @return {boolean} true on found\n */\nexport const inArray = (arr, value) => !!arr.filter(a => a === value).length\n\n// quick and dirty to turn non array to array\nexport const toArray = (arg) => isArray(arg) ? arg : [arg]\n\n/**\n * parse string to json or just return the original value if error happened\n * @param {*} n input\n * @param {boolean} [t=true] or throw\n * @return {*} json object on success\n */\nexport const parseJson = function(n, t=true) {\n try {\n return JSON.parse(n)\n } catch(e) {\n if (t) {\n return n\n }\n throw new Error(e)\n }\n}\n\n/**\n * @param {object} obj for search\n * @param {string} key target\n * @return {boolean} true on success\n */\nexport const isObjectHasKey = function(obj, key) {\n try {\n const keys = Object.keys(obj)\n return inArray(keys, key)\n } catch(e) {\n // @BUG when the obj is not an OBJECT we got some weird output\n return false\n }\n}\n\n/**\n * create a event name\n * @param {string[]} args\n * @return {string} event name for use\n */\nexport const createEvt = (...args) => args.join('_')\n\n/**\n * simple util method to get the value\n * @param {string} name of the key\n * @param {object} obj to take value from\n * @return {*} the object value id by name or undefined\n */\nexport const getConfigValue = (name, obj) => (\n obj && isPlainObject(obj) ? ( (name in obj) ? obj[name] : undefined ) : undefined\n)\n\n/**\n * small util to make sure the return value is valid JSON object\n * @param {*} n input\n * @return {object} correct JSON object\n */\nexport const toJson = n => {\n if (typeof n === 'string') {\n return parseJson(n)\n }\n return parseJson(JSON.stringify(n))\n}\n\n/**\n * Check several parameter that there is something in the param\n * @param {*} param input\n * @return {boolean}\n */\nexport const isNotEmpty = function(param) {\n return param !== undefined && param !== false && param !== null && trim(param) !== ''\n}\n\n/**\n * Simple check if the prop is function\n * @param {*} prop input\n * @return {boolean} true on success\n */\nexport const isFunc = prop => {\n if (typeof prop === 'function') {\n return true;\n }\n console.error(`Expect to be Function type! Got ${typeof prop}`)\n}\n\n/**\n * Shorthand method for Object.assign \n * @param {array} args \n * @return {object} merge together object by key \n */\nexport const assign = (...args) => Reflect.apply(Object.assign, Object, args)\n \n/** \n * generic placeholder function\n * @return {boolean} false \n */\nexport const nil = () => false\n\n/**\n * generic turn config into immutatble \n */\nexport const freeze = config => Object.freeze(config)","/**\n * Removes all key-value entries from the list cache.\n *\n * @private\n * @name clear\n * @memberOf ListCache\n */\nfunction listCacheClear() {\n this.__data__ = [];\n this.size = 0;\n}\n\nexport default listCacheClear;\n","/**\n * Performs a\n * [`SameValueZero`](http://ecma-international.org/ecma-262/7.0/#sec-samevaluezero)\n * comparison between two values to determine if they are equivalent.\n *\n * @static\n * @memberOf _\n * @since 4.0.0\n * @category Lang\n * @param {*} value The value to compare.\n * @param {*} other The other value to compare.\n * @returns {boolean} Returns `true` if the values are equivalent, else `false`.\n * @example\n *\n * var object = { 'a': 1 };\n * var other = { 'a': 1 };\n *\n * _.eq(object, object);\n * // => true\n *\n * _.eq(object, other);\n * // => false\n *\n * _.eq('a', 'a');\n * // => true\n *\n * _.eq('a', Object('a'));\n * // => false\n *\n * _.eq(NaN, NaN);\n * // => true\n */\nfunction eq(value, other) {\n return value === other || (value !== value && other !== other);\n}\n\nexport default eq;\n","/**\n * Removes `key` and its value from the stack.\n *\n * @private\n * @name delete\n * @memberOf Stack\n * @param {string} key The key of the value to remove.\n * @returns {boolean} Returns `true` if the entry was removed, else `false`.\n */\nfunction stackDelete(key) {\n var data = this.__data__,\n result = data['delete'](key);\n\n this.size = data.size;\n return result;\n}\n\nexport default stackDelete;\n","/**\n * Gets the stack value for `key`.\n *\n * @private\n * @name get\n * @memberOf Stack\n * @param {string} key The key of the value to get.\n * @returns {*} Returns the entry value.\n */\nfunction stackGet(key) {\n return this.__data__.get(key);\n}\n\nexport default stackGet;\n","/**\n * Checks if a stack value for `key` exists.\n *\n * @private\n * @name has\n * @memberOf Stack\n * @param {string} key The key of the entry to check.\n * @returns {boolean} Returns `true` if an entry for `key` exists, else `false`.\n */\nfunction stackHas(key) {\n return this.__data__.has(key);\n}\n\nexport default stackHas;\n","/**\n * Checks if `value` is the\n * [language type](http://www.ecma-international.org/ecma-262/7.0/#sec-ecmascript-language-types)\n * of `Object`. (e.g. arrays, functions, objects, regexes, `new Number(0)`, and `new String('')`)\n *\n * @static\n * @memberOf _\n * @since 0.1.0\n * @category Lang\n * @param {*} value The value to check.\n * @returns {boolean} Returns `true` if `value` is an object, else `false`.\n * @example\n *\n * _.isObject({});\n * // => true\n *\n * _.isObject([1, 2, 3]);\n * // => true\n *\n * _.isObject(_.noop);\n * // => true\n *\n * _.isObject(null);\n * // => false\n */\nfunction isObject(value) {\n var type = typeof value;\n return value != null && (type == 'object' || type == 'function');\n}\n\nexport default isObject;\n","/** Used for built-in method references. */\nvar funcProto = Function.prototype;\n\n/** Used to resolve the decompiled source of functions. */\nvar funcToString = funcProto.toString;\n\n/**\n * Converts `func` to its source code.\n *\n * @private\n * @param {Function} func The function to convert.\n * @returns {string} Returns the source code.\n */\nfunction toSource(func) {\n if (func != null) {\n try {\n return funcToString.call(func);\n } catch (e) {}\n try {\n return (func + '');\n } catch (e) {}\n }\n return '';\n}\n\nexport default toSource;\n","/**\n * Gets the value at `key` of `object`.\n *\n * @private\n * @param {Object} [object] The object to query.\n * @param {string} key The key of the property to get.\n * @returns {*} Returns the property value.\n */\nfunction getValue(object, key) {\n return object == null ? undefined : object[key];\n}\n\nexport default getValue;\n","/**\n * Removes `key` and its value from the hash.\n *\n * @private\n * @name delete\n * @memberOf Hash\n * @param {Object} hash The hash to modify.\n * @param {string} key The key of the value to remove.\n * @returns {boolean} Returns `true` if the entry was removed, else `false`.\n */\nfunction hashDelete(key) {\n var result = this.has(key) && delete this.__data__[key];\n this.size -= result ? 1 : 0;\n return result;\n}\n\nexport default hashDelete;\n","/**\n * Checks if `value` is suitable for use as unique object key.\n *\n * @private\n * @param {*} value The value to check.\n * @returns {boolean} Returns `true` if `value` is suitable, else `false`.\n */\nfunction isKeyable(value) {\n var type = typeof value;\n return (type == 'string' || type == 'number' || type == 'symbol' || type == 'boolean')\n ? (value !== '__proto__')\n : (value === null);\n}\n\nexport default isKeyable;\n","/**\n * Creates a base function for methods like `_.forIn` and `_.forOwn`.\n *\n * @private\n * @param {boolean} [fromRight] Specify iterating from right to left.\n * @returns {Function} Returns the new base function.\n */\nfunction createBaseFor(fromRight) {\n return function(object, iteratee, keysFunc) {\n var index = -1,\n iterable = Object(object),\n props = keysFunc(object),\n length = props.length;\n\n while (length--) {\n var key = props[fromRight ? length : ++index];\n if (iteratee(iterable[key], key, iterable) === false) {\n break;\n }\n }\n return object;\n };\n}\n\nexport default createBaseFor;\n","/**\n * Copies the values of `source` to `array`.\n *\n * @private\n * @param {Array} source The array to copy values from.\n * @param {Array} [array=[]] The array to copy values to.\n * @returns {Array} Returns `array`.\n */\nfunction copyArray(source, array) {\n var index = -1,\n length = source.length;\n\n array || (array = Array(length));\n while (++index < length) {\n array[index] = source[index];\n }\n return array;\n}\n\nexport default copyArray;\n","/** Used for built-in method references. */\nvar objectProto = Object.prototype;\n\n/**\n * Checks if `value` is likely a prototype object.\n *\n * @private\n * @param {*} value The value to check.\n * @returns {boolean} Returns `true` if `value` is a prototype, else `false`.\n */\nfunction isPrototype(value) {\n var Ctor = value && value.constructor,\n proto = (typeof Ctor == 'function' && Ctor.prototype) || objectProto;\n\n return value === proto;\n}\n\nexport default isPrototype;\n","/** Used as references for various `Number` constants. */\nvar MAX_SAFE_INTEGER = 9007199254740991;\n\n/**\n * Checks if `value` is a valid array-like length.\n *\n * **Note:** This method is loosely based on\n * [`ToLength`](http://ecma-international.org/ecma-262/7.0/#sec-tolength).\n *\n * @static\n * @memberOf _\n * @since 4.0.0\n * @category Lang\n * @param {*} value The value to check.\n * @returns {boolean} Returns `true` if `value` is a valid length, else `false`.\n * @example\n *\n * _.isLength(3);\n * // => true\n *\n * _.isLength(Number.MIN_VALUE);\n * // => false\n *\n * _.isLength(Infinity);\n * // => false\n *\n * _.isLength('3');\n * // => false\n */\nfunction isLength(value) {\n return typeof value == 'number' &&\n value > -1 && value % 1 == 0 && value <= MAX_SAFE_INTEGER;\n}\n\nexport default isLength;\n","/**\n * This method returns `false`.\n *\n * @static\n * @memberOf _\n * @since 4.13.0\n * @category Util\n * @returns {boolean} Returns `false`.\n * @example\n *\n * _.times(2, _.stubFalse);\n * // => [false, false]\n */\nfunction stubFalse() {\n return false;\n}\n\nexport default stubFalse;\n","/**\n * The base implementation of `_.unary` without support for storing metadata.\n *\n * @private\n * @param {Function} func The function to cap arguments for.\n * @returns {Function} Returns the new capped function.\n */\nfunction baseUnary(func) {\n return function(value) {\n return func(value);\n };\n}\n\nexport default baseUnary;\n","/**\n * Gets the value at `key`, unless `key` is \"__proto__\" or \"constructor\".\n *\n * @private\n * @param {Object} object The object to query.\n * @param {string} key The key of the property to get.\n * @returns {*} Returns the property value.\n */\nfunction safeGet(object, key) {\n if (key === 'constructor' && typeof object[key] === 'function') {\n return;\n }\n\n if (key == '__proto__') {\n return;\n }\n\n return object[key];\n}\n\nexport default safeGet;\n","/**\n * The base implementation of `_.times` without support for iteratee shorthands\n * or max array length checks.\n *\n * @private\n * @param {number} n The number of times to invoke `iteratee`.\n * @param {Function} iteratee The function invoked per iteration.\n * @returns {Array} Returns the array of results.\n */\nfunction baseTimes(n, iteratee) {\n var index = -1,\n result = Array(n);\n\n while (++index < n) {\n result[index] = iteratee(index);\n }\n return result;\n}\n\nexport default baseTimes;\n","/** Used as references for various `Number` constants. */\nvar MAX_SAFE_INTEGER = 9007199254740991;\n\n/** Used to detect unsigned integer values. */\nvar reIsUint = /^(?:0|[1-9]\\d*)$/;\n\n/**\n * Checks if `value` is a valid array-like index.\n *\n * @private\n * @param {*} value The value to check.\n * @param {number} [length=MAX_SAFE_INTEGER] The upper bounds of a valid index.\n * @returns {boolean} Returns `true` if `value` is a valid index, else `false`.\n */\nfunction isIndex(value, length) {\n var type = typeof value;\n length = length == null ? MAX_SAFE_INTEGER : length;\n\n return !!length &&\n (type == 'number' ||\n (type != 'symbol' && reIsUint.test(value))) &&\n (value > -1 && value % 1 == 0 && value < length);\n}\n\nexport default isIndex;\n","/**\n * This function is like\n * [`Object.keys`](http://ecma-international.org/ecma-262/7.0/#sec-object.keys)\n * except that it includes inherited enumerable properties.\n *\n * @private\n * @param {Object} object The object to query.\n * @returns {Array} Returns the array of property names.\n */\nfunction nativeKeysIn(object) {\n var result = [];\n if (object != null) {\n for (var key in Object(object)) {\n result.push(key);\n }\n }\n return result;\n}\n\nexport default nativeKeysIn;\n","/**\n * This method returns the first argument it receives.\n *\n * @static\n * @since 0.1.0\n * @memberOf _\n * @category Util\n * @param {*} value Any value.\n * @returns {*} Returns `value`.\n * @example\n *\n * var object = { 'a': 1 };\n *\n * console.log(_.identity(object) === object);\n * // => true\n */\nfunction identity(value) {\n return value;\n}\n\nexport default identity;\n","/**\n * A faster alternative to `Function#apply`, this function invokes `func`\n * with the `this` binding of `thisArg` and the arguments of `args`.\n *\n * @private\n * @param {Function} func The function to invoke.\n * @param {*} thisArg The `this` binding of `func`.\n * @param {Array} args The arguments to invoke `func` with.\n * @returns {*} Returns the result of `func`.\n */\nfunction apply(func, thisArg, args) {\n switch (args.length) {\n case 0: return func.call(thisArg);\n case 1: return func.call(thisArg, args[0]);\n case 2: return func.call(thisArg, args[0], args[1]);\n case 3: return func.call(thisArg, args[0], args[1], args[2]);\n }\n return func.apply(thisArg, args);\n}\n\nexport default apply;\n","/**\n * Creates a function that returns `value`.\n *\n * @static\n * @memberOf _\n * @since 2.4.0\n * @category Util\n * @param {*} value The value to return from the new function.\n * @returns {Function} Returns the new constant function.\n * @example\n *\n * var objects = _.times(2, _.constant({ 'a': 1 }));\n *\n * console.log(objects);\n * // => [{ 'a': 1 }, { 'a': 1 }]\n *\n * console.log(objects[0] === objects[1]);\n * // => true\n */\nfunction constant(value) {\n return function() {\n return value;\n };\n}\n\nexport default constant;\n","/** Used to detect hot functions by number of calls within a span of milliseconds. */\nvar HOT_COUNT = 800,\n HOT_SPAN = 16;\n\n/* Built-in method references for those with the same name as other `lodash` methods. */\nvar nativeNow = Date.now;\n\n/**\n * Creates a function that'll short out and invoke `identity` instead\n * of `func` when it's called `HOT_COUNT` or more times in `HOT_SPAN`\n * milliseconds.\n *\n * @private\n * @param {Function} func The function to restrict.\n * @returns {Function} Returns the new shortable function.\n */\nfunction shortOut(func) {\n var count = 0,\n lastCalled = 0;\n\n return function() {\n var stamp = nativeNow(),\n remaining = HOT_SPAN - (stamp - lastCalled);\n\n lastCalled = stamp;\n if (remaining > 0) {\n if (++count >= HOT_COUNT) {\n return arguments[0];\n }\n } else {\n count = 0;\n }\n return func.apply(undefined, arguments);\n };\n}\n\nexport default shortOut;\n","// this get throw from within the checkOptions when run through the enum failed\nexport default class JsonqlEnumError extends Error {\n constructor(...args) {\n super(...args)\n\n this.message = args[0]\n this.detail = args[1]\n\n this.className = JsonqlEnumError.name;\n\n if (Error.captureStackTrace) {\n Error.captureStackTrace(this, JsonqlEnumError)\n }\n }\n\n static get name() {\n return 'JsonqlEnumError'\n }\n}\n","// this will throw from inside the checkOptions\nexport default class JsonqlTypeError extends Error {\n constructor(...args) {\n super(...args)\n\n this.message = args[0]\n this.detail = args[1]\n\n this.className = JsonqlTypeError.name\n\n if (Error.captureStackTrace) {\n Error.captureStackTrace(this, JsonqlTypeError)\n }\n }\n\n static get name() {\n return 'JsonqlTypeError'\n }\n}\n","// allow supply a custom checker function\n// if that failed then we throw this error\nexport default class JsonqlCheckerError extends Error {\n constructor(...args) {\n super(...args)\n this.message = args[0]\n this.detail = args[1]\n\n this.className = JsonqlCheckerError.name;\n\n if (Error.captureStackTrace) {\n Error.captureStackTrace(this, JsonqlCheckerError)\n }\n }\n\n static get name() {\n return 'JsonqlCheckerError'\n }\n}\n","// custom validation error class\n// when validaton failed\nexport default class JsonqlValidationError extends Error {\n constructor(...args) {\n super(...args)\n\n this.message = args[0]\n this.detail = args[1]\n\n this.className = JsonqlValidationError.name;\n\n if (Error.captureStackTrace) {\n Error.captureStackTrace(this, JsonqlValidationError)\n }\n }\n\n static get name() {\n return 'JsonqlValidationError'\n }\n}\n","// split the contract into the node side and the generic side\nimport { isObjectHasKey } from './generic'\nimport isPlainObject from 'lodash-es/isPlainObject'\nimport {\n QUERY_NAME,\n MUTATION_NAME,\n SOCKET_NAME,\n QUERY_ARG_NAME,\n PAYLOAD_PARAM_NAME,\n CONDITION_PARAM_NAME\n} from 'jsonql-constants'\nimport { JsonqlError, JsonqlResolverNotFoundError } from 'jsonql-errors'\n/**\n * Check if the json is a contract file or not\n * @param {object} contract json object\n * @return {boolean} true\n */\nexport function checkIsContract(contract) {\n return isPlainObject(contract)\n && (\n isObjectHasKey(contract, QUERY_NAME)\n || isObjectHasKey(contract, MUTATION_NAME)\n || isObjectHasKey(contract, SOCKET_NAME)\n )\n}\n\n/**\n * Wrapper method that check if it's contract then return the contract or false\n * @param {object} contract the object to check\n * @return {boolean | object} false when it's not\n */\nexport function isContract(contract) {\n return checkIsContract(contract) ? contract : false\n}\n\n/**\n * Ported from jsonql-params-validator but different\n * if we don't find the socket part then return false\n * @param {object} contract the contract object\n * @return {object|boolean} false on failed\n */\nexport function extractSocketPart(contract) {\n if (isObjectHasKey(contract, SOCKET_NAME)) {\n return contract[SOCKET_NAME]\n }\n return false\n}\n\n/**\n * Extract the args from the payload\n * @param {object} payload to work with\n * @param {string} type of call\n * @return {array} args\n */\nexport function extractArgsFromPayload(payload, type) {\n switch (type) {\n case QUERY_NAME:\n return payload[QUERY_ARG_NAME]\n case MUTATION_NAME:\n return [\n payload[PAYLOAD_PARAM_NAME],\n payload[CONDITION_PARAM_NAME]\n ]\n default:\n throw new JsonqlError(`Unknown ${type} to extract argument from!`)\n }\n}\n\n/**\n * Like what the name said\n * @param {object} contract the contract json\n * @param {string} type query|mutation\n * @param {string} name of the function\n * @return {object} the params part of the contract\n */\nexport function extractParamsFromContract(contract, type, name) {\n try {\n const result = contract[type][name]\n // debug('extractParamsFromContract', result)\n if (!result) {\n // debug(name, type, contract)\n throw new JsonqlResolverNotFoundError(name, type)\n }\n return result\n } catch(e) {\n throw new JsonqlResolverNotFoundError(name, e)\n }\n}\n","/**\n * @param {boolean} sec return in second or not\n * @return {number} timestamp\n */\nexport const timestamp = (sec = false) => {\n let time = Date.now()\n return sec ? Math.floor( time / 1000 ) : time\n}\n","// ported from jsonql-params-validator\n// craete several helper function to construct / extract the payload\n// and make sure they are all the same\nimport {\n PAYLOAD_PARAM_NAME,\n CONDITION_PARAM_NAME,\n RESOLVER_PARAM_NAME,\n QUERY_ARG_NAME,\n TIMESTAMP_PARAM_NAME\n} from 'jsonql-constants'\n\nimport JsonqlValidationError from 'jsonql-errors/src/validation-error'\n\nimport isArray from 'lodash-es/isArray'\nimport isString from 'lodash-es/isString'\nimport isPlainObject from 'lodash-es/isPlainObject'\n\nimport { timestamp } from './timestamp'\nimport { parseJson } from './generic'\n\n/**\n * check if the payload has a timestamp field, then append a new timestamp to it\n * @param {object} payload from the com\n * @return {array} timestamp field with an array value\n */\nexport const handleTimestamp = payload => {\n let ts = payload[TIMESTAMP_PARAM_NAME]\n if (!isArray(ts)) {\n ts = [ts]\n }\n ts.push( timestamp() )\n\n return ts\n}\n\n/**\n * make sure it's an object (it was call formatPayload but it doesn't make sense)\n * @param {*} payload the object comes in could be string based\n * @return {object} the transformed payload\n */\nexport const toPayload = payload => isString(payload) ? parseJson(payload) : payload\n\n/**\n * @param {*} args arguments to send\n *@return {object} formatted payload\n */\nexport const formatPayload = (args) => (\n { [QUERY_ARG_NAME]: args }\n)\n\n/**\n * extract the resolver name from the payload \n * @param {object} payload\n * @return {string} resolver name \n */\nexport function getResolverFromPayload(payload) {\n const keys = Object.keys(payload)\n return keys.filter(key => key !== TIMESTAMP_PARAM_NAME)[0]\n}\n\n/**\n * wrapper method to add the timestamp as well\n * @param {string} resolverName\n * @param {*} payload\n * @return {object} delierable\n */\nexport function createDeliverable(resolverName, payload) {\n return {\n [resolverName]: payload,\n [TIMESTAMP_PARAM_NAME]: [ timestamp() ]\n }\n}\n\n/**\n * @param {string} resolverName name of function\n * @param {array} [args=[]] from the ...args\n * @param {boolean} [jsonp = false] add v1.3.0 to koa\n * @return {object} formatted argument\n */\nexport function createQuery(resolverName, args = [], jsonp = false) {\n if (isString(resolverName) && isArray(args)) {\n let payload = formatPayload(args)\n if (jsonp === true) {\n return payload\n }\n return createDeliverable(resolverName, payload)\n }\n throw new JsonqlValidationError(`[createQuery] expect resolverName to be string and args to be array!`, { resolverName, args })\n}\n\n/**\n * string version of the createQuery\n * @return {string}\n */\nexport function createQueryStr(resolverName, args = [], jsonp = false) {\n return JSON.stringify(createQuery(resolverName, args, jsonp))\n}\n\n/**\n * @param {string} resolverName name of function\n * @param {*} payload to send\n * @param {object} [condition={}] for what\n * @param {boolean} [jsonp = false] add v1.3.0 to koa\n * @return {object} formatted argument\n */\nexport function createMutation(resolverName, payload, condition = {}, jsonp = false) {\n const _payload = {\n [PAYLOAD_PARAM_NAME]: payload,\n [CONDITION_PARAM_NAME]: condition\n }\n if (jsonp === true) {\n return _payload\n }\n if (isString(resolverName)) {\n return createDeliverable(resolverName, _payload)\n }\n throw new JsonqlValidationError(`[createMutation] expect resolverName to be string!`, { resolverName, payload, condition })\n}\n\n/**\n * string version of createMutation\n * @return {string}\n */\nexport function createMutationStr(resolverName, payload, condition = {}, jsonp = false) {\n return JSON.stringify(createMutation(resolverName, payload, condition, jsonp))\n}\n\n/**\n * Extract the parts from payload and format for use\n * @param {string} resolverName name of fn\n * @param {object} payload the incoming json\n * @return {object|boolean} false on failed\n */\nexport function getQueryFromArgs(resolverName, payload) {\n if (resolverName && isPlainObject(payload)) {\n const args = payload[resolverName]\n if (args[QUERY_ARG_NAME]) {\n return {\n [RESOLVER_PARAM_NAME]: resolverName,\n [QUERY_ARG_NAME]: args[QUERY_ARG_NAME],\n [TIMESTAMP_PARAM_NAME]: handleTimestamp(payload)\n }\n }\n }\n return false\n}\n\n/**\n * Share function so no repeat\n * @param {object} payload the payload from client\n * @param {function} processor the last get result method\n * @return {*} result processed result\n */\nfunction processPayload(payload, processor) {\n const p = toPayload(payload)\n const resolverName = getResolverFromPayload(p)\n return Reflect.apply(processor, null, [resolverName, p])\n}\n\n/**\n * extra the payload back\n * @param {*} payload from http call\n * @return {object} resolverName and args\n */\nexport function getQueryFromPayload(payload) {\n const result = processPayload(payload, getQueryFromArgs)\n if (result !== false) {\n return result\n }\n throw new JsonqlValidationError('[getQueryArgs] Payload is malformed!', payload)\n}\n\n/**\n * Further break down from method below for use else where\n * @param {string} resolverName name of fn\n * @param {object} payload payload\n * @return {object|boolean} false on failed\n */\nexport function getMutationFromArgs(resolverName, payload) {\n if (resolverName && isPlainObject(payload)) {\n const args = payload[resolverName]\n if (args) {\n return {\n [RESOLVER_PARAM_NAME]: resolverName,\n [PAYLOAD_PARAM_NAME]: args[PAYLOAD_PARAM_NAME],\n [CONDITION_PARAM_NAME]: args[CONDITION_PARAM_NAME],\n [TIMESTAMP_PARAM_NAME]: handleTimestamp(payload)\n }\n }\n }\n return false\n}\n\n/**\n * @param {object} payload\n * @return {object} resolverName, payload, conditon\n */\nexport function getMutationFromPayload(payload) {\n const result = processPayload(payload, getMutationFromArgs)\n\n if (result !== false) {\n return result\n }\n throw new JsonqlValidationError('[getMutationArgs] Payload is malformed!', payload)\n}\n","// take out all the namespace related methods in one place for easy to find\nimport {\n JSONQL_PATH,\n PUBLIC_KEY,\n NSP_GROUP,\n PUBLIC_NAMESPACE\n} from 'jsonql-constants'\nimport { extractSocketPart } from './contract'\nconst SOCKET_NOT_FOUND_ERR = `socket not found in contract!`\nconst SIZE = 'size'\n\n/**\n * create the group using publicNamespace when there is only public\n * @param {object} socket from contract\n * @param {string} publicNamespace\n */\nfunction groupPublicNamespace(socket, publicNamespace) {\n let g = {}\n for (let resolverName in socket) {\n let params = socket[resolverName]\n g[resolverName] = params\n }\n return { size: 1, nspGroup: {[publicNamespace]: g}, publicNamespace}\n}\n\n\n/**\n * @BUG we should check the socket part instead of expect the downstream to read the menu!\n * We only need this when the enableAuth is true otherwise there is only one namespace\n * @param {object} contract the socket part of the contract file\n * @return {object} 1. remap the contract using the namespace --> resolvers\n * 2. the size of the object (1 all private, 2 mixed public with private)\n * 3. which namespace is public\n */\nexport function groupByNamespace(contract) {\n let socket = extractSocketPart(contract)\n if (socket === false) {\n throw new JsonqlError('groupByNamespace', SOCKET_NOT_FOUND_ERR)\n }\n let prop = {\n [NSP_GROUP]: {},\n [PUBLIC_NAMESPACE]: null,\n [SIZE]: 0 \n }\n\n for (let resolverName in socket) {\n let params = socket[resolverName]\n let { namespace } = params\n if (namespace) {\n if (!prop[NSP_GROUP][namespace]) {\n ++prop[SIZE]\n prop[NSP_GROUP][namespace] = {}\n }\n prop[NSP_GROUP][namespace][resolverName] = params\n // get the public namespace\n if (!prop[PUBLIC_NAMESPACE] && params[PUBLIC_KEY]) {\n prop[PUBLIC_NAMESPACE] = namespace\n }\n }\n }\n \n return prop \n}\n\n/**\n * @NOTE ported from jsonql-ws-client\n * Got to make sure the connection order otherwise\n * it will hang\n * @param {object} nspGroup contract\n * @param {string} publicNamespace like the name said\n * @return {array} namespaces in order\n */\nexport function getNamespaceInOrder(nspGroup, publicNamespace) {\n let names = [] // need to make sure the order!\n for (let namespace in nspGroup) {\n if (namespace === publicNamespace) {\n names[1] = namespace\n } else {\n names[0] = namespace\n }\n }\n return names\n}\n\n/**\n * @TODO this might change, what if we want to do room with ws\n * 1. there will only be max two namespace\n * 2. when it's normal we will have the stock path as namespace\n * 3. when enableAuth then we will have two, one is jsonql/public + private\n * @param {object} config options\n * @return {array} of namespace(s)\n */\nexport function getNamespace(config) {\n const base = JSONQL_PATH\n if (config.enableAuth) {\n // the public come first @1.0.1 we use the constants instead of the user supplied value\n // @1.0.4 we use the config value again, because we could control this via the post init\n return [\n [ base , config.privateNamespace ].join('/'),\n [ base , config.publicNamespace ].join('/')\n ]\n }\n return [ base ]\n}\n\n/**\n * get the private namespace\n * @param {array} namespaces array\n * @return {*} string on success\n */\nexport function getPrivateNamespace(namespaces) {\n return namespaces.length > 1 ? namespaces[0] : false\n}\n\n/**\n * Got a problem with a contract that is public only the groupByNamespace is wrong\n * which is actually not a problem when using a fallback, but to be sure things in order\n * we could combine with the config to group it\n * @param {object} config configuration\n * @return {object} nspInfo object\n */\nexport function getNspInfoByConfig(config) {\n const { contract, enableAuth } = config\n const namespaces = getNamespace(config)\n let nspInfo = enableAuth ? groupByNamespace(contract)\n : groupPublicNamespace(contract.socket, namespaces[0])\n // add the namespaces into it as well\n return Object.assign(nspInfo, { namespaces })\n}\n\n","// There are the socket related methods ported back from \n// ws-server-core and ws-client-core \nimport {\n WS_REPLY_TYPE,\n WS_EVT_NAME,\n WS_DATA_NAME,\n TIMESTAMP_PARAM_NAME,\n ERROR_KEY,\n EMIT_REPLY_TYPE,\n ACKNOWLEDGE_REPLY_TYPE\n} from 'jsonql-constants'\nimport { JsonqlError } from 'jsonql-errors' \nimport isString from 'lodash-es/isString'\n\nimport { toJson, isObjectHasKey, nil } from './generic'\nimport { timestamp } from './timestamp'\n\nconst PAYLOAD_NOT_DECODED_ERR = 'payload can not decoded'\nconst WS_KEYS = [\n WS_REPLY_TYPE,\n WS_EVT_NAME,\n WS_DATA_NAME\n]\n\n/////////////////////////////////////\n// REPLY FROM SERVER //\n/////////////////////////////////////\n\n\n/**\n * The ws doesn't have a acknowledge callback like socket.io\n * so we have to DIY one for ws and other that doesn't have it\n * @param {string} type of reply\n * @param {string} resolverName which is replying\n * @param {*} data payload\n * @param {array} [ts= []] the last received ts, if any \n * @return {string} stringify json\n */\nexport const createWsReply = (type, resolverName, data, ts = []) => {\n ts.push(timestamp())\n return JSON.stringify({\n data: {\n [WS_REPLY_TYPE]: type,\n [WS_EVT_NAME]: resolverName,\n [WS_DATA_NAME]: toJson(data)\n },\n [TIMESTAMP_PARAM_NAME]: ts \n })\n}\n\n// extended function \nexport const createReplyMsg = (resolverName, data, ts = []) => (\n createWsReply(EMIT_REPLY_TYPE, resolverName, data, ts)\n)\n\nexport const createAcknowledgeMsg = (resolverName, data, ts = []) => (\n createWsReply(ACKNOWLEDGE_REPLY_TYPE, resolverName, data, ts)\n)\n\n/**\n * @param {string|object} payload should be string when reply but could be transformed\n * @return {boolean} true is OK\n */\nexport const isWsReply = payload => {\n const json = isString(payload) ? toJson(payload) : payload\n const { data } = json\n if (data) {\n let result = WS_KEYS.filter(key => isObjectHasKey(data, key))\n return (result.length === WS_KEYS.length) ? data : false\n }\n return false\n}\n\n/**\n * @param {string|object} data received data\n * @param {function} [cb=nil] this is for extracting the TS field or when it's error\n * @return {object} false on failed\n */\nexport const extractWsPayload = (payload, cb = nil) => {\n try {\n const json = toJson(payload)\n // now handle the data\n let _data\n if ((_data = isWsReply(json)) !== false) {\n // note the ts property is on its own \n cb(TIMESTAMP_PARAM_NAME, json[TIMESTAMP_PARAM_NAME])\n \n return {\n data: toJson(_data[WS_DATA_NAME]),\n resolverName: _data[WS_EVT_NAME],\n type: _data[WS_REPLY_TYPE]\n }\n }\n throw new JsonqlError(PAYLOAD_NOT_DECODED_ERR, payload)\n } catch(e) {\n return cb(ERROR_KEY, e)\n }\n}\n","// this will be part of the init client sequence\n// as soon as we create a ws client\n// we listen to the on.connect event \n// then we send a init-ping event back to the server\n// and server issue a csrf token back to use \n// we use this token to create a new client and destroy the old one\nimport {\n INTERCOM_RESOLVER_NAME, \n SOCKET_PING_EVENT_NAME,\n HEADERS_KEY,\n DATA_KEY,\n CSRF_HEADER_KEY\n} from 'jsonql-constants'\nimport { \n createQueryStr, \n extractWsPayload,\n timestamp,\n toJson \n} from 'jsonql-utils/module'\nimport {\n JsonqlError\n} from 'jsonql-errors'\nconst CSRF_HEADER_NOT_EXIST_ERR = 'CSRF header is not in the received payload'\n\n/**\n * Util method \n * @param {string} payload return from server\n * @return {object} the useful bit \n */\nfunction extractSrvPayload(payload) {\n let json = toJson(payload)\n \n if (json && typeof json === 'object') {\n // note this method expect the json.data inside\n return extractWsPayload(json)\n }\n \n throw new JsonqlError('extractSrvPayload', json)\n}\n\n/**\n * call the server to get a csrf token \n * @return {string} formatted payload to send to the server \n */\nfunction createInitPing() {\n const ts = timestamp()\n\n return createQueryStr(INTERCOM_RESOLVER_NAME, [SOCKET_PING_EVENT_NAME, ts])\n}\n\n/**\n * Take the raw on.message result back then decoded it \n * @param {*} payload the raw result from server\n * @return {object} the csrf payload\n */\nfunction extractPingResult(payload) {\n const result = extractSrvPayload(payload)\n \n if (result && result[DATA_KEY] && result[DATA_KEY][CSRF_HEADER_KEY]) {\n return {\n [HEADERS_KEY]: result[DATA_KEY]\n }\n }\n\n throw new JsonqlError('extractPingResult', CSRF_HEADER_NOT_EXIST_ERR)\n}\n\n\n/**\n * Create a generic intercom method\n * @param {string} type the event type \n * @param {array} args if any \n * @return {string} formatted payload to send\n */\nfunction createIntercomPayload(type, ...args) {\n const ts = timestamp()\n let payload = [type].concat(args)\n payload.push(ts)\n return createQueryStr(INTERCOM_RESOLVER_NAME, payload)\n}\n\n\nexport { \n extractSrvPayload,\n createInitPing, \n extractPingResult, \n createIntercomPayload \n}","// validator numbers\n// import { NUMBER_TYPES } from './constants';\n\nimport isNaN from 'lodash-es/isNaN'\nimport isString from 'lodash-es/isString'\n/**\n * @2015-05-04 found a problem if the value is a number like string\n * it will pass, so add a chck if it's string before we pass to next\n * @param {number} value expected value\n * @return {boolean} true if OK\n */\nconst checkIsNumber = function(value) {\n return isString(value) ? false : !isNaN( parseFloat(value) )\n}\n\nexport default checkIsNumber\n","// validate string type\nimport trim from 'lodash-es/trim'\nimport isString from 'lodash-es/isString'\n/**\n * @param {string} value expected value\n * @return {boolean} true if OK\n */\nconst checkIsString = function(value) {\n return (trim(value) !== '') ? isString(value) : false\n}\n\nexport default checkIsString\n","// check for boolean\n\n/**\n * @param {boolean} value expected\n * @return {boolean} true if OK\n */\nconst checkIsBoolean = function(value) {\n return value !== null && value !== undefined && typeof value === 'boolean'\n}\n\nexport default checkIsBoolean\n","// validate any thing only check if there is something\n\nimport trim from 'lodash-es/trim'\n\n/**\n * @param {*} value the value\n * @param {boolean} [checkNull=true] strict check if there is null value\n * @return {boolean} true is OK\n */\nconst checkIsAny = function(value, checkNull = true) {\n if (value !== undefined && value !== '' && trim(value) !== '') {\n if (checkNull === false || (checkNull === true && value !== null)) {\n return true;\n }\n }\n return false;\n}\n\nexport default checkIsAny\n","// Good practice rule - No magic number\n\nconst ARGS_NOT_ARRAY_ERR = `args is not an array! You might want to do: ES6 Array.from(arguments) or ES5 Array.prototype.slice.call(arguments)`\nconst PARAMS_NOT_ARRAY_ERR = `params is not an array! Did something gone wrong when you generate the contract.json?`\nconst EXCEPTION_CASE_ERR = 'Could not understand your arguments and parameter structure!'\nconst UNUSUAL_CASE_ERR = 'This is an unusual situation where the arguments are more than the params, but not mark as spread'\n\nconst RETURNS_NAME = 'returns'\n\nimport {\n \n DEFAULT_TYPE, // this is a mistake should move back to the validation\n DATA_KEY, \n ERROR_KEY,\n\n TYPE_KEY,\n OPTIONAL_KEY,\n ENUM_KEY,\n ARGS_KEY,\n CHECKER_KEY,\n ALIAS_KEY,\n\n ARRAY_TYPE_LFT,\n ARRAY_TYPE_RGT,\n \n ARRAY_TYPE,\n OBJECT_TYPE,\n STRING_TYPE,\n BOOLEAN_TYPE,\n NUMBER_TYPE,\n KEY_WORD,\n OR_SEPERATOR\n} from 'jsonql-constants'\n\n// group all export in one \nexport {\n ARGS_NOT_ARRAY_ERR,\n PARAMS_NOT_ARRAY_ERR,\n EXCEPTION_CASE_ERR,\n UNUSUAL_CASE_ERR,\n DEFAULT_TYPE,\n ARRAY_TYPE_LFT,\n ARRAY_TYPE_RGT,\n TYPE_KEY,\n OPTIONAL_KEY,\n ENUM_KEY,\n ARGS_KEY,\n CHECKER_KEY,\n ALIAS_KEY,\n ARRAY_TYPE,\n OBJECT_TYPE,\n STRING_TYPE,\n BOOLEAN_TYPE,\n NUMBER_TYPE,\n KEY_WORD,\n OR_SEPERATOR,\n\n RETURNS_NAME,\n\n DATA_KEY, \n ERROR_KEY \n}","// primitive types\nimport checkIsNumber from './number'\nimport checkIsString from './string'\nimport checkIsBoolean from './boolean'\nimport checkIsAny from './any'\nimport { NUMBER_TYPE, STRING_TYPE, BOOLEAN_TYPE } from './constants'\n\n/**\n * this is a wrapper method to call different one based on their type\n * @param {string} type to check\n * @return {function} a function to handle the type\n */\nconst combineFn = function(type) {\n switch (type) {\n case NUMBER_TYPE:\n return checkIsNumber\n case STRING_TYPE:\n return checkIsString\n case BOOLEAN_TYPE:\n return checkIsBoolean\n default:\n return checkIsAny\n }\n}\n\nexport default combineFn\n","// validate array type\n\nimport isArray from 'lodash-es/isArray'\nimport trim from 'lodash-es/trim'\nimport combineFn from './combine'\nimport {\n ARRAY_TYPE_LFT,\n ARRAY_TYPE_RGT,\n OR_SEPERATOR\n} from './constants'\n\n/**\n * @param {array} value expected\n * @param {string} [type=''] pass the type if we encounter array. then we need to check the value as well\n * @return {boolean} true if OK\n */\nexport const checkIsArray = function(value, type='') {\n if (isArray(value)) {\n if (type === '' || trim(type)==='') {\n return true;\n }\n // we test it in reverse\n // @TODO if the type is an array (OR) then what?\n // we need to take into account this could be an array\n const c = value.filter(v => !combineFn(type)(v))\n return !(c.length > 0)\n }\n return false\n}\n\n/**\n * check if it matches the array. pattern\n * @param {string} type\n * @return {boolean|array} false means NO, always return array\n */\nexport const isArrayLike = function(type) {\n // @TODO could that have something like array<> instead of array.<>? missing the dot?\n // because type script is Array without the dot\n if (type.indexOf(ARRAY_TYPE_LFT) > -1 && type.indexOf(ARRAY_TYPE_RGT) > -1) {\n const _type = type.replace(ARRAY_TYPE_LFT, '').replace(ARRAY_TYPE_RGT, '')\n if (_type.indexOf(OR_SEPERATOR)) {\n return _type.split(OR_SEPERATOR)\n }\n return [_type]\n }\n return false\n}\n\n/**\n * we might encounter something like array. then we need to take it apart\n * @param {object} p the prepared object for processing\n * @param {string|array} type the type came from \n * @return {boolean} for the filter to operate on\n */\nexport const arrayTypeHandler = function(p, type) {\n const { arg } = p\n // need a special case to handle the OR type\n // we need to test the args instead of the type(s)\n if (type.length > 1) {\n return !arg.filter(v => (\n !(type.length > type.filter(t => !combineFn(t)(v)).length)\n )).length\n }\n // type is array so this will be or!\n return type.length > type.filter(t => !checkIsArray(arg, t)).length\n}\n","// validate object type\n\nimport isPlainObject from 'lodash-es/isPlainObject'\n// import filter from 'lodash-es/filter'\nimport combineFn from './combine'\nimport { checkIsArray, isArrayLike, arrayTypeHandler } from './array'\n/**\n * @TODO if provide with the keys then we need to check if the key:value type as well\n * @param {object} value expected\n * @param {array} [keys=null] if it has the keys array to compare as well\n * @return {boolean} true if OK\n */\nexport const checkIsObject = function(value, keys=null) {\n if (isPlainObject(value)) {\n if (!keys) {\n return true\n }\n if (checkIsArray(keys)) {\n // please note we DON'T care if some is optional\n // plese refer to the contract.json for the keys\n return !keys.filter(key => {\n let _value = value[key.name];\n return !(key.type.length > key.type.filter(type => {\n let tmp;\n if (_value !== undefined) {\n if ((tmp = isArrayLike(type)) !== false) {\n return !arrayTypeHandler({arg: _value}, tmp)\n // return tmp.filter(t => !checkIsArray(_value, t)).length;\n // @TODO there might be an object within an object with keys as well :S\n }\n return !combineFn(type)(_value)\n }\n return true\n }).length)\n }).length;\n }\n }\n return false\n}\n\n/**\n * fold this into it's own function to handler different object type\n * @param {object} p the prepared object for process\n * @return {boolean}\n */\nexport const objectTypeHandler = function(p) {\n const { arg, param } = p\n let _args = [arg]\n if (Array.isArray(param.keys) && param.keys.length) {\n _args.push(param.keys)\n }\n // just simple check\n return Reflect.apply(checkIsObject, null, _args)\n}\n","// move the index.js code here that make more sense to find where things are\n\nimport {\n checkIsArray,\n isArrayLike,\n arrayTypeHandler,\n objectTypeHandler,\n combineFn,\n notEmpty\n} from './index'\n\nimport {\n DEFAULT_TYPE,\n ARRAY_TYPE,\n OBJECT_TYPE,\n ARGS_NOT_ARRAY_ERR,\n PARAMS_NOT_ARRAY_ERR,\n EXCEPTION_CASE_ERR,\n DATA_KEY, \n ERROR_KEY \n} from './constants'\n\n\nimport JsonqlValidationError from 'jsonql-errors/src/validation-error'\nimport JsonqlError from 'jsonql-errors/src/error'\n// import debug from 'debug'\n// const debugFn = debug('jsonql-params-validator:validator')\n// also export this for use in other places\n\n/**\n * We need to handle those optional parameter without a default value\n * @param {object} params from contract.json\n * @return {boolean} for filter operation false is actually OK\n */\nconst optionalHandler = function( params ) {\n const { arg, param } = params\n if (notEmpty(arg)) {\n // debug('call optional handler', arg, params);\n // loop through the type in param\n return !(param.type.length > param.type.filter(type =>\n validateHandler(type, params)\n ).length)\n }\n return false\n}\n\n/**\n * actually picking the validator\n * @param {*} type for checking\n * @param {*} value for checking\n * @return {boolean} true on OK\n */\nconst validateHandler = function(type, value) {\n let tmp;\n switch (true) {\n case type === OBJECT_TYPE:\n // debugFn('call OBJECT_TYPE')\n return !objectTypeHandler(value)\n case type === ARRAY_TYPE:\n // debugFn('call ARRAY_TYPE')\n return !checkIsArray(value.arg)\n // @TODO when the type is not present, it always fall through here\n // so we need to find a way to actually pre-check the type first\n // AKA check the contract.json map before running here\n case (tmp = isArrayLike(type)) !== false:\n // debugFn('call ARRAY_LIKE: %O', value)\n return !arrayTypeHandler(value, tmp)\n default:\n return !combineFn(type)(value.arg)\n }\n}\n\n/**\n * it get too longer to fit in one line so break it out from the fn below\n * @param {*} arg value\n * @param {object} param config\n * @return {*} value or apply default value\n */\nconst getOptionalValue = function(arg, param) {\n if (arg !== undefined) {\n return arg\n }\n return (param.optional === true && param.defaultvalue !== undefined ? param.defaultvalue : null)\n}\n\n/**\n * padding the arguments with defaultValue if the arguments did not provide the value\n * this will be the name export\n * @param {array} args normalized arguments\n * @param {array} params from contract.json\n * @return {array} merge the two together\n */\nexport const normalizeArgs = function(args, params) {\n // first we should check if this call require a validation at all\n // there will be situation where the function doesn't need args and params\n if (!checkIsArray(params)) {\n // debugFn('params value', params)\n throw new JsonqlValidationError(PARAMS_NOT_ARRAY_ERR)\n }\n if (params.length === 0) {\n return []\n }\n if (!checkIsArray(args)) {\n throw new JsonqlValidationError(ARGS_NOT_ARRAY_ERR)\n }\n // debugFn(args, params);\n // fall through switch\n switch(true) {\n case args.length == params.length: // standard\n return args.map((arg, i) => (\n {\n arg,\n index: i,\n param: params[i]\n }\n ))\n case params[0].variable === true: // using spread syntax\n const type = params[0].type;\n return args.map((arg, i) => (\n {\n arg,\n index: i, // keep the index for reference\n param: params[i] || { type, name: '_' }\n }\n ))\n // with optional defaultValue parameters\n case args.length < params.length:\n return params.map((param, i) => (\n {\n param,\n index: i,\n arg: getOptionalValue(args[i], param),\n optional: param.optional || false\n }\n ))\n // this one pass more than it should have anything after the args.length will be cast as any type\n case args.length > params.length:\n let ctn = params.length;\n // this happens when we have those array. type\n let _type = [ DEFAULT_TYPE ]\n // we only looking at the first one, this might be a @BUG\n /*\n if ((tmp = isArrayLike(params[0].type[0])) !== false) {\n _type = tmp;\n } */\n // if we use the params as guide then the rest will get throw out\n // which is not what we want, instead, anything without the param\n // will get a any type and optional flag\n return args.map((arg, i) => {\n let optional = i >= ctn ? true : !!params[i].optional\n let param = params[i] || { type: _type, name: `_${i}` }\n return {\n arg: optional ? getOptionalValue(arg, param) : arg,\n index: i,\n param,\n optional\n }\n })\n // @TODO find out if there is more cases not cover\n default: // this should never happen\n // debugFn('args', args)\n // debugFn('params', params)\n // this is unknown therefore we just throw it!\n throw new JsonqlError(EXCEPTION_CASE_ERR, { args, params })\n }\n}\n\n// what we want is after the validaton we also get the normalized result\n// which is with the optional property if the argument didn't provide it\n/**\n * process the array of params back to their arguments\n * @param {array} result the params result\n * @return {array} arguments\n */\nconst processReturn = result => result.map(r => r.arg)\n\n/**\n * validator main interface\n * @param {array} args the arguments pass to the method call\n * @param {array} params from the contract for that method\n * @param {boolean} [withResul=false] if true then this will return the normalize result as well\n * @return {array} empty array on success, or failed parameter and reasons\n */\nexport const validateSync = function(args, params, withResult = false) {\n let cleanArgs = normalizeArgs(args, params)\n let checkResult = cleanArgs.filter(p => {\n // v1.4.4 this fixed the problem, the root level optional is from the last fn\n if (p.optional === true || p.param.optional === true) {\n return optionalHandler(p)\n }\n // because array of types means OR so if one pass means pass\n return !(p.param.type.length > p.param.type.filter(\n type => validateHandler(type, p)\n ).length)\n })\n // using the same convention we been using all this time\n return !withResult ? checkResult : {\n [ERROR_KEY]: checkResult,\n [DATA_KEY]: processReturn(cleanArgs)\n }\n}\n\n/**\n * A wrapper method that return promise\n * @param {array} args arguments\n * @param {array} params from contract.json\n * @param {boolean} [withResul=false] if true then this will return the normalize result as well\n * @return {object} promise.then or catch\n */\nexport const validateAsync = function(args, params, withResult = false) {\n return new Promise((resolver, rejecter) => {\n const result = validateSync(args, params, withResult)\n if (withResult) {\n return result[ERROR_KEY].length ? rejecter(result[ERROR_KEY])\n : resolver(result[DATA_KEY])\n }\n // the different is just in the then or catch phrase\n return result.length ? rejecter(result) : resolver([])\n })\n}\n","/** Used to stand-in for `undefined` hash values. */\nvar HASH_UNDEFINED = '__lodash_hash_undefined__';\n\n/**\n * Adds `value` to the array cache.\n *\n * @private\n * @name add\n * @memberOf SetCache\n * @alias push\n * @param {*} value The value to cache.\n * @returns {Object} Returns the cache instance.\n */\nfunction setCacheAdd(value) {\n this.__data__.set(value, HASH_UNDEFINED);\n return this;\n}\n\nexport default setCacheAdd;\n","/**\n * Checks if `value` is in the array cache.\n *\n * @private\n * @name has\n * @memberOf SetCache\n * @param {*} value The value to search for.\n * @returns {number} Returns `true` if `value` is found, else `false`.\n */\nfunction setCacheHas(value) {\n return this.__data__.has(value);\n}\n\nexport default setCacheHas;\n","/**\n * A specialized version of `_.some` for arrays without support for iteratee\n * shorthands.\n *\n * @private\n * @param {Array} [array] The array to iterate over.\n * @param {Function} predicate The function invoked per iteration.\n * @returns {boolean} Returns `true` if any element passes the predicate check,\n * else `false`.\n */\nfunction arraySome(array, predicate) {\n var index = -1,\n length = array == null ? 0 : array.length;\n\n while (++index < length) {\n if (predicate(array[index], index, array)) {\n return true;\n }\n }\n return false;\n}\n\nexport default arraySome;\n","/**\n * Checks if a `cache` value for `key` exists.\n *\n * @private\n * @param {Object} cache The cache to query.\n * @param {string} key The key of the entry to check.\n * @returns {boolean} Returns `true` if an entry for `key` exists, else `false`.\n */\nfunction cacheHas(cache, key) {\n return cache.has(key);\n}\n\nexport default cacheHas;\n","/**\n * Converts `map` to its key-value pairs.\n *\n * @private\n * @param {Object} map The map to convert.\n * @returns {Array} Returns the key-value pairs.\n */\nfunction mapToArray(map) {\n var index = -1,\n result = Array(map.size);\n\n map.forEach(function(value, key) {\n result[++index] = [key, value];\n });\n return result;\n}\n\nexport default mapToArray;\n","/**\n * Converts `set` to an array of its values.\n *\n * @private\n * @param {Object} set The set to convert.\n * @returns {Array} Returns the values.\n */\nfunction setToArray(set) {\n var index = -1,\n result = Array(set.size);\n\n set.forEach(function(value) {\n result[++index] = value;\n });\n return result;\n}\n\nexport default setToArray;\n","/**\n * Appends the elements of `values` to `array`.\n *\n * @private\n * @param {Array} array The array to modify.\n * @param {Array} values The values to append.\n * @returns {Array} Returns `array`.\n */\nfunction arrayPush(array, values) {\n var index = -1,\n length = values.length,\n offset = array.length;\n\n while (++index < length) {\n array[offset + index] = values[index];\n }\n return array;\n}\n\nexport default arrayPush;\n","/**\n * A specialized version of `_.filter` for arrays without support for\n * iteratee shorthands.\n *\n * @private\n * @param {Array} [array] The array to iterate over.\n * @param {Function} predicate The function invoked per iteration.\n * @returns {Array} Returns the new filtered array.\n */\nfunction arrayFilter(array, predicate) {\n var index = -1,\n length = array == null ? 0 : array.length,\n resIndex = 0,\n result = [];\n\n while (++index < length) {\n var value = array[index];\n if (predicate(value, index, array)) {\n result[resIndex++] = value;\n }\n }\n return result;\n}\n\nexport default arrayFilter;\n","/**\n * This method returns a new empty array.\n *\n * @static\n * @memberOf _\n * @since 4.13.0\n * @category Util\n * @returns {Array} Returns the new empty array.\n * @example\n *\n * var arrays = _.times(2, _.stubArray);\n *\n * console.log(arrays);\n * // => [[], []]\n *\n * console.log(arrays[0] === arrays[1]);\n * // => false\n */\nfunction stubArray() {\n return [];\n}\n\nexport default stubArray;\n","/**\n * A specialized version of `matchesProperty` for source values suitable\n * for strict equality comparisons, i.e. `===`.\n *\n * @private\n * @param {string} key The key of the property to get.\n * @param {*} srcValue The value to match.\n * @returns {Function} Returns the new spec function.\n */\nfunction matchesStrictComparable(key, srcValue) {\n return function(object) {\n if (object == null) {\n return false;\n }\n return object[key] === srcValue &&\n (srcValue !== undefined || (key in Object(object)));\n };\n}\n\nexport default matchesStrictComparable;\n","/**\n * The base implementation of `_.hasIn` without support for deep paths.\n *\n * @private\n * @param {Object} [object] The object to query.\n * @param {Array|string} key The key to check.\n * @returns {boolean} Returns `true` if `key` exists, else `false`.\n */\nfunction baseHasIn(object, key) {\n return object != null && key in Object(object);\n}\n\nexport default baseHasIn;\n","/**\n * The base implementation of `_.property` without support for deep paths.\n *\n * @private\n * @param {string} key The key of the property to get.\n * @returns {Function} Returns the new accessor function.\n */\nfunction baseProperty(key) {\n return function(object) {\n return object == null ? undefined : object[key];\n };\n}\n\nexport default baseProperty;\n","/** Error message constants. */\nvar FUNC_ERROR_TEXT = 'Expected a function';\n\n/**\n * Creates a function that negates the result of the predicate `func`. The\n * `func` predicate is invoked with the `this` binding and arguments of the\n * created function.\n *\n * @static\n * @memberOf _\n * @since 3.0.0\n * @category Function\n * @param {Function} predicate The predicate to negate.\n * @returns {Function} Returns the new negated function.\n * @example\n *\n * function isEven(n) {\n * return n % 2 == 0;\n * }\n *\n * _.filter([1, 2, 3, 4, 5, 6], _.negate(isEven));\n * // => [1, 3, 5]\n */\nfunction negate(predicate) {\n if (typeof predicate != 'function') {\n throw new TypeError(FUNC_ERROR_TEXT);\n }\n return function() {\n var args = arguments;\n switch (args.length) {\n case 0: return !predicate.call(this);\n case 1: return !predicate.call(this, args[0]);\n case 2: return !predicate.call(this, args[0], args[1]);\n case 3: return !predicate.call(this, args[0], args[1], args[2]);\n }\n return !predicate.apply(this, args);\n };\n}\n\nexport default negate;\n","/**\n * The base implementation of methods like `_.findKey` and `_.findLastKey`,\n * without support for iteratee shorthands, which iterates over `collection`\n * using `eachFunc`.\n *\n * @private\n * @param {Array|Object} collection The collection to inspect.\n * @param {Function} predicate The function invoked per iteration.\n * @param {Function} eachFunc The function to iterate over `collection`.\n * @returns {*} Returns the found element or its key, else `undefined`.\n */\nfunction baseFindKey(collection, predicate, eachFunc) {\n var result;\n eachFunc(collection, function(value, key, collection) {\n if (predicate(value, key, collection)) {\n result = key;\n return false;\n }\n });\n return result;\n}\n\nexport default baseFindKey;\n","/**\n * @param {array} arr Array for check\n * @param {*} value target\n * @return {boolean} true on successs\n */\nconst isInArray = function(arr, value) {\n return !!arr.filter(a => a === value).length\n}\n\nexport default isInArray\n","// breaking the whole thing up to see what cause the multiple calls issue\n\nimport isFunction from 'lodash-es/isFunction'\nimport merge from 'lodash-es/merge'\nimport mapValues from 'lodash-es/mapValues'\n\nimport JsonqlEnumError from 'jsonql-errors/src/enum-error'\nimport JsonqlTypeError from 'jsonql-errors/src/type-error'\nimport JsonqlCheckerError from 'jsonql-errors/src/checker-error'\n\nimport {\n TYPE_KEY,\n OPTIONAL_KEY,\n ENUM_KEY,\n ARGS_KEY,\n CHECKER_KEY,\n KEY_WORD\n} from '../constants'\nimport { checkIsArray } from '../array'\n\n// import debug from 'debug';\n// const debugFn = debug('jsonql-params-validator:options:validation')\n\n/**\n * just make sure it returns an array to use\n * @param {*} arg input\n * @return {array} output\n */\nconst toArray = arg => checkIsArray(arg) ? arg : [arg]\n\n/**\n * DIY in array\n * @param {array} arr to check against\n * @param {*} value to check\n * @return {boolean} true on OK\n */\nconst inArray = (arr, value) => (\n !!arr.filter(v => v === value).length\n)\n\n/**\n * break out to make the code easier to read\n * @param {object} value to process\n * @param {function} cb the validateSync\n * @return {array} empty on success\n */\nfunction validateHandler(value, cb) {\n // cb is the validateSync methods\n let args = [\n [ value[ARGS_KEY] ],\n [{\n [TYPE_KEY]: toArray(value[TYPE_KEY]),\n [OPTIONAL_KEY]: value[OPTIONAL_KEY]\n }]\n ]\n // debugFn('validateHandler', args)\n return Reflect.apply(cb, null, args)\n}\n\n/**\n * Check against the enum value if it's provided\n * @param {*} value to check\n * @param {*} enumv to check against if it's not false\n * @return {boolean} true on OK\n */\nconst enumHandler = (value, enumv) => {\n if (checkIsArray(enumv)) {\n return inArray(enumv, value)\n }\n return true\n}\n\n/**\n * Allow passing a function to check the value\n * There might be a problem here if the function is incorrect\n * and that will makes it hard to debug what is going on inside\n * @TODO there could be a few feature add to this one under different circumstance\n * @param {*} value to check\n * @param {function} checker for checking\n */\nconst checkerHandler = (value, checker) => {\n try {\n return isFunction(checker) ? checker.apply(null, [value]) : false\n } catch (e) {\n return false\n }\n}\n\n/**\n * Taken out from the runValidaton this only validate the required values\n * @param {array} args from the config2argsAction\n * @param {function} cb validateSync\n * @return {array} of configuration values\n */\nfunction runValidationAction(cb) {\n return (value, key) => {\n // debugFn('runValidationAction', key, value)\n if (value[KEY_WORD]) {\n return value[ARGS_KEY]\n }\n const check = validateHandler(value, cb)\n if (check.length) {\n // log('runValidationAction', key, value)\n throw new JsonqlTypeError(key, check)\n }\n if (value[ENUM_KEY] !== false && !enumHandler(value[ARGS_KEY], value[ENUM_KEY])) {\n // log(ENUM_KEY, value[ENUM_KEY])\n throw new JsonqlEnumError(key)\n }\n if (value[CHECKER_KEY] !== false && !checkerHandler(value[ARGS_KEY], value[CHECKER_KEY])) {\n // log(CHECKER_KEY, value[CHECKER_KEY])\n throw new JsonqlCheckerError(key)\n }\n return value[ARGS_KEY]\n }\n}\n\n/**\n * @param {object} args from the config2argsAction\n * @param {function} cb validateSync\n * @return {object} of configuration values\n */\nexport default function runValidation(args, cb) {\n const [ argsForValidate, pristineValues ] = args\n // turn the thing into an array and see what happen here\n // debugFn('_args', argsForValidate)\n const result = mapValues(argsForValidate, runValidationAction(cb))\n return merge(result, pristineValues)\n}\n","/// this is port back from the client to share across all projects\n\nimport merge from 'lodash-es/merge'\nimport { prepareArgsForValidation } from './prepare-args-for-validation'\nimport runValidation from './run-validation'\n\n// import debug from 'debug'\n// const debugFn = debug('jsonql-params-validator:check-options-async')\n\n/**\n * Quick transform\n * @param {object} config that one\n * @param {object} appProps mutation configuration options\n * @return {object} put that arg into the args\n */\nconst configToArgs = (config, appProps) => {\n return Promise.resolve(\n prepareArgsForValidation(config, appProps)\n )\n}\n\n/**\n * @param {object} config user provide configuration option\n * @param {object} appProps mutation configuration options\n * @param {object} constProps the immutable configuration options\n * @param {function} cb the validateSync method\n * @return {object} Promise resolve merge config object\n */\nexport default function(config = {}, appProps, constProps, cb) {\n return configToArgs(config, appProps)\n .then(args1 => runValidation(args1, cb))\n // next if every thing good then pass to final merging\n .then(args2 => merge({}, args2, constProps))\n}\n","// create function to construct the config entry so we don't need to keep building object\n\nimport isFunction from 'lodash-es/isFunction'\nimport isString from 'lodash-es/isString'\nimport {\n ARGS_KEY,\n TYPE_KEY,\n CHECKER_KEY,\n ENUM_KEY,\n OPTIONAL_KEY,\n ALIAS_KEY\n} from 'jsonql-constants'\n\nimport { checkIsArray } from '../array'\n// import checkIsBoolean from '../boolean'\n// import debug from 'debug';\n// const debugFn = debug('jsonql-params-validator:construct-config');\n/**\n * @param {*} args value\n * @param {string} type for value\n * @param {boolean} [optional=false]\n * @param {boolean|array} [enumv=false]\n * @param {boolean|function} [checker=false]\n * @return {object} config entry\n */\nexport default function constructConfig(args, type, optional=false, enumv=false, checker=false, alias=false) {\n let base = {\n [ARGS_KEY]: args,\n [TYPE_KEY]: type\n }\n if (optional === true) {\n base[OPTIONAL_KEY] = true\n }\n if (checkIsArray(enumv)) {\n base[ENUM_KEY] = enumv\n }\n if (isFunction(checker)) {\n base[CHECKER_KEY] = checker\n }\n if (isString(alias)) {\n base[ALIAS_KEY] = alias\n }\n return base\n}\n","// export also create wrapper methods\nimport checkOptionsAsync from './check-options-async'\nimport checkOptionsSync from './check-options-sync'\nimport constructConfigFn from './construct-config'\nimport {\n ENUM_KEY,\n CHECKER_KEY,\n ALIAS_KEY,\n OPTIONAL_KEY\n} from 'jsonql-constants'\n\n/**\n * This has a different interface\n * @param {*} value to supply\n * @param {string|array} type for checking\n * @param {object} params to map against the config check\n * @param {array} params.enumv NOT enum\n * @param {boolean} params.optional false then nothing\n * @param {function} params.checker need more work on this one later\n * @param {string} params.alias mostly for cmd\n */\nconst createConfig = (value, type, params = {}) => {\n // Note the enumv not ENUM\n // const { enumv, optional, checker, alias } = params;\n // let args = [value, type, optional, enumv, checker, alias];\n const {\n [OPTIONAL_KEY]: o,\n [ENUM_KEY]: e,\n [CHECKER_KEY]: c,\n [ALIAS_KEY]: a\n } = params;\n return constructConfigFn.apply(null, [value, type, o, e, c, a])\n}\n\n// for testing purpose\nconst JSONQL_PARAMS_VALIDATOR_INFO = '__PLACEHOLDER__'\n\n/**\n * construct the actual end user method, rename with prefix get since 1.5.2\n * @param {function} validateSync validation method\n * @return {function} for performaning the actual valdiation\n */\nconst getCheckConfigAsync = function(validateSync) {\n /**\n * We recreate the method here to avoid the circlar import\n * @param {object} config user supply configuration\n * @param {object} appProps mutation options\n * @param {object} [constantProps={}] optional: immutation options\n * @return {object} all checked configuration\n */\n return function(config, appProps, constantProps= {}) {\n return checkOptionsAsync(config, appProps, constantProps, validateSync)\n }\n}\n\n/**\n * copy of above but it's sync, rename with prefix get since 1.5.2\n * @param {function} validateSync validation method\n * @return {function} for performaning the actual valdiation\n */\nconst getCheckConfig = function(validateSync) {\n return function(config, appProps, constantProps = {}) {\n return checkOptionsSync(config, appProps, constantProps, validateSync)\n }\n}\n\n// re-export\nexport {\n createConfig,\n constructConfigFn,\n getCheckConfigAsync,\n getCheckConfig,\n JSONQL_PARAMS_VALIDATOR_INFO\n}\n","// export\nimport {\n checkIsObject,\n notEmpty,\n checkIsAny,\n checkIsString,\n checkIsBoolean,\n checkIsNumber,\n checkIsArray\n} from './src'\nimport * as validator from './src/validator'\n// configuration checking\nimport * as jsonqlOptions from './src/options'\n// the two extra functions\nimport isInArray from './src/is-in-array'\nimport isObjectHasKeyFn from './src/is-key-in-object'\n\nconst isObject = checkIsObject\nconst isAny = checkIsAny\nconst isString = checkIsString\nconst isBoolean = checkIsBoolean\nconst isNumber = checkIsNumber\nconst isArray = checkIsArray\nconst isNotEmpty = notEmpty\n\nconst normalizeArgs = validator.normalizeArgs\nconst validateSync = validator.validateSync\nconst validateAsync = validator.validateAsync\n\nconst JSONQL_PARAMS_VALIDATOR_INFO = jsonqlOptions.JSONQL_PARAMS_VALIDATOR_INFO\n\nconst createConfig = jsonqlOptions.createConfig\nconst constructConfig = jsonqlOptions.constructConfigFn\n// construct the final output 1.5.2\nconst checkConfigAsync = jsonqlOptions.getCheckConfigAsync(validator.validateSync)\nconst checkConfig = jsonqlOptions.getCheckConfig(validator.validateSync)\n\nconst inArray = isInArray\nconst isObjectHasKey = isObjectHasKeyFn\n\n// check returns methods \nimport { \n checkReturns, \n checkReturnsAsync, \n checkResolverReturns, \n checkResolverReturnsAsync \n} from './src/returns'\n\n\n// group the in one \nexport {\n JSONQL_PARAMS_VALIDATOR_INFO,\n \n isObject,\n isAny,\n isString,\n isBoolean,\n isNumber,\n isArray,\n isNotEmpty,\n \n inArray,\n isObjectHasKey,\n\n normalizeArgs,\n validateSync,\n validateAsync,\n\n createConfig,\n constructConfig,\n checkConfig,\n checkConfigAsync,\n\n checkReturns, \n checkReturnsAsync, \n checkResolverReturns, \n checkResolverReturnsAsync\n}\n\n\n\n\n\n","// move the get logger stuff here\n\n// it does nothing\nconst dummyLogger = () => {}\n\n/**\n * re-use the debugOn prop to control this log method\n * @param {object} opts configuration\n * @return {function} the log function\n */\nconst getLogger = (opts) => {\n const { debugOn } = opts \n if (debugOn) {\n return (...args) => {\n Reflect.apply(console.info, console, ['[jsonql-ws-client-core]', ...args])\n }\n }\n return dummyLogger\n}\n\n/**\n * Make sure there is a log method\n * @param {object} opts configuration\n * @return {object} opts\n */\nconst getLogFn = opts => {\n const { log } = opts // 1.3.9 if we pass a log method here then we use this\n if (!log || typeof log !== 'function') {\n return getLogger(opts)\n }\n opts.log('---> getLogFn user supplied log function <---', opts)\n return log\n}\n\nexport { getLogFn }","// group all the repetitive message here\n\nexport const TAKEN_BY_OTHER_TYPE_ERR = 'You are trying to register an event already been taken by other type:'\n","// Create two WeakMap store as a private keys\nexport const NB_EVENT_SERVICE_PRIVATE_STORE = new WeakMap()\nexport const NB_EVENT_SERVICE_PRIVATE_LAZY = new WeakMap()\n","/**\n * generate a 32bit hash based on the function.toString()\n * _from http://stackoverflow.com/questions/7616461/generate-a-hash-_from-string-in-javascript-jquery\n * @param {string} s the converted to string function\n * @return {string} the hashed function string\n */\nexport function hashCode(s) {\n\treturn s.split(\"\").reduce(function(a,b){a=((a<<5)-a)+b.charCodeAt(0);return a&a},0)\n}\n\n/**\n * wrapper to make sure it string\n * @param {*} input whatever\n * @return {string} output\n */\nexport function hashCode2Str(s) {\n return hashCode(s) + ''\n}\n\n/**\n * Just check if a pattern is an RegExp object\n * @param {*} pat whatever\n * @return {boolean} false when its not\n */\nexport function isRegExp(pat) {\n return pat instanceof RegExp\n}\n\n/**\n * check if its string\n * @param {*} arg whatever\n * @return {boolean} false when it's not\n */\nexport function isString(arg) {\n return typeof arg === 'string'\n}\n\n/**\n * Find from the array by matching the pattern\n * @param {*} pattern a string or RegExp object\n * @return {object} regex object or false when we can not id the input\n */\nexport function getRegex(pattern) {\n switch (true) {\n case isRegExp(pattern) === true:\n return pattern\n case isString(pattern) === true:\n return new RegExp(pattern)\n default:\n return false\n }\n}\n","// making all the functionality on it's own\n// import { WatchClass } from './watch'\n/*\nwe use a different way to do the same watch thing now\nthis.watch('suspend', function(value, prop, oldValue) {\n this.logger(`${prop} set from ${oldValue} to ${value}`)\n // it means it set the suspend = true then release it\n if (oldValue === true && value === false) {\n // we want this happen after the return happens\n setTimeout(() => {\n this.release()\n }, 1)\n }\n return value; // we need to return the value to store it\n})\n*/\nimport { getRegex, isRegExp } from './utils'\n\nexport default class SuspendClass {\n\n constructor() {\n // suspend, release and queue\n this.__suspend_state__ = null\n // to do this proper we don't use a new prop to hold the event name pattern\n this.__pattern__ = null\n this.queueStore = new Set()\n }\n\n /**\n * start suspend\n * @return {void}\n */\n $suspend() {\n this.logger(`---> SUSPEND ALL OPS <---`)\n this.__suspend__(true)\n }\n\n /**\n * release the queue\n * @return {void}\n */\n $release() {\n this.logger(`---> RELEASE SUSPENDED QUEUE <---`)\n this.__suspend__(false)\n }\n\n /**\n * suspend event by pattern\n * @param {string} pattern the pattern search matches the event name\n * @return {void}\n */\n $suspendEvent(pattern) {\n const regex = getRegex(pattern)\n if (isRegExp(regex)) {\n this.__pattern__ = regex\n return this.$suspend()\n }\n throw new Error(`We expect a pattern variable to be string or RegExp, but we got \"${typeof regex}\" instead`)\n }\n\n /**\n * queuing call up when it's in suspend mode\n * @param {string} evt the event name\n * @param {*} args unknown number of arguments\n * @return {boolean} true when added or false when it's not\n */\n $queue(evt, ...args) {\n this.logger('($queue) get called')\n if (this.__suspend_state__ === true) {\n if (isRegExp(this.__pattern__)) { // it's better then check if its not null\n // check the pattern and decide if we want to suspend it or not\n let found = this.__pattern__.test(evt)\n if (!found) {\n return false\n }\n }\n this.logger('($queue) added to $queue', args)\n // @TODO there shouldn't be any duplicate, but how to make sure?\n this.queueStore.add([evt].concat(args))\n // return this.queueStore.size\n }\n return !!this.__suspend_state__\n }\n\n /**\n * a getter to get all the store queue\n * @return {array} Set turn into Array before return\n */\n get $queues() {\n let size = this.queueStore.size\n this.logger('($queues)', `size: ${size}`)\n if (size > 0) {\n return Array.from(this.queueStore)\n }\n return []\n }\n\n /**\n * to set the suspend and check if it's boolean value\n * @param {boolean} value to trigger\n */\n __suspend__(value) {\n if (typeof value === 'boolean') {\n const lastValue = this.__suspend_state__\n this.__suspend_state__ = value\n this.logger(`($suspend) Change from \"${lastValue}\" --> \"${value}\"`)\n if (lastValue === true && value === false) {\n this.__release__()\n }\n } else {\n throw new Error(`$suspend only accept Boolean value! we got ${typeof value}`)\n }\n }\n\n /**\n * Release the queue\n * @return {int} size if any\n */\n __release__() {\n let size = this.queueStore.size\n let pattern = this.__pattern__\n this.__pattern__ = null\n this.logger(`(release) was called with ${size}${pattern ? ' for \"' + pattern + '\"': ''} item${size > 1 ? 's' : ''}`)\n if (size > 0) {\n const queue = Array.from(this.queueStore)\n this.queueStore.clear()\n this.logger('(release queue)', queue)\n queue.forEach(args => {\n this.logger(args)\n Reflect.apply(this.$trigger, this, args)\n })\n this.logger(`Release size ${this.queueStore.size}`)\n }\n\n return size\n }\n}\n","// break up the main file because its getting way too long\nimport {\n NB_EVENT_SERVICE_PRIVATE_STORE,\n NB_EVENT_SERVICE_PRIVATE_LAZY\n} from './store'\nimport { hashCode2Str, isString } from './utils'\nimport SuspendClass from './suspend'\n\nexport default class StoreService extends SuspendClass {\n\n constructor(config = {}) {\n super()\n if (config.logger && typeof config.logger === 'function') {\n this.logger = config.logger\n }\n this.keep = config.keep\n // for the $done setter\n this.result = config.keep ? [] : null\n // we need to init the store first otherwise it could be a lot of checking later\n this.normalStore = new Map()\n this.lazyStore = new Map()\n }\n\n /**\n * validate the event name(s)\n * @param {string[]} evt event name\n * @return {boolean} true when OK\n */\n validateEvt(...evt) {\n evt.forEach(e => {\n if (!isString(e)) {\n this.logger('(validateEvt)', e)\n throw new Error(`Event name must be string type! we got ${typeof e}`)\n }\n })\n return true\n }\n\n /**\n * Simple quick check on the two main parameters\n * @param {string} evt event name\n * @param {function} callback function to call\n * @return {boolean} true when OK\n */\n validate(evt, callback) {\n if (this.validateEvt(evt)) {\n if (typeof callback === 'function') {\n return true\n }\n }\n throw new Error(`callback required to be function type! we got ${typeof callback}`)\n }\n\n /**\n * Check if this type is correct or not added in V1.5.0\n * @param {string} type for checking\n * @return {boolean} true on OK\n */\n validateType(type) {\n this.validateEvt(type)\n const types = ['on', 'only', 'once', 'onlyOnce']\n return !!types.filter(t => type === t).length\n }\n\n /**\n * Run the callback\n * @param {function} callback function to execute\n * @param {array} payload for callback\n * @param {object} ctx context or null\n * @return {void} the result store in $done\n */\n run(callback, payload, ctx) {\n this.logger('(run) callback:', callback, 'payload:', payload, 'context:', ctx)\n this.$done = Reflect.apply(callback, ctx, this.toArray(payload))\n }\n\n /**\n * Take the content out and remove it from store id by the name\n * @param {string} evt event name\n * @param {string} [storeName = lazyStore] name of store\n * @return {object|boolean} content or false on not found\n */\n takeFromStore(evt, storeName = 'lazyStore') {\n let store = this[storeName] // it could be empty at this point\n if (store) {\n this.logger('(takeFromStore)', storeName, store)\n if (store.has(evt)) {\n let content = store.get(evt)\n this.logger(`(takeFromStore) has \"${evt}\"`, content)\n store.delete(evt)\n return content\n }\n return false\n }\n throw new Error(`\"${storeName}\" is not supported!`)\n }\n\n /**\n * This was part of the $get. We take it out\n * so we could use a regex to remove more than one event\n * @param {object} store the store to return from\n * @param {string} evt event name\n * @param {boolean} full return just the callback or everything\n * @return {array|boolean} false when not found\n */\n findFromStore(evt, store, full = false) {\n if (store.has(evt)) {\n return Array\n .from(store.get(evt))\n .map( l => {\n if (full) {\n return l\n }\n let [key, callback, ] = l\n return callback\n })\n }\n return false\n }\n\n /**\n * Similar to the findFromStore, but remove\n * @param {string} evt event name\n * @param {object} store the store to remove from\n * @return {boolean} false when not found\n */\n removeFromStore(evt, store) {\n if (store.has(evt)) {\n this.logger('($off)', evt)\n store.delete(evt)\n return true\n }\n return false\n }\n\n /**\n * The add to store step is similar so make it generic for resuse\n * @param {object} store which store to use\n * @param {string} evt event name\n * @param {spread} args because the lazy store and normal store store different things\n * @return {array} store and the size of the store\n */\n addToStore(store, evt, ...args) {\n let fnSet\n if (store.has(evt)) {\n this.logger(`(addToStore) \"${evt}\" existed`)\n fnSet = store.get(evt)\n } else {\n this.logger(`(addToStore) create new Set for \"${evt}\"`)\n // this is new\n fnSet = new Set()\n }\n // lazy only store 2 items - this is not the case in V1.6.0 anymore\n // we need to check the first parameter is string or not\n if (args.length > 2) {\n if (Array.isArray(args[0])) { // lazy store\n // check if this type of this event already register in the lazy store\n let [,,t] = args\n if (!this.checkTypeInLazyStore(evt, t)) {\n fnSet.add(args)\n }\n } else {\n if (!this.checkContentExist(args, fnSet)) {\n this.logger(`(addToStore) insert new`, args)\n fnSet.add(args)\n }\n }\n } else { // add straight to lazy store\n fnSet.add(args)\n }\n store.set(evt, fnSet)\n return [store, fnSet.size]\n }\n\n /**\n * @param {array} args for compare\n * @param {object} fnSet A Set to search from\n * @return {boolean} true on exist\n */\n checkContentExist(args, fnSet) {\n let list = Array.from(fnSet)\n return !!list.filter(li => {\n let [hash,] = li\n return hash === args[0]\n }).length\n }\n\n /**\n * get the existing type to make sure no mix type add to the same store\n * @param {string} evtName event name\n * @param {string} type the type to check\n * @return {boolean} true you can add, false then you can't add this type\n */\n checkTypeInStore(evtName, type) {\n this.validateEvt(evtName, type)\n let all = this.$get(evtName, true)\n if (all === false) {\n // pristine it means you can add\n return true\n }\n // it should only have ONE type in ONE event store\n return !all.filter(list => {\n let [ ,,,t ] = list\n return type !== t\n }).length\n }\n\n /**\n * This is checking just the lazy store because the structure is different\n * therefore we need to use a new method to check it\n */\n checkTypeInLazyStore(evtName, type) {\n this.validateEvt(evtName, type)\n let store = this.lazyStore.get(evtName)\n this.logger('(checkTypeInLazyStore)', store)\n if (store) {\n return !!Array\n .from(store)\n .filter(li => {\n let [,,t] = li\n return t !== type\n }).length\n }\n return false\n }\n\n /**\n * wrapper to re-use the addToStore,\n * V1.3.0 add extra check to see if this type can add to this evt\n * @param {string} evt event name\n * @param {string} type on or once\n * @param {function} callback function\n * @param {object} context the context the function execute in or null\n * @return {number} size of the store\n */\n addToNormalStore(evt, type, callback, context = null) {\n this.logger(`(addToNormalStore) try to add \"${type}\" --> \"${evt}\" to normal store`)\n // @TODO we need to check the existing store for the type first!\n if (this.checkTypeInStore(evt, type)) {\n this.logger('(addToNormalStore)', `\"${type}\" --> \"${evt}\" can add to normal store`)\n let key = this.hashFnToKey(callback)\n let args = [this.normalStore, evt, key, callback, context, type]\n let [_store, size] = Reflect.apply(this.addToStore, this, args)\n this.normalStore = _store\n return size\n }\n return false\n }\n\n /**\n * Add to lazy store this get calls when the callback is not register yet\n * so we only get a payload object or even nothing\n * @param {string} evt event name\n * @param {array} payload of arguments or empty if there is none\n * @param {object} [context=null] the context the callback execute in\n * @param {string} [type=false] register a type so no other type can add to this evt\n * @return {number} size of the store\n */\n addToLazyStore(evt, payload = [], context = null, type = false) {\n // this is add in V1.6.0\n // when there is type then we will need to check if this already added in lazy store\n // and no other type can add to this lazy store\n let args = [this.lazyStore, evt, this.toArray(payload), context]\n if (type) {\n args.push(type)\n }\n let [_store, size] = Reflect.apply(this.addToStore, this, args)\n this.lazyStore = _store\n this.logger(`(addToLazyStore) size: ${size}`)\n return size\n }\n\n /**\n * make sure we store the argument correctly\n * @param {*} arg could be array\n * @return {array} make sured\n */\n toArray(arg) {\n return Array.isArray(arg) ? arg : [arg]\n }\n\n /**\n * setter to store the Set in private\n * @param {object} obj a Set\n */\n set normalStore(obj) {\n NB_EVENT_SERVICE_PRIVATE_STORE.set(this, obj)\n }\n\n /**\n * @return {object} Set object\n */\n get normalStore() {\n return NB_EVENT_SERVICE_PRIVATE_STORE.get(this)\n }\n\n /**\n * setter to store the Set in lazy store\n * @param {object} obj a Set\n */\n set lazyStore(obj) {\n NB_EVENT_SERVICE_PRIVATE_LAZY.set(this , obj)\n }\n\n /**\n * @return {object} the lazy store Set\n */\n get lazyStore() {\n return NB_EVENT_SERVICE_PRIVATE_LAZY.get(this)\n }\n\n /**\n * generate a hashKey to identify the function call\n * The build-in store some how could store the same values!\n * @param {function} fn the converted to string function\n * @return {string} hashKey\n */\n hashFnToKey(fn) {\n return hashCode2Str(fn.toString())\n }\n}\n","// The top level\nimport { TAKEN_BY_OTHER_TYPE_ERR } from './constants'\nimport StoreService from './store-service'\n// export\nexport default class EventService extends StoreService {\n /**\n * class constructor\n */\n constructor(config = {}) {\n super(config)\n }\n\n /**\n * logger function for overwrite\n */\n logger() {}\n\n // for id if the instance is this class\n get $name() {\n return 'to1source-event'\n }\n\n // take this down in the next release\n get is() {\n return this.$name\n }\n\n //////////////////////////\n // PUBLIC METHODS //\n //////////////////////////\n\n /**\n * Register your evt handler, note we don't check the type here,\n * we expect you to be sensible and know what you are doing.\n * @param {string} evt name of event\n * @param {function} callback bind method --> if it's array or not\n * @param {object} [context=null] to execute this call in\n * @return {number} the size of the store\n */\n $on(evt , callback , context = null) {\n const type = 'on'\n this.validate(evt, callback)\n // first need to check if this evt is in lazy store\n let lazyStoreContent = this.takeFromStore(evt)\n // this is normal register first then call later\n if (lazyStoreContent === false) {\n this.logger(`($on) \"${evt}\" is not in lazy store`)\n // @TODO we need to check if there was other listener to this\n // event and are they the same type then we could solve that\n // register the different type to the same event name\n return this.addToNormalStore(evt, type, callback, context)\n }\n this.logger(`($on) ${evt} found in lazy store`)\n // this is when they call $trigger before register this callback\n let size = 0\n lazyStoreContent.forEach(content => {\n let [ payload, ctx, t ] = content\n if (t && t !== type) {\n throw new Error(`${TAKEN_BY_OTHER_TYPE_ERR} ${t}`)\n }\n this.logger(`($on)`, `call run \"${evt}\"`)\n this.run(callback, payload, context || ctx)\n size += this.addToNormalStore(evt, type, callback, context || ctx)\n })\n\n this.logger(`($on) return size ${size}`)\n return size\n }\n\n /**\n * once only registered it once, there is no overwrite option here\n * @NOTE change in v1.3.0 $once can add multiple listeners\n * but once the event fired, it will remove this event (see $only)\n * @param {string} evt name\n * @param {function} callback to execute\n * @param {object} [context=null] the handler execute in\n * @return {boolean} result\n */\n $once(evt , callback , context = null) {\n this.validate(evt, callback)\n const type = 'once'\n let lazyStoreContent = this.takeFromStore(evt)\n // this is normal register before call $trigger\n let nStore = this.normalStore;\n if (lazyStoreContent === false) {\n this.logger(`($once) \"${evt}\" is not in the lazy store`)\n // v1.3.0 $once now allow to add multiple listeners\n return this.addToNormalStore(evt, type, callback, context)\n } else {\n // now this is the tricky bit\n // there is a potential bug here that cause by the developer\n // if they call $trigger first, the lazy won't know it's a once call\n // so if in the middle they register any call with the same evt name\n // then this $once call will be fucked - add this to the documentation\n this.logger('($once)', lazyStoreContent)\n const list = Array.from(lazyStoreContent)\n // should never have more than 1\n const [ payload, ctx, t ] = list[0]\n if (t && t !== type) {\n throw new Error(`${TAKEN_BY_OTHER_TYPE_ERR} ${t}`)\n }\n this.logger('($once)', `call run \"${evt}\"`)\n this.run(callback, payload, context || ctx)\n // remove this evt from store\n this.$off(evt)\n }\n }\n\n /**\n * This one event can only bind one callbackback\n * @param {string} evt event name\n * @param {function} callback event handler\n * @param {object} [context=null] the context the event handler execute in\n * @return {boolean} true bind for first time, false already existed\n */\n $only(evt, callback, context = null) {\n this.validate(evt, callback)\n const type = 'only'\n let added = false\n let lazyStoreContent = this.takeFromStore(evt)\n // this is normal register before call $trigger\n let nStore = this.normalStore\n if (!nStore.has(evt)) {\n this.logger(`($only) \"${evt}\" add to normalStore`)\n added = this.addToNormalStore(evt, type, callback, context)\n }\n if (lazyStoreContent !== false) {\n // there are data store in lazy store\n this.logger(`($only) \"${evt}\" found data in lazy store to execute`)\n const list = Array.from(lazyStoreContent)\n // $only allow to trigger this multiple time on the single handler\n list.forEach( li => {\n const [ payload, ctx, t ] = li\n if (t && t !== type) {\n throw new Error(`${TAKEN_BY_OTHER_TYPE_ERR} ${t}`)\n }\n this.logger(`($only) call run \"${evt}\"`)\n this.run(callback, payload, context || ctx)\n })\n }\n return added\n }\n\n /**\n * $only + $once this is because I found a very subtile bug when we pass a\n * resolver, rejecter - and it never fire because that's OLD added in v1.4.0\n * @param {string} evt event name\n * @param {function} callback to call later\n * @param {object} [context=null] exeucte context\n * @return {void}\n */\n $onlyOnce(evt, callback, context = null) {\n this.validate(evt, callback)\n const type = 'onlyOnce'\n let added = false\n let lazyStoreContent = this.takeFromStore(evt)\n // this is normal register before call $trigger\n let nStore = this.normalStore;\n if (!nStore.has(evt)) {\n this.logger(`($onlyOnce) \"${evt}\" add to normalStore`)\n added = this.addToNormalStore(evt, type, callback, context)\n }\n if (lazyStoreContent !== false) {\n // there are data store in lazy store\n this.logger('($onlyOnce)', lazyStoreContent)\n const list = Array.from(lazyStoreContent)\n // should never have more than 1\n const [ payload, ctx, t ] = list[0]\n if (t && t !== 'onlyOnce') {\n throw new Error(`${TAKEN_BY_OTHER_TYPE_ERR} ${t}`)\n }\n this.logger(`($onlyOnce) call run \"${evt}\"`)\n this.run(callback, payload, context || ctx)\n // remove this evt from store\n this.$off(evt)\n }\n return added\n }\n\n /**\n * This is a shorthand of $off + $on added in V1.5.0\n * @param {string} evt event name\n * @param {function} callback to exeucte\n * @param {object} [context = null] or pass a string as type\n * @param {string} [type=on] what type of method to replace\n * @return {*}\n */\n $replace(evt, callback, context = null, type = 'on') {\n if (this.validateType(type)) {\n this.$off(evt)\n let method = this['$' + type]\n this.logger(`($replace)`, evt, callback)\n return Reflect.apply(method, this, [evt, callback, context])\n }\n throw new Error(`${type} is not supported!`)\n }\n\n /**\n * trigger the event\n * @param {string} evt name NOT allow array anymore!\n * @param {mixed} [payload = []] pass to fn\n * @param {object|string} [context = null] overwrite what stored\n * @param {string} [type=false] if pass this then we need to add type to store too\n * @return {number} if it has been execute how many times\n */\n $trigger(evt , payload = [] , context = null, type = false) {\n this.validateEvt(evt)\n let found = 0\n // first check the normal store\n let nStore = this.normalStore\n this.logger('($trigger) normalStore', nStore)\n if (nStore.has(evt)) {\n this.logger(`($trigger) \"${evt}\" found`)\n // @1.8.0 to add the suspend queue\n let added = this.$queue(evt, payload, context, type)\n if (added) {\n this.logger(`($trigger) Currently suspended \"${evt}\" added to queue, nothing executed. Exit now.`)\n return false // not executed\n }\n let nSet = Array.from(nStore.get(evt))\n let ctn = nSet.length\n let hasOnce = false\n let hasOnly = false\n for (let i=0; i < ctn; ++i) {\n ++found;\n // this.logger('found', found)\n let [ _, callback, ctx, type ] = nSet[i]\n this.logger(`($trigger) call run for ${evt}`)\n this.run(callback, payload, context || ctx)\n if (type === 'once' || type === 'onlyOnce') {\n hasOnce = true;\n }\n }\n if (hasOnce) {\n nStore.delete(evt)\n }\n return found\n }\n // now this is not register yet\n this.addToLazyStore(evt, payload, context, type)\n return found\n }\n\n /**\n * this is an alias to the $trigger\n * @NOTE breaking change in V1.6.0 we swap the parameter aroun\n * @NOTE breaking change: v1.9.1 it return an function to accept the params as spread\n * @param {string} evt event name\n * @param {string} type of call\n * @param {object} context what context callback execute in\n * @return {*} from $trigger\n */\n $call(evt, type = false, context = null) {\n const ctx = this\n\n return (...args) => {\n let _args = [evt, args, context, type]\n return Reflect.apply(ctx.$trigger, ctx, _args)\n }\n }\n\n /**\n * remove the evt from all the stores\n * @param {string} evt name\n * @return {boolean} true actually delete something\n */\n $off(evt) {\n // @TODO we will allow a regex pattern to mass remove event\n this.validateEvt(evt)\n let stores = [ this.lazyStore, this.normalStore ]\n\n return !!stores\n .filter(store => store.has(evt))\n .map(store => this.removeFromStore(evt, store))\n .length\n }\n\n /**\n * return all the listener bind to that event name\n * @param {string} evtName event name\n * @param {boolean} [full=false] if true then return the entire content\n * @return {array|boolean} listerner(s) or false when not found\n */\n $get(evt, full = false) {\n // @TODO should we allow the same Regex to search for all?\n this.validateEvt(evt)\n let store = this.normalStore\n return this.findFromStore(evt, store, full)\n }\n\n /**\n * store the return result from the run\n * @param {*} value whatever return from callback\n */\n set $done(value) {\n this.logger('($done) set value: ', value)\n if (this.keep) {\n this.result.push(value)\n } else {\n this.result = value\n }\n }\n\n /**\n * @TODO is there any real use with the keep prop?\n * getter for $done\n * @return {*} whatever last store result\n */\n get $done() {\n this.logger('($done) get result:', this.result)\n if (this.keep) {\n return this.result[this.result.length - 1]\n }\n return this.result\n }\n\n /**\n * Take a look inside the stores\n * @param {number|null} idx of the store, null means all\n * @return {void}\n */\n $debug(idx = null) {\n let names = ['lazyStore', 'normalStore']\n let stores = [this.lazyStore, this.normalStore]\n if (stores[idx]) {\n this.logger(names[idx], stores[idx])\n } else {\n stores.map((store, i) => {\n this.logger(names[i], store)\n })\n }\n }\n}\n","// default\nimport To1sourceEvent from './src/event-service'\n\nexport default To1sourceEvent\n","// this will generate a event emitter and will be use everywhere\nimport EventEmitterClass from '@to1source/event'\n// create a clone version so we know which one we actually is using\nclass JsonqlWsEvt extends EventEmitterClass {\n\n constructor(logger) {\n if (typeof logger !== 'function') {\n throw new Error(`Just die here the logger is not a function!`)\n }\n logger(`---> Create a new EventEmitter <---`)\n // this ee will always come with the logger\n // because we should take the ee from the configuration\n super({ logger })\n }\n\n get name() {\n return'jsonql-ws-client-core'\n }\n}\n\n/**\n * getting the event emitter\n * @param {object} opts configuration\n * @return {object} the event emitter instance\n */\nconst getEventEmitter = opts => {\n const { log, eventEmitter } = opts\n \n if (eventEmitter) {\n log(`eventEmitter is:`, eventEmitter.name)\n return eventEmitter\n }\n \n return new JsonqlWsEvt( opts.log )\n}\n\nexport { \n getEventEmitter, \n EventEmitterClass // for other module to build from \n}\n","// group all the small functions here\nimport { EMIT_REPLY_TYPE } from 'jsonql-constants'\nimport { toArray, createEvt } from 'jsonql-utils/src/generic'\nimport JsonqlValidationError from 'jsonql-errors/src/validation-error'\n\n\n/**\n * WebSocket is strict about the path, therefore we need to make sure before it goes in\n * @param {string} url input url\n * @return {string} url with correct path name\n */\nexport const fixWss = url => {\n const uri = url.toLowerCase()\n if (uri.indexOf('http') > -1) {\n if (uri.indexOf('https') > -1) {\n return uri.replace('https', 'wss')\n }\n return uri.replace('http', 'ws')\n }\n return uri\n}\n\n\n/**\n * get a stock host name from browser\n */\nexport const getHostName = () => {\n try {\n return [window.location.protocol, window.location.host].join('//')\n } catch(e) {\n throw new JsonqlValidationError(e)\n }\n}\n\n/**\n * Unbind the event\n * @param {object} ee EventEmitter\n * @param {string} namespace\n * @return {void}\n */\nexport const clearMainEmitEvt = (ee, namespace) => {\n let nsps = toArray(namespace)\n nsps.forEach(n => {\n ee.$off(createEvt(n, EMIT_REPLY_TYPE))\n })\n}\n\n\n","// constants\n\nimport {\n EMIT_REPLY_TYPE,\n JS_WS_SOCKET_IO_NAME,\n JS_WS_NAME,\n ON_MESSAGE_FN_NAME,\n ON_RESULT_FN_NAME\n} from 'jsonql-constants'\n\nconst SOCKET_IO = JS_WS_SOCKET_IO_NAME\nconst WS = JS_WS_NAME\n\nconst AVAILABLE_SERVERS = [SOCKET_IO, WS]\n\nconst SOCKET_NOT_DEFINE_ERR = 'socket is not define in the contract file!'\n\nconst SERVER_NOT_SUPPORT_ERR = 'is not supported server name!'\n\nconst MISSING_PROP_ERR = 'Missing property in contract!'\n\nconst UNKNOWN_CLIENT_ERR = 'Unknown client type!'\n\nconst EMIT_EVT = EMIT_REPLY_TYPE\n\nconst NAMESPACE_KEY = 'namespaceMap'\n\nconst UNKNOWN_RESULT = 'UKNNOWN RESULT!'\n\nconst NOT_ALLOW_OP = 'This operation is not allow!'\n\nconst MY_NAMESPACE = 'myNamespace'\n\nconst CB_FN_NAME = 'on'\n// this is a socket only (for now) feature so we just put it here \nconst DISCONNECTED_ERROR_MSG = `You have disconnected from the socket server, please reconnect.`\n\nexport {\n SOCKET_IO,\n WS,\n AVAILABLE_SERVERS,\n SOCKET_NOT_DEFINE_ERR,\n SERVER_NOT_SUPPORT_ERR,\n MISSING_PROP_ERR,\n UNKNOWN_CLIENT_ERR,\n EMIT_EVT,\n ON_MESSAGE_FN_NAME,\n ON_RESULT_FN_NAME,\n NAMESPACE_KEY,\n UNKNOWN_RESULT,\n NOT_ALLOW_OP,\n MY_NAMESPACE,\n CB_FN_NAME,\n DISCONNECTED_ERROR_MSG\n}\n","// breaking it up further to share between methods\nimport { DATA_KEY, ERROR_KEY } from 'jsonql-constants'\nimport { UNKNOWN_RESULT } from '../options/constants'\nimport { isObjectHasKey } from '../utils'\n\n/**\n * break out to use in different places to handle the return from server\n * @param {object} data from server\n * @param {function} resolver NOT from promise\n * @param {function} rejecter NOT from promise\n * @return {void} nothing\n */\nexport function respondHandler(data, resolver, rejecter) {\n if (isObjectHasKey(data, ERROR_KEY)) {\n // debugFn('-- rejecter called --', data[ERROR_KEY])\n rejecter(data[ERROR_KEY])\n } else if (isObjectHasKey(data, DATA_KEY)) {\n // debugFn('-- resolver called --', data[DATA_KEY])\n resolver(data[DATA_KEY])\n } else {\n // debugFn('-- UNKNOWN_RESULT --', data)\n rejecter({message: UNKNOWN_RESULT, error: data})\n }\n}\n","// the actual trigger call method\nimport { ON_RESULT_FN_NAME, EMIT_REPLY_TYPE } from 'jsonql-constants'\nimport { createEvt, toArray } from '../utils'\nimport { respondHandler } from './respond-handler'\n\n/**\n * just wrapper\n * @param {object} ee EventEmitter\n * @param {string} namespace where this belongs\n * @param {string} resolverName resolver\n * @param {array} args arguments\n * @param {function} log function \n * @return {void} nothing\n */\nexport function actionCall(ee, namespace, resolverName, args = [], log) {\n // reply event \n const outEventName = createEvt(namespace, EMIT_REPLY_TYPE)\n\n log(`actionCall: ${outEventName} --> ${resolverName}`, args)\n // This is the out going call \n ee.$trigger(outEventName, [resolverName, toArray(args)])\n \n // then we need to listen to the event callback here as well\n return new Promise((resolver, rejecter) => {\n const inEventName = createEvt(namespace, resolverName, ON_RESULT_FN_NAME)\n // this cause the onResult got the result back first \n // and it should be the promise resolve first\n // @TODO we need to rewrote the respondHandler to change the problem stated above \n ee.$on(\n inEventName,\n function actionCallResultHandler(result) {\n log(`got the first result`, result)\n respondHandler(result, resolver, rejecter)\n }\n )\n })\n}\n","// setting up the send method \nimport { JsonqlValidationError } from 'jsonql-errors'\nimport {\n ON_ERROR_FN_NAME,\n SEND_MSG_FN_NAME\n} from 'jsonql-constants'\nimport { validateAsync } from 'jsonql-params-validator'\nimport { objDefineProps, createEvt, toArray, nil } from '../utils'\nimport { actionCall } from './action-call'\n\n/** \n * pairing with the server vesrion SEND_MSG_FN_NAME\n * last of the chain so only return the resolver (fn)\n * This is now change to a getter / setter method \n * and call like this: resolver.send(...args)\n * @param {function} fn the resolver function \n * @param {object} ee event emitter instance \n * @param {string} namespace the namespace it belongs to \n * @param {string} resolverName name of the resolver \n * @param {object} params from contract \n * @param {function} log a logger function\n * @return {function} return the resolver itself \n */ \nexport const setupSendMethod = (fn, ee, namespace, resolverName, params, log) => (\n objDefineProps(\n fn, \n SEND_MSG_FN_NAME, \n nil, \n function sendHandler() {\n // let _log = (...args) => Reflect.apply(console.info, console, ['[SEND]'].concat(args))\n /** \n * This will follow the same pattern like the resolver \n * @param {array} args list of unknown argument follow the resolver \n * @return {promise} resolve the result \n */\n return function sendCallback(...args) {\n return validateAsync(args, params.params, true)\n .then(_args => {\n // @TODO check the result \n // because the validation could failed with the list of fail properties \n log(namespace, resolverName, _args)\n return actionCall(ee, namespace, resolverName, _args, _log)\n })\n .catch(err => {\n // @TODO it shouldn't be just a validation error \n // it could be server return error, so we need to check \n // what error we got back here first \n log('send error', err)\n // @TODO it might not an validation error need the finalCatch here\n ee.$call(\n createEvt(namespace, resolverName, ON_ERROR_FN_NAME),\n [new JsonqlValidationError(resolverName, err)]\n )\n })\n } \n })\n)\n","// break up the original setup resolver method here\n// import { JsonqlValidationError, finalCatch } from 'jsonql-errors'\nimport {\n ON_ERROR_FN_NAME,\n ON_MESSAGE_FN_NAME,\n ON_RESULT_FN_NAME\n} from 'jsonql-constants'\n// local \nimport { MY_NAMESPACE } from '../options/constants'\nimport { chainFns, objDefineProps, injectToFn, createEvt, isFunc } from '../utils'\nimport { respondHandler } from './respond-handler'\nimport { setupSendMethod } from './setup-send-method'\n\n/**\n * The first one in the chain, just setup a namespace prop\n * the rest are passing through\n * @param {function} fn the resolver function\n * @param {object} ee the event emitter \n * @param {string} resolverName what it said\n * @param {object} params for resolver from contract\n * @param {function} log the logger function\n * @return {array}\n */\nconst setupNamespace = (fn, ee, namespace, resolverName, params, log) => [\n injectToFn(fn, MY_NAMESPACE, namespace),\n ee,\n namespace,\n resolverName,\n params,\n log \n]\n\n/** \n * onResult handler\n */ \nconst setupOnResult = (fn, ee, namespace, resolverName, params, log) => [\n objDefineProps(fn, ON_RESULT_FN_NAME, function(resultCallback) {\n if (isFunc(resultCallback)) {\n ee.$on(\n createEvt(namespace, resolverName, ON_RESULT_FN_NAME),\n function resultHandler(result) {\n respondHandler(result, resultCallback, (error) => {\n log(`Catch error: \"${resolverName}\"`, error)\n ee.$trigger(\n createEvt(namespace, resolverName, ON_ERROR_FN_NAME), \n error\n )\n })\n }\n )\n }\n }),\n ee,\n namespace,\n resolverName,\n params,\n log\n]\n\n/** \n * we do need to add the send prop back because it's the only way to deal with\n * bi-directional data stream \n */\nconst setupOnMessage = (fn, ee, namespace, resolverName, params, log) => [\n objDefineProps(fn, ON_MESSAGE_FN_NAME, function(messageCallback) {\n // we expect this to be a function\n if (isFunc(messageCallback)) {\n // did that add to the callback\n let onMessageCallback = (args) => {\n respondHandler(args, messageCallback, (error) => {\n log(`Catch error: \"${resolverName}\"`, error)\n ee.$trigger(\n createEvt(namespace, resolverName, ON_ERROR_FN_NAME), \n error\n )\n })\n }\n // register the handler for this message event\n ee.$only(\n createEvt(namespace, resolverName, ON_MESSAGE_FN_NAME), \n onMessageCallback\n )\n }\n }),\n ee,\n namespace,\n resolverName,\n params,\n log\n]\n\n/** \n * ON_ERROR_FN_NAME handler\n */\nconst setupOnError = (fn, ee, namespace, resolverName, params, log) => [\n objDefineProps(fn, ON_ERROR_FN_NAME, function(resolverErrorHandler) {\n if (isFunc(resolverErrorHandler)) {\n // please note ON_ERROR_FN_NAME can add multiple listners\n ee.$only(\n createEvt(namespace, resolverName, ON_ERROR_FN_NAME), \n resolverErrorHandler\n )\n }\n }),\n ee,\n namespace,\n resolverName,\n params,\n log\n]\n\n/**\n * Add extra property / listeners to the resolver\n * @param {string} namespace where this belongs\n * @param {string} resolverName name as event name\n * @param {object} params from contract\n * @param {function} fn resolver function\n * @param {object} ee EventEmitter\n * @param {function} log function \n * @return {function} resolver\n */\nexport function setupResolver(namespace, resolverName, params, fn, ee, log) {\n let fns = [\n setupNamespace, \n setupOnResult, \n setupOnMessage, \n setupOnError, \n setupSendMethod\n ]\n \n // get the executor\n const executor = Reflect.apply(chainFns, null, fns)\n const args = [fn, ee, namespace, resolverName, params, log]\n\n return Reflect.apply(executor, null, args)\n}\n","// put all the resolver related methods here to make it more clear\n\n// this will be a mini client server architect\n// The reason is when the enableAuth setup - the private route\n// might not be validated, but we need the callable point is ready\n// therefore this part will always take the contract and generate\n// callable api for the developer to setup their front end\n// the only thing is - when they call they might get an error or\n// NOT_LOGIN_IN and they can react to this error accordingly\nimport { finalCatch } from 'jsonql-errors'\nimport { validateAsync } from 'jsonql-params-validator'\nimport { setupResolver } from './setup-resolver'\nimport { actionCall } from './action-call'\nimport {\n createEvt,\n objDefineProps,\n isFunc,\n injectToFn\n} from '../utils'\nimport {\n ON_ERROR_FN_NAME,\n ON_READY_FN_NAME\n} from 'jsonql-constants'\n\n/**\n * create the actual function to send message to server\n * @param {object} ee EventEmitter instance\n * @param {string} namespace this resolver end point\n * @param {string} resolverName name of resolver as event name\n * @param {object} params from contract\n * @param {function} log pass the log function\n * @return {function} resolver\n */\nfunction createResolver(ee, namespace, resolverName, params, log) {\n // note we pass the new withResult=true option\n return function resolver(...args) {\n return validateAsync(args, params.params, true)\n .then(_args => actionCall(ee, namespace, resolverName, _args, log))\n .catch(finalCatch)\n }\n}\n\n/**\n * step one get the clientmap with the namespace\n * @param {object} opts configuration\n * @param {object} ee EventEmitter\n * @param {object} nspGroup resolvers index by their namespace\n * @return {promise} resolve the clientmapped, and start the chain\n */\nexport function generateResolvers(opts, ee, nspGroup) {\n let client= {}\n let { log } = opts\n\n for (let namespace in nspGroup) {\n let list = nspGroup[namespace]\n for (let resolverName in list) {\n // resolverNames.push(resolverName)\n let params = list[resolverName]\n let fn = createResolver(ee, namespace, resolverName, params, log)\n // this should set as a getter therefore can not be overwrite by accident\n // obj[resolverName] = setupResolver(namespace, resolverName, params, fn, ee)\n client = injectToFn(\n client,\n resolverName,\n setupResolver(namespace, resolverName, params, fn, ee, log)\n )\n }\n }\n // resolve the clientto start the chain\n // chain the result to allow the chain processing\n return [ client, opts, ee, nspGroup ]\n}\n\n/**\n * The problem is the namespace can have more than one\n * and we only have on onError message\n * @param {object} clientthe client itself\n * @param {object} opts configuration\n * @param {object} ee Event Emitter\n * @param {object} nspGroup namespace keys\n * @return {array} [obj, opts, ee]\n */\nexport function setupNamespaceErrorListener(client, opts, ee, nspGroup) {\n return [\n objDefineProps(\n client,\n ON_ERROR_FN_NAME,\n function namespaceErrorCallbackHandler(namespaceErrorHandler) {\n if (isFunc(namespaceErrorHandler)) {\n // please note ON_ERROR_FN_NAME can add multiple listners\n for (let namespace in nspGroup) {\n // this one is very tricky, we need to make sure the trigger is calling\n // with the namespace as well as the error\n ee.$on(createEvt(namespace, ON_ERROR_FN_NAME), namespaceErrorHandler)\n }\n }\n }\n ),\n opts,\n ee\n ]\n}\n\n/**\n * This event will fire when the socket.io.on('connection') and ws.onopen\n * @param {object} client client itself\n * @param {object} opts configuration\n * @param {object} ee Event Emitter\n * @return {array} [ obj, opts, ee ]\n */\nexport function setupOnReadyListener(client, opts, ee) {\n return [\n objDefineProps(\n client,\n ON_READY_FN_NAME,\n function onReadyCallbackHandler(onReadyCallback) {\n if (isFunc(onReadyCallback)) {\n // reduce it down to just one flat level\n // @2020-03-19 only allow ONE onReady callback otherwise\n // it will get fire multiple times which is not what we want\n ee.$only(ON_READY_FN_NAME, onReadyCallback)\n }\n }\n ),\n opts,\n ee\n ]\n}\n","// resolvers generator\n// we change the interface to return promise from v1.0.3\n// this way we make sure the obj return is correct and timely\nimport { chainFns } from '../utils'\nimport { setupAuthMethods } from './setup-auth-methods'\nimport {\n generateResolvers,\n setupOnReadyListener,\n setupNamespaceErrorListener\n} from './generator-methods'\n\nimport {\n NSP_GROUP\n} from 'jsonql-constants'\n\n/**\n * prepare the methods\n * @param {object} opts configuration\n * @param {object} nspMap resolvers index by their namespace\n * @param {object} ee EventEmitter\n * @return {object} of resolvers\n * @public\n */\nexport function callersGenerator(opts, nspMap, ee) {\n let fns = [\n generateResolvers,\n setupOnReadyListener,\n setupNamespaceErrorListener\n ]\n if (opts.enableAuth) {\n fns.push(createAuthMethods)\n }\n // we will always get back the [ obj, opts, ee ]\n // then we only return the obj (wsClient)\n // This has move outside of here, into the main method\n // the reason is we could switch around the sequence much easier\n // fns.push(setupFinalStep)\n // run it\n const generator = Reflect.apply(chainFns, null, fns)\n\n return generator(opts, ee, nspMap[NSP_GROUP])\n}\n","// this is a new method that will create several\n// intercom method also reverse listen to the server\n// such as disconnect (server issue disconnect)\nimport { injectToFn } from '../utils'\nimport { DISCONNECT_EVENT_NAME } from 'jsonql-constants'\n\n/**\n * this is the new method that setup the intercom handler\n * also this serve as the final call in the then chain to\n * output the client\n * @param {object} client the client\n * @param {object} opts configuration\n * @param {object} ee the event emitter\n * @return {object} client\n */\nexport function setupInterCom(client, opts, ee) {\n const { disconnectHandlerName } = opts\n\n return injectToFn(\n client,\n disconnectHandlerName,\n function disconnectHandler(...args) {\n ee.$trigger(DISCONNECT_EVENT_NAME, args)\n }\n )\n}\n","// The final step of the setup before it returns the client\nimport { setupInterCom } from './setup-intercom'\n\n/**\n * The final step to return the client\n * @param {object} params wrapper object to call the result forward \n * @param {object} params.client the client\n * @param {object} params.opts configuration\n * @param {object} params.ee the event emitter\n * @return {object} client\n */\nfunction setupFinalStep({ obj, opts, ee }) {\n\n const client = setupInterCom(obj, opts, ee)\n\n opts.log(`---> The final step to return the ws-client <---`)\n // add some debug functions\n client.verifyEventEmitter = () => ee.is\n // we add back the two things into the client\n // then when we do integration, we run it in reverse,\n // create the ws client first then the host client\n client.eventEmitter = opts.eventEmitter\n client.log = opts.log\n // we just inject a helloWorld method here\n // client[HELLO_FN] =\n\n return client\n}\n\n\nexport { setupFinalStep }\n","// create options\nimport {\n checkConfigAsync,\n checkConfig\n} from 'jsonql-params-validator'\nimport {\n wsCoreCheckMap,\n wsCoreConstProps,\n socketCheckMap\n} from './defaults'\nimport {\n fixWss,\n getHostName,\n getEventEmitter,\n getNspInfoByConfig,\n getLogFn\n} from '../utils'\n\n/**\n * We need this to find the socket server type\n * @param {*} config\n * @return {string} the name of the socket server if any\n */\nfunction checkSocketClientType(config) {\n return checkConfig(config, socketCheckMap)\n}\n\n/**\n * Create a combine checkConfig for the creating the combine client\n * @param {*} configCheckMap\n * @param {*} constProps\n * @return {function} takes the user input config then resolve the configuration\n */\nfunction createCombineConfigCheck(configCheckMap, constProps) {\n const combineCheckMap = Object.assign({}, configCheckMap, wsCoreCheckMap)\n const combineConstProps = Object.assign({}, constProps, wsCoreConstProps)\n return config => checkConfigAsync(config, combineCheckMap, combineConstProps)\n}\n\n\n/**\n * wrapper method to check this already did the pre check\n * @param {object} config user supply config\n * @param {object} defaultOptions for checking\n * @param {object} constProps user supply const props\n * @return {promise} resolve to the checked opitons\n */\nfunction checkConfiguration(config, defaultOptions, constProps) {\n const defaultCheckMap= Object.assign(wsCoreCheckMap, defaultOptions)\n const wsConstProps = Object.assign(wsCoreConstProps, constProps)\n\n return checkConfigAsync(config, defaultCheckMap, wsConstProps)\n}\n\n/**\n * Taking the `then` part from the method below\n * @param {object} opts\n * @return {promise} opts all done\n */\nfunction postCheckInjectOpts(opts) {\n return Promise.resolve(opts)\n .then(opts => {\n if (!opts.hostname) {\n opts.hostname = getHostName()\n }\n // @TODO the contract now will supply the namespace information\n // and we need to use that to group the namespace call\n opts.wssPath = fixWss([opts.hostname, opts.namespace].join('/'), opts.serverType)\n // get the log function here\n opts.log = getLogFn(opts)\n\n opts.eventEmitter = getEventEmitter(opts)\n\n return opts\n })\n}\n\n/**\n * Don't want to make things confusing\n * Breaking up the opts process in one place\n * then generate the necessary parameter in another step\n * @2020-3-20 here we suspend operation by it's namespace first\n * Then in the framework part, after the connection establish we release\n * the queue\n * @param {object} opts checked --> merge --> injected\n * @return {object} {opts, nspMap, ee}\n */\nfunction createRequiredParams(opts) {\n const nspMap = getNspInfoByConfig(opts)\n const ee = opts.eventEmitter\n // @TODO here we are going to add suspend event to the namespace related methods\n \n\n return { opts, nspMap, ee }\n}\n\nexport {\n // properties\n wsCoreCheckMap,\n wsCoreConstProps,\n // functions\n checkConfiguration,\n postCheckInjectOpts,\n createRequiredParams,\n // this will just get export for integration\n checkSocketClientType,\n createCombineConfigCheck\n}\n","// the top level API\n// The goal is to create a generic method that will able to handle\n// any kind of clients\n// import { injectToFn } from 'jsonql-utils'\nimport {\n callersGenerator,\n setupFinalStep\n} from './callers'\nimport {\n checkConfiguration,\n postCheckInjectOpts,\n createRequiredParams\n} from './options'\n\n\n/**\n * 0.5.0 we break up the wsClientCore in two parts one without the config check\n * @param {function} socketClientListener\n * @return {function} to actually generate the client\n */\nexport function wsClientCoreAction(socketClientListener) {\n /**\n * This is a breaking change, to continue the onion skin design\n * @param {object} config the already checked config\n * @return {promise} resolve the client\n */\n return (config = {}) => {\n\n return postCheckInjectOpts(config)\n // the following two moved to wsPostConfig\n .then(createRequiredParams)\n .then(\n ({opts, nspMap, ee}) => socketClientListener(opts, nspMap, ee)\n )\n .then( // there is problem here, we wrap up the operation inside\n ({opts, nspMap, ee}) => callersGenerator(opts, nspMap, ee)\n )\n .then(setupFinalStep)\n .catch(err => {\n console.error(`jsonql-ws-core-client init error`, err)\n })\n }\n}\n\n/**\n * The main interface which will generate the socket clients and map all events\n * @param {object} socketClientListerner this is the one method export by various clients\n * @param {object} [configCheckMap={}] we should do all the checking in the core instead of the client\n * @param {object} [constProps={}] add this to supply the constProps from the downstream client\n * @return {function} accept a config then return the wsClient instance with all the available API\n */\nexport function wsClientCore(socketClientListener, configCheckMap = {}, constProps = {}) {\n // we need to inject property to this client later\n return (config = {}) => checkConfiguration(config, configCheckMap, constProps)\n .then(\n wsClientCoreAction(socketClientListener)\n )\n}\n","// this is getting too confusing \n// therefore we move it back to the framework specific \n\n/**\n * wrapper method to create a nsp without login\n * @param {string|boolean} namespace namespace url could be false\n * @param {object} opts configuration\n * @return {object} ws client instance\n */\nfunction createNspClient(namespace, opts) {\n const { hostname, wssPath, wsOptions, nspClient, log } = opts\n const url = namespace ? [hostname, namespace].join('/') : wssPath\n log(`createNspClient --> `, url)\n\n return nspClient(url, wsOptions)\n}\n\n/**\n * wrapper method to create a nsp with token auth\n * @param {string} namespace namespace url\n * @param {object} opts configuration\n * @return {object} ws client instance\n */\nfunction createNspAuthClient(namespace, opts) {\n const { hostname, wssPath, token, wsOptions, nspAuthClient, log } = opts\n const url = namespace ? [hostname, namespace].join('/') : wssPath\n \n log(`createNspAuthClient -->`, url)\n\n if (token && typeof token !== 'string') {\n throw new Error(`Expect token to be string, but got ${token}`)\n }\n \n return nspAuthClient(url, token, wsOptions)\n}\n\nexport {\n createNspClient,\n createNspAuthClient\n}\n","// this use by client-event-handler\nimport { ON_ERROR_FN_NAME } from 'jsonql-constants'\nimport { createEvt } from '../utils'\n\n/**\n * trigger errors on all the namespace onError handler\n * @param {object} ee Event Emitter\n * @param {array} namespaces nsps string\n * @param {string} message optional\n * @return {void}\n */\nexport function triggerNamespacesOnError(ee, namespaces, message) {\n namespaces.forEach( namespace => {\n ee.$trigger(\n createEvt(namespace, ON_ERROR_FN_NAME), \n [{ message, namespace }]\n )\n })\n}\n\n/**\n * Handle the onerror callback \n * @param {object} ee event emitter \n * @param {string} namespace which namespace has error \n * @param {*} err error object\n * @return {void} \n */\nexport const handleNamespaceOnError = (ee, namespace, err) => {\n ee.$trigger(createEvt(namespace, ON_ERROR_FN_NAME), [err])\n}","// NOT IN USE AT THE MOMENT JUST KEEP IT HERE FOR THE TIME BEING \nimport {\n LOGOUT_EVENT_NAME,\n NOT_LOGIN_ERR_MSG,\n ON_ERROR_FN_NAME,\n ON_RESULT_FN_NAME,\n DISCONNECT_EVENT_NAME\n} from 'jsonql-constants'\nimport { EMIT_EVT, DISCONNECTED_ERROR_MSG } from '../options/constants'\nimport { createEvt, clearMainEmitEvt } from '../utils'\nimport { triggerNamespacesOnError } from './trigger-namespaces-on-error'\n\n/**\n * Only when there is a private namespace then we bind to this event\n * @param {object} nsps the available nsp(s)\n * @param {array} namespaces available namespace \n * @param {object} ee eventEmitter \n * @param {object} opts configuration\n * @return {void}\n */\nexport const logoutEvtListener = (nsps, namespaces, ee, opts) => {\n const { log } = opts \n // this will be available regardless enableAuth\n // because the server can log the client out\n ee.$on(\n LOGOUT_EVENT_NAME, \n function logoutEvtCallback() {\n const privateNamespace = getPrivateNamespace(namespaces)\n log(`${LOGOUT_EVENT_NAME} event triggered`)\n // disconnect(nsps, opts.serverType)\n // we need to issue error to all the namespace onError Listerner\n triggerNamespacesOnError(ee, [privateNamespace], LOGOUT_EVENT_NAME)\n // rebind all of the Listerner to the fake one\n log(`logout from ${privateNamespace}`)\n\n clearMainEmitEvt(ee, privateNamespace)\n // we need to issue one more call to the server before we disconnect\n // now this is a catch 22, here we are not suppose to do anything platform specific\n // so that should fire before trigger this event\n // clear out the nsp\n nsps[privateNamespace] = null \n // add a NOT LOGIN error if call\n notLoginWsListerner(privateNamespace, ee, opts)\n }\n )\n}\n\n/**\n * A Event Listerner placeholder when it's not connect to any nsp\n * @param {string} namespace nsp\n * @param {object} ee EventEmitter\n * @param {object} opts configuration\n * @return {void}\n */\nexport const notConnectedListener = (namespace, ee, opts) => {\n const { log } = opts \n\n ee.$only(\n createEvt(namespace, EMIT_EVT),\n function disconnectedEvtCallback(resolverName, args) {\n log(`[disconnectedListerner] hijack the ws call`, namespace, resolverName, args)\n const error = {\n message: DISCONNECTED_ERROR_MSG\n }\n ee.$call(createEvt(namespace, resolverName, ON_ERROR_FN_NAME), [ error ])\n // also trigger the result Listerner, but wrap inside the error key\n ee.$call(createEvt(namespace, resolverName, ON_RESULT_FN_NAME), [{ error }])\n }\n )\n}\n\n\n/**\n * The disconnect event Listerner, now we log the client out from everything\n * @TODO now we are another problem they disconnect, how to reconnect\n * @param {object} nsps the available nsp(s)\n * @param {array} namespaces available namespace \n * @param {object} ee eventEmitter \n * @param {object} opts configuration\n * @return {void}\n */\nexport const disconnectListener = (nsps, namespaces, ee, opts) => {\n const { log } = opts \n ee.$on(\n DISCONNECT_EVENT_NAME, \n function disconnectEvtCallback() {\n triggerNamespacesOnError(ee, namespaces, DISCONNECT_EVENT_NAME)\n namespaces.forEach( namespace => { \n log(`disconnect from ${namespace}`)\n\n clearMainEmitEvt(ee, namespace)\n nsps[namespace] = null \n disconnectedListerner(namespace, ee, opts)\n })\n }\n )\n}\n\n/**\n * A Event Listerner placeholder when it's not connect to the private nsp\n * @param {string} namespace nsp\n * @param {object} ee EventEmitter\n * @param {object} opts configuration\n * @return {void}\n */\nexport const notLoginListener = (namespace, ee, opts) => {\n const { log } = opts \n\n ee.$only(\n createEvt(namespace, EMIT_EVT),\n function notLoginListernerCallback(resolverName, args) {\n log('[notLoginListerner] hijack the ws call', namespace, resolverName, args)\n const error = { message: NOT_LOGIN_ERR_MSG }\n // It should just throw error here and should not call the result\n // because that's channel for handling normal event not the fake one\n ee.$call(createEvt(namespace, resolverName, ON_ERROR_FN_NAME), [ error ])\n // also trigger the result Listerner, but wrap inside the error key\n ee.$call(createEvt(namespace, resolverName, ON_RESULT_FN_NAME), [{ error }])\n }\n )\n}","// This is share between different clients so we export it\n// @TODO port what is in the ws-main-handler\n// because all the client side call are via the ee\n// and that makes it re-usable between different client setup\n\n/*\nInside the map call but we take it out for now and until the WebSocket version is fully working\nimport { SOCKET_IO } from '../options/constants'\n // @TODO need to double check this\n if (opts.serverType === SOCKET_IO) {\n let { nspGroup } = nspMap\n args.push(nspGroup[namespace])\n }\n*/\nimport { getPrivateNamespace } from 'jsonql-utils/src/namespace'\nimport { logoutEvtListener, notLoginListener } from './event-listeners'\n\n\n/**\n * centralize all the comm in one place\n * @param {function} bindSocketEventHandler binding the ee to ws --> this is the core bit\n * @param {object} nsps namespaced nsp\n * @return {void} nothing\n */\nexport function clientEventListener(bindSocketEventListener, nsps) {\n /**\n * BREAKING CHANGE instead of one flat structure\n * we return a function to accept the two \n * @param {object} opts configuration\n * @param {object} nspMap this is not in the opts \n * @param {object} ee Event Emitter instance\n * @return {array} although we return something but this is the last step and nothing to do further\n */\n return (opts, nspMap, ee) => {\n // since all these params already in the opts\n const { log } = opts\n const { namespaces } = nspMap\n // @1.1.3 add isPrivate prop to id which namespace is the private nsp\n // then we can use this prop to determine if we need to fire the ON_LOGIN_PROP_NAME event\n const privateNamespace = getPrivateNamespace(namespaces)\n \n return namespaces.map(namespace => {\n let isPrivate = privateNamespace === namespace\n log(namespace, ` --> ${isPrivate ? 'private': 'public'} nsp --> `, nsps[namespace] !== false)\n if (nsps[namespace]) {\n log('[call bindWsHandler]', isPrivate, namespace)\n\n let args = [namespace, nsps[namespace], ee, isPrivate, opts]\n // Finally we binding everything together\n Reflect.apply(bindSocketEventListener, null, args)\n\n } else {\n log(`binding notLoginWsHandler to ${namespace}`)\n // a dummy placeholder\n // @TODO but it should be a not connect handler \n // when it's not login (or fail) this should be handle differently \n notLoginListener(namespace, ee, opts)\n }\n if (isPrivate) {\n log(`Has private and add logoutEvtHandler`)\n logoutEvtListener(nsps, namespaces, ee, opts)\n }\n // just return something its not going to get use anywhere\n return isPrivate \n })\n }\n}\n","// jsonql-ws-core takes over the check configuration\n// here we only have to supply the options that is unique to this client\n// create options\nimport { JS_WS_NAME } from 'jsonql-constants'\n// constant props\nconst wsClientConstProps = {\n version: '__PLACEHOLDER__', // will get replace\n serverType: JS_WS_NAME\n}\n\nexport { wsClientConstProps }\n","// pass the different type of ws to generate the client\n// this is where the framework specific code get injected\nimport { TOKEN_PARAM_NAME } from 'jsonql-constants'\nimport { fixWss } from '../modules'\nimport {\n createInitPing, \n extractPingResult\n} from '../modules'\n\n/**\n * Group the ping and get respond create new client in one\n * @param {object} ws \n * @param {object} WebSocket \n * @param {string} url\n * @param {function} resolver \n * @param {function} rejecter \n * @param {boolean} auth client or not\n * @return {promise} resolve the confirm client\n */\nfunction initPingAction(ws, WebSocket, url, resolver, rejecter, wsOptions) {\n // @TODO how to we id this client can issue a CSRF\n // by origin? \n ws.onopen = function onOpenCallback() {\n ws.send(createInitPing())\n }\n\n ws.onmessage = function onMessageCallback(payload) {\n try {\n const header = extractPingResult(payload.data)\n // @NOTE the break down test in ws-client-core show no problems\n // the problem was cause by malform nspInfo that time? \n setTimeout(() => { // delay or not show no different but just on the safe side\n ws.terminate()\n }, 50)\n const newWs = new WebSocket(url, Object.assign(wsOptions, header)) \n resolver(newWs) \n } catch(e) {\n rejecter(e)\n }\n }\n\n ws.onerror = function onErrorCallback(err) {\n rejecter(err)\n }\n}\n\n/**\n * less duplicated code the better \n * @param {object} WebSocket \n * @param {string} url formatted url\n * @param {object} options or not\n * @return {promise} resolve the actual verified client\n */\nfunction asyncConnect(WebSocket, url, options) {\n \n return new Promise((resolver, rejecter) => { \n \n const unconfirmClient = new WebSocket(url, options)\n \n initPingAction(unconfirmClient, WebSocket, url, resolver, rejecter, options)\n })\n}\n\n\n/**\n * The bug was in the wsOptions where ws don't need it but socket.io do\n * therefore the object was pass as second parameter!\n * @NOTE here we only return a method to create the client, it might not get call \n * @param {object} WebSocket the client or node version of ws\n * @param {boolean} auth if it's auth then 3 param or just one\n * @param {object} opts this is a breaking change we will init the client twice\n */\nfunction initWebSocketClient(WebSocket, auth, log) {\n if (auth === false) {\n /**\n * Create a non-protected client\n * @param {string} url \n * @param {object} [wsOptions={}]\n * @return {promise} resolve to the confirmed client\n */\n return function createWsClient(url, wsOptions = {}) {\n const _url = fixWss(url)\n log(`nspClient: \\n${_url}\\n`, wsOptions)\n\n return asyncConnect(WebSocket, _url, wsOptions)\n }\n }\n\n /**\n * Create a client with auth token\n * @param {string} url start with ws:// @TODO check this?\n * @param {string} token the jwt token\n * @param {object} [wsOptions={}] extra options pass to the WebSocket object\n * @return {object} ws instance\n */\n return function createWsAuthClient(url, token, wsOptions = {}) {\n const ws_url = fixWss(url)\n // console.log('what happen here?', url, ws_url, token)\n const _url = token && typeof token === 'string' ? `${ws_url}?${TOKEN_PARAM_NAME}=${token}` : ws_url\n log(`nspAuthClient: \\n${_url}\\n`, wsOptions)\n\n return asyncConnect(WebSocket, _url, wsOptions)\n }\n}\n\nexport { initWebSocketClient }","/** Used for built-in method references. */\nvar objectProto = Object.prototype;\n\n/**\n * Used to resolve the\n * [`toStringTag`](http://ecma-international.org/ecma-262/7.0/#sec-object.prototype.tostring)\n * of values.\n */\nvar nativeObjectToString = objectProto.toString;\n\n/**\n * Converts `value` to a string using `Object.prototype.toString`.\n *\n * @private\n * @param {*} value The value to convert.\n * @returns {string} Returns the converted string.\n */\nfunction objectToString(value) {\n return nativeObjectToString.call(value);\n}\n\nexport default objectToString;\n","/**\n * Creates a unary function that invokes `func` with its argument transformed.\n *\n * @private\n * @param {Function} func The function to wrap.\n * @param {Function} transform The argument transform.\n * @returns {Function} Returns the new function.\n */\nfunction overArg(func, transform) {\n return function(arg) {\n return func(transform(arg));\n };\n}\n\nexport default overArg;\n","/**\n * Checks if `value` is object-like. A value is object-like if it's not `null`\n * and has a `typeof` result of \"object\".\n *\n * @static\n * @memberOf _\n * @since 4.0.0\n * @category Lang\n * @param {*} value The value to check.\n * @returns {boolean} Returns `true` if `value` is object-like, else `false`.\n * @example\n *\n * _.isObjectLike({});\n * // => true\n *\n * _.isObjectLike([1, 2, 3]);\n * // => true\n *\n * _.isObjectLike(_.noop);\n * // => false\n *\n * _.isObjectLike(null);\n * // => false\n */\nfunction isObjectLike(value) {\n return value != null && typeof value == 'object';\n}\n\nexport default isObjectLike;\n","/**\n * Removes all key-value entries from the list cache.\n *\n * @private\n * @name clear\n * @memberOf ListCache\n */\nfunction listCacheClear() {\n this.__data__ = [];\n this.size = 0;\n}\n\nexport default listCacheClear;\n","/**\n * Performs a\n * [`SameValueZero`](http://ecma-international.org/ecma-262/7.0/#sec-samevaluezero)\n * comparison between two values to determine if they are equivalent.\n *\n * @static\n * @memberOf _\n * @since 4.0.0\n * @category Lang\n * @param {*} value The value to compare.\n * @param {*} other The other value to compare.\n * @returns {boolean} Returns `true` if the values are equivalent, else `false`.\n * @example\n *\n * var object = { 'a': 1 };\n * var other = { 'a': 1 };\n *\n * _.eq(object, object);\n * // => true\n *\n * _.eq(object, other);\n * // => false\n *\n * _.eq('a', 'a');\n * // => true\n *\n * _.eq('a', Object('a'));\n * // => false\n *\n * _.eq(NaN, NaN);\n * // => true\n */\nfunction eq(value, other) {\n return value === other || (value !== value && other !== other);\n}\n\nexport default eq;\n","/**\n * Removes `key` and its value from the stack.\n *\n * @private\n * @name delete\n * @memberOf Stack\n * @param {string} key The key of the value to remove.\n * @returns {boolean} Returns `true` if the entry was removed, else `false`.\n */\nfunction stackDelete(key) {\n var data = this.__data__,\n result = data['delete'](key);\n\n this.size = data.size;\n return result;\n}\n\nexport default stackDelete;\n","/**\n * Gets the stack value for `key`.\n *\n * @private\n * @name get\n * @memberOf Stack\n * @param {string} key The key of the value to get.\n * @returns {*} Returns the entry value.\n */\nfunction stackGet(key) {\n return this.__data__.get(key);\n}\n\nexport default stackGet;\n","/**\n * Checks if a stack value for `key` exists.\n *\n * @private\n * @name has\n * @memberOf Stack\n * @param {string} key The key of the entry to check.\n * @returns {boolean} Returns `true` if an entry for `key` exists, else `false`.\n */\nfunction stackHas(key) {\n return this.__data__.has(key);\n}\n\nexport default stackHas;\n","/**\n * Checks if `value` is the\n * [language type](http://www.ecma-international.org/ecma-262/7.0/#sec-ecmascript-language-types)\n * of `Object`. (e.g. arrays, functions, objects, regexes, `new Number(0)`, and `new String('')`)\n *\n * @static\n * @memberOf _\n * @since 0.1.0\n * @category Lang\n * @param {*} value The value to check.\n * @returns {boolean} Returns `true` if `value` is an object, else `false`.\n * @example\n *\n * _.isObject({});\n * // => true\n *\n * _.isObject([1, 2, 3]);\n * // => true\n *\n * _.isObject(_.noop);\n * // => true\n *\n * _.isObject(null);\n * // => false\n */\nfunction isObject(value) {\n var type = typeof value;\n return value != null && (type == 'object' || type == 'function');\n}\n\nexport default isObject;\n","/** Used for built-in method references. */\nvar funcProto = Function.prototype;\n\n/** Used to resolve the decompiled source of functions. */\nvar funcToString = funcProto.toString;\n\n/**\n * Converts `func` to its source code.\n *\n * @private\n * @param {Function} func The function to convert.\n * @returns {string} Returns the source code.\n */\nfunction toSource(func) {\n if (func != null) {\n try {\n return funcToString.call(func);\n } catch (e) {}\n try {\n return (func + '');\n } catch (e) {}\n }\n return '';\n}\n\nexport default toSource;\n","/**\n * Gets the value at `key` of `object`.\n *\n * @private\n * @param {Object} [object] The object to query.\n * @param {string} key The key of the property to get.\n * @returns {*} Returns the property value.\n */\nfunction getValue(object, key) {\n return object == null ? undefined : object[key];\n}\n\nexport default getValue;\n","/**\n * Removes `key` and its value from the hash.\n *\n * @private\n * @name delete\n * @memberOf Hash\n * @param {Object} hash The hash to modify.\n * @param {string} key The key of the value to remove.\n * @returns {boolean} Returns `true` if the entry was removed, else `false`.\n */\nfunction hashDelete(key) {\n var result = this.has(key) && delete this.__data__[key];\n this.size -= result ? 1 : 0;\n return result;\n}\n\nexport default hashDelete;\n","/**\n * Checks if `value` is suitable for use as unique object key.\n *\n * @private\n * @param {*} value The value to check.\n * @returns {boolean} Returns `true` if `value` is suitable, else `false`.\n */\nfunction isKeyable(value) {\n var type = typeof value;\n return (type == 'string' || type == 'number' || type == 'symbol' || type == 'boolean')\n ? (value !== '__proto__')\n : (value === null);\n}\n\nexport default isKeyable;\n","/**\n * Creates a base function for methods like `_.forIn` and `_.forOwn`.\n *\n * @private\n * @param {boolean} [fromRight] Specify iterating from right to left.\n * @returns {Function} Returns the new base function.\n */\nfunction createBaseFor(fromRight) {\n return function(object, iteratee, keysFunc) {\n var index = -1,\n iterable = Object(object),\n props = keysFunc(object),\n length = props.length;\n\n while (length--) {\n var key = props[fromRight ? length : ++index];\n if (iteratee(iterable[key], key, iterable) === false) {\n break;\n }\n }\n return object;\n };\n}\n\nexport default createBaseFor;\n","/**\n * Copies the values of `source` to `array`.\n *\n * @private\n * @param {Array} source The array to copy values from.\n * @param {Array} [array=[]] The array to copy values to.\n * @returns {Array} Returns `array`.\n */\nfunction copyArray(source, array) {\n var index = -1,\n length = source.length;\n\n array || (array = Array(length));\n while (++index < length) {\n array[index] = source[index];\n }\n return array;\n}\n\nexport default copyArray;\n","/** Used for built-in method references. */\nvar objectProto = Object.prototype;\n\n/**\n * Checks if `value` is likely a prototype object.\n *\n * @private\n * @param {*} value The value to check.\n * @returns {boolean} Returns `true` if `value` is a prototype, else `false`.\n */\nfunction isPrototype(value) {\n var Ctor = value && value.constructor,\n proto = (typeof Ctor == 'function' && Ctor.prototype) || objectProto;\n\n return value === proto;\n}\n\nexport default isPrototype;\n","/**\n * Checks if `value` is classified as an `Array` object.\n *\n * @static\n * @memberOf _\n * @since 0.1.0\n * @category Lang\n * @param {*} value The value to check.\n * @returns {boolean} Returns `true` if `value` is an array, else `false`.\n * @example\n *\n * _.isArray([1, 2, 3]);\n * // => true\n *\n * _.isArray(document.body.children);\n * // => false\n *\n * _.isArray('abc');\n * // => false\n *\n * _.isArray(_.noop);\n * // => false\n */\nvar isArray = Array.isArray;\n\nexport default isArray;\n","/** Used as references for various `Number` constants. */\nvar MAX_SAFE_INTEGER = 9007199254740991;\n\n/**\n * Checks if `value` is a valid array-like length.\n *\n * **Note:** This method is loosely based on\n * [`ToLength`](http://ecma-international.org/ecma-262/7.0/#sec-tolength).\n *\n * @static\n * @memberOf _\n * @since 4.0.0\n * @category Lang\n * @param {*} value The value to check.\n * @returns {boolean} Returns `true` if `value` is a valid length, else `false`.\n * @example\n *\n * _.isLength(3);\n * // => true\n *\n * _.isLength(Number.MIN_VALUE);\n * // => false\n *\n * _.isLength(Infinity);\n * // => false\n *\n * _.isLength('3');\n * // => false\n */\nfunction isLength(value) {\n return typeof value == 'number' &&\n value > -1 && value % 1 == 0 && value <= MAX_SAFE_INTEGER;\n}\n\nexport default isLength;\n","/**\n * This method returns `false`.\n *\n * @static\n * @memberOf _\n * @since 4.13.0\n * @category Util\n * @returns {boolean} Returns `false`.\n * @example\n *\n * _.times(2, _.stubFalse);\n * // => [false, false]\n */\nfunction stubFalse() {\n return false;\n}\n\nexport default stubFalse;\n","/**\n * The base implementation of `_.unary` without support for storing metadata.\n *\n * @private\n * @param {Function} func The function to cap arguments for.\n * @returns {Function} Returns the new capped function.\n */\nfunction baseUnary(func) {\n return function(value) {\n return func(value);\n };\n}\n\nexport default baseUnary;\n","/**\n * Gets the value at `key`, unless `key` is \"__proto__\" or \"constructor\".\n *\n * @private\n * @param {Object} object The object to query.\n * @param {string} key The key of the property to get.\n * @returns {*} Returns the property value.\n */\nfunction safeGet(object, key) {\n if (key === 'constructor' && typeof object[key] === 'function') {\n return;\n }\n\n if (key == '__proto__') {\n return;\n }\n\n return object[key];\n}\n\nexport default safeGet;\n","/**\n * The base implementation of `_.times` without support for iteratee shorthands\n * or max array length checks.\n *\n * @private\n * @param {number} n The number of times to invoke `iteratee`.\n * @param {Function} iteratee The function invoked per iteration.\n * @returns {Array} Returns the array of results.\n */\nfunction baseTimes(n, iteratee) {\n var index = -1,\n result = Array(n);\n\n while (++index < n) {\n result[index] = iteratee(index);\n }\n return result;\n}\n\nexport default baseTimes;\n","/** Used as references for various `Number` constants. */\nvar MAX_SAFE_INTEGER = 9007199254740991;\n\n/** Used to detect unsigned integer values. */\nvar reIsUint = /^(?:0|[1-9]\\d*)$/;\n\n/**\n * Checks if `value` is a valid array-like index.\n *\n * @private\n * @param {*} value The value to check.\n * @param {number} [length=MAX_SAFE_INTEGER] The upper bounds of a valid index.\n * @returns {boolean} Returns `true` if `value` is a valid index, else `false`.\n */\nfunction isIndex(value, length) {\n var type = typeof value;\n length = length == null ? MAX_SAFE_INTEGER : length;\n\n return !!length &&\n (type == 'number' ||\n (type != 'symbol' && reIsUint.test(value))) &&\n (value > -1 && value % 1 == 0 && value < length);\n}\n\nexport default isIndex;\n","/**\n * This function is like\n * [`Object.keys`](http://ecma-international.org/ecma-262/7.0/#sec-object.keys)\n * except that it includes inherited enumerable properties.\n *\n * @private\n * @param {Object} object The object to query.\n * @returns {Array} Returns the array of property names.\n */\nfunction nativeKeysIn(object) {\n var result = [];\n if (object != null) {\n for (var key in Object(object)) {\n result.push(key);\n }\n }\n return result;\n}\n\nexport default nativeKeysIn;\n","/**\n * This method returns the first argument it receives.\n *\n * @static\n * @since 0.1.0\n * @memberOf _\n * @category Util\n * @param {*} value Any value.\n * @returns {*} Returns `value`.\n * @example\n *\n * var object = { 'a': 1 };\n *\n * console.log(_.identity(object) === object);\n * // => true\n */\nfunction identity(value) {\n return value;\n}\n\nexport default identity;\n","/**\n * A faster alternative to `Function#apply`, this function invokes `func`\n * with the `this` binding of `thisArg` and the arguments of `args`.\n *\n * @private\n * @param {Function} func The function to invoke.\n * @param {*} thisArg The `this` binding of `func`.\n * @param {Array} args The arguments to invoke `func` with.\n * @returns {*} Returns the result of `func`.\n */\nfunction apply(func, thisArg, args) {\n switch (args.length) {\n case 0: return func.call(thisArg);\n case 1: return func.call(thisArg, args[0]);\n case 2: return func.call(thisArg, args[0], args[1]);\n case 3: return func.call(thisArg, args[0], args[1], args[2]);\n }\n return func.apply(thisArg, args);\n}\n\nexport default apply;\n","/**\n * Creates a function that returns `value`.\n *\n * @static\n * @memberOf _\n * @since 2.4.0\n * @category Util\n * @param {*} value The value to return from the new function.\n * @returns {Function} Returns the new constant function.\n * @example\n *\n * var objects = _.times(2, _.constant({ 'a': 1 }));\n *\n * console.log(objects);\n * // => [{ 'a': 1 }, { 'a': 1 }]\n *\n * console.log(objects[0] === objects[1]);\n * // => true\n */\nfunction constant(value) {\n return function() {\n return value;\n };\n}\n\nexport default constant;\n","/** Used to detect hot functions by number of calls within a span of milliseconds. */\nvar HOT_COUNT = 800,\n HOT_SPAN = 16;\n\n/* Built-in method references for those with the same name as other `lodash` methods. */\nvar nativeNow = Date.now;\n\n/**\n * Creates a function that'll short out and invoke `identity` instead\n * of `func` when it's called `HOT_COUNT` or more times in `HOT_SPAN`\n * milliseconds.\n *\n * @private\n * @param {Function} func The function to restrict.\n * @returns {Function} Returns the new shortable function.\n */\nfunction shortOut(func) {\n var count = 0,\n lastCalled = 0;\n\n return function() {\n var stamp = nativeNow(),\n remaining = HOT_SPAN - (stamp - lastCalled);\n\n lastCalled = stamp;\n if (remaining > 0) {\n if (++count >= HOT_COUNT) {\n return arguments[0];\n }\n } else {\n count = 0;\n }\n return func.apply(undefined, arguments);\n };\n}\n\nexport default shortOut;\n","// break it out on its own because\n// it's building from the lodash-es from scratch\n// according to this discussion https://github.com/lodash/lodash/issues/3298\nimport isPlainObject from 'lodash-es/isPlainObject'\nimport merge from 'lodash-es/merge'\n\n/**\n * previously we already make sure the order of the namespaces\n * and attach the auth client to it\n * @param {array} promises array of unresolved promises\n * @param {boolean} asObject if true then merge the result object\n * @return {object} promise resolved with the array of promises resolved results\n */\nexport function chainPromises(promises, asObject = false) {\n return promises.reduce((promiseChain, currentTask) => (\n promiseChain.then(chainResults => (\n currentTask.then(currentResult => (\n asObject === false ? [...chainResults, currentResult] : merge(chainResults, currentResult)\n ))\n ))\n ), Promise.resolve(\n asObject === false ? [] : (isPlainObject(asObject) ? asObject : {})\n ))\n}\n\n\n/**\n * This one return a different result from the chainPromises\n * it will be the same like chainFns that take one promise resolve as the next fn parameter\n * @param {function} initPromise a function that accept param and resolve result\n * @param {array} promises array of function pass that resolve promises\n * @return {promise} resolve the processed result\n */\nexport function chainProcessPromises(initPromise, ...promises) {\n return (...args) => (\n promises.reduce((promiseChain, currentTask) => (\n promiseChain.then(chainResult => (\n currentTask(chainResult)\n )\n )\n ), Reflect.apply(initPromise, null, args))\n )\n}\n","// @BUG when call disconnected \n// this keep causing an \"Disconnect call failed TypeError: Cannot read property 'readyState' of null\"\n// I think that is because it's not login then it can not be disconnect\n// how do we track this state globally\nimport { LOGIN_EVENT_NAME } from 'jsonql-constants'\nimport { clearMainEmitEvt } from '../modules'\n\n/**\n * create a login event handler \n * @param {object} opts configurations \n * @param {object} nspMap contain all the required info\n * @param {object} ee event emitter \n * @return {void}\n */\nexport function loginEventHandler(opts, nspMap, ee) {\n const { log } = opts\n const { namespaces } = nspMap\n\n ee.$only(LOGIN_EVENT_NAME, function loginEventHandlerCallback(tokenFromLoginAction) {\n \n log('createClient LOGIN_EVENT_NAME $only handler')\n\n clearMainEmitEvt(ee, namespaces)\n // console.log('LOGIN_EVENT_NAME', token)\n const newNsps = createNspAction(opts, nspMap, tokenFromLoginAction)\n // rebind it\n Reflect.apply(\n clientEventHandler, // @NOTE is this the problem that cause the hang up?\n null,\n args.concat([newNsps.namespaces, newNsps.nsps])\n )\n })\n}","// bunch of generic helpers\n\nimport isArray from 'lodash-es/isArray'\nimport isPlainObject from 'lodash-es/isPlainObject'\nimport trim from 'lodash-es/trim'\n\n/**\n * DIY in Array\n * @param {array} arr to check from\n * @param {*} value to check against\n * @return {boolean} true on found\n */\nexport const inArray = (arr, value) => !!arr.filter(a => a === value).length\n\n// quick and dirty to turn non array to array\nexport const toArray = (arg) => isArray(arg) ? arg : [arg]\n\n/**\n * parse string to json or just return the original value if error happened\n * @param {*} n input\n * @param {boolean} [t=true] or throw\n * @return {*} json object on success\n */\nexport const parseJson = function(n, t=true) {\n try {\n return JSON.parse(n)\n } catch(e) {\n if (t) {\n return n\n }\n throw new Error(e)\n }\n}\n\n/**\n * @param {object} obj for search\n * @param {string} key target\n * @return {boolean} true on success\n */\nexport const isObjectHasKey = function(obj, key) {\n try {\n const keys = Object.keys(obj)\n return inArray(keys, key)\n } catch(e) {\n // @BUG when the obj is not an OBJECT we got some weird output\n return false\n }\n}\n\n/**\n * create a event name\n * @param {string[]} args\n * @return {string} event name for use\n */\nexport const createEvt = (...args) => args.join('_')\n\n/**\n * simple util method to get the value\n * @param {string} name of the key\n * @param {object} obj to take value from\n * @return {*} the object value id by name or undefined\n */\nexport const getConfigValue = (name, obj) => (\n obj && isPlainObject(obj) ? ( (name in obj) ? obj[name] : undefined ) : undefined\n)\n\n/**\n * small util to make sure the return value is valid JSON object\n * @param {*} n input\n * @return {object} correct JSON object\n */\nexport const toJson = n => {\n if (typeof n === 'string') {\n return parseJson(n)\n }\n return parseJson(JSON.stringify(n))\n}\n\n/**\n * Check several parameter that there is something in the param\n * @param {*} param input\n * @return {boolean}\n */\nexport const isNotEmpty = function(param) {\n return param !== undefined && param !== false && param !== null && trim(param) !== ''\n}\n\n/**\n * Simple check if the prop is function\n * @param {*} prop input\n * @return {boolean} true on success\n */\nexport const isFunc = prop => {\n if (typeof prop === 'function') {\n return true;\n }\n console.error(`Expect to be Function type! Got ${typeof prop}`)\n}\n\n// generic placeholder function\nexport const nil = () => false\n","// custom validation error class\n// when validaton failed\nexport default class JsonqlValidationError extends Error {\n constructor(...args) {\n super(...args)\n\n this.message = args[0]\n this.detail = args[1]\n\n this.className = JsonqlValidationError.name;\n\n if (Error.captureStackTrace) {\n Error.captureStackTrace(this, JsonqlValidationError)\n }\n }\n\n static get name() {\n return 'JsonqlValidationError'\n }\n}\n","/**\n * @param {boolean} sec return in second or not\n * @return {number} timestamp\n */\nexport const timestamp = (sec = false) => {\n let time = Date.now()\n return sec ? Math.floor( time / 1000 ) : time\n}\n","// ported from jsonql-params-validator\n// craete several helper function to construct / extract the payload\n// and make sure they are all the same\nimport {\n PAYLOAD_PARAM_NAME,\n CONDITION_PARAM_NAME,\n RESOLVER_PARAM_NAME,\n QUERY_ARG_NAME,\n TIMESTAMP_PARAM_NAME\n} from 'jsonql-constants'\n\nimport JsonqlValidationError from 'jsonql-errors/src/validation-error'\n\nimport isArray from 'lodash-es/isArray'\nimport isString from 'lodash-es/isString'\nimport isPlainObject from 'lodash-es/isPlainObject'\n\nimport { timestamp } from './timestamp'\nimport { parseJson } from './generic'\n\n/**\n * check if the payload has a timestamp field, then append a new timestamp to it\n * @param {object} payload from the com\n * @return {array} timestamp field with an array value\n */\nexport const handleTimestamp = payload => {\n let ts = payload[TIMESTAMP_PARAM_NAME]\n if (!isArray(ts)) {\n ts = [ts]\n }\n ts.push( timestamp() )\n\n return ts\n}\n\n/**\n * make sure it's an object (it was call formatPayload but it doesn't make sense)\n * @param {*} payload the object comes in could be string based\n * @return {object} the transformed payload\n */\nexport const toPayload = payload => isString(payload) ? parseJson(payload) : payload\n\n/**\n * @param {*} args arguments to send\n *@return {object} formatted payload\n */\nexport const formatPayload = (args) => (\n { [QUERY_ARG_NAME]: args }\n)\n\n/**\n * extract the resolver name from the payload \n * @param {object} payload\n * @return {string} resolver name \n */\nexport function getResolverFromPayload(payload) {\n const keys = Object.keys(payload)\n return keys.filter(key => key !== TIMESTAMP_PARAM_NAME)[0]\n}\n\n/**\n * wrapper method to add the timestamp as well\n * @param {string} resolverName\n * @param {*} payload\n * @return {object} delierable\n */\nexport function createDeliverable(resolverName, payload) {\n return {\n [resolverName]: payload,\n [TIMESTAMP_PARAM_NAME]: [ timestamp() ]\n }\n}\n\n/**\n * @param {string} resolverName name of function\n * @param {array} [args=[]] from the ...args\n * @param {boolean} [jsonp = false] add v1.3.0 to koa\n * @return {object} formatted argument\n */\nexport function createQuery(resolverName, args = [], jsonp = false) {\n if (isString(resolverName) && isArray(args)) {\n let payload = formatPayload(args)\n if (jsonp === true) {\n return payload\n }\n return createDeliverable(resolverName, payload)\n }\n throw new JsonqlValidationError(`[createQuery] expect resolverName to be string and args to be array!`, { resolverName, args })\n}\n\n/**\n * string version of the createQuery\n * @return {string}\n */\nexport function createQueryStr(resolverName, args = [], jsonp = false) {\n return JSON.stringify(createQuery(resolverName, args, jsonp))\n}\n\n/**\n * @param {string} resolverName name of function\n * @param {*} payload to send\n * @param {object} [condition={}] for what\n * @param {boolean} [jsonp = false] add v1.3.0 to koa\n * @return {object} formatted argument\n */\nexport function createMutation(resolverName, payload, condition = {}, jsonp = false) {\n const _payload = {\n [PAYLOAD_PARAM_NAME]: payload,\n [CONDITION_PARAM_NAME]: condition\n }\n if (jsonp === true) {\n return _payload\n }\n if (isString(resolverName)) {\n return createDeliverable(resolverName, _payload)\n }\n throw new JsonqlValidationError(`[createMutation] expect resolverName to be string!`, { resolverName, payload, condition })\n}\n\n/**\n * string version of createMutation\n * @return {string}\n */\nexport function createMutationStr(resolverName, payload, condition = {}, jsonp = false) {\n return JSON.stringify(createMutation(resolverName, payload, condition, jsonp))\n}\n\n/**\n * Extract the parts from payload and format for use\n * @param {string} resolverName name of fn\n * @param {object} payload the incoming json\n * @return {object|boolean} false on failed\n */\nexport function getQueryFromArgs(resolverName, payload) {\n if (resolverName && isPlainObject(payload)) {\n const args = payload[resolverName]\n if (args[QUERY_ARG_NAME]) {\n return {\n [RESOLVER_PARAM_NAME]: resolverName,\n [QUERY_ARG_NAME]: args[QUERY_ARG_NAME],\n [TIMESTAMP_PARAM_NAME]: handleTimestamp(payload)\n }\n }\n }\n return false\n}\n\n/**\n * Share function so no repeat\n * @param {object} payload the payload from client\n * @param {function} processor the last get result method\n * @return {*} result processed result\n */\nfunction processPayload(payload, processor) {\n const p = toPayload(payload)\n const resolverName = getResolverFromPayload(p)\n return Reflect.apply(processor, null, [resolverName, p])\n}\n\n/**\n * extra the payload back\n * @param {*} payload from http call\n * @return {object} resolverName and args\n */\nexport function getQueryFromPayload(payload) {\n const result = processPayload(payload, getQueryFromArgs)\n if (result !== false) {\n return result\n }\n throw new JsonqlValidationError('[getQueryArgs] Payload is malformed!', payload)\n}\n\n/**\n * Further break down from method below for use else where\n * @param {string} resolverName name of fn\n * @param {object} payload payload\n * @return {object|boolean} false on failed\n */\nexport function getMutationFromArgs(resolverName, payload) {\n if (resolverName && isPlainObject(payload)) {\n const args = payload[resolverName]\n if (args) {\n return {\n [RESOLVER_PARAM_NAME]: resolverName,\n [PAYLOAD_PARAM_NAME]: args[PAYLOAD_PARAM_NAME],\n [CONDITION_PARAM_NAME]: args[CONDITION_PARAM_NAME],\n [TIMESTAMP_PARAM_NAME]: handleTimestamp(payload)\n }\n }\n }\n return false\n}\n\n/**\n * @param {object} payload\n * @return {object} resolverName, payload, conditon\n */\nexport function getMutationFromPayload(payload) {\n const result = processPayload(payload, getMutationFromArgs)\n\n if (result !== false) {\n return result\n }\n throw new JsonqlValidationError('[getMutationArgs] Payload is malformed!', payload)\n}\n","// There are the socket related methods ported back from \n// ws-server-core and ws-client-core \nimport {\n WS_REPLY_TYPE,\n WS_EVT_NAME,\n WS_DATA_NAME,\n TIMESTAMP_PARAM_NAME,\n ERROR_KEY,\n EMIT_REPLY_TYPE,\n ACKNOWLEDGE_REPLY_TYPE\n} from 'jsonql-constants'\nimport { JsonqlError } from 'jsonql-errors' \nimport isString from 'lodash-es/isString'\n\nimport { toJson, isObjectHasKey, nil } from './generic'\nimport { timestamp } from './timestamp'\n\nconst PAYLOAD_NOT_DECODED_ERR = 'payload can not decoded'\nconst WS_KEYS = [\n WS_REPLY_TYPE,\n WS_EVT_NAME,\n WS_DATA_NAME\n]\n\n\n/**\n * The ws doesn't have a acknowledge callback like socket.io\n * so we have to DIY one for ws and other that doesn't have it\n * @param {string} type of reply\n * @param {string} resolverName which is replying\n * @param {*} data payload\n * @param {array} [ts= []] the last received ts, if any \n * @return {string} stringify json\n */\nexport const createWsReply = (type, resolverName, data, ts = []) => {\n ts.push(timestamp())\n return JSON.stringify({\n data: {\n [WS_REPLY_TYPE]: type,\n [WS_EVT_NAME]: resolverName,\n [WS_DATA_NAME]: toJson(data)\n },\n [TIMESTAMP_PARAM_NAME]: ts \n })\n}\n\n// extended function \nexport const createReplyMsg = (resolverName, data, ts = []) => (\n createWsReply(EMIT_REPLY_TYPE, resolverName, data, ts)\n)\n\nexport const createAcknowledgeMsg = (resolverName, data, ts = []) => (\n createWsReply(ACKNOWLEDGE_REPLY_TYPE, resolverName, data, ts)\n)\n\n/**\n * @param {string|object} payload should be string when reply but could be transformed\n * @return {boolean} true is OK\n */\nexport const isWsReply = payload => {\n const json = isString(payload) ? toJson(payload) : payload\n const { data } = json\n if (data) {\n let result = WS_KEYS.filter(key => isObjectHasKey(data, key))\n return (result.length === WS_KEYS.length) ? data : false\n }\n return false\n}\n\n/**\n * @param {string|object} data received data\n * @param {function} [cb=nil] this is for extracting the TS field or when it's error\n * @return {object} false on failed\n */\nexport const extractWsPayload = (payload, cb = nil) => {\n try {\n const json = toJson(payload)\n // now handle the data\n let _data\n if ((_data = isWsReply(json)) !== false) {\n // note the ts property is on its own \n cb(TIMESTAMP_PARAM_NAME, json[TIMESTAMP_PARAM_NAME])\n \n return {\n data: toJson(_data[WS_DATA_NAME]),\n resolverName: _data[WS_EVT_NAME],\n type: _data[WS_REPLY_TYPE]\n }\n }\n throw new JsonqlError(PAYLOAD_NOT_DECODED_ERR, payload)\n } catch(e) {\n return cb(ERROR_KEY, e)\n }\n}\n","// the WebSocket main handler\nimport {\n LOGOUT_EVENT_NAME,\n ACKNOWLEDGE_REPLY_TYPE,\n EMIT_REPLY_TYPE,\n ERROR_KEY,\n\n ON_ERROR_FN_NAME,\n ON_MESSAGE_FN_NAME,\n ON_RESULT_FN_NAME,\n ON_READY_FN_NAME,\n ON_LOGIN_FN_NAME\n} from 'jsonql-constants'\nimport {\n createQueryStr,\n createEvt,\n extractWsPayload\n} from 'jsonql-utils/module'\nimport {\n handleNamespaceOnError,\n createIntercomPayload\n} from '../modules'\n\n/**\n * in some edge case we might not even have a resolverName, then\n * we issue a global error for the developer to catch it\n * @param {object} ee event emitter\n * @param {string} namespace nsp\n * @param {string} resolverName resolver\n * @param {object} json decoded payload or error object\n * @return {undefined} nothing return\n */\nconst errorTypeHandler = (ee, namespace, resolverName, json) => {\n let evt = [namespace]\n if (resolverName) {\n evt.push(resolverName)\n }\n evt.push(ON_ERROR_FN_NAME)\n let evtName = Reflect.apply(createEvt, null, evt)\n // test if there is a data field\n let payload = json.data || json\n ee.$trigger(evtName, [payload])\n}\n\n/**\n * Handle the logout event when it's enableAuth\n * @param {object} ee eventEmitter\n * @param {object} ws the WebSocket instance\n * @return {void}\n */\nconst logoutEventListener = (ee, ws) => {\n // listen to the LOGOUT_EVENT_NAME when this is a private nsp\n ee.$on(LOGOUT_EVENT_NAME, function closeEvtHandler() {\n try {\n // @TODO we need find a way to get the userdata\n ws.send(createIntercomPayload(LOGOUT_EVENT_NAME))\n log('terminate ws connection')\n ws.terminate()\n } catch(e) {\n console.error('ws.terminate error', e)\n }\n })\n}\n\n/**\n * Binding the event to socket normally\n * @param {string} namespace\n * @param {object} ws the nsp\n * @param {object} ee EventEmitter\n * @param {boolean} isPrivate to id if this namespace is private or not\n * @param {object} opts configuration\n * @return {object} promise resolve after the onopen event\n */\nexport function bindSocketEventHandler(namespace, ws, ee, isPrivate, opts) {\n const { log } = opts\n let onReadCalls = 2\n // log(`log test, isPrivate:`, isPrivate)\n // connection open\n ws.onopen = function onOpenCallback() {\n\n log('=== ws.onopen listened -->', namespace)\n // we just call the onReady\n ee.$call(ON_READY_FN_NAME)(namespace)\n // we only want to allow it get call twice (number of namespaces)\n --onReadCalls\n if (onReadCalls === 0) {\n ee.$off(ON_READY_FN_NAME)\n }\n\n // need an extra parameter here to id the private nsp\n if (isPrivate) {\n log(`isPrivate and fire the ${ON_LOGIN_FN_NAME}`)\n ee.$call(ON_LOGIN_FN_NAME)(namespace)\n }\n // add listener only after the open is called\n ee.$only(\n createEvt(namespace, EMIT_REPLY_TYPE),\n /**\n * actually send the payload to server\n * @param {string} resolverName\n * @param {array} args NEED TO CHECK HOW WE PASS THIS!\n */\n function wsMainOnEvtHandler(resolverName, args) {\n\n const payload = createQueryStr(resolverName, args)\n log('ws.onopen.send', resolverName, args, payload)\n\n ws.send(payload)\n }\n )\n }\n\n // reply\n // If we change it to the event callback style\n // then the payload will just be the payload and fucks up the extractWsPayload call @TODO\n ws.onmessage = function onMessageCallback(payload) {\n // console.log(`on.message`, typeof payload, payload)\n try {\n // log(`ws.onmessage raw payload`, payload)\n // @TODO the payload actually contain quite a few things - is that changed?\n // type: message, data: data_send_from_server\n const json = extractWsPayload(payload.data)\n const { resolverName, type } = json\n\n log('Respond from server', type, json)\n\n switch (type) {\n case EMIT_REPLY_TYPE:\n let e1 = createEvt(namespace, resolverName, ON_MESSAGE_FN_NAME)\n let r = ee.$trigger(e1, [json])\n log(`EMIT_REPLY_TYPE`, e1, r)\n break\n case ACKNOWLEDGE_REPLY_TYPE:\n let e2 = createEvt(namespace, resolverName, ON_RESULT_FN_NAME)\n let x2 = ee.$trigger(e2, [json])\n log(`ACKNOWLEDGE_REPLY_TYPE`, e2, x2)\n break\n case ERROR_KEY:\n // this is handled error and we won't throw it\n // we need to extract the error from json\n log(`ERROR_KEY`)\n errorTypeHandler(ee, namespace, resolverName, json)\n break\n // @TODO there should be an error type instead of roll into the other two types? TBC\n default:\n // if this happen then we should throw it and halt the operation all together\n log('Unhandled event!', json)\n errorTypeHandler(ee, namespace, resolverName, json)\n // let error = {error: {'message': 'Unhandled event!', type}};\n // ee.$trigger(createEvt(namespace, resolverName, ON_RESULT_FN_NAME), [error])\n }\n } catch(e) {\n console.error(`ws.onmessage error`, e)\n errorTypeHandler(ee, namespace, false, e)\n }\n }\n // when the server close the connection\n ws.onclose = function onCloseCallback() {\n log('ws.onclose callback')\n // @TODO what to do with this\n // ee.$trigger(LOGOUT_EVENT_NAME, [namespace])\n }\n // add a onerror event handler here\n ws.onerror = function onErrorCallback(err) {\n // trigger a global error event\n log(`ws.onerror`, err)\n handleNamespaceOnError(ee, namespace, err)\n }\n\n if (isPrivate) {\n logoutEventListener(ee, ws)\n }\n\n}\n","// actually binding the event client to the socket client\n\n// from the jsonql-ws-client-core\nimport { clientEventListener } from '../modules'\n// local \nimport { createNspAction } from './create-nsp-action'\nimport { loginEventHandler } from './login-event-handler'\nimport { bindSocketEventHandler } from './bind-socket-event-handler'\n\n/**\n * create the NSP(s) and determine if this require auth or not \n * @param {object} opts configuration\n * @param {object} nspMap namespace with resolvers\n * @param {object} ee EventEmitter to pass through\n * @return {object} what comes in what goes out\n */\nfunction createNsp(opts, nspMap, ee) {\n // now create the nsps\n // const { namespaces } = nspMap\n const { token } = opts\n\n return createNspAction(opts, nspMap, token)\n .then(nsps => {\n const listenerFn = clientEventListener(bindSocketEventHandler, nsps)\n // now run it\n listenerFn(opts, nspMap, ee)\n\n if (opts.enableAuth) {\n loginEventHandler(opts, nspMap, ee)\n }\n // return what input\n return { opts, nspMap, ee }\n }) \n}\n\nexport { createNsp }","// breaking up the create-nsp.js file \n// then regroup them back together here \nimport { createNsp } from './create-nsp'\n\nexport default createNsp\n","// share method to create the wsClientResolver\nimport { initWebSocketClient } from './init-websocket-client'\nimport createNsp from '../create-nsp'\nimport { NSP_CLIENT, NSP_AUTH_CLIENT } from 'jsonql-constants'\n\n/**\n * Create the framework <---> jsonql client binding\n * @param {object} frameworkModule the different WebSocket module\n * @return {function} the wsClientResolver\n */\nfunction bindFrameworkToJsonql(frameworkModule) {\n /**\n * wsClientResolver\n * @param {object} opts configuration\n * @param {object} nspMap from the contract\n * @param {object} ee instance of the eventEmitter\n * @return {object} passing the same 3 input out with additional in the opts\n */\n return function createClientBindingAction(opts, nspMap, ee) {\n const { log } = opts\n opts[NSP_CLIENT] = initWebSocketClient(frameworkModule, false, log)\n opts[NSP_AUTH_CLIENT] = initWebSocketClient(frameworkModule, true, log) \n // @1.0.7 remove later once everything fixed \n \n log(`bindFrameworkToJsonql`, ee.name, nspMap)\n // console.log(`contract`, opts.contract)\n return createNsp(opts, nspMap, ee)\n }\n}\n\nexport { bindFrameworkToJsonql }","// this will be the news style interface that will pass to the jsonql-ws-client\n// then return a function for accepting an opts to generate the final\n// client api\nimport WebSocket from 'ws'\nimport createWebSocketBinding from '../core/create-websocket-binding'\n\n/**\n * @param {object} opts configuration\n * @param {object} nspMap from the contract\n * @param {object} ee instance of the eventEmitter\n * @return {object} passing the same 3 input out with additional in the opts\n */\nexport default createWebSocketBinding(WebSocket)\n","// this is the module entry point for node client\nimport {\n wsClientCore\n} from './core/modules'\nimport { wsClientConstProps } from './options'\n\nimport nodeFrameworkSocketEngine from './node/node-framework-socket-engine'\n\n// export back the function and that's it\nexport default function wsNodeClient(config = {}, constProps = {}) {\n const initClientMethod = wsClientCore(\n nodeFrameworkSocketEngine, \n {}, \n Object.assign({}, wsClientConstProps, constProps)\n )\n return initClientMethod(config)\n}\n"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;ACAA;;;;;;;;;ACAA;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;ACAA;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;ACAA;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;"} \ No newline at end of file +{"version":3,"file":"main.js","sources":["../../ws-client-core/node_modules/lodash-es/isArray.js","node_modules/rollup-plugin-node-globals/src/global.js","../../ws-client-core/node_modules/lodash-es/_objectToString.js","../../ws-client-core/node_modules/lodash-es/_overArg.js","../../ws-client-core/node_modules/lodash-es/isObjectLike.js","../../ws-client-core/node_modules/lodash-es/_arrayMap.js","../../ws-client-core/node_modules/lodash-es/_baseSlice.js","../../ws-client-core/node_modules/lodash-es/_baseFindIndex.js","../../ws-client-core/node_modules/lodash-es/_baseIsNaN.js","../../ws-client-core/node_modules/lodash-es/_strictIndexOf.js","../../ws-client-core/node_modules/lodash-es/_asciiToArray.js","../../ws-client-core/node_modules/lodash-es/_hasUnicode.js","../../ws-client-core/node_modules/lodash-es/_unicodeToArray.js","../../ws-client-core/node_modules/jsonql-utils/src/generic.js","../../ws-client-core/node_modules/lodash-es/_listCacheClear.js","../../ws-client-core/node_modules/lodash-es/eq.js","../../ws-client-core/node_modules/lodash-es/_stackDelete.js","../../ws-client-core/node_modules/lodash-es/_stackGet.js","../../ws-client-core/node_modules/lodash-es/_stackHas.js","../../ws-client-core/node_modules/lodash-es/isObject.js","../../ws-client-core/node_modules/lodash-es/_toSource.js","../../ws-client-core/node_modules/lodash-es/_getValue.js","../../ws-client-core/node_modules/lodash-es/_hashDelete.js","../../ws-client-core/node_modules/lodash-es/_isKeyable.js","../../ws-client-core/node_modules/lodash-es/_createBaseFor.js","../../ws-client-core/node_modules/lodash-es/_copyArray.js","../../ws-client-core/node_modules/lodash-es/_isPrototype.js","../../ws-client-core/node_modules/lodash-es/isLength.js","../../ws-client-core/node_modules/lodash-es/stubFalse.js","../../ws-client-core/node_modules/lodash-es/_baseUnary.js","../../ws-client-core/node_modules/lodash-es/_safeGet.js","../../ws-client-core/node_modules/lodash-es/_baseTimes.js","../../ws-client-core/node_modules/lodash-es/_isIndex.js","../../ws-client-core/node_modules/lodash-es/_nativeKeysIn.js","../../ws-client-core/node_modules/lodash-es/identity.js","../../ws-client-core/node_modules/lodash-es/_apply.js","../../ws-client-core/node_modules/lodash-es/constant.js","../../ws-client-core/node_modules/lodash-es/_shortOut.js","../../ws-client-core/node_modules/jsonql-errors/src/enum-error.js","../../ws-client-core/node_modules/jsonql-errors/src/type-error.js","../../ws-client-core/node_modules/jsonql-errors/src/checker-error.js","../../ws-client-core/node_modules/jsonql-errors/src/validation-error.js","../../ws-client-core/node_modules/jsonql-utils/src/contract.js","../../ws-client-core/node_modules/jsonql-utils/src/timestamp.js","../../ws-client-core/node_modules/jsonql-utils/src/params-api.js","../../ws-client-core/node_modules/jsonql-utils/src/namespace.js","../../ws-client-core/node_modules/jsonql-utils/src/socket.js","../../ws-client-core/src/callers/intercom-methods.js","../../ws-client-core/node_modules/jsonql-params-validator/src/number.js","../../ws-client-core/node_modules/jsonql-params-validator/src/string.js","../../ws-client-core/node_modules/jsonql-params-validator/src/boolean.js","../../ws-client-core/node_modules/jsonql-params-validator/src/any.js","../../ws-client-core/node_modules/jsonql-params-validator/src/constants.js","../../ws-client-core/node_modules/jsonql-params-validator/src/combine.js","../../ws-client-core/node_modules/jsonql-params-validator/src/array.js","../../ws-client-core/node_modules/jsonql-params-validator/src/object.js","../../ws-client-core/node_modules/jsonql-params-validator/src/validator.js","../../ws-client-core/node_modules/lodash-es/_setCacheAdd.js","../../ws-client-core/node_modules/lodash-es/_setCacheHas.js","../../ws-client-core/node_modules/lodash-es/_arraySome.js","../../ws-client-core/node_modules/lodash-es/_cacheHas.js","../../ws-client-core/node_modules/lodash-es/_mapToArray.js","../../ws-client-core/node_modules/lodash-es/_setToArray.js","../../ws-client-core/node_modules/lodash-es/_arrayPush.js","../../ws-client-core/node_modules/lodash-es/_arrayFilter.js","../../ws-client-core/node_modules/lodash-es/stubArray.js","../../ws-client-core/node_modules/lodash-es/_matchesStrictComparable.js","../../ws-client-core/node_modules/lodash-es/_baseHasIn.js","../../ws-client-core/node_modules/lodash-es/_baseProperty.js","../../ws-client-core/node_modules/lodash-es/negate.js","../../ws-client-core/node_modules/lodash-es/_baseFindKey.js","../../ws-client-core/node_modules/jsonql-params-validator/src/is-in-array.js","../../ws-client-core/node_modules/jsonql-params-validator/src/options/run-validation.js","../../ws-client-core/node_modules/jsonql-params-validator/src/options/check-options-async.js","../../ws-client-core/node_modules/jsonql-params-validator/src/options/construct-config.js","../../ws-client-core/node_modules/jsonql-params-validator/src/options/index.js","../../ws-client-core/node_modules/jsonql-params-validator/index.js","../../ws-client-core/src/utils/get-log-fn.js","../../ws-client-core/node_modules/@to1source/event/src/constants.js","../../ws-client-core/node_modules/@to1source/event/src/store.js","../../ws-client-core/node_modules/@to1source/event/src/utils.js","../../ws-client-core/node_modules/@to1source/event/src/suspend.js","../../ws-client-core/node_modules/@to1source/event/src/store-service.js","../../ws-client-core/node_modules/@to1source/event/src/event-service.js","../../ws-client-core/node_modules/@to1source/event/index.js","../../ws-client-core/src/utils/get-event-emitter.js","../../ws-client-core/src/utils/helpers.js","../../ws-client-core/src/callers/setup-auth-methods.js","../../ws-client-core/src/options/constants.js","../../ws-client-core/src/callers/respond-handler.js","../../ws-client-core/src/callers/action-call.js","../../ws-client-core/src/callers/setup-send-method.js","../../ws-client-core/src/callers/setup-resolver.js","../../ws-client-core/src/callers/generator-methods.js","../../ws-client-core/src/callers/callers-generator.js","../../ws-client-core/src/callers/setup-intercom.js","../../ws-client-core/src/callers/setup-final-step.js","../../ws-client-core/src/options/index.js","../../ws-client-core/src/api.js","../../ws-client-core/src/listener/create-nsp-clients.js","../../ws-client-core/src/listener/trigger-namespaces-on-error.js","../../ws-client-core/src/listener/event-listeners.js","../../ws-client-core/src/listener/client-event-listener.js","src/options/index.js","src/core/create-websocket-binding/init-websocket-client.js","node_modules/lodash-es/_objectToString.js","node_modules/lodash-es/_overArg.js","node_modules/lodash-es/isObjectLike.js","node_modules/lodash-es/_listCacheClear.js","node_modules/lodash-es/eq.js","node_modules/lodash-es/_stackDelete.js","node_modules/lodash-es/_stackGet.js","node_modules/lodash-es/_stackHas.js","node_modules/lodash-es/isObject.js","node_modules/lodash-es/_toSource.js","node_modules/lodash-es/_getValue.js","node_modules/lodash-es/_hashDelete.js","node_modules/lodash-es/_isKeyable.js","node_modules/lodash-es/_createBaseFor.js","node_modules/lodash-es/_copyArray.js","node_modules/lodash-es/_isPrototype.js","node_modules/lodash-es/isArray.js","node_modules/lodash-es/isLength.js","node_modules/lodash-es/stubFalse.js","node_modules/lodash-es/_baseUnary.js","node_modules/lodash-es/_safeGet.js","node_modules/lodash-es/_baseTimes.js","node_modules/lodash-es/_isIndex.js","node_modules/lodash-es/_nativeKeysIn.js","node_modules/lodash-es/identity.js","node_modules/lodash-es/_apply.js","node_modules/lodash-es/constant.js","node_modules/lodash-es/_shortOut.js","node_modules/jsonql-utils/src/chain-promises.js","src/core/create-nsp/login-event-handler.js","node_modules/jsonql-utils/src/generic.js","node_modules/jsonql-errors/src/validation-error.js","node_modules/jsonql-utils/src/timestamp.js","node_modules/jsonql-utils/src/params-api.js","node_modules/jsonql-utils/src/socket.js","src/core/create-nsp/bind-socket-event-handler.js","src/core/create-nsp/create-nsp.js","src/core/create-nsp/index.js","src/core/create-websocket-binding/bind-framework-to-jsonql.js","src/node/node-framework-socket-engine.js","src/node-ws-client.js"],"sourcesContent":["/**\n * Checks if `value` is classified as an `Array` object.\n *\n * @static\n * @memberOf _\n * @since 0.1.0\n * @category Lang\n * @param {*} value The value to check.\n * @returns {boolean} Returns `true` if `value` is an array, else `false`.\n * @example\n *\n * _.isArray([1, 2, 3]);\n * // => true\n *\n * _.isArray(document.body.children);\n * // => false\n *\n * _.isArray('abc');\n * // => false\n *\n * _.isArray(_.noop);\n * // => false\n */\nvar isArray = Array.isArray;\n\nexport default isArray;\n","export default (typeof global !== \"undefined\" ? global :\n typeof self !== \"undefined\" ? self :\n typeof window !== \"undefined\" ? window : {});\n","/** Used for built-in method references. */\nvar objectProto = Object.prototype;\n\n/**\n * Used to resolve the\n * [`toStringTag`](http://ecma-international.org/ecma-262/7.0/#sec-object.prototype.tostring)\n * of values.\n */\nvar nativeObjectToString = objectProto.toString;\n\n/**\n * Converts `value` to a string using `Object.prototype.toString`.\n *\n * @private\n * @param {*} value The value to convert.\n * @returns {string} Returns the converted string.\n */\nfunction objectToString(value) {\n return nativeObjectToString.call(value);\n}\n\nexport default objectToString;\n","/**\n * Creates a unary function that invokes `func` with its argument transformed.\n *\n * @private\n * @param {Function} func The function to wrap.\n * @param {Function} transform The argument transform.\n * @returns {Function} Returns the new function.\n */\nfunction overArg(func, transform) {\n return function(arg) {\n return func(transform(arg));\n };\n}\n\nexport default overArg;\n","/**\n * Checks if `value` is object-like. A value is object-like if it's not `null`\n * and has a `typeof` result of \"object\".\n *\n * @static\n * @memberOf _\n * @since 4.0.0\n * @category Lang\n * @param {*} value The value to check.\n * @returns {boolean} Returns `true` if `value` is object-like, else `false`.\n * @example\n *\n * _.isObjectLike({});\n * // => true\n *\n * _.isObjectLike([1, 2, 3]);\n * // => true\n *\n * _.isObjectLike(_.noop);\n * // => false\n *\n * _.isObjectLike(null);\n * // => false\n */\nfunction isObjectLike(value) {\n return value != null && typeof value == 'object';\n}\n\nexport default isObjectLike;\n","/**\n * A specialized version of `_.map` for arrays without support for iteratee\n * shorthands.\n *\n * @private\n * @param {Array} [array] The array to iterate over.\n * @param {Function} iteratee The function invoked per iteration.\n * @returns {Array} Returns the new mapped array.\n */\nfunction arrayMap(array, iteratee) {\n var index = -1,\n length = array == null ? 0 : array.length,\n result = Array(length);\n\n while (++index < length) {\n result[index] = iteratee(array[index], index, array);\n }\n return result;\n}\n\nexport default arrayMap;\n","/**\n * The base implementation of `_.slice` without an iteratee call guard.\n *\n * @private\n * @param {Array} array The array to slice.\n * @param {number} [start=0] The start position.\n * @param {number} [end=array.length] The end position.\n * @returns {Array} Returns the slice of `array`.\n */\nfunction baseSlice(array, start, end) {\n var index = -1,\n length = array.length;\n\n if (start < 0) {\n start = -start > length ? 0 : (length + start);\n }\n end = end > length ? length : end;\n if (end < 0) {\n end += length;\n }\n length = start > end ? 0 : ((end - start) >>> 0);\n start >>>= 0;\n\n var result = Array(length);\n while (++index < length) {\n result[index] = array[index + start];\n }\n return result;\n}\n\nexport default baseSlice;\n","/**\n * The base implementation of `_.findIndex` and `_.findLastIndex` without\n * support for iteratee shorthands.\n *\n * @private\n * @param {Array} array The array to inspect.\n * @param {Function} predicate The function invoked per iteration.\n * @param {number} fromIndex The index to search from.\n * @param {boolean} [fromRight] Specify iterating from right to left.\n * @returns {number} Returns the index of the matched value, else `-1`.\n */\nfunction baseFindIndex(array, predicate, fromIndex, fromRight) {\n var length = array.length,\n index = fromIndex + (fromRight ? 1 : -1);\n\n while ((fromRight ? index-- : ++index < length)) {\n if (predicate(array[index], index, array)) {\n return index;\n }\n }\n return -1;\n}\n\nexport default baseFindIndex;\n","/**\n * The base implementation of `_.isNaN` without support for number objects.\n *\n * @private\n * @param {*} value The value to check.\n * @returns {boolean} Returns `true` if `value` is `NaN`, else `false`.\n */\nfunction baseIsNaN(value) {\n return value !== value;\n}\n\nexport default baseIsNaN;\n","/**\n * A specialized version of `_.indexOf` which performs strict equality\n * comparisons of values, i.e. `===`.\n *\n * @private\n * @param {Array} array The array to inspect.\n * @param {*} value The value to search for.\n * @param {number} fromIndex The index to search from.\n * @returns {number} Returns the index of the matched value, else `-1`.\n */\nfunction strictIndexOf(array, value, fromIndex) {\n var index = fromIndex - 1,\n length = array.length;\n\n while (++index < length) {\n if (array[index] === value) {\n return index;\n }\n }\n return -1;\n}\n\nexport default strictIndexOf;\n","/**\n * Converts an ASCII `string` to an array.\n *\n * @private\n * @param {string} string The string to convert.\n * @returns {Array} Returns the converted array.\n */\nfunction asciiToArray(string) {\n return string.split('');\n}\n\nexport default asciiToArray;\n","/** Used to compose unicode character classes. */\nvar rsAstralRange = '\\\\ud800-\\\\udfff',\n rsComboMarksRange = '\\\\u0300-\\\\u036f',\n reComboHalfMarksRange = '\\\\ufe20-\\\\ufe2f',\n rsComboSymbolsRange = '\\\\u20d0-\\\\u20ff',\n rsComboRange = rsComboMarksRange + reComboHalfMarksRange + rsComboSymbolsRange,\n rsVarRange = '\\\\ufe0e\\\\ufe0f';\n\n/** Used to compose unicode capture groups. */\nvar rsZWJ = '\\\\u200d';\n\n/** Used to detect strings with [zero-width joiners or code points from the astral planes](http://eev.ee/blog/2015/09/12/dark-corners-of-unicode/). */\nvar reHasUnicode = RegExp('[' + rsZWJ + rsAstralRange + rsComboRange + rsVarRange + ']');\n\n/**\n * Checks if `string` contains Unicode symbols.\n *\n * @private\n * @param {string} string The string to inspect.\n * @returns {boolean} Returns `true` if a symbol is found, else `false`.\n */\nfunction hasUnicode(string) {\n return reHasUnicode.test(string);\n}\n\nexport default hasUnicode;\n","/** Used to compose unicode character classes. */\nvar rsAstralRange = '\\\\ud800-\\\\udfff',\n rsComboMarksRange = '\\\\u0300-\\\\u036f',\n reComboHalfMarksRange = '\\\\ufe20-\\\\ufe2f',\n rsComboSymbolsRange = '\\\\u20d0-\\\\u20ff',\n rsComboRange = rsComboMarksRange + reComboHalfMarksRange + rsComboSymbolsRange,\n rsVarRange = '\\\\ufe0e\\\\ufe0f';\n\n/** Used to compose unicode capture groups. */\nvar rsAstral = '[' + rsAstralRange + ']',\n rsCombo = '[' + rsComboRange + ']',\n rsFitz = '\\\\ud83c[\\\\udffb-\\\\udfff]',\n rsModifier = '(?:' + rsCombo + '|' + rsFitz + ')',\n rsNonAstral = '[^' + rsAstralRange + ']',\n rsRegional = '(?:\\\\ud83c[\\\\udde6-\\\\uddff]){2}',\n rsSurrPair = '[\\\\ud800-\\\\udbff][\\\\udc00-\\\\udfff]',\n rsZWJ = '\\\\u200d';\n\n/** Used to compose unicode regexes. */\nvar reOptMod = rsModifier + '?',\n rsOptVar = '[' + rsVarRange + ']?',\n rsOptJoin = '(?:' + rsZWJ + '(?:' + [rsNonAstral, rsRegional, rsSurrPair].join('|') + ')' + rsOptVar + reOptMod + ')*',\n rsSeq = rsOptVar + reOptMod + rsOptJoin,\n rsSymbol = '(?:' + [rsNonAstral + rsCombo + '?', rsCombo, rsRegional, rsSurrPair, rsAstral].join('|') + ')';\n\n/** Used to match [string symbols](https://mathiasbynens.be/notes/javascript-unicode). */\nvar reUnicode = RegExp(rsFitz + '(?=' + rsFitz + ')|' + rsSymbol + rsSeq, 'g');\n\n/**\n * Converts a Unicode `string` to an array.\n *\n * @private\n * @param {string} string The string to convert.\n * @returns {Array} Returns the converted array.\n */\nfunction unicodeToArray(string) {\n return string.match(reUnicode) || [];\n}\n\nexport default unicodeToArray;\n","// bunch of generic helpers\n\nimport isArray from 'lodash-es/isArray'\nimport isPlainObject from 'lodash-es/isPlainObject'\nimport trim from 'lodash-es/trim'\n\n/**\n * DIY in Array\n * @param {array} arr to check from\n * @param {*} value to check against\n * @return {boolean} true on found\n */\nexport const inArray = (arr, value) => !!arr.filter(a => a === value).length\n\n// quick and dirty to turn non array to array\nexport const toArray = (arg) => isArray(arg) ? arg : [arg]\n\n/**\n * parse string to json or just return the original value if error happened\n * @param {*} n input\n * @param {boolean} [t=true] or throw\n * @return {*} json object on success\n */\nexport const parseJson = function(n, t=true) {\n try {\n return JSON.parse(n)\n } catch(e) {\n if (t) {\n return n\n }\n throw new Error(e)\n }\n}\n\n/**\n * @param {object} obj for search\n * @param {string} key target\n * @return {boolean} true on success\n */\nexport const isObjectHasKey = function(obj, key) {\n try {\n const keys = Object.keys(obj)\n return inArray(keys, key)\n } catch(e) {\n // @BUG when the obj is not an OBJECT we got some weird output\n return false\n }\n}\n\n/**\n * create a event name\n * @param {string[]} args\n * @return {string} event name for use\n */\nexport const createEvt = (...args) => args.join('_')\n\n/**\n * simple util method to get the value\n * @param {string} name of the key\n * @param {object} obj to take value from\n * @return {*} the object value id by name or undefined\n */\nexport const getConfigValue = (name, obj) => (\n obj && isPlainObject(obj) ? ( (name in obj) ? obj[name] : undefined ) : undefined\n)\n\n/**\n * small util to make sure the return value is valid JSON object\n * @param {*} n input\n * @return {object} correct JSON object\n */\nexport const toJson = n => {\n if (typeof n === 'string') {\n return parseJson(n)\n }\n return parseJson(JSON.stringify(n))\n}\n\n/**\n * Check several parameter that there is something in the param\n * @param {*} param input\n * @return {boolean}\n */\nexport const isNotEmpty = function(param) {\n return param !== undefined && param !== false && param !== null && trim(param) !== ''\n}\n\n/**\n * Simple check if the prop is function\n * @param {*} prop input\n * @return {boolean} true on success\n */\nexport const isFunc = prop => {\n if (typeof prop === 'function') {\n return true;\n }\n console.error(`Expect to be Function type! Got ${typeof prop}`)\n}\n\n/**\n * Shorthand method for Object.assign \n * @param {array} args \n * @return {object} merge together object by key \n */\nexport const assign = (...args) => Reflect.apply(Object.assign, Object, args)\n \n/** \n * generic placeholder function\n * @return {boolean} false \n */\nexport const nil = () => false\n\n/**\n * generic turn config into immutatble \n */\nexport const freeze = config => Object.freeze(config)","/**\n * Removes all key-value entries from the list cache.\n *\n * @private\n * @name clear\n * @memberOf ListCache\n */\nfunction listCacheClear() {\n this.__data__ = [];\n this.size = 0;\n}\n\nexport default listCacheClear;\n","/**\n * Performs a\n * [`SameValueZero`](http://ecma-international.org/ecma-262/7.0/#sec-samevaluezero)\n * comparison between two values to determine if they are equivalent.\n *\n * @static\n * @memberOf _\n * @since 4.0.0\n * @category Lang\n * @param {*} value The value to compare.\n * @param {*} other The other value to compare.\n * @returns {boolean} Returns `true` if the values are equivalent, else `false`.\n * @example\n *\n * var object = { 'a': 1 };\n * var other = { 'a': 1 };\n *\n * _.eq(object, object);\n * // => true\n *\n * _.eq(object, other);\n * // => false\n *\n * _.eq('a', 'a');\n * // => true\n *\n * _.eq('a', Object('a'));\n * // => false\n *\n * _.eq(NaN, NaN);\n * // => true\n */\nfunction eq(value, other) {\n return value === other || (value !== value && other !== other);\n}\n\nexport default eq;\n","/**\n * Removes `key` and its value from the stack.\n *\n * @private\n * @name delete\n * @memberOf Stack\n * @param {string} key The key of the value to remove.\n * @returns {boolean} Returns `true` if the entry was removed, else `false`.\n */\nfunction stackDelete(key) {\n var data = this.__data__,\n result = data['delete'](key);\n\n this.size = data.size;\n return result;\n}\n\nexport default stackDelete;\n","/**\n * Gets the stack value for `key`.\n *\n * @private\n * @name get\n * @memberOf Stack\n * @param {string} key The key of the value to get.\n * @returns {*} Returns the entry value.\n */\nfunction stackGet(key) {\n return this.__data__.get(key);\n}\n\nexport default stackGet;\n","/**\n * Checks if a stack value for `key` exists.\n *\n * @private\n * @name has\n * @memberOf Stack\n * @param {string} key The key of the entry to check.\n * @returns {boolean} Returns `true` if an entry for `key` exists, else `false`.\n */\nfunction stackHas(key) {\n return this.__data__.has(key);\n}\n\nexport default stackHas;\n","/**\n * Checks if `value` is the\n * [language type](http://www.ecma-international.org/ecma-262/7.0/#sec-ecmascript-language-types)\n * of `Object`. (e.g. arrays, functions, objects, regexes, `new Number(0)`, and `new String('')`)\n *\n * @static\n * @memberOf _\n * @since 0.1.0\n * @category Lang\n * @param {*} value The value to check.\n * @returns {boolean} Returns `true` if `value` is an object, else `false`.\n * @example\n *\n * _.isObject({});\n * // => true\n *\n * _.isObject([1, 2, 3]);\n * // => true\n *\n * _.isObject(_.noop);\n * // => true\n *\n * _.isObject(null);\n * // => false\n */\nfunction isObject(value) {\n var type = typeof value;\n return value != null && (type == 'object' || type == 'function');\n}\n\nexport default isObject;\n","/** Used for built-in method references. */\nvar funcProto = Function.prototype;\n\n/** Used to resolve the decompiled source of functions. */\nvar funcToString = funcProto.toString;\n\n/**\n * Converts `func` to its source code.\n *\n * @private\n * @param {Function} func The function to convert.\n * @returns {string} Returns the source code.\n */\nfunction toSource(func) {\n if (func != null) {\n try {\n return funcToString.call(func);\n } catch (e) {}\n try {\n return (func + '');\n } catch (e) {}\n }\n return '';\n}\n\nexport default toSource;\n","/**\n * Gets the value at `key` of `object`.\n *\n * @private\n * @param {Object} [object] The object to query.\n * @param {string} key The key of the property to get.\n * @returns {*} Returns the property value.\n */\nfunction getValue(object, key) {\n return object == null ? undefined : object[key];\n}\n\nexport default getValue;\n","/**\n * Removes `key` and its value from the hash.\n *\n * @private\n * @name delete\n * @memberOf Hash\n * @param {Object} hash The hash to modify.\n * @param {string} key The key of the value to remove.\n * @returns {boolean} Returns `true` if the entry was removed, else `false`.\n */\nfunction hashDelete(key) {\n var result = this.has(key) && delete this.__data__[key];\n this.size -= result ? 1 : 0;\n return result;\n}\n\nexport default hashDelete;\n","/**\n * Checks if `value` is suitable for use as unique object key.\n *\n * @private\n * @param {*} value The value to check.\n * @returns {boolean} Returns `true` if `value` is suitable, else `false`.\n */\nfunction isKeyable(value) {\n var type = typeof value;\n return (type == 'string' || type == 'number' || type == 'symbol' || type == 'boolean')\n ? (value !== '__proto__')\n : (value === null);\n}\n\nexport default isKeyable;\n","/**\n * Creates a base function for methods like `_.forIn` and `_.forOwn`.\n *\n * @private\n * @param {boolean} [fromRight] Specify iterating from right to left.\n * @returns {Function} Returns the new base function.\n */\nfunction createBaseFor(fromRight) {\n return function(object, iteratee, keysFunc) {\n var index = -1,\n iterable = Object(object),\n props = keysFunc(object),\n length = props.length;\n\n while (length--) {\n var key = props[fromRight ? length : ++index];\n if (iteratee(iterable[key], key, iterable) === false) {\n break;\n }\n }\n return object;\n };\n}\n\nexport default createBaseFor;\n","/**\n * Copies the values of `source` to `array`.\n *\n * @private\n * @param {Array} source The array to copy values from.\n * @param {Array} [array=[]] The array to copy values to.\n * @returns {Array} Returns `array`.\n */\nfunction copyArray(source, array) {\n var index = -1,\n length = source.length;\n\n array || (array = Array(length));\n while (++index < length) {\n array[index] = source[index];\n }\n return array;\n}\n\nexport default copyArray;\n","/** Used for built-in method references. */\nvar objectProto = Object.prototype;\n\n/**\n * Checks if `value` is likely a prototype object.\n *\n * @private\n * @param {*} value The value to check.\n * @returns {boolean} Returns `true` if `value` is a prototype, else `false`.\n */\nfunction isPrototype(value) {\n var Ctor = value && value.constructor,\n proto = (typeof Ctor == 'function' && Ctor.prototype) || objectProto;\n\n return value === proto;\n}\n\nexport default isPrototype;\n","/** Used as references for various `Number` constants. */\nvar MAX_SAFE_INTEGER = 9007199254740991;\n\n/**\n * Checks if `value` is a valid array-like length.\n *\n * **Note:** This method is loosely based on\n * [`ToLength`](http://ecma-international.org/ecma-262/7.0/#sec-tolength).\n *\n * @static\n * @memberOf _\n * @since 4.0.0\n * @category Lang\n * @param {*} value The value to check.\n * @returns {boolean} Returns `true` if `value` is a valid length, else `false`.\n * @example\n *\n * _.isLength(3);\n * // => true\n *\n * _.isLength(Number.MIN_VALUE);\n * // => false\n *\n * _.isLength(Infinity);\n * // => false\n *\n * _.isLength('3');\n * // => false\n */\nfunction isLength(value) {\n return typeof value == 'number' &&\n value > -1 && value % 1 == 0 && value <= MAX_SAFE_INTEGER;\n}\n\nexport default isLength;\n","/**\n * This method returns `false`.\n *\n * @static\n * @memberOf _\n * @since 4.13.0\n * @category Util\n * @returns {boolean} Returns `false`.\n * @example\n *\n * _.times(2, _.stubFalse);\n * // => [false, false]\n */\nfunction stubFalse() {\n return false;\n}\n\nexport default stubFalse;\n","/**\n * The base implementation of `_.unary` without support for storing metadata.\n *\n * @private\n * @param {Function} func The function to cap arguments for.\n * @returns {Function} Returns the new capped function.\n */\nfunction baseUnary(func) {\n return function(value) {\n return func(value);\n };\n}\n\nexport default baseUnary;\n","/**\n * Gets the value at `key`, unless `key` is \"__proto__\" or \"constructor\".\n *\n * @private\n * @param {Object} object The object to query.\n * @param {string} key The key of the property to get.\n * @returns {*} Returns the property value.\n */\nfunction safeGet(object, key) {\n if (key === 'constructor' && typeof object[key] === 'function') {\n return;\n }\n\n if (key == '__proto__') {\n return;\n }\n\n return object[key];\n}\n\nexport default safeGet;\n","/**\n * The base implementation of `_.times` without support for iteratee shorthands\n * or max array length checks.\n *\n * @private\n * @param {number} n The number of times to invoke `iteratee`.\n * @param {Function} iteratee The function invoked per iteration.\n * @returns {Array} Returns the array of results.\n */\nfunction baseTimes(n, iteratee) {\n var index = -1,\n result = Array(n);\n\n while (++index < n) {\n result[index] = iteratee(index);\n }\n return result;\n}\n\nexport default baseTimes;\n","/** Used as references for various `Number` constants. */\nvar MAX_SAFE_INTEGER = 9007199254740991;\n\n/** Used to detect unsigned integer values. */\nvar reIsUint = /^(?:0|[1-9]\\d*)$/;\n\n/**\n * Checks if `value` is a valid array-like index.\n *\n * @private\n * @param {*} value The value to check.\n * @param {number} [length=MAX_SAFE_INTEGER] The upper bounds of a valid index.\n * @returns {boolean} Returns `true` if `value` is a valid index, else `false`.\n */\nfunction isIndex(value, length) {\n var type = typeof value;\n length = length == null ? MAX_SAFE_INTEGER : length;\n\n return !!length &&\n (type == 'number' ||\n (type != 'symbol' && reIsUint.test(value))) &&\n (value > -1 && value % 1 == 0 && value < length);\n}\n\nexport default isIndex;\n","/**\n * This function is like\n * [`Object.keys`](http://ecma-international.org/ecma-262/7.0/#sec-object.keys)\n * except that it includes inherited enumerable properties.\n *\n * @private\n * @param {Object} object The object to query.\n * @returns {Array} Returns the array of property names.\n */\nfunction nativeKeysIn(object) {\n var result = [];\n if (object != null) {\n for (var key in Object(object)) {\n result.push(key);\n }\n }\n return result;\n}\n\nexport default nativeKeysIn;\n","/**\n * This method returns the first argument it receives.\n *\n * @static\n * @since 0.1.0\n * @memberOf _\n * @category Util\n * @param {*} value Any value.\n * @returns {*} Returns `value`.\n * @example\n *\n * var object = { 'a': 1 };\n *\n * console.log(_.identity(object) === object);\n * // => true\n */\nfunction identity(value) {\n return value;\n}\n\nexport default identity;\n","/**\n * A faster alternative to `Function#apply`, this function invokes `func`\n * with the `this` binding of `thisArg` and the arguments of `args`.\n *\n * @private\n * @param {Function} func The function to invoke.\n * @param {*} thisArg The `this` binding of `func`.\n * @param {Array} args The arguments to invoke `func` with.\n * @returns {*} Returns the result of `func`.\n */\nfunction apply(func, thisArg, args) {\n switch (args.length) {\n case 0: return func.call(thisArg);\n case 1: return func.call(thisArg, args[0]);\n case 2: return func.call(thisArg, args[0], args[1]);\n case 3: return func.call(thisArg, args[0], args[1], args[2]);\n }\n return func.apply(thisArg, args);\n}\n\nexport default apply;\n","/**\n * Creates a function that returns `value`.\n *\n * @static\n * @memberOf _\n * @since 2.4.0\n * @category Util\n * @param {*} value The value to return from the new function.\n * @returns {Function} Returns the new constant function.\n * @example\n *\n * var objects = _.times(2, _.constant({ 'a': 1 }));\n *\n * console.log(objects);\n * // => [{ 'a': 1 }, { 'a': 1 }]\n *\n * console.log(objects[0] === objects[1]);\n * // => true\n */\nfunction constant(value) {\n return function() {\n return value;\n };\n}\n\nexport default constant;\n","/** Used to detect hot functions by number of calls within a span of milliseconds. */\nvar HOT_COUNT = 800,\n HOT_SPAN = 16;\n\n/* Built-in method references for those with the same name as other `lodash` methods. */\nvar nativeNow = Date.now;\n\n/**\n * Creates a function that'll short out and invoke `identity` instead\n * of `func` when it's called `HOT_COUNT` or more times in `HOT_SPAN`\n * milliseconds.\n *\n * @private\n * @param {Function} func The function to restrict.\n * @returns {Function} Returns the new shortable function.\n */\nfunction shortOut(func) {\n var count = 0,\n lastCalled = 0;\n\n return function() {\n var stamp = nativeNow(),\n remaining = HOT_SPAN - (stamp - lastCalled);\n\n lastCalled = stamp;\n if (remaining > 0) {\n if (++count >= HOT_COUNT) {\n return arguments[0];\n }\n } else {\n count = 0;\n }\n return func.apply(undefined, arguments);\n };\n}\n\nexport default shortOut;\n","// this get throw from within the checkOptions when run through the enum failed\nexport default class JsonqlEnumError extends Error {\n constructor(...args) {\n super(...args)\n\n this.message = args[0]\n this.detail = args[1]\n\n this.className = JsonqlEnumError.name;\n\n if (Error.captureStackTrace) {\n Error.captureStackTrace(this, JsonqlEnumError)\n }\n }\n\n static get name() {\n return 'JsonqlEnumError'\n }\n}\n","// this will throw from inside the checkOptions\nexport default class JsonqlTypeError extends Error {\n constructor(...args) {\n super(...args)\n\n this.message = args[0]\n this.detail = args[1]\n\n this.className = JsonqlTypeError.name\n\n if (Error.captureStackTrace) {\n Error.captureStackTrace(this, JsonqlTypeError)\n }\n }\n\n static get name() {\n return 'JsonqlTypeError'\n }\n}\n","// allow supply a custom checker function\n// if that failed then we throw this error\nexport default class JsonqlCheckerError extends Error {\n constructor(...args) {\n super(...args)\n this.message = args[0]\n this.detail = args[1]\n\n this.className = JsonqlCheckerError.name;\n\n if (Error.captureStackTrace) {\n Error.captureStackTrace(this, JsonqlCheckerError)\n }\n }\n\n static get name() {\n return 'JsonqlCheckerError'\n }\n}\n","// custom validation error class\n// when validaton failed\nexport default class JsonqlValidationError extends Error {\n constructor(...args) {\n super(...args)\n\n this.message = args[0]\n this.detail = args[1]\n\n this.className = JsonqlValidationError.name;\n\n if (Error.captureStackTrace) {\n Error.captureStackTrace(this, JsonqlValidationError)\n }\n }\n\n static get name() {\n return 'JsonqlValidationError'\n }\n}\n","// split the contract into the node side and the generic side\nimport { isObjectHasKey } from './generic'\nimport isPlainObject from 'lodash-es/isPlainObject'\nimport {\n QUERY_NAME,\n MUTATION_NAME,\n SOCKET_NAME,\n QUERY_ARG_NAME,\n PAYLOAD_PARAM_NAME,\n CONDITION_PARAM_NAME\n} from 'jsonql-constants'\nimport { JsonqlError, JsonqlResolverNotFoundError } from 'jsonql-errors'\n/**\n * Check if the json is a contract file or not\n * @param {object} contract json object\n * @return {boolean} true\n */\nexport function checkIsContract(contract) {\n return isPlainObject(contract)\n && (\n isObjectHasKey(contract, QUERY_NAME)\n || isObjectHasKey(contract, MUTATION_NAME)\n || isObjectHasKey(contract, SOCKET_NAME)\n )\n}\n\n/**\n * Wrapper method that check if it's contract then return the contract or false\n * @param {object} contract the object to check\n * @return {boolean | object} false when it's not\n */\nexport function isContract(contract) {\n return checkIsContract(contract) ? contract : false\n}\n\n/**\n * Ported from jsonql-params-validator but different\n * if we don't find the socket part then return false\n * @param {object} contract the contract object\n * @return {object|boolean} false on failed\n */\nexport function extractSocketPart(contract) {\n if (isObjectHasKey(contract, SOCKET_NAME)) {\n return contract[SOCKET_NAME]\n }\n return false\n}\n\n/**\n * Extract the args from the payload\n * @param {object} payload to work with\n * @param {string} type of call\n * @return {array} args\n */\nexport function extractArgsFromPayload(payload, type) {\n switch (type) {\n case QUERY_NAME:\n return payload[QUERY_ARG_NAME]\n case MUTATION_NAME:\n return [\n payload[PAYLOAD_PARAM_NAME],\n payload[CONDITION_PARAM_NAME]\n ]\n default:\n throw new JsonqlError(`Unknown ${type} to extract argument from!`)\n }\n}\n\n/**\n * Like what the name said\n * @param {object} contract the contract json\n * @param {string} type query|mutation\n * @param {string} name of the function\n * @return {object} the params part of the contract\n */\nexport function extractParamsFromContract(contract, type, name) {\n try {\n const result = contract[type][name]\n // debug('extractParamsFromContract', result)\n if (!result) {\n // debug(name, type, contract)\n throw new JsonqlResolverNotFoundError(name, type)\n }\n return result\n } catch(e) {\n throw new JsonqlResolverNotFoundError(name, e)\n }\n}\n","/**\n * @param {boolean} sec return in second or not\n * @return {number} timestamp\n */\nexport const timestamp = (sec = false) => {\n let time = Date.now()\n return sec ? Math.floor( time / 1000 ) : time\n}\n","// ported from jsonql-params-validator\n// craete several helper function to construct / extract the payload\n// and make sure they are all the same\nimport {\n PAYLOAD_PARAM_NAME,\n CONDITION_PARAM_NAME,\n RESOLVER_PARAM_NAME,\n QUERY_ARG_NAME,\n TIMESTAMP_PARAM_NAME\n} from 'jsonql-constants'\n\nimport JsonqlValidationError from 'jsonql-errors/src/validation-error'\n\nimport isArray from 'lodash-es/isArray'\nimport isString from 'lodash-es/isString'\nimport isPlainObject from 'lodash-es/isPlainObject'\n\nimport { timestamp } from './timestamp'\nimport { parseJson } from './generic'\n\n/**\n * check if the payload has a timestamp field, then append a new timestamp to it\n * @param {object} payload from the com\n * @return {array} timestamp field with an array value\n */\nexport const handleTimestamp = payload => {\n let ts = payload[TIMESTAMP_PARAM_NAME]\n if (!isArray(ts)) {\n ts = [ts]\n }\n ts.push( timestamp() )\n\n return ts\n}\n\n/**\n * make sure it's an object (it was call formatPayload but it doesn't make sense)\n * @param {*} payload the object comes in could be string based\n * @return {object} the transformed payload\n */\nexport const toPayload = payload => isString(payload) ? parseJson(payload) : payload\n\n/**\n * @param {*} args arguments to send\n *@return {object} formatted payload\n */\nexport const formatPayload = (args) => (\n { [QUERY_ARG_NAME]: args }\n)\n\n/**\n * extract the resolver name from the payload \n * @param {object} payload\n * @return {string} resolver name \n */\nexport function getResolverFromPayload(payload) {\n const keys = Object.keys(payload)\n return keys.filter(key => key !== TIMESTAMP_PARAM_NAME)[0]\n}\n\n/**\n * wrapper method to add the timestamp as well\n * @param {string} resolverName\n * @param {*} payload\n * @return {object} delierable\n */\nexport function createDeliverable(resolverName, payload) {\n return {\n [resolverName]: payload,\n [TIMESTAMP_PARAM_NAME]: [ timestamp() ]\n }\n}\n\n/**\n * @param {string} resolverName name of function\n * @param {array} [args=[]] from the ...args\n * @param {boolean} [jsonp = false] add v1.3.0 to koa\n * @return {object} formatted argument\n */\nexport function createQuery(resolverName, args = [], jsonp = false) {\n if (isString(resolverName) && isArray(args)) {\n let payload = formatPayload(args)\n if (jsonp === true) {\n return payload\n }\n return createDeliverable(resolverName, payload)\n }\n throw new JsonqlValidationError(`[createQuery] expect resolverName to be string and args to be array!`, { resolverName, args })\n}\n\n/**\n * string version of the createQuery\n * @return {string}\n */\nexport function createQueryStr(resolverName, args = [], jsonp = false) {\n return JSON.stringify(createQuery(resolverName, args, jsonp))\n}\n\n/**\n * @param {string} resolverName name of function\n * @param {*} payload to send\n * @param {object} [condition={}] for what\n * @param {boolean} [jsonp = false] add v1.3.0 to koa\n * @return {object} formatted argument\n */\nexport function createMutation(resolverName, payload, condition = {}, jsonp = false) {\n const _payload = {\n [PAYLOAD_PARAM_NAME]: payload,\n [CONDITION_PARAM_NAME]: condition\n }\n if (jsonp === true) {\n return _payload\n }\n if (isString(resolverName)) {\n return createDeliverable(resolverName, _payload)\n }\n throw new JsonqlValidationError(`[createMutation] expect resolverName to be string!`, { resolverName, payload, condition })\n}\n\n/**\n * string version of createMutation\n * @return {string}\n */\nexport function createMutationStr(resolverName, payload, condition = {}, jsonp = false) {\n return JSON.stringify(createMutation(resolverName, payload, condition, jsonp))\n}\n\n/**\n * Extract the parts from payload and format for use\n * @param {string} resolverName name of fn\n * @param {object} payload the incoming json\n * @return {object|boolean} false on failed\n */\nexport function getQueryFromArgs(resolverName, payload) {\n if (resolverName && isPlainObject(payload)) {\n const args = payload[resolverName]\n if (args[QUERY_ARG_NAME]) {\n return {\n [RESOLVER_PARAM_NAME]: resolverName,\n [QUERY_ARG_NAME]: args[QUERY_ARG_NAME],\n [TIMESTAMP_PARAM_NAME]: handleTimestamp(payload)\n }\n }\n }\n return false\n}\n\n/**\n * Share function so no repeat\n * @param {object} payload the payload from client\n * @param {function} processor the last get result method\n * @return {*} result processed result\n */\nfunction processPayload(payload, processor) {\n const p = toPayload(payload)\n const resolverName = getResolverFromPayload(p)\n return Reflect.apply(processor, null, [resolverName, p])\n}\n\n/**\n * extra the payload back\n * @param {*} payload from http call\n * @return {object} resolverName and args\n */\nexport function getQueryFromPayload(payload) {\n const result = processPayload(payload, getQueryFromArgs)\n if (result !== false) {\n return result\n }\n throw new JsonqlValidationError('[getQueryArgs] Payload is malformed!', payload)\n}\n\n/**\n * Further break down from method below for use else where\n * @param {string} resolverName name of fn\n * @param {object} payload payload\n * @return {object|boolean} false on failed\n */\nexport function getMutationFromArgs(resolverName, payload) {\n if (resolverName && isPlainObject(payload)) {\n const args = payload[resolverName]\n if (args) {\n return {\n [RESOLVER_PARAM_NAME]: resolverName,\n [PAYLOAD_PARAM_NAME]: args[PAYLOAD_PARAM_NAME],\n [CONDITION_PARAM_NAME]: args[CONDITION_PARAM_NAME],\n [TIMESTAMP_PARAM_NAME]: handleTimestamp(payload)\n }\n }\n }\n return false\n}\n\n/**\n * @param {object} payload\n * @return {object} resolverName, payload, conditon\n */\nexport function getMutationFromPayload(payload) {\n const result = processPayload(payload, getMutationFromArgs)\n\n if (result !== false) {\n return result\n }\n throw new JsonqlValidationError('[getMutationArgs] Payload is malformed!', payload)\n}\n","// take out all the namespace related methods in one place for easy to find\nimport {\n JSONQL_PATH,\n PUBLIC_KEY,\n NSP_GROUP,\n PUBLIC_NAMESPACE\n} from 'jsonql-constants'\nimport { extractSocketPart } from './contract'\nconst SOCKET_NOT_FOUND_ERR = `socket not found in contract!`\nconst SIZE = 'size'\n\n/**\n * create the group using publicNamespace when there is only public\n * @param {object} socket from contract\n * @param {string} publicNamespace\n */\nfunction groupPublicNamespace(socket, publicNamespace) {\n let g = {}\n for (let resolverName in socket) {\n let params = socket[resolverName]\n g[resolverName] = params\n }\n return { size: 1, nspGroup: {[publicNamespace]: g}, publicNamespace}\n}\n\n\n/**\n * @BUG we should check the socket part instead of expect the downstream to read the menu!\n * We only need this when the enableAuth is true otherwise there is only one namespace\n * @param {object} contract the socket part of the contract file\n * @return {object} 1. remap the contract using the namespace --> resolvers\n * 2. the size of the object (1 all private, 2 mixed public with private)\n * 3. which namespace is public\n */\nexport function groupByNamespace(contract) {\n let socket = extractSocketPart(contract)\n if (socket === false) {\n throw new JsonqlError('groupByNamespace', SOCKET_NOT_FOUND_ERR)\n }\n let prop = {\n [NSP_GROUP]: {},\n [PUBLIC_NAMESPACE]: null,\n [SIZE]: 0 \n }\n\n for (let resolverName in socket) {\n let params = socket[resolverName]\n let { namespace } = params\n if (namespace) {\n if (!prop[NSP_GROUP][namespace]) {\n ++prop[SIZE]\n prop[NSP_GROUP][namespace] = {}\n }\n prop[NSP_GROUP][namespace][resolverName] = params\n // get the public namespace\n if (!prop[PUBLIC_NAMESPACE] && params[PUBLIC_KEY]) {\n prop[PUBLIC_NAMESPACE] = namespace\n }\n }\n }\n \n return prop \n}\n\n/**\n * @NOTE ported from jsonql-ws-client\n * Got to make sure the connection order otherwise\n * it will hang\n * @param {object} nspGroup contract\n * @param {string} publicNamespace like the name said\n * @return {array} namespaces in order\n */\nexport function getNamespaceInOrder(nspGroup, publicNamespace) {\n let names = [] // need to make sure the order!\n for (let namespace in nspGroup) {\n if (namespace === publicNamespace) {\n names[1] = namespace\n } else {\n names[0] = namespace\n }\n }\n return names\n}\n\n/**\n * @TODO this might change, what if we want to do room with ws\n * 1. there will only be max two namespace\n * 2. when it's normal we will have the stock path as namespace\n * 3. when enableAuth then we will have two, one is jsonql/public + private\n * @param {object} config options\n * @return {array} of namespace(s)\n */\nexport function getNamespace(config) {\n const base = JSONQL_PATH\n if (config.enableAuth) {\n // the public come first @1.0.1 we use the constants instead of the user supplied value\n // @1.0.4 we use the config value again, because we could control this via the post init\n return [\n [ base , config.privateNamespace ].join('/'),\n [ base , config.publicNamespace ].join('/')\n ]\n }\n return [ base ]\n}\n\n/**\n * get the private namespace\n * @param {array} namespaces array\n * @return {*} string on success\n */\nexport function getPrivateNamespace(namespaces) {\n return namespaces.length > 1 ? namespaces[0] : false\n}\n\n/**\n * Got a problem with a contract that is public only the groupByNamespace is wrong\n * which is actually not a problem when using a fallback, but to be sure things in order\n * we could combine with the config to group it\n * @param {object} config configuration\n * @return {object} nspInfo object\n */\nexport function getNspInfoByConfig(config) {\n const { contract, enableAuth } = config\n const namespaces = getNamespace(config)\n let nspInfo = enableAuth ? groupByNamespace(contract)\n : groupPublicNamespace(contract.socket, namespaces[0])\n // add the namespaces into it as well\n return Object.assign(nspInfo, { namespaces })\n}\n\n","// There are the socket related methods ported back from \n// ws-server-core and ws-client-core \nimport {\n WS_REPLY_TYPE,\n WS_EVT_NAME,\n WS_DATA_NAME,\n TIMESTAMP_PARAM_NAME,\n ERROR_KEY,\n EMIT_REPLY_TYPE,\n ACKNOWLEDGE_REPLY_TYPE\n} from 'jsonql-constants'\nimport { JsonqlError } from 'jsonql-errors' \nimport isString from 'lodash-es/isString'\n\nimport { toJson, isObjectHasKey, nil } from './generic'\nimport { timestamp } from './timestamp'\n\nconst PAYLOAD_NOT_DECODED_ERR = 'payload can not decoded'\nconst WS_KEYS = [\n WS_REPLY_TYPE,\n WS_EVT_NAME,\n WS_DATA_NAME\n]\n\n/////////////////////////////////////\n// REPLY FROM SERVER //\n/////////////////////////////////////\n\n\n/**\n * The ws doesn't have a acknowledge callback like socket.io\n * so we have to DIY one for ws and other that doesn't have it\n * @param {string} type of reply\n * @param {string} resolverName which is replying\n * @param {*} data payload\n * @param {array} [ts= []] the last received ts, if any \n * @return {string} stringify json\n */\nexport const createWsReply = (type, resolverName, data, ts = []) => {\n ts.push(timestamp())\n return JSON.stringify({\n data: {\n [WS_REPLY_TYPE]: type,\n [WS_EVT_NAME]: resolverName,\n [WS_DATA_NAME]: toJson(data)\n },\n [TIMESTAMP_PARAM_NAME]: ts \n })\n}\n\n// extended function \nexport const createReplyMsg = (resolverName, data, ts = []) => (\n createWsReply(EMIT_REPLY_TYPE, resolverName, data, ts)\n)\n\nexport const createAcknowledgeMsg = (resolverName, data, ts = []) => (\n createWsReply(ACKNOWLEDGE_REPLY_TYPE, resolverName, data, ts)\n)\n\n/**\n * @param {string|object} payload should be string when reply but could be transformed\n * @return {boolean} true is OK\n */\nexport const isWsReply = payload => {\n const json = isString(payload) ? toJson(payload) : payload\n const { data } = json\n if (data) {\n let result = WS_KEYS.filter(key => isObjectHasKey(data, key))\n return (result.length === WS_KEYS.length) ? data : false\n }\n return false\n}\n\n/**\n * @param {string|object} data received data\n * @param {function} [cb=nil] this is for extracting the TS field or when it's error\n * @return {object} false on failed\n */\nexport const extractWsPayload = (payload, cb = nil) => {\n try {\n const json = toJson(payload)\n // now handle the data\n let _data\n if ((_data = isWsReply(json)) !== false) {\n // note the ts property is on its own \n cb(TIMESTAMP_PARAM_NAME, json[TIMESTAMP_PARAM_NAME])\n \n return {\n data: toJson(_data[WS_DATA_NAME]),\n resolverName: _data[WS_EVT_NAME],\n type: _data[WS_REPLY_TYPE]\n }\n }\n throw new JsonqlError(PAYLOAD_NOT_DECODED_ERR, payload)\n } catch(e) {\n return cb(ERROR_KEY, e)\n }\n}\n","// this will be part of the init client sequence\n// as soon as we create a ws client\n// we listen to the on.connect event \n// then we send a init-ping event back to the server\n// and server issue a csrf token back to use \n// we use this token to create a new client and destroy the old one\nimport {\n INTERCOM_RESOLVER_NAME, \n SOCKET_PING_EVENT_NAME,\n HEADERS_KEY,\n DATA_KEY,\n CSRF_HEADER_KEY\n} from 'jsonql-constants'\nimport { \n createQueryStr, \n extractWsPayload,\n timestamp,\n toJson \n} from 'jsonql-utils/module'\nimport {\n JsonqlError\n} from 'jsonql-errors'\nconst CSRF_HEADER_NOT_EXIST_ERR = 'CSRF header is not in the received payload'\n\n/**\n * Util method \n * @param {string} payload return from server\n * @return {object} the useful bit \n */\nfunction extractSrvPayload(payload) {\n let json = toJson(payload)\n \n if (json && typeof json === 'object') {\n // note this method expect the json.data inside\n return extractWsPayload(json)\n }\n \n throw new JsonqlError('extractSrvPayload', json)\n}\n\n/**\n * call the server to get a csrf token \n * @return {string} formatted payload to send to the server \n */\nfunction createInitPing() {\n const ts = timestamp()\n\n return createQueryStr(INTERCOM_RESOLVER_NAME, [SOCKET_PING_EVENT_NAME, ts])\n}\n\n/**\n * Take the raw on.message result back then decoded it \n * @param {*} payload the raw result from server\n * @return {object} the csrf payload\n */\nfunction extractPingResult(payload) {\n const result = extractSrvPayload(payload)\n \n if (result && result[DATA_KEY] && result[DATA_KEY][CSRF_HEADER_KEY]) {\n return {\n [HEADERS_KEY]: result[DATA_KEY]\n }\n }\n\n throw new JsonqlError('extractPingResult', CSRF_HEADER_NOT_EXIST_ERR)\n}\n\n\n/**\n * Create a generic intercom method\n * @param {string} type the event type \n * @param {array} args if any \n * @return {string} formatted payload to send\n */\nfunction createIntercomPayload(type, ...args) {\n const ts = timestamp()\n let payload = [type].concat(args)\n payload.push(ts)\n return createQueryStr(INTERCOM_RESOLVER_NAME, payload)\n}\n\n\nexport { \n extractSrvPayload,\n createInitPing, \n extractPingResult, \n createIntercomPayload \n}","// validator numbers\n// import { NUMBER_TYPES } from './constants';\n\nimport isNaN from 'lodash-es/isNaN'\nimport isString from 'lodash-es/isString'\n/**\n * @2015-05-04 found a problem if the value is a number like string\n * it will pass, so add a chck if it's string before we pass to next\n * @param {number} value expected value\n * @return {boolean} true if OK\n */\nconst checkIsNumber = function(value) {\n return isString(value) ? false : !isNaN( parseFloat(value) )\n}\n\nexport default checkIsNumber\n","// validate string type\nimport trim from 'lodash-es/trim'\nimport isString from 'lodash-es/isString'\n/**\n * @param {string} value expected value\n * @return {boolean} true if OK\n */\nconst checkIsString = function(value) {\n return (trim(value) !== '') ? isString(value) : false\n}\n\nexport default checkIsString\n","// check for boolean\n\n/**\n * @param {boolean} value expected\n * @return {boolean} true if OK\n */\nconst checkIsBoolean = function(value) {\n return value !== null && value !== undefined && typeof value === 'boolean'\n}\n\nexport default checkIsBoolean\n","// validate any thing only check if there is something\n\nimport trim from 'lodash-es/trim'\n\n/**\n * @param {*} value the value\n * @param {boolean} [checkNull=true] strict check if there is null value\n * @return {boolean} true is OK\n */\nconst checkIsAny = function(value, checkNull = true) {\n if (value !== undefined && value !== '' && trim(value) !== '') {\n if (checkNull === false || (checkNull === true && value !== null)) {\n return true;\n }\n }\n return false;\n}\n\nexport default checkIsAny\n","// Good practice rule - No magic number\n\nconst ARGS_NOT_ARRAY_ERR = `args is not an array! You might want to do: ES6 Array.from(arguments) or ES5 Array.prototype.slice.call(arguments)`\nconst PARAMS_NOT_ARRAY_ERR = `params is not an array! Did something gone wrong when you generate the contract.json?`\nconst EXCEPTION_CASE_ERR = 'Could not understand your arguments and parameter structure!'\nconst UNUSUAL_CASE_ERR = 'This is an unusual situation where the arguments are more than the params, but not mark as spread'\n\nconst RETURNS_NAME = 'returns'\n\nimport {\n \n DEFAULT_TYPE, // this is a mistake should move back to the validation\n DATA_KEY, \n ERROR_KEY,\n\n TYPE_KEY,\n OPTIONAL_KEY,\n ENUM_KEY,\n ARGS_KEY,\n CHECKER_KEY,\n ALIAS_KEY,\n\n ARRAY_TYPE_LFT,\n ARRAY_TYPE_RGT,\n \n ARRAY_TYPE,\n OBJECT_TYPE,\n STRING_TYPE,\n BOOLEAN_TYPE,\n NUMBER_TYPE,\n KEY_WORD,\n OR_SEPERATOR\n} from 'jsonql-constants'\n\n// group all export in one \nexport {\n ARGS_NOT_ARRAY_ERR,\n PARAMS_NOT_ARRAY_ERR,\n EXCEPTION_CASE_ERR,\n UNUSUAL_CASE_ERR,\n DEFAULT_TYPE,\n ARRAY_TYPE_LFT,\n ARRAY_TYPE_RGT,\n TYPE_KEY,\n OPTIONAL_KEY,\n ENUM_KEY,\n ARGS_KEY,\n CHECKER_KEY,\n ALIAS_KEY,\n ARRAY_TYPE,\n OBJECT_TYPE,\n STRING_TYPE,\n BOOLEAN_TYPE,\n NUMBER_TYPE,\n KEY_WORD,\n OR_SEPERATOR,\n\n RETURNS_NAME,\n\n DATA_KEY, \n ERROR_KEY \n}","// primitive types\nimport checkIsNumber from './number'\nimport checkIsString from './string'\nimport checkIsBoolean from './boolean'\nimport checkIsAny from './any'\nimport { NUMBER_TYPE, STRING_TYPE, BOOLEAN_TYPE } from './constants'\n\n/**\n * this is a wrapper method to call different one based on their type\n * @param {string} type to check\n * @return {function} a function to handle the type\n */\nconst combineFn = function(type) {\n switch (type) {\n case NUMBER_TYPE:\n return checkIsNumber\n case STRING_TYPE:\n return checkIsString\n case BOOLEAN_TYPE:\n return checkIsBoolean\n default:\n return checkIsAny\n }\n}\n\nexport default combineFn\n","// validate array type\n\nimport isArray from 'lodash-es/isArray'\nimport trim from 'lodash-es/trim'\nimport combineFn from './combine'\nimport {\n ARRAY_TYPE_LFT,\n ARRAY_TYPE_RGT,\n OR_SEPERATOR\n} from './constants'\n\n/**\n * @param {array} value expected\n * @param {string} [type=''] pass the type if we encounter array. then we need to check the value as well\n * @return {boolean} true if OK\n */\nexport const checkIsArray = function(value, type='') {\n if (isArray(value)) {\n if (type === '' || trim(type)==='') {\n return true;\n }\n // we test it in reverse\n // @TODO if the type is an array (OR) then what?\n // we need to take into account this could be an array\n const c = value.filter(v => !combineFn(type)(v))\n return !(c.length > 0)\n }\n return false\n}\n\n/**\n * check if it matches the array. pattern\n * @param {string} type\n * @return {boolean|array} false means NO, always return array\n */\nexport const isArrayLike = function(type) {\n // @TODO could that have something like array<> instead of array.<>? missing the dot?\n // because type script is Array without the dot\n if (type.indexOf(ARRAY_TYPE_LFT) > -1 && type.indexOf(ARRAY_TYPE_RGT) > -1) {\n const _type = type.replace(ARRAY_TYPE_LFT, '').replace(ARRAY_TYPE_RGT, '')\n if (_type.indexOf(OR_SEPERATOR)) {\n return _type.split(OR_SEPERATOR)\n }\n return [_type]\n }\n return false\n}\n\n/**\n * we might encounter something like array. then we need to take it apart\n * @param {object} p the prepared object for processing\n * @param {string|array} type the type came from \n * @return {boolean} for the filter to operate on\n */\nexport const arrayTypeHandler = function(p, type) {\n const { arg } = p\n // need a special case to handle the OR type\n // we need to test the args instead of the type(s)\n if (type.length > 1) {\n return !arg.filter(v => (\n !(type.length > type.filter(t => !combineFn(t)(v)).length)\n )).length\n }\n // type is array so this will be or!\n return type.length > type.filter(t => !checkIsArray(arg, t)).length\n}\n","// validate object type\n\nimport isPlainObject from 'lodash-es/isPlainObject'\n// import filter from 'lodash-es/filter'\nimport combineFn from './combine'\nimport { checkIsArray, isArrayLike, arrayTypeHandler } from './array'\n/**\n * @TODO if provide with the keys then we need to check if the key:value type as well\n * @param {object} value expected\n * @param {array} [keys=null] if it has the keys array to compare as well\n * @return {boolean} true if OK\n */\nexport const checkIsObject = function(value, keys=null) {\n if (isPlainObject(value)) {\n if (!keys) {\n return true\n }\n if (checkIsArray(keys)) {\n // please note we DON'T care if some is optional\n // plese refer to the contract.json for the keys\n return !keys.filter(key => {\n let _value = value[key.name];\n return !(key.type.length > key.type.filter(type => {\n let tmp;\n if (_value !== undefined) {\n if ((tmp = isArrayLike(type)) !== false) {\n return !arrayTypeHandler({arg: _value}, tmp)\n // return tmp.filter(t => !checkIsArray(_value, t)).length;\n // @TODO there might be an object within an object with keys as well :S\n }\n return !combineFn(type)(_value)\n }\n return true\n }).length)\n }).length;\n }\n }\n return false\n}\n\n/**\n * fold this into it's own function to handler different object type\n * @param {object} p the prepared object for process\n * @return {boolean}\n */\nexport const objectTypeHandler = function(p) {\n const { arg, param } = p\n let _args = [arg]\n if (Array.isArray(param.keys) && param.keys.length) {\n _args.push(param.keys)\n }\n // just simple check\n return Reflect.apply(checkIsObject, null, _args)\n}\n","// move the index.js code here that make more sense to find where things are\n\nimport {\n checkIsArray,\n isArrayLike,\n arrayTypeHandler,\n objectTypeHandler,\n combineFn,\n notEmpty\n} from './index'\n\nimport {\n DEFAULT_TYPE,\n ARRAY_TYPE,\n OBJECT_TYPE,\n ARGS_NOT_ARRAY_ERR,\n PARAMS_NOT_ARRAY_ERR,\n EXCEPTION_CASE_ERR,\n DATA_KEY, \n ERROR_KEY \n} from './constants'\n\n\nimport JsonqlValidationError from 'jsonql-errors/src/validation-error'\nimport JsonqlError from 'jsonql-errors/src/error'\n// import debug from 'debug'\n// const debugFn = debug('jsonql-params-validator:validator')\n// also export this for use in other places\n\n/**\n * We need to handle those optional parameter without a default value\n * @param {object} params from contract.json\n * @return {boolean} for filter operation false is actually OK\n */\nconst optionalHandler = function( params ) {\n const { arg, param } = params\n if (notEmpty(arg)) {\n // debug('call optional handler', arg, params);\n // loop through the type in param\n return !(param.type.length > param.type.filter(type =>\n validateHandler(type, params)\n ).length)\n }\n return false\n}\n\n/**\n * actually picking the validator\n * @param {*} type for checking\n * @param {*} value for checking\n * @return {boolean} true on OK\n */\nconst validateHandler = function(type, value) {\n let tmp;\n switch (true) {\n case type === OBJECT_TYPE:\n // debugFn('call OBJECT_TYPE')\n return !objectTypeHandler(value)\n case type === ARRAY_TYPE:\n // debugFn('call ARRAY_TYPE')\n return !checkIsArray(value.arg)\n // @TODO when the type is not present, it always fall through here\n // so we need to find a way to actually pre-check the type first\n // AKA check the contract.json map before running here\n case (tmp = isArrayLike(type)) !== false:\n // debugFn('call ARRAY_LIKE: %O', value)\n return !arrayTypeHandler(value, tmp)\n default:\n return !combineFn(type)(value.arg)\n }\n}\n\n/**\n * it get too longer to fit in one line so break it out from the fn below\n * @param {*} arg value\n * @param {object} param config\n * @return {*} value or apply default value\n */\nconst getOptionalValue = function(arg, param) {\n if (arg !== undefined) {\n return arg\n }\n return (param.optional === true && param.defaultvalue !== undefined ? param.defaultvalue : null)\n}\n\n/**\n * padding the arguments with defaultValue if the arguments did not provide the value\n * this will be the name export\n * @param {array} args normalized arguments\n * @param {array} params from contract.json\n * @return {array} merge the two together\n */\nexport const normalizeArgs = function(args, params) {\n // first we should check if this call require a validation at all\n // there will be situation where the function doesn't need args and params\n if (!checkIsArray(params)) {\n // debugFn('params value', params)\n throw new JsonqlValidationError(PARAMS_NOT_ARRAY_ERR)\n }\n if (params.length === 0) {\n return []\n }\n if (!checkIsArray(args)) {\n throw new JsonqlValidationError(ARGS_NOT_ARRAY_ERR)\n }\n // debugFn(args, params);\n // fall through switch\n switch(true) {\n case args.length == params.length: // standard\n return args.map((arg, i) => (\n {\n arg,\n index: i,\n param: params[i]\n }\n ))\n case params[0].variable === true: // using spread syntax\n const type = params[0].type;\n return args.map((arg, i) => (\n {\n arg,\n index: i, // keep the index for reference\n param: params[i] || { type, name: '_' }\n }\n ))\n // with optional defaultValue parameters\n case args.length < params.length:\n return params.map((param, i) => (\n {\n param,\n index: i,\n arg: getOptionalValue(args[i], param),\n optional: param.optional || false\n }\n ))\n // this one pass more than it should have anything after the args.length will be cast as any type\n case args.length > params.length:\n let ctn = params.length;\n // this happens when we have those array. type\n let _type = [ DEFAULT_TYPE ]\n // we only looking at the first one, this might be a @BUG\n /*\n if ((tmp = isArrayLike(params[0].type[0])) !== false) {\n _type = tmp;\n } */\n // if we use the params as guide then the rest will get throw out\n // which is not what we want, instead, anything without the param\n // will get a any type and optional flag\n return args.map((arg, i) => {\n let optional = i >= ctn ? true : !!params[i].optional\n let param = params[i] || { type: _type, name: `_${i}` }\n return {\n arg: optional ? getOptionalValue(arg, param) : arg,\n index: i,\n param,\n optional\n }\n })\n // @TODO find out if there is more cases not cover\n default: // this should never happen\n // debugFn('args', args)\n // debugFn('params', params)\n // this is unknown therefore we just throw it!\n throw new JsonqlError(EXCEPTION_CASE_ERR, { args, params })\n }\n}\n\n// what we want is after the validaton we also get the normalized result\n// which is with the optional property if the argument didn't provide it\n/**\n * process the array of params back to their arguments\n * @param {array} result the params result\n * @return {array} arguments\n */\nconst processReturn = result => result.map(r => r.arg)\n\n/**\n * validator main interface\n * @param {array} args the arguments pass to the method call\n * @param {array} params from the contract for that method\n * @param {boolean} [withResul=false] if true then this will return the normalize result as well\n * @return {array} empty array on success, or failed parameter and reasons\n */\nexport const validateSync = function(args, params, withResult = false) {\n let cleanArgs = normalizeArgs(args, params)\n let checkResult = cleanArgs.filter(p => {\n // v1.4.4 this fixed the problem, the root level optional is from the last fn\n if (p.optional === true || p.param.optional === true) {\n return optionalHandler(p)\n }\n // because array of types means OR so if one pass means pass\n return !(p.param.type.length > p.param.type.filter(\n type => validateHandler(type, p)\n ).length)\n })\n // using the same convention we been using all this time\n return !withResult ? checkResult : {\n [ERROR_KEY]: checkResult,\n [DATA_KEY]: processReturn(cleanArgs)\n }\n}\n\n/**\n * A wrapper method that return promise\n * @param {array} args arguments\n * @param {array} params from contract.json\n * @param {boolean} [withResul=false] if true then this will return the normalize result as well\n * @return {object} promise.then or catch\n */\nexport const validateAsync = function(args, params, withResult = false) {\n return new Promise((resolver, rejecter) => {\n const result = validateSync(args, params, withResult)\n if (withResult) {\n return result[ERROR_KEY].length ? rejecter(result[ERROR_KEY])\n : resolver(result[DATA_KEY])\n }\n // the different is just in the then or catch phrase\n return result.length ? rejecter(result) : resolver([])\n })\n}\n","/** Used to stand-in for `undefined` hash values. */\nvar HASH_UNDEFINED = '__lodash_hash_undefined__';\n\n/**\n * Adds `value` to the array cache.\n *\n * @private\n * @name add\n * @memberOf SetCache\n * @alias push\n * @param {*} value The value to cache.\n * @returns {Object} Returns the cache instance.\n */\nfunction setCacheAdd(value) {\n this.__data__.set(value, HASH_UNDEFINED);\n return this;\n}\n\nexport default setCacheAdd;\n","/**\n * Checks if `value` is in the array cache.\n *\n * @private\n * @name has\n * @memberOf SetCache\n * @param {*} value The value to search for.\n * @returns {number} Returns `true` if `value` is found, else `false`.\n */\nfunction setCacheHas(value) {\n return this.__data__.has(value);\n}\n\nexport default setCacheHas;\n","/**\n * A specialized version of `_.some` for arrays without support for iteratee\n * shorthands.\n *\n * @private\n * @param {Array} [array] The array to iterate over.\n * @param {Function} predicate The function invoked per iteration.\n * @returns {boolean} Returns `true` if any element passes the predicate check,\n * else `false`.\n */\nfunction arraySome(array, predicate) {\n var index = -1,\n length = array == null ? 0 : array.length;\n\n while (++index < length) {\n if (predicate(array[index], index, array)) {\n return true;\n }\n }\n return false;\n}\n\nexport default arraySome;\n","/**\n * Checks if a `cache` value for `key` exists.\n *\n * @private\n * @param {Object} cache The cache to query.\n * @param {string} key The key of the entry to check.\n * @returns {boolean} Returns `true` if an entry for `key` exists, else `false`.\n */\nfunction cacheHas(cache, key) {\n return cache.has(key);\n}\n\nexport default cacheHas;\n","/**\n * Converts `map` to its key-value pairs.\n *\n * @private\n * @param {Object} map The map to convert.\n * @returns {Array} Returns the key-value pairs.\n */\nfunction mapToArray(map) {\n var index = -1,\n result = Array(map.size);\n\n map.forEach(function(value, key) {\n result[++index] = [key, value];\n });\n return result;\n}\n\nexport default mapToArray;\n","/**\n * Converts `set` to an array of its values.\n *\n * @private\n * @param {Object} set The set to convert.\n * @returns {Array} Returns the values.\n */\nfunction setToArray(set) {\n var index = -1,\n result = Array(set.size);\n\n set.forEach(function(value) {\n result[++index] = value;\n });\n return result;\n}\n\nexport default setToArray;\n","/**\n * Appends the elements of `values` to `array`.\n *\n * @private\n * @param {Array} array The array to modify.\n * @param {Array} values The values to append.\n * @returns {Array} Returns `array`.\n */\nfunction arrayPush(array, values) {\n var index = -1,\n length = values.length,\n offset = array.length;\n\n while (++index < length) {\n array[offset + index] = values[index];\n }\n return array;\n}\n\nexport default arrayPush;\n","/**\n * A specialized version of `_.filter` for arrays without support for\n * iteratee shorthands.\n *\n * @private\n * @param {Array} [array] The array to iterate over.\n * @param {Function} predicate The function invoked per iteration.\n * @returns {Array} Returns the new filtered array.\n */\nfunction arrayFilter(array, predicate) {\n var index = -1,\n length = array == null ? 0 : array.length,\n resIndex = 0,\n result = [];\n\n while (++index < length) {\n var value = array[index];\n if (predicate(value, index, array)) {\n result[resIndex++] = value;\n }\n }\n return result;\n}\n\nexport default arrayFilter;\n","/**\n * This method returns a new empty array.\n *\n * @static\n * @memberOf _\n * @since 4.13.0\n * @category Util\n * @returns {Array} Returns the new empty array.\n * @example\n *\n * var arrays = _.times(2, _.stubArray);\n *\n * console.log(arrays);\n * // => [[], []]\n *\n * console.log(arrays[0] === arrays[1]);\n * // => false\n */\nfunction stubArray() {\n return [];\n}\n\nexport default stubArray;\n","/**\n * A specialized version of `matchesProperty` for source values suitable\n * for strict equality comparisons, i.e. `===`.\n *\n * @private\n * @param {string} key The key of the property to get.\n * @param {*} srcValue The value to match.\n * @returns {Function} Returns the new spec function.\n */\nfunction matchesStrictComparable(key, srcValue) {\n return function(object) {\n if (object == null) {\n return false;\n }\n return object[key] === srcValue &&\n (srcValue !== undefined || (key in Object(object)));\n };\n}\n\nexport default matchesStrictComparable;\n","/**\n * The base implementation of `_.hasIn` without support for deep paths.\n *\n * @private\n * @param {Object} [object] The object to query.\n * @param {Array|string} key The key to check.\n * @returns {boolean} Returns `true` if `key` exists, else `false`.\n */\nfunction baseHasIn(object, key) {\n return object != null && key in Object(object);\n}\n\nexport default baseHasIn;\n","/**\n * The base implementation of `_.property` without support for deep paths.\n *\n * @private\n * @param {string} key The key of the property to get.\n * @returns {Function} Returns the new accessor function.\n */\nfunction baseProperty(key) {\n return function(object) {\n return object == null ? undefined : object[key];\n };\n}\n\nexport default baseProperty;\n","/** Error message constants. */\nvar FUNC_ERROR_TEXT = 'Expected a function';\n\n/**\n * Creates a function that negates the result of the predicate `func`. The\n * `func` predicate is invoked with the `this` binding and arguments of the\n * created function.\n *\n * @static\n * @memberOf _\n * @since 3.0.0\n * @category Function\n * @param {Function} predicate The predicate to negate.\n * @returns {Function} Returns the new negated function.\n * @example\n *\n * function isEven(n) {\n * return n % 2 == 0;\n * }\n *\n * _.filter([1, 2, 3, 4, 5, 6], _.negate(isEven));\n * // => [1, 3, 5]\n */\nfunction negate(predicate) {\n if (typeof predicate != 'function') {\n throw new TypeError(FUNC_ERROR_TEXT);\n }\n return function() {\n var args = arguments;\n switch (args.length) {\n case 0: return !predicate.call(this);\n case 1: return !predicate.call(this, args[0]);\n case 2: return !predicate.call(this, args[0], args[1]);\n case 3: return !predicate.call(this, args[0], args[1], args[2]);\n }\n return !predicate.apply(this, args);\n };\n}\n\nexport default negate;\n","/**\n * The base implementation of methods like `_.findKey` and `_.findLastKey`,\n * without support for iteratee shorthands, which iterates over `collection`\n * using `eachFunc`.\n *\n * @private\n * @param {Array|Object} collection The collection to inspect.\n * @param {Function} predicate The function invoked per iteration.\n * @param {Function} eachFunc The function to iterate over `collection`.\n * @returns {*} Returns the found element or its key, else `undefined`.\n */\nfunction baseFindKey(collection, predicate, eachFunc) {\n var result;\n eachFunc(collection, function(value, key, collection) {\n if (predicate(value, key, collection)) {\n result = key;\n return false;\n }\n });\n return result;\n}\n\nexport default baseFindKey;\n","/**\n * @param {array} arr Array for check\n * @param {*} value target\n * @return {boolean} true on successs\n */\nconst isInArray = function(arr, value) {\n return !!arr.filter(a => a === value).length\n}\n\nexport default isInArray\n","// breaking the whole thing up to see what cause the multiple calls issue\n\nimport isFunction from 'lodash-es/isFunction'\nimport merge from 'lodash-es/merge'\nimport mapValues from 'lodash-es/mapValues'\n\nimport JsonqlEnumError from 'jsonql-errors/src/enum-error'\nimport JsonqlTypeError from 'jsonql-errors/src/type-error'\nimport JsonqlCheckerError from 'jsonql-errors/src/checker-error'\n\nimport {\n TYPE_KEY,\n OPTIONAL_KEY,\n ENUM_KEY,\n ARGS_KEY,\n CHECKER_KEY,\n KEY_WORD\n} from '../constants'\nimport { checkIsArray } from '../array'\n\n// import debug from 'debug';\n// const debugFn = debug('jsonql-params-validator:options:validation')\n\n/**\n * just make sure it returns an array to use\n * @param {*} arg input\n * @return {array} output\n */\nconst toArray = arg => checkIsArray(arg) ? arg : [arg]\n\n/**\n * DIY in array\n * @param {array} arr to check against\n * @param {*} value to check\n * @return {boolean} true on OK\n */\nconst inArray = (arr, value) => (\n !!arr.filter(v => v === value).length\n)\n\n/**\n * break out to make the code easier to read\n * @param {object} value to process\n * @param {function} cb the validateSync\n * @return {array} empty on success\n */\nfunction validateHandler(value, cb) {\n // cb is the validateSync methods\n let args = [\n [ value[ARGS_KEY] ],\n [{\n [TYPE_KEY]: toArray(value[TYPE_KEY]),\n [OPTIONAL_KEY]: value[OPTIONAL_KEY]\n }]\n ]\n // debugFn('validateHandler', args)\n return Reflect.apply(cb, null, args)\n}\n\n/**\n * Check against the enum value if it's provided\n * @param {*} value to check\n * @param {*} enumv to check against if it's not false\n * @return {boolean} true on OK\n */\nconst enumHandler = (value, enumv) => {\n if (checkIsArray(enumv)) {\n return inArray(enumv, value)\n }\n return true\n}\n\n/**\n * Allow passing a function to check the value\n * There might be a problem here if the function is incorrect\n * and that will makes it hard to debug what is going on inside\n * @TODO there could be a few feature add to this one under different circumstance\n * @param {*} value to check\n * @param {function} checker for checking\n */\nconst checkerHandler = (value, checker) => {\n try {\n return isFunction(checker) ? checker.apply(null, [value]) : false\n } catch (e) {\n return false\n }\n}\n\n/**\n * Taken out from the runValidaton this only validate the required values\n * @param {array} args from the config2argsAction\n * @param {function} cb validateSync\n * @return {array} of configuration values\n */\nfunction runValidationAction(cb) {\n return (value, key) => {\n // debugFn('runValidationAction', key, value)\n if (value[KEY_WORD]) {\n return value[ARGS_KEY]\n }\n const check = validateHandler(value, cb)\n if (check.length) {\n // log('runValidationAction', key, value)\n throw new JsonqlTypeError(key, check)\n }\n if (value[ENUM_KEY] !== false && !enumHandler(value[ARGS_KEY], value[ENUM_KEY])) {\n // log(ENUM_KEY, value[ENUM_KEY])\n throw new JsonqlEnumError(key)\n }\n if (value[CHECKER_KEY] !== false && !checkerHandler(value[ARGS_KEY], value[CHECKER_KEY])) {\n // log(CHECKER_KEY, value[CHECKER_KEY])\n throw new JsonqlCheckerError(key)\n }\n return value[ARGS_KEY]\n }\n}\n\n/**\n * @param {object} args from the config2argsAction\n * @param {function} cb validateSync\n * @return {object} of configuration values\n */\nexport default function runValidation(args, cb) {\n const [ argsForValidate, pristineValues ] = args\n // turn the thing into an array and see what happen here\n // debugFn('_args', argsForValidate)\n const result = mapValues(argsForValidate, runValidationAction(cb))\n return merge(result, pristineValues)\n}\n","/// this is port back from the client to share across all projects\n\nimport merge from 'lodash-es/merge'\nimport { prepareArgsForValidation } from './prepare-args-for-validation'\nimport runValidation from './run-validation'\n\n// import debug from 'debug'\n// const debugFn = debug('jsonql-params-validator:check-options-async')\n\n/**\n * Quick transform\n * @param {object} config that one\n * @param {object} appProps mutation configuration options\n * @return {object} put that arg into the args\n */\nconst configToArgs = (config, appProps) => {\n return Promise.resolve(\n prepareArgsForValidation(config, appProps)\n )\n}\n\n/**\n * @param {object} config user provide configuration option\n * @param {object} appProps mutation configuration options\n * @param {object} constProps the immutable configuration options\n * @param {function} cb the validateSync method\n * @return {object} Promise resolve merge config object\n */\nexport default function(config = {}, appProps, constProps, cb) {\n return configToArgs(config, appProps)\n .then(args1 => runValidation(args1, cb))\n // next if every thing good then pass to final merging\n .then(args2 => merge({}, args2, constProps))\n}\n","// create function to construct the config entry so we don't need to keep building object\n\nimport isFunction from 'lodash-es/isFunction'\nimport isString from 'lodash-es/isString'\nimport {\n ARGS_KEY,\n TYPE_KEY,\n CHECKER_KEY,\n ENUM_KEY,\n OPTIONAL_KEY,\n ALIAS_KEY\n} from 'jsonql-constants'\n\nimport { checkIsArray } from '../array'\n// import checkIsBoolean from '../boolean'\n// import debug from 'debug';\n// const debugFn = debug('jsonql-params-validator:construct-config');\n/**\n * @param {*} args value\n * @param {string} type for value\n * @param {boolean} [optional=false]\n * @param {boolean|array} [enumv=false]\n * @param {boolean|function} [checker=false]\n * @return {object} config entry\n */\nexport default function constructConfig(args, type, optional=false, enumv=false, checker=false, alias=false) {\n let base = {\n [ARGS_KEY]: args,\n [TYPE_KEY]: type\n }\n if (optional === true) {\n base[OPTIONAL_KEY] = true\n }\n if (checkIsArray(enumv)) {\n base[ENUM_KEY] = enumv\n }\n if (isFunction(checker)) {\n base[CHECKER_KEY] = checker\n }\n if (isString(alias)) {\n base[ALIAS_KEY] = alias\n }\n return base\n}\n","// export also create wrapper methods\nimport checkOptionsAsync from './check-options-async'\nimport checkOptionsSync from './check-options-sync'\nimport constructConfigFn from './construct-config'\nimport {\n ENUM_KEY,\n CHECKER_KEY,\n ALIAS_KEY,\n OPTIONAL_KEY\n} from 'jsonql-constants'\n\n/**\n * This has a different interface\n * @param {*} value to supply\n * @param {string|array} type for checking\n * @param {object} params to map against the config check\n * @param {array} params.enumv NOT enum\n * @param {boolean} params.optional false then nothing\n * @param {function} params.checker need more work on this one later\n * @param {string} params.alias mostly for cmd\n */\nconst createConfig = (value, type, params = {}) => {\n // Note the enumv not ENUM\n // const { enumv, optional, checker, alias } = params;\n // let args = [value, type, optional, enumv, checker, alias];\n const {\n [OPTIONAL_KEY]: o,\n [ENUM_KEY]: e,\n [CHECKER_KEY]: c,\n [ALIAS_KEY]: a\n } = params;\n return constructConfigFn.apply(null, [value, type, o, e, c, a])\n}\n\n// for testing purpose\nconst JSONQL_PARAMS_VALIDATOR_INFO = '__PLACEHOLDER__'\n\n/**\n * construct the actual end user method, rename with prefix get since 1.5.2\n * @param {function} validateSync validation method\n * @return {function} for performaning the actual valdiation\n */\nconst getCheckConfigAsync = function(validateSync) {\n /**\n * We recreate the method here to avoid the circlar import\n * @param {object} config user supply configuration\n * @param {object} appProps mutation options\n * @param {object} [constantProps={}] optional: immutation options\n * @return {object} all checked configuration\n */\n return function(config, appProps, constantProps= {}) {\n return checkOptionsAsync(config, appProps, constantProps, validateSync)\n }\n}\n\n/**\n * copy of above but it's sync, rename with prefix get since 1.5.2\n * @param {function} validateSync validation method\n * @return {function} for performaning the actual valdiation\n */\nconst getCheckConfig = function(validateSync) {\n return function(config, appProps, constantProps = {}) {\n return checkOptionsSync(config, appProps, constantProps, validateSync)\n }\n}\n\n// re-export\nexport {\n createConfig,\n constructConfigFn,\n getCheckConfigAsync,\n getCheckConfig,\n JSONQL_PARAMS_VALIDATOR_INFO\n}\n","// export\nimport {\n checkIsObject,\n notEmpty,\n checkIsAny,\n checkIsString,\n checkIsBoolean,\n checkIsNumber,\n checkIsArray\n} from './src'\nimport * as validator from './src/validator'\n// configuration checking\nimport * as jsonqlOptions from './src/options'\n// the two extra functions\nimport isInArray from './src/is-in-array'\nimport isObjectHasKeyFn from './src/is-key-in-object'\n\nconst isObject = checkIsObject\nconst isAny = checkIsAny\nconst isString = checkIsString\nconst isBoolean = checkIsBoolean\nconst isNumber = checkIsNumber\nconst isArray = checkIsArray\nconst isNotEmpty = notEmpty\n\nconst normalizeArgs = validator.normalizeArgs\nconst validateSync = validator.validateSync\nconst validateAsync = validator.validateAsync\n\nconst JSONQL_PARAMS_VALIDATOR_INFO = jsonqlOptions.JSONQL_PARAMS_VALIDATOR_INFO\n\nconst createConfig = jsonqlOptions.createConfig\nconst constructConfig = jsonqlOptions.constructConfigFn\n// construct the final output 1.5.2\nconst checkConfigAsync = jsonqlOptions.getCheckConfigAsync(validator.validateSync)\nconst checkConfig = jsonqlOptions.getCheckConfig(validator.validateSync)\n\nconst inArray = isInArray\nconst isObjectHasKey = isObjectHasKeyFn\n\n// check returns methods \nimport { \n checkReturns, \n checkReturnsAsync, \n checkResolverReturns, \n checkResolverReturnsAsync \n} from './src/returns'\n\n\n// group the in one \nexport {\n JSONQL_PARAMS_VALIDATOR_INFO,\n \n isObject,\n isAny,\n isString,\n isBoolean,\n isNumber,\n isArray,\n isNotEmpty,\n \n inArray,\n isObjectHasKey,\n\n normalizeArgs,\n validateSync,\n validateAsync,\n\n createConfig,\n constructConfig,\n checkConfig,\n checkConfigAsync,\n\n checkReturns, \n checkReturnsAsync, \n checkResolverReturns, \n checkResolverReturnsAsync\n}\n\n\n\n\n\n","// move the get logger stuff here\n\n// it does nothing\nconst dummyLogger = () => {}\n\n/**\n * re-use the debugOn prop to control this log method\n * @param {object} opts configuration\n * @return {function} the log function\n */\nconst getLogger = (opts) => {\n const { debugOn } = opts \n if (debugOn) {\n return (...args) => {\n Reflect.apply(console.info, console, ['[jsonql-ws-client-core]', ...args])\n }\n }\n return dummyLogger\n}\n\n/**\n * Make sure there is a log method\n * @param {object} opts configuration\n * @return {object} opts\n */\nconst getLogFn = opts => {\n const { log } = opts // 1.3.9 if we pass a log method here then we use this\n if (!log || typeof log !== 'function') {\n return getLogger(opts)\n }\n opts.log('---> getLogFn user supplied log function <---', opts)\n return log\n}\n\nexport { getLogFn }","// group all the repetitive message here\n\nexport const TAKEN_BY_OTHER_TYPE_ERR = 'You are trying to register an event already been taken by other type:'\n","// Create two WeakMap store as a private keys\nexport const NB_EVENT_SERVICE_PRIVATE_STORE = new WeakMap()\nexport const NB_EVENT_SERVICE_PRIVATE_LAZY = new WeakMap()\n","/**\n * generate a 32bit hash based on the function.toString()\n * _from http://stackoverflow.com/questions/7616461/generate-a-hash-_from-string-in-javascript-jquery\n * @param {string} s the converted to string function\n * @return {string} the hashed function string\n */\nexport function hashCode(s) {\n\treturn s.split(\"\").reduce(function(a,b){a=((a<<5)-a)+b.charCodeAt(0);return a&a},0)\n}\n\n/**\n * wrapper to make sure it string\n * @param {*} input whatever\n * @return {string} output\n */\nexport function hashCode2Str(s) {\n return hashCode(s) + ''\n}\n\n/**\n * Just check if a pattern is an RegExp object\n * @param {*} pat whatever\n * @return {boolean} false when its not\n */\nexport function isRegExp(pat) {\n return pat instanceof RegExp\n}\n\n/**\n * check if its string\n * @param {*} arg whatever\n * @return {boolean} false when it's not\n */\nexport function isString(arg) {\n return typeof arg === 'string'\n}\n\n/**\n * Find from the array by matching the pattern\n * @param {*} pattern a string or RegExp object\n * @return {object} regex object or false when we can not id the input\n */\nexport function getRegex(pattern) {\n switch (true) {\n case isRegExp(pattern) === true:\n return pattern\n case isString(pattern) === true:\n return new RegExp(pattern)\n default:\n return false\n }\n}\n","// making all the functionality on it's own\n// import { WatchClass } from './watch'\n/*\nwe use a different way to do the same watch thing now\nthis.watch('suspend', function(value, prop, oldValue) {\n this.logger(`${prop} set from ${oldValue} to ${value}`)\n // it means it set the suspend = true then release it\n if (oldValue === true && value === false) {\n // we want this happen after the return happens\n setTimeout(() => {\n this.release()\n }, 1)\n }\n return value; // we need to return the value to store it\n})\n*/\nimport { getRegex, isRegExp } from './utils'\n\nexport default class SuspendClass {\n\n constructor() {\n // suspend, release and queue\n this.__suspend_state__ = null\n // to do this proper we don't use a new prop to hold the event name pattern\n this.__pattern__ = null\n this.queueStore = new Set()\n }\n\n /**\n * start suspend\n * @return {void}\n */\n $suspend() {\n this.logger(`---> SUSPEND ALL OPS <---`)\n this.__suspend__(true)\n }\n\n /**\n * release the queue\n * @return {void}\n */\n $release() {\n this.logger(`---> RELEASE SUSPENDED QUEUE <---`)\n this.__suspend__(false)\n }\n\n /**\n * suspend event by pattern\n * @param {string} pattern the pattern search matches the event name\n * @return {void}\n */\n $suspendEvent(pattern) {\n const regex = getRegex(pattern)\n if (isRegExp(regex)) {\n this.__pattern__ = regex\n return this.$suspend()\n }\n throw new Error(`We expect a pattern variable to be string or RegExp, but we got \"${typeof regex}\" instead`)\n }\n\n /**\n * queuing call up when it's in suspend mode\n * @param {string} evt the event name\n * @param {*} args unknown number of arguments\n * @return {boolean} true when added or false when it's not\n */\n $queue(evt, ...args) {\n this.logger('($queue) get called')\n if (this.__suspend_state__ === true) {\n if (isRegExp(this.__pattern__)) { // it's better then check if its not null\n // check the pattern and decide if we want to suspend it or not\n let found = this.__pattern__.test(evt)\n if (!found) {\n return false\n }\n }\n this.logger('($queue) added to $queue', args)\n // @TODO there shouldn't be any duplicate, but how to make sure?\n this.queueStore.add([evt].concat(args))\n // return this.queueStore.size\n }\n return !!this.__suspend_state__\n }\n\n /**\n * a getter to get all the store queue\n * @return {array} Set turn into Array before return\n */\n get $queues() {\n let size = this.queueStore.size\n this.logger('($queues)', `size: ${size}`)\n if (size > 0) {\n return Array.from(this.queueStore)\n }\n return []\n }\n\n /**\n * to set the suspend and check if it's boolean value\n * @param {boolean} value to trigger\n */\n __suspend__(value) {\n if (typeof value === 'boolean') {\n const lastValue = this.__suspend_state__\n this.__suspend_state__ = value\n this.logger(`($suspend) Change from \"${lastValue}\" --> \"${value}\"`)\n if (lastValue === true && value === false) {\n this.__release__()\n }\n } else {\n throw new Error(`$suspend only accept Boolean value! we got ${typeof value}`)\n }\n }\n\n /**\n * Release the queue\n * @return {int} size if any\n */\n __release__() {\n let size = this.queueStore.size\n let pattern = this.__pattern__\n this.__pattern__ = null\n this.logger(`(release) was called with ${size}${pattern ? ' for \"' + pattern + '\"': ''} item${size > 1 ? 's' : ''}`)\n if (size > 0) {\n const queue = Array.from(this.queueStore)\n this.queueStore.clear()\n this.logger('(release queue)', queue)\n queue.forEach(args => {\n this.logger(args)\n Reflect.apply(this.$trigger, this, args)\n })\n this.logger(`Release size ${this.queueStore.size}`)\n }\n\n return size\n }\n}\n","// break up the main file because its getting way too long\nimport {\n NB_EVENT_SERVICE_PRIVATE_STORE,\n NB_EVENT_SERVICE_PRIVATE_LAZY\n} from './store'\nimport { hashCode2Str, isString } from './utils'\nimport SuspendClass from './suspend'\n\nexport default class StoreService extends SuspendClass {\n\n constructor(config = {}) {\n super()\n if (config.logger && typeof config.logger === 'function') {\n this.logger = config.logger\n }\n this.keep = config.keep\n // for the $done setter\n this.result = config.keep ? [] : null\n // we need to init the store first otherwise it could be a lot of checking later\n this.normalStore = new Map()\n this.lazyStore = new Map()\n }\n\n /**\n * validate the event name(s)\n * @param {string[]} evt event name\n * @return {boolean} true when OK\n */\n validateEvt(...evt) {\n evt.forEach(e => {\n if (!isString(e)) {\n this.logger('(validateEvt)', e)\n throw new Error(`Event name must be string type! we got ${typeof e}`)\n }\n })\n return true\n }\n\n /**\n * Simple quick check on the two main parameters\n * @param {string} evt event name\n * @param {function} callback function to call\n * @return {boolean} true when OK\n */\n validate(evt, callback) {\n if (this.validateEvt(evt)) {\n if (typeof callback === 'function') {\n return true\n }\n }\n throw new Error(`callback required to be function type! we got ${typeof callback}`)\n }\n\n /**\n * Check if this type is correct or not added in V1.5.0\n * @param {string} type for checking\n * @return {boolean} true on OK\n */\n validateType(type) {\n this.validateEvt(type)\n const types = ['on', 'only', 'once', 'onlyOnce']\n return !!types.filter(t => type === t).length\n }\n\n /**\n * Run the callback\n * @param {function} callback function to execute\n * @param {array} payload for callback\n * @param {object} ctx context or null\n * @return {void} the result store in $done\n */\n run(callback, payload, ctx) {\n this.logger('(run) callback:', callback, 'payload:', payload, 'context:', ctx)\n this.$done = Reflect.apply(callback, ctx, this.toArray(payload))\n }\n\n /**\n * Take the content out and remove it from store id by the name\n * @param {string} evt event name\n * @param {string} [storeName = lazyStore] name of store\n * @return {object|boolean} content or false on not found\n */\n takeFromStore(evt, storeName = 'lazyStore') {\n let store = this[storeName] // it could be empty at this point\n if (store) {\n this.logger('(takeFromStore)', storeName, store)\n if (store.has(evt)) {\n let content = store.get(evt)\n this.logger(`(takeFromStore) has \"${evt}\"`, content)\n store.delete(evt)\n return content\n }\n return false\n }\n throw new Error(`\"${storeName}\" is not supported!`)\n }\n\n /**\n * This was part of the $get. We take it out\n * so we could use a regex to remove more than one event\n * @param {object} store the store to return from\n * @param {string} evt event name\n * @param {boolean} full return just the callback or everything\n * @return {array|boolean} false when not found\n */\n findFromStore(evt, store, full = false) {\n if (store.has(evt)) {\n return Array\n .from(store.get(evt))\n .map( l => {\n if (full) {\n return l\n }\n let [key, callback, ] = l\n return callback\n })\n }\n return false\n }\n\n /**\n * Similar to the findFromStore, but remove\n * @param {string} evt event name\n * @param {object} store the store to remove from\n * @return {boolean} false when not found\n */\n removeFromStore(evt, store) {\n if (store.has(evt)) {\n this.logger('($off)', evt)\n store.delete(evt)\n return true\n }\n return false\n }\n\n /**\n * The add to store step is similar so make it generic for resuse\n * @param {object} store which store to use\n * @param {string} evt event name\n * @param {spread} args because the lazy store and normal store store different things\n * @return {array} store and the size of the store\n */\n addToStore(store, evt, ...args) {\n let fnSet\n if (store.has(evt)) {\n this.logger(`(addToStore) \"${evt}\" existed`)\n fnSet = store.get(evt)\n } else {\n this.logger(`(addToStore) create new Set for \"${evt}\"`)\n // this is new\n fnSet = new Set()\n }\n // lazy only store 2 items - this is not the case in V1.6.0 anymore\n // we need to check the first parameter is string or not\n if (args.length > 2) {\n if (Array.isArray(args[0])) { // lazy store\n // check if this type of this event already register in the lazy store\n let [,,t] = args\n if (!this.checkTypeInLazyStore(evt, t)) {\n fnSet.add(args)\n }\n } else {\n if (!this.checkContentExist(args, fnSet)) {\n this.logger(`(addToStore) insert new`, args)\n fnSet.add(args)\n }\n }\n } else { // add straight to lazy store\n fnSet.add(args)\n }\n store.set(evt, fnSet)\n return [store, fnSet.size]\n }\n\n /**\n * @param {array} args for compare\n * @param {object} fnSet A Set to search from\n * @return {boolean} true on exist\n */\n checkContentExist(args, fnSet) {\n let list = Array.from(fnSet)\n return !!list.filter(li => {\n let [hash,] = li\n return hash === args[0]\n }).length\n }\n\n /**\n * get the existing type to make sure no mix type add to the same store\n * @param {string} evtName event name\n * @param {string} type the type to check\n * @return {boolean} true you can add, false then you can't add this type\n */\n checkTypeInStore(evtName, type) {\n this.validateEvt(evtName, type)\n let all = this.$get(evtName, true)\n if (all === false) {\n // pristine it means you can add\n return true\n }\n // it should only have ONE type in ONE event store\n return !all.filter(list => {\n let [ ,,,t ] = list\n return type !== t\n }).length\n }\n\n /**\n * This is checking just the lazy store because the structure is different\n * therefore we need to use a new method to check it\n */\n checkTypeInLazyStore(evtName, type) {\n this.validateEvt(evtName, type)\n let store = this.lazyStore.get(evtName)\n this.logger('(checkTypeInLazyStore)', store)\n if (store) {\n return !!Array\n .from(store)\n .filter(li => {\n let [,,t] = li\n return t !== type\n }).length\n }\n return false\n }\n\n /**\n * wrapper to re-use the addToStore,\n * V1.3.0 add extra check to see if this type can add to this evt\n * @param {string} evt event name\n * @param {string} type on or once\n * @param {function} callback function\n * @param {object} context the context the function execute in or null\n * @return {number} size of the store\n */\n addToNormalStore(evt, type, callback, context = null) {\n this.logger(`(addToNormalStore) try to add \"${type}\" --> \"${evt}\" to normal store`)\n // @TODO we need to check the existing store for the type first!\n if (this.checkTypeInStore(evt, type)) {\n this.logger('(addToNormalStore)', `\"${type}\" --> \"${evt}\" can add to normal store`)\n let key = this.hashFnToKey(callback)\n let args = [this.normalStore, evt, key, callback, context, type]\n let [_store, size] = Reflect.apply(this.addToStore, this, args)\n this.normalStore = _store\n return size\n }\n return false\n }\n\n /**\n * Add to lazy store this get calls when the callback is not register yet\n * so we only get a payload object or even nothing\n * @param {string} evt event name\n * @param {array} payload of arguments or empty if there is none\n * @param {object} [context=null] the context the callback execute in\n * @param {string} [type=false] register a type so no other type can add to this evt\n * @return {number} size of the store\n */\n addToLazyStore(evt, payload = [], context = null, type = false) {\n // this is add in V1.6.0\n // when there is type then we will need to check if this already added in lazy store\n // and no other type can add to this lazy store\n let args = [this.lazyStore, evt, this.toArray(payload), context]\n if (type) {\n args.push(type)\n }\n let [_store, size] = Reflect.apply(this.addToStore, this, args)\n this.lazyStore = _store\n this.logger(`(addToLazyStore) size: ${size}`)\n return size\n }\n\n /**\n * make sure we store the argument correctly\n * @param {*} arg could be array\n * @return {array} make sured\n */\n toArray(arg) {\n return Array.isArray(arg) ? arg : [arg]\n }\n\n /**\n * setter to store the Set in private\n * @param {object} obj a Set\n */\n set normalStore(obj) {\n NB_EVENT_SERVICE_PRIVATE_STORE.set(this, obj)\n }\n\n /**\n * @return {object} Set object\n */\n get normalStore() {\n return NB_EVENT_SERVICE_PRIVATE_STORE.get(this)\n }\n\n /**\n * setter to store the Set in lazy store\n * @param {object} obj a Set\n */\n set lazyStore(obj) {\n NB_EVENT_SERVICE_PRIVATE_LAZY.set(this , obj)\n }\n\n /**\n * @return {object} the lazy store Set\n */\n get lazyStore() {\n return NB_EVENT_SERVICE_PRIVATE_LAZY.get(this)\n }\n\n /**\n * generate a hashKey to identify the function call\n * The build-in store some how could store the same values!\n * @param {function} fn the converted to string function\n * @return {string} hashKey\n */\n hashFnToKey(fn) {\n return hashCode2Str(fn.toString())\n }\n}\n","// The top level\nimport { TAKEN_BY_OTHER_TYPE_ERR } from './constants'\nimport StoreService from './store-service'\n// export\nexport default class EventService extends StoreService {\n /**\n * class constructor\n */\n constructor(config = {}) {\n super(config)\n }\n\n /**\n * logger function for overwrite\n */\n logger() {}\n\n // for id if the instance is this class\n get $name() {\n return 'to1source-event'\n }\n\n // take this down in the next release\n get is() {\n return this.$name\n }\n\n //////////////////////////\n // PUBLIC METHODS //\n //////////////////////////\n\n /**\n * Register your evt handler, note we don't check the type here,\n * we expect you to be sensible and know what you are doing.\n * @param {string} evt name of event\n * @param {function} callback bind method --> if it's array or not\n * @param {object} [context=null] to execute this call in\n * @return {number} the size of the store\n */\n $on(evt , callback , context = null) {\n const type = 'on'\n this.validate(evt, callback)\n // first need to check if this evt is in lazy store\n let lazyStoreContent = this.takeFromStore(evt)\n // this is normal register first then call later\n if (lazyStoreContent === false) {\n this.logger(`($on) \"${evt}\" is not in lazy store`)\n // @TODO we need to check if there was other listener to this\n // event and are they the same type then we could solve that\n // register the different type to the same event name\n return this.addToNormalStore(evt, type, callback, context)\n }\n this.logger(`($on) ${evt} found in lazy store`)\n // this is when they call $trigger before register this callback\n let size = 0\n lazyStoreContent.forEach(content => {\n let [ payload, ctx, t ] = content\n if (t && t !== type) {\n throw new Error(`${TAKEN_BY_OTHER_TYPE_ERR} ${t}`)\n }\n this.logger(`($on)`, `call run \"${evt}\"`)\n this.run(callback, payload, context || ctx)\n size += this.addToNormalStore(evt, type, callback, context || ctx)\n })\n\n this.logger(`($on) return size ${size}`)\n return size\n }\n\n /**\n * once only registered it once, there is no overwrite option here\n * @NOTE change in v1.3.0 $once can add multiple listeners\n * but once the event fired, it will remove this event (see $only)\n * @param {string} evt name\n * @param {function} callback to execute\n * @param {object} [context=null] the handler execute in\n * @return {boolean} result\n */\n $once(evt , callback , context = null) {\n this.validate(evt, callback)\n const type = 'once'\n let lazyStoreContent = this.takeFromStore(evt)\n // this is normal register before call $trigger\n let nStore = this.normalStore;\n if (lazyStoreContent === false) {\n this.logger(`($once) \"${evt}\" is not in the lazy store`)\n // v1.3.0 $once now allow to add multiple listeners\n return this.addToNormalStore(evt, type, callback, context)\n } else {\n // now this is the tricky bit\n // there is a potential bug here that cause by the developer\n // if they call $trigger first, the lazy won't know it's a once call\n // so if in the middle they register any call with the same evt name\n // then this $once call will be fucked - add this to the documentation\n this.logger('($once)', lazyStoreContent)\n const list = Array.from(lazyStoreContent)\n // should never have more than 1\n const [ payload, ctx, t ] = list[0]\n if (t && t !== type) {\n throw new Error(`${TAKEN_BY_OTHER_TYPE_ERR} ${t}`)\n }\n this.logger('($once)', `call run \"${evt}\"`)\n this.run(callback, payload, context || ctx)\n // remove this evt from store\n this.$off(evt)\n }\n }\n\n /**\n * This one event can only bind one callbackback\n * @param {string} evt event name\n * @param {function} callback event handler\n * @param {object} [context=null] the context the event handler execute in\n * @return {boolean} true bind for first time, false already existed\n */\n $only(evt, callback, context = null) {\n this.validate(evt, callback)\n const type = 'only'\n let added = false\n let lazyStoreContent = this.takeFromStore(evt)\n // this is normal register before call $trigger\n let nStore = this.normalStore\n if (!nStore.has(evt)) {\n this.logger(`($only) \"${evt}\" add to normalStore`)\n added = this.addToNormalStore(evt, type, callback, context)\n }\n if (lazyStoreContent !== false) {\n // there are data store in lazy store\n this.logger(`($only) \"${evt}\" found data in lazy store to execute`)\n const list = Array.from(lazyStoreContent)\n // $only allow to trigger this multiple time on the single handler\n list.forEach( li => {\n const [ payload, ctx, t ] = li\n if (t && t !== type) {\n throw new Error(`${TAKEN_BY_OTHER_TYPE_ERR} ${t}`)\n }\n this.logger(`($only) call run \"${evt}\"`)\n this.run(callback, payload, context || ctx)\n })\n }\n return added\n }\n\n /**\n * $only + $once this is because I found a very subtile bug when we pass a\n * resolver, rejecter - and it never fire because that's OLD added in v1.4.0\n * @param {string} evt event name\n * @param {function} callback to call later\n * @param {object} [context=null] exeucte context\n * @return {void}\n */\n $onlyOnce(evt, callback, context = null) {\n this.validate(evt, callback)\n const type = 'onlyOnce'\n let added = false\n let lazyStoreContent = this.takeFromStore(evt)\n // this is normal register before call $trigger\n let nStore = this.normalStore;\n if (!nStore.has(evt)) {\n this.logger(`($onlyOnce) \"${evt}\" add to normalStore`)\n added = this.addToNormalStore(evt, type, callback, context)\n }\n if (lazyStoreContent !== false) {\n // there are data store in lazy store\n this.logger('($onlyOnce)', lazyStoreContent)\n const list = Array.from(lazyStoreContent)\n // should never have more than 1\n const [ payload, ctx, t ] = list[0]\n if (t && t !== 'onlyOnce') {\n throw new Error(`${TAKEN_BY_OTHER_TYPE_ERR} ${t}`)\n }\n this.logger(`($onlyOnce) call run \"${evt}\"`)\n this.run(callback, payload, context || ctx)\n // remove this evt from store\n this.$off(evt)\n }\n return added\n }\n\n /**\n * This is a shorthand of $off + $on added in V1.5.0\n * @param {string} evt event name\n * @param {function} callback to exeucte\n * @param {object} [context = null] or pass a string as type\n * @param {string} [type=on] what type of method to replace\n * @return {*}\n */\n $replace(evt, callback, context = null, type = 'on') {\n if (this.validateType(type)) {\n this.$off(evt)\n let method = this['$' + type]\n this.logger(`($replace)`, evt, callback)\n return Reflect.apply(method, this, [evt, callback, context])\n }\n throw new Error(`${type} is not supported!`)\n }\n\n /**\n * trigger the event\n * @param {string} evt name NOT allow array anymore!\n * @param {mixed} [payload = []] pass to fn\n * @param {object|string} [context = null] overwrite what stored\n * @param {string} [type=false] if pass this then we need to add type to store too\n * @return {number} if it has been execute how many times\n */\n $trigger(evt , payload = [] , context = null, type = false) {\n this.validateEvt(evt)\n let found = 0\n // first check the normal store\n let nStore = this.normalStore\n this.logger('($trigger) normalStore', nStore)\n if (nStore.has(evt)) {\n this.logger(`($trigger) \"${evt}\" found`)\n // @1.8.0 to add the suspend queue\n let added = this.$queue(evt, payload, context, type)\n if (added) {\n this.logger(`($trigger) Currently suspended \"${evt}\" added to queue, nothing executed. Exit now.`)\n return false // not executed\n }\n let nSet = Array.from(nStore.get(evt))\n let ctn = nSet.length\n let hasOnce = false\n let hasOnly = false\n for (let i=0; i < ctn; ++i) {\n ++found;\n // this.logger('found', found)\n let [ _, callback, ctx, type ] = nSet[i]\n this.logger(`($trigger) call run for ${evt}`)\n this.run(callback, payload, context || ctx)\n if (type === 'once' || type === 'onlyOnce') {\n hasOnce = true;\n }\n }\n if (hasOnce) {\n nStore.delete(evt)\n }\n return found\n }\n // now this is not register yet\n this.addToLazyStore(evt, payload, context, type)\n return found\n }\n\n /**\n * this is an alias to the $trigger\n * @NOTE breaking change in V1.6.0 we swap the parameter aroun\n * @NOTE breaking change: v1.9.1 it return an function to accept the params as spread\n * @param {string} evt event name\n * @param {string} type of call\n * @param {object} context what context callback execute in\n * @return {*} from $trigger\n */\n $call(evt, type = false, context = null) {\n const ctx = this\n\n return (...args) => {\n let _args = [evt, args, context, type]\n return Reflect.apply(ctx.$trigger, ctx, _args)\n }\n }\n\n /**\n * remove the evt from all the stores\n * @param {string} evt name\n * @return {boolean} true actually delete something\n */\n $off(evt) {\n // @TODO we will allow a regex pattern to mass remove event\n this.validateEvt(evt)\n let stores = [ this.lazyStore, this.normalStore ]\n\n return !!stores\n .filter(store => store.has(evt))\n .map(store => this.removeFromStore(evt, store))\n .length\n }\n\n /**\n * return all the listener bind to that event name\n * @param {string} evtName event name\n * @param {boolean} [full=false] if true then return the entire content\n * @return {array|boolean} listerner(s) or false when not found\n */\n $get(evt, full = false) {\n // @TODO should we allow the same Regex to search for all?\n this.validateEvt(evt)\n let store = this.normalStore\n return this.findFromStore(evt, store, full)\n }\n\n /**\n * store the return result from the run\n * @param {*} value whatever return from callback\n */\n set $done(value) {\n this.logger('($done) set value: ', value)\n if (this.keep) {\n this.result.push(value)\n } else {\n this.result = value\n }\n }\n\n /**\n * @TODO is there any real use with the keep prop?\n * getter for $done\n * @return {*} whatever last store result\n */\n get $done() {\n this.logger('($done) get result:', this.result)\n if (this.keep) {\n return this.result[this.result.length - 1]\n }\n return this.result\n }\n\n /**\n * Take a look inside the stores\n * @param {number|null} idx of the store, null means all\n * @return {void}\n */\n $debug(idx = null) {\n let names = ['lazyStore', 'normalStore']\n let stores = [this.lazyStore, this.normalStore]\n if (stores[idx]) {\n this.logger(names[idx], stores[idx])\n } else {\n stores.map((store, i) => {\n this.logger(names[i], store)\n })\n }\n }\n}\n","// default\nimport To1sourceEvent from './src/event-service'\n\nexport default To1sourceEvent\n","// this will generate a event emitter and will be use everywhere\nimport EventEmitterClass from '@to1source/event'\n// create a clone version so we know which one we actually is using\nclass JsonqlWsEvt extends EventEmitterClass {\n\n constructor(logger) {\n if (typeof logger !== 'function') {\n throw new Error(`Just die here the logger is not a function!`)\n }\n logger(`---> Create a new EventEmitter <---`)\n // this ee will always come with the logger\n // because we should take the ee from the configuration\n super({ logger })\n }\n\n get name() {\n return'jsonql-ws-client-core'\n }\n}\n\n/**\n * getting the event emitter\n * @param {object} opts configuration\n * @return {object} the event emitter instance\n */\nconst getEventEmitter = opts => {\n const { log, eventEmitter } = opts\n \n if (eventEmitter) {\n log(`eventEmitter is:`, eventEmitter.name)\n return eventEmitter\n }\n \n return new JsonqlWsEvt( opts.log )\n}\n\nexport { \n getEventEmitter, \n EventEmitterClass // for other module to build from \n}\n","// group all the small functions here\nimport { EMIT_REPLY_TYPE } from 'jsonql-constants'\nimport { toArray, createEvt } from 'jsonql-utils/src/generic'\nimport JsonqlValidationError from 'jsonql-errors/src/validation-error'\n\n\n/**\n * WebSocket is strict about the path, therefore we need to make sure before it goes in\n * @param {string} url input url\n * @return {string} url with correct path name\n */\nexport const fixWss = url => {\n const uri = url.toLowerCase()\n if (uri.indexOf('http') > -1) {\n if (uri.indexOf('https') > -1) {\n return uri.replace('https', 'wss')\n }\n return uri.replace('http', 'ws')\n }\n return uri\n}\n\n\n/**\n * get a stock host name from browser\n */\nexport const getHostName = () => {\n try {\n return [window.location.protocol, window.location.host].join('//')\n } catch(e) {\n throw new JsonqlValidationError(e)\n }\n}\n\n/**\n * Unbind the event\n * @param {object} ee EventEmitter\n * @param {string} namespace\n * @return {void}\n */\nexport const clearMainEmitEvt = (ee, namespace) => {\n let nsps = toArray(namespace)\n nsps.forEach(n => {\n ee.$off(createEvt(n, EMIT_REPLY_TYPE))\n })\n}\n\n\n","// take out from the resolver-methods\nimport {\n LOGIN_EVENT_NAME,\n LOGOUT_EVENT_NAME,\n ON_LOGIN_FN_NAME\n} from 'jsonql-constants'\nimport { JsonqlValidationError } from 'jsonql-errors'\nimport { injectToFn, chainFns, isString, objDefineProps, isFunc } from '../utils'\n\n\n/**\n * @TODO this is now become unnecessary because the login is a slave to the\n * http-client - but keep this for now and see what we want to do with it later\n * @UPDATE it might be better if we decoup the two http-client only emit a login event\n * Here should catch it and reload the ws client @TBC\n * break out from createAuthMethods to allow chaining call\n * @param {object} obj the main client object\n * @param {object} opts configuration\n * @param {object} ee event emitter\n * @return {array} [ obj, opts, ee ] what comes in what goes out\n */\nconst setupLoginHandler = (obj, opts, ee) => [\n injectToFn(obj, opts.loginHandlerName, function loginHandler(token) {\n if (token && isString(token)) {\n opts.log(`Received ${LOGIN_EVENT_NAME} with ${token}`)\n // @TODO add the interceptor hook\n return ee.$trigger(LOGIN_EVENT_NAME, [token])\n }\n // should trigger a global error instead @TODO\n throw new JsonqlValidationError(opts.loginHandlerName, `Unexpected token ${token}`)\n }),\n opts,\n ee\n]\n\n\n/**\n * break out from createAuthMethods to allow chaining call - final in chain\n * @param {object} obj the main client object\n * @param {object} opts configuration\n * @param {object} ee event emitter\n * @return {array} [ obj, opts, ee ] what comes in what goes out\n */\nconst setupLogoutHandler = (obj, opts, ee) => [\n injectToFn(obj, opts.logoutHandlerName, function logoutHandler(...args) {\n ee.$trigger(LOGOUT_EVENT_NAME, args)\n }),\n opts,\n ee\n]\n\n\n/**\n * This event will fire when the socket.io.on('connection') and ws.onopen\n * Plus this will check if it's the private namespace that fired the event\n * @param {object} obj the client itself\n * @param {object} ee Event Emitter\n * @return {array} [ obj, opts, ee] what comes in what goes out\n */\nconst setupOnLoginhandler = (obj, opts, ee) => [\n objDefineProps(obj, ON_LOGIN_FN_NAME, function onLoginCallbackHandler(onLoginCallback) {\n if (isFunc(onLoginCallback)) {\n // only one callback can registered with it, TBC\n ee.$only(ON_LOGIN_FN_NAME, onLoginCallback)\n }\n }),\n opts,\n ee\n]\n\n// @TODO future feature setup switch user\n\n\n/**\n * Create auth related methods\n * @param {object} obj the client itself\n * @param {object} opts configuration\n * @param {object} ee Event Emitter\n * @return {array} [ obj, opts, ee ] what comes in what goes out\n */\nexport function setupAuthMethods(obj, opts, ee) {\n return chainFns(\n setupLoginHandler,\n setupLogoutHandler,\n setupOnLoginhandler\n )(obj, opts, ee)\n}\n","// constants\n\nimport {\n EMIT_REPLY_TYPE,\n JS_WS_SOCKET_IO_NAME,\n JS_WS_NAME,\n ON_MESSAGE_FN_NAME,\n ON_RESULT_FN_NAME\n} from 'jsonql-constants'\n\nconst SOCKET_IO = JS_WS_SOCKET_IO_NAME\nconst WS = JS_WS_NAME\n\nconst AVAILABLE_SERVERS = [SOCKET_IO, WS]\n\nconst SOCKET_NOT_DEFINE_ERR = 'socket is not define in the contract file!'\n\nconst SERVER_NOT_SUPPORT_ERR = 'is not supported server name!'\n\nconst MISSING_PROP_ERR = 'Missing property in contract!'\n\nconst UNKNOWN_CLIENT_ERR = 'Unknown client type!'\n\nconst EMIT_EVT = EMIT_REPLY_TYPE\n\nconst NAMESPACE_KEY = 'namespaceMap'\n\nconst UNKNOWN_RESULT = 'UKNNOWN RESULT!'\n\nconst NOT_ALLOW_OP = 'This operation is not allow!'\n\nconst MY_NAMESPACE = 'myNamespace'\n\nconst CB_FN_NAME = 'on'\n// this is a socket only (for now) feature so we just put it here \nconst DISCONNECTED_ERROR_MSG = `You have disconnected from the socket server, please reconnect.`\n\nexport {\n SOCKET_IO,\n WS,\n AVAILABLE_SERVERS,\n SOCKET_NOT_DEFINE_ERR,\n SERVER_NOT_SUPPORT_ERR,\n MISSING_PROP_ERR,\n UNKNOWN_CLIENT_ERR,\n EMIT_EVT,\n ON_MESSAGE_FN_NAME,\n ON_RESULT_FN_NAME,\n NAMESPACE_KEY,\n UNKNOWN_RESULT,\n NOT_ALLOW_OP,\n MY_NAMESPACE,\n CB_FN_NAME,\n DISCONNECTED_ERROR_MSG\n}\n","// breaking it up further to share between methods\nimport { DATA_KEY, ERROR_KEY } from 'jsonql-constants'\nimport { UNKNOWN_RESULT } from '../options/constants'\nimport { isObjectHasKey } from '../utils'\n\n/**\n * break out to use in different places to handle the return from server\n * @param {object} data from server\n * @param {function} resolver NOT from promise\n * @param {function} rejecter NOT from promise\n * @return {void} nothing\n */\nexport function respondHandler(data, resolver, rejecter) {\n if (isObjectHasKey(data, ERROR_KEY)) {\n // debugFn('-- rejecter called --', data[ERROR_KEY])\n rejecter(data[ERROR_KEY])\n } else if (isObjectHasKey(data, DATA_KEY)) {\n // debugFn('-- resolver called --', data[DATA_KEY])\n resolver(data[DATA_KEY])\n } else {\n // debugFn('-- UNKNOWN_RESULT --', data)\n rejecter({message: UNKNOWN_RESULT, error: data})\n }\n}\n","// the actual trigger call method\nimport { ON_RESULT_FN_NAME, EMIT_REPLY_TYPE } from 'jsonql-constants'\nimport { createEvt, toArray } from '../utils'\nimport { respondHandler } from './respond-handler'\n\n/**\n * just wrapper\n * @param {object} ee EventEmitter\n * @param {string} namespace where this belongs\n * @param {string} resolverName resolver\n * @param {array} args arguments\n * @param {function} log function \n * @return {void} nothing\n */\nexport function actionCall(ee, namespace, resolverName, args = [], log) {\n // reply event \n const outEventName = createEvt(namespace, EMIT_REPLY_TYPE)\n\n log(`actionCall: ${outEventName} --> ${resolverName}`, args)\n // This is the out going call \n ee.$trigger(outEventName, [resolverName, toArray(args)])\n \n // then we need to listen to the event callback here as well\n return new Promise((resolver, rejecter) => {\n const inEventName = createEvt(namespace, resolverName, ON_RESULT_FN_NAME)\n // this cause the onResult got the result back first \n // and it should be the promise resolve first\n // @TODO we need to rewrote the respondHandler to change the problem stated above \n ee.$on(\n inEventName,\n function actionCallResultHandler(result) {\n log(`got the first result`, result)\n respondHandler(result, resolver, rejecter)\n }\n )\n })\n}\n","// setting up the send method \nimport { JsonqlValidationError } from 'jsonql-errors'\nimport {\n ON_ERROR_FN_NAME,\n SEND_MSG_FN_NAME\n} from 'jsonql-constants'\nimport { validateAsync } from 'jsonql-params-validator'\nimport { objDefineProps, createEvt, toArray, nil } from '../utils'\nimport { actionCall } from './action-call'\n\n/** \n * pairing with the server vesrion SEND_MSG_FN_NAME\n * last of the chain so only return the resolver (fn)\n * This is now change to a getter / setter method \n * and call like this: resolver.send(...args)\n * @param {function} fn the resolver function \n * @param {object} ee event emitter instance \n * @param {string} namespace the namespace it belongs to \n * @param {string} resolverName name of the resolver \n * @param {object} params from contract \n * @param {function} log a logger function\n * @return {function} return the resolver itself \n */ \nexport const setupSendMethod = (fn, ee, namespace, resolverName, params, log) => (\n objDefineProps(\n fn, \n SEND_MSG_FN_NAME, \n nil, \n function sendHandler() {\n // let _log = (...args) => Reflect.apply(console.info, console, ['[SEND]'].concat(args))\n /** \n * This will follow the same pattern like the resolver \n * @param {array} args list of unknown argument follow the resolver \n * @return {promise} resolve the result \n */\n return function sendCallback(...args) {\n return validateAsync(args, params.params, true)\n .then(_args => {\n // @TODO check the result \n // because the validation could failed with the list of fail properties \n log(namespace, resolverName, _args)\n return actionCall(ee, namespace, resolverName, _args, _log)\n })\n .catch(err => {\n // @TODO it shouldn't be just a validation error \n // it could be server return error, so we need to check \n // what error we got back here first \n log('send error', err)\n // @TODO it might not an validation error need the finalCatch here\n ee.$call(\n createEvt(namespace, resolverName, ON_ERROR_FN_NAME),\n [new JsonqlValidationError(resolverName, err)]\n )\n })\n } \n })\n)\n","// break up the original setup resolver method here\n// import { JsonqlValidationError, finalCatch } from 'jsonql-errors'\nimport {\n ON_ERROR_FN_NAME,\n ON_MESSAGE_FN_NAME,\n ON_RESULT_FN_NAME\n} from 'jsonql-constants'\n// local \nimport { MY_NAMESPACE } from '../options/constants'\nimport { chainFns, objDefineProps, injectToFn, createEvt, isFunc } from '../utils'\nimport { respondHandler } from './respond-handler'\nimport { setupSendMethod } from './setup-send-method'\n\n/**\n * The first one in the chain, just setup a namespace prop\n * the rest are passing through\n * @param {function} fn the resolver function\n * @param {object} ee the event emitter \n * @param {string} resolverName what it said\n * @param {object} params for resolver from contract\n * @param {function} log the logger function\n * @return {array}\n */\nconst setupNamespace = (fn, ee, namespace, resolverName, params, log) => [\n injectToFn(fn, MY_NAMESPACE, namespace),\n ee,\n namespace,\n resolverName,\n params,\n log \n]\n\n/** \n * onResult handler\n */ \nconst setupOnResult = (fn, ee, namespace, resolverName, params, log) => [\n objDefineProps(fn, ON_RESULT_FN_NAME, function(resultCallback) {\n if (isFunc(resultCallback)) {\n ee.$on(\n createEvt(namespace, resolverName, ON_RESULT_FN_NAME),\n function resultHandler(result) {\n respondHandler(result, resultCallback, (error) => {\n log(`Catch error: \"${resolverName}\"`, error)\n ee.$trigger(\n createEvt(namespace, resolverName, ON_ERROR_FN_NAME), \n error\n )\n })\n }\n )\n }\n }),\n ee,\n namespace,\n resolverName,\n params,\n log\n]\n\n/** \n * we do need to add the send prop back because it's the only way to deal with\n * bi-directional data stream \n */\nconst setupOnMessage = (fn, ee, namespace, resolverName, params, log) => [\n objDefineProps(fn, ON_MESSAGE_FN_NAME, function(messageCallback) {\n // we expect this to be a function\n if (isFunc(messageCallback)) {\n // did that add to the callback\n let onMessageCallback = (args) => {\n respondHandler(args, messageCallback, (error) => {\n log(`Catch error: \"${resolverName}\"`, error)\n ee.$trigger(\n createEvt(namespace, resolverName, ON_ERROR_FN_NAME), \n error\n )\n })\n }\n // register the handler for this message event\n ee.$only(\n createEvt(namespace, resolverName, ON_MESSAGE_FN_NAME), \n onMessageCallback\n )\n }\n }),\n ee,\n namespace,\n resolverName,\n params,\n log\n]\n\n/** \n * ON_ERROR_FN_NAME handler\n */\nconst setupOnError = (fn, ee, namespace, resolverName, params, log) => [\n objDefineProps(fn, ON_ERROR_FN_NAME, function(resolverErrorHandler) {\n if (isFunc(resolverErrorHandler)) {\n // please note ON_ERROR_FN_NAME can add multiple listners\n ee.$only(\n createEvt(namespace, resolverName, ON_ERROR_FN_NAME), \n resolverErrorHandler\n )\n }\n }),\n ee,\n namespace,\n resolverName,\n params,\n log\n]\n\n/**\n * Add extra property / listeners to the resolver\n * @param {string} namespace where this belongs\n * @param {string} resolverName name as event name\n * @param {object} params from contract\n * @param {function} fn resolver function\n * @param {object} ee EventEmitter\n * @param {function} log function \n * @return {function} resolver\n */\nexport function setupResolver(namespace, resolverName, params, fn, ee, log) {\n let fns = [\n setupNamespace, \n setupOnResult, \n setupOnMessage, \n setupOnError, \n setupSendMethod\n ]\n \n // get the executor\n const executor = Reflect.apply(chainFns, null, fns)\n const args = [fn, ee, namespace, resolverName, params, log]\n\n return Reflect.apply(executor, null, args)\n}\n","// put all the resolver related methods here to make it more clear\n\n// this will be a mini client server architect\n// The reason is when the enableAuth setup - the private route\n// might not be validated, but we need the callable point is ready\n// therefore this part will always take the contract and generate\n// callable api for the developer to setup their front end\n// the only thing is - when they call they might get an error or\n// NOT_LOGIN_IN and they can react to this error accordingly\nimport { finalCatch } from 'jsonql-errors'\nimport { validateAsync } from 'jsonql-params-validator'\nimport { setupResolver } from './setup-resolver'\nimport { actionCall } from './action-call'\nimport {\n createEvt,\n objDefineProps,\n isFunc,\n injectToFn\n} from '../utils'\nimport {\n ON_ERROR_FN_NAME,\n ON_READY_FN_NAME\n} from 'jsonql-constants'\n\n/**\n * create the actual function to send message to server\n * @param {object} ee EventEmitter instance\n * @param {string} namespace this resolver end point\n * @param {string} resolverName name of resolver as event name\n * @param {object} params from contract\n * @param {function} log pass the log function\n * @return {function} resolver\n */\nfunction createResolver(ee, namespace, resolverName, params, log) {\n // note we pass the new withResult=true option\n return function resolver(...args) {\n return validateAsync(args, params.params, true)\n .then(_args => actionCall(ee, namespace, resolverName, _args, log))\n .catch(finalCatch)\n }\n}\n\n/**\n * step one get the clientmap with the namespace\n * @param {object} opts configuration\n * @param {object} ee EventEmitter\n * @param {object} nspGroup resolvers index by their namespace\n * @return {promise} resolve the clientmapped, and start the chain\n */\nexport function generateResolvers(opts, ee, nspGroup) {\n let client= {}\n let { log } = opts\n\n for (let namespace in nspGroup) {\n let list = nspGroup[namespace]\n for (let resolverName in list) {\n // resolverNames.push(resolverName)\n let params = list[resolverName]\n let fn = createResolver(ee, namespace, resolverName, params, log)\n // this should set as a getter therefore can not be overwrite by accident\n // obj[resolverName] = setupResolver(namespace, resolverName, params, fn, ee)\n client = injectToFn(\n client,\n resolverName,\n setupResolver(namespace, resolverName, params, fn, ee, log)\n )\n }\n }\n // resolve the clientto start the chain\n // chain the result to allow the chain processing\n return [ client, opts, ee, nspGroup ]\n}\n\n/**\n * The problem is the namespace can have more than one\n * and we only have on onError message\n * @param {object} clientthe client itself\n * @param {object} opts configuration\n * @param {object} ee Event Emitter\n * @param {object} nspGroup namespace keys\n * @return {array} [obj, opts, ee]\n */\nexport function setupNamespaceErrorListener(client, opts, ee, nspGroup) {\n return [\n objDefineProps(\n client,\n ON_ERROR_FN_NAME,\n function namespaceErrorCallbackHandler(namespaceErrorHandler) {\n if (isFunc(namespaceErrorHandler)) {\n // please note ON_ERROR_FN_NAME can add multiple listners\n for (let namespace in nspGroup) {\n // this one is very tricky, we need to make sure the trigger is calling\n // with the namespace as well as the error\n ee.$on(createEvt(namespace, ON_ERROR_FN_NAME), namespaceErrorHandler)\n }\n }\n }\n ),\n opts,\n ee\n ]\n}\n\n/**\n * This event will fire when the socket.io.on('connection') and ws.onopen\n * @param {object} client client itself\n * @param {object} opts configuration\n * @param {object} ee Event Emitter\n * @return {array} [ obj, opts, ee ]\n */\nexport function setupOnReadyListener(client, opts, ee) {\n return [\n objDefineProps(\n client,\n ON_READY_FN_NAME,\n function onReadyCallbackHandler(onReadyCallback) {\n if (isFunc(onReadyCallback)) {\n // reduce it down to just one flat level\n // @2020-03-19 only allow ONE onReady callback otherwise\n // it will get fire multiple times which is not what we want\n ee.$only(ON_READY_FN_NAME, onReadyCallback)\n }\n }\n ),\n opts,\n ee\n ]\n}\n","// resolvers generator\n// we change the interface to return promise from v1.0.3\n// this way we make sure the obj return is correct and timely\nimport { chainFns } from '../utils'\nimport { setupAuthMethods } from './setup-auth-methods'\nimport {\n generateResolvers,\n setupOnReadyListener,\n setupNamespaceErrorListener\n} from './generator-methods'\n\nimport {\n NSP_GROUP\n} from 'jsonql-constants'\n\n/**\n * prepare the methods\n * @param {object} opts configuration\n * @param {object} nspMap resolvers index by their namespace\n * @param {object} ee EventEmitter\n * @return {object} of resolvers\n * @public\n */\nexport function callersGenerator(opts, nspMap, ee) {\n let fns = [\n generateResolvers,\n setupOnReadyListener,\n setupNamespaceErrorListener\n ]\n if (opts.enableAuth) {\n fns.push(setupAuthMethods)\n }\n // we will always get back the [ obj, opts, ee ]\n // then we only return the obj (wsClient)\n // This has move outside of here, into the main method\n // the reason is we could switch around the sequence much easier\n // fns.push(setupFinalStep)\n // run it\n const generator = Reflect.apply(chainFns, null, fns)\n\n return generator(opts, ee, nspMap[NSP_GROUP])\n}\n","// this is a new method that will create several\n// intercom method also reverse listen to the server\n// such as disconnect (server issue disconnect)\nimport { injectToFn } from '../utils'\nimport { DISCONNECT_EVENT_NAME } from 'jsonql-constants'\n\n/**\n * this is the new method that setup the intercom handler\n * also this serve as the final call in the then chain to\n * output the client\n * @param {object} client the client\n * @param {object} opts configuration\n * @param {object} ee the event emitter\n * @return {object} client\n */\nexport function setupInterCom(client, opts, ee) {\n const { disconnectHandlerName } = opts\n\n return injectToFn(\n client,\n disconnectHandlerName,\n function disconnectHandler(...args) {\n ee.$trigger(DISCONNECT_EVENT_NAME, args)\n }\n )\n}\n","// The final step of the setup before it returns the client\nimport { setupInterCom } from './setup-intercom'\n\n/**\n * The final step to return the client\n * @param {object} obj the client\n * @param {object} opts configuration\n * @param {object} ee the event emitter\n * @return {object} client\n */\nfunction setupFinalStep(obj, opts, ee) {\n\n const client = setupInterCom(obj, opts, ee)\n\n opts.log(`---> The final step to return the ws-client <---`)\n // add some debug functions\n client.verifyEventEmitter = () => ee.is\n // we add back the two things into the client\n // then when we do integration, we run it in reverse,\n // create the ws client first then the host client\n client.eventEmitter = opts.eventEmitter\n client.log = opts.log\n // we just inject a helloWorld method here\n // client[HELLO_FN] =\n\n return client\n}\n\n\nexport { setupFinalStep }\n","// create options\nimport {\n checkConfigAsync,\n checkConfig\n} from 'jsonql-params-validator'\nimport {\n wsCoreCheckMap,\n wsCoreConstProps,\n socketCheckMap\n} from './defaults'\nimport {\n fixWss,\n getHostName,\n getEventEmitter,\n getNspInfoByConfig,\n getLogFn\n} from '../utils'\n\n/**\n * We need this to find the socket server type\n * @param {*} config\n * @return {string} the name of the socket server if any\n */\nfunction checkSocketClientType(config) {\n return checkConfig(config, socketCheckMap)\n}\n\n/**\n * Create a combine checkConfig for the creating the combine client\n * @param {*} configCheckMap\n * @param {*} constProps\n * @return {function} takes the user input config then resolve the configuration\n */\nfunction createCombineConfigCheck(configCheckMap, constProps) {\n const combineCheckMap = Object.assign({}, configCheckMap, wsCoreCheckMap)\n const combineConstProps = Object.assign({}, constProps, wsCoreConstProps)\n return config => checkConfigAsync(config, combineCheckMap, combineConstProps)\n}\n\n\n/**\n * wrapper method to check this already did the pre check\n * @param {object} config user supply config\n * @param {object} defaultOptions for checking\n * @param {object} constProps user supply const props\n * @return {promise} resolve to the checked opitons\n */\nfunction checkConfiguration(config, defaultOptions, constProps) {\n const defaultCheckMap= Object.assign(wsCoreCheckMap, defaultOptions)\n const wsConstProps = Object.assign(wsCoreConstProps, constProps)\n\n return checkConfigAsync(config, defaultCheckMap, wsConstProps)\n}\n\n/**\n * Taking the `then` part from the method below\n * @param {object} opts\n * @return {promise} opts all done\n */\nfunction postCheckInjectOpts(opts) {\n return Promise.resolve(opts)\n .then(opts => {\n if (!opts.hostname) {\n opts.hostname = getHostName()\n }\n // @TODO the contract now will supply the namespace information\n // and we need to use that to group the namespace call\n opts.wssPath = fixWss([opts.hostname, opts.namespace].join('/'), opts.serverType)\n // get the log function here\n opts.log = getLogFn(opts)\n\n opts.eventEmitter = getEventEmitter(opts)\n\n return opts\n })\n}\n\n/**\n * Don't want to make things confusing\n * Breaking up the opts process in one place\n * then generate the necessary parameter in another step\n * @2020-3-20 here we suspend operation by it's namespace first\n * Then in the framework part, after the connection establish we release\n * the queue\n * @param {object} opts checked --> merge --> injected\n * @return {object} {opts, nspMap, ee}\n */\nfunction createRequiredParams(opts) {\n const nspMap = getNspInfoByConfig(opts)\n const ee = opts.eventEmitter\n // @TODO here we are going to add suspend event to the namespace related methods\n \n\n return { opts, nspMap, ee }\n}\n\nexport {\n // properties\n wsCoreCheckMap,\n wsCoreConstProps,\n // functions\n checkConfiguration,\n postCheckInjectOpts,\n createRequiredParams,\n // this will just get export for integration\n checkSocketClientType,\n createCombineConfigCheck\n}\n","// the top level API\n// The goal is to create a generic method that will able to handle\n// any kind of clients\n// import { injectToFn } from 'jsonql-utils'\nimport {\n callersGenerator,\n setupFinalStep\n} from './callers'\nimport {\n checkConfiguration,\n postCheckInjectOpts,\n createRequiredParams\n} from './options'\n\n\n/**\n * 0.5.0 we break up the wsClientCore in two parts one without the config check\n * @param {function} socketClientListener\n * @return {function} to actually generate the client\n */\nexport function wsClientCoreAction(socketClientListener) {\n /**\n * This is a breaking change, to continue the onion skin design\n * @param {object} config the already checked config\n * @return {promise} resolve the client\n */\n return (config = {}) => {\n\n return postCheckInjectOpts(config)\n // the following two moved to wsPostConfig\n .then(createRequiredParams)\n .then(\n ({opts, nspMap, ee}) => socketClientListener(opts, nspMap, ee)\n )\n .then( \n ({opts, nspMap, ee}) => callersGenerator(opts, nspMap, ee)\n )\n // because it returns as an array of params\n .then(result => Reflect.apply(setupFinalStep, null, result))\n .catch(err => {\n console.error(`jsonql-ws-core-client init error`, err)\n })\n }\n}\n\n/**\n * The main interface which will generate the socket clients and map all events\n * @param {object} socketClientListerner this is the one method export by various clients\n * @param {object} [configCheckMap={}] we should do all the checking in the core instead of the client\n * @param {object} [constProps={}] add this to supply the constProps from the downstream client\n * @return {function} accept a config then return the wsClient instance with all the available API\n */\nexport function wsClientCore(socketClientListener, configCheckMap = {}, constProps = {}) {\n // we need to inject property to this client later\n return (config = {}) => checkConfiguration(config, configCheckMap, constProps)\n .then(\n wsClientCoreAction(socketClientListener)\n )\n}\n","// this is getting too confusing \n// therefore we move it back to the framework specific \n\n/**\n * wrapper method to create a nsp without login\n * @param {string|boolean} namespace namespace url could be false\n * @param {object} opts configuration\n * @return {object} ws client instance\n */\nfunction createNspClient(namespace, opts) {\n const { hostname, wssPath, wsOptions, nspClient, log } = opts\n const url = namespace ? [hostname, namespace].join('/') : wssPath\n log(`createNspClient --> `, url)\n\n return nspClient(url, wsOptions)\n}\n\n/**\n * wrapper method to create a nsp with token auth\n * @param {string} namespace namespace url\n * @param {object} opts configuration\n * @return {object} ws client instance\n */\nfunction createNspAuthClient(namespace, opts) {\n const { hostname, wssPath, token, wsOptions, nspAuthClient, log } = opts\n const url = namespace ? [hostname, namespace].join('/') : wssPath\n \n log(`createNspAuthClient -->`, url)\n\n if (token && typeof token !== 'string') {\n throw new Error(`Expect token to be string, but got ${token}`)\n }\n \n return nspAuthClient(url, token, wsOptions)\n}\n\nexport {\n createNspClient,\n createNspAuthClient\n}\n","// this use by client-event-handler\nimport { ON_ERROR_FN_NAME } from 'jsonql-constants'\nimport { createEvt } from '../utils'\n\n/**\n * trigger errors on all the namespace onError handler\n * @param {object} ee Event Emitter\n * @param {array} namespaces nsps string\n * @param {string} message optional\n * @return {void}\n */\nexport function triggerNamespacesOnError(ee, namespaces, message) {\n namespaces.forEach( namespace => {\n ee.$trigger(\n createEvt(namespace, ON_ERROR_FN_NAME), \n [{ message, namespace }]\n )\n })\n}\n\n/**\n * Handle the onerror callback \n * @param {object} ee event emitter \n * @param {string} namespace which namespace has error \n * @param {*} err error object\n * @return {void} \n */\nexport const handleNamespaceOnError = (ee, namespace, err) => {\n ee.$trigger(createEvt(namespace, ON_ERROR_FN_NAME), [err])\n}","// NOT IN USE AT THE MOMENT JUST KEEP IT HERE FOR THE TIME BEING \nimport {\n LOGOUT_EVENT_NAME,\n NOT_LOGIN_ERR_MSG,\n ON_ERROR_FN_NAME,\n ON_RESULT_FN_NAME,\n DISCONNECT_EVENT_NAME\n} from 'jsonql-constants'\nimport { EMIT_EVT, DISCONNECTED_ERROR_MSG } from '../options/constants'\nimport { createEvt, clearMainEmitEvt } from '../utils'\nimport { triggerNamespacesOnError } from './trigger-namespaces-on-error'\n\n/**\n * Only when there is a private namespace then we bind to this event\n * @param {object} nsps the available nsp(s)\n * @param {array} namespaces available namespace \n * @param {object} ee eventEmitter \n * @param {object} opts configuration\n * @return {void}\n */\nexport const logoutEvtListener = (nsps, namespaces, ee, opts) => {\n const { log } = opts \n // this will be available regardless enableAuth\n // because the server can log the client out\n ee.$on(\n LOGOUT_EVENT_NAME, \n function logoutEvtCallback() {\n const privateNamespace = getPrivateNamespace(namespaces)\n log(`${LOGOUT_EVENT_NAME} event triggered`)\n // disconnect(nsps, opts.serverType)\n // we need to issue error to all the namespace onError Listerner\n triggerNamespacesOnError(ee, [privateNamespace], LOGOUT_EVENT_NAME)\n // rebind all of the Listerner to the fake one\n log(`logout from ${privateNamespace}`)\n\n clearMainEmitEvt(ee, privateNamespace)\n // we need to issue one more call to the server before we disconnect\n // now this is a catch 22, here we are not suppose to do anything platform specific\n // so that should fire before trigger this event\n // clear out the nsp\n nsps[privateNamespace] = null \n // add a NOT LOGIN error if call\n notLoginWsListerner(privateNamespace, ee, opts)\n }\n )\n}\n\n/**\n * A Event Listerner placeholder when it's not connect to any nsp\n * @param {string} namespace nsp\n * @param {object} ee EventEmitter\n * @param {object} opts configuration\n * @return {void}\n */\nexport const notConnectedListener = (namespace, ee, opts) => {\n const { log } = opts \n\n ee.$only(\n createEvt(namespace, EMIT_EVT),\n function disconnectedEvtCallback(resolverName, args) {\n log(`[disconnectedListerner] hijack the ws call`, namespace, resolverName, args)\n const error = {\n message: DISCONNECTED_ERROR_MSG\n }\n ee.$call(createEvt(namespace, resolverName, ON_ERROR_FN_NAME), [ error ])\n // also trigger the result Listerner, but wrap inside the error key\n ee.$call(createEvt(namespace, resolverName, ON_RESULT_FN_NAME), [{ error }])\n }\n )\n}\n\n\n/**\n * The disconnect event Listerner, now we log the client out from everything\n * @TODO now we are another problem they disconnect, how to reconnect\n * @param {object} nsps the available nsp(s)\n * @param {array} namespaces available namespace \n * @param {object} ee eventEmitter \n * @param {object} opts configuration\n * @return {void}\n */\nexport const disconnectListener = (nsps, namespaces, ee, opts) => {\n const { log } = opts \n ee.$on(\n DISCONNECT_EVENT_NAME, \n function disconnectEvtCallback() {\n triggerNamespacesOnError(ee, namespaces, DISCONNECT_EVENT_NAME)\n namespaces.forEach( namespace => { \n log(`disconnect from ${namespace}`)\n\n clearMainEmitEvt(ee, namespace)\n nsps[namespace] = null \n disconnectedListerner(namespace, ee, opts)\n })\n }\n )\n}\n\n/**\n * A Event Listerner placeholder when it's not connect to the private nsp\n * @param {string} namespace nsp\n * @param {object} ee EventEmitter\n * @param {object} opts configuration\n * @return {void}\n */\nexport const notLoginListener = (namespace, ee, opts) => {\n const { log } = opts \n\n ee.$only(\n createEvt(namespace, EMIT_EVT),\n function notLoginListernerCallback(resolverName, args) {\n log('[notLoginListerner] hijack the ws call', namespace, resolverName, args)\n const error = { message: NOT_LOGIN_ERR_MSG }\n // It should just throw error here and should not call the result\n // because that's channel for handling normal event not the fake one\n ee.$call(createEvt(namespace, resolverName, ON_ERROR_FN_NAME), [ error ])\n // also trigger the result Listerner, but wrap inside the error key\n ee.$call(createEvt(namespace, resolverName, ON_RESULT_FN_NAME), [{ error }])\n }\n )\n}","// This is share between different clients so we export it\n// @TODO port what is in the ws-main-handler\n// because all the client side call are via the ee\n// and that makes it re-usable between different client setup\n\n/*\nInside the map call but we take it out for now and until the WebSocket version is fully working\nimport { SOCKET_IO } from '../options/constants'\n // @TODO need to double check this\n if (opts.serverType === SOCKET_IO) {\n let { nspGroup } = nspMap\n args.push(nspGroup[namespace])\n }\n*/\nimport { getPrivateNamespace } from 'jsonql-utils/src/namespace'\nimport { logoutEvtListener, notLoginListener } from './event-listeners'\n\n\n/**\n * centralize all the comm in one place\n * @param {function} bindSocketEventHandler binding the ee to ws --> this is the core bit\n * @param {object} nsps namespaced nsp\n * @return {void} nothing\n */\nexport function clientEventListener(bindSocketEventListener, nsps) {\n /**\n * BREAKING CHANGE instead of one flat structure\n * we return a function to accept the two \n * @param {object} opts configuration\n * @param {object} nspMap this is not in the opts \n * @param {object} ee Event Emitter instance\n * @return {array} although we return something but this is the last step and nothing to do further\n */\n return (opts, nspMap, ee) => {\n // since all these params already in the opts\n const { log } = opts\n const { namespaces } = nspMap\n // @1.1.3 add isPrivate prop to id which namespace is the private nsp\n // then we can use this prop to determine if we need to fire the ON_LOGIN_PROP_NAME event\n const privateNamespace = getPrivateNamespace(namespaces)\n \n return namespaces.map(namespace => {\n let isPrivate = privateNamespace === namespace\n log(namespace, ` --> ${isPrivate ? 'private': 'public'} nsp --> `, nsps[namespace] !== false)\n if (nsps[namespace]) {\n log('[call bindWsHandler]', isPrivate, namespace)\n\n let args = [namespace, nsps[namespace], ee, isPrivate, opts]\n // Finally we binding everything together\n Reflect.apply(bindSocketEventListener, null, args)\n\n } else {\n log(`binding notLoginWsHandler to ${namespace}`)\n // a dummy placeholder\n // @TODO but it should be a not connect handler \n // when it's not login (or fail) this should be handle differently \n notLoginListener(namespace, ee, opts)\n }\n if (isPrivate) {\n log(`Has private and add logoutEvtHandler`)\n logoutEvtListener(nsps, namespaces, ee, opts)\n }\n // just return something its not going to get use anywhere\n return isPrivate \n })\n }\n}\n","// jsonql-ws-core takes over the check configuration\n// here we only have to supply the options that is unique to this client\n// create options\nimport { JS_WS_NAME } from 'jsonql-constants'\n// constant props\nconst wsClientConstProps = {\n version: '__PLACEHOLDER__', // will get replace\n serverType: JS_WS_NAME\n}\n\nexport { wsClientConstProps }\n","// pass the different type of ws to generate the client\n// this is where the framework specific code get injected\nimport { TOKEN_PARAM_NAME } from 'jsonql-constants'\nimport { fixWss } from '../modules'\nimport {\n createInitPing, \n extractPingResult\n} from '../modules'\n\n/**\n * Group the ping and get respond create new client in one\n * @param {object} ws \n * @param {object} WebSocket \n * @param {string} url\n * @param {function} resolver \n * @param {function} rejecter \n * @param {boolean} auth client or not\n * @return {promise} resolve the confirm client\n */\nfunction initPingAction(ws, WebSocket, url, resolver, rejecter, wsOptions) {\n // @TODO how to we id this client can issue a CSRF\n // by origin? \n ws.onopen = function onOpenCallback() {\n ws.send(createInitPing())\n }\n\n ws.onmessage = function onMessageCallback(payload) {\n try {\n const header = extractPingResult(payload.data)\n // @NOTE the break down test in ws-client-core show no problems\n // the problem was cause by malform nspInfo that time? \n setTimeout(() => { // delay or not show no different but just on the safe side\n ws.terminate()\n }, 50)\n const newWs = new WebSocket(url, Object.assign(wsOptions, header)) \n resolver(newWs) \n } catch(e) {\n rejecter(e)\n }\n }\n\n ws.onerror = function onErrorCallback(err) {\n rejecter(err)\n }\n}\n\n/**\n * less duplicated code the better \n * @param {object} WebSocket \n * @param {string} url formatted url\n * @param {object} options or not\n * @return {promise} resolve the actual verified client\n */\nfunction asyncConnect(WebSocket, url, options) {\n \n return new Promise((resolver, rejecter) => { \n \n const unconfirmClient = new WebSocket(url, options)\n \n initPingAction(unconfirmClient, WebSocket, url, resolver, rejecter, options)\n })\n}\n\n\n/**\n * The bug was in the wsOptions where ws don't need it but socket.io do\n * therefore the object was pass as second parameter!\n * @NOTE here we only return a method to create the client, it might not get call \n * @param {object} WebSocket the client or node version of ws\n * @param {boolean} auth if it's auth then 3 param or just one\n * @param {object} opts this is a breaking change we will init the client twice\n */\nfunction initWebSocketClient(WebSocket, auth, log) {\n if (auth === false) {\n /**\n * Create a non-protected client\n * @param {string} url \n * @param {object} [wsOptions={}]\n * @return {promise} resolve to the confirmed client\n */\n return function createWsClient(url, wsOptions = {}) {\n const _url = fixWss(url)\n log(`nspClient: \\n${_url}\\n`, wsOptions)\n\n return asyncConnect(WebSocket, _url, wsOptions)\n }\n }\n\n /**\n * Create a client with auth token\n * @param {string} url start with ws:// @TODO check this?\n * @param {string} token the jwt token\n * @param {object} [wsOptions={}] extra options pass to the WebSocket object\n * @return {object} ws instance\n */\n return function createWsAuthClient(url, token, wsOptions = {}) {\n const ws_url = fixWss(url)\n // console.log('what happen here?', url, ws_url, token)\n const _url = token && typeof token === 'string' ? `${ws_url}?${TOKEN_PARAM_NAME}=${token}` : ws_url\n log(`nspAuthClient: \\n${_url}\\n`, wsOptions)\n\n return asyncConnect(WebSocket, _url, wsOptions)\n }\n}\n\nexport { initWebSocketClient }","/** Used for built-in method references. */\nvar objectProto = Object.prototype;\n\n/**\n * Used to resolve the\n * [`toStringTag`](http://ecma-international.org/ecma-262/7.0/#sec-object.prototype.tostring)\n * of values.\n */\nvar nativeObjectToString = objectProto.toString;\n\n/**\n * Converts `value` to a string using `Object.prototype.toString`.\n *\n * @private\n * @param {*} value The value to convert.\n * @returns {string} Returns the converted string.\n */\nfunction objectToString(value) {\n return nativeObjectToString.call(value);\n}\n\nexport default objectToString;\n","/**\n * Creates a unary function that invokes `func` with its argument transformed.\n *\n * @private\n * @param {Function} func The function to wrap.\n * @param {Function} transform The argument transform.\n * @returns {Function} Returns the new function.\n */\nfunction overArg(func, transform) {\n return function(arg) {\n return func(transform(arg));\n };\n}\n\nexport default overArg;\n","/**\n * Checks if `value` is object-like. A value is object-like if it's not `null`\n * and has a `typeof` result of \"object\".\n *\n * @static\n * @memberOf _\n * @since 4.0.0\n * @category Lang\n * @param {*} value The value to check.\n * @returns {boolean} Returns `true` if `value` is object-like, else `false`.\n * @example\n *\n * _.isObjectLike({});\n * // => true\n *\n * _.isObjectLike([1, 2, 3]);\n * // => true\n *\n * _.isObjectLike(_.noop);\n * // => false\n *\n * _.isObjectLike(null);\n * // => false\n */\nfunction isObjectLike(value) {\n return value != null && typeof value == 'object';\n}\n\nexport default isObjectLike;\n","/**\n * Removes all key-value entries from the list cache.\n *\n * @private\n * @name clear\n * @memberOf ListCache\n */\nfunction listCacheClear() {\n this.__data__ = [];\n this.size = 0;\n}\n\nexport default listCacheClear;\n","/**\n * Performs a\n * [`SameValueZero`](http://ecma-international.org/ecma-262/7.0/#sec-samevaluezero)\n * comparison between two values to determine if they are equivalent.\n *\n * @static\n * @memberOf _\n * @since 4.0.0\n * @category Lang\n * @param {*} value The value to compare.\n * @param {*} other The other value to compare.\n * @returns {boolean} Returns `true` if the values are equivalent, else `false`.\n * @example\n *\n * var object = { 'a': 1 };\n * var other = { 'a': 1 };\n *\n * _.eq(object, object);\n * // => true\n *\n * _.eq(object, other);\n * // => false\n *\n * _.eq('a', 'a');\n * // => true\n *\n * _.eq('a', Object('a'));\n * // => false\n *\n * _.eq(NaN, NaN);\n * // => true\n */\nfunction eq(value, other) {\n return value === other || (value !== value && other !== other);\n}\n\nexport default eq;\n","/**\n * Removes `key` and its value from the stack.\n *\n * @private\n * @name delete\n * @memberOf Stack\n * @param {string} key The key of the value to remove.\n * @returns {boolean} Returns `true` if the entry was removed, else `false`.\n */\nfunction stackDelete(key) {\n var data = this.__data__,\n result = data['delete'](key);\n\n this.size = data.size;\n return result;\n}\n\nexport default stackDelete;\n","/**\n * Gets the stack value for `key`.\n *\n * @private\n * @name get\n * @memberOf Stack\n * @param {string} key The key of the value to get.\n * @returns {*} Returns the entry value.\n */\nfunction stackGet(key) {\n return this.__data__.get(key);\n}\n\nexport default stackGet;\n","/**\n * Checks if a stack value for `key` exists.\n *\n * @private\n * @name has\n * @memberOf Stack\n * @param {string} key The key of the entry to check.\n * @returns {boolean} Returns `true` if an entry for `key` exists, else `false`.\n */\nfunction stackHas(key) {\n return this.__data__.has(key);\n}\n\nexport default stackHas;\n","/**\n * Checks if `value` is the\n * [language type](http://www.ecma-international.org/ecma-262/7.0/#sec-ecmascript-language-types)\n * of `Object`. (e.g. arrays, functions, objects, regexes, `new Number(0)`, and `new String('')`)\n *\n * @static\n * @memberOf _\n * @since 0.1.0\n * @category Lang\n * @param {*} value The value to check.\n * @returns {boolean} Returns `true` if `value` is an object, else `false`.\n * @example\n *\n * _.isObject({});\n * // => true\n *\n * _.isObject([1, 2, 3]);\n * // => true\n *\n * _.isObject(_.noop);\n * // => true\n *\n * _.isObject(null);\n * // => false\n */\nfunction isObject(value) {\n var type = typeof value;\n return value != null && (type == 'object' || type == 'function');\n}\n\nexport default isObject;\n","/** Used for built-in method references. */\nvar funcProto = Function.prototype;\n\n/** Used to resolve the decompiled source of functions. */\nvar funcToString = funcProto.toString;\n\n/**\n * Converts `func` to its source code.\n *\n * @private\n * @param {Function} func The function to convert.\n * @returns {string} Returns the source code.\n */\nfunction toSource(func) {\n if (func != null) {\n try {\n return funcToString.call(func);\n } catch (e) {}\n try {\n return (func + '');\n } catch (e) {}\n }\n return '';\n}\n\nexport default toSource;\n","/**\n * Gets the value at `key` of `object`.\n *\n * @private\n * @param {Object} [object] The object to query.\n * @param {string} key The key of the property to get.\n * @returns {*} Returns the property value.\n */\nfunction getValue(object, key) {\n return object == null ? undefined : object[key];\n}\n\nexport default getValue;\n","/**\n * Removes `key` and its value from the hash.\n *\n * @private\n * @name delete\n * @memberOf Hash\n * @param {Object} hash The hash to modify.\n * @param {string} key The key of the value to remove.\n * @returns {boolean} Returns `true` if the entry was removed, else `false`.\n */\nfunction hashDelete(key) {\n var result = this.has(key) && delete this.__data__[key];\n this.size -= result ? 1 : 0;\n return result;\n}\n\nexport default hashDelete;\n","/**\n * Checks if `value` is suitable for use as unique object key.\n *\n * @private\n * @param {*} value The value to check.\n * @returns {boolean} Returns `true` if `value` is suitable, else `false`.\n */\nfunction isKeyable(value) {\n var type = typeof value;\n return (type == 'string' || type == 'number' || type == 'symbol' || type == 'boolean')\n ? (value !== '__proto__')\n : (value === null);\n}\n\nexport default isKeyable;\n","/**\n * Creates a base function for methods like `_.forIn` and `_.forOwn`.\n *\n * @private\n * @param {boolean} [fromRight] Specify iterating from right to left.\n * @returns {Function} Returns the new base function.\n */\nfunction createBaseFor(fromRight) {\n return function(object, iteratee, keysFunc) {\n var index = -1,\n iterable = Object(object),\n props = keysFunc(object),\n length = props.length;\n\n while (length--) {\n var key = props[fromRight ? length : ++index];\n if (iteratee(iterable[key], key, iterable) === false) {\n break;\n }\n }\n return object;\n };\n}\n\nexport default createBaseFor;\n","/**\n * Copies the values of `source` to `array`.\n *\n * @private\n * @param {Array} source The array to copy values from.\n * @param {Array} [array=[]] The array to copy values to.\n * @returns {Array} Returns `array`.\n */\nfunction copyArray(source, array) {\n var index = -1,\n length = source.length;\n\n array || (array = Array(length));\n while (++index < length) {\n array[index] = source[index];\n }\n return array;\n}\n\nexport default copyArray;\n","/** Used for built-in method references. */\nvar objectProto = Object.prototype;\n\n/**\n * Checks if `value` is likely a prototype object.\n *\n * @private\n * @param {*} value The value to check.\n * @returns {boolean} Returns `true` if `value` is a prototype, else `false`.\n */\nfunction isPrototype(value) {\n var Ctor = value && value.constructor,\n proto = (typeof Ctor == 'function' && Ctor.prototype) || objectProto;\n\n return value === proto;\n}\n\nexport default isPrototype;\n","/**\n * Checks if `value` is classified as an `Array` object.\n *\n * @static\n * @memberOf _\n * @since 0.1.0\n * @category Lang\n * @param {*} value The value to check.\n * @returns {boolean} Returns `true` if `value` is an array, else `false`.\n * @example\n *\n * _.isArray([1, 2, 3]);\n * // => true\n *\n * _.isArray(document.body.children);\n * // => false\n *\n * _.isArray('abc');\n * // => false\n *\n * _.isArray(_.noop);\n * // => false\n */\nvar isArray = Array.isArray;\n\nexport default isArray;\n","/** Used as references for various `Number` constants. */\nvar MAX_SAFE_INTEGER = 9007199254740991;\n\n/**\n * Checks if `value` is a valid array-like length.\n *\n * **Note:** This method is loosely based on\n * [`ToLength`](http://ecma-international.org/ecma-262/7.0/#sec-tolength).\n *\n * @static\n * @memberOf _\n * @since 4.0.0\n * @category Lang\n * @param {*} value The value to check.\n * @returns {boolean} Returns `true` if `value` is a valid length, else `false`.\n * @example\n *\n * _.isLength(3);\n * // => true\n *\n * _.isLength(Number.MIN_VALUE);\n * // => false\n *\n * _.isLength(Infinity);\n * // => false\n *\n * _.isLength('3');\n * // => false\n */\nfunction isLength(value) {\n return typeof value == 'number' &&\n value > -1 && value % 1 == 0 && value <= MAX_SAFE_INTEGER;\n}\n\nexport default isLength;\n","/**\n * This method returns `false`.\n *\n * @static\n * @memberOf _\n * @since 4.13.0\n * @category Util\n * @returns {boolean} Returns `false`.\n * @example\n *\n * _.times(2, _.stubFalse);\n * // => [false, false]\n */\nfunction stubFalse() {\n return false;\n}\n\nexport default stubFalse;\n","/**\n * The base implementation of `_.unary` without support for storing metadata.\n *\n * @private\n * @param {Function} func The function to cap arguments for.\n * @returns {Function} Returns the new capped function.\n */\nfunction baseUnary(func) {\n return function(value) {\n return func(value);\n };\n}\n\nexport default baseUnary;\n","/**\n * Gets the value at `key`, unless `key` is \"__proto__\" or \"constructor\".\n *\n * @private\n * @param {Object} object The object to query.\n * @param {string} key The key of the property to get.\n * @returns {*} Returns the property value.\n */\nfunction safeGet(object, key) {\n if (key === 'constructor' && typeof object[key] === 'function') {\n return;\n }\n\n if (key == '__proto__') {\n return;\n }\n\n return object[key];\n}\n\nexport default safeGet;\n","/**\n * The base implementation of `_.times` without support for iteratee shorthands\n * or max array length checks.\n *\n * @private\n * @param {number} n The number of times to invoke `iteratee`.\n * @param {Function} iteratee The function invoked per iteration.\n * @returns {Array} Returns the array of results.\n */\nfunction baseTimes(n, iteratee) {\n var index = -1,\n result = Array(n);\n\n while (++index < n) {\n result[index] = iteratee(index);\n }\n return result;\n}\n\nexport default baseTimes;\n","/** Used as references for various `Number` constants. */\nvar MAX_SAFE_INTEGER = 9007199254740991;\n\n/** Used to detect unsigned integer values. */\nvar reIsUint = /^(?:0|[1-9]\\d*)$/;\n\n/**\n * Checks if `value` is a valid array-like index.\n *\n * @private\n * @param {*} value The value to check.\n * @param {number} [length=MAX_SAFE_INTEGER] The upper bounds of a valid index.\n * @returns {boolean} Returns `true` if `value` is a valid index, else `false`.\n */\nfunction isIndex(value, length) {\n var type = typeof value;\n length = length == null ? MAX_SAFE_INTEGER : length;\n\n return !!length &&\n (type == 'number' ||\n (type != 'symbol' && reIsUint.test(value))) &&\n (value > -1 && value % 1 == 0 && value < length);\n}\n\nexport default isIndex;\n","/**\n * This function is like\n * [`Object.keys`](http://ecma-international.org/ecma-262/7.0/#sec-object.keys)\n * except that it includes inherited enumerable properties.\n *\n * @private\n * @param {Object} object The object to query.\n * @returns {Array} Returns the array of property names.\n */\nfunction nativeKeysIn(object) {\n var result = [];\n if (object != null) {\n for (var key in Object(object)) {\n result.push(key);\n }\n }\n return result;\n}\n\nexport default nativeKeysIn;\n","/**\n * This method returns the first argument it receives.\n *\n * @static\n * @since 0.1.0\n * @memberOf _\n * @category Util\n * @param {*} value Any value.\n * @returns {*} Returns `value`.\n * @example\n *\n * var object = { 'a': 1 };\n *\n * console.log(_.identity(object) === object);\n * // => true\n */\nfunction identity(value) {\n return value;\n}\n\nexport default identity;\n","/**\n * A faster alternative to `Function#apply`, this function invokes `func`\n * with the `this` binding of `thisArg` and the arguments of `args`.\n *\n * @private\n * @param {Function} func The function to invoke.\n * @param {*} thisArg The `this` binding of `func`.\n * @param {Array} args The arguments to invoke `func` with.\n * @returns {*} Returns the result of `func`.\n */\nfunction apply(func, thisArg, args) {\n switch (args.length) {\n case 0: return func.call(thisArg);\n case 1: return func.call(thisArg, args[0]);\n case 2: return func.call(thisArg, args[0], args[1]);\n case 3: return func.call(thisArg, args[0], args[1], args[2]);\n }\n return func.apply(thisArg, args);\n}\n\nexport default apply;\n","/**\n * Creates a function that returns `value`.\n *\n * @static\n * @memberOf _\n * @since 2.4.0\n * @category Util\n * @param {*} value The value to return from the new function.\n * @returns {Function} Returns the new constant function.\n * @example\n *\n * var objects = _.times(2, _.constant({ 'a': 1 }));\n *\n * console.log(objects);\n * // => [{ 'a': 1 }, { 'a': 1 }]\n *\n * console.log(objects[0] === objects[1]);\n * // => true\n */\nfunction constant(value) {\n return function() {\n return value;\n };\n}\n\nexport default constant;\n","/** Used to detect hot functions by number of calls within a span of milliseconds. */\nvar HOT_COUNT = 800,\n HOT_SPAN = 16;\n\n/* Built-in method references for those with the same name as other `lodash` methods. */\nvar nativeNow = Date.now;\n\n/**\n * Creates a function that'll short out and invoke `identity` instead\n * of `func` when it's called `HOT_COUNT` or more times in `HOT_SPAN`\n * milliseconds.\n *\n * @private\n * @param {Function} func The function to restrict.\n * @returns {Function} Returns the new shortable function.\n */\nfunction shortOut(func) {\n var count = 0,\n lastCalled = 0;\n\n return function() {\n var stamp = nativeNow(),\n remaining = HOT_SPAN - (stamp - lastCalled);\n\n lastCalled = stamp;\n if (remaining > 0) {\n if (++count >= HOT_COUNT) {\n return arguments[0];\n }\n } else {\n count = 0;\n }\n return func.apply(undefined, arguments);\n };\n}\n\nexport default shortOut;\n","// break it out on its own because\n// it's building from the lodash-es from scratch\n// according to this discussion https://github.com/lodash/lodash/issues/3298\nimport isPlainObject from 'lodash-es/isPlainObject'\nimport merge from 'lodash-es/merge'\n\n/**\n * previously we already make sure the order of the namespaces\n * and attach the auth client to it\n * @param {array} promises array of unresolved promises\n * @param {boolean} asObject if true then merge the result object\n * @return {object} promise resolved with the array of promises resolved results\n */\nexport function chainPromises(promises, asObject = false) {\n return promises.reduce((promiseChain, currentTask) => (\n promiseChain.then(chainResults => (\n currentTask.then(currentResult => (\n asObject === false ? [...chainResults, currentResult] : merge(chainResults, currentResult)\n ))\n ))\n ), Promise.resolve(\n asObject === false ? [] : (isPlainObject(asObject) ? asObject : {})\n ))\n}\n\n\n/**\n * This one return a different result from the chainPromises\n * it will be the same like chainFns that take one promise resolve as the next fn parameter\n * @param {function} initPromise a function that accept param and resolve result\n * @param {array} promises array of function pass that resolve promises\n * @return {promise} resolve the processed result\n */\nexport function chainProcessPromises(initPromise, ...promises) {\n return (...args) => (\n promises.reduce((promiseChain, currentTask) => (\n promiseChain.then(chainResult => (\n currentTask(chainResult)\n )\n )\n ), Reflect.apply(initPromise, null, args))\n )\n}\n","// @BUG when call disconnected \n// this keep causing an \"Disconnect call failed TypeError: Cannot read property 'readyState' of null\"\n// I think that is because it's not login then it can not be disconnect\n// how do we track this state globally\nimport { LOGIN_EVENT_NAME } from 'jsonql-constants'\nimport { clearMainEmitEvt } from '../modules'\n\n/**\n * create a login event handler \n * @param {object} opts configurations \n * @param {object} nspMap contain all the required info\n * @param {object} ee event emitter \n * @return {void}\n */\nexport function loginEventHandler(opts, nspMap, ee) {\n const { log } = opts\n const { namespaces } = nspMap\n\n ee.$only(LOGIN_EVENT_NAME, function loginEventHandlerCallback(tokenFromLoginAction) {\n \n log('createClient LOGIN_EVENT_NAME $only handler')\n\n clearMainEmitEvt(ee, namespaces)\n // console.log('LOGIN_EVENT_NAME', token)\n const newNsps = createNspAction(opts, nspMap, tokenFromLoginAction)\n // rebind it\n Reflect.apply(\n clientEventHandler, // @NOTE is this the problem that cause the hang up?\n null,\n args.concat([newNsps.namespaces, newNsps.nsps])\n )\n })\n}","// bunch of generic helpers\n\nimport isArray from 'lodash-es/isArray'\nimport isPlainObject from 'lodash-es/isPlainObject'\nimport trim from 'lodash-es/trim'\n\n/**\n * DIY in Array\n * @param {array} arr to check from\n * @param {*} value to check against\n * @return {boolean} true on found\n */\nexport const inArray = (arr, value) => !!arr.filter(a => a === value).length\n\n// quick and dirty to turn non array to array\nexport const toArray = (arg) => isArray(arg) ? arg : [arg]\n\n/**\n * parse string to json or just return the original value if error happened\n * @param {*} n input\n * @param {boolean} [t=true] or throw\n * @return {*} json object on success\n */\nexport const parseJson = function(n, t=true) {\n try {\n return JSON.parse(n)\n } catch(e) {\n if (t) {\n return n\n }\n throw new Error(e)\n }\n}\n\n/**\n * @param {object} obj for search\n * @param {string} key target\n * @return {boolean} true on success\n */\nexport const isObjectHasKey = function(obj, key) {\n try {\n const keys = Object.keys(obj)\n return inArray(keys, key)\n } catch(e) {\n // @BUG when the obj is not an OBJECT we got some weird output\n return false\n }\n}\n\n/**\n * create a event name\n * @param {string[]} args\n * @return {string} event name for use\n */\nexport const createEvt = (...args) => args.join('_')\n\n/**\n * simple util method to get the value\n * @param {string} name of the key\n * @param {object} obj to take value from\n * @return {*} the object value id by name or undefined\n */\nexport const getConfigValue = (name, obj) => (\n obj && isPlainObject(obj) ? ( (name in obj) ? obj[name] : undefined ) : undefined\n)\n\n/**\n * small util to make sure the return value is valid JSON object\n * @param {*} n input\n * @return {object} correct JSON object\n */\nexport const toJson = n => {\n if (typeof n === 'string') {\n return parseJson(n)\n }\n return parseJson(JSON.stringify(n))\n}\n\n/**\n * Check several parameter that there is something in the param\n * @param {*} param input\n * @return {boolean}\n */\nexport const isNotEmpty = function(param) {\n return param !== undefined && param !== false && param !== null && trim(param) !== ''\n}\n\n/**\n * Simple check if the prop is function\n * @param {*} prop input\n * @return {boolean} true on success\n */\nexport const isFunc = prop => {\n if (typeof prop === 'function') {\n return true;\n }\n console.error(`Expect to be Function type! Got ${typeof prop}`)\n}\n\n// generic placeholder function\nexport const nil = () => false\n","// custom validation error class\n// when validaton failed\nexport default class JsonqlValidationError extends Error {\n constructor(...args) {\n super(...args)\n\n this.message = args[0]\n this.detail = args[1]\n\n this.className = JsonqlValidationError.name;\n\n if (Error.captureStackTrace) {\n Error.captureStackTrace(this, JsonqlValidationError)\n }\n }\n\n static get name() {\n return 'JsonqlValidationError'\n }\n}\n","/**\n * @param {boolean} sec return in second or not\n * @return {number} timestamp\n */\nexport const timestamp = (sec = false) => {\n let time = Date.now()\n return sec ? Math.floor( time / 1000 ) : time\n}\n","// ported from jsonql-params-validator\n// craete several helper function to construct / extract the payload\n// and make sure they are all the same\nimport {\n PAYLOAD_PARAM_NAME,\n CONDITION_PARAM_NAME,\n RESOLVER_PARAM_NAME,\n QUERY_ARG_NAME,\n TIMESTAMP_PARAM_NAME\n} from 'jsonql-constants'\n\nimport JsonqlValidationError from 'jsonql-errors/src/validation-error'\n\nimport isArray from 'lodash-es/isArray'\nimport isString from 'lodash-es/isString'\nimport isPlainObject from 'lodash-es/isPlainObject'\n\nimport { timestamp } from './timestamp'\nimport { parseJson } from './generic'\n\n/**\n * check if the payload has a timestamp field, then append a new timestamp to it\n * @param {object} payload from the com\n * @return {array} timestamp field with an array value\n */\nexport const handleTimestamp = payload => {\n let ts = payload[TIMESTAMP_PARAM_NAME]\n if (!isArray(ts)) {\n ts = [ts]\n }\n ts.push( timestamp() )\n\n return ts\n}\n\n/**\n * make sure it's an object (it was call formatPayload but it doesn't make sense)\n * @param {*} payload the object comes in could be string based\n * @return {object} the transformed payload\n */\nexport const toPayload = payload => isString(payload) ? parseJson(payload) : payload\n\n/**\n * @param {*} args arguments to send\n *@return {object} formatted payload\n */\nexport const formatPayload = (args) => (\n { [QUERY_ARG_NAME]: args }\n)\n\n/**\n * extract the resolver name from the payload \n * @param {object} payload\n * @return {string} resolver name \n */\nexport function getResolverFromPayload(payload) {\n const keys = Object.keys(payload)\n return keys.filter(key => key !== TIMESTAMP_PARAM_NAME)[0]\n}\n\n/**\n * wrapper method to add the timestamp as well\n * @param {string} resolverName\n * @param {*} payload\n * @return {object} delierable\n */\nexport function createDeliverable(resolverName, payload) {\n return {\n [resolverName]: payload,\n [TIMESTAMP_PARAM_NAME]: [ timestamp() ]\n }\n}\n\n/**\n * @param {string} resolverName name of function\n * @param {array} [args=[]] from the ...args\n * @param {boolean} [jsonp = false] add v1.3.0 to koa\n * @return {object} formatted argument\n */\nexport function createQuery(resolverName, args = [], jsonp = false) {\n if (isString(resolverName) && isArray(args)) {\n let payload = formatPayload(args)\n if (jsonp === true) {\n return payload\n }\n return createDeliverable(resolverName, payload)\n }\n throw new JsonqlValidationError(`[createQuery] expect resolverName to be string and args to be array!`, { resolverName, args })\n}\n\n/**\n * string version of the createQuery\n * @return {string}\n */\nexport function createQueryStr(resolverName, args = [], jsonp = false) {\n return JSON.stringify(createQuery(resolverName, args, jsonp))\n}\n\n/**\n * @param {string} resolverName name of function\n * @param {*} payload to send\n * @param {object} [condition={}] for what\n * @param {boolean} [jsonp = false] add v1.3.0 to koa\n * @return {object} formatted argument\n */\nexport function createMutation(resolverName, payload, condition = {}, jsonp = false) {\n const _payload = {\n [PAYLOAD_PARAM_NAME]: payload,\n [CONDITION_PARAM_NAME]: condition\n }\n if (jsonp === true) {\n return _payload\n }\n if (isString(resolverName)) {\n return createDeliverable(resolverName, _payload)\n }\n throw new JsonqlValidationError(`[createMutation] expect resolverName to be string!`, { resolverName, payload, condition })\n}\n\n/**\n * string version of createMutation\n * @return {string}\n */\nexport function createMutationStr(resolverName, payload, condition = {}, jsonp = false) {\n return JSON.stringify(createMutation(resolverName, payload, condition, jsonp))\n}\n\n/**\n * Extract the parts from payload and format for use\n * @param {string} resolverName name of fn\n * @param {object} payload the incoming json\n * @return {object|boolean} false on failed\n */\nexport function getQueryFromArgs(resolverName, payload) {\n if (resolverName && isPlainObject(payload)) {\n const args = payload[resolverName]\n if (args[QUERY_ARG_NAME]) {\n return {\n [RESOLVER_PARAM_NAME]: resolverName,\n [QUERY_ARG_NAME]: args[QUERY_ARG_NAME],\n [TIMESTAMP_PARAM_NAME]: handleTimestamp(payload)\n }\n }\n }\n return false\n}\n\n/**\n * Share function so no repeat\n * @param {object} payload the payload from client\n * @param {function} processor the last get result method\n * @return {*} result processed result\n */\nfunction processPayload(payload, processor) {\n const p = toPayload(payload)\n const resolverName = getResolverFromPayload(p)\n return Reflect.apply(processor, null, [resolverName, p])\n}\n\n/**\n * extra the payload back\n * @param {*} payload from http call\n * @return {object} resolverName and args\n */\nexport function getQueryFromPayload(payload) {\n const result = processPayload(payload, getQueryFromArgs)\n if (result !== false) {\n return result\n }\n throw new JsonqlValidationError('[getQueryArgs] Payload is malformed!', payload)\n}\n\n/**\n * Further break down from method below for use else where\n * @param {string} resolverName name of fn\n * @param {object} payload payload\n * @return {object|boolean} false on failed\n */\nexport function getMutationFromArgs(resolverName, payload) {\n if (resolverName && isPlainObject(payload)) {\n const args = payload[resolverName]\n if (args) {\n return {\n [RESOLVER_PARAM_NAME]: resolverName,\n [PAYLOAD_PARAM_NAME]: args[PAYLOAD_PARAM_NAME],\n [CONDITION_PARAM_NAME]: args[CONDITION_PARAM_NAME],\n [TIMESTAMP_PARAM_NAME]: handleTimestamp(payload)\n }\n }\n }\n return false\n}\n\n/**\n * @param {object} payload\n * @return {object} resolverName, payload, conditon\n */\nexport function getMutationFromPayload(payload) {\n const result = processPayload(payload, getMutationFromArgs)\n\n if (result !== false) {\n return result\n }\n throw new JsonqlValidationError('[getMutationArgs] Payload is malformed!', payload)\n}\n","// There are the socket related methods ported back from \n// ws-server-core and ws-client-core \nimport {\n WS_REPLY_TYPE,\n WS_EVT_NAME,\n WS_DATA_NAME,\n TIMESTAMP_PARAM_NAME,\n ERROR_KEY,\n EMIT_REPLY_TYPE,\n ACKNOWLEDGE_REPLY_TYPE\n} from 'jsonql-constants'\nimport { JsonqlError } from 'jsonql-errors' \nimport isString from 'lodash-es/isString'\n\nimport { toJson, isObjectHasKey, nil } from './generic'\nimport { timestamp } from './timestamp'\n\nconst PAYLOAD_NOT_DECODED_ERR = 'payload can not decoded'\nconst WS_KEYS = [\n WS_REPLY_TYPE,\n WS_EVT_NAME,\n WS_DATA_NAME\n]\n\n\n/**\n * The ws doesn't have a acknowledge callback like socket.io\n * so we have to DIY one for ws and other that doesn't have it\n * @param {string} type of reply\n * @param {string} resolverName which is replying\n * @param {*} data payload\n * @param {array} [ts= []] the last received ts, if any \n * @return {string} stringify json\n */\nexport const createWsReply = (type, resolverName, data, ts = []) => {\n ts.push(timestamp())\n return JSON.stringify({\n data: {\n [WS_REPLY_TYPE]: type,\n [WS_EVT_NAME]: resolverName,\n [WS_DATA_NAME]: toJson(data)\n },\n [TIMESTAMP_PARAM_NAME]: ts \n })\n}\n\n// extended function \nexport const createReplyMsg = (resolverName, data, ts = []) => (\n createWsReply(EMIT_REPLY_TYPE, resolverName, data, ts)\n)\n\nexport const createAcknowledgeMsg = (resolverName, data, ts = []) => (\n createWsReply(ACKNOWLEDGE_REPLY_TYPE, resolverName, data, ts)\n)\n\n/**\n * @param {string|object} payload should be string when reply but could be transformed\n * @return {boolean} true is OK\n */\nexport const isWsReply = payload => {\n const json = isString(payload) ? toJson(payload) : payload\n const { data } = json\n if (data) {\n let result = WS_KEYS.filter(key => isObjectHasKey(data, key))\n return (result.length === WS_KEYS.length) ? data : false\n }\n return false\n}\n\n/**\n * @param {string|object} data received data\n * @param {function} [cb=nil] this is for extracting the TS field or when it's error\n * @return {object} false on failed\n */\nexport const extractWsPayload = (payload, cb = nil) => {\n try {\n const json = toJson(payload)\n // now handle the data\n let _data\n if ((_data = isWsReply(json)) !== false) {\n // note the ts property is on its own \n cb(TIMESTAMP_PARAM_NAME, json[TIMESTAMP_PARAM_NAME])\n \n return {\n data: toJson(_data[WS_DATA_NAME]),\n resolverName: _data[WS_EVT_NAME],\n type: _data[WS_REPLY_TYPE]\n }\n }\n throw new JsonqlError(PAYLOAD_NOT_DECODED_ERR, payload)\n } catch(e) {\n return cb(ERROR_KEY, e)\n }\n}\n","// the WebSocket main handler\nimport {\n LOGOUT_EVENT_NAME,\n ACKNOWLEDGE_REPLY_TYPE,\n EMIT_REPLY_TYPE,\n ERROR_KEY,\n\n ON_ERROR_FN_NAME,\n ON_MESSAGE_FN_NAME,\n ON_RESULT_FN_NAME,\n ON_READY_FN_NAME,\n ON_LOGIN_FN_NAME\n} from 'jsonql-constants'\nimport {\n createQueryStr,\n createEvt,\n extractWsPayload\n} from 'jsonql-utils/module'\nimport {\n handleNamespaceOnError,\n createIntercomPayload\n} from '../modules'\n\n/**\n * in some edge case we might not even have a resolverName, then\n * we issue a global error for the developer to catch it\n * @param {object} ee event emitter\n * @param {string} namespace nsp\n * @param {string} resolverName resolver\n * @param {object} json decoded payload or error object\n * @return {undefined} nothing return\n */\nconst errorTypeHandler = (ee, namespace, resolverName, json) => {\n let evt = [namespace]\n if (resolverName) {\n evt.push(resolverName)\n }\n evt.push(ON_ERROR_FN_NAME)\n let evtName = Reflect.apply(createEvt, null, evt)\n // test if there is a data field\n let payload = json.data || json\n ee.$trigger(evtName, [payload])\n}\n\n/**\n * Handle the logout event when it's enableAuth\n * @param {object} ee eventEmitter\n * @param {object} ws the WebSocket instance\n * @return {void}\n */\nconst logoutEventListener = (ee, ws) => {\n // listen to the LOGOUT_EVENT_NAME when this is a private nsp\n ee.$on(LOGOUT_EVENT_NAME, function closeEvtHandler() {\n try {\n // @TODO we need find a way to get the userdata\n ws.send(createIntercomPayload(LOGOUT_EVENT_NAME))\n log('terminate ws connection')\n ws.terminate()\n } catch(e) {\n console.error('ws.terminate error', e)\n }\n })\n}\n\n/**\n * Binding the event to socket normally\n * @param {string} namespace\n * @param {object} ws the nsp\n * @param {object} ee EventEmitter\n * @param {boolean} isPrivate to id if this namespace is private or not\n * @param {object} opts configuration\n * @return {object} promise resolve after the onopen event\n */\nexport function bindSocketEventHandler(namespace, ws, ee, isPrivate, opts) {\n const { log } = opts\n let onReadCalls = 2\n // log(`log test, isPrivate:`, isPrivate)\n // connection open\n ws.onopen = function onOpenCallback() {\n\n log('=== ws.onopen listened -->', namespace)\n // we just call the onReady\n ee.$call(ON_READY_FN_NAME)(namespace)\n // we only want to allow it get call twice (number of namespaces)\n --onReadCalls\n if (onReadCalls === 0) {\n ee.$off(ON_READY_FN_NAME)\n }\n\n // need an extra parameter here to id the private nsp\n if (isPrivate) {\n log(`isPrivate and fire the ${ON_LOGIN_FN_NAME}`)\n ee.$call(ON_LOGIN_FN_NAME)(namespace)\n }\n // add listener only after the open is called\n ee.$only(\n createEvt(namespace, EMIT_REPLY_TYPE),\n /**\n * actually send the payload to server\n * @param {string} resolverName\n * @param {array} args NEED TO CHECK HOW WE PASS THIS!\n */\n function wsMainOnEvtHandler(resolverName, args) {\n\n const payload = createQueryStr(resolverName, args)\n log('ws.onopen.send', resolverName, args, payload)\n\n ws.send(payload)\n }\n )\n }\n\n // reply\n // If we change it to the event callback style\n // then the payload will just be the payload and fucks up the extractWsPayload call @TODO\n ws.onmessage = function onMessageCallback(payload) {\n // console.log(`on.message`, typeof payload, payload)\n try {\n // log(`ws.onmessage raw payload`, payload)\n // @TODO the payload actually contain quite a few things - is that changed?\n // type: message, data: data_send_from_server\n const json = extractWsPayload(payload.data)\n const { resolverName, type } = json\n\n log('Respond from server', type, json)\n\n switch (type) {\n case EMIT_REPLY_TYPE:\n let e1 = createEvt(namespace, resolverName, ON_MESSAGE_FN_NAME)\n let r = ee.$trigger(e1, [json])\n log(`EMIT_REPLY_TYPE`, e1, r)\n break\n case ACKNOWLEDGE_REPLY_TYPE:\n let e2 = createEvt(namespace, resolverName, ON_RESULT_FN_NAME)\n let x2 = ee.$trigger(e2, [json])\n log(`ACKNOWLEDGE_REPLY_TYPE`, e2, x2)\n break\n case ERROR_KEY:\n // this is handled error and we won't throw it\n // we need to extract the error from json\n log(`ERROR_KEY`)\n errorTypeHandler(ee, namespace, resolverName, json)\n break\n // @TODO there should be an error type instead of roll into the other two types? TBC\n default:\n // if this happen then we should throw it and halt the operation all together\n log('Unhandled event!', json)\n errorTypeHandler(ee, namespace, resolverName, json)\n // let error = {error: {'message': 'Unhandled event!', type}};\n // ee.$trigger(createEvt(namespace, resolverName, ON_RESULT_FN_NAME), [error])\n }\n } catch(e) {\n console.error(`ws.onmessage error`, e)\n errorTypeHandler(ee, namespace, false, e)\n }\n }\n // when the server close the connection\n ws.onclose = function onCloseCallback() {\n log('ws.onclose callback')\n // @TODO what to do with this\n // ee.$trigger(LOGOUT_EVENT_NAME, [namespace])\n }\n // add a onerror event handler here\n ws.onerror = function onErrorCallback(err) {\n // trigger a global error event\n log(`ws.onerror`, err)\n handleNamespaceOnError(ee, namespace, err)\n }\n\n if (isPrivate) {\n logoutEventListener(ee, ws)\n }\n\n}\n","// actually binding the event client to the socket client\n\n// from the jsonql-ws-client-core\nimport { clientEventListener } from '../modules'\n// local \nimport { createNspAction } from './create-nsp-action'\nimport { loginEventHandler } from './login-event-handler'\nimport { bindSocketEventHandler } from './bind-socket-event-handler'\n\n/**\n * create the NSP(s) and determine if this require auth or not \n * @param {object} opts configuration\n * @param {object} nspMap namespace with resolvers\n * @param {object} ee EventEmitter to pass through\n * @return {object} what comes in what goes out\n */\nfunction createNsp(opts, nspMap, ee) {\n // now create the nsps\n // const { namespaces } = nspMap\n const { token } = opts\n\n return createNspAction(opts, nspMap, token)\n .then(nsps => {\n const listenerFn = clientEventListener(bindSocketEventHandler, nsps)\n // now run it\n listenerFn(opts, nspMap, ee)\n\n if (opts.enableAuth) {\n loginEventHandler(opts, nspMap, ee)\n }\n // return what input\n return { opts, nspMap, ee }\n }) \n}\n\nexport { createNsp }","// breaking up the create-nsp.js file \n// then regroup them back together here \nimport { createNsp } from './create-nsp'\n\nexport default createNsp\n","// share method to create the wsClientResolver\nimport { initWebSocketClient } from './init-websocket-client'\nimport createNsp from '../create-nsp'\nimport { NSP_CLIENT, NSP_AUTH_CLIENT } from 'jsonql-constants'\n\n/**\n * Create the framework <---> jsonql client binding\n * @param {object} frameworkModule the different WebSocket module\n * @return {function} the wsClientResolver\n */\nfunction bindFrameworkToJsonql(frameworkModule) {\n /**\n * wsClientResolver\n * @param {object} opts configuration\n * @param {object} nspMap from the contract\n * @param {object} ee instance of the eventEmitter\n * @return {object} passing the same 3 input out with additional in the opts\n */\n return function createClientBindingAction(opts, nspMap, ee) {\n const { log } = opts\n opts[NSP_CLIENT] = initWebSocketClient(frameworkModule, false, log)\n opts[NSP_AUTH_CLIENT] = initWebSocketClient(frameworkModule, true, log) \n // @1.0.7 remove later once everything fixed \n \n log(`bindFrameworkToJsonql`, ee.name, nspMap)\n // console.log(`contract`, opts.contract)\n return createNsp(opts, nspMap, ee)\n }\n}\n\nexport { bindFrameworkToJsonql }","// this will be the news style interface that will pass to the jsonql-ws-client\n// then return a function for accepting an opts to generate the final\n// client api\nimport WebSocket from 'ws'\nimport createWebSocketBinding from '../core/create-websocket-binding'\n\n/**\n * @param {object} opts configuration\n * @param {object} nspMap from the contract\n * @param {object} ee instance of the eventEmitter\n * @return {object} passing the same 3 input out with additional in the opts\n */\nexport default createWebSocketBinding(WebSocket)\n","// this is the module entry point for node client\nimport {\n wsClientCore\n} from './core/modules'\nimport { wsClientConstProps } from './options'\n\nimport nodeFrameworkSocketEngine from './node/node-framework-socket-engine'\n\n// export back the function and that's it\nexport default function wsNodeClient(config = {}, constProps = {}) {\n const initClientMethod = wsClientCore(\n nodeFrameworkSocketEngine, \n {}, \n Object.assign({}, wsClientConstProps, constProps)\n )\n return initClientMethod(config)\n}\n"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;ACAA;;;;;;;;;ACAA;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;ACAA;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;ACAA;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;ACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;;"} \ No newline at end of file diff --git a/packages/@jsonql/ws/src/core/create-nsp/create-nsp.js b/packages/@jsonql/ws/src/core/create-nsp/create-nsp.js index 8b8feb0f..d284322a 100644 --- a/packages/@jsonql/ws/src/core/create-nsp/create-nsp.js +++ b/packages/@jsonql/ws/src/core/create-nsp/create-nsp.js @@ -2,13 +2,13 @@ // from the jsonql-ws-client-core import { clientEventListener } from '../modules' -// local +// local import { createNspAction } from './create-nsp-action' -import { loginEventHandler } from './login-event-handler' +import { loginEventListener } from './login-event-listener' import { bindSocketEventHandler } from './bind-socket-event-handler' /** - * create the NSP(s) and determine if this require auth or not + * create the NSP(s) and determine if this require auth or not * @param {object} opts configuration * @param {object} nspMap namespace with resolvers * @param {object} ee EventEmitter to pass through @@ -30,7 +30,7 @@ function createNsp(opts, nspMap, ee) { } // return what input return { opts, nspMap, ee } - }) + }) } -export { createNsp } \ No newline at end of file +export { createNsp } diff --git a/packages/@jsonql/ws/src/core/create-nsp/login-event-handler.js b/packages/@jsonql/ws/src/core/create-nsp/login-event-listener.js similarity index 82% rename from packages/@jsonql/ws/src/core/create-nsp/login-event-handler.js rename to packages/@jsonql/ws/src/core/create-nsp/login-event-listener.js index 89f83bce..3764268f 100644 --- a/packages/@jsonql/ws/src/core/create-nsp/login-event-handler.js +++ b/packages/@jsonql/ws/src/core/create-nsp/login-event-listener.js @@ -1,4 +1,4 @@ -// @BUG when call disconnected +// @BUG when call disconnected // this keep causing an "Disconnect call failed TypeError: Cannot read property 'readyState' of null" // I think that is because it's not login then it can not be disconnect // how do we track this state globally @@ -6,18 +6,18 @@ import { LOGIN_EVENT_NAME } from 'jsonql-constants' import { clearMainEmitEvt } from '../modules' /** - * create a login event handler - * @param {object} opts configurations + * create a login event handler + * @param {object} opts configurations * @param {object} nspMap contain all the required info - * @param {object} ee event emitter + * @param {object} ee event emitter * @return {void} */ -export function loginEventHandler(opts, nspMap, ee) { +export function loginEventListener(opts, nspMap, ee) { const { log } = opts const { namespaces } = nspMap ee.$only(LOGIN_EVENT_NAME, function loginEventHandlerCallback(tokenFromLoginAction) { - + log('createClient LOGIN_EVENT_NAME $only handler') clearMainEmitEvt(ee, namespaces) @@ -30,4 +30,4 @@ export function loginEventHandler(opts, nspMap, ee) { args.concat([newNsps.namespaces, newNsps.nsps]) ) }) -} \ No newline at end of file +} diff --git a/packages/ws-client-core/src/api.js b/packages/ws-client-core/src/api.js index 52072cd6..c4f9dfb2 100644 --- a/packages/ws-client-core/src/api.js +++ b/packages/ws-client-core/src/api.js @@ -32,10 +32,11 @@ export function wsClientCoreAction(socketClientListener) { .then( ({opts, nspMap, ee}) => socketClientListener(opts, nspMap, ee) ) - .then( // there is problem here, we wrap up the operation inside + .then( ({opts, nspMap, ee}) => callersGenerator(opts, nspMap, ee) ) - .then(setupFinalStep) + // because it returns as an array of params + .then(result => Reflect.apply(setupFinalStep, null, result)) .catch(err => { console.error(`jsonql-ws-core-client init error`, err) }) diff --git a/packages/ws-client-core/src/callers/callers-generator.js b/packages/ws-client-core/src/callers/callers-generator.js index 814078e7..862c01de 100644 --- a/packages/ws-client-core/src/callers/callers-generator.js +++ b/packages/ws-client-core/src/callers/callers-generator.js @@ -28,6 +28,8 @@ export function callersGenerator(opts, nspMap, ee) { setupNamespaceErrorListener ] if (opts.enableAuth) { + // there is a problem here, when this is a public namespace + // it should not have a login logout event attach to it fns.push(setupAuthMethods) } // we will always get back the [ obj, opts, ee ] diff --git a/packages/ws-client-core/src/callers/setup-final-step.js b/packages/ws-client-core/src/callers/setup-final-step.js index 3f84c491..d6db2354 100644 --- a/packages/ws-client-core/src/callers/setup-final-step.js +++ b/packages/ws-client-core/src/callers/setup-final-step.js @@ -3,13 +3,12 @@ import { setupInterCom } from './setup-intercom' /** * The final step to return the client - * @param {object} params wrapper object to call the result forward - * @param {object} params.client the client - * @param {object} params.opts configuration - * @param {object} params.ee the event emitter + * @param {object} obj the client + * @param {object} opts configuration + * @param {object} ee the event emitter * @return {object} client */ -function setupFinalStep({ obj, opts, ee }) { +function setupFinalStep(obj, opts, ee) { const client = setupInterCom(obj, opts, ee) diff --git a/packages/ws-client-core/src/listener/client-event-listener.js b/packages/ws-client-core/src/listener/client-event-listener.js index 7aa76708..fa00291c 100644 --- a/packages/ws-client-core/src/listener/client-event-listener.js +++ b/packages/ws-client-core/src/listener/client-event-listener.js @@ -15,7 +15,6 @@ import { SOCKET_IO } from '../options/constants' import { getPrivateNamespace } from 'jsonql-utils/src/namespace' import { logoutEvtListener, notLoginListener } from './event-listeners' - /** * centralize all the comm in one place * @param {function} bindSocketEventHandler binding the ee to ws --> this is the core bit @@ -25,9 +24,9 @@ import { logoutEvtListener, notLoginListener } from './event-listeners' export function clientEventListener(bindSocketEventListener, nsps) { /** * BREAKING CHANGE instead of one flat structure - * we return a function to accept the two + * we return a function to accept the two * @param {object} opts configuration - * @param {object} nspMap this is not in the opts + * @param {object} nspMap this is not in the opts * @param {object} ee Event Emitter instance * @return {array} although we return something but this is the last step and nothing to do further */ @@ -38,7 +37,7 @@ export function clientEventListener(bindSocketEventListener, nsps) { // @1.1.3 add isPrivate prop to id which namespace is the private nsp // then we can use this prop to determine if we need to fire the ON_LOGIN_PROP_NAME event const privateNamespace = getPrivateNamespace(namespaces) - + return namespaces.map(namespace => { let isPrivate = privateNamespace === namespace log(namespace, ` --> ${isPrivate ? 'private': 'public'} nsp --> `, nsps[namespace] !== false) @@ -52,8 +51,8 @@ export function clientEventListener(bindSocketEventListener, nsps) { } else { log(`binding notLoginWsHandler to ${namespace}`) // a dummy placeholder - // @TODO but it should be a not connect handler - // when it's not login (or fail) this should be handle differently + // @TODO but it should be a not connect handler + // when it's not login (or fail) this should be handle differently notLoginListener(namespace, ee, opts) } if (isPrivate) { @@ -61,7 +60,7 @@ export function clientEventListener(bindSocketEventListener, nsps) { logoutEvtListener(nsps, namespaces, ee, opts) } // just return something its not going to get use anywhere - return isPrivate + return isPrivate }) } } -- Gitee From f9c9944a8186c87244760c11206e6e6aaa263d9c Mon Sep 17 00:00:00 2001 From: joelchu Date: Fri, 20 Mar 2020 15:53:33 +0800 Subject: [PATCH 10/11] rethink about how the socket internal event works and remove redudant event name and rename the connected event to just connect and disconnect --- packages/@jsonql/ws/src/core/create-nsp/create-nsp.js | 3 ++- .../@jsonql/ws/src/core/create-nsp/login-event-listener.js | 7 ++++++- packages/constants/package.json | 2 +- packages/constants/socket.js | 5 ++--- packages/ws-client-core/src/api.js | 6 +++--- 5 files changed, 14 insertions(+), 9 deletions(-) diff --git a/packages/@jsonql/ws/src/core/create-nsp/create-nsp.js b/packages/@jsonql/ws/src/core/create-nsp/create-nsp.js index d284322a..a148e936 100644 --- a/packages/@jsonql/ws/src/core/create-nsp/create-nsp.js +++ b/packages/@jsonql/ws/src/core/create-nsp/create-nsp.js @@ -2,10 +2,11 @@ // from the jsonql-ws-client-core import { clientEventListener } from '../modules' +import { bindSocketEventHandler } from './bind-socket-event-handler' // local import { createNspAction } from './create-nsp-action' import { loginEventListener } from './login-event-listener' -import { bindSocketEventHandler } from './bind-socket-event-handler' + /** * create the NSP(s) and determine if this require auth or not diff --git a/packages/@jsonql/ws/src/core/create-nsp/login-event-listener.js b/packages/@jsonql/ws/src/core/create-nsp/login-event-listener.js index 3764268f..f611d76c 100644 --- a/packages/@jsonql/ws/src/core/create-nsp/login-event-listener.js +++ b/packages/@jsonql/ws/src/core/create-nsp/login-event-listener.js @@ -5,8 +5,12 @@ import { LOGIN_EVENT_NAME } from 'jsonql-constants' import { clearMainEmitEvt } from '../modules' +import { clientEventListener } from '../modules' +import { bindSocketEventHandler } from './bind-socket-event-handler' + /** - * create a login event handler + * create a login event handler, that will unbind all existing ws --> event + * then rebind them together, so this is a re-run of the create-nsp * @param {object} opts configurations * @param {object} nspMap contain all the required info * @param {object} ee event emitter @@ -24,6 +28,7 @@ export function loginEventListener(opts, nspMap, ee) { // console.log('LOGIN_EVENT_NAME', token) const newNsps = createNspAction(opts, nspMap, tokenFromLoginAction) // rebind it + Reflect.apply( clientEventHandler, // @NOTE is this the problem that cause the hang up? null, diff --git a/packages/constants/package.json b/packages/constants/package.json index 421e9565..28910981 100755 --- a/packages/constants/package.json +++ b/packages/constants/package.json @@ -1,6 +1,6 @@ { "name": "jsonql-constants", - "version": "2.0.6", + "version": "2.0.7", "description": "All the share constants for jsonql modules", "main": "main.js", "module": "index.js", diff --git a/packages/constants/socket.js b/packages/constants/socket.js index 24b5356d..aade6988 100644 --- a/packages/constants/socket.js +++ b/packages/constants/socket.js @@ -9,8 +9,7 @@ export const LOGOUT_EVENT_NAME = '__logout__' // when ws switch on standalone mode then we add this event to allow // perform a standalone login method export const SA_LOGIN_EVENT_NAME = '__standalone_login__' -// after the user issue the disconnect, then we need a reconnect -export const RECONNECT_EVENT_NAME = '__reconnect__' + // when we receive the token and decode the userdata // we will inject two more properties into the userdata object export const SOCKET_CLIENT_ID_KEY = '__socket_client_id_key__' @@ -21,7 +20,7 @@ export const SOCKET_CLIENT_TS_KEY = '__socket_client_ts_key__' // connection, the following new event @1.9.2 will correct this edge case // although it should never happens, but in some edge case might want to // disconnect from the current server, then re-establish connection later -export const CONNECTED_EVENT_NAME = '__connected__' +export const CONNECT_EVENT_NAME = '__connect__' export const DISCONNECT_EVENT_NAME = '__disconnect__' // instead of using an event name in place of resolverName in the param // we use this internal resolverName instead, and in type using the event names diff --git a/packages/ws-client-core/src/api.js b/packages/ws-client-core/src/api.js index c4f9dfb2..4e616d3c 100644 --- a/packages/ws-client-core/src/api.js +++ b/packages/ws-client-core/src/api.js @@ -30,11 +30,11 @@ export function wsClientCoreAction(socketClientListener) { // the following two moved to wsPostConfig .then(createRequiredParams) .then( - ({opts, nspMap, ee}) => socketClientListener(opts, nspMap, ee) - ) - .then( ({opts, nspMap, ee}) => callersGenerator(opts, nspMap, ee) ) + .then( + ({opts, nspMap, ee}) => socketClientListener(opts, nspMap, ee) + ) // because it returns as an array of params .then(result => Reflect.apply(setupFinalStep, null, result)) .catch(err => { -- Gitee From 42b4bc9027edf87cd8d7f76a1232d68787dd2a5d Mon Sep 17 00:00:00 2001 From: joelchu Date: Fri, 20 Mar 2020 15:54:56 +0800 Subject: [PATCH 11/11] jsonql-constants to 2.0.7 --- packages/constants/README.md | 3 +-- packages/constants/browser.js | 5 ++--- packages/constants/constants.json | 5 ++--- packages/constants/index.js | 7 +++---- packages/constants/main.js | 5 ++--- packages/constants/socket.js | 2 +- 6 files changed, 11 insertions(+), 16 deletions(-) diff --git a/packages/constants/README.md b/packages/constants/README.md index ad8c6615..16b756d0 100755 --- a/packages/constants/README.md +++ b/packages/constants/README.md @@ -177,10 +177,9 @@ Please consult the detail break down below. - LOGIN_EVENT_NAME - LOGOUT_EVENT_NAME - SA_LOGIN_EVENT_NAME -- RECONNECT_EVENT_NAME - SOCKET_CLIENT_ID_KEY - SOCKET_CLIENT_TS_KEY -- CONNECTED_EVENT_NAME +- CONNECT_EVENT_NAME - DISCONNECT_EVENT_NAME - INTERCOM_RESOLVER_NAME - INTER_COM_EVENT_NAMES diff --git a/packages/constants/browser.js b/packages/constants/browser.js index e6c842c1..17bcc231 100644 --- a/packages/constants/browser.js +++ b/packages/constants/browser.js @@ -175,14 +175,13 @@ var jsonqlConstants = { "LOGIN_EVENT_NAME": "__login__", "LOGOUT_EVENT_NAME": "__logout__", "SA_LOGIN_EVENT_NAME": "__standalone_login__", - "RECONNECT_EVENT_NAME": "__reconnect__", "SOCKET_CLIENT_ID_KEY": "__socket_client_id_key__", "SOCKET_CLIENT_TS_KEY": "__socket_client_ts_key__", - "CONNECTED_EVENT_NAME": "__connected__", + "CONNECT_EVENT_NAME": "__connect__", "DISCONNECT_EVENT_NAME": "__disconnect__", "INTERCOM_RESOLVER_NAME": "__intercom__", "INTER_COM_EVENT_NAMES": [ - "__connected__", + "__connect__", "__switch__", "__disconnect__" ], diff --git a/packages/constants/constants.json b/packages/constants/constants.json index 51a120b9..7f41310f 100644 --- a/packages/constants/constants.json +++ b/packages/constants/constants.json @@ -175,14 +175,13 @@ "LOGIN_EVENT_NAME": "__login__", "LOGOUT_EVENT_NAME": "__logout__", "SA_LOGIN_EVENT_NAME": "__standalone_login__", - "RECONNECT_EVENT_NAME": "__reconnect__", "SOCKET_CLIENT_ID_KEY": "__socket_client_id_key__", "SOCKET_CLIENT_TS_KEY": "__socket_client_ts_key__", - "CONNECTED_EVENT_NAME": "__connected__", + "CONNECT_EVENT_NAME": "__connect__", "DISCONNECT_EVENT_NAME": "__disconnect__", "INTERCOM_RESOLVER_NAME": "__intercom__", "INTER_COM_EVENT_NAMES": [ - "__connected__", + "__connect__", "__switch__", "__disconnect__" ], diff --git a/packages/constants/index.js b/packages/constants/index.js index a27d0f80..d7ab441b 100644 --- a/packages/constants/index.js +++ b/packages/constants/index.js @@ -255,8 +255,7 @@ export const LOGOUT_EVENT_NAME = '__logout__' // when ws switch on standalone mode then we add this event to allow // perform a standalone login method export const SA_LOGIN_EVENT_NAME = '__standalone_login__' -// after the user issue the disconnect, then we need a reconnect -export const RECONNECT_EVENT_NAME = '__reconnect__' + // when we receive the token and decode the userdata // we will inject two more properties into the userdata object export const SOCKET_CLIENT_ID_KEY = '__socket_client_id_key__' @@ -267,7 +266,7 @@ export const SOCKET_CLIENT_TS_KEY = '__socket_client_ts_key__' // connection, the following new event @1.9.2 will correct this edge case // although it should never happens, but in some edge case might want to // disconnect from the current server, then re-establish connection later -export const CONNECTED_EVENT_NAME = '__connected__' +export const CONNECT_EVENT_NAME = '__connect__' export const DISCONNECT_EVENT_NAME = '__disconnect__' // instead of using an event name in place of resolverName in the param // we use this internal resolverName instead, and in type using the event names @@ -276,7 +275,7 @@ export const INTERCOM_RESOLVER_NAME = '__intercom__' // to create a handler to handle this kind of event // export const INTER_COM_EVENT_NAME = '__inter_com__' export const INTER_COM_EVENT_NAMES = [ - CONNECTED_EVENT_NAME, + CONNECT_EVENT_NAME, SWITCH_USER_EVENT_NAME, DISCONNECT_EVENT_NAME ] diff --git a/packages/constants/main.js b/packages/constants/main.js index 59e4a33a..39e91445 100644 --- a/packages/constants/main.js +++ b/packages/constants/main.js @@ -175,14 +175,13 @@ module.exports = { "LOGIN_EVENT_NAME": "__login__", "LOGOUT_EVENT_NAME": "__logout__", "SA_LOGIN_EVENT_NAME": "__standalone_login__", - "RECONNECT_EVENT_NAME": "__reconnect__", "SOCKET_CLIENT_ID_KEY": "__socket_client_id_key__", "SOCKET_CLIENT_TS_KEY": "__socket_client_ts_key__", - "CONNECTED_EVENT_NAME": "__connected__", + "CONNECT_EVENT_NAME": "__connect__", "DISCONNECT_EVENT_NAME": "__disconnect__", "INTERCOM_RESOLVER_NAME": "__intercom__", "INTER_COM_EVENT_NAMES": [ - "__connected__", + "__connect__", "__switch__", "__disconnect__" ], diff --git a/packages/constants/socket.js b/packages/constants/socket.js index aade6988..670e7aec 100644 --- a/packages/constants/socket.js +++ b/packages/constants/socket.js @@ -29,7 +29,7 @@ export const INTERCOM_RESOLVER_NAME = '__intercom__' // to create a handler to handle this kind of event // export const INTER_COM_EVENT_NAME = '__inter_com__' export const INTER_COM_EVENT_NAMES = [ - CONNECTED_EVENT_NAME, + CONNECT_EVENT_NAME, SWITCH_USER_EVENT_NAME, DISCONNECT_EVENT_NAME ] -- Gitee