From 21dc3dc78668ebe18ae5974b0b6335a7939b7bb2 Mon Sep 17 00:00:00 2001 From: joelchu Date: Thu, 12 Mar 2020 16:56:25 +0800 Subject: [PATCH 01/45] using the NSP_GROUP to extract the info instead of hardcoded --- packages/ws-server-core/package.json | 6 +++--- packages/ws-server-core/src/handles/get-socket-handler.js | 5 +++-- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/packages/ws-server-core/package.json b/packages/ws-server-core/package.json index 31853e80..2fed94d9 100644 --- a/packages/ws-server-core/package.json +++ b/packages/ws-server-core/package.json @@ -1,6 +1,6 @@ { "name": "jsonql-ws-server-core", - "version": "0.7.3", + "version": "0.7.4", "description": "This is the core module that drive the Jsonql WS Socket server, not for direct use.", "main": "index.js", "files": [ @@ -30,12 +30,12 @@ "debug": "^4.1.1", "esm": "^3.2.25", "fs-extra": "^8.1.0", - "jsonql-constants": "^1.9.8", + "jsonql-constants": "^1.9.9", "jsonql-errors": "^1.1.10", "jsonql-jwt": "^1.3.9", "jsonql-params-validator": "^1.5.3", "jsonql-resolver": "^1.1.2", - "jsonql-utils": "^1.1.2", + "jsonql-utils": "^1.1.3", "lodash": "^4.17.15" }, "devDependencies": { 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 e5cc7f09..334683ac 100644 --- a/packages/ws-server-core/src/handles/get-socket-handler.js +++ b/packages/ws-server-core/src/handles/get-socket-handler.js @@ -1,7 +1,8 @@ const { LOGOUT_EVENT_NAME, SA_LOGIN_EVENT_NAME, - INTER_COM_EVENT_NAME + INTER_COM_EVENT_NAME, + NSP_GROUP } = require('jsonql-constants') const { getResolverFromPayload } = require('jsonql-utils') const { handleInterCom } = require('./handle-intercom') @@ -43,7 +44,7 @@ function matchResolverByNamespace(resolverName, namespace, nspGroup) { * @return {void} unless we throw an error */ function getSocketHandler(config, ws, deliverFn, req, connectedNamespace, payload, userdata) { - const { nspGroup } = config.nspInfo + const nspGroup = config.nspInfo[NSP_GROUP] const resolverName = getResolverFromPayload(payload) const args = payload[resolverName] // it might be the special internal event? -- Gitee From 9cdf1fab62698d81f0a46f31f6b6812569b34423 Mon Sep 17 00:00:00 2001 From: joelchu Date: Thu, 12 Mar 2020 18:51:19 +0800 Subject: [PATCH 02/45] remove unnecessary function calls --- packages/ws-server/package.json | 6 +++--- packages/ws-server/src/core/create-ws-server.js | 4 ++-- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/packages/ws-server/package.json b/packages/ws-server/package.json index c0f773fe..9e0c4815 100755 --- a/packages/ws-server/package.json +++ b/packages/ws-server/package.json @@ -1,6 +1,6 @@ { "name": "jsonql-ws-server", - "version": "1.7.1", + "version": "1.7.2", "description": "Setup WebSocket server for the jsonql to run on the same host, automatic generate public / private channel using contract", "main": "index.js", "files": [ @@ -31,8 +31,8 @@ "dependencies": { "colors": "^1.4.0", "debug": "^4.1.1", - "jsonql-utils": "^1.1.2", - "jsonql-ws-server-core": "^0.7.3", + "jsonql-utils": "^1.1.3", + "jsonql-ws-server-core": "^0.7.4", "ws": "^7.2.3" }, "devDependencies": { diff --git a/packages/ws-server/src/core/create-ws-server.js b/packages/ws-server/src/core/create-ws-server.js index 1850229d..78e9ce5e 100644 --- a/packages/ws-server/src/core/create-ws-server.js +++ b/packages/ws-server/src/core/create-ws-server.js @@ -1,5 +1,5 @@ // web socket server based on ws -const { getNamespace } = require('jsonql-utils') +// const { getNamespace } = require('jsonql-utils') const { createVerifyClient } = require('./security') const { getPath, getNspByPath } = require('../utils') const { getDebug, WebSocket } = require('../modules') @@ -12,7 +12,7 @@ const colors = require('colors/safe') * @return {array} of nsps */ const generateNsp = config => { - const namespaces = getNamespace(config) + const { namespaces } = config.nspInfo //getNamespace(config) return namespaces .map(name => { const verifyClient = createVerifyClient(name, config, config.publicKey) -- Gitee From 83dbfafbe8300bdce2d13ccc05cb2574429b0482 Mon Sep 17 00:00:00 2001 From: joelchu Date: Thu, 12 Mar 2020 20:05:13 +0800 Subject: [PATCH 03/45] verify the core callback are working correctly --- packages/ws-client-core/tests/tbd.test.js | 20 +++++++++++++++++--- 1 file changed, 17 insertions(+), 3 deletions(-) diff --git a/packages/ws-client-core/tests/tbd.test.js b/packages/ws-client-core/tests/tbd.test.js index 25c9dd30..16e9bdeb 100644 --- a/packages/ws-client-core/tests/tbd.test.js +++ b/packages/ws-client-core/tests/tbd.test.js @@ -6,11 +6,13 @@ const { mockClient, log } = require('./fixtures/lib/mock-client') const { ON_ERROR_FN_NAME, - ON_READY_FN_NAME + ON_READY_FN_NAME, + ON_LOGIN_FN_NAME } = require('jsonql-constants') test.before(async t => { t.context.client = await mockClient() + t.context.client1 = await mockClient(true) }) test.cb(`We should able to get a list of event register via the eventEmitter`, t => { @@ -24,10 +26,12 @@ test.cb(`We should able to get a list of event register via the eventEmitter`, t t.truthy(client) // note it's one name onError that will listen to all the nsp errors - client[ON_ERROR_FN_NAME] = function() { - log(`OnError callback added`) + client[ON_ERROR_FN_NAME] = function(err) { + log(`OnError callback added`, err) } + + // there is only one onReady call now client[ON_READY_FN_NAME] = function(msg) { log(`onError callback added`, msg) @@ -35,5 +39,15 @@ test.cb(`We should able to get a list of event register via the eventEmitter`, t t.end() return msg.replace('!',' news!') } +}) +test.cb(`Should able to listsen to the onLogin callback`, t => { + + t.plan(1) + + t.context.client1[ON_LOGIN_FN_NAME] = function(msg) { + log(`onLogin callback`, msg) + t.truthy(msg) + t.end() + } }) -- Gitee From c2162ba8787d943830d959ab3a2da1835b30dcfc Mon Sep 17 00:00:00 2001 From: joelchu Date: Thu, 12 Mar 2020 20:43:28 +0800 Subject: [PATCH 04/45] The things on this side are working fine --- .../ws-client-core/src/core/action-call.js | 2 +- packages/ws-client-core/tests/tbd.test.js | 40 +++++++++++++++++-- 2 files changed, 37 insertions(+), 5 deletions(-) diff --git a/packages/ws-client-core/src/core/action-call.js b/packages/ws-client-core/src/core/action-call.js index b02f22b8..298e2837 100644 --- a/packages/ws-client-core/src/core/action-call.js +++ b/packages/ws-client-core/src/core/action-call.js @@ -16,7 +16,7 @@ export function actionCall(ee, namespace, resolverName, args = [], log) { // reply event const outEventName = createEvt(namespace, EMIT_REPLY_TYPE) - log(`actionCall: ${eventName} --> ${resolverName}`, args) + log(`actionCall: ${outEventName} --> ${resolverName}`, args) // This is the out going call ee.$trigger(outEventName, [resolverName, toArray(args)]) diff --git a/packages/ws-client-core/tests/tbd.test.js b/packages/ws-client-core/tests/tbd.test.js index 16e9bdeb..9d417d65 100644 --- a/packages/ws-client-core/tests/tbd.test.js +++ b/packages/ws-client-core/tests/tbd.test.js @@ -3,12 +3,14 @@ // espcially debug the event system const test = require('ava') const { mockClient, log } = require('./fixtures/lib/mock-client') - +const { createEvt } = require('../src/utils') const { ON_ERROR_FN_NAME, ON_READY_FN_NAME, - ON_LOGIN_FN_NAME + ON_LOGIN_FN_NAME, + ON_RESULT_FN_NAME } = require('jsonql-constants') +// const { createWsReply } = require('jsonql-utils') test.before(async t => { t.context.client = await mockClient() @@ -30,8 +32,6 @@ test.cb(`We should able to get a list of event register via the eventEmitter`, t log(`OnError callback added`, err) } - - // there is only one onReady call now client[ON_READY_FN_NAME] = function(msg) { log(`onError callback added`, msg) @@ -51,3 +51,35 @@ test.cb(`Should able to listsen to the onLogin callback`, t => { t.end() } }) + + +test.cb(`Should able to call the socket function`, t => { + + const resolverName = 'sendExtraMsg' + + const namespace = 'jsonql' + + const evt = createEvt(namespace, resolverName, ON_RESULT_FN_NAME) + + t.plan(1) + + const ee = t.context.client.eventEmitter + + // log('EventEmitter', ee) + + t.context.client[resolverName](1) + .then(result => { + t.truthy(result) + t.end() + }) + .catch(err => { + log(err) + t.end() + }) + + setTimeout(() => { + + ee.$trigger(evt, [{data: 'na na na'}]) + }, 300) + +}) \ No newline at end of file -- Gitee From 4ef1b5c44e3e78403484b74e3c40e2cc0804198e Mon Sep 17 00:00:00 2001 From: joelchu Date: Thu, 12 Mar 2020 20:56:54 +0800 Subject: [PATCH 05/45] replace the process-contract with the new getNspInfoFromConfig --- packages/ws-client-core/src/options/index.js | 4 +- packages/ws-client-core/src/utils/index.js | 8 ++-- .../src/utils/process-contract.js | 37 ------------------- 3 files changed, 6 insertions(+), 43 deletions(-) delete mode 100644 packages/ws-client-core/src/utils/process-contract.js diff --git a/packages/ws-client-core/src/options/index.js b/packages/ws-client-core/src/options/index.js index d0aa7f61..c24da7b8 100644 --- a/packages/ws-client-core/src/options/index.js +++ b/packages/ws-client-core/src/options/index.js @@ -12,7 +12,7 @@ import { fixWss, getHostName, getEventEmitter, - processContract, + getNspInfoByConfig, getLogFn } from '../utils' @@ -72,7 +72,7 @@ function postCheckInjectOpts(opts) { function createRequiredParams(opts) { return { opts, - nspMap: processContract(opts), + nspMap: getNspInfoByConfig(opts.contract), ee: opts.eventEmitter } } diff --git a/packages/ws-client-core/src/utils/index.js b/packages/ws-client-core/src/utils/index.js index d035578f..1784e698 100644 --- a/packages/ws-client-core/src/utils/index.js +++ b/packages/ws-client-core/src/utils/index.js @@ -15,10 +15,10 @@ import { chainFns, chainPromises, objHasProp, - nil + nil, + getNspInfoByConfig } from 'jsonql-utils/module' -import processContract from './process-contract' import { fixWss, getHostName, @@ -44,8 +44,8 @@ export { chainPromises, objHasProp, nil, - - processContract, + getNspInfoByConfig, + fixWss, getHostName, diff --git a/packages/ws-client-core/src/utils/process-contract.js b/packages/ws-client-core/src/utils/process-contract.js deleted file mode 100644 index 674b9231..00000000 --- a/packages/ws-client-core/src/utils/process-contract.js +++ /dev/null @@ -1,37 +0,0 @@ -// mapping the resolver to their respective nsp -import { JSONQL_PATH, NSP_SET, PUBLIC_NAMESPACE } from 'jsonql-constants' -import { groupByNamespace, extractSocketPart } from 'jsonql-utils/module' -import { JsonqlResolverNotFoundError } from 'jsonql-errors' - -import { MISSING_PROP_ERR } from '../options/constants' - -/** - * Just make sure the object contain what we are looking for - * @param {object} opts configuration from checkOptions - * @return {object} the target content - */ -const getResolverList = contract => { - const result = extractSocketPart(contract) - if (result !== false) { - return result - } - throw new JsonqlResolverNotFoundError(MISSING_PROP_ERR) -} - -/** - * process the contract first - * @param {object} opts configuration - * @return {object} sorted list - */ -export default function processContract(opts) { - const { contract, enableAuth } = opts - if (enableAuth) { - return groupByNamespace(contract) - } - return { - [NSP_SET]: { - [JSONQL_PATH]: getResolverList(contract) - }, - [PUBLIC_NAMESPACE]: JSONQL_PATH - } -} -- Gitee From 0ba962b8f14c3d95153fe8e7907e7bf81fd8329f Mon Sep 17 00:00:00 2001 From: joelchu Date: Thu, 12 Mar 2020 23:12:05 +0800 Subject: [PATCH 06/45] fixed up the deps problem --- packages/ws-client-core/package.json | 8 ++++---- packages/ws-client-core/src/core/generator.js | 13 +++++++------ .../ws-client-core/src/core/resolver-methods.js | 16 ++++++++-------- packages/ws-client-core/src/options/index.js | 2 +- 4 files changed, 20 insertions(+), 19 deletions(-) diff --git a/packages/ws-client-core/package.json b/packages/ws-client-core/package.json index aa93a245..01d6649a 100644 --- a/packages/ws-client-core/package.json +++ b/packages/ws-client-core/package.json @@ -42,7 +42,7 @@ "require": [ "esm" ], - "cache": true, + "cache": false, "concurrency": 5, "failFast": true, "failWithoutAssertions": false, @@ -54,17 +54,17 @@ }, "dependencies": { "@to1source/event": "^1.0.0", - "jsonql-constants": "^1.9.8", + "jsonql-constants": "^1.9.9", "jsonql-errors": "^1.1.10", "jsonql-params-validator": "^1.5.3", - "jsonql-utils": "^1.1.2" + "jsonql-utils": "^1.1.3" }, "devDependencies": { "ava": "^3.5.0", "esm": "^3.2.25", "fs-extra": "^8.1.0", "jsonql-contract": "^1.8.8", - "jsonql-ws-server": "^1.7.1", + "jsonql-ws-server": "^1.7.2", "kefir": "^3.8.6", "ws": "^7.2.3" }, diff --git a/packages/ws-client-core/src/core/generator.js b/packages/ws-client-core/src/core/generator.js index be89b385..e71fec52 100644 --- a/packages/ws-client-core/src/core/generator.js +++ b/packages/ws-client-core/src/core/generator.js @@ -11,7 +11,9 @@ import { import { setupFinalStep } from './setup-final-step' - +import { + NSP_GROUP +} from 'jsonql-constants' /** * prepare the methods * @param {object} opts configuration @@ -21,14 +23,13 @@ import { * @public */ export function generator(opts, nspMap, ee) { - const { nspSet } = nspMap - const { enableAuth } = opts + let args = [ generateResolvers, createNamespaceErrorHandler, createOnReadyHandler ] - if (enableAuth) { + if (opts.enableAuth) { args.push( createAuthMethods ) @@ -36,8 +37,8 @@ export function generator(opts, nspMap, ee) { // we will always get back the [ obj, opts, ee ] // then we only return the obj (wsClient) args.push(setupFinalStep) - // run it const fn = Reflect.apply(chainFns, null, args) - return fn(opts, ee, nspSet) + + return fn(opts, ee, nspMap[NSP_GROUP]) } diff --git a/packages/ws-client-core/src/core/resolver-methods.js b/packages/ws-client-core/src/core/resolver-methods.js index fa323ee6..347f1e29 100644 --- a/packages/ws-client-core/src/core/resolver-methods.js +++ b/packages/ws-client-core/src/core/resolver-methods.js @@ -44,15 +44,15 @@ function createResolver(ee, namespace, resolverName, params, log) { * step one get the clientmap with the namespace * @param {object} opts configuration * @param {object} ee EventEmitter - * @param {object} nspSet resolvers index by their namespace + * @param {object} nspGroup resolvers index by their namespace * @return {promise} resolve the clientmapped, and start the chain */ -export function generateResolvers(opts, ee, nspSet) { +export function generateResolvers(opts, ee, nspGroup) { let client= {} let { log } = opts - for (let namespace in nspSet) { - let list = nspSet[namespace] + for (let namespace in nspGroup) { + let list = nspGroup[namespace] for (let resolverName in list) { // resolverNames.push(resolverName) let params = list[resolverName] @@ -64,7 +64,7 @@ export function generateResolvers(opts, ee, nspSet) { } // resolve the clientto start the chain // chain the result to allow the chain processing - return [ client, opts, ee, nspSet ] + return [ client, opts, ee, nspGroup ] } /** @@ -73,10 +73,10 @@ export function generateResolvers(opts, ee, nspSet) { * @param {object} clientthe client itself * @param {object} opts configuration * @param {object} ee Event Emitter - * @param {object} nspSet namespace keys + * @param {object} nspGroup namespace keys * @return {array} [obj, opts, ee] */ -export function createNamespaceErrorHandler(client, opts, ee, nspSet) { +export function createNamespaceErrorHandler(client, opts, ee, nspGroup) { return [ // using the onError as name // @TODO we should follow the convention earlier @@ -84,7 +84,7 @@ export function createNamespaceErrorHandler(client, opts, ee, nspSet) { objDefineProps(client, ON_ERROR_FN_NAME, function namespaceErrorCallbackHandler(namespaceErrorHandler) { if (isFunc(namespaceErrorHandler)) { // please note ON_ERROR_FN_NAME can add multiple listners - for (let namespace in nspSet) { + for (let namespace in nspGroup) { // this one is very tricky, we need to make sure the trigger is calling // with the namespace as well as the error ee.$on(createEvt(namespace, ON_ERROR_FN_NAME), namespaceErrorHandler) diff --git a/packages/ws-client-core/src/options/index.js b/packages/ws-client-core/src/options/index.js index c24da7b8..3a0d1f42 100644 --- a/packages/ws-client-core/src/options/index.js +++ b/packages/ws-client-core/src/options/index.js @@ -72,7 +72,7 @@ function postCheckInjectOpts(opts) { function createRequiredParams(opts) { return { opts, - nspMap: getNspInfoByConfig(opts.contract), + nspMap: getNspInfoByConfig(opts), ee: opts.eventEmitter } } -- Gitee From 28603414924c2f6a6a5689216a83c99355baa9cf Mon Sep 17 00:00:00 2001 From: joelchu Date: Fri, 13 Mar 2020 09:00:32 +0800 Subject: [PATCH 07/45] moving files around --- .../@jsonql/ws/dist/jsonql-ws-client.umd.js | 2 +- packages/@jsonql/ws/main.js | 2 +- packages/@jsonql/ws/node.js | 2 +- packages/@jsonql/ws/package.json | 8 ++-- packages/@jsonql/ws/src/core/create-nsp.js | 6 +-- .../@jsonql/ws/src/core/extract-ws-payload.js | 43 ------------------- .../@jsonql/ws/src/core/generate-ws-client.js | 14 ++++++ packages/@jsonql/ws/src/core/modules.js | 30 +++---------- .../ws/src/core/socket-event-handler.js | 5 +-- .../ws/src/{ => core}/ws-client-resolver.js | 4 +- packages/@jsonql/ws/src/node/stream-api.js | 2 +- .../koa/src/middlewares/auth-middleware.js | 4 +- 12 files changed, 38 insertions(+), 84 deletions(-) delete mode 100644 packages/@jsonql/ws/src/core/extract-ws-payload.js create mode 100644 packages/@jsonql/ws/src/core/generate-ws-client.js rename packages/@jsonql/ws/src/{ => core}/ws-client-resolver.js (80%) diff --git a/packages/@jsonql/ws/dist/jsonql-ws-client.umd.js b/packages/@jsonql/ws/dist/jsonql-ws-client.umd.js index fcef5215..f0602f89 100644 --- a/packages/@jsonql/ws/dist/jsonql-ws-client.umd.js +++ b/packages/@jsonql/ws/dist/jsonql-ws-client.umd.js @@ -1,2 +1,2 @@ -!function(t,e){"object"==typeof exports&&"undefined"!=typeof module?module.exports=e():"function"==typeof define&&define.amd?define(e):(t=t||self).jsonqlWsClient=e()}(this,(function(){"use strict";var t="undefined"!=typeof global?global:"undefined"!=typeof self?self:"undefined"!=typeof window?window:{},e="object"==typeof t&&t&&t.Object===Object&&t,r="object"==typeof self&&self&&self.Object===Object&&self,n=e||r||Function("return this")(),o=n.Symbol;function i(t,e){for(var r=-1,n=null==t?0:t.length,o=Array(n);++r=n?t:function(t,e,r){var n=-1,o=t.length;e<0&&(e=-e>o?0:o+e),(r=r>o?o:r)<0&&(r+=o),o=e>r?0:r-e>>>0,e>>>=0;for(var i=Array(o);++n-1;);return r}(n,o),function(t,e){for(var r=t.length;r--&&j(e,t[r],0)>-1;);return r}(n,o)+1).join("")}var M=function(t){return!!u(t)||null!=t&&""!==q(t)};function F(t){return function(t){return"number"==typeof t||v(t)&&"[object Number]"==h(t)}(t)&&t!=+t}function L(t){return"string"==typeof t||!u(t)&&v(t)&&"[object String]"==h(t)}var W=function(t){return!L(t)&&!F(parseFloat(t))},J=function(t){return""!==q(t)&&L(t)},D=function(t){return null!=t&&"boolean"==typeof t},U=function(t,e){return void 0===e&&(e=!0),void 0!==t&&""!==t&&""!==q(t)&&(!1===e||!0===e&&null!==t)},H=function(t){switch(t){case"number":return W;case"string":return J;case"boolean":return D;default:return U}},I=function(t,e){return void 0===e&&(e=""),!!u(t)&&(""===e||""===q(e)||!(t.filter((function(t){return!H(e)(t)})).length>0))},B=function(t){if(t.indexOf("array.<")>-1&&t.indexOf(">")>-1){var e=t.replace("array.<","").replace(">","");return e.indexOf("|")?e.split("|"):[e]}return!1},V=function(t,e){var r=t.arg;return e.length>1?!r.filter((function(t){return!(e.length>e.filter((function(e){return!H(e)(t)})).length)})).length:e.length>e.filter((function(t){return!I(r,t)})).length};function Y(t,e){return function(r){return t(e(r))}}var G=Y(Object.getPrototypeOf,Object),K=Function.prototype,Q=Object.prototype,X=K.toString,Z=Q.hasOwnProperty,tt=X.call(Object);function et(t){if(!v(t)||"[object Object]"!=h(t))return!1;var e=G(t);if(null===e)return!0;var r=Z.call(e,"constructor")&&e.constructor;return"function"==typeof r&&r instanceof r&&X.call(r)==tt}var rt,nt=function(t,e,r){for(var n=-1,o=Object(t),i=r(t),u=i.length;u--;){var a=i[rt?u:++n];if(!1===e(o[a],a,o))break}return t};function ot(t){return v(t)&&"[object Arguments]"==h(t)}var it=Object.prototype,ut=it.hasOwnProperty,at=it.propertyIsEnumerable,ct=ot(function(){return arguments}())?ot:function(t){return v(t)&&ut.call(t,"callee")&&!at.call(t,"callee")};var st="object"==typeof exports&&exports&&!exports.nodeType&&exports,ft=st&&"object"==typeof module&&module&&!module.nodeType&&module,lt=ft&&ft.exports===st?n.Buffer:void 0,pt=(lt?lt.isBuffer:void 0)||function(){return!1},ht=/^(?:0|[1-9]\d*)$/;function vt(t,e){var r=typeof t;return!!(e=null==e?9007199254740991:e)&&("number"==r||"symbol"!=r&&ht.test(t))&&t>-1&&t%1==0&&t-1&&t%1==0&&t<=9007199254740991}var dt={};dt["[object Float32Array]"]=dt["[object Float64Array]"]=dt["[object Int8Array]"]=dt["[object Int16Array]"]=dt["[object Int32Array]"]=dt["[object Uint8Array]"]=dt["[object Uint8ClampedArray]"]=dt["[object Uint16Array]"]=dt["[object Uint32Array]"]=!0,dt["[object Arguments]"]=dt["[object Array]"]=dt["[object ArrayBuffer]"]=dt["[object Boolean]"]=dt["[object DataView]"]=dt["[object Date]"]=dt["[object Error]"]=dt["[object Function]"]=dt["[object Map]"]=dt["[object Number]"]=dt["[object Object]"]=dt["[object RegExp]"]=dt["[object Set]"]=dt["[object String]"]=dt["[object WeakMap]"]=!1;var yt,_t="object"==typeof exports&&exports&&!exports.nodeType&&exports,bt=_t&&"object"==typeof module&&module&&!module.nodeType&&module,mt=bt&&bt.exports===_t&&e.process,jt=function(){try{var t=bt&&bt.require&&bt.require("util").types;return t||mt&&mt.binding&&mt.binding("util")}catch(t){}}(),wt=jt&&jt.isTypedArray,St=wt?(yt=wt,function(t){return yt(t)}):function(t){return v(t)&>(t.length)&&!!dt[h(t)]},Ot=Object.prototype.hasOwnProperty;function Et(t,e){var r=u(t),n=!r&&ct(t),o=!r&&!n&&pt(t),i=!r&&!n&&!o&&St(t),a=r||n||o||i,c=a?function(t,e){for(var r=-1,n=Array(t);++r-1},Ft.prototype.set=function(t,e){var r=this.__data__,n=qt(r,t);return n<0?(++this.size,r.push([t,e])):r[n][1]=e,this};var Lt,Wt=n["__core-js_shared__"],Jt=(Lt=/[^.]+$/.exec(Wt&&Wt.keys&&Wt.keys.IE_PROTO||""))?"Symbol(src)_1."+Lt:"";var Dt=Function.prototype.toString;function Ut(t){if(null!=t){try{return Dt.call(t)}catch(t){}try{return t+""}catch(t){}}return""}var Ht=/^\[object .+?Constructor\]$/,It=Function.prototype,Bt=Object.prototype,Vt=It.toString,Yt=Bt.hasOwnProperty,Gt=RegExp("^"+Vt.call(Yt).replace(/[\\^$.*+?()[\]{}|]/g,"\\$&").replace(/hasOwnProperty|(function).*?(?=\\\()| for .+?(?=\\\])/g,"$1.*?")+"$");function Kt(t){return!(!Pt(t)||function(t){return!!Jt&&Jt in t}(t))&&(xt(t)?Gt:Ht).test(Ut(t))}function Qt(t,e){var r=function(t,e){return null==t?void 0:t[e]}(t,e);return Kt(r)?r:void 0}var Xt=Qt(n,"Map"),Zt=Qt(Object,"create");var te=Object.prototype.hasOwnProperty;var ee=Object.prototype.hasOwnProperty;function re(t){var e=-1,r=null==t?0:t.length;for(this.clear();++ea))return!1;var s=i.get(t);if(s&&i.get(e))return s==e;var f=-1,l=!0,p=2&r?new ue:void 0;for(i.set(t,e),i.set(e,t);++fe.type.filter((function(t){var e;return void 0===r||(!1!==(e=B(t))?!V({arg:r},e):!H(t)(r))})).length)})).length}return!1},rr=function(t){function e(){for(var r=[],n=arguments.length;n--;)r[n]=arguments[n];t.apply(this,r),this.message=r[0],this.detail=r[1],this.className=e.name,t.captureStackTrace&&t.captureStackTrace(this,e)}t&&(e.__proto__=t),e.prototype=Object.create(t&&t.prototype),e.prototype.constructor=e;var r={name:{configurable:!0}};return r.name.get=function(){return"JsonqlValidationError"},Object.defineProperties(e,r),e}(Error),nr=function(t){function e(){for(var r=[],n=arguments.length;n--;)r[n]=arguments[n];t.apply(this,r),this.message=r[0],this.detail=r[1],this.className=e.name,t.captureStackTrace&&t.captureStackTrace(this,e)}t&&(e.__proto__=t),e.prototype=Object.create(t&&t.prototype),e.prototype.constructor=e;var r={name:{configurable:!0},statusCode:{configurable:!0}};return r.name.get=function(){return"JsonqlError"},r.statusCode.get=function(){return-1},Object.defineProperties(e,r),e}(Error),or=function(t,e){var r,n,o,i,u;switch(!0){case"object"===t:return o=(n=e).arg,i=n.param,u=[o],Array.isArray(i.keys)&&i.keys.length&&u.push(i.keys),!Reflect.apply(er,null,u);case"array"===t:return!I(e.arg);case!1!==(r=B(t)):return!V(e,r);default:return!H(t)(e.arg)}},ir=function(t,e){return void 0!==t?t:!0===e.optional&&void 0!==e.defaultvalue?e.defaultvalue:null},ur=function(t,e,r){var n;void 0===r&&(r=!1);var o=function(t,e){if(!I(e))throw new rr("params is not an array! Did something gone wrong when you generate the contract.json?");if(0===e.length)return[];if(!I(t))throw new rr("args is not an array! You might want to do: ES6 Array.from(arguments) or ES5 Array.prototype.slice.call(arguments)");switch(!0){case t.length==e.length:return t.map((function(t,r){return{arg:t,index:r,param:e[r]}}));case!0===e[0].variable:var r=e[0].type;return t.map((function(t,n){return{arg:t,index:n,param:e[n]||{type:r,name:"_"}}}));case t.lengthe.length:var n=e.length,o=["any"];return t.map((function(t,r){var i=r>=n||!!e[r].optional,u=e[r]||{type:o,name:"_"+r};return{arg:i?ir(t,u):t,index:r,param:u,optional:i}}));default:throw new nr("Could not understand your arguments and parameter structure!",{args:t,params:e})}}(t,e),i=o.filter((function(t){return!0===t.optional||!0===t.param.optional?function(t){var e=t.arg,r=t.param;return!!M(e)&&!(r.type.length>r.type.filter((function(e){return or(e,t)})).length)}(t):!(t.param.type.length>t.param.type.filter((function(e){return or(e,t)})).length)}));return r?((n={}).error=i,n.data=o.map((function(t){return t.arg})),n):i},ar=function(){try{var t=Qt(Object,"defineProperty");return t({},"",{}),t}catch(t){}}();function cr(t,e,r){"__proto__"==e&&ar?ar(t,e,{configurable:!0,enumerable:!0,value:r,writable:!0}):t[e]=r}function sr(t,e,r){(void 0===r||Ct(t[e],r))&&(void 0!==r||e in t)||cr(t,e,r)}var fr="object"==typeof exports&&exports&&!exports.nodeType&&exports,lr=fr&&"object"==typeof module&&module&&!module.nodeType&&module,pr=lr&&lr.exports===fr?n.Buffer:void 0,hr=pr?pr.allocUnsafe:void 0;function vr(t,e){var r,n,o=e?(r=t.buffer,n=new r.constructor(r.byteLength),new se(n).set(new se(r)),n):t.buffer;return new t.constructor(o,t.byteOffset,t.length)}var gr=Object.create,dr=function(){function t(){}return function(e){if(!Pt(e))return{};if(gr)return gr(e);t.prototype=e;var r=new t;return t.prototype=void 0,r}}();function yr(t,e){if(("constructor"!==e||"function"!=typeof t[e])&&"__proto__"!=e)return t[e]}var _r=Object.prototype.hasOwnProperty;function br(t,e,r){var n=t[e];_r.call(t,e)&&Ct(n,r)&&(void 0!==r||e in t)||cr(t,e,r)}var mr=Object.prototype.hasOwnProperty;function jr(t){if(!Pt(t))return function(t){var e=[];if(null!=t)for(var r in Object(t))e.push(r);return e}(t);var e=$t(t),r=[];for(var n in t)("constructor"!=n||!e&&mr.call(t,n))&&r.push(n);return r}function wr(t){return Nt(t)?Et(t,!0):jr(t)}function Sr(t){return function(t,e,r,n){var o=!r;r||(r={});for(var i=-1,u=e.length;++i0){if(++e>=800)return arguments[0]}else e=0;return t.apply(void 0,arguments)}}(Tr);function xr(t,e){return Pr(function(t,e,r){return e=$r(void 0===e?t.length-1:e,0),function(){for(var n=arguments,o=-1,i=$r(n.length-e,0),u=Array(i);++o1?e[n-1]:void 0,i=n>2?e[2]:void 0;for(o=Nr.length>3&&"function"==typeof o?(n--,o):void 0,i&&function(t,e,r){if(!Pt(r))return!1;var n=typeof e;return!!("number"==n?Nt(r)&&vt(e,r.length):"string"==n&&e in r)&&Ct(r[e],t)}(e[0],e[1],i)&&(o=n<3?void 0:o,n=1),t=Object(t);++r0;)e[r]=arguments[r+1];if(this.logger("($queue) get called"),!0===this.__suspend_state__){if(on(this.__pattern__)){var n=this.__pattern__.test(t);if(!n)return!1}this.logger("($queue) added to $queue",e),this.queueStore.add([t].concat(e))}return!!this.__suspend_state__},cn.$queues.get=function(){var t=this.queueStore.size;return this.logger("($queues)","size: "+t),t>0?Array.from(this.queueStore):[]},an.prototype.__suspend__=function(t){if("boolean"!=typeof t)throw new Error("$suspend only accept Boolean value! we got "+typeof t);var e=this.__suspend_state__;this.__suspend_state__=t,this.logger('($suspend) Change from "'+e+'" --\x3e "'+t+'"'),!0===e&&!1===t&&this.__release__()},an.prototype.__release__=function(){var t=this,e=this.queueStore.size,r=this.__pattern__;if(this.__pattern__=null,this.logger("(release) was called with "+e+(r?' for "'+r+'"':"")+" item"+(e>1?"s":"")),e>0){var n=Array.from(this.queueStore);this.queueStore.clear(),this.logger("(release queue)",n),n.forEach((function(e){t.logger(e),Reflect.apply(t.$trigger,t,e)})),this.logger("Release size "+this.queueStore.size)}return e},Object.defineProperties(an.prototype,cn);var sn=function(t){function e(e){if("function"!=typeof e)throw new Error("Just die here the logger is not a function!");e("---\x3e Create a new EventEmitter <---"),t.call(this,{logger:e})}t&&(e.__proto__=t),e.prototype=Object.create(t&&t.prototype),e.prototype.constructor=e;var r={name:{configurable:!0}};return r.name.get=function(){return"jsonql-ws-client-core"},Object.defineProperties(e.prototype,r),e}(function(t){function e(e){void 0===e&&(e={}),t.call(this,e)}t&&(e.__proto__=t),e.prototype=Object.create(t&&t.prototype),e.prototype.constructor=e;var r={$name:{configurable:!0},is:{configurable:!0},$done:{configurable:!0}};return e.prototype.logger=function(){},r.$name.get=function(){return"to1source-event"},r.is.get=function(){return this.$name},e.prototype.$on=function(t,e,r){var n=this;void 0===r&&(r=null);this.validate(t,e);var o=this.takeFromStore(t);if(!1===o)return this.logger('($on) "'+t+'" is not in lazy store'),this.addToNormalStore(t,"on",e,r);this.logger("($on) "+t+" found in lazy store");var i=0;return o.forEach((function(o){var u=o[0],a=o[1],c=o[2];if(c&&"on"!==c)throw new Error(en+" "+c);n.logger("($on)",'call run "'+t+'"'),n.run(e,u,r||a),i+=n.addToNormalStore(t,"on",e,r||a)})),this.logger("($on) return size "+i),i},e.prototype.$once=function(t,e,r){void 0===r&&(r=null),this.validate(t,e);var n=this.takeFromStore(t);this.normalStore;if(!1===n)return this.logger('($once) "'+t+'" is not in the lazy store'),this.addToNormalStore(t,"once",e,r);this.logger("($once)",n);var o=Array.from(n)[0],i=o[0],u=o[1],a=o[2];if(a&&"once"!==a)throw new Error(en+" "+a);this.logger("($once)",'call run "'+t+'"'),this.run(e,i,r||u),this.$off(t)},e.prototype.$only=function(t,e,r){var n=this;void 0===r&&(r=null),this.validate(t,e);var o=!1,i=this.takeFromStore(t);(this.normalStore.has(t)||(this.logger('($only) "'+t+'" add to normalStore'),o=this.addToNormalStore(t,"only",e,r)),!1!==i)&&(this.logger('($only) "'+t+'" found data in lazy store to execute'),Array.from(i).forEach((function(o){var i=o[0],u=o[1],a=o[2];if(a&&"only"!==a)throw new Error(en+" "+a);n.logger('($only) call run "'+t+'"'),n.run(e,i,r||u)})));return o},e.prototype.$onlyOnce=function(t,e,r){void 0===r&&(r=null),this.validate(t,e);var n=!1,o=this.takeFromStore(t);if(this.normalStore.has(t)||(this.logger('($onlyOnce) "'+t+'" add to normalStore'),n=this.addToNormalStore(t,"onlyOnce",e,r)),!1!==o){this.logger("($onlyOnce)",o);var i=Array.from(o)[0],u=i[0],a=i[1],c=i[2];if(c&&"onlyOnce"!==c)throw new Error(en+" "+c);this.logger('($onlyOnce) call run "'+t+'"'),this.run(e,u,r||a),this.$off(t)}return n},e.prototype.$replace=function(t,e,r,n){if(void 0===r&&(r=null),void 0===n&&(n="on"),this.validateType(n)){this.$off(t);var o=this["$"+n];return this.logger("($replace)",t,e),Reflect.apply(o,this,[t,e,r])}throw new Error(n+" is not supported!")},e.prototype.$trigger=function(t,e,r,n){void 0===e&&(e=[]),void 0===r&&(r=null),void 0===n&&(n=!1),this.validateEvt(t);var o=0,i=this.normalStore;if(this.logger("($trigger) normalStore",i),i.has(t)){if(this.logger('($trigger) "'+t+'" found'),this.$queue(t,e,r,n))return this.logger('($trigger) Currently suspended "'+t+'" added to queue, nothing executed. Exit now.'),!1;for(var u=Array.from(i.get(t)),a=u.length,c=!1,s=0;s0;)n[o]=arguments[o+2];if(t.has(e)?(this.logger('(addToStore) "'+e+'" existed'),r=t.get(e)):(this.logger('(addToStore) create new Set for "'+e+'"'),r=new Set),n.length>2)if(Array.isArray(n[0])){var i=n[2];this.checkTypeInLazyStore(e,i)||r.add(n)}else this.checkContentExist(n,r)||(this.logger("(addToStore) insert new",n),r.add(n));else r.add(n);return t.set(e,r),[t,r.size]},e.prototype.checkContentExist=function(t,e){return!!Array.from(e).filter((function(e){return e[0]===t[0]})).length},e.prototype.checkTypeInStore=function(t,e){this.validateEvt(t,e);var r=this.$get(t,!0);return!1===r||!r.filter((function(t){var r=t[3];return e!==r})).length},e.prototype.checkTypeInLazyStore=function(t,e){this.validateEvt(t,e);var r=this.lazyStore.get(t);return this.logger("(checkTypeInLazyStore)",r),!!r&&!!Array.from(r).filter((function(t){return t[2]!==e})).length},e.prototype.addToNormalStore=function(t,e,r,n){if(void 0===n&&(n=null),this.logger('(addToNormalStore) try to add "'+e+'" --\x3e "'+t+'" to normal store'),this.checkTypeInStore(t,e)){this.logger("(addToNormalStore)",'"'+e+'" --\x3e "'+t+'" can add to normal store');var o=this.hashFnToKey(r),i=[this.normalStore,t,o,r,n,e],u=Reflect.apply(this.addToStore,this,i),a=u[0],c=u[1];return this.normalStore=a,c}return!1},e.prototype.addToLazyStore=function(t,e,r,n){void 0===e&&(e=[]),void 0===r&&(r=null),void 0===n&&(n=!1);var o=[this.lazyStore,t,this.toArray(e),r];n&&o.push(n);var i=Reflect.apply(this.addToStore,this,o),u=i[0],a=i[1];return this.lazyStore=u,this.logger("(addToLazyStore) size: "+a),a},e.prototype.toArray=function(t){return Array.isArray(t)?t:[t]},r.normalStore.set=function(t){rn.set(this,t)},r.normalStore.get=function(){return rn.get(this)},r.lazyStore.set=function(t){nn.set(this,t)},r.lazyStore.get=function(){return nn.get(this)},e.prototype.hashFnToKey=function(t){return function(t){return t.split("").reduce((function(t,e){return(t=(t<<5)-t+e.charCodeAt(0))&t}),0)}(t.toString())+""},Object.defineProperties(e.prototype,r),e}(an))),fn=function(t){return u(t)?t:[t]},ln=function(t,e){try{var r=Object.keys(t);return n=e,!!r.filter((function(t){return t===n})).length}catch(t){return!1}var n},pn=function(){for(var t=[],e=arguments.length;e--;)t[e]=arguments[e];return t.join("_")},hn=function(t){if("function"==typeof t)return!0;console.error("Expect to be Function type! Got "+typeof t)},vn=function(){return!1},gn=function(t){for(var e=[],r=arguments.length-1;r-- >0;)e[r]=arguments[r+1];return function(){for(var r=[],n=arguments.length;n--;)r[n]=arguments[n];return e.reduce((function(t,e){return Reflect.apply(e,null,fn(t))}),Reflect.apply(t,null,r))}};function dn(t,e,r,n){return void 0===n&&(n=null),void 0===Object.getOwnPropertyDescriptor(t,e)&&Object.defineProperty(t,e,{set:r,get:null===n?function(){return null}:n}),t}function yn(t,e,r,n){void 0===n&&(n=!1);var o=function(t,e){var r=Object.getOwnPropertyDescriptor(t,e);return void 0!==r&&r.value?r.value:r}(t,e);return!1===n&&void 0!==o||Object.defineProperty(t,e,{value:r,writable:n}),t}var _n=function(t){function e(){for(var r=[],n=arguments.length;n--;)r[n]=arguments[n];t.apply(this,r),this.message=r[0],this.detail=r[1],this.className=e.name,t.captureStackTrace&&t.captureStackTrace(this,e)}t&&(e.__proto__=t),e.prototype=Object.create(t&&t.prototype),e.prototype.constructor=e;var r={statusCode:{configurable:!0},name:{configurable:!0}};return r.statusCode.get=function(){return 406},r.name.get=function(){return"Jsonql406Error"},Object.defineProperties(e,r),e}(Error),bn=function(t){function e(){for(var r=[],n=arguments.length;n--;)r[n]=arguments[n];t.apply(this,r),this.message=r[0],this.detail=r[1],this.className=e.name,t.captureStackTrace&&t.captureStackTrace(this,e)}t&&(e.__proto__=t),e.prototype=Object.create(t&&t.prototype),e.prototype.constructor=e;var r={statusCode:{configurable:!0},name:{configurable:!0}};return r.statusCode.get=function(){return 500},r.name.get=function(){return"Jsonql500Error"},Object.defineProperties(e,r),e}(Error),mn=function(t){function e(){for(var r=[],n=arguments.length;n--;)r[n]=arguments[n];t.apply(this,r),this.message=r[0],this.detail=r[1],this.className=e.name,t.captureStackTrace&&t.captureStackTrace(this,e)}t&&(e.__proto__=t),e.prototype=Object.create(t&&t.prototype),e.prototype.constructor=e;var r={statusCode:{configurable:!0},name:{configurable:!0}};return r.statusCode.get=function(){return 403},r.name.get=function(){return"JsonqlForbiddenError"},Object.defineProperties(e,r),e}(Error),jn=function(t){function e(){for(var r=[],n=arguments.length;n--;)r[n]=arguments[n];t.apply(this,r),this.message=r[0],this.detail=r[1],this.className=e.name,t.captureStackTrace&&t.captureStackTrace(this,e)}t&&(e.__proto__=t),e.prototype=Object.create(t&&t.prototype),e.prototype.constructor=e;var r={statusCode:{configurable:!0},name:{configurable:!0}};return r.statusCode.get=function(){return 401},r.name.get=function(){return"JsonqlAuthorisationError"},Object.defineProperties(e,r),e}(Error),wn=function(t){function e(){for(var r=[],n=arguments.length;n--;)r[n]=arguments[n];t.apply(this,r),this.message=r[0],this.detail=r[1],this.className=e.name,t.captureStackTrace&&t.captureStackTrace(this,e)}t&&(e.__proto__=t),e.prototype=Object.create(t&&t.prototype),e.prototype.constructor=e;var r={statusCode:{configurable:!0},name:{configurable:!0}};return r.statusCode.get=function(){return 401},r.name.get=function(){return"JsonqlContractAuthError"},Object.defineProperties(e,r),e}(Error),Sn=function(t){function e(){for(var r=[],n=arguments.length;n--;)r[n]=arguments[n];t.apply(this,r),this.message=r[0],this.detail=r[1],this.className=e.name,t.captureStackTrace&&t.captureStackTrace(this,e)}t&&(e.__proto__=t),e.prototype=Object.create(t&&t.prototype),e.prototype.constructor=e;var r={statusCode:{configurable:!0},name:{configurable:!0}};return r.statusCode.get=function(){return 500},r.name.get=function(){return"JsonqlResolverAppError"},Object.defineProperties(e,r),e}(Error),On=function(t){function e(){for(var r=[],n=arguments.length;n--;)r[n]=arguments[n];t.apply(this,r),this.message=r[0],this.detail=r[1],this.className=e.name,t.captureStackTrace&&t.captureStackTrace(this,e)}t&&(e.__proto__=t),e.prototype=Object.create(t&&t.prototype),e.prototype.constructor=e;var r={statusCode:{configurable:!0},name:{configurable:!0}};return r.statusCode.get=function(){return 404},r.name.get=function(){return"JsonqlResolverNotFoundError"},Object.defineProperties(e,r),e}(Error),En=function(t){function e(r,n){t.call(this,n),this.statusCode=r,this.className=e.name}t&&(e.__proto__=t),e.prototype=Object.create(t&&t.prototype),e.prototype.constructor=e;var r={name:{configurable:!0}};return r.name.get=function(){return"JsonqlServerError"},Object.defineProperties(e,r),e}(Error);function kn(t){if(Array.isArray(t))throw new rr("",t);var e=t.message||"No message",r=t.detail||t;switch(!0){case t instanceof _n:throw new _n(e,r);case t instanceof bn:throw new bn(e,r);case t instanceof mn:throw new mn(e,r);case t instanceof jn:throw new jn(e,r);case t instanceof wn:throw new wn(e,r);case t instanceof Sn:throw new Sn(e,r);case t instanceof On:throw new On(e,r);case t instanceof Ur:throw new Ur(e,r);case t instanceof Hr:throw new Hr(e,r);case t instanceof Ir:throw new Ir(e,r);case t instanceof rr:throw new rr(e,r);case t instanceof En:throw new En(e,r);default:throw new nr(e,r)}}function $n(t){return!!ln(t,"socket")&&t.socket}function Tn(t){var e,r,n=t.contract;return t.enableAuth?function(t){var e=$n(t);if(!1===e)throw new JsonqlError("groupByNamespace","socket not found in contract!");var r,n={},o=0;for(var i in e){var u=e[i],a=u.namespace;a&&(n[a]||(++o,n[a]={}),n[a][i]=u,!r&&u.public&&(r=a))}return{size:o,nspGroup:n,publicNamespace:r}}(n):((r={}).nspSet=((e={}).jsonql=function(t){var e=$n(t);if(!1!==e)return e;throw new On("Missing property in contract!")}(n),e),r.publicNamespace="jsonql",r)}var An=function(t){var e=t.toLowerCase();return e.indexOf("http")>-1?e.indexOf("https")>-1?e.replace("https","wss"):e.replace("http","ws"):e},Pn=function(t,e){fn(e).forEach((function(e){t.$off(pn(e,"emit_reply"))}))},xn=function(t,e,r){return[yn(t,e.loginHandlerName,(function(t){if(t&&Gr(t))return e.log("Received __login__ with "+t),r.$trigger("__login__",[t]);throw new rr(e.loginHandlerName,"Unexpected token "+t)})),e,r]},Nn=function(t,e,r){return[yn(t,e.logoutHandlerName,(function(){for(var t=[],e=arguments.length;e--;)t[e]=arguments[e];r.$trigger("__logout__",t)})),e,r]},zn=function(t,e,r){return[dn(t,"onLogin",(function(t){hn(t)&&r.$only("onLogin",t)})),e,r]};function Rn(t,e,r){return gn(xn,Nn,zn)(t,e,r)}function Cn(t,e,r){ln(t,"error")?r(t.error):ln(t,"data")?e(t.data):r({message:"UKNNOWN RESULT!",error:t})}function qn(t,e,r,n,o){void 0===n&&(n=[]);var i=pn(e,"emit_reply");return o("actionCall: "+i+" --\x3e "+r,n),t.$trigger(i,[r,fn(n)]),new Promise((function(n,i){t.$on(pn(e,r,"onResult"),(function(t){o("got the first result",t),Cn(t,n,i)}))}))}var Mn,Fn,Ln,Wn=function(t,e,r,n,o,i){return dn(t,"send",vn,(function(){var t=function(){for(var t=[],e=arguments.length;e--;)t[e]=arguments[e];return Reflect.apply(console.info,console,["[SEND]"].concat(t))};return function(){for(var i=[],u=arguments.length;u--;)i[u]=arguments[u];return Kr(i,o.params,!0).then((function(o){return t(r,n,o),qn(e,r,n,o,t)})).catch((function(o){t("send error",o),e.$call(pn(r,n,"onError"),[new rr(n,o)])}))}}))},Jn=function(t,e,r,n,o,i){return[yn(t,"myNamespace",r),e,r,n,o,i]},Dn=function(t,e,r,n,o,i){return[dn(t,"onResult",(function(t){hn(t)&&e.$on(pn(r,n,"onResult"),(function(o){Cn(o,t,(function(t){i('Catch error: "'+n+'"',t),e.$trigger(pn(r,n,"onError"),t)}))}))})),e,r,n,o,i]},Un=function(t,e,r,n,o,i){return[dn(t,"onMessage",(function(t){if(hn(t)){e.$only(pn(r,n,"onMessage"),(function(o){Cn(o,t,(function(t){i('Catch error: "'+n+'"',t),e.$trigger(pn(r,n,"onError"),t)}))}))}})),e,r,n,o,i]},Hn=function(t,e,r,n,o,i){return[dn(t,"onError",(function(t){hn(t)&&e.$only(pn(r,n,"onError"),t)})),e,r,n,o,i]};function In(t,e,r,n,o,i){var u=[Jn,Dn,Un,Hn,Wn],a=Reflect.apply(gn,null,u),c=[n,o,t,e,r,i];return Reflect.apply(a,null,c)}function Bn(t,e,r,n,o){return function(){for(var i=[],u=arguments.length;u--;)i[u]=arguments[u];return Kr(i,n.params,!0).then((function(n){return qn(t,e,r,n,o)})).catch(kn)}}function Vn(t,e,r){var n={},o=t.log;for(var i in r){var u=r[i];for(var a in u){var c=u[a];n=yn(n,a,In(i,a,c,Bn(e,i,a,c,o),e,o))}}return[n,t,e,r]}function Yn(t,e,r,n){return[dn(t,"onError",(function(t){if(hn(t))for(var e in n)r.$on(pn(e,"onError"),t)})),e,r]}function Gn(t,e,r){return[dn(t,"onReady",(function(t){hn(t)&&r.$on("onReady",t)})),e,r]}function Kn(t,e,r){var n=function(t,e,r){return yn(t,e.disconnectHandlerName,(function(){for(var t=[],e=arguments.length;e--;)t[e]=arguments[e];r.$trigger("__disconnect__",t)}))}(t,e,r);return e.log("---\x3e The final step to return the ws-client <---"),n.verifyEventEmitter=function(){return r.is},n.eventEmitter=e.eventEmitter,n.log=e.log,n}var Qn=["roundtip","handshake"],Xn={standalone:Qr(!1,["boolean"]),debugOn:Qr(!1,["boolean"]),loginHandlerName:Qr("login",["string"]),logoutHandlerName:Qr("logout",["string"]),disconnectHandlerName:Qr("disconnect",["string"]),switchUserHandlerName:Qr("switch-user",["string"]),loginMethod:Qr("handshake",["string"],(Mn={},Mn.enumv=Qn,Mn)),useJwt:Qr(!0,["boolean","string"]),authStrKey:Qr(null,["string"]),hostname:Qr(!1,["string"]),namespace:Qr("jsonql",["string"]),wsOptions:Qr({},["object"]),contract:Qr({},["object"],(Fn={},Fn.checker=function(t){return!!function(t){return et(t)&&(ln(t,"query")||ln(t,"mutation")||ln(t,"socket"))}(t)&&t},Fn)),enableAuth:Qr(!1,["boolean"]),token:Qr(!1,["string"])},Zn={};Zn.serverType=Qr(null,["string"],((Ln={}).alias="socketClientType",Ln));var to=Object.assign(Xn,Zn),eo={log:null,eventEmitter:null,nspClient:null,nspAuthClient:null,wssPath:""};function ro(t){return Promise.resolve(t).then((function(t){return t.hostname||(t.hostname=function(){try{return[window.location.protocol,window.location.host].join("//")}catch(t){throw new rr(t)}}()),t.wssPath=An([t.hostname,t.namespace].join("/"),t.serverType),t.log=tn(t),t.eventEmitter=function(t){var e=t.log,r=t.eventEmitter;return r?(e("eventEmitter is:",r.name),r):new sn(t.log)}(t),t}))}function no(t){return{opts:t,nspMap:Tn(t),ee:t.eventEmitter}}function oo(t,e){return ro(e).then(no).then((function(e){var r=e.opts,n=e.nspMap,o=e.ee;return t(r,n,o)})).then((function(t){return function(t,e,r){var n=e.nspSet,o=[Vn,Yn,Gn];return t.enableAuth&&o.push(Rn),o.push(Kn),Reflect.apply(gn,null,o)(t,r,n)}(t.opts,t.nspMap,t.ee)})).catch((function(t){console.error("jsonql-ws-core-client init error",t)}))}function io(t,e,r){return void 0===e&&(e={}),void 0===r&&(r={}),function(n){return void 0===n&&(n={}),function(t,e,r){var n=Object.assign(eo,r),o=Object.assign(to,e);return Xr(t,o,n)}(n,e,r).then((function(e){return oo(t,e)}))}}function uo(t,e){var r=e.hostname,n=e.wssPath,o=e.wsOptions;return(0,e.nspClient)(t?[r,t].join("/"):n,o)}function ao(t,e,r){e.forEach((function(e){t.$trigger(pn(e,"onError"),[{message:r,namespace:e}])}))}var co=function(t,e,r){var n=r.log;e.$only(pn(t,"emit_reply"),(function(r,o){n("[notLoginHandler] hijack the ws call",t,r,o);var i={message:"NOT LOGIN"};e.$call(pn(t,r,"onError"),[i]),e.$call(pn(t,r,"onResult"),[{error:i}])}))},so=function(t){return t.length>1&&t[0]},fo=function(t,e,r,n){var o=n.log;r.$on("__disconnect__",(function(){ao(r,e,"__disconnect__"),e.forEach((function(e){o("disconnect from "+e),Pn(r,e),t[e]=null,function(t,e,r){var n=r.log;e.$only(pn(t,"emit_reply"),(function(r,o){n("[disconnectedHandler] hijack the ws call",t,r,o);var i={message:"You have disconnected from the socket server, please reconnect."};e.$call(pn(t,r,"onError"),[i]),e.$call(pn(t,r,"onResult"),[{error:i}])}))}(e,r,n)}))}))};function lo(t,e,r,n,o,i){var u=so(o),a=!1,c=!1,s=t.log;o.forEach((function(o){if(a=u===o,c||(c=a),i[o]){s("[call bindWsHandler]",a,o);var f=[o,i[o],r,a,t];if("socket.io"===t.serverType){var l=e.nspSet;f.push(l[o])}Reflect.apply(n,null,f)}else co(o,r,t)})),c&&(s("Has private and add logoutEvtHandler"),function(t,e,r,n){var o=n.log;r.$on("__logout__",(function(){var i=so(e);o("__logout__ event triggered"),ao(r,[i],"__logout__"),o("logout from "+i),Pn(r,i),t[i]=null,co(i,r,n)}))}(i,o,r,t)),fo(i,o,r,t)}var po={version:"version: 1.1.1 module: umd",serverType:"ws"},ho=Object.assign({},to,{}),vo=Object.assign({},eo,po),go=null;"undefined"!=typeof WebSocket?go=WebSocket:"undefined"!=typeof MozWebSocket?go=MozWebSocket:void 0!==t?go=t.WebSocket||t.MozWebSocket:"undefined"!=typeof window?go=window.WebSocket||window.MozWebSocket:"undefined"!=typeof self&&(go=self.WebSocket||self.MozWebSocket);var yo=go;function _o(t,e){return void 0===e&&(e=!1),!1===e?function(e){return new t(An(e))}:function(e,r){var n=An(e),o=r&&"string"==typeof r?n+"?token="+r:n;try{return new t(o)}catch(t){return console.error("WebSocket Connection Error",t),!1}}}var bo=Array.isArray,mo="object"==typeof t&&t&&t.Object===Object&&t,jo="object"==typeof self&&self&&self.Object===Object&&self,wo=(mo||jo||Function("return this")()).Symbol,So=Object.prototype,Oo=So.hasOwnProperty,Eo=So.toString,ko=wo?wo.toStringTag:void 0;var $o=Object.prototype.toString;var To=wo?wo.toStringTag:void 0;function Ao(t){return null==t?void 0===t?"[object Undefined]":"[object Null]":To&&To in Object(t)?function(t){var e=Oo.call(t,ko),r=t[ko];try{t[ko]=void 0;var n=!0}catch(t){}var o=Eo.call(t);return n&&(e?t[ko]=r:delete t[ko]),o}(t):function(t){return $o.call(t)}(t)}function Po(t){return null!=t&&"object"==typeof t}var xo=wo?wo.prototype:void 0,No=xo?xo.toString:void 0;function zo(t){if("string"==typeof t)return t;if(bo(t))return function(t,e){for(var r=-1,n=null==t?0:t.length,o=Array(n);++r=n?t:function(t,e,r){var n=-1,o=t.length;e<0&&(e=-e>o?0:o+e),(r=r>o?o:r)<0&&(r+=o),o=e>r?0:r-e>>>0,e>>>=0;for(var i=Array(o);++n-1;);return r}(o,i),function(t,e){for(var r=t.length;r--&&qo(e,t[r],0)>-1;);return r}(o,i)+1).join("")}var Qo=function(){for(var t=[],e=arguments.length;e--;)t[e]=arguments[e];return t.join("_")},Xo=function(t){function e(){for(var r=[],n=arguments.length;n--;)r[n]=arguments[n];t.apply(this,r),this.message=r[0],this.detail=r[1],this.className=e.name,t.captureStackTrace&&t.captureStackTrace(this,e)}t&&(e.__proto__=t),e.prototype=Object.create(t&&t.prototype),e.prototype.constructor=e;var r={name:{configurable:!0}};return r.name.get=function(){return"JsonqlValidationError"},Object.defineProperties(e,r),e}(Error),Zo=function(t){function e(){for(var r=[],n=arguments.length;n--;)r[n]=arguments[n];t.apply(this,r),this.message=r[0],this.detail=r[1],this.className=e.name,t.captureStackTrace&&t.captureStackTrace(this,e)}t&&(e.__proto__=t),e.prototype=Object.create(t&&t.prototype),e.prototype.constructor=e;var r={name:{configurable:!0},statusCode:{configurable:!0}};return r.name.get=function(){return"JsonqlError"},r.statusCode.get=function(){return-1},Object.defineProperties(e,r),e}(Error),ti=function(t){void 0===t&&(t=!1);var e=Date.now();return t?Math.floor(e/1e3):e};function ei(t){return"string"==typeof t||!bo(t)&&Po(t)&&"[object String]"==Ao(t)}function ri(t,e,r){if(void 0===e&&(e=[]),void 0===r&&(r=!1),ei(t)&&bo(e)){var n=function(t){var e;return(e={}).args=t,e}(e);return!0===r?n:function(t,e){var r;return(r={})[t]=e,r.TS=[ti()],r}(t,n)}throw new Xo("[createQuery] expect resolverName to be string and args to be array!",{resolverName:t,args:e})}var ni=function(t){return""!==Ko(t)&&ei(t)},oi=["__reply__","__event__","__data__"],ii=function(t){var e=t.data;return!!e&&(oi.filter((function(t){return function(t,e){try{var r=Object.keys(t);return n=e,!!r.filter((function(t){return t===n})).length}catch(t){return!1}var n}(e,t)})).length===oi.length&&e)},ui=function(t,e,r,n,o){var i=[e];r&&i.push(r),i.push(o);var u=Reflect.apply(Qo,null,i),a=n.data||n;t.$trigger(u,[a])};function ai(t,e,r,n,o){var i=function(){for(var t=[],e=arguments.length;e--;)t[e]=arguments[e];return Reflect.apply(console.info,console,["[socketEventHandler]"].concat(t))};i("log test, isPrivate:",n),e.onopen=function(){i("ws.onopen listened"),r.$call("onReady",t),n&&(i("isPrivate and fire the onLogin"),r.$call("onLogin",t)),r.$only(Qo(t,"emit_reply"),(function(t,r){var n=function(t,e,r){return void 0===e&&(e=[]),void 0===r&&(r=!1),JSON.stringify(ri(t,e,r))}(t,r);i("calling server",t,r,n),e.send(n)}))},e.onmessage=function(e){try{var n=function(t){var e,r=t.data,n=ni(r)?JSON.parse(r):r;if(!1!==(e=ii(n)))return{resolverName:e.__event__,data:e.__data__,type:e.__reply__};throw new Zo("payload can not be decoded",t)}(e),o=n.resolverName,u=n.type;switch(i("Hear from server",u,n),u){case"emit_reply":var a=Qo(t,o,"onMessage"),c=r.$trigger(a,[n]);i("EMIT_REPLY_TYPE",a,c);break;case"acknowledge_reply":var s=Qo(t,o,"onResult"),f=r.$trigger(s,[n]);i("ACKNOWLEDGE_REPLY_TYPE",s,f);break;case"error":i("ERROR_TYPE"),ui(r,t,o,n,"onError");break;default:i("Unhandled event!",n),ui(r,t,o,n,"onError")}}catch(e){console.error("ws.onmessage error",e),ui(r,t,!1,e,"onError")}},e.onclose=function(){i("ws.onclose callback")},e.onerror=function(e){i("ws.onerror",e),r.$trigger(Qo(t,"onError"),[e])},n&&r.$on("__logout__",(function(){try{i("terminate ws connection"),e.terminate()}catch(t){console.error("ws.terminate error",t)}}))}var ci=function(t,e,r){var n,o=t.log,i=e.nspSet,u=e.publicNamespace,a=!1,c=[],s={};if(t.enableAuth)a=!0,s=(c=function(t,e){var r=[];for(var n in t)n===e?r[1]=n:r[0]=n;return r}(i,u)).map((function(e,n){var i,u,a;return 0===n?r?(t.token=r,o("create createNspAuthClient at run time"),(i={})[e]=function(t,e){var r=e.hostname,n=e.wssPath,o=e.token,i=e.wsOptions,u=e.nspAuthClient,a=t?[r,t].join("/"):n;if(o&&"string"!=typeof o)throw new Error("Expect token to be string, but got "+o);return u(a,o,i)}(e,t),i):((u={})[e]=!1,u):((a={})[e]=uo(e,t),a)})).reduce((function(t,e){return Object.assign(t,e)}),{});else{var f=(n=i,console.error("This method is going to be deprectead in the next release, please use getResolverFromPayload instead"),Object.keys(n)[0]);c.push(f),s[f]=uo(!1,t)}return{nsps:s,namespaces:c,loginRequired:a}};function si(t,e,r,n){var o=n.log;t.$only("__login__",(function(i){o("createClient LOGIN_EVENT_NAME $only handler"),Pn(t,e);var u=ci(n,r,i);Reflect.apply(lo,null,args.concat([u.namespaces,u.nsps]))}))}var fi,li,pi,hi=(li=_o(fi=yo),pi=_o(fi,!0),function(t,e,r){t.nspClient=li,t.nspAuthClient=pi;var n=t.log;return n&&"function"==typeof n&&(n("@jsonql/ws ee",r.name),n("@jsonql/ws createClientResolver",t)),function(t,e,r){var n=[t,e,r,ai],o=t.token,i=(t.log,ci(t,e,o)),u=i.nsps,a=i.namespaces,c=i.loginRequired;return Reflect.apply(lo,null,n.concat([a,u])),c&&si(r,a,e,t),{opts:t,nspMap:e,ee:r}}(t,e,r)});return function(t,e){return void 0===t&&(t={}),void 0===e&&(e={}),io(hi,ho,Object.assign({},vo,e))(t)}})); +!function(t,e){"object"==typeof exports&&"undefined"!=typeof module?module.exports=e():"function"==typeof define&&define.amd?define(e):(t=t||self).jsonqlWsClient=e()}(this,(function(){"use strict";var t="undefined"!=typeof global?global:"undefined"!=typeof self?self:"undefined"!=typeof window?window:{},e="object"==typeof t&&t&&t.Object===Object&&t,r="object"==typeof self&&self&&self.Object===Object&&self,n=e||r||Function("return this")(),o=n.Symbol;function i(t,e){for(var r=-1,n=null==t?0:t.length,o=Array(n);++r=n?t:function(t,e,r){var n=-1,o=t.length;e<0&&(e=-e>o?0:o+e),(r=r>o?o:r)<0&&(r+=o),o=e>r?0:r-e>>>0,e>>>=0;for(var i=Array(o);++n-1;);return r}(n,o),function(t,e){for(var r=t.length;r--&&j(e,t[r],0)>-1;);return r}(n,o)+1).join("")}var F=function(t){return!!a(t)||null!=t&&""!==q(t)};function M(t){return function(t){return"number"==typeof t||v(t)&&"[object Number]"==h(t)}(t)&&t!=+t}function L(t){return"string"==typeof t||!a(t)&&v(t)&&"[object String]"==h(t)}var W=function(t){return!L(t)&&!M(parseFloat(t))},J=function(t){return""!==q(t)&&L(t)},U=function(t){return null!=t&&"boolean"==typeof t},D=function(t,e){return void 0===e&&(e=!0),void 0!==t&&""!==t&&""!==q(t)&&(!1===e||!0===e&&null!==t)},H=function(t){switch(t){case"number":return W;case"string":return J;case"boolean":return U;default:return D}},I=function(t,e){return void 0===e&&(e=""),!!a(t)&&(""===e||""===q(e)||!(t.filter((function(t){return!H(e)(t)})).length>0))},G=function(t){if(t.indexOf("array.<")>-1&&t.indexOf(">")>-1){var e=t.replace("array.<","").replace(">","");return e.indexOf("|")?e.split("|"):[e]}return!1},B=function(t,e){var r=t.arg;return e.length>1?!r.filter((function(t){return!(e.length>e.filter((function(e){return!H(e)(t)})).length)})).length:e.length>e.filter((function(t){return!I(r,t)})).length};function V(t,e){return function(r){return t(e(r))}}var Y=V(Object.getPrototypeOf,Object),K=Function.prototype,Q=Object.prototype,X=K.toString,Z=Q.hasOwnProperty,tt=X.call(Object);function et(t){if(!v(t)||"[object Object]"!=h(t))return!1;var e=Y(t);if(null===e)return!0;var r=Z.call(e,"constructor")&&e.constructor;return"function"==typeof r&&r instanceof r&&X.call(r)==tt}var rt,nt=function(t,e,r){for(var n=-1,o=Object(t),i=r(t),a=i.length;a--;){var u=i[rt?a:++n];if(!1===e(o[u],u,o))break}return t};function ot(t){return v(t)&&"[object Arguments]"==h(t)}var it=Object.prototype,at=it.hasOwnProperty,ut=it.propertyIsEnumerable,ct=ot(function(){return arguments}())?ot:function(t){return v(t)&&at.call(t,"callee")&&!ut.call(t,"callee")};var st="object"==typeof exports&&exports&&!exports.nodeType&&exports,ft=st&&"object"==typeof module&&module&&!module.nodeType&&module,lt=ft&&ft.exports===st?n.Buffer:void 0,pt=(lt?lt.isBuffer:void 0)||function(){return!1},ht=/^(?:0|[1-9]\d*)$/;function vt(t,e){var r=typeof t;return!!(e=null==e?9007199254740991:e)&&("number"==r||"symbol"!=r&&ht.test(t))&&t>-1&&t%1==0&&t-1&&t%1==0&&t<=9007199254740991}var dt={};dt["[object Float32Array]"]=dt["[object Float64Array]"]=dt["[object Int8Array]"]=dt["[object Int16Array]"]=dt["[object Int32Array]"]=dt["[object Uint8Array]"]=dt["[object Uint8ClampedArray]"]=dt["[object Uint16Array]"]=dt["[object Uint32Array]"]=!0,dt["[object Arguments]"]=dt["[object Array]"]=dt["[object ArrayBuffer]"]=dt["[object Boolean]"]=dt["[object DataView]"]=dt["[object Date]"]=dt["[object Error]"]=dt["[object Function]"]=dt["[object Map]"]=dt["[object Number]"]=dt["[object Object]"]=dt["[object RegExp]"]=dt["[object Set]"]=dt["[object String]"]=dt["[object WeakMap]"]=!1;var yt,_t="object"==typeof exports&&exports&&!exports.nodeType&&exports,bt=_t&&"object"==typeof module&&module&&!module.nodeType&&module,mt=bt&&bt.exports===_t&&e.process,jt=function(){try{var t=bt&&bt.require&&bt.require("util").types;return t||mt&&mt.binding&&mt.binding("util")}catch(t){}}(),wt=jt&&jt.isTypedArray,Ot=wt?(yt=wt,function(t){return yt(t)}):function(t){return v(t)&>(t.length)&&!!dt[h(t)]},St=Object.prototype.hasOwnProperty;function Et(t,e){var r=a(t),n=!r&&ct(t),o=!r&&!n&&pt(t),i=!r&&!n&&!o&&Ot(t),u=r||n||o||i,c=u?function(t,e){for(var r=-1,n=Array(t);++r-1},Mt.prototype.set=function(t,e){var r=this.__data__,n=qt(r,t);return n<0?(++this.size,r.push([t,e])):r[n][1]=e,this};var Lt,Wt=n["__core-js_shared__"],Jt=(Lt=/[^.]+$/.exec(Wt&&Wt.keys&&Wt.keys.IE_PROTO||""))?"Symbol(src)_1."+Lt:"";var Ut=Function.prototype.toString;function Dt(t){if(null!=t){try{return Ut.call(t)}catch(t){}try{return t+""}catch(t){}}return""}var Ht=/^\[object .+?Constructor\]$/,It=Function.prototype,Gt=Object.prototype,Bt=It.toString,Vt=Gt.hasOwnProperty,Yt=RegExp("^"+Bt.call(Vt).replace(/[\\^$.*+?()[\]{}|]/g,"\\$&").replace(/hasOwnProperty|(function).*?(?=\\\()| for .+?(?=\\\])/g,"$1.*?")+"$");function Kt(t){return!(!Pt(t)||function(t){return!!Jt&&Jt in t}(t))&&(Nt(t)?Yt:Ht).test(Dt(t))}function Qt(t,e){var r=function(t,e){return null==t?void 0:t[e]}(t,e);return Kt(r)?r:void 0}var Xt=Qt(n,"Map"),Zt=Qt(Object,"create");var te=Object.prototype.hasOwnProperty;var ee=Object.prototype.hasOwnProperty;function re(t){var e=-1,r=null==t?0:t.length;for(this.clear();++eu))return!1;var s=i.get(t);if(s&&i.get(e))return s==e;var f=-1,l=!0,p=2&r?new ae:void 0;for(i.set(t,e),i.set(e,t);++fe.type.filter((function(t){var e;return void 0===r||(!1!==(e=G(t))?!B({arg:r},e):!H(t)(r))})).length)})).length}return!1},rr=function(t){function e(){for(var r=[],n=arguments.length;n--;)r[n]=arguments[n];t.apply(this,r),this.message=r[0],this.detail=r[1],this.className=e.name,t.captureStackTrace&&t.captureStackTrace(this,e)}t&&(e.__proto__=t),e.prototype=Object.create(t&&t.prototype),e.prototype.constructor=e;var r={name:{configurable:!0}};return r.name.get=function(){return"JsonqlValidationError"},Object.defineProperties(e,r),e}(Error),nr=function(t){function e(){for(var r=[],n=arguments.length;n--;)r[n]=arguments[n];t.apply(this,r),this.message=r[0],this.detail=r[1],this.className=e.name,t.captureStackTrace&&t.captureStackTrace(this,e)}t&&(e.__proto__=t),e.prototype=Object.create(t&&t.prototype),e.prototype.constructor=e;var r={name:{configurable:!0},statusCode:{configurable:!0}};return r.name.get=function(){return"JsonqlError"},r.statusCode.get=function(){return-1},Object.defineProperties(e,r),e}(Error),or=function(t,e){var r,n,o,i,a;switch(!0){case"object"===t:return o=(n=e).arg,i=n.param,a=[o],Array.isArray(i.keys)&&i.keys.length&&a.push(i.keys),!Reflect.apply(er,null,a);case"array"===t:return!I(e.arg);case!1!==(r=G(t)):return!B(e,r);default:return!H(t)(e.arg)}},ir=function(t,e){return void 0!==t?t:!0===e.optional&&void 0!==e.defaultvalue?e.defaultvalue:null},ar=function(t,e,r){var n;void 0===r&&(r=!1);var o=function(t,e){if(!I(e))throw new rr("params is not an array! Did something gone wrong when you generate the contract.json?");if(0===e.length)return[];if(!I(t))throw new rr("args is not an array! You might want to do: ES6 Array.from(arguments) or ES5 Array.prototype.slice.call(arguments)");switch(!0){case t.length==e.length:return t.map((function(t,r){return{arg:t,index:r,param:e[r]}}));case!0===e[0].variable:var r=e[0].type;return t.map((function(t,n){return{arg:t,index:n,param:e[n]||{type:r,name:"_"}}}));case t.lengthe.length:var n=e.length,o=["any"];return t.map((function(t,r){var i=r>=n||!!e[r].optional,a=e[r]||{type:o,name:"_"+r};return{arg:i?ir(t,a):t,index:r,param:a,optional:i}}));default:throw new nr("Could not understand your arguments and parameter structure!",{args:t,params:e})}}(t,e),i=o.filter((function(t){return!0===t.optional||!0===t.param.optional?function(t){var e=t.arg,r=t.param;return!!F(e)&&!(r.type.length>r.type.filter((function(e){return or(e,t)})).length)}(t):!(t.param.type.length>t.param.type.filter((function(e){return or(e,t)})).length)}));return r?((n={}).error=i,n.data=o.map((function(t){return t.arg})),n):i},ur=function(){try{var t=Qt(Object,"defineProperty");return t({},"",{}),t}catch(t){}}();function cr(t,e,r){"__proto__"==e&&ur?ur(t,e,{configurable:!0,enumerable:!0,value:r,writable:!0}):t[e]=r}function sr(t,e,r){(void 0===r||Ct(t[e],r))&&(void 0!==r||e in t)||cr(t,e,r)}var fr="object"==typeof exports&&exports&&!exports.nodeType&&exports,lr=fr&&"object"==typeof module&&module&&!module.nodeType&&module,pr=lr&&lr.exports===fr?n.Buffer:void 0,hr=pr?pr.allocUnsafe:void 0;function vr(t,e){var r,n,o=e?(r=t.buffer,n=new r.constructor(r.byteLength),new se(n).set(new se(r)),n):t.buffer;return new t.constructor(o,t.byteOffset,t.length)}var gr=Object.create,dr=function(){function t(){}return function(e){if(!Pt(e))return{};if(gr)return gr(e);t.prototype=e;var r=new t;return t.prototype=void 0,r}}();function yr(t,e){if(("constructor"!==e||"function"!=typeof t[e])&&"__proto__"!=e)return t[e]}var _r=Object.prototype.hasOwnProperty;function br(t,e,r){var n=t[e];_r.call(t,e)&&Ct(n,r)&&(void 0!==r||e in t)||cr(t,e,r)}var mr=Object.prototype.hasOwnProperty;function jr(t){if(!Pt(t))return function(t){var e=[];if(null!=t)for(var r in Object(t))e.push(r);return e}(t);var e=$t(t),r=[];for(var n in t)("constructor"!=n||!e&&mr.call(t,n))&&r.push(n);return r}function wr(t){return xt(t)?Et(t,!0):jr(t)}function Or(t){return function(t,e,r,n){var o=!r;r||(r={});for(var i=-1,a=e.length;++i0){if(++e>=800)return arguments[0]}else e=0;return t.apply(void 0,arguments)}}(Tr);function Nr(t,e){return Pr(function(t,e,r){return e=$r(void 0===e?t.length-1:e,0),function(){for(var n=arguments,o=-1,i=$r(n.length-e,0),a=Array(i);++o1?e[n-1]:void 0,i=n>2?e[2]:void 0;for(o=xr.length>3&&"function"==typeof o?(n--,o):void 0,i&&function(t,e,r){if(!Pt(r))return!1;var n=typeof e;return!!("number"==n?xt(r)&&vt(e,r.length):"string"==n&&e in r)&&Ct(r[e],t)}(e[0],e[1],i)&&(o=n<3?void 0:o,n=1),t=Object(t);++r0;)e[r]=arguments[r+1];if(this.logger("($queue) get called"),!0===this.__suspend_state__){if(on(this.__pattern__)){var n=this.__pattern__.test(t);if(!n)return!1}this.logger("($queue) added to $queue",e),this.queueStore.add([t].concat(e))}return!!this.__suspend_state__},cn.$queues.get=function(){var t=this.queueStore.size;return this.logger("($queues)","size: "+t),t>0?Array.from(this.queueStore):[]},un.prototype.__suspend__=function(t){if("boolean"!=typeof t)throw new Error("$suspend only accept Boolean value! we got "+typeof t);var e=this.__suspend_state__;this.__suspend_state__=t,this.logger('($suspend) Change from "'+e+'" --\x3e "'+t+'"'),!0===e&&!1===t&&this.__release__()},un.prototype.__release__=function(){var t=this,e=this.queueStore.size,r=this.__pattern__;if(this.__pattern__=null,this.logger("(release) was called with "+e+(r?' for "'+r+'"':"")+" item"+(e>1?"s":"")),e>0){var n=Array.from(this.queueStore);this.queueStore.clear(),this.logger("(release queue)",n),n.forEach((function(e){t.logger(e),Reflect.apply(t.$trigger,t,e)})),this.logger("Release size "+this.queueStore.size)}return e},Object.defineProperties(un.prototype,cn);var sn=function(t){function e(e){if("function"!=typeof e)throw new Error("Just die here the logger is not a function!");e("---\x3e Create a new EventEmitter <---"),t.call(this,{logger:e})}t&&(e.__proto__=t),e.prototype=Object.create(t&&t.prototype),e.prototype.constructor=e;var r={name:{configurable:!0}};return r.name.get=function(){return"jsonql-ws-client-core"},Object.defineProperties(e.prototype,r),e}(function(t){function e(e){void 0===e&&(e={}),t.call(this,e)}t&&(e.__proto__=t),e.prototype=Object.create(t&&t.prototype),e.prototype.constructor=e;var r={$name:{configurable:!0},is:{configurable:!0},$done:{configurable:!0}};return e.prototype.logger=function(){},r.$name.get=function(){return"to1source-event"},r.is.get=function(){return this.$name},e.prototype.$on=function(t,e,r){var n=this;void 0===r&&(r=null);this.validate(t,e);var o=this.takeFromStore(t);if(!1===o)return this.logger('($on) "'+t+'" is not in lazy store'),this.addToNormalStore(t,"on",e,r);this.logger("($on) "+t+" found in lazy store");var i=0;return o.forEach((function(o){var a=o[0],u=o[1],c=o[2];if(c&&"on"!==c)throw new Error(en+" "+c);n.logger("($on)",'call run "'+t+'"'),n.run(e,a,r||u),i+=n.addToNormalStore(t,"on",e,r||u)})),this.logger("($on) return size "+i),i},e.prototype.$once=function(t,e,r){void 0===r&&(r=null),this.validate(t,e);var n=this.takeFromStore(t);this.normalStore;if(!1===n)return this.logger('($once) "'+t+'" is not in the lazy store'),this.addToNormalStore(t,"once",e,r);this.logger("($once)",n);var o=Array.from(n)[0],i=o[0],a=o[1],u=o[2];if(u&&"once"!==u)throw new Error(en+" "+u);this.logger("($once)",'call run "'+t+'"'),this.run(e,i,r||a),this.$off(t)},e.prototype.$only=function(t,e,r){var n=this;void 0===r&&(r=null),this.validate(t,e);var o=!1,i=this.takeFromStore(t);(this.normalStore.has(t)||(this.logger('($only) "'+t+'" add to normalStore'),o=this.addToNormalStore(t,"only",e,r)),!1!==i)&&(this.logger('($only) "'+t+'" found data in lazy store to execute'),Array.from(i).forEach((function(o){var i=o[0],a=o[1],u=o[2];if(u&&"only"!==u)throw new Error(en+" "+u);n.logger('($only) call run "'+t+'"'),n.run(e,i,r||a)})));return o},e.prototype.$onlyOnce=function(t,e,r){void 0===r&&(r=null),this.validate(t,e);var n=!1,o=this.takeFromStore(t);if(this.normalStore.has(t)||(this.logger('($onlyOnce) "'+t+'" add to normalStore'),n=this.addToNormalStore(t,"onlyOnce",e,r)),!1!==o){this.logger("($onlyOnce)",o);var i=Array.from(o)[0],a=i[0],u=i[1],c=i[2];if(c&&"onlyOnce"!==c)throw new Error(en+" "+c);this.logger('($onlyOnce) call run "'+t+'"'),this.run(e,a,r||u),this.$off(t)}return n},e.prototype.$replace=function(t,e,r,n){if(void 0===r&&(r=null),void 0===n&&(n="on"),this.validateType(n)){this.$off(t);var o=this["$"+n];return this.logger("($replace)",t,e),Reflect.apply(o,this,[t,e,r])}throw new Error(n+" is not supported!")},e.prototype.$trigger=function(t,e,r,n){void 0===e&&(e=[]),void 0===r&&(r=null),void 0===n&&(n=!1),this.validateEvt(t);var o=0,i=this.normalStore;if(this.logger("($trigger) normalStore",i),i.has(t)){if(this.logger('($trigger) "'+t+'" found'),this.$queue(t,e,r,n))return this.logger('($trigger) Currently suspended "'+t+'" added to queue, nothing executed. Exit now.'),!1;for(var a=Array.from(i.get(t)),u=a.length,c=!1,s=0;s0;)n[o]=arguments[o+2];if(t.has(e)?(this.logger('(addToStore) "'+e+'" existed'),r=t.get(e)):(this.logger('(addToStore) create new Set for "'+e+'"'),r=new Set),n.length>2)if(Array.isArray(n[0])){var i=n[2];this.checkTypeInLazyStore(e,i)||r.add(n)}else this.checkContentExist(n,r)||(this.logger("(addToStore) insert new",n),r.add(n));else r.add(n);return t.set(e,r),[t,r.size]},e.prototype.checkContentExist=function(t,e){return!!Array.from(e).filter((function(e){return e[0]===t[0]})).length},e.prototype.checkTypeInStore=function(t,e){this.validateEvt(t,e);var r=this.$get(t,!0);return!1===r||!r.filter((function(t){var r=t[3];return e!==r})).length},e.prototype.checkTypeInLazyStore=function(t,e){this.validateEvt(t,e);var r=this.lazyStore.get(t);return this.logger("(checkTypeInLazyStore)",r),!!r&&!!Array.from(r).filter((function(t){return t[2]!==e})).length},e.prototype.addToNormalStore=function(t,e,r,n){if(void 0===n&&(n=null),this.logger('(addToNormalStore) try to add "'+e+'" --\x3e "'+t+'" to normal store'),this.checkTypeInStore(t,e)){this.logger("(addToNormalStore)",'"'+e+'" --\x3e "'+t+'" can add to normal store');var o=this.hashFnToKey(r),i=[this.normalStore,t,o,r,n,e],a=Reflect.apply(this.addToStore,this,i),u=a[0],c=a[1];return this.normalStore=u,c}return!1},e.prototype.addToLazyStore=function(t,e,r,n){void 0===e&&(e=[]),void 0===r&&(r=null),void 0===n&&(n=!1);var o=[this.lazyStore,t,this.toArray(e),r];n&&o.push(n);var i=Reflect.apply(this.addToStore,this,o),a=i[0],u=i[1];return this.lazyStore=a,this.logger("(addToLazyStore) size: "+u),u},e.prototype.toArray=function(t){return Array.isArray(t)?t:[t]},r.normalStore.set=function(t){rn.set(this,t)},r.normalStore.get=function(){return rn.get(this)},r.lazyStore.set=function(t){nn.set(this,t)},r.lazyStore.get=function(){return nn.get(this)},e.prototype.hashFnToKey=function(t){return function(t){return t.split("").reduce((function(t,e){return(t=(t<<5)-t+e.charCodeAt(0))&t}),0)}(t.toString())+""},Object.defineProperties(e.prototype,r),e}(un))),fn=function(t){return a(t)?t:[t]},ln=function(t,e){try{var r=Object.keys(t);return n=e,!!r.filter((function(t){return t===n})).length}catch(t){return!1}var n},pn=function(){for(var t=[],e=arguments.length;e--;)t[e]=arguments[e];return t.join("_")},hn=function(t){if("function"==typeof t)return!0;console.error("Expect to be Function type! Got "+typeof t)},vn=function(){return!1},gn=function(t){for(var e=[],r=arguments.length-1;r-- >0;)e[r]=arguments[r+1];return function(){for(var r=[],n=arguments.length;n--;)r[n]=arguments[n];return e.reduce((function(t,e){return Reflect.apply(e,null,fn(t))}),Reflect.apply(t,null,r))}};function dn(t,e,r,n){return void 0===n&&(n=null),void 0===Object.getOwnPropertyDescriptor(t,e)&&Object.defineProperty(t,e,{set:r,get:null===n?function(){return null}:n}),t}function yn(t,e,r,n){void 0===n&&(n=!1);var o=function(t,e){var r=Object.getOwnPropertyDescriptor(t,e);return void 0!==r&&r.value?r.value:r}(t,e);return!1===n&&void 0!==o||Object.defineProperty(t,e,{value:r,writable:n}),t}var _n=function(t){function e(){for(var r=[],n=arguments.length;n--;)r[n]=arguments[n];t.apply(this,r),this.message=r[0],this.detail=r[1],this.className=e.name,t.captureStackTrace&&t.captureStackTrace(this,e)}t&&(e.__proto__=t),e.prototype=Object.create(t&&t.prototype),e.prototype.constructor=e;var r={statusCode:{configurable:!0},name:{configurable:!0}};return r.statusCode.get=function(){return 406},r.name.get=function(){return"Jsonql406Error"},Object.defineProperties(e,r),e}(Error),bn=function(t){function e(){for(var r=[],n=arguments.length;n--;)r[n]=arguments[n];t.apply(this,r),this.message=r[0],this.detail=r[1],this.className=e.name,t.captureStackTrace&&t.captureStackTrace(this,e)}t&&(e.__proto__=t),e.prototype=Object.create(t&&t.prototype),e.prototype.constructor=e;var r={statusCode:{configurable:!0},name:{configurable:!0}};return r.statusCode.get=function(){return 500},r.name.get=function(){return"Jsonql500Error"},Object.defineProperties(e,r),e}(Error),mn=function(t){function e(){for(var r=[],n=arguments.length;n--;)r[n]=arguments[n];t.apply(this,r),this.message=r[0],this.detail=r[1],this.className=e.name,t.captureStackTrace&&t.captureStackTrace(this,e)}t&&(e.__proto__=t),e.prototype=Object.create(t&&t.prototype),e.prototype.constructor=e;var r={statusCode:{configurable:!0},name:{configurable:!0}};return r.statusCode.get=function(){return 403},r.name.get=function(){return"JsonqlForbiddenError"},Object.defineProperties(e,r),e}(Error),jn=function(t){function e(){for(var r=[],n=arguments.length;n--;)r[n]=arguments[n];t.apply(this,r),this.message=r[0],this.detail=r[1],this.className=e.name,t.captureStackTrace&&t.captureStackTrace(this,e)}t&&(e.__proto__=t),e.prototype=Object.create(t&&t.prototype),e.prototype.constructor=e;var r={statusCode:{configurable:!0},name:{configurable:!0}};return r.statusCode.get=function(){return 401},r.name.get=function(){return"JsonqlAuthorisationError"},Object.defineProperties(e,r),e}(Error),wn=function(t){function e(){for(var r=[],n=arguments.length;n--;)r[n]=arguments[n];t.apply(this,r),this.message=r[0],this.detail=r[1],this.className=e.name,t.captureStackTrace&&t.captureStackTrace(this,e)}t&&(e.__proto__=t),e.prototype=Object.create(t&&t.prototype),e.prototype.constructor=e;var r={statusCode:{configurable:!0},name:{configurable:!0}};return r.statusCode.get=function(){return 401},r.name.get=function(){return"JsonqlContractAuthError"},Object.defineProperties(e,r),e}(Error),On=function(t){function e(){for(var r=[],n=arguments.length;n--;)r[n]=arguments[n];t.apply(this,r),this.message=r[0],this.detail=r[1],this.className=e.name,t.captureStackTrace&&t.captureStackTrace(this,e)}t&&(e.__proto__=t),e.prototype=Object.create(t&&t.prototype),e.prototype.constructor=e;var r={statusCode:{configurable:!0},name:{configurable:!0}};return r.statusCode.get=function(){return 500},r.name.get=function(){return"JsonqlResolverAppError"},Object.defineProperties(e,r),e}(Error),Sn=function(t){function e(){for(var r=[],n=arguments.length;n--;)r[n]=arguments[n];t.apply(this,r),this.message=r[0],this.detail=r[1],this.className=e.name,t.captureStackTrace&&t.captureStackTrace(this,e)}t&&(e.__proto__=t),e.prototype=Object.create(t&&t.prototype),e.prototype.constructor=e;var r={statusCode:{configurable:!0},name:{configurable:!0}};return r.statusCode.get=function(){return 404},r.name.get=function(){return"JsonqlResolverNotFoundError"},Object.defineProperties(e,r),e}(Error),En=function(t){function e(r,n){t.call(this,n),this.statusCode=r,this.className=e.name}t&&(e.__proto__=t),e.prototype=Object.create(t&&t.prototype),e.prototype.constructor=e;var r={name:{configurable:!0}};return r.name.get=function(){return"JsonqlServerError"},Object.defineProperties(e,r),e}(Error);function kn(t){if(Array.isArray(t))throw new rr("",t);var e=t.message||"No message",r=t.detail||t;switch(!0){case t instanceof _n:throw new _n(e,r);case t instanceof bn:throw new bn(e,r);case t instanceof mn:throw new mn(e,r);case t instanceof jn:throw new jn(e,r);case t instanceof wn:throw new wn(e,r);case t instanceof On:throw new On(e,r);case t instanceof Sn:throw new Sn(e,r);case t instanceof Dr:throw new Dr(e,r);case t instanceof Hr:throw new Hr(e,r);case t instanceof Ir:throw new Ir(e,r);case t instanceof rr:throw new rr(e,r);case t instanceof En:throw new En(e,r);default:throw new nr(e,r)}}function $n(t){var e=function(t){return!!ln(t,"socket")&&t.socket}(t);if(!1===e)throw new JsonqlError("groupByNamespace","socket not found in contract!");var r={nspGroup:{},publicNamespace:null,size:0};for(var n in e){var o=e[n],i=o.namespace;i&&(r.nspGroup[i]||(++r.size,r.nspGroup[i]={}),r.nspGroup[i][n]=o,!r.publicNamespace&&o.public&&(r.publicNamespace=i))}return r}var Tn=function(t){var e=t.toLowerCase();return e.indexOf("http")>-1?e.indexOf("https")>-1?e.replace("https","wss"):e.replace("http","ws"):e},An=function(t,e){fn(e).forEach((function(e){t.$off(pn(e,"emit_reply"))}))},Pn=function(t,e,r){return[yn(t,e.loginHandlerName,(function(t){if(t&&Yr(t))return e.log("Received __login__ with "+t),r.$trigger("__login__",[t]);throw new rr(e.loginHandlerName,"Unexpected token "+t)})),e,r]},Nn=function(t,e,r){return[yn(t,e.logoutHandlerName,(function(){for(var t=[],e=arguments.length;e--;)t[e]=arguments[e];r.$trigger("__logout__",t)})),e,r]},xn=function(t,e,r){return[dn(t,"onLogin",(function(t){hn(t)&&r.$only("onLogin",t)})),e,r]};function zn(t,e,r){return gn(Pn,Nn,xn)(t,e,r)}function Rn(t,e,r){ln(t,"error")?r(t.error):ln(t,"data")?e(t.data):r({message:"UKNNOWN RESULT!",error:t})}function Cn(t,e,r,n,o){void 0===n&&(n=[]);var i=pn(e,"emit_reply");return o("actionCall: "+i+" --\x3e "+r,n),t.$trigger(i,[r,fn(n)]),new Promise((function(n,i){var a=pn(e,r,"onResult");t.$on(a,(function(t){o("got the first result",t),Rn(t,n,i)}))}))}var qn,Fn,Mn,Ln=function(t,e,r,n,o,i){return dn(t,"send",vn,(function(){return function(){for(var t=[],a=arguments.length;a--;)t[a]=arguments[a];return Kr(t,o.params,!0).then((function(t){return i(r,n,t),Cn(e,r,n,t,_log)})).catch((function(t){i("send error",t),e.$call(pn(r,n,"onError"),[new rr(n,t)])}))}}))},Wn=function(t,e,r,n,o,i){return[yn(t,"myNamespace",r),e,r,n,o,i]},Jn=function(t,e,r,n,o,i){return[dn(t,"onResult",(function(t){hn(t)&&e.$on(pn(r,n,"onResult"),(function(o){Rn(o,t,(function(t){i('Catch error: "'+n+'"',t),e.$trigger(pn(r,n,"onError"),t)}))}))})),e,r,n,o,i]},Un=function(t,e,r,n,o,i){return[dn(t,"onMessage",(function(t){if(hn(t)){e.$only(pn(r,n,"onMessage"),(function(o){Rn(o,t,(function(t){i('Catch error: "'+n+'"',t),e.$trigger(pn(r,n,"onError"),t)}))}))}})),e,r,n,o,i]},Dn=function(t,e,r,n,o,i){return[dn(t,"onError",(function(t){hn(t)&&e.$only(pn(r,n,"onError"),t)})),e,r,n,o,i]};function Hn(t,e,r,n,o,i){var a=[Wn,Jn,Un,Dn,Ln],u=Reflect.apply(gn,null,a),c=[n,o,t,e,r,i];return Reflect.apply(u,null,c)}function In(t,e,r,n,o){return function(){for(var i=[],a=arguments.length;a--;)i[a]=arguments[a];return Kr(i,n.params,!0).then((function(n){return Cn(t,e,r,n,o)})).catch(kn)}}function Gn(t,e,r){var n={},o=t.log;for(var i in r){var a=r[i];for(var u in a){var c=a[u];n=yn(n,u,Hn(i,u,c,In(e,i,u,c,o),e,o))}}return[n,t,e,r]}function Bn(t,e,r,n){return[dn(t,"onError",(function(t){if(hn(t))for(var e in n)r.$on(pn(e,"onError"),t)})),e,r]}function Vn(t,e,r){return[dn(t,"onReady",(function(t){hn(t)&&r.$on("onReady",t)})),e,r]}function Yn(t,e,r){var n=function(t,e,r){return yn(t,e.disconnectHandlerName,(function(){for(var t=[],e=arguments.length;e--;)t[e]=arguments[e];r.$trigger("__disconnect__",t)}))}(t,e,r);return e.log("---\x3e The final step to return the ws-client <---"),n.verifyEventEmitter=function(){return r.is},n.eventEmitter=e.eventEmitter,n.log=e.log,n}var Kn=["roundtip","handshake"],Qn={standalone:Qr(!1,["boolean"]),debugOn:Qr(!1,["boolean"]),loginHandlerName:Qr("login",["string"]),logoutHandlerName:Qr("logout",["string"]),disconnectHandlerName:Qr("disconnect",["string"]),switchUserHandlerName:Qr("switch-user",["string"]),loginMethod:Qr("handshake",["string"],(qn={},qn.enumv=Kn,qn)),useJwt:Qr(!0,["boolean","string"]),authStrKey:Qr(null,["string"]),hostname:Qr(!1,["string"]),namespace:Qr("jsonql",["string"]),wsOptions:Qr({},["object"]),contract:Qr({},["object"],(Fn={},Fn.checker=function(t){return!!function(t){return et(t)&&(ln(t,"query")||ln(t,"mutation")||ln(t,"socket"))}(t)&&t},Fn)),enableAuth:Qr(!1,["boolean"]),token:Qr(!1,["string"])},Xn={};Xn.serverType=Qr(null,["string"],((Mn={}).alias="socketClientType",Mn));var Zn=Object.assign(Qn,Xn),to={log:null,eventEmitter:null,nspClient:null,nspAuthClient:null,wssPath:""};function eo(t){return Promise.resolve(t).then((function(t){return t.hostname||(t.hostname=function(){try{return[window.location.protocol,window.location.host].join("//")}catch(t){throw new rr(t)}}()),t.wssPath=Tn([t.hostname,t.namespace].join("/"),t.serverType),t.log=tn(t),t.eventEmitter=function(t){var e=t.log,r=t.eventEmitter;return r?(e("eventEmitter is:",r.name),r):new sn(t.log)}(t),t}))}function ro(t){return{opts:t,nspMap:(e=t,r=e.contract,n=e.enableAuth,o=function(t){var e="jsonql";return t.enableAuth?[[e,t.publicNamespace].join("/"),[e,t.privateNamespace].join("/")]:[e]}(e),i=n?$n(r):function(t,e){var r,n={};for(var o in t){var i=t[o];n[o]=i}return{size:1,nspGroup:(r={},r[e]=n,r),publicNamespace:e}}(r.socket,o[0]),Object.assign(i,{namespaces:o})),ee:t.eventEmitter};var e,r,n,o,i}function no(t,e){return eo(e).then(ro).then((function(e){var r=e.opts,n=e.nspMap,o=e.ee;return t(r,n,o)})).then((function(t){return function(t,e,r){var n=[Gn,Bn,Vn];return t.enableAuth&&n.push(zn),n.push(Yn),Reflect.apply(gn,null,n)(t,r,e.nspGroup)}(t.opts,t.nspMap,t.ee)})).catch((function(t){console.error("jsonql-ws-core-client init error",t)}))}function oo(t,e,r){return void 0===e&&(e={}),void 0===r&&(r={}),function(n){return void 0===n&&(n={}),function(t,e,r){var n=Object.assign(to,r),o=Object.assign(Zn,e);return Xr(t,o,n)}(n,e,r).then((function(e){return no(t,e)}))}}function io(t,e){var r=e.hostname,n=e.wssPath,o=e.wsOptions;return(0,e.nspClient)(t?[r,t].join("/"):n,o)}function ao(t,e,r){e.forEach((function(e){t.$trigger(pn(e,"onError"),[{message:r,namespace:e}])}))}var uo=function(t,e,r){var n=r.log;e.$only(pn(t,"emit_reply"),(function(r,o){n("[notLoginHandler] hijack the ws call",t,r,o);var i={message:"NOT LOGIN"};e.$call(pn(t,r,"onError"),[i]),e.$call(pn(t,r,"onResult"),[{error:i}])}))},co=function(t){return t.length>1&&t[0]},so=function(t,e,r,n){var o=n.log;r.$on("__disconnect__",(function(){ao(r,e,"__disconnect__"),e.forEach((function(e){o("disconnect from "+e),An(r,e),t[e]=null,function(t,e,r){var n=r.log;e.$only(pn(t,"emit_reply"),(function(r,o){n("[disconnectedHandler] hijack the ws call",t,r,o);var i={message:"You have disconnected from the socket server, please reconnect."};e.$call(pn(t,r,"onError"),[i]),e.$call(pn(t,r,"onResult"),[{error:i}])}))}(e,r,n)}))}))};function fo(t,e,r,n,o,i){var a=co(o),u=!1,c=!1,s=t.log;o.forEach((function(o){if(u=a===o,c||(c=u),i[o]){s("[call bindWsHandler]",u,o);var f=[o,i[o],r,u,t];if("socket.io"===t.serverType){var l=e.nspSet;f.push(l[o])}Reflect.apply(n,null,f)}else uo(o,r,t)})),c&&(s("Has private and add logoutEvtHandler"),function(t,e,r,n){var o=n.log;r.$on("__logout__",(function(){var i=co(e);o("__logout__ event triggered"),ao(r,[i],"__logout__"),o("logout from "+i),An(r,i),t[i]=null,uo(i,r,n)}))}(i,o,r,t)),so(i,o,r,t)}var lo={version:"version: 1.1.1 module: umd",serverType:"ws"},po=Object.assign({},Zn,{}),ho=Object.assign({},to,lo),vo=null;"undefined"!=typeof WebSocket?vo=WebSocket:"undefined"!=typeof MozWebSocket?vo=MozWebSocket:void 0!==t?vo=t.WebSocket||t.MozWebSocket:"undefined"!=typeof window?vo=window.WebSocket||window.MozWebSocket:"undefined"!=typeof self&&(vo=self.WebSocket||self.MozWebSocket);var go=vo;function yo(t,e){return void 0===e&&(e=!1),!1===e?function(e){return new t(Tn(e))}:function(e,r){var n=Tn(e),o=r&&"string"==typeof r?n+"?token="+r:n;try{return new t(o)}catch(t){return console.error("WebSocket Connection Error",t),!1}}}var _o=Array.isArray,bo="object"==typeof t&&t&&t.Object===Object&&t,mo="object"==typeof self&&self&&self.Object===Object&&self,jo=(bo||mo||Function("return this")()).Symbol,wo=Object.prototype,Oo=wo.hasOwnProperty,So=wo.toString,Eo=jo?jo.toStringTag:void 0;var ko=Object.prototype.toString;var $o=jo?jo.toStringTag:void 0;function To(t){return null==t?void 0===t?"[object Undefined]":"[object Null]":$o&&$o in Object(t)?function(t){var e=Oo.call(t,Eo),r=t[Eo];try{t[Eo]=void 0;var n=!0}catch(t){}var o=So.call(t);return n&&(e?t[Eo]=r:delete t[Eo]),o}(t):function(t){return ko.call(t)}(t)}function Ao(t){return null!=t&&"object"==typeof t}var Po=jo?jo.prototype:void 0,No=Po?Po.toString:void 0;function xo(t){if("string"==typeof t)return t;if(_o(t))return function(t,e){for(var r=-1,n=null==t?0:t.length,o=Array(n);++r=n?t:function(t,e,r){var n=-1,o=t.length;e<0&&(e=-e>o?0:o+e),(r=r>o?o:r)<0&&(r+=o),o=e>r?0:r-e>>>0,e>>>=0;for(var i=Array(o);++n-1;);return r}(o,i),function(t,e){for(var r=t.length;r--&&Co(e,t[r],0)>-1;);return r}(o,i)+1).join("")}var Ko=function(){for(var t=[],e=arguments.length;e--;)t[e]=arguments[e];return t.join("_")},Qo=function(t){function e(){for(var r=[],n=arguments.length;n--;)r[n]=arguments[n];t.apply(this,r),this.message=r[0],this.detail=r[1],this.className=e.name,t.captureStackTrace&&t.captureStackTrace(this,e)}t&&(e.__proto__=t),e.prototype=Object.create(t&&t.prototype),e.prototype.constructor=e;var r={name:{configurable:!0}};return r.name.get=function(){return"JsonqlValidationError"},Object.defineProperties(e,r),e}(Error),Xo=function(t){function e(){for(var r=[],n=arguments.length;n--;)r[n]=arguments[n];t.apply(this,r),this.message=r[0],this.detail=r[1],this.className=e.name,t.captureStackTrace&&t.captureStackTrace(this,e)}t&&(e.__proto__=t),e.prototype=Object.create(t&&t.prototype),e.prototype.constructor=e;var r={name:{configurable:!0},statusCode:{configurable:!0}};return r.name.get=function(){return"JsonqlError"},r.statusCode.get=function(){return-1},Object.defineProperties(e,r),e}(Error),Zo=function(t){void 0===t&&(t=!1);var e=Date.now();return t?Math.floor(e/1e3):e};function ti(t){return"string"==typeof t||!_o(t)&&Ao(t)&&"[object String]"==To(t)}function ei(t,e,r){if(void 0===e&&(e=[]),void 0===r&&(r=!1),ti(t)&&_o(e)){var n=function(t){var e;return(e={}).args=t,e}(e);return!0===r?n:function(t,e){var r;return(r={})[t]=e,r.TS=[Zo()],r}(t,n)}throw new Qo("[createQuery] expect resolverName to be string and args to be array!",{resolverName:t,args:e})}var ri=function(t){return""!==Yo(t)&&ti(t)},ni=["__reply__","__event__","__data__"],oi=function(t){var e=t.data;return!!e&&(ni.filter((function(t){return function(t,e){try{var r=Object.keys(t);return n=e,!!r.filter((function(t){return t===n})).length}catch(t){return!1}var n}(e,t)})).length===ni.length&&e)},ii=function(t,e,r,n,o){var i=[e];r&&i.push(r),i.push(o);var a=Reflect.apply(Ko,null,i),u=n.data||n;t.$trigger(a,[u])};function ai(t,e,r,n,o){var i=o.log;i("log test, isPrivate:",n),e.onopen=function(){i("ws.onopen listened"),r.$call("onReady",t),n&&(i("isPrivate and fire the onLogin"),r.$call("onLogin",t)),r.$only(Ko(t,"emit_reply"),(function(t,r){var n=function(t,e,r){return void 0===e&&(e=[]),void 0===r&&(r=!1),JSON.stringify(ei(t,e,r))}(t,r);i("calling server",t,r,n),e.send(n)}))},e.onmessage=function(e){try{var n=function(t){var e,r=t.data,n=ri(r)?JSON.parse(r):r;if(!1!==(e=oi(n)))return{resolverName:e.__event__,data:e.__data__,type:e.__reply__};throw new Xo("payload can not be decoded",t)}(e),o=n.resolverName,a=n.type;switch(i("Hear from server",a,n),a){case"emit_reply":var u=Ko(t,o,"onMessage"),c=r.$trigger(u,[n]);i("EMIT_REPLY_TYPE",u,c);break;case"acknowledge_reply":var s=Ko(t,o,"onResult"),f=r.$trigger(s,[n]);i("ACKNOWLEDGE_REPLY_TYPE",s,f);break;case"error":i("ERROR_TYPE"),ii(r,t,o,n,"onError");break;default:i("Unhandled event!",n),ii(r,t,o,n,"onError")}}catch(e){console.error("ws.onmessage error",e),ii(r,t,!1,e,"onError")}},e.onclose=function(){i("ws.onclose callback")},e.onerror=function(e){i("ws.onerror",e),r.$trigger(Ko(t,"onError"),[e])},n&&r.$on("__logout__",(function(){try{i("terminate ws connection"),e.terminate()}catch(t){console.error("ws.terminate error",t)}}))}var ui=function(t,e,r){var n,o=t.log,i=e.nspGroup,a=e.publicNamespace,u=!1,c=[],s={};if(t.enableAuth)u=!0,s=(c=function(t,e){var r=[];for(var n in t)n===e?r[1]=n:r[0]=n;return r}(i,a)).map((function(e,n){var i,a,u;return 0===n?r?(t.token=r,o("create createNspAuthClient at run time"),(i={})[e]=function(t,e){var r=e.hostname,n=e.wssPath,o=e.token,i=e.wsOptions,a=e.nspAuthClient,u=t?[r,t].join("/"):n;if(o&&"string"!=typeof o)throw new Error("Expect token to be string, but got "+o);return a(u,o,i)}(e,t),i):((a={})[e]=!1,a):((u={})[e]=io(e,t),u)})).reduce((function(t,e){return Object.assign(t,e)}),{});else{var f=(n=i,console.error("This method is going to be deprectead in the next release, please use getResolverFromPayload instead"),Object.keys(n)[0]);c.push(f),s[f]=io(!1,t)}return{nsps:s,namespaces:c,loginRequired:u}};function ci(t,e,r,n){var o=n.log;t.$only("__login__",(function(i){o("createClient LOGIN_EVENT_NAME $only handler"),An(t,e);var a=ui(n,r,i);Reflect.apply(fo,null,args.concat([a.namespaces,a.nsps]))}))}var si,fi,li,pi=(fi=yo(si=go),li=yo(si,!0),function(t,e,r){t.nspClient=fi,t.nspAuthClient=li;var n=t.log;return n&&"function"==typeof n&&(n("@jsonql/ws ee",r.name),n("@jsonql/ws createClientResolver",t)),function(t,e,r){var n=[t,e,r,ai],o=t.token,i=(t.log,ui(t,e,o)),a=i.nsps,u=i.namespaces,c=i.loginRequired;return Reflect.apply(fo,null,n.concat([u,a])),c&&ci(r,u,e,t),{opts:t,nspMap:e,ee:r}}(t,e,r)});return function(t,e){return void 0===t&&(t={}),void 0===e&&(e={}),oo(pi,po,Object.assign({},ho,e))(t)}})); //# sourceMappingURL=jsonql-ws-client.umd.js.map diff --git a/packages/@jsonql/ws/main.js b/packages/@jsonql/ws/main.js index 144dbf3a..8fea0722 100644 --- a/packages/@jsonql/ws/main.js +++ b/packages/@jsonql/ws/main.js @@ -1,2 +1,2 @@ -"use strict";var t,e=(t=require("ws"))&&"object"==typeof t&&"default"in t?t.default:t,r="undefined"!=typeof global?global:"undefined"!=typeof self?self:"undefined"!=typeof window?window:{},n="object"==typeof r&&r&&r.Object===Object&&r,o="object"==typeof self&&self&&self.Object===Object&&self,i=n||o||Function("return this")(),a=i.Symbol;function u(t,e){for(var r=-1,n=null==t?0:t.length,o=Array(n);++r=n?t:function(t,e,r){var n=-1,o=t.length;e<0&&(e=-e>o?0:o+e),(r=r>o?o:r)<0&&(r+=o),o=e>r?0:r-e>>>0,e>>>=0;for(var i=Array(o);++n-1;);return r}(n,o),function(t,e){for(var r=t.length;r--&&O(e,t[r],0)>-1;);return r}(n,o)+1).join("")}var M=function(t){return!!c(t)||null!=t&&""!==L(t)};function J(t){return function(t){return"number"==typeof t||d(t)&&"[object Number]"==g(t)}(t)&&t!=+t}function D(t){return"string"==typeof t||!c(t)&&d(t)&&"[object String]"==g(t)}var U=function(t){return!D(t)&&!J(parseFloat(t))},H=function(t){return""!==L(t)&&D(t)},I=function(t){return null!=t&&"boolean"==typeof t},W=function(t,e){return void 0===e&&(e=!0),void 0!==t&&""!==t&&""!==L(t)&&(!1===e||!0===e&&null!==t)},B=function(t){switch(t){case"number":return U;case"string":return H;case"boolean":return I;default:return W}},V=function(t,e){return void 0===e&&(e=""),!!c(t)&&(""===e||""===L(e)||!(t.filter((function(t){return!B(e)(t)})).length>0))},Y=function(t){if(t.indexOf("array.<")>-1&&t.indexOf(">")>-1){var e=t.replace("array.<","").replace(">","");return e.indexOf("|")?e.split("|"):[e]}return!1},G=function(t,e){var r=t.arg;return e.length>1?!r.filter((function(t){return!(e.length>e.filter((function(e){return!B(e)(t)})).length)})).length:e.length>e.filter((function(t){return!V(r,t)})).length};function K(t,e){return function(r){return t(e(r))}}var Q=K(Object.getPrototypeOf,Object),X=Function.prototype,Z=Object.prototype,tt=X.toString,et=Z.hasOwnProperty,rt=tt.call(Object);function nt(t){if(!d(t)||"[object Object]"!=g(t))return!1;var e=Q(t);if(null===e)return!0;var r=et.call(e,"constructor")&&e.constructor;return"function"==typeof r&&r instanceof r&&tt.call(r)==rt}var ot,it=function(t,e,r){for(var n=-1,o=Object(t),i=r(t),a=i.length;a--;){var u=i[ot?a:++n];if(!1===e(o[u],u,o))break}return t};function at(t){return d(t)&&"[object Arguments]"==g(t)}var ut=Object.prototype,ct=ut.hasOwnProperty,st=ut.propertyIsEnumerable,ft=at(function(){return arguments}())?at:function(t){return d(t)&&ct.call(t,"callee")&&!st.call(t,"callee")};var lt="object"==typeof exports&&exports&&!exports.nodeType&&exports,pt=lt&&"object"==typeof module&&module&&!module.nodeType&&module,ht=pt&&pt.exports===lt?i.Buffer:void 0,vt=(ht?ht.isBuffer:void 0)||function(){return!1},gt=/^(?:0|[1-9]\d*)$/;function dt(t,e){var r=typeof t;return!!(e=null==e?9007199254740991:e)&&("number"==r||"symbol"!=r&>.test(t))&&t>-1&&t%1==0&&t-1&&t%1==0&&t<=9007199254740991}var _t={};_t["[object Float32Array]"]=_t["[object Float64Array]"]=_t["[object Int8Array]"]=_t["[object Int16Array]"]=_t["[object Int32Array]"]=_t["[object Uint8Array]"]=_t["[object Uint8ClampedArray]"]=_t["[object Uint16Array]"]=_t["[object Uint32Array]"]=!0,_t["[object Arguments]"]=_t["[object Array]"]=_t["[object ArrayBuffer]"]=_t["[object Boolean]"]=_t["[object DataView]"]=_t["[object Date]"]=_t["[object Error]"]=_t["[object Function]"]=_t["[object Map]"]=_t["[object Number]"]=_t["[object Object]"]=_t["[object RegExp]"]=_t["[object Set]"]=_t["[object String]"]=_t["[object WeakMap]"]=!1;var bt,mt="object"==typeof exports&&exports&&!exports.nodeType&&exports,jt=mt&&"object"==typeof module&&module&&!module.nodeType&&module,wt=jt&&jt.exports===mt&&n.process,Ot=function(){try{var t=jt&&jt.require&&jt.require("util").types;return t||wt&&wt.binding&&wt.binding("util")}catch(t){}}(),St=Ot&&Ot.isTypedArray,Et=St?(bt=St,function(t){return bt(t)}):function(t){return d(t)&&yt(t.length)&&!!_t[g(t)]},kt=Object.prototype.hasOwnProperty;function $t(t,e){var r=c(t),n=!r&&ft(t),o=!r&&!n&&vt(t),i=!r&&!n&&!o&&Et(t),a=r||n||o||i,u=a?function(t,e){for(var r=-1,n=Array(t);++r-1},Jt.prototype.set=function(t,e){var r=this.__data__,n=Lt(r,t);return n<0?(++this.size,r.push([t,e])):r[n][1]=e,this};var Dt,Ut=i["__core-js_shared__"],Ht=(Dt=/[^.]+$/.exec(Ut&&Ut.keys&&Ut.keys.IE_PROTO||""))?"Symbol(src)_1."+Dt:"";var It=Function.prototype.toString;function Wt(t){if(null!=t){try{return It.call(t)}catch(t){}try{return t+""}catch(t){}}return""}var Bt=/^\[object .+?Constructor\]$/,Vt=Function.prototype,Yt=Object.prototype,Gt=Vt.toString,Kt=Yt.hasOwnProperty,Qt=RegExp("^"+Gt.call(Kt).replace(/[\\^$.*+?()[\]{}|]/g,"\\$&").replace(/hasOwnProperty|(function).*?(?=\\\()| for .+?(?=\\\])/g,"$1.*?")+"$");function Xt(t){return!(!Nt(t)||function(t){return!!Ht&&Ht in t}(t))&&(zt(t)?Qt:Bt).test(Wt(t))}function Zt(t,e){var r=function(t,e){return null==t?void 0:t[e]}(t,e);return Xt(r)?r:void 0}var te=Zt(i,"Map"),ee=Zt(Object,"create");var re=Object.prototype.hasOwnProperty;var ne=Object.prototype.hasOwnProperty;function oe(t){var e=-1,r=null==t?0:t.length;for(this.clear();++eu))return!1;var s=i.get(t);if(s&&i.get(e))return s==e;var f=-1,l=!0,p=2&r?new ce:void 0;for(i.set(t,e),i.set(e,t);++fe.type.filter((function(t){var e;return void 0===r||(!1!==(e=Y(t))?!G({arg:r},e):!B(t)(r))})).length)})).length}return!1},or=function(t){function e(){for(var r=[],n=arguments.length;n--;)r[n]=arguments[n];t.apply(this,r),this.message=r[0],this.detail=r[1],this.className=e.name,t.captureStackTrace&&t.captureStackTrace(this,e)}t&&(e.__proto__=t),e.prototype=Object.create(t&&t.prototype),e.prototype.constructor=e;var r={name:{configurable:!0}};return r.name.get=function(){return"JsonqlValidationError"},Object.defineProperties(e,r),e}(Error),ir=function(t){function e(){for(var r=[],n=arguments.length;n--;)r[n]=arguments[n];t.apply(this,r),this.message=r[0],this.detail=r[1],this.className=e.name,t.captureStackTrace&&t.captureStackTrace(this,e)}t&&(e.__proto__=t),e.prototype=Object.create(t&&t.prototype),e.prototype.constructor=e;var r={name:{configurable:!0},statusCode:{configurable:!0}};return r.name.get=function(){return"JsonqlError"},r.statusCode.get=function(){return-1},Object.defineProperties(e,r),e}(Error),ar=function(t,e){var r,n,o,i,a;switch(!0){case"object"===t:return o=(n=e).arg,i=n.param,a=[o],Array.isArray(i.keys)&&i.keys.length&&a.push(i.keys),!Reflect.apply(nr,null,a);case"array"===t:return!V(e.arg);case!1!==(r=Y(t)):return!G(e,r);default:return!B(t)(e.arg)}},ur=function(t,e){return void 0!==t?t:!0===e.optional&&void 0!==e.defaultvalue?e.defaultvalue:null},cr=function(t,e,r){var n;void 0===r&&(r=!1);var o=function(t,e){if(!V(e))throw new or("params is not an array! Did something gone wrong when you generate the contract.json?");if(0===e.length)return[];if(!V(t))throw new or("args is not an array! You might want to do: ES6 Array.from(arguments) or ES5 Array.prototype.slice.call(arguments)");switch(!0){case t.length==e.length:return t.map((function(t,r){return{arg:t,index:r,param:e[r]}}));case!0===e[0].variable:var r=e[0].type;return t.map((function(t,n){return{arg:t,index:n,param:e[n]||{type:r,name:"_"}}}));case t.lengthe.length:var n=e.length,o=["any"];return t.map((function(t,r){var i=r>=n||!!e[r].optional,a=e[r]||{type:o,name:"_"+r};return{arg:i?ur(t,a):t,index:r,param:a,optional:i}}));default:throw new ir("Could not understand your arguments and parameter structure!",{args:t,params:e})}}(t,e),i=o.filter((function(t){return!0===t.optional||!0===t.param.optional?function(t){var e=t.arg,r=t.param;return!!M(e)&&!(r.type.length>r.type.filter((function(e){return ar(e,t)})).length)}(t):!(t.param.type.length>t.param.type.filter((function(e){return ar(e,t)})).length)}));return r?((n={}).error=i,n.data=o.map((function(t){return t.arg})),n):i},sr=function(){try{var t=Zt(Object,"defineProperty");return t({},"",{}),t}catch(t){}}();function fr(t,e,r){"__proto__"==e&&sr?sr(t,e,{configurable:!0,enumerable:!0,value:r,writable:!0}):t[e]=r}function lr(t,e,r){(void 0===r||Ft(t[e],r))&&(void 0!==r||e in t)||fr(t,e,r)}var pr="object"==typeof exports&&exports&&!exports.nodeType&&exports,hr=pr&&"object"==typeof module&&module&&!module.nodeType&&module,vr=hr&&hr.exports===pr?i.Buffer:void 0,gr=vr?vr.allocUnsafe:void 0;function dr(t,e){var r,n,o=e?(r=t.buffer,n=new r.constructor(r.byteLength),new le(n).set(new le(r)),n):t.buffer;return new t.constructor(o,t.byteOffset,t.length)}var yr=Object.create,_r=function(){function t(){}return function(e){if(!Nt(e))return{};if(yr)return yr(e);t.prototype=e;var r=new t;return t.prototype=void 0,r}}();function br(t,e){if(("constructor"!==e||"function"!=typeof t[e])&&"__proto__"!=e)return t[e]}var mr=Object.prototype.hasOwnProperty;function jr(t,e,r){var n=t[e];mr.call(t,e)&&Ft(n,r)&&(void 0!==r||e in t)||fr(t,e,r)}var wr=Object.prototype.hasOwnProperty;function Or(t){if(!Nt(t))return function(t){var e=[];if(null!=t)for(var r in Object(t))e.push(r);return e}(t);var e=At(t),r=[];for(var n in t)("constructor"!=n||!e&&wr.call(t,n))&&r.push(n);return r}function Sr(t){return Rt(t)?$t(t,!0):Or(t)}function Er(t){return function(t,e,r,n){var o=!r;r||(r={});for(var i=-1,a=e.length;++i0){if(++e>=800)return arguments[0]}else e=0;return t.apply(void 0,arguments)}}(Pr);function zr(t,e){return Nr(function(t,e,r){return e=Ar(void 0===e?t.length-1:e,0),function(){for(var n=arguments,o=-1,i=Ar(n.length-e,0),a=Array(i);++o1?e[n-1]:void 0,i=n>2?e[2]:void 0;for(o=Rr.length>3&&"function"==typeof o?(n--,o):void 0,i&&function(t,e,r){if(!Nt(r))return!1;var n=typeof e;return!!("number"==n?Rt(r)&&dt(e,r.length):"string"==n&&e in r)&&Ft(r[e],t)}(e[0],e[1],i)&&(o=n<3?void 0:o,n=1),t=Object(t);++r0;)e[r]=arguments[r+1];if(this.logger("($queue) get called"),!0===this.__suspend_state__){if(un(this.__pattern__)){var n=this.__pattern__.test(t);if(!n)return!1}this.logger("($queue) added to $queue",e),this.queueStore.add([t].concat(e))}return!!this.__suspend_state__},fn.$queues.get=function(){var t=this.queueStore.size;return this.logger("($queues)","size: "+t),t>0?Array.from(this.queueStore):[]},sn.prototype.__suspend__=function(t){if("boolean"!=typeof t)throw new Error("$suspend only accept Boolean value! we got "+typeof t);var e=this.__suspend_state__;this.__suspend_state__=t,this.logger('($suspend) Change from "'+e+'" --\x3e "'+t+'"'),!0===e&&!1===t&&this.__release__()},sn.prototype.__release__=function(){var t=this,e=this.queueStore.size,r=this.__pattern__;if(this.__pattern__=null,this.logger("(release) was called with "+e+(r?' for "'+r+'"':"")+" item"+(e>1?"s":"")),e>0){var n=Array.from(this.queueStore);this.queueStore.clear(),this.logger("(release queue)",n),n.forEach((function(e){t.logger(e),Reflect.apply(t.$trigger,t,e)})),this.logger("Release size "+this.queueStore.size)}return e},Object.defineProperties(sn.prototype,fn);var ln=function(t){function e(e){if("function"!=typeof e)throw new Error("Just die here the logger is not a function!");e("---\x3e Create a new EventEmitter <---"),t.call(this,{logger:e})}t&&(e.__proto__=t),e.prototype=Object.create(t&&t.prototype),e.prototype.constructor=e;var r={name:{configurable:!0}};return r.name.get=function(){return"jsonql-ws-client-core"},Object.defineProperties(e.prototype,r),e}(function(t){function e(e){void 0===e&&(e={}),t.call(this,e)}t&&(e.__proto__=t),e.prototype=Object.create(t&&t.prototype),e.prototype.constructor=e;var r={$name:{configurable:!0},is:{configurable:!0},$done:{configurable:!0}};return e.prototype.logger=function(){},r.$name.get=function(){return"to1source-event"},r.is.get=function(){return this.$name},e.prototype.$on=function(t,e,r){var n=this;void 0===r&&(r=null);this.validate(t,e);var o=this.takeFromStore(t);if(!1===o)return this.logger('($on) "'+t+'" is not in lazy store'),this.addToNormalStore(t,"on",e,r);this.logger("($on) "+t+" found in lazy store");var i=0;return o.forEach((function(o){var a=o[0],u=o[1],c=o[2];if(c&&"on"!==c)throw new Error(nn+" "+c);n.logger("($on)",'call run "'+t+'"'),n.run(e,a,r||u),i+=n.addToNormalStore(t,"on",e,r||u)})),this.logger("($on) return size "+i),i},e.prototype.$once=function(t,e,r){void 0===r&&(r=null),this.validate(t,e);var n=this.takeFromStore(t);this.normalStore;if(!1===n)return this.logger('($once) "'+t+'" is not in the lazy store'),this.addToNormalStore(t,"once",e,r);this.logger("($once)",n);var o=Array.from(n)[0],i=o[0],a=o[1],u=o[2];if(u&&"once"!==u)throw new Error(nn+" "+u);this.logger("($once)",'call run "'+t+'"'),this.run(e,i,r||a),this.$off(t)},e.prototype.$only=function(t,e,r){var n=this;void 0===r&&(r=null),this.validate(t,e);var o=!1,i=this.takeFromStore(t);(this.normalStore.has(t)||(this.logger('($only) "'+t+'" add to normalStore'),o=this.addToNormalStore(t,"only",e,r)),!1!==i)&&(this.logger('($only) "'+t+'" found data in lazy store to execute'),Array.from(i).forEach((function(o){var i=o[0],a=o[1],u=o[2];if(u&&"only"!==u)throw new Error(nn+" "+u);n.logger('($only) call run "'+t+'"'),n.run(e,i,r||a)})));return o},e.prototype.$onlyOnce=function(t,e,r){void 0===r&&(r=null),this.validate(t,e);var n=!1,o=this.takeFromStore(t);if(this.normalStore.has(t)||(this.logger('($onlyOnce) "'+t+'" add to normalStore'),n=this.addToNormalStore(t,"onlyOnce",e,r)),!1!==o){this.logger("($onlyOnce)",o);var i=Array.from(o)[0],a=i[0],u=i[1],c=i[2];if(c&&"onlyOnce"!==c)throw new Error(nn+" "+c);this.logger('($onlyOnce) call run "'+t+'"'),this.run(e,a,r||u),this.$off(t)}return n},e.prototype.$replace=function(t,e,r,n){if(void 0===r&&(r=null),void 0===n&&(n="on"),this.validateType(n)){this.$off(t);var o=this["$"+n];return this.logger("($replace)",t,e),Reflect.apply(o,this,[t,e,r])}throw new Error(n+" is not supported!")},e.prototype.$trigger=function(t,e,r,n){void 0===e&&(e=[]),void 0===r&&(r=null),void 0===n&&(n=!1),this.validateEvt(t);var o=0,i=this.normalStore;if(this.logger("($trigger) normalStore",i),i.has(t)){if(this.logger('($trigger) "'+t+'" found'),this.$queue(t,e,r,n))return this.logger('($trigger) Currently suspended "'+t+'" added to queue, nothing executed. Exit now.'),!1;for(var a=Array.from(i.get(t)),u=a.length,c=!1,s=0;s0;)n[o]=arguments[o+2];if(t.has(e)?(this.logger('(addToStore) "'+e+'" existed'),r=t.get(e)):(this.logger('(addToStore) create new Set for "'+e+'"'),r=new Set),n.length>2)if(Array.isArray(n[0])){var i=n[2];this.checkTypeInLazyStore(e,i)||r.add(n)}else this.checkContentExist(n,r)||(this.logger("(addToStore) insert new",n),r.add(n));else r.add(n);return t.set(e,r),[t,r.size]},e.prototype.checkContentExist=function(t,e){return!!Array.from(e).filter((function(e){return e[0]===t[0]})).length},e.prototype.checkTypeInStore=function(t,e){this.validateEvt(t,e);var r=this.$get(t,!0);return!1===r||!r.filter((function(t){var r=t[3];return e!==r})).length},e.prototype.checkTypeInLazyStore=function(t,e){this.validateEvt(t,e);var r=this.lazyStore.get(t);return this.logger("(checkTypeInLazyStore)",r),!!r&&!!Array.from(r).filter((function(t){return t[2]!==e})).length},e.prototype.addToNormalStore=function(t,e,r,n){if(void 0===n&&(n=null),this.logger('(addToNormalStore) try to add "'+e+'" --\x3e "'+t+'" to normal store'),this.checkTypeInStore(t,e)){this.logger("(addToNormalStore)",'"'+e+'" --\x3e "'+t+'" can add to normal store');var o=this.hashFnToKey(r),i=[this.normalStore,t,o,r,n,e],a=Reflect.apply(this.addToStore,this,i),u=a[0],c=a[1];return this.normalStore=u,c}return!1},e.prototype.addToLazyStore=function(t,e,r,n){void 0===e&&(e=[]),void 0===r&&(r=null),void 0===n&&(n=!1);var o=[this.lazyStore,t,this.toArray(e),r];n&&o.push(n);var i=Reflect.apply(this.addToStore,this,o),a=i[0],u=i[1];return this.lazyStore=a,this.logger("(addToLazyStore) size: "+u),u},e.prototype.toArray=function(t){return Array.isArray(t)?t:[t]},r.normalStore.set=function(t){on.set(this,t)},r.normalStore.get=function(){return on.get(this)},r.lazyStore.set=function(t){an.set(this,t)},r.lazyStore.get=function(){return an.get(this)},e.prototype.hashFnToKey=function(t){return function(t){return t.split("").reduce((function(t,e){return(t=(t<<5)-t+e.charCodeAt(0))&t}),0)}(t.toString())+""},Object.defineProperties(e.prototype,r),e}(sn))),pn=function(t){return c(t)?t:[t]},hn=function(t,e){try{var r=Object.keys(t);return n=e,!!r.filter((function(t){return t===n})).length}catch(t){return!1}var n},vn=function(){for(var t=[],e=arguments.length;e--;)t[e]=arguments[e];return t.join("_")},gn=function(t){if("function"==typeof t)return!0;console.error("Expect to be Function type! Got "+typeof t)},dn=function(){return!1},yn=function(t){for(var e=[],r=arguments.length-1;r-- >0;)e[r]=arguments[r+1];return function(){for(var r=[],n=arguments.length;n--;)r[n]=arguments[n];return e.reduce((function(t,e){return Reflect.apply(e,null,pn(t))}),Reflect.apply(t,null,r))}};function _n(t,e,r,n){return void 0===n&&(n=null),void 0===Object.getOwnPropertyDescriptor(t,e)&&Object.defineProperty(t,e,{set:r,get:null===n?function(){return null}:n}),t}function bn(t,e,r,n){void 0===n&&(n=!1);var o=function(t,e){var r=Object.getOwnPropertyDescriptor(t,e);return void 0!==r&&r.value?r.value:r}(t,e);return!1===n&&void 0!==o||Object.defineProperty(t,e,{value:r,writable:n}),t}var mn=function(t){function e(){for(var r=[],n=arguments.length;n--;)r[n]=arguments[n];t.apply(this,r),this.message=r[0],this.detail=r[1],this.className=e.name,t.captureStackTrace&&t.captureStackTrace(this,e)}t&&(e.__proto__=t),e.prototype=Object.create(t&&t.prototype),e.prototype.constructor=e;var r={statusCode:{configurable:!0},name:{configurable:!0}};return r.statusCode.get=function(){return 406},r.name.get=function(){return"Jsonql406Error"},Object.defineProperties(e,r),e}(Error),jn=function(t){function e(){for(var r=[],n=arguments.length;n--;)r[n]=arguments[n];t.apply(this,r),this.message=r[0],this.detail=r[1],this.className=e.name,t.captureStackTrace&&t.captureStackTrace(this,e)}t&&(e.__proto__=t),e.prototype=Object.create(t&&t.prototype),e.prototype.constructor=e;var r={statusCode:{configurable:!0},name:{configurable:!0}};return r.statusCode.get=function(){return 500},r.name.get=function(){return"Jsonql500Error"},Object.defineProperties(e,r),e}(Error),wn=function(t){function e(){for(var r=[],n=arguments.length;n--;)r[n]=arguments[n];t.apply(this,r),this.message=r[0],this.detail=r[1],this.className=e.name,t.captureStackTrace&&t.captureStackTrace(this,e)}t&&(e.__proto__=t),e.prototype=Object.create(t&&t.prototype),e.prototype.constructor=e;var r={statusCode:{configurable:!0},name:{configurable:!0}};return r.statusCode.get=function(){return 403},r.name.get=function(){return"JsonqlForbiddenError"},Object.defineProperties(e,r),e}(Error),On=function(t){function e(){for(var r=[],n=arguments.length;n--;)r[n]=arguments[n];t.apply(this,r),this.message=r[0],this.detail=r[1],this.className=e.name,t.captureStackTrace&&t.captureStackTrace(this,e)}t&&(e.__proto__=t),e.prototype=Object.create(t&&t.prototype),e.prototype.constructor=e;var r={statusCode:{configurable:!0},name:{configurable:!0}};return r.statusCode.get=function(){return 401},r.name.get=function(){return"JsonqlAuthorisationError"},Object.defineProperties(e,r),e}(Error),Sn=function(t){function e(){for(var r=[],n=arguments.length;n--;)r[n]=arguments[n];t.apply(this,r),this.message=r[0],this.detail=r[1],this.className=e.name,t.captureStackTrace&&t.captureStackTrace(this,e)}t&&(e.__proto__=t),e.prototype=Object.create(t&&t.prototype),e.prototype.constructor=e;var r={statusCode:{configurable:!0},name:{configurable:!0}};return r.statusCode.get=function(){return 401},r.name.get=function(){return"JsonqlContractAuthError"},Object.defineProperties(e,r),e}(Error),En=function(t){function e(){for(var r=[],n=arguments.length;n--;)r[n]=arguments[n];t.apply(this,r),this.message=r[0],this.detail=r[1],this.className=e.name,t.captureStackTrace&&t.captureStackTrace(this,e)}t&&(e.__proto__=t),e.prototype=Object.create(t&&t.prototype),e.prototype.constructor=e;var r={statusCode:{configurable:!0},name:{configurable:!0}};return r.statusCode.get=function(){return 500},r.name.get=function(){return"JsonqlResolverAppError"},Object.defineProperties(e,r),e}(Error),kn=function(t){function e(){for(var r=[],n=arguments.length;n--;)r[n]=arguments[n];t.apply(this,r),this.message=r[0],this.detail=r[1],this.className=e.name,t.captureStackTrace&&t.captureStackTrace(this,e)}t&&(e.__proto__=t),e.prototype=Object.create(t&&t.prototype),e.prototype.constructor=e;var r={statusCode:{configurable:!0},name:{configurable:!0}};return r.statusCode.get=function(){return 404},r.name.get=function(){return"JsonqlResolverNotFoundError"},Object.defineProperties(e,r),e}(Error),$n=function(t){function e(r,n){t.call(this,n),this.statusCode=r,this.className=e.name}t&&(e.__proto__=t),e.prototype=Object.create(t&&t.prototype),e.prototype.constructor=e;var r={name:{configurable:!0}};return r.name.get=function(){return"JsonqlServerError"},Object.defineProperties(e,r),e}(Error);function Tn(t){if(Array.isArray(t))throw new or("",t);var e=t.message||"No message",r=t.detail||t;switch(!0){case t instanceof mn:throw new mn(e,r);case t instanceof jn:throw new jn(e,r);case t instanceof wn:throw new wn(e,r);case t instanceof On:throw new On(e,r);case t instanceof Sn:throw new Sn(e,r);case t instanceof En:throw new En(e,r);case t instanceof kn:throw new kn(e,r);case t instanceof Wr:throw new Wr(e,r);case t instanceof Br:throw new Br(e,r);case t instanceof Vr:throw new Vr(e,r);case t instanceof or:throw new or(e,r);case t instanceof $n:throw new $n(e,r);default:throw new ir(e,r)}}function An(t){return!!hn(t,"socket")&&t.socket}function Pn(t){var e,r,n=t.contract;return t.enableAuth?function(t){var e=An(t);if(!1===e)throw new JsonqlError("groupByNamespace","socket not found in contract!");var r,n={},o=0;for(var i in e){var a=e[i],u=a.namespace;u&&(n[u]||(++o,n[u]={}),n[u][i]=a,!r&&a.public&&(r=u))}return{size:o,nspGroup:n,publicNamespace:r}}(n):((r={}).nspSet=((e={}).jsonql=function(t){var e=An(t);if(!1!==e)return e;throw new kn("Missing property in contract!")}(n),e),r.publicNamespace="jsonql",r)}var xn=function(t){var e=t.toLowerCase();return e.indexOf("http")>-1?e.indexOf("https")>-1?e.replace("https","wss"):e.replace("http","ws"):e},Nn=function(t,e){pn(e).forEach((function(e){t.$off(vn(e,"emit_reply"))}))},zn=function(t,e,r){return[bn(t,e.loginHandlerName,(function(t){if(t&&Qr(t))return e.log("Received __login__ with "+t),r.$trigger("__login__",[t]);throw new or(e.loginHandlerName,"Unexpected token "+t)})),e,r]},Rn=function(t,e,r){return[bn(t,e.logoutHandlerName,(function(){for(var t=[],e=arguments.length;e--;)t[e]=arguments[e];r.$trigger("__logout__",t)})),e,r]},qn=function(t,e,r){return[_n(t,"onLogin",(function(t){gn(t)&&r.$only("onLogin",t)})),e,r]};function Cn(t,e,r){return yn(zn,Rn,qn)(t,e,r)}function Fn(t,e,r){hn(t,"error")?r(t.error):hn(t,"data")?e(t.data):r({message:"UKNNOWN RESULT!",error:t})}function Ln(t,e,r,n,o){void 0===n&&(n=[]);var i=vn(e,"emit_reply");return o("actionCall: "+i+" --\x3e "+r,n),t.$trigger(i,[r,pn(n)]),new Promise((function(n,i){t.$on(vn(e,r,"onResult"),(function(t){o("got the first result",t),Fn(t,n,i)}))}))}var Mn,Jn,Dn,Un=function(t,e,r,n,o,i){return _n(t,"send",dn,(function(){var t=function(){for(var t=[],e=arguments.length;e--;)t[e]=arguments[e];return Reflect.apply(console.info,console,["[SEND]"].concat(t))};return function(){for(var i=[],a=arguments.length;a--;)i[a]=arguments[a];return Xr(i,o.params,!0).then((function(o){return t(r,n,o),Ln(e,r,n,o,t)})).catch((function(o){t("send error",o),e.$call(vn(r,n,"onError"),[new or(n,o)])}))}}))},Hn=function(t,e,r,n,o,i){return[bn(t,"myNamespace",r),e,r,n,o,i]},In=function(t,e,r,n,o,i){return[_n(t,"onResult",(function(t){gn(t)&&e.$on(vn(r,n,"onResult"),(function(o){Fn(o,t,(function(t){i('Catch error: "'+n+'"',t),e.$trigger(vn(r,n,"onError"),t)}))}))})),e,r,n,o,i]},Wn=function(t,e,r,n,o,i){return[_n(t,"onMessage",(function(t){if(gn(t)){e.$only(vn(r,n,"onMessage"),(function(o){Fn(o,t,(function(t){i('Catch error: "'+n+'"',t),e.$trigger(vn(r,n,"onError"),t)}))}))}})),e,r,n,o,i]},Bn=function(t,e,r,n,o,i){return[_n(t,"onError",(function(t){gn(t)&&e.$only(vn(r,n,"onError"),t)})),e,r,n,o,i]};function Vn(t,e,r,n,o,i){var a=[Hn,In,Wn,Bn,Un],u=Reflect.apply(yn,null,a),c=[n,o,t,e,r,i];return Reflect.apply(u,null,c)}function Yn(t,e,r,n,o){return function(){for(var i=[],a=arguments.length;a--;)i[a]=arguments[a];return Xr(i,n.params,!0).then((function(n){return Ln(t,e,r,n,o)})).catch(Tn)}}function Gn(t,e,r){var n={},o=t.log;for(var i in r){var a=r[i];for(var u in a){var c=a[u];n=bn(n,u,Vn(i,u,c,Yn(e,i,u,c,o),e,o))}}return[n,t,e,r]}function Kn(t,e,r,n){return[_n(t,"onError",(function(t){if(gn(t))for(var e in n)r.$on(vn(e,"onError"),t)})),e,r]}function Qn(t,e,r){return[_n(t,"onReady",(function(t){gn(t)&&r.$on("onReady",t)})),e,r]}function Xn(t,e,r){var n=function(t,e,r){return bn(t,e.disconnectHandlerName,(function(){for(var t=[],e=arguments.length;e--;)t[e]=arguments[e];r.$trigger("__disconnect__",t)}))}(t,e,r);return e.log("---\x3e The final step to return the ws-client <---"),n.verifyEventEmitter=function(){return r.is},n.eventEmitter=e.eventEmitter,n.log=e.log,n}var Zn=["roundtip","handshake"],to={standalone:Zr(!1,["boolean"]),debugOn:Zr(!1,["boolean"]),loginHandlerName:Zr("login",["string"]),logoutHandlerName:Zr("logout",["string"]),disconnectHandlerName:Zr("disconnect",["string"]),switchUserHandlerName:Zr("switch-user",["string"]),loginMethod:Zr("handshake",["string"],(Mn={},Mn.enumv=Zn,Mn)),useJwt:Zr(!0,["boolean","string"]),authStrKey:Zr(null,["string"]),hostname:Zr(!1,["string"]),namespace:Zr("jsonql",["string"]),wsOptions:Zr({},["object"]),contract:Zr({},["object"],(Jn={},Jn.checker=function(t){return!!function(t){return nt(t)&&(hn(t,"query")||hn(t,"mutation")||hn(t,"socket"))}(t)&&t},Jn)),enableAuth:Zr(!1,["boolean"]),token:Zr(!1,["string"])},eo={};eo.serverType=Zr(null,["string"],((Dn={}).alias="socketClientType",Dn));var ro=Object.assign(to,eo),no={log:null,eventEmitter:null,nspClient:null,nspAuthClient:null,wssPath:""};function oo(t){return Promise.resolve(t).then((function(t){return t.hostname||(t.hostname=function(){try{return[window.location.protocol,window.location.host].join("//")}catch(t){throw new or(t)}}()),t.wssPath=xn([t.hostname,t.namespace].join("/"),t.serverType),t.log=rn(t),t.eventEmitter=function(t){var e=t.log,r=t.eventEmitter;return r?(e("eventEmitter is:",r.name),r):new ln(t.log)}(t),t}))}function io(t){return{opts:t,nspMap:Pn(t),ee:t.eventEmitter}}function ao(t,e){return oo(e).then(io).then((function(e){var r=e.opts,n=e.nspMap,o=e.ee;return t(r,n,o)})).then((function(t){return function(t,e,r){var n=e.nspSet,o=[Gn,Kn,Qn];return t.enableAuth&&o.push(Cn),o.push(Xn),Reflect.apply(yn,null,o)(t,r,n)}(t.opts,t.nspMap,t.ee)})).catch((function(t){console.error("jsonql-ws-core-client init error",t)}))}function uo(t,e,r){return void 0===e&&(e={}),void 0===r&&(r={}),function(n){return void 0===n&&(n={}),function(t,e,r){var n=Object.assign(no,r),o=Object.assign(ro,e);return tn(t,o,n)}(n,e,r).then((function(e){return ao(t,e)}))}}function co(t,e){var r=e.hostname,n=e.wssPath,o=e.wsOptions;return(0,e.nspClient)(t?[r,t].join("/"):n,o)}function so(t,e,r){e.forEach((function(e){t.$trigger(vn(e,"onError"),[{message:r,namespace:e}])}))}var fo=function(t,e,r){var n=r.log;e.$only(vn(t,"emit_reply"),(function(r,o){n("[notLoginHandler] hijack the ws call",t,r,o);var i={message:"NOT LOGIN"};e.$call(vn(t,r,"onError"),[i]),e.$call(vn(t,r,"onResult"),[{error:i}])}))},lo=function(t){return t.length>1&&t[0]},po=function(t,e,r,n){var o=n.log;r.$on("__disconnect__",(function(){so(r,e,"__disconnect__"),e.forEach((function(e){o("disconnect from "+e),Nn(r,e),t[e]=null,function(t,e,r){var n=r.log;e.$only(vn(t,"emit_reply"),(function(r,o){n("[disconnectedHandler] hijack the ws call",t,r,o);var i={message:"You have disconnected from the socket server, please reconnect."};e.$call(vn(t,r,"onError"),[i]),e.$call(vn(t,r,"onResult"),[{error:i}])}))}(e,r,n)}))}))};function ho(t,e,r,n,o,i){var a=lo(o),u=!1,c=!1,s=t.log;o.forEach((function(o){if(u=a===o,c||(c=u),i[o]){s("[call bindWsHandler]",u,o);var f=[o,i[o],r,u,t];if("socket.io"===t.serverType){var l=e.nspSet;f.push(l[o])}Reflect.apply(n,null,f)}else fo(o,r,t)})),c&&(s("Has private and add logoutEvtHandler"),function(t,e,r,n){var o=n.log;r.$on("__logout__",(function(){var i=lo(e);o("__logout__ event triggered"),so(r,[i],"__logout__"),o("logout from "+i),Nn(r,i),t[i]=null,fo(i,r,n)}))}(i,o,r,t)),po(i,o,r,t)}var vo={version:"version: 1.1.1 module: cjs",serverType:"ws"},go=Object.assign({},ro,{}),yo=Object.assign({},no,vo);function _o(t,e){return void 0===e&&(e=!1),!1===e?function(e){return new t(xn(e))}:function(e,r){var n=xn(e),o=r&&"string"==typeof r?n+"?token="+r:n;try{return new t(o)}catch(t){return console.error("WebSocket Connection Error",t),!1}}}var bo=Array.isArray,mo="object"==typeof r&&r&&r.Object===Object&&r,jo="object"==typeof self&&self&&self.Object===Object&&self,wo=(mo||jo||Function("return this")()).Symbol,Oo=Object.prototype,So=Oo.hasOwnProperty,Eo=Oo.toString,ko=wo?wo.toStringTag:void 0;var $o=Object.prototype.toString;var To=wo?wo.toStringTag:void 0;function Ao(t){return null==t?void 0===t?"[object Undefined]":"[object Null]":To&&To in Object(t)?function(t){var e=So.call(t,ko),r=t[ko];try{t[ko]=void 0;var n=!0}catch(t){}var o=Eo.call(t);return n&&(e?t[ko]=r:delete t[ko]),o}(t):function(t){return $o.call(t)}(t)}function Po(t){return null!=t&&"object"==typeof t}var xo=wo?wo.prototype:void 0,No=xo?xo.toString:void 0;function zo(t){if("string"==typeof t)return t;if(bo(t))return function(t,e){for(var r=-1,n=null==t?0:t.length,o=Array(n);++r=n?t:function(t,e,r){var n=-1,o=t.length;e<0&&(e=-e>o?0:o+e),(r=r>o?o:r)<0&&(r+=o),o=e>r?0:r-e>>>0,e>>>=0;for(var i=Array(o);++n-1;);return r}(o,i),function(t,e){for(var r=t.length;r--&&Co(e,t[r],0)>-1;);return r}(o,i)+1).join("")}var Qo=function(){for(var t=[],e=arguments.length;e--;)t[e]=arguments[e];return t.join("_")},Xo=function(t){function e(){for(var r=[],n=arguments.length;n--;)r[n]=arguments[n];t.apply(this,r),this.message=r[0],this.detail=r[1],this.className=e.name,t.captureStackTrace&&t.captureStackTrace(this,e)}t&&(e.__proto__=t),e.prototype=Object.create(t&&t.prototype),e.prototype.constructor=e;var r={name:{configurable:!0}};return r.name.get=function(){return"JsonqlValidationError"},Object.defineProperties(e,r),e}(Error),Zo=function(t){function e(){for(var r=[],n=arguments.length;n--;)r[n]=arguments[n];t.apply(this,r),this.message=r[0],this.detail=r[1],this.className=e.name,t.captureStackTrace&&t.captureStackTrace(this,e)}t&&(e.__proto__=t),e.prototype=Object.create(t&&t.prototype),e.prototype.constructor=e;var r={name:{configurable:!0},statusCode:{configurable:!0}};return r.name.get=function(){return"JsonqlError"},r.statusCode.get=function(){return-1},Object.defineProperties(e,r),e}(Error),ti=function(t){void 0===t&&(t=!1);var e=Date.now();return t?Math.floor(e/1e3):e};function ei(t){return"string"==typeof t||!bo(t)&&Po(t)&&"[object String]"==Ao(t)}function ri(t,e,r){if(void 0===e&&(e=[]),void 0===r&&(r=!1),ei(t)&&bo(e)){var n=function(t){var e;return(e={}).args=t,e}(e);return!0===r?n:function(t,e){var r;return(r={})[t]=e,r.TS=[ti()],r}(t,n)}throw new Xo("[createQuery] expect resolverName to be string and args to be array!",{resolverName:t,args:e})}var ni=function(t){return""!==Ko(t)&&ei(t)},oi=["__reply__","__event__","__data__"],ii=function(t){var e=t.data;return!!e&&(oi.filter((function(t){return function(t,e){try{var r=Object.keys(t);return n=e,!!r.filter((function(t){return t===n})).length}catch(t){return!1}var n}(e,t)})).length===oi.length&&e)},ai=function(t,e,r,n,o){var i=[e];r&&i.push(r),i.push(o);var a=Reflect.apply(Qo,null,i),u=n.data||n;t.$trigger(a,[u])};function ui(t,e,r,n,o){var i=function(){for(var t=[],e=arguments.length;e--;)t[e]=arguments[e];return Reflect.apply(console.info,console,["[socketEventHandler]"].concat(t))};i("log test, isPrivate:",n),e.onopen=function(){i("ws.onopen listened"),r.$call("onReady",t),n&&(i("isPrivate and fire the onLogin"),r.$call("onLogin",t)),r.$only(Qo(t,"emit_reply"),(function(t,r){var n=function(t,e,r){return void 0===e&&(e=[]),void 0===r&&(r=!1),JSON.stringify(ri(t,e,r))}(t,r);i("calling server",t,r,n),e.send(n)}))},e.onmessage=function(e){try{var n=function(t){var e,r=t.data,n=ni(r)?JSON.parse(r):r;if(!1!==(e=ii(n)))return{resolverName:e.__event__,data:e.__data__,type:e.__reply__};throw new Zo("payload can not be decoded",t)}(e),o=n.resolverName,a=n.type;switch(i("Hear from server",a,n),a){case"emit_reply":var u=Qo(t,o,"onMessage"),c=r.$trigger(u,[n]);i("EMIT_REPLY_TYPE",u,c);break;case"acknowledge_reply":var s=Qo(t,o,"onResult"),f=r.$trigger(s,[n]);i("ACKNOWLEDGE_REPLY_TYPE",s,f);break;case"error":i("ERROR_TYPE"),ai(r,t,o,n,"onError");break;default:i("Unhandled event!",n),ai(r,t,o,n,"onError")}}catch(e){console.error("ws.onmessage error",e),ai(r,t,!1,e,"onError")}},e.onclose=function(){i("ws.onclose callback")},e.onerror=function(e){i("ws.onerror",e),r.$trigger(Qo(t,"onError"),[e])},n&&r.$on("__logout__",(function(){try{i("terminate ws connection"),e.terminate()}catch(t){console.error("ws.terminate error",t)}}))}var ci=function(t,e,r){var n,o=t.log,i=e.nspSet,a=e.publicNamespace,u=!1,c=[],s={};if(t.enableAuth)u=!0,s=(c=function(t,e){var r=[];for(var n in t)n===e?r[1]=n:r[0]=n;return r}(i,a)).map((function(e,n){var i,a,u;return 0===n?r?(t.token=r,o("create createNspAuthClient at run time"),(i={})[e]=function(t,e){var r=e.hostname,n=e.wssPath,o=e.token,i=e.wsOptions,a=e.nspAuthClient,u=t?[r,t].join("/"):n;if(o&&"string"!=typeof o)throw new Error("Expect token to be string, but got "+o);return a(u,o,i)}(e,t),i):((a={})[e]=!1,a):((u={})[e]=co(e,t),u)})).reduce((function(t,e){return Object.assign(t,e)}),{});else{var f=(n=i,console.error("This method is going to be deprectead in the next release, please use getResolverFromPayload instead"),Object.keys(n)[0]);c.push(f),s[f]=co(!1,t)}return{nsps:s,namespaces:c,loginRequired:u}};function si(t,e,r,n){var o=n.log;t.$only("__login__",(function(i){o("createClient LOGIN_EVENT_NAME $only handler"),Nn(t,e);var a=ci(n,r,i);Reflect.apply(ho,null,args.concat([a.namespaces,a.nsps]))}))}var fi,li,pi,hi=(li=_o(fi=e),pi=_o(fi,!0),function(t,e,r){t.nspClient=li,t.nspAuthClient=pi;var n=t.log;return n&&"function"==typeof n&&(n("@jsonql/ws ee",r.name),n("@jsonql/ws createClientResolver",t)),function(t,e,r){var n=[t,e,r,ui],o=t.token,i=(t.log,ci(t,e,o)),a=i.nsps,u=i.namespaces,c=i.loginRequired;return Reflect.apply(ho,null,n.concat([u,a])),c&&si(r,u,e,t),{opts:t,nspMap:e,ee:r}}(t,e,r)});module.exports=function(t,e){return void 0===t&&(t={}),void 0===e&&(e={}),uo(hi,go,Object.assign({},yo,e))(t)}; +"use strict";var t,e=(t=require("ws"))&&"object"==typeof t&&"default"in t?t.default:t,r="undefined"!=typeof global?global:"undefined"!=typeof self?self:"undefined"!=typeof window?window:{},n="object"==typeof r&&r&&r.Object===Object&&r,o="object"==typeof self&&self&&self.Object===Object&&self,i=n||o||Function("return this")(),a=i.Symbol;function u(t,e){for(var r=-1,n=null==t?0:t.length,o=Array(n);++r=n?t:function(t,e,r){var n=-1,o=t.length;e<0&&(e=-e>o?0:o+e),(r=r>o?o:r)<0&&(r+=o),o=e>r?0:r-e>>>0,e>>>=0;for(var i=Array(o);++n-1;);return r}(n,o),function(t,e){for(var r=t.length;r--&&O(e,t[r],0)>-1;);return r}(n,o)+1).join("")}var M=function(t){return!!c(t)||null!=t&&""!==L(t)};function J(t){return function(t){return"number"==typeof t||d(t)&&"[object Number]"==g(t)}(t)&&t!=+t}function U(t){return"string"==typeof t||!c(t)&&d(t)&&"[object String]"==g(t)}var D=function(t){return!U(t)&&!J(parseFloat(t))},H=function(t){return""!==L(t)&&U(t)},I=function(t){return null!=t&&"boolean"==typeof t},G=function(t,e){return void 0===e&&(e=!0),void 0!==t&&""!==t&&""!==L(t)&&(!1===e||!0===e&&null!==t)},W=function(t){switch(t){case"number":return D;case"string":return H;case"boolean":return I;default:return G}},B=function(t,e){return void 0===e&&(e=""),!!c(t)&&(""===e||""===L(e)||!(t.filter((function(t){return!W(e)(t)})).length>0))},V=function(t){if(t.indexOf("array.<")>-1&&t.indexOf(">")>-1){var e=t.replace("array.<","").replace(">","");return e.indexOf("|")?e.split("|"):[e]}return!1},Y=function(t,e){var r=t.arg;return e.length>1?!r.filter((function(t){return!(e.length>e.filter((function(e){return!W(e)(t)})).length)})).length:e.length>e.filter((function(t){return!B(r,t)})).length};function K(t,e){return function(r){return t(e(r))}}var Q=K(Object.getPrototypeOf,Object),X=Function.prototype,Z=Object.prototype,tt=X.toString,et=Z.hasOwnProperty,rt=tt.call(Object);function nt(t){if(!d(t)||"[object Object]"!=g(t))return!1;var e=Q(t);if(null===e)return!0;var r=et.call(e,"constructor")&&e.constructor;return"function"==typeof r&&r instanceof r&&tt.call(r)==rt}var ot,it=function(t,e,r){for(var n=-1,o=Object(t),i=r(t),a=i.length;a--;){var u=i[ot?a:++n];if(!1===e(o[u],u,o))break}return t};function at(t){return d(t)&&"[object Arguments]"==g(t)}var ut=Object.prototype,ct=ut.hasOwnProperty,st=ut.propertyIsEnumerable,ft=at(function(){return arguments}())?at:function(t){return d(t)&&ct.call(t,"callee")&&!st.call(t,"callee")};var lt="object"==typeof exports&&exports&&!exports.nodeType&&exports,pt=lt&&"object"==typeof module&&module&&!module.nodeType&&module,ht=pt&&pt.exports===lt?i.Buffer:void 0,vt=(ht?ht.isBuffer:void 0)||function(){return!1},gt=/^(?:0|[1-9]\d*)$/;function dt(t,e){var r=typeof t;return!!(e=null==e?9007199254740991:e)&&("number"==r||"symbol"!=r&>.test(t))&&t>-1&&t%1==0&&t-1&&t%1==0&&t<=9007199254740991}var _t={};_t["[object Float32Array]"]=_t["[object Float64Array]"]=_t["[object Int8Array]"]=_t["[object Int16Array]"]=_t["[object Int32Array]"]=_t["[object Uint8Array]"]=_t["[object Uint8ClampedArray]"]=_t["[object Uint16Array]"]=_t["[object Uint32Array]"]=!0,_t["[object Arguments]"]=_t["[object Array]"]=_t["[object ArrayBuffer]"]=_t["[object Boolean]"]=_t["[object DataView]"]=_t["[object Date]"]=_t["[object Error]"]=_t["[object Function]"]=_t["[object Map]"]=_t["[object Number]"]=_t["[object Object]"]=_t["[object RegExp]"]=_t["[object Set]"]=_t["[object String]"]=_t["[object WeakMap]"]=!1;var bt,mt="object"==typeof exports&&exports&&!exports.nodeType&&exports,jt=mt&&"object"==typeof module&&module&&!module.nodeType&&module,wt=jt&&jt.exports===mt&&n.process,Ot=function(){try{var t=jt&&jt.require&&jt.require("util").types;return t||wt&&wt.binding&&wt.binding("util")}catch(t){}}(),St=Ot&&Ot.isTypedArray,Et=St?(bt=St,function(t){return bt(t)}):function(t){return d(t)&&yt(t.length)&&!!_t[g(t)]},kt=Object.prototype.hasOwnProperty;function $t(t,e){var r=c(t),n=!r&&ft(t),o=!r&&!n&&vt(t),i=!r&&!n&&!o&&Et(t),a=r||n||o||i,u=a?function(t,e){for(var r=-1,n=Array(t);++r-1},Jt.prototype.set=function(t,e){var r=this.__data__,n=Lt(r,t);return n<0?(++this.size,r.push([t,e])):r[n][1]=e,this};var Ut,Dt=i["__core-js_shared__"],Ht=(Ut=/[^.]+$/.exec(Dt&&Dt.keys&&Dt.keys.IE_PROTO||""))?"Symbol(src)_1."+Ut:"";var It=Function.prototype.toString;function Gt(t){if(null!=t){try{return It.call(t)}catch(t){}try{return t+""}catch(t){}}return""}var Wt=/^\[object .+?Constructor\]$/,Bt=Function.prototype,Vt=Object.prototype,Yt=Bt.toString,Kt=Vt.hasOwnProperty,Qt=RegExp("^"+Yt.call(Kt).replace(/[\\^$.*+?()[\]{}|]/g,"\\$&").replace(/hasOwnProperty|(function).*?(?=\\\()| for .+?(?=\\\])/g,"$1.*?")+"$");function Xt(t){return!(!xt(t)||function(t){return!!Ht&&Ht in t}(t))&&(zt(t)?Qt:Wt).test(Gt(t))}function Zt(t,e){var r=function(t,e){return null==t?void 0:t[e]}(t,e);return Xt(r)?r:void 0}var te=Zt(i,"Map"),ee=Zt(Object,"create");var re=Object.prototype.hasOwnProperty;var ne=Object.prototype.hasOwnProperty;function oe(t){var e=-1,r=null==t?0:t.length;for(this.clear();++eu))return!1;var s=i.get(t);if(s&&i.get(e))return s==e;var f=-1,l=!0,p=2&r?new ce:void 0;for(i.set(t,e),i.set(e,t);++fe.type.filter((function(t){var e;return void 0===r||(!1!==(e=V(t))?!Y({arg:r},e):!W(t)(r))})).length)})).length}return!1},or=function(t){function e(){for(var r=[],n=arguments.length;n--;)r[n]=arguments[n];t.apply(this,r),this.message=r[0],this.detail=r[1],this.className=e.name,t.captureStackTrace&&t.captureStackTrace(this,e)}t&&(e.__proto__=t),e.prototype=Object.create(t&&t.prototype),e.prototype.constructor=e;var r={name:{configurable:!0}};return r.name.get=function(){return"JsonqlValidationError"},Object.defineProperties(e,r),e}(Error),ir=function(t){function e(){for(var r=[],n=arguments.length;n--;)r[n]=arguments[n];t.apply(this,r),this.message=r[0],this.detail=r[1],this.className=e.name,t.captureStackTrace&&t.captureStackTrace(this,e)}t&&(e.__proto__=t),e.prototype=Object.create(t&&t.prototype),e.prototype.constructor=e;var r={name:{configurable:!0},statusCode:{configurable:!0}};return r.name.get=function(){return"JsonqlError"},r.statusCode.get=function(){return-1},Object.defineProperties(e,r),e}(Error),ar=function(t,e){var r,n,o,i,a;switch(!0){case"object"===t:return o=(n=e).arg,i=n.param,a=[o],Array.isArray(i.keys)&&i.keys.length&&a.push(i.keys),!Reflect.apply(nr,null,a);case"array"===t:return!B(e.arg);case!1!==(r=V(t)):return!Y(e,r);default:return!W(t)(e.arg)}},ur=function(t,e){return void 0!==t?t:!0===e.optional&&void 0!==e.defaultvalue?e.defaultvalue:null},cr=function(t,e,r){var n;void 0===r&&(r=!1);var o=function(t,e){if(!B(e))throw new or("params is not an array! Did something gone wrong when you generate the contract.json?");if(0===e.length)return[];if(!B(t))throw new or("args is not an array! You might want to do: ES6 Array.from(arguments) or ES5 Array.prototype.slice.call(arguments)");switch(!0){case t.length==e.length:return t.map((function(t,r){return{arg:t,index:r,param:e[r]}}));case!0===e[0].variable:var r=e[0].type;return t.map((function(t,n){return{arg:t,index:n,param:e[n]||{type:r,name:"_"}}}));case t.lengthe.length:var n=e.length,o=["any"];return t.map((function(t,r){var i=r>=n||!!e[r].optional,a=e[r]||{type:o,name:"_"+r};return{arg:i?ur(t,a):t,index:r,param:a,optional:i}}));default:throw new ir("Could not understand your arguments and parameter structure!",{args:t,params:e})}}(t,e),i=o.filter((function(t){return!0===t.optional||!0===t.param.optional?function(t){var e=t.arg,r=t.param;return!!M(e)&&!(r.type.length>r.type.filter((function(e){return ar(e,t)})).length)}(t):!(t.param.type.length>t.param.type.filter((function(e){return ar(e,t)})).length)}));return r?((n={}).error=i,n.data=o.map((function(t){return t.arg})),n):i},sr=function(){try{var t=Zt(Object,"defineProperty");return t({},"",{}),t}catch(t){}}();function fr(t,e,r){"__proto__"==e&&sr?sr(t,e,{configurable:!0,enumerable:!0,value:r,writable:!0}):t[e]=r}function lr(t,e,r){(void 0===r||Ft(t[e],r))&&(void 0!==r||e in t)||fr(t,e,r)}var pr="object"==typeof exports&&exports&&!exports.nodeType&&exports,hr=pr&&"object"==typeof module&&module&&!module.nodeType&&module,vr=hr&&hr.exports===pr?i.Buffer:void 0,gr=vr?vr.allocUnsafe:void 0;function dr(t,e){var r,n,o=e?(r=t.buffer,n=new r.constructor(r.byteLength),new le(n).set(new le(r)),n):t.buffer;return new t.constructor(o,t.byteOffset,t.length)}var yr=Object.create,_r=function(){function t(){}return function(e){if(!xt(e))return{};if(yr)return yr(e);t.prototype=e;var r=new t;return t.prototype=void 0,r}}();function br(t,e){if(("constructor"!==e||"function"!=typeof t[e])&&"__proto__"!=e)return t[e]}var mr=Object.prototype.hasOwnProperty;function jr(t,e,r){var n=t[e];mr.call(t,e)&&Ft(n,r)&&(void 0!==r||e in t)||fr(t,e,r)}var wr=Object.prototype.hasOwnProperty;function Or(t){if(!xt(t))return function(t){var e=[];if(null!=t)for(var r in Object(t))e.push(r);return e}(t);var e=At(t),r=[];for(var n in t)("constructor"!=n||!e&&wr.call(t,n))&&r.push(n);return r}function Sr(t){return Rt(t)?$t(t,!0):Or(t)}function Er(t){return function(t,e,r,n){var o=!r;r||(r={});for(var i=-1,a=e.length;++i0){if(++e>=800)return arguments[0]}else e=0;return t.apply(void 0,arguments)}}(Pr);function zr(t,e){return xr(function(t,e,r){return e=Ar(void 0===e?t.length-1:e,0),function(){for(var n=arguments,o=-1,i=Ar(n.length-e,0),a=Array(i);++o1?e[n-1]:void 0,i=n>2?e[2]:void 0;for(o=Rr.length>3&&"function"==typeof o?(n--,o):void 0,i&&function(t,e,r){if(!xt(r))return!1;var n=typeof e;return!!("number"==n?Rt(r)&&dt(e,r.length):"string"==n&&e in r)&&Ft(r[e],t)}(e[0],e[1],i)&&(o=n<3?void 0:o,n=1),t=Object(t);++r0;)e[r]=arguments[r+1];if(this.logger("($queue) get called"),!0===this.__suspend_state__){if(un(this.__pattern__)){var n=this.__pattern__.test(t);if(!n)return!1}this.logger("($queue) added to $queue",e),this.queueStore.add([t].concat(e))}return!!this.__suspend_state__},fn.$queues.get=function(){var t=this.queueStore.size;return this.logger("($queues)","size: "+t),t>0?Array.from(this.queueStore):[]},sn.prototype.__suspend__=function(t){if("boolean"!=typeof t)throw new Error("$suspend only accept Boolean value! we got "+typeof t);var e=this.__suspend_state__;this.__suspend_state__=t,this.logger('($suspend) Change from "'+e+'" --\x3e "'+t+'"'),!0===e&&!1===t&&this.__release__()},sn.prototype.__release__=function(){var t=this,e=this.queueStore.size,r=this.__pattern__;if(this.__pattern__=null,this.logger("(release) was called with "+e+(r?' for "'+r+'"':"")+" item"+(e>1?"s":"")),e>0){var n=Array.from(this.queueStore);this.queueStore.clear(),this.logger("(release queue)",n),n.forEach((function(e){t.logger(e),Reflect.apply(t.$trigger,t,e)})),this.logger("Release size "+this.queueStore.size)}return e},Object.defineProperties(sn.prototype,fn);var ln=function(t){function e(e){if("function"!=typeof e)throw new Error("Just die here the logger is not a function!");e("---\x3e Create a new EventEmitter <---"),t.call(this,{logger:e})}t&&(e.__proto__=t),e.prototype=Object.create(t&&t.prototype),e.prototype.constructor=e;var r={name:{configurable:!0}};return r.name.get=function(){return"jsonql-ws-client-core"},Object.defineProperties(e.prototype,r),e}(function(t){function e(e){void 0===e&&(e={}),t.call(this,e)}t&&(e.__proto__=t),e.prototype=Object.create(t&&t.prototype),e.prototype.constructor=e;var r={$name:{configurable:!0},is:{configurable:!0},$done:{configurable:!0}};return e.prototype.logger=function(){},r.$name.get=function(){return"to1source-event"},r.is.get=function(){return this.$name},e.prototype.$on=function(t,e,r){var n=this;void 0===r&&(r=null);this.validate(t,e);var o=this.takeFromStore(t);if(!1===o)return this.logger('($on) "'+t+'" is not in lazy store'),this.addToNormalStore(t,"on",e,r);this.logger("($on) "+t+" found in lazy store");var i=0;return o.forEach((function(o){var a=o[0],u=o[1],c=o[2];if(c&&"on"!==c)throw new Error(nn+" "+c);n.logger("($on)",'call run "'+t+'"'),n.run(e,a,r||u),i+=n.addToNormalStore(t,"on",e,r||u)})),this.logger("($on) return size "+i),i},e.prototype.$once=function(t,e,r){void 0===r&&(r=null),this.validate(t,e);var n=this.takeFromStore(t);this.normalStore;if(!1===n)return this.logger('($once) "'+t+'" is not in the lazy store'),this.addToNormalStore(t,"once",e,r);this.logger("($once)",n);var o=Array.from(n)[0],i=o[0],a=o[1],u=o[2];if(u&&"once"!==u)throw new Error(nn+" "+u);this.logger("($once)",'call run "'+t+'"'),this.run(e,i,r||a),this.$off(t)},e.prototype.$only=function(t,e,r){var n=this;void 0===r&&(r=null),this.validate(t,e);var o=!1,i=this.takeFromStore(t);(this.normalStore.has(t)||(this.logger('($only) "'+t+'" add to normalStore'),o=this.addToNormalStore(t,"only",e,r)),!1!==i)&&(this.logger('($only) "'+t+'" found data in lazy store to execute'),Array.from(i).forEach((function(o){var i=o[0],a=o[1],u=o[2];if(u&&"only"!==u)throw new Error(nn+" "+u);n.logger('($only) call run "'+t+'"'),n.run(e,i,r||a)})));return o},e.prototype.$onlyOnce=function(t,e,r){void 0===r&&(r=null),this.validate(t,e);var n=!1,o=this.takeFromStore(t);if(this.normalStore.has(t)||(this.logger('($onlyOnce) "'+t+'" add to normalStore'),n=this.addToNormalStore(t,"onlyOnce",e,r)),!1!==o){this.logger("($onlyOnce)",o);var i=Array.from(o)[0],a=i[0],u=i[1],c=i[2];if(c&&"onlyOnce"!==c)throw new Error(nn+" "+c);this.logger('($onlyOnce) call run "'+t+'"'),this.run(e,a,r||u),this.$off(t)}return n},e.prototype.$replace=function(t,e,r,n){if(void 0===r&&(r=null),void 0===n&&(n="on"),this.validateType(n)){this.$off(t);var o=this["$"+n];return this.logger("($replace)",t,e),Reflect.apply(o,this,[t,e,r])}throw new Error(n+" is not supported!")},e.prototype.$trigger=function(t,e,r,n){void 0===e&&(e=[]),void 0===r&&(r=null),void 0===n&&(n=!1),this.validateEvt(t);var o=0,i=this.normalStore;if(this.logger("($trigger) normalStore",i),i.has(t)){if(this.logger('($trigger) "'+t+'" found'),this.$queue(t,e,r,n))return this.logger('($trigger) Currently suspended "'+t+'" added to queue, nothing executed. Exit now.'),!1;for(var a=Array.from(i.get(t)),u=a.length,c=!1,s=0;s0;)n[o]=arguments[o+2];if(t.has(e)?(this.logger('(addToStore) "'+e+'" existed'),r=t.get(e)):(this.logger('(addToStore) create new Set for "'+e+'"'),r=new Set),n.length>2)if(Array.isArray(n[0])){var i=n[2];this.checkTypeInLazyStore(e,i)||r.add(n)}else this.checkContentExist(n,r)||(this.logger("(addToStore) insert new",n),r.add(n));else r.add(n);return t.set(e,r),[t,r.size]},e.prototype.checkContentExist=function(t,e){return!!Array.from(e).filter((function(e){return e[0]===t[0]})).length},e.prototype.checkTypeInStore=function(t,e){this.validateEvt(t,e);var r=this.$get(t,!0);return!1===r||!r.filter((function(t){var r=t[3];return e!==r})).length},e.prototype.checkTypeInLazyStore=function(t,e){this.validateEvt(t,e);var r=this.lazyStore.get(t);return this.logger("(checkTypeInLazyStore)",r),!!r&&!!Array.from(r).filter((function(t){return t[2]!==e})).length},e.prototype.addToNormalStore=function(t,e,r,n){if(void 0===n&&(n=null),this.logger('(addToNormalStore) try to add "'+e+'" --\x3e "'+t+'" to normal store'),this.checkTypeInStore(t,e)){this.logger("(addToNormalStore)",'"'+e+'" --\x3e "'+t+'" can add to normal store');var o=this.hashFnToKey(r),i=[this.normalStore,t,o,r,n,e],a=Reflect.apply(this.addToStore,this,i),u=a[0],c=a[1];return this.normalStore=u,c}return!1},e.prototype.addToLazyStore=function(t,e,r,n){void 0===e&&(e=[]),void 0===r&&(r=null),void 0===n&&(n=!1);var o=[this.lazyStore,t,this.toArray(e),r];n&&o.push(n);var i=Reflect.apply(this.addToStore,this,o),a=i[0],u=i[1];return this.lazyStore=a,this.logger("(addToLazyStore) size: "+u),u},e.prototype.toArray=function(t){return Array.isArray(t)?t:[t]},r.normalStore.set=function(t){on.set(this,t)},r.normalStore.get=function(){return on.get(this)},r.lazyStore.set=function(t){an.set(this,t)},r.lazyStore.get=function(){return an.get(this)},e.prototype.hashFnToKey=function(t){return function(t){return t.split("").reduce((function(t,e){return(t=(t<<5)-t+e.charCodeAt(0))&t}),0)}(t.toString())+""},Object.defineProperties(e.prototype,r),e}(sn))),pn=function(t){return c(t)?t:[t]},hn=function(t,e){try{var r=Object.keys(t);return n=e,!!r.filter((function(t){return t===n})).length}catch(t){return!1}var n},vn=function(){for(var t=[],e=arguments.length;e--;)t[e]=arguments[e];return t.join("_")},gn=function(t){if("function"==typeof t)return!0;console.error("Expect to be Function type! Got "+typeof t)},dn=function(){return!1},yn=function(t){for(var e=[],r=arguments.length-1;r-- >0;)e[r]=arguments[r+1];return function(){for(var r=[],n=arguments.length;n--;)r[n]=arguments[n];return e.reduce((function(t,e){return Reflect.apply(e,null,pn(t))}),Reflect.apply(t,null,r))}};function _n(t,e,r,n){return void 0===n&&(n=null),void 0===Object.getOwnPropertyDescriptor(t,e)&&Object.defineProperty(t,e,{set:r,get:null===n?function(){return null}:n}),t}function bn(t,e,r,n){void 0===n&&(n=!1);var o=function(t,e){var r=Object.getOwnPropertyDescriptor(t,e);return void 0!==r&&r.value?r.value:r}(t,e);return!1===n&&void 0!==o||Object.defineProperty(t,e,{value:r,writable:n}),t}var mn=function(t){function e(){for(var r=[],n=arguments.length;n--;)r[n]=arguments[n];t.apply(this,r),this.message=r[0],this.detail=r[1],this.className=e.name,t.captureStackTrace&&t.captureStackTrace(this,e)}t&&(e.__proto__=t),e.prototype=Object.create(t&&t.prototype),e.prototype.constructor=e;var r={statusCode:{configurable:!0},name:{configurable:!0}};return r.statusCode.get=function(){return 406},r.name.get=function(){return"Jsonql406Error"},Object.defineProperties(e,r),e}(Error),jn=function(t){function e(){for(var r=[],n=arguments.length;n--;)r[n]=arguments[n];t.apply(this,r),this.message=r[0],this.detail=r[1],this.className=e.name,t.captureStackTrace&&t.captureStackTrace(this,e)}t&&(e.__proto__=t),e.prototype=Object.create(t&&t.prototype),e.prototype.constructor=e;var r={statusCode:{configurable:!0},name:{configurable:!0}};return r.statusCode.get=function(){return 500},r.name.get=function(){return"Jsonql500Error"},Object.defineProperties(e,r),e}(Error),wn=function(t){function e(){for(var r=[],n=arguments.length;n--;)r[n]=arguments[n];t.apply(this,r),this.message=r[0],this.detail=r[1],this.className=e.name,t.captureStackTrace&&t.captureStackTrace(this,e)}t&&(e.__proto__=t),e.prototype=Object.create(t&&t.prototype),e.prototype.constructor=e;var r={statusCode:{configurable:!0},name:{configurable:!0}};return r.statusCode.get=function(){return 403},r.name.get=function(){return"JsonqlForbiddenError"},Object.defineProperties(e,r),e}(Error),On=function(t){function e(){for(var r=[],n=arguments.length;n--;)r[n]=arguments[n];t.apply(this,r),this.message=r[0],this.detail=r[1],this.className=e.name,t.captureStackTrace&&t.captureStackTrace(this,e)}t&&(e.__proto__=t),e.prototype=Object.create(t&&t.prototype),e.prototype.constructor=e;var r={statusCode:{configurable:!0},name:{configurable:!0}};return r.statusCode.get=function(){return 401},r.name.get=function(){return"JsonqlAuthorisationError"},Object.defineProperties(e,r),e}(Error),Sn=function(t){function e(){for(var r=[],n=arguments.length;n--;)r[n]=arguments[n];t.apply(this,r),this.message=r[0],this.detail=r[1],this.className=e.name,t.captureStackTrace&&t.captureStackTrace(this,e)}t&&(e.__proto__=t),e.prototype=Object.create(t&&t.prototype),e.prototype.constructor=e;var r={statusCode:{configurable:!0},name:{configurable:!0}};return r.statusCode.get=function(){return 401},r.name.get=function(){return"JsonqlContractAuthError"},Object.defineProperties(e,r),e}(Error),En=function(t){function e(){for(var r=[],n=arguments.length;n--;)r[n]=arguments[n];t.apply(this,r),this.message=r[0],this.detail=r[1],this.className=e.name,t.captureStackTrace&&t.captureStackTrace(this,e)}t&&(e.__proto__=t),e.prototype=Object.create(t&&t.prototype),e.prototype.constructor=e;var r={statusCode:{configurable:!0},name:{configurable:!0}};return r.statusCode.get=function(){return 500},r.name.get=function(){return"JsonqlResolverAppError"},Object.defineProperties(e,r),e}(Error),kn=function(t){function e(){for(var r=[],n=arguments.length;n--;)r[n]=arguments[n];t.apply(this,r),this.message=r[0],this.detail=r[1],this.className=e.name,t.captureStackTrace&&t.captureStackTrace(this,e)}t&&(e.__proto__=t),e.prototype=Object.create(t&&t.prototype),e.prototype.constructor=e;var r={statusCode:{configurable:!0},name:{configurable:!0}};return r.statusCode.get=function(){return 404},r.name.get=function(){return"JsonqlResolverNotFoundError"},Object.defineProperties(e,r),e}(Error),$n=function(t){function e(r,n){t.call(this,n),this.statusCode=r,this.className=e.name}t&&(e.__proto__=t),e.prototype=Object.create(t&&t.prototype),e.prototype.constructor=e;var r={name:{configurable:!0}};return r.name.get=function(){return"JsonqlServerError"},Object.defineProperties(e,r),e}(Error);function Tn(t){if(Array.isArray(t))throw new or("",t);var e=t.message||"No message",r=t.detail||t;switch(!0){case t instanceof mn:throw new mn(e,r);case t instanceof jn:throw new jn(e,r);case t instanceof wn:throw new wn(e,r);case t instanceof On:throw new On(e,r);case t instanceof Sn:throw new Sn(e,r);case t instanceof En:throw new En(e,r);case t instanceof kn:throw new kn(e,r);case t instanceof Gr:throw new Gr(e,r);case t instanceof Wr:throw new Wr(e,r);case t instanceof Br:throw new Br(e,r);case t instanceof or:throw new or(e,r);case t instanceof $n:throw new $n(e,r);default:throw new ir(e,r)}}function An(t){var e=function(t){return!!hn(t,"socket")&&t.socket}(t);if(!1===e)throw new JsonqlError("groupByNamespace","socket not found in contract!");var r={nspGroup:{},publicNamespace:null,size:0};for(var n in e){var o=e[n],i=o.namespace;i&&(r.nspGroup[i]||(++r.size,r.nspGroup[i]={}),r.nspGroup[i][n]=o,!r.publicNamespace&&o.public&&(r.publicNamespace=i))}return r}var Pn=function(t){var e=t.toLowerCase();return e.indexOf("http")>-1?e.indexOf("https")>-1?e.replace("https","wss"):e.replace("http","ws"):e},Nn=function(t,e){pn(e).forEach((function(e){t.$off(vn(e,"emit_reply"))}))},xn=function(t,e,r){return[bn(t,e.loginHandlerName,(function(t){if(t&&Qr(t))return e.log("Received __login__ with "+t),r.$trigger("__login__",[t]);throw new or(e.loginHandlerName,"Unexpected token "+t)})),e,r]},zn=function(t,e,r){return[bn(t,e.logoutHandlerName,(function(){for(var t=[],e=arguments.length;e--;)t[e]=arguments[e];r.$trigger("__logout__",t)})),e,r]},Rn=function(t,e,r){return[_n(t,"onLogin",(function(t){gn(t)&&r.$only("onLogin",t)})),e,r]};function Cn(t,e,r){return yn(xn,zn,Rn)(t,e,r)}function qn(t,e,r){hn(t,"error")?r(t.error):hn(t,"data")?e(t.data):r({message:"UKNNOWN RESULT!",error:t})}function Fn(t,e,r,n,o){void 0===n&&(n=[]);var i=vn(e,"emit_reply");return o("actionCall: "+i+" --\x3e "+r,n),t.$trigger(i,[r,pn(n)]),new Promise((function(n,i){var a=vn(e,r,"onResult");t.$on(a,(function(t){o("got the first result",t),qn(t,n,i)}))}))}var Ln,Mn,Jn,Un=function(t,e,r,n,o,i){return _n(t,"send",dn,(function(){return function(){for(var t=[],a=arguments.length;a--;)t[a]=arguments[a];return Xr(t,o.params,!0).then((function(t){return i(r,n,t),Fn(e,r,n,t,_log)})).catch((function(t){i("send error",t),e.$call(vn(r,n,"onError"),[new or(n,t)])}))}}))},Dn=function(t,e,r,n,o,i){return[bn(t,"myNamespace",r),e,r,n,o,i]},Hn=function(t,e,r,n,o,i){return[_n(t,"onResult",(function(t){gn(t)&&e.$on(vn(r,n,"onResult"),(function(o){qn(o,t,(function(t){i('Catch error: "'+n+'"',t),e.$trigger(vn(r,n,"onError"),t)}))}))})),e,r,n,o,i]},In=function(t,e,r,n,o,i){return[_n(t,"onMessage",(function(t){if(gn(t)){e.$only(vn(r,n,"onMessage"),(function(o){qn(o,t,(function(t){i('Catch error: "'+n+'"',t),e.$trigger(vn(r,n,"onError"),t)}))}))}})),e,r,n,o,i]},Gn=function(t,e,r,n,o,i){return[_n(t,"onError",(function(t){gn(t)&&e.$only(vn(r,n,"onError"),t)})),e,r,n,o,i]};function Wn(t,e,r,n,o,i){var a=[Dn,Hn,In,Gn,Un],u=Reflect.apply(yn,null,a),c=[n,o,t,e,r,i];return Reflect.apply(u,null,c)}function Bn(t,e,r,n,o){return function(){for(var i=[],a=arguments.length;a--;)i[a]=arguments[a];return Xr(i,n.params,!0).then((function(n){return Fn(t,e,r,n,o)})).catch(Tn)}}function Vn(t,e,r){var n={},o=t.log;for(var i in r){var a=r[i];for(var u in a){var c=a[u];n=bn(n,u,Wn(i,u,c,Bn(e,i,u,c,o),e,o))}}return[n,t,e,r]}function Yn(t,e,r,n){return[_n(t,"onError",(function(t){if(gn(t))for(var e in n)r.$on(vn(e,"onError"),t)})),e,r]}function Kn(t,e,r){return[_n(t,"onReady",(function(t){gn(t)&&r.$on("onReady",t)})),e,r]}function Qn(t,e,r){var n=function(t,e,r){return bn(t,e.disconnectHandlerName,(function(){for(var t=[],e=arguments.length;e--;)t[e]=arguments[e];r.$trigger("__disconnect__",t)}))}(t,e,r);return e.log("---\x3e The final step to return the ws-client <---"),n.verifyEventEmitter=function(){return r.is},n.eventEmitter=e.eventEmitter,n.log=e.log,n}var Xn=["roundtip","handshake"],Zn={standalone:Zr(!1,["boolean"]),debugOn:Zr(!1,["boolean"]),loginHandlerName:Zr("login",["string"]),logoutHandlerName:Zr("logout",["string"]),disconnectHandlerName:Zr("disconnect",["string"]),switchUserHandlerName:Zr("switch-user",["string"]),loginMethod:Zr("handshake",["string"],(Ln={},Ln.enumv=Xn,Ln)),useJwt:Zr(!0,["boolean","string"]),authStrKey:Zr(null,["string"]),hostname:Zr(!1,["string"]),namespace:Zr("jsonql",["string"]),wsOptions:Zr({},["object"]),contract:Zr({},["object"],(Mn={},Mn.checker=function(t){return!!function(t){return nt(t)&&(hn(t,"query")||hn(t,"mutation")||hn(t,"socket"))}(t)&&t},Mn)),enableAuth:Zr(!1,["boolean"]),token:Zr(!1,["string"])},to={};to.serverType=Zr(null,["string"],((Jn={}).alias="socketClientType",Jn));var eo=Object.assign(Zn,to),ro={log:null,eventEmitter:null,nspClient:null,nspAuthClient:null,wssPath:""};function no(t){return Promise.resolve(t).then((function(t){return t.hostname||(t.hostname=function(){try{return[window.location.protocol,window.location.host].join("//")}catch(t){throw new or(t)}}()),t.wssPath=Pn([t.hostname,t.namespace].join("/"),t.serverType),t.log=rn(t),t.eventEmitter=function(t){var e=t.log,r=t.eventEmitter;return r?(e("eventEmitter is:",r.name),r):new ln(t.log)}(t),t}))}function oo(t){return{opts:t,nspMap:(e=t,r=e.contract,n=e.enableAuth,o=function(t){var e="jsonql";return t.enableAuth?[[e,t.publicNamespace].join("/"),[e,t.privateNamespace].join("/")]:[e]}(e),i=n?An(r):function(t,e){var r,n={};for(var o in t){var i=t[o];n[o]=i}return{size:1,nspGroup:(r={},r[e]=n,r),publicNamespace:e}}(r.socket,o[0]),Object.assign(i,{namespaces:o})),ee:t.eventEmitter};var e,r,n,o,i}function io(t,e){return no(e).then(oo).then((function(e){var r=e.opts,n=e.nspMap,o=e.ee;return t(r,n,o)})).then((function(t){return function(t,e,r){var n=[Vn,Yn,Kn];return t.enableAuth&&n.push(Cn),n.push(Qn),Reflect.apply(yn,null,n)(t,r,e.nspGroup)}(t.opts,t.nspMap,t.ee)})).catch((function(t){console.error("jsonql-ws-core-client init error",t)}))}function ao(t,e,r){return void 0===e&&(e={}),void 0===r&&(r={}),function(n){return void 0===n&&(n={}),function(t,e,r){var n=Object.assign(ro,r),o=Object.assign(eo,e);return tn(t,o,n)}(n,e,r).then((function(e){return io(t,e)}))}}function uo(t,e){var r=e.hostname,n=e.wssPath,o=e.wsOptions;return(0,e.nspClient)(t?[r,t].join("/"):n,o)}function co(t,e,r){e.forEach((function(e){t.$trigger(vn(e,"onError"),[{message:r,namespace:e}])}))}var so=function(t,e,r){var n=r.log;e.$only(vn(t,"emit_reply"),(function(r,o){n("[notLoginHandler] hijack the ws call",t,r,o);var i={message:"NOT LOGIN"};e.$call(vn(t,r,"onError"),[i]),e.$call(vn(t,r,"onResult"),[{error:i}])}))},fo=function(t){return t.length>1&&t[0]},lo=function(t,e,r,n){var o=n.log;r.$on("__disconnect__",(function(){co(r,e,"__disconnect__"),e.forEach((function(e){o("disconnect from "+e),Nn(r,e),t[e]=null,function(t,e,r){var n=r.log;e.$only(vn(t,"emit_reply"),(function(r,o){n("[disconnectedHandler] hijack the ws call",t,r,o);var i={message:"You have disconnected from the socket server, please reconnect."};e.$call(vn(t,r,"onError"),[i]),e.$call(vn(t,r,"onResult"),[{error:i}])}))}(e,r,n)}))}))};function po(t,e,r,n,o,i){var a=fo(o),u=!1,c=!1,s=t.log;o.forEach((function(o){if(u=a===o,c||(c=u),i[o]){s("[call bindWsHandler]",u,o);var f=[o,i[o],r,u,t];if("socket.io"===t.serverType){var l=e.nspSet;f.push(l[o])}Reflect.apply(n,null,f)}else so(o,r,t)})),c&&(s("Has private and add logoutEvtHandler"),function(t,e,r,n){var o=n.log;r.$on("__logout__",(function(){var i=fo(e);o("__logout__ event triggered"),co(r,[i],"__logout__"),o("logout from "+i),Nn(r,i),t[i]=null,so(i,r,n)}))}(i,o,r,t)),lo(i,o,r,t)}var ho={version:"version: 1.1.1 module: cjs",serverType:"ws"},vo=Object.assign({},eo,{}),go=Object.assign({},ro,ho);function yo(t,e){return void 0===e&&(e=!1),!1===e?function(e){return new t(Pn(e))}:function(e,r){var n=Pn(e),o=r&&"string"==typeof r?n+"?token="+r:n;try{return new t(o)}catch(t){return console.error("WebSocket Connection Error",t),!1}}}var _o=Array.isArray,bo="object"==typeof r&&r&&r.Object===Object&&r,mo="object"==typeof self&&self&&self.Object===Object&&self,jo=(bo||mo||Function("return this")()).Symbol,wo=Object.prototype,Oo=wo.hasOwnProperty,So=wo.toString,Eo=jo?jo.toStringTag:void 0;var ko=Object.prototype.toString;var $o=jo?jo.toStringTag:void 0;function To(t){return null==t?void 0===t?"[object Undefined]":"[object Null]":$o&&$o in Object(t)?function(t){var e=Oo.call(t,Eo),r=t[Eo];try{t[Eo]=void 0;var n=!0}catch(t){}var o=So.call(t);return n&&(e?t[Eo]=r:delete t[Eo]),o}(t):function(t){return ko.call(t)}(t)}function Ao(t){return null!=t&&"object"==typeof t}var Po=jo?jo.prototype:void 0,No=Po?Po.toString:void 0;function xo(t){if("string"==typeof t)return t;if(_o(t))return function(t,e){for(var r=-1,n=null==t?0:t.length,o=Array(n);++r=n?t:function(t,e,r){var n=-1,o=t.length;e<0&&(e=-e>o?0:o+e),(r=r>o?o:r)<0&&(r+=o),o=e>r?0:r-e>>>0,e>>>=0;for(var i=Array(o);++n-1;);return r}(o,i),function(t,e){for(var r=t.length;r--&&Co(e,t[r],0)>-1;);return r}(o,i)+1).join("")}var Ko=function(){for(var t=[],e=arguments.length;e--;)t[e]=arguments[e];return t.join("_")},Qo=function(t){function e(){for(var r=[],n=arguments.length;n--;)r[n]=arguments[n];t.apply(this,r),this.message=r[0],this.detail=r[1],this.className=e.name,t.captureStackTrace&&t.captureStackTrace(this,e)}t&&(e.__proto__=t),e.prototype=Object.create(t&&t.prototype),e.prototype.constructor=e;var r={name:{configurable:!0}};return r.name.get=function(){return"JsonqlValidationError"},Object.defineProperties(e,r),e}(Error),Xo=function(t){function e(){for(var r=[],n=arguments.length;n--;)r[n]=arguments[n];t.apply(this,r),this.message=r[0],this.detail=r[1],this.className=e.name,t.captureStackTrace&&t.captureStackTrace(this,e)}t&&(e.__proto__=t),e.prototype=Object.create(t&&t.prototype),e.prototype.constructor=e;var r={name:{configurable:!0},statusCode:{configurable:!0}};return r.name.get=function(){return"JsonqlError"},r.statusCode.get=function(){return-1},Object.defineProperties(e,r),e}(Error),Zo=function(t){void 0===t&&(t=!1);var e=Date.now();return t?Math.floor(e/1e3):e};function ti(t){return"string"==typeof t||!_o(t)&&Ao(t)&&"[object String]"==To(t)}function ei(t,e,r){if(void 0===e&&(e=[]),void 0===r&&(r=!1),ti(t)&&_o(e)){var n=function(t){var e;return(e={}).args=t,e}(e);return!0===r?n:function(t,e){var r;return(r={})[t]=e,r.TS=[Zo()],r}(t,n)}throw new Qo("[createQuery] expect resolverName to be string and args to be array!",{resolverName:t,args:e})}var ri=function(t){return""!==Yo(t)&&ti(t)},ni=["__reply__","__event__","__data__"],oi=function(t){var e=t.data;return!!e&&(ni.filter((function(t){return function(t,e){try{var r=Object.keys(t);return n=e,!!r.filter((function(t){return t===n})).length}catch(t){return!1}var n}(e,t)})).length===ni.length&&e)},ii=function(t,e,r,n,o){var i=[e];r&&i.push(r),i.push(o);var a=Reflect.apply(Ko,null,i),u=n.data||n;t.$trigger(a,[u])};function ai(t,e,r,n,o){var i=o.log;i("log test, isPrivate:",n),e.onopen=function(){i("ws.onopen listened"),r.$call("onReady",t),n&&(i("isPrivate and fire the onLogin"),r.$call("onLogin",t)),r.$only(Ko(t,"emit_reply"),(function(t,r){var n=function(t,e,r){return void 0===e&&(e=[]),void 0===r&&(r=!1),JSON.stringify(ei(t,e,r))}(t,r);i("calling server",t,r,n),e.send(n)}))},e.onmessage=function(e){try{var n=function(t){var e,r=t.data,n=ri(r)?JSON.parse(r):r;if(!1!==(e=oi(n)))return{resolverName:e.__event__,data:e.__data__,type:e.__reply__};throw new Xo("payload can not be decoded",t)}(e),o=n.resolverName,a=n.type;switch(i("Hear from server",a,n),a){case"emit_reply":var u=Ko(t,o,"onMessage"),c=r.$trigger(u,[n]);i("EMIT_REPLY_TYPE",u,c);break;case"acknowledge_reply":var s=Ko(t,o,"onResult"),f=r.$trigger(s,[n]);i("ACKNOWLEDGE_REPLY_TYPE",s,f);break;case"error":i("ERROR_TYPE"),ii(r,t,o,n,"onError");break;default:i("Unhandled event!",n),ii(r,t,o,n,"onError")}}catch(e){console.error("ws.onmessage error",e),ii(r,t,!1,e,"onError")}},e.onclose=function(){i("ws.onclose callback")},e.onerror=function(e){i("ws.onerror",e),r.$trigger(Ko(t,"onError"),[e])},n&&r.$on("__logout__",(function(){try{i("terminate ws connection"),e.terminate()}catch(t){console.error("ws.terminate error",t)}}))}var ui=function(t,e,r){var n,o=t.log,i=e.nspGroup,a=e.publicNamespace,u=!1,c=[],s={};if(t.enableAuth)u=!0,s=(c=function(t,e){var r=[];for(var n in t)n===e?r[1]=n:r[0]=n;return r}(i,a)).map((function(e,n){var i,a,u;return 0===n?r?(t.token=r,o("create createNspAuthClient at run time"),(i={})[e]=function(t,e){var r=e.hostname,n=e.wssPath,o=e.token,i=e.wsOptions,a=e.nspAuthClient,u=t?[r,t].join("/"):n;if(o&&"string"!=typeof o)throw new Error("Expect token to be string, but got "+o);return a(u,o,i)}(e,t),i):((a={})[e]=!1,a):((u={})[e]=uo(e,t),u)})).reduce((function(t,e){return Object.assign(t,e)}),{});else{var f=(n=i,console.error("This method is going to be deprectead in the next release, please use getResolverFromPayload instead"),Object.keys(n)[0]);c.push(f),s[f]=uo(!1,t)}return{nsps:s,namespaces:c,loginRequired:u}};function ci(t,e,r,n){var o=n.log;t.$only("__login__",(function(i){o("createClient LOGIN_EVENT_NAME $only handler"),Nn(t,e);var a=ui(n,r,i);Reflect.apply(po,null,args.concat([a.namespaces,a.nsps]))}))}var si,fi,li,pi=(fi=yo(si=e),li=yo(si,!0),function(t,e,r){t.nspClient=fi,t.nspAuthClient=li;var n=t.log;return n&&"function"==typeof n&&(n("@jsonql/ws ee",r.name),n("@jsonql/ws createClientResolver",t)),function(t,e,r){var n=[t,e,r,ai],o=t.token,i=(t.log,ui(t,e,o)),a=i.nsps,u=i.namespaces,c=i.loginRequired;return Reflect.apply(po,null,n.concat([u,a])),c&&ci(r,u,e,t),{opts:t,nspMap:e,ee:r}}(t,e,r)});module.exports=function(t,e){return void 0===t&&(t={}),void 0===e&&(e={}),ao(pi,vo,Object.assign({},go,e))(t)}; //# sourceMappingURL=main.js.map diff --git a/packages/@jsonql/ws/node.js b/packages/@jsonql/ws/node.js index d07a9111..2bbf1c5f 100644 --- a/packages/@jsonql/ws/node.js +++ b/packages/@jsonql/ws/node.js @@ -1,2 +1,2 @@ -"use strict";Object.defineProperty(exports,"__esModule",{value:!0});var t,e=(t=require("ws"))&&"object"==typeof t&&"default"in t?t.default:t,r="undefined"!=typeof global?global:"undefined"!=typeof self?self:"undefined"!=typeof window?window:{},n="object"==typeof r&&r&&r.Object===Object&&r,o="object"==typeof self&&self&&self.Object===Object&&self,i=n||o||Function("return this")(),a=i.Symbol;function u(t,e){for(var r=-1,n=null==t?0:t.length,o=Array(n);++r=n?t:function(t,e,r){var n=-1,o=t.length;e<0&&(e=-e>o?0:o+e),(r=r>o?o:r)<0&&(r+=o),o=e>r?0:r-e>>>0,e>>>=0;for(var i=Array(o);++n-1;);return r}(n,o),function(t,e){for(var r=t.length;r--&&O(e,t[r],0)>-1;);return r}(n,o)+1).join("")}var M=function(t){return!!c(t)||null!=t&&""!==L(t)};function J(t){return function(t){return"number"==typeof t||d(t)&&"[object Number]"==g(t)}(t)&&t!=+t}function D(t){return"string"==typeof t||!c(t)&&d(t)&&"[object String]"==g(t)}var U=function(t){return!D(t)&&!J(parseFloat(t))},H=function(t){return""!==L(t)&&D(t)},I=function(t){return null!=t&&"boolean"==typeof t},W=function(t,e){return void 0===e&&(e=!0),void 0!==t&&""!==t&&""!==L(t)&&(!1===e||!0===e&&null!==t)},B=function(t){switch(t){case"number":return U;case"string":return H;case"boolean":return I;default:return W}},V=function(t,e){return void 0===e&&(e=""),!!c(t)&&(""===e||""===L(e)||!(t.filter((function(t){return!B(e)(t)})).length>0))},Y=function(t){if(t.indexOf("array.<")>-1&&t.indexOf(">")>-1){var e=t.replace("array.<","").replace(">","");return e.indexOf("|")?e.split("|"):[e]}return!1},G=function(t,e){var r=t.arg;return e.length>1?!r.filter((function(t){return!(e.length>e.filter((function(e){return!B(e)(t)})).length)})).length:e.length>e.filter((function(t){return!V(r,t)})).length};function K(t,e){return function(r){return t(e(r))}}var Q=K(Object.getPrototypeOf,Object),X=Function.prototype,Z=Object.prototype,tt=X.toString,et=Z.hasOwnProperty,rt=tt.call(Object);function nt(t){if(!d(t)||"[object Object]"!=g(t))return!1;var e=Q(t);if(null===e)return!0;var r=et.call(e,"constructor")&&e.constructor;return"function"==typeof r&&r instanceof r&&tt.call(r)==rt}var ot,it=function(t,e,r){for(var n=-1,o=Object(t),i=r(t),a=i.length;a--;){var u=i[ot?a:++n];if(!1===e(o[u],u,o))break}return t};function at(t){return d(t)&&"[object Arguments]"==g(t)}var ut=Object.prototype,ct=ut.hasOwnProperty,st=ut.propertyIsEnumerable,ft=at(function(){return arguments}())?at:function(t){return d(t)&&ct.call(t,"callee")&&!st.call(t,"callee")};var lt="object"==typeof exports&&exports&&!exports.nodeType&&exports,pt=lt&&"object"==typeof module&&module&&!module.nodeType&&module,ht=pt&&pt.exports===lt?i.Buffer:void 0,vt=(ht?ht.isBuffer:void 0)||function(){return!1},gt=/^(?:0|[1-9]\d*)$/;function dt(t,e){var r=typeof t;return!!(e=null==e?9007199254740991:e)&&("number"==r||"symbol"!=r&>.test(t))&&t>-1&&t%1==0&&t-1&&t%1==0&&t<=9007199254740991}var _t={};_t["[object Float32Array]"]=_t["[object Float64Array]"]=_t["[object Int8Array]"]=_t["[object Int16Array]"]=_t["[object Int32Array]"]=_t["[object Uint8Array]"]=_t["[object Uint8ClampedArray]"]=_t["[object Uint16Array]"]=_t["[object Uint32Array]"]=!0,_t["[object Arguments]"]=_t["[object Array]"]=_t["[object ArrayBuffer]"]=_t["[object Boolean]"]=_t["[object DataView]"]=_t["[object Date]"]=_t["[object Error]"]=_t["[object Function]"]=_t["[object Map]"]=_t["[object Number]"]=_t["[object Object]"]=_t["[object RegExp]"]=_t["[object Set]"]=_t["[object String]"]=_t["[object WeakMap]"]=!1;var bt,mt="object"==typeof exports&&exports&&!exports.nodeType&&exports,jt=mt&&"object"==typeof module&&module&&!module.nodeType&&module,wt=jt&&jt.exports===mt&&n.process,Ot=function(){try{var t=jt&&jt.require&&jt.require("util").types;return t||wt&&wt.binding&&wt.binding("util")}catch(t){}}(),St=Ot&&Ot.isTypedArray,Et=St?(bt=St,function(t){return bt(t)}):function(t){return d(t)&&yt(t.length)&&!!_t[g(t)]},kt=Object.prototype.hasOwnProperty;function $t(t,e){var r=c(t),n=!r&&ft(t),o=!r&&!n&&vt(t),i=!r&&!n&&!o&&Et(t),a=r||n||o||i,u=a?function(t,e){for(var r=-1,n=Array(t);++r-1},Jt.prototype.set=function(t,e){var r=this.__data__,n=Lt(r,t);return n<0?(++this.size,r.push([t,e])):r[n][1]=e,this};var Dt,Ut=i["__core-js_shared__"],Ht=(Dt=/[^.]+$/.exec(Ut&&Ut.keys&&Ut.keys.IE_PROTO||""))?"Symbol(src)_1."+Dt:"";var It=Function.prototype.toString;function Wt(t){if(null!=t){try{return It.call(t)}catch(t){}try{return t+""}catch(t){}}return""}var Bt=/^\[object .+?Constructor\]$/,Vt=Function.prototype,Yt=Object.prototype,Gt=Vt.toString,Kt=Yt.hasOwnProperty,Qt=RegExp("^"+Gt.call(Kt).replace(/[\\^$.*+?()[\]{}|]/g,"\\$&").replace(/hasOwnProperty|(function).*?(?=\\\()| for .+?(?=\\\])/g,"$1.*?")+"$");function Xt(t){return!(!Nt(t)||function(t){return!!Ht&&Ht in t}(t))&&(zt(t)?Qt:Bt).test(Wt(t))}function Zt(t,e){var r=function(t,e){return null==t?void 0:t[e]}(t,e);return Xt(r)?r:void 0}var te=Zt(i,"Map"),ee=Zt(Object,"create");var re=Object.prototype.hasOwnProperty;var ne=Object.prototype.hasOwnProperty;function oe(t){var e=-1,r=null==t?0:t.length;for(this.clear();++eu))return!1;var s=i.get(t);if(s&&i.get(e))return s==e;var f=-1,l=!0,p=2&r?new ce:void 0;for(i.set(t,e),i.set(e,t);++fe.type.filter((function(t){var e;return void 0===r||(!1!==(e=Y(t))?!G({arg:r},e):!B(t)(r))})).length)})).length}return!1},or=function(t){function e(){for(var r=[],n=arguments.length;n--;)r[n]=arguments[n];t.apply(this,r),this.message=r[0],this.detail=r[1],this.className=e.name,t.captureStackTrace&&t.captureStackTrace(this,e)}t&&(e.__proto__=t),e.prototype=Object.create(t&&t.prototype),e.prototype.constructor=e;var r={name:{configurable:!0}};return r.name.get=function(){return"JsonqlValidationError"},Object.defineProperties(e,r),e}(Error),ir=function(t){function e(){for(var r=[],n=arguments.length;n--;)r[n]=arguments[n];t.apply(this,r),this.message=r[0],this.detail=r[1],this.className=e.name,t.captureStackTrace&&t.captureStackTrace(this,e)}t&&(e.__proto__=t),e.prototype=Object.create(t&&t.prototype),e.prototype.constructor=e;var r={name:{configurable:!0},statusCode:{configurable:!0}};return r.name.get=function(){return"JsonqlError"},r.statusCode.get=function(){return-1},Object.defineProperties(e,r),e}(Error),ar=function(t,e){var r,n,o,i,a;switch(!0){case"object"===t:return o=(n=e).arg,i=n.param,a=[o],Array.isArray(i.keys)&&i.keys.length&&a.push(i.keys),!Reflect.apply(nr,null,a);case"array"===t:return!V(e.arg);case!1!==(r=Y(t)):return!G(e,r);default:return!B(t)(e.arg)}},ur=function(t,e){return void 0!==t?t:!0===e.optional&&void 0!==e.defaultvalue?e.defaultvalue:null},cr=function(t,e,r){var n;void 0===r&&(r=!1);var o=function(t,e){if(!V(e))throw new or("params is not an array! Did something gone wrong when you generate the contract.json?");if(0===e.length)return[];if(!V(t))throw new or("args is not an array! You might want to do: ES6 Array.from(arguments) or ES5 Array.prototype.slice.call(arguments)");switch(!0){case t.length==e.length:return t.map((function(t,r){return{arg:t,index:r,param:e[r]}}));case!0===e[0].variable:var r=e[0].type;return t.map((function(t,n){return{arg:t,index:n,param:e[n]||{type:r,name:"_"}}}));case t.lengthe.length:var n=e.length,o=["any"];return t.map((function(t,r){var i=r>=n||!!e[r].optional,a=e[r]||{type:o,name:"_"+r};return{arg:i?ur(t,a):t,index:r,param:a,optional:i}}));default:throw new ir("Could not understand your arguments and parameter structure!",{args:t,params:e})}}(t,e),i=o.filter((function(t){return!0===t.optional||!0===t.param.optional?function(t){var e=t.arg,r=t.param;return!!M(e)&&!(r.type.length>r.type.filter((function(e){return ar(e,t)})).length)}(t):!(t.param.type.length>t.param.type.filter((function(e){return ar(e,t)})).length)}));return r?((n={}).error=i,n.data=o.map((function(t){return t.arg})),n):i},sr=function(){try{var t=Zt(Object,"defineProperty");return t({},"",{}),t}catch(t){}}();function fr(t,e,r){"__proto__"==e&&sr?sr(t,e,{configurable:!0,enumerable:!0,value:r,writable:!0}):t[e]=r}function lr(t,e,r){(void 0===r||Ft(t[e],r))&&(void 0!==r||e in t)||fr(t,e,r)}var pr="object"==typeof exports&&exports&&!exports.nodeType&&exports,hr=pr&&"object"==typeof module&&module&&!module.nodeType&&module,vr=hr&&hr.exports===pr?i.Buffer:void 0,gr=vr?vr.allocUnsafe:void 0;function dr(t,e){var r,n,o=e?(r=t.buffer,n=new r.constructor(r.byteLength),new le(n).set(new le(r)),n):t.buffer;return new t.constructor(o,t.byteOffset,t.length)}var yr=Object.create,_r=function(){function t(){}return function(e){if(!Nt(e))return{};if(yr)return yr(e);t.prototype=e;var r=new t;return t.prototype=void 0,r}}();function br(t,e){if(("constructor"!==e||"function"!=typeof t[e])&&"__proto__"!=e)return t[e]}var mr=Object.prototype.hasOwnProperty;function jr(t,e,r){var n=t[e];mr.call(t,e)&&Ft(n,r)&&(void 0!==r||e in t)||fr(t,e,r)}var wr=Object.prototype.hasOwnProperty;function Or(t){if(!Nt(t))return function(t){var e=[];if(null!=t)for(var r in Object(t))e.push(r);return e}(t);var e=At(t),r=[];for(var n in t)("constructor"!=n||!e&&wr.call(t,n))&&r.push(n);return r}function Sr(t){return Rt(t)?$t(t,!0):Or(t)}function Er(t){return function(t,e,r,n){var o=!r;r||(r={});for(var i=-1,a=e.length;++i0){if(++e>=800)return arguments[0]}else e=0;return t.apply(void 0,arguments)}}(Pr);function zr(t,e){return Nr(function(t,e,r){return e=Ar(void 0===e?t.length-1:e,0),function(){for(var n=arguments,o=-1,i=Ar(n.length-e,0),a=Array(i);++o1?e[n-1]:void 0,i=n>2?e[2]:void 0;for(o=Rr.length>3&&"function"==typeof o?(n--,o):void 0,i&&function(t,e,r){if(!Nt(r))return!1;var n=typeof e;return!!("number"==n?Rt(r)&&dt(e,r.length):"string"==n&&e in r)&&Ft(r[e],t)}(e[0],e[1],i)&&(o=n<3?void 0:o,n=1),t=Object(t);++r0;)e[r]=arguments[r+1];if(this.logger("($queue) get called"),!0===this.__suspend_state__){if(un(this.__pattern__)){var n=this.__pattern__.test(t);if(!n)return!1}this.logger("($queue) added to $queue",e),this.queueStore.add([t].concat(e))}return!!this.__suspend_state__},fn.$queues.get=function(){var t=this.queueStore.size;return this.logger("($queues)","size: "+t),t>0?Array.from(this.queueStore):[]},sn.prototype.__suspend__=function(t){if("boolean"!=typeof t)throw new Error("$suspend only accept Boolean value! we got "+typeof t);var e=this.__suspend_state__;this.__suspend_state__=t,this.logger('($suspend) Change from "'+e+'" --\x3e "'+t+'"'),!0===e&&!1===t&&this.__release__()},sn.prototype.__release__=function(){var t=this,e=this.queueStore.size,r=this.__pattern__;if(this.__pattern__=null,this.logger("(release) was called with "+e+(r?' for "'+r+'"':"")+" item"+(e>1?"s":"")),e>0){var n=Array.from(this.queueStore);this.queueStore.clear(),this.logger("(release queue)",n),n.forEach((function(e){t.logger(e),Reflect.apply(t.$trigger,t,e)})),this.logger("Release size "+this.queueStore.size)}return e},Object.defineProperties(sn.prototype,fn);var ln=function(t){function e(e){if("function"!=typeof e)throw new Error("Just die here the logger is not a function!");e("---\x3e Create a new EventEmitter <---"),t.call(this,{logger:e})}t&&(e.__proto__=t),e.prototype=Object.create(t&&t.prototype),e.prototype.constructor=e;var r={name:{configurable:!0}};return r.name.get=function(){return"jsonql-ws-client-core"},Object.defineProperties(e.prototype,r),e}(function(t){function e(e){void 0===e&&(e={}),t.call(this,e)}t&&(e.__proto__=t),e.prototype=Object.create(t&&t.prototype),e.prototype.constructor=e;var r={$name:{configurable:!0},is:{configurable:!0},$done:{configurable:!0}};return e.prototype.logger=function(){},r.$name.get=function(){return"to1source-event"},r.is.get=function(){return this.$name},e.prototype.$on=function(t,e,r){var n=this;void 0===r&&(r=null);this.validate(t,e);var o=this.takeFromStore(t);if(!1===o)return this.logger('($on) "'+t+'" is not in lazy store'),this.addToNormalStore(t,"on",e,r);this.logger("($on) "+t+" found in lazy store");var i=0;return o.forEach((function(o){var a=o[0],u=o[1],c=o[2];if(c&&"on"!==c)throw new Error(nn+" "+c);n.logger("($on)",'call run "'+t+'"'),n.run(e,a,r||u),i+=n.addToNormalStore(t,"on",e,r||u)})),this.logger("($on) return size "+i),i},e.prototype.$once=function(t,e,r){void 0===r&&(r=null),this.validate(t,e);var n=this.takeFromStore(t);this.normalStore;if(!1===n)return this.logger('($once) "'+t+'" is not in the lazy store'),this.addToNormalStore(t,"once",e,r);this.logger("($once)",n);var o=Array.from(n)[0],i=o[0],a=o[1],u=o[2];if(u&&"once"!==u)throw new Error(nn+" "+u);this.logger("($once)",'call run "'+t+'"'),this.run(e,i,r||a),this.$off(t)},e.prototype.$only=function(t,e,r){var n=this;void 0===r&&(r=null),this.validate(t,e);var o=!1,i=this.takeFromStore(t);(this.normalStore.has(t)||(this.logger('($only) "'+t+'" add to normalStore'),o=this.addToNormalStore(t,"only",e,r)),!1!==i)&&(this.logger('($only) "'+t+'" found data in lazy store to execute'),Array.from(i).forEach((function(o){var i=o[0],a=o[1],u=o[2];if(u&&"only"!==u)throw new Error(nn+" "+u);n.logger('($only) call run "'+t+'"'),n.run(e,i,r||a)})));return o},e.prototype.$onlyOnce=function(t,e,r){void 0===r&&(r=null),this.validate(t,e);var n=!1,o=this.takeFromStore(t);if(this.normalStore.has(t)||(this.logger('($onlyOnce) "'+t+'" add to normalStore'),n=this.addToNormalStore(t,"onlyOnce",e,r)),!1!==o){this.logger("($onlyOnce)",o);var i=Array.from(o)[0],a=i[0],u=i[1],c=i[2];if(c&&"onlyOnce"!==c)throw new Error(nn+" "+c);this.logger('($onlyOnce) call run "'+t+'"'),this.run(e,a,r||u),this.$off(t)}return n},e.prototype.$replace=function(t,e,r,n){if(void 0===r&&(r=null),void 0===n&&(n="on"),this.validateType(n)){this.$off(t);var o=this["$"+n];return this.logger("($replace)",t,e),Reflect.apply(o,this,[t,e,r])}throw new Error(n+" is not supported!")},e.prototype.$trigger=function(t,e,r,n){void 0===e&&(e=[]),void 0===r&&(r=null),void 0===n&&(n=!1),this.validateEvt(t);var o=0,i=this.normalStore;if(this.logger("($trigger) normalStore",i),i.has(t)){if(this.logger('($trigger) "'+t+'" found'),this.$queue(t,e,r,n))return this.logger('($trigger) Currently suspended "'+t+'" added to queue, nothing executed. Exit now.'),!1;for(var a=Array.from(i.get(t)),u=a.length,c=!1,s=0;s0;)n[o]=arguments[o+2];if(t.has(e)?(this.logger('(addToStore) "'+e+'" existed'),r=t.get(e)):(this.logger('(addToStore) create new Set for "'+e+'"'),r=new Set),n.length>2)if(Array.isArray(n[0])){var i=n[2];this.checkTypeInLazyStore(e,i)||r.add(n)}else this.checkContentExist(n,r)||(this.logger("(addToStore) insert new",n),r.add(n));else r.add(n);return t.set(e,r),[t,r.size]},e.prototype.checkContentExist=function(t,e){return!!Array.from(e).filter((function(e){return e[0]===t[0]})).length},e.prototype.checkTypeInStore=function(t,e){this.validateEvt(t,e);var r=this.$get(t,!0);return!1===r||!r.filter((function(t){var r=t[3];return e!==r})).length},e.prototype.checkTypeInLazyStore=function(t,e){this.validateEvt(t,e);var r=this.lazyStore.get(t);return this.logger("(checkTypeInLazyStore)",r),!!r&&!!Array.from(r).filter((function(t){return t[2]!==e})).length},e.prototype.addToNormalStore=function(t,e,r,n){if(void 0===n&&(n=null),this.logger('(addToNormalStore) try to add "'+e+'" --\x3e "'+t+'" to normal store'),this.checkTypeInStore(t,e)){this.logger("(addToNormalStore)",'"'+e+'" --\x3e "'+t+'" can add to normal store');var o=this.hashFnToKey(r),i=[this.normalStore,t,o,r,n,e],a=Reflect.apply(this.addToStore,this,i),u=a[0],c=a[1];return this.normalStore=u,c}return!1},e.prototype.addToLazyStore=function(t,e,r,n){void 0===e&&(e=[]),void 0===r&&(r=null),void 0===n&&(n=!1);var o=[this.lazyStore,t,this.toArray(e),r];n&&o.push(n);var i=Reflect.apply(this.addToStore,this,o),a=i[0],u=i[1];return this.lazyStore=a,this.logger("(addToLazyStore) size: "+u),u},e.prototype.toArray=function(t){return Array.isArray(t)?t:[t]},r.normalStore.set=function(t){on.set(this,t)},r.normalStore.get=function(){return on.get(this)},r.lazyStore.set=function(t){an.set(this,t)},r.lazyStore.get=function(){return an.get(this)},e.prototype.hashFnToKey=function(t){return function(t){return t.split("").reduce((function(t,e){return(t=(t<<5)-t+e.charCodeAt(0))&t}),0)}(t.toString())+""},Object.defineProperties(e.prototype,r),e}(sn))),pn=function(t){return c(t)?t:[t]},hn=function(t,e){try{var r=Object.keys(t);return n=e,!!r.filter((function(t){return t===n})).length}catch(t){return!1}var n},vn=function(){for(var t=[],e=arguments.length;e--;)t[e]=arguments[e];return t.join("_")},gn=function(t){if("function"==typeof t)return!0;console.error("Expect to be Function type! Got "+typeof t)},dn=function(){return!1},yn=function(t){for(var e=[],r=arguments.length-1;r-- >0;)e[r]=arguments[r+1];return function(){for(var r=[],n=arguments.length;n--;)r[n]=arguments[n];return e.reduce((function(t,e){return Reflect.apply(e,null,pn(t))}),Reflect.apply(t,null,r))}};function _n(t,e,r,n){return void 0===n&&(n=null),void 0===Object.getOwnPropertyDescriptor(t,e)&&Object.defineProperty(t,e,{set:r,get:null===n?function(){return null}:n}),t}function bn(t,e,r,n){void 0===n&&(n=!1);var o=function(t,e){var r=Object.getOwnPropertyDescriptor(t,e);return void 0!==r&&r.value?r.value:r}(t,e);return!1===n&&void 0!==o||Object.defineProperty(t,e,{value:r,writable:n}),t}var mn=function(t){function e(){for(var r=[],n=arguments.length;n--;)r[n]=arguments[n];t.apply(this,r),this.message=r[0],this.detail=r[1],this.className=e.name,t.captureStackTrace&&t.captureStackTrace(this,e)}t&&(e.__proto__=t),e.prototype=Object.create(t&&t.prototype),e.prototype.constructor=e;var r={statusCode:{configurable:!0},name:{configurable:!0}};return r.statusCode.get=function(){return 406},r.name.get=function(){return"Jsonql406Error"},Object.defineProperties(e,r),e}(Error),jn=function(t){function e(){for(var r=[],n=arguments.length;n--;)r[n]=arguments[n];t.apply(this,r),this.message=r[0],this.detail=r[1],this.className=e.name,t.captureStackTrace&&t.captureStackTrace(this,e)}t&&(e.__proto__=t),e.prototype=Object.create(t&&t.prototype),e.prototype.constructor=e;var r={statusCode:{configurable:!0},name:{configurable:!0}};return r.statusCode.get=function(){return 500},r.name.get=function(){return"Jsonql500Error"},Object.defineProperties(e,r),e}(Error),wn=function(t){function e(){for(var r=[],n=arguments.length;n--;)r[n]=arguments[n];t.apply(this,r),this.message=r[0],this.detail=r[1],this.className=e.name,t.captureStackTrace&&t.captureStackTrace(this,e)}t&&(e.__proto__=t),e.prototype=Object.create(t&&t.prototype),e.prototype.constructor=e;var r={statusCode:{configurable:!0},name:{configurable:!0}};return r.statusCode.get=function(){return 403},r.name.get=function(){return"JsonqlForbiddenError"},Object.defineProperties(e,r),e}(Error),On=function(t){function e(){for(var r=[],n=arguments.length;n--;)r[n]=arguments[n];t.apply(this,r),this.message=r[0],this.detail=r[1],this.className=e.name,t.captureStackTrace&&t.captureStackTrace(this,e)}t&&(e.__proto__=t),e.prototype=Object.create(t&&t.prototype),e.prototype.constructor=e;var r={statusCode:{configurable:!0},name:{configurable:!0}};return r.statusCode.get=function(){return 401},r.name.get=function(){return"JsonqlAuthorisationError"},Object.defineProperties(e,r),e}(Error),Sn=function(t){function e(){for(var r=[],n=arguments.length;n--;)r[n]=arguments[n];t.apply(this,r),this.message=r[0],this.detail=r[1],this.className=e.name,t.captureStackTrace&&t.captureStackTrace(this,e)}t&&(e.__proto__=t),e.prototype=Object.create(t&&t.prototype),e.prototype.constructor=e;var r={statusCode:{configurable:!0},name:{configurable:!0}};return r.statusCode.get=function(){return 401},r.name.get=function(){return"JsonqlContractAuthError"},Object.defineProperties(e,r),e}(Error),En=function(t){function e(){for(var r=[],n=arguments.length;n--;)r[n]=arguments[n];t.apply(this,r),this.message=r[0],this.detail=r[1],this.className=e.name,t.captureStackTrace&&t.captureStackTrace(this,e)}t&&(e.__proto__=t),e.prototype=Object.create(t&&t.prototype),e.prototype.constructor=e;var r={statusCode:{configurable:!0},name:{configurable:!0}};return r.statusCode.get=function(){return 500},r.name.get=function(){return"JsonqlResolverAppError"},Object.defineProperties(e,r),e}(Error),kn=function(t){function e(){for(var r=[],n=arguments.length;n--;)r[n]=arguments[n];t.apply(this,r),this.message=r[0],this.detail=r[1],this.className=e.name,t.captureStackTrace&&t.captureStackTrace(this,e)}t&&(e.__proto__=t),e.prototype=Object.create(t&&t.prototype),e.prototype.constructor=e;var r={statusCode:{configurable:!0},name:{configurable:!0}};return r.statusCode.get=function(){return 404},r.name.get=function(){return"JsonqlResolverNotFoundError"},Object.defineProperties(e,r),e}(Error),$n=function(t){function e(r,n){t.call(this,n),this.statusCode=r,this.className=e.name}t&&(e.__proto__=t),e.prototype=Object.create(t&&t.prototype),e.prototype.constructor=e;var r={name:{configurable:!0}};return r.name.get=function(){return"JsonqlServerError"},Object.defineProperties(e,r),e}(Error);function Tn(t){if(Array.isArray(t))throw new or("",t);var e=t.message||"No message",r=t.detail||t;switch(!0){case t instanceof mn:throw new mn(e,r);case t instanceof jn:throw new jn(e,r);case t instanceof wn:throw new wn(e,r);case t instanceof On:throw new On(e,r);case t instanceof Sn:throw new Sn(e,r);case t instanceof En:throw new En(e,r);case t instanceof kn:throw new kn(e,r);case t instanceof Wr:throw new Wr(e,r);case t instanceof Br:throw new Br(e,r);case t instanceof Vr:throw new Vr(e,r);case t instanceof or:throw new or(e,r);case t instanceof $n:throw new $n(e,r);default:throw new ir(e,r)}}function An(t){return!!hn(t,"socket")&&t.socket}function Pn(t){var e,r,n=t.contract;return t.enableAuth?function(t){var e=An(t);if(!1===e)throw new JsonqlError("groupByNamespace","socket not found in contract!");var r,n={},o=0;for(var i in e){var a=e[i],u=a.namespace;u&&(n[u]||(++o,n[u]={}),n[u][i]=a,!r&&a.public&&(r=u))}return{size:o,nspGroup:n,publicNamespace:r}}(n):((r={}).nspSet=((e={}).jsonql=function(t){var e=An(t);if(!1!==e)return e;throw new kn("Missing property in contract!")}(n),e),r.publicNamespace="jsonql",r)}var xn=function(t){var e=t.toLowerCase();return e.indexOf("http")>-1?e.indexOf("https")>-1?e.replace("https","wss"):e.replace("http","ws"):e},Nn=function(t,e){pn(e).forEach((function(e){t.$off(vn(e,"emit_reply"))}))},zn=function(t,e,r){return[bn(t,e.loginHandlerName,(function(t){if(t&&Qr(t))return e.log("Received __login__ with "+t),r.$trigger("__login__",[t]);throw new or(e.loginHandlerName,"Unexpected token "+t)})),e,r]},Rn=function(t,e,r){return[bn(t,e.logoutHandlerName,(function(){for(var t=[],e=arguments.length;e--;)t[e]=arguments[e];r.$trigger("__logout__",t)})),e,r]},Cn=function(t,e,r){return[_n(t,"onLogin",(function(t){gn(t)&&r.$only("onLogin",t)})),e,r]};function qn(t,e,r){return yn(zn,Rn,Cn)(t,e,r)}function Fn(t,e,r){hn(t,"error")?r(t.error):hn(t,"data")?e(t.data):r({message:"UKNNOWN RESULT!",error:t})}function Ln(t,e,r,n,o){void 0===n&&(n=[]);var i=vn(e,"emit_reply");return o("actionCall: "+i+" --\x3e "+r,n),t.$trigger(i,[r,pn(n)]),new Promise((function(n,i){t.$on(vn(e,r,"onResult"),(function(t){o("got the first result",t),Fn(t,n,i)}))}))}var Mn,Jn,Dn,Un=function(t,e,r,n,o,i){return _n(t,"send",dn,(function(){var t=function(){for(var t=[],e=arguments.length;e--;)t[e]=arguments[e];return Reflect.apply(console.info,console,["[SEND]"].concat(t))};return function(){for(var i=[],a=arguments.length;a--;)i[a]=arguments[a];return Xr(i,o.params,!0).then((function(o){return t(r,n,o),Ln(e,r,n,o,t)})).catch((function(o){t("send error",o),e.$call(vn(r,n,"onError"),[new or(n,o)])}))}}))},Hn=function(t,e,r,n,o,i){return[bn(t,"myNamespace",r),e,r,n,o,i]},In=function(t,e,r,n,o,i){return[_n(t,"onResult",(function(t){gn(t)&&e.$on(vn(r,n,"onResult"),(function(o){Fn(o,t,(function(t){i('Catch error: "'+n+'"',t),e.$trigger(vn(r,n,"onError"),t)}))}))})),e,r,n,o,i]},Wn=function(t,e,r,n,o,i){return[_n(t,"onMessage",(function(t){if(gn(t)){e.$only(vn(r,n,"onMessage"),(function(o){Fn(o,t,(function(t){i('Catch error: "'+n+'"',t),e.$trigger(vn(r,n,"onError"),t)}))}))}})),e,r,n,o,i]},Bn=function(t,e,r,n,o,i){return[_n(t,"onError",(function(t){gn(t)&&e.$only(vn(r,n,"onError"),t)})),e,r,n,o,i]};function Vn(t,e,r,n,o,i){var a=[Hn,In,Wn,Bn,Un],u=Reflect.apply(yn,null,a),c=[n,o,t,e,r,i];return Reflect.apply(u,null,c)}function Yn(t,e,r,n,o){return function(){for(var i=[],a=arguments.length;a--;)i[a]=arguments[a];return Xr(i,n.params,!0).then((function(n){return Ln(t,e,r,n,o)})).catch(Tn)}}function Gn(t,e,r){var n={},o=t.log;for(var i in r){var a=r[i];for(var u in a){var c=a[u];n=bn(n,u,Vn(i,u,c,Yn(e,i,u,c,o),e,o))}}return[n,t,e,r]}function Kn(t,e,r,n){return[_n(t,"onError",(function(t){if(gn(t))for(var e in n)r.$on(vn(e,"onError"),t)})),e,r]}function Qn(t,e,r){return[_n(t,"onReady",(function(t){gn(t)&&r.$on("onReady",t)})),e,r]}function Xn(t,e,r){var n=function(t,e,r){return bn(t,e.disconnectHandlerName,(function(){for(var t=[],e=arguments.length;e--;)t[e]=arguments[e];r.$trigger("__disconnect__",t)}))}(t,e,r);return e.log("---\x3e The final step to return the ws-client <---"),n.verifyEventEmitter=function(){return r.is},n.eventEmitter=e.eventEmitter,n.log=e.log,n}var Zn=["roundtip","handshake"],to={standalone:Zr(!1,["boolean"]),debugOn:Zr(!1,["boolean"]),loginHandlerName:Zr("login",["string"]),logoutHandlerName:Zr("logout",["string"]),disconnectHandlerName:Zr("disconnect",["string"]),switchUserHandlerName:Zr("switch-user",["string"]),loginMethod:Zr("handshake",["string"],(Mn={},Mn.enumv=Zn,Mn)),useJwt:Zr(!0,["boolean","string"]),authStrKey:Zr(null,["string"]),hostname:Zr(!1,["string"]),namespace:Zr("jsonql",["string"]),wsOptions:Zr({},["object"]),contract:Zr({},["object"],(Jn={},Jn.checker=function(t){return!!function(t){return nt(t)&&(hn(t,"query")||hn(t,"mutation")||hn(t,"socket"))}(t)&&t},Jn)),enableAuth:Zr(!1,["boolean"]),token:Zr(!1,["string"])},eo={};eo.serverType=Zr(null,["string"],((Dn={}).alias="socketClientType",Dn));var ro=Object.assign(to,eo);function no(t){return Promise.resolve(t).then((function(t){return t.hostname||(t.hostname=function(){try{return[window.location.protocol,window.location.host].join("//")}catch(t){throw new or(t)}}()),t.wssPath=xn([t.hostname,t.namespace].join("/"),t.serverType),t.log=rn(t),t.eventEmitter=function(t){var e=t.log,r=t.eventEmitter;return r?(e("eventEmitter is:",r.name),r):new ln(t.log)}(t),t}))}function oo(t){return{opts:t,nspMap:Pn(t),ee:t.eventEmitter}}function io(t,e){return no(e).then(oo).then((function(e){var r=e.opts,n=e.nspMap,o=e.ee;return t(r,n,o)})).then((function(t){return function(t,e,r){var n=e.nspSet,o=[Gn,Kn,Qn];return t.enableAuth&&o.push(qn),o.push(Xn),Reflect.apply(yn,null,o)(t,r,n)}(t.opts,t.nspMap,t.ee)})).catch((function(t){console.error("jsonql-ws-core-client init error",t)}))}function ao(t,e){var r=e.hostname,n=e.wssPath,o=e.wsOptions;return(0,e.nspClient)(t?[r,t].join("/"):n,o)}function uo(t,e,r){e.forEach((function(e){t.$trigger(vn(e,"onError"),[{message:r,namespace:e}])}))}var co=function(t,e,r){var n=r.log;e.$only(vn(t,"emit_reply"),(function(r,o){n("[notLoginHandler] hijack the ws call",t,r,o);var i={message:"NOT LOGIN"};e.$call(vn(t,r,"onError"),[i]),e.$call(vn(t,r,"onResult"),[{error:i}])}))},so=function(t){return t.length>1&&t[0]},fo=function(t,e,r,n){var o=n.log;r.$on("__disconnect__",(function(){uo(r,e,"__disconnect__"),e.forEach((function(e){o("disconnect from "+e),Nn(r,e),t[e]=null,function(t,e,r){var n=r.log;e.$only(vn(t,"emit_reply"),(function(r,o){n("[disconnectedHandler] hijack the ws call",t,r,o);var i={message:"You have disconnected from the socket server, please reconnect."};e.$call(vn(t,r,"onError"),[i]),e.$call(vn(t,r,"onResult"),[{error:i}])}))}(e,r,n)}))}))};function lo(t,e,r,n,o,i){var a=so(o),u=!1,c=!1,s=t.log;o.forEach((function(o){if(u=a===o,c||(c=u),i[o]){s("[call bindWsHandler]",u,o);var f=[o,i[o],r,u,t];if("socket.io"===t.serverType){var l=e.nspSet;f.push(l[o])}Reflect.apply(n,null,f)}else co(o,r,t)})),c&&(s("Has private and add logoutEvtHandler"),function(t,e,r,n){var o=n.log;r.$on("__logout__",(function(){var i=so(e);o("__logout__ event triggered"),uo(r,[i],"__logout__"),o("logout from "+i),Nn(r,i),t[i]=null,co(i,r,n)}))}(i,o,r,t)),fo(i,o,r,t)}var po={version:"version: 1.1.1 module: cjs-module",serverType:"ws"},ho=Object.assign({},ro,{}),vo=Object.assign({},{log:null,eventEmitter:null,nspClient:null,nspAuthClient:null,wssPath:""},po);function go(t,e){return void 0===e&&(e=!1),!1===e?function(e){return new t(xn(e))}:function(e,r){var n=xn(e),o=r&&"string"==typeof r?n+"?token="+r:n;try{return new t(o)}catch(t){return console.error("WebSocket Connection Error",t),!1}}}var yo=Array.isArray,_o="object"==typeof r&&r&&r.Object===Object&&r,bo="object"==typeof self&&self&&self.Object===Object&&self,mo=(_o||bo||Function("return this")()).Symbol,jo=Object.prototype,wo=jo.hasOwnProperty,Oo=jo.toString,So=mo?mo.toStringTag:void 0;var Eo=Object.prototype.toString;var ko=mo?mo.toStringTag:void 0;function $o(t){return null==t?void 0===t?"[object Undefined]":"[object Null]":ko&&ko in Object(t)?function(t){var e=wo.call(t,So),r=t[So];try{t[So]=void 0;var n=!0}catch(t){}var o=Oo.call(t);return n&&(e?t[So]=r:delete t[So]),o}(t):function(t){return Eo.call(t)}(t)}function To(t){return null!=t&&"object"==typeof t}var Ao=mo?mo.prototype:void 0,Po=Ao?Ao.toString:void 0;function xo(t){if("string"==typeof t)return t;if(yo(t))return function(t,e){for(var r=-1,n=null==t?0:t.length,o=Array(n);++r=n?t:function(t,e,r){var n=-1,o=t.length;e<0&&(e=-e>o?0:o+e),(r=r>o?o:r)<0&&(r+=o),o=e>r?0:r-e>>>0,e>>>=0;for(var i=Array(o);++n-1;);return r}(o,i),function(t,e){for(var r=t.length;r--&&Ro(e,t[r],0)>-1;);return r}(o,i)+1).join("")}var Go=function(){for(var t=[],e=arguments.length;e--;)t[e]=arguments[e];return t.join("_")},Ko=function(t){function e(){for(var r=[],n=arguments.length;n--;)r[n]=arguments[n];t.apply(this,r),this.message=r[0],this.detail=r[1],this.className=e.name,t.captureStackTrace&&t.captureStackTrace(this,e)}t&&(e.__proto__=t),e.prototype=Object.create(t&&t.prototype),e.prototype.constructor=e;var r={name:{configurable:!0}};return r.name.get=function(){return"JsonqlValidationError"},Object.defineProperties(e,r),e}(Error),Qo=function(t){function e(){for(var r=[],n=arguments.length;n--;)r[n]=arguments[n];t.apply(this,r),this.message=r[0],this.detail=r[1],this.className=e.name,t.captureStackTrace&&t.captureStackTrace(this,e)}t&&(e.__proto__=t),e.prototype=Object.create(t&&t.prototype),e.prototype.constructor=e;var r={name:{configurable:!0},statusCode:{configurable:!0}};return r.name.get=function(){return"JsonqlError"},r.statusCode.get=function(){return-1},Object.defineProperties(e,r),e}(Error),Xo=function(t){void 0===t&&(t=!1);var e=Date.now();return t?Math.floor(e/1e3):e};function Zo(t){return"string"==typeof t||!yo(t)&&To(t)&&"[object String]"==$o(t)}function ti(t,e,r){if(void 0===e&&(e=[]),void 0===r&&(r=!1),Zo(t)&&yo(e)){var n=function(t){var e;return(e={}).args=t,e}(e);return!0===r?n:function(t,e){var r;return(r={})[t]=e,r.TS=[Xo()],r}(t,n)}throw new Ko("[createQuery] expect resolverName to be string and args to be array!",{resolverName:t,args:e})}var ei=function(t){return""!==Yo(t)&&Zo(t)},ri=["__reply__","__event__","__data__"],ni=function(t){var e=t.data;return!!e&&(ri.filter((function(t){return function(t,e){try{var r=Object.keys(t);return n=e,!!r.filter((function(t){return t===n})).length}catch(t){return!1}var n}(e,t)})).length===ri.length&&e)},oi=function(t,e,r,n,o){var i=[e];r&&i.push(r),i.push(o);var a=Reflect.apply(Go,null,i),u=n.data||n;t.$trigger(a,[u])};function ii(t,e,r,n,o){var i=function(){for(var t=[],e=arguments.length;e--;)t[e]=arguments[e];return Reflect.apply(console.info,console,["[socketEventHandler]"].concat(t))};i("log test, isPrivate:",n),e.onopen=function(){i("ws.onopen listened"),r.$call("onReady",t),n&&(i("isPrivate and fire the onLogin"),r.$call("onLogin",t)),r.$only(Go(t,"emit_reply"),(function(t,r){var n=function(t,e,r){return void 0===e&&(e=[]),void 0===r&&(r=!1),JSON.stringify(ti(t,e,r))}(t,r);i("calling server",t,r,n),e.send(n)}))},e.onmessage=function(e){try{var n=function(t){var e,r=t.data,n=ei(r)?JSON.parse(r):r;if(!1!==(e=ni(n)))return{resolverName:e.__event__,data:e.__data__,type:e.__reply__};throw new Qo("payload can not be decoded",t)}(e),o=n.resolverName,a=n.type;switch(i("Hear from server",a,n),a){case"emit_reply":var u=Go(t,o,"onMessage"),c=r.$trigger(u,[n]);i("EMIT_REPLY_TYPE",u,c);break;case"acknowledge_reply":var s=Go(t,o,"onResult"),f=r.$trigger(s,[n]);i("ACKNOWLEDGE_REPLY_TYPE",s,f);break;case"error":i("ERROR_TYPE"),oi(r,t,o,n,"onError");break;default:i("Unhandled event!",n),oi(r,t,o,n,"onError")}}catch(e){console.error("ws.onmessage error",e),oi(r,t,!1,e,"onError")}},e.onclose=function(){i("ws.onclose callback")},e.onerror=function(e){i("ws.onerror",e),r.$trigger(Go(t,"onError"),[e])},n&&r.$on("__logout__",(function(){try{i("terminate ws connection"),e.terminate()}catch(t){console.error("ws.terminate error",t)}}))}var ai=function(t,e,r){var n,o=t.log,i=e.nspSet,a=e.publicNamespace,u=!1,c=[],s={};if(t.enableAuth)u=!0,s=(c=function(t,e){var r=[];for(var n in t)n===e?r[1]=n:r[0]=n;return r}(i,a)).map((function(e,n){var i,a,u;return 0===n?r?(t.token=r,o("create createNspAuthClient at run time"),(i={})[e]=function(t,e){var r=e.hostname,n=e.wssPath,o=e.token,i=e.wsOptions,a=e.nspAuthClient,u=t?[r,t].join("/"):n;if(o&&"string"!=typeof o)throw new Error("Expect token to be string, but got "+o);return a(u,o,i)}(e,t),i):((a={})[e]=!1,a):((u={})[e]=ao(e,t),u)})).reduce((function(t,e){return Object.assign(t,e)}),{});else{var f=(n=i,console.error("This method is going to be deprectead in the next release, please use getResolverFromPayload instead"),Object.keys(n)[0]);c.push(f),s[f]=ao(!1,t)}return{nsps:s,namespaces:c,loginRequired:u}};function ui(t,e,r,n){var o=n.log;t.$only("__login__",(function(i){o("createClient LOGIN_EVENT_NAME $only handler"),Nn(t,e);var a=ai(n,r,i);Reflect.apply(lo,null,args.concat([a.namespaces,a.nsps]))}))}var ci,si,fi,li,pi=(si=go(ci=e),fi=go(ci,!0),function(t,e,r){t.nspClient=si,t.nspAuthClient=fi;var n=t.log;return n&&"function"==typeof n&&(n("@jsonql/ws ee",r.name),n("@jsonql/ws createClientResolver",t)),function(t,e,r){var n=[t,e,r,ii],o=t.token,i=(t.log,ai(t,e,o)),a=i.nsps,u=i.namespaces,c=i.loginRequired;return Reflect.apply(lo,null,n.concat([u,a])),c&&ui(r,u,e,t),{opts:t,nspMap:e,ee:r}}(t,e,r)}),hi=(li=pi,function(t){return Promise.resolve(t).then((function(t){return io(li,t)}))});exports.checkSocketClientType=function(t){return tn(t,eo)},exports.createWsClient=hi,exports.jsonqlWsClientAppProps=ho,exports.jsonqlWsConstProps=vo; +"use strict";Object.defineProperty(exports,"__esModule",{value:!0});var t,e=(t=require("ws"))&&"object"==typeof t&&"default"in t?t.default:t,r="undefined"!=typeof global?global:"undefined"!=typeof self?self:"undefined"!=typeof window?window:{},n="object"==typeof r&&r&&r.Object===Object&&r,o="object"==typeof self&&self&&self.Object===Object&&self,i=n||o||Function("return this")(),a=i.Symbol;function u(t,e){for(var r=-1,n=null==t?0:t.length,o=Array(n);++r=n?t:function(t,e,r){var n=-1,o=t.length;e<0&&(e=-e>o?0:o+e),(r=r>o?o:r)<0&&(r+=o),o=e>r?0:r-e>>>0,e>>>=0;for(var i=Array(o);++n-1;);return r}(n,o),function(t,e){for(var r=t.length;r--&&O(e,t[r],0)>-1;);return r}(n,o)+1).join("")}var M=function(t){return!!c(t)||null!=t&&""!==L(t)};function J(t){return function(t){return"number"==typeof t||d(t)&&"[object Number]"==g(t)}(t)&&t!=+t}function U(t){return"string"==typeof t||!c(t)&&d(t)&&"[object String]"==g(t)}var D=function(t){return!U(t)&&!J(parseFloat(t))},H=function(t){return""!==L(t)&&U(t)},I=function(t){return null!=t&&"boolean"==typeof t},W=function(t,e){return void 0===e&&(e=!0),void 0!==t&&""!==t&&""!==L(t)&&(!1===e||!0===e&&null!==t)},G=function(t){switch(t){case"number":return D;case"string":return H;case"boolean":return I;default:return W}},B=function(t,e){return void 0===e&&(e=""),!!c(t)&&(""===e||""===L(e)||!(t.filter((function(t){return!G(e)(t)})).length>0))},V=function(t){if(t.indexOf("array.<")>-1&&t.indexOf(">")>-1){var e=t.replace("array.<","").replace(">","");return e.indexOf("|")?e.split("|"):[e]}return!1},Y=function(t,e){var r=t.arg;return e.length>1?!r.filter((function(t){return!(e.length>e.filter((function(e){return!G(e)(t)})).length)})).length:e.length>e.filter((function(t){return!B(r,t)})).length};function K(t,e){return function(r){return t(e(r))}}var Q=K(Object.getPrototypeOf,Object),X=Function.prototype,Z=Object.prototype,tt=X.toString,et=Z.hasOwnProperty,rt=tt.call(Object);function nt(t){if(!d(t)||"[object Object]"!=g(t))return!1;var e=Q(t);if(null===e)return!0;var r=et.call(e,"constructor")&&e.constructor;return"function"==typeof r&&r instanceof r&&tt.call(r)==rt}var ot,it=function(t,e,r){for(var n=-1,o=Object(t),i=r(t),a=i.length;a--;){var u=i[ot?a:++n];if(!1===e(o[u],u,o))break}return t};function at(t){return d(t)&&"[object Arguments]"==g(t)}var ut=Object.prototype,ct=ut.hasOwnProperty,st=ut.propertyIsEnumerable,ft=at(function(){return arguments}())?at:function(t){return d(t)&&ct.call(t,"callee")&&!st.call(t,"callee")};var lt="object"==typeof exports&&exports&&!exports.nodeType&&exports,pt=lt&&"object"==typeof module&&module&&!module.nodeType&&module,ht=pt&&pt.exports===lt?i.Buffer:void 0,vt=(ht?ht.isBuffer:void 0)||function(){return!1},gt=/^(?:0|[1-9]\d*)$/;function dt(t,e){var r=typeof t;return!!(e=null==e?9007199254740991:e)&&("number"==r||"symbol"!=r&>.test(t))&&t>-1&&t%1==0&&t-1&&t%1==0&&t<=9007199254740991}var _t={};_t["[object Float32Array]"]=_t["[object Float64Array]"]=_t["[object Int8Array]"]=_t["[object Int16Array]"]=_t["[object Int32Array]"]=_t["[object Uint8Array]"]=_t["[object Uint8ClampedArray]"]=_t["[object Uint16Array]"]=_t["[object Uint32Array]"]=!0,_t["[object Arguments]"]=_t["[object Array]"]=_t["[object ArrayBuffer]"]=_t["[object Boolean]"]=_t["[object DataView]"]=_t["[object Date]"]=_t["[object Error]"]=_t["[object Function]"]=_t["[object Map]"]=_t["[object Number]"]=_t["[object Object]"]=_t["[object RegExp]"]=_t["[object Set]"]=_t["[object String]"]=_t["[object WeakMap]"]=!1;var bt,mt="object"==typeof exports&&exports&&!exports.nodeType&&exports,jt=mt&&"object"==typeof module&&module&&!module.nodeType&&module,wt=jt&&jt.exports===mt&&n.process,Ot=function(){try{var t=jt&&jt.require&&jt.require("util").types;return t||wt&&wt.binding&&wt.binding("util")}catch(t){}}(),St=Ot&&Ot.isTypedArray,Et=St?(bt=St,function(t){return bt(t)}):function(t){return d(t)&&yt(t.length)&&!!_t[g(t)]},kt=Object.prototype.hasOwnProperty;function $t(t,e){var r=c(t),n=!r&&ft(t),o=!r&&!n&&vt(t),i=!r&&!n&&!o&&Et(t),a=r||n||o||i,u=a?function(t,e){for(var r=-1,n=Array(t);++r-1},Jt.prototype.set=function(t,e){var r=this.__data__,n=Lt(r,t);return n<0?(++this.size,r.push([t,e])):r[n][1]=e,this};var Ut,Dt=i["__core-js_shared__"],Ht=(Ut=/[^.]+$/.exec(Dt&&Dt.keys&&Dt.keys.IE_PROTO||""))?"Symbol(src)_1."+Ut:"";var It=Function.prototype.toString;function Wt(t){if(null!=t){try{return It.call(t)}catch(t){}try{return t+""}catch(t){}}return""}var Gt=/^\[object .+?Constructor\]$/,Bt=Function.prototype,Vt=Object.prototype,Yt=Bt.toString,Kt=Vt.hasOwnProperty,Qt=RegExp("^"+Yt.call(Kt).replace(/[\\^$.*+?()[\]{}|]/g,"\\$&").replace(/hasOwnProperty|(function).*?(?=\\\()| for .+?(?=\\\])/g,"$1.*?")+"$");function Xt(t){return!(!Nt(t)||function(t){return!!Ht&&Ht in t}(t))&&(zt(t)?Qt:Gt).test(Wt(t))}function Zt(t,e){var r=function(t,e){return null==t?void 0:t[e]}(t,e);return Xt(r)?r:void 0}var te=Zt(i,"Map"),ee=Zt(Object,"create");var re=Object.prototype.hasOwnProperty;var ne=Object.prototype.hasOwnProperty;function oe(t){var e=-1,r=null==t?0:t.length;for(this.clear();++eu))return!1;var s=i.get(t);if(s&&i.get(e))return s==e;var f=-1,l=!0,p=2&r?new ce:void 0;for(i.set(t,e),i.set(e,t);++fe.type.filter((function(t){var e;return void 0===r||(!1!==(e=V(t))?!Y({arg:r},e):!G(t)(r))})).length)})).length}return!1},or=function(t){function e(){for(var r=[],n=arguments.length;n--;)r[n]=arguments[n];t.apply(this,r),this.message=r[0],this.detail=r[1],this.className=e.name,t.captureStackTrace&&t.captureStackTrace(this,e)}t&&(e.__proto__=t),e.prototype=Object.create(t&&t.prototype),e.prototype.constructor=e;var r={name:{configurable:!0}};return r.name.get=function(){return"JsonqlValidationError"},Object.defineProperties(e,r),e}(Error),ir=function(t){function e(){for(var r=[],n=arguments.length;n--;)r[n]=arguments[n];t.apply(this,r),this.message=r[0],this.detail=r[1],this.className=e.name,t.captureStackTrace&&t.captureStackTrace(this,e)}t&&(e.__proto__=t),e.prototype=Object.create(t&&t.prototype),e.prototype.constructor=e;var r={name:{configurable:!0},statusCode:{configurable:!0}};return r.name.get=function(){return"JsonqlError"},r.statusCode.get=function(){return-1},Object.defineProperties(e,r),e}(Error),ar=function(t,e){var r,n,o,i,a;switch(!0){case"object"===t:return o=(n=e).arg,i=n.param,a=[o],Array.isArray(i.keys)&&i.keys.length&&a.push(i.keys),!Reflect.apply(nr,null,a);case"array"===t:return!B(e.arg);case!1!==(r=V(t)):return!Y(e,r);default:return!G(t)(e.arg)}},ur=function(t,e){return void 0!==t?t:!0===e.optional&&void 0!==e.defaultvalue?e.defaultvalue:null},cr=function(t,e,r){var n;void 0===r&&(r=!1);var o=function(t,e){if(!B(e))throw new or("params is not an array! Did something gone wrong when you generate the contract.json?");if(0===e.length)return[];if(!B(t))throw new or("args is not an array! You might want to do: ES6 Array.from(arguments) or ES5 Array.prototype.slice.call(arguments)");switch(!0){case t.length==e.length:return t.map((function(t,r){return{arg:t,index:r,param:e[r]}}));case!0===e[0].variable:var r=e[0].type;return t.map((function(t,n){return{arg:t,index:n,param:e[n]||{type:r,name:"_"}}}));case t.lengthe.length:var n=e.length,o=["any"];return t.map((function(t,r){var i=r>=n||!!e[r].optional,a=e[r]||{type:o,name:"_"+r};return{arg:i?ur(t,a):t,index:r,param:a,optional:i}}));default:throw new ir("Could not understand your arguments and parameter structure!",{args:t,params:e})}}(t,e),i=o.filter((function(t){return!0===t.optional||!0===t.param.optional?function(t){var e=t.arg,r=t.param;return!!M(e)&&!(r.type.length>r.type.filter((function(e){return ar(e,t)})).length)}(t):!(t.param.type.length>t.param.type.filter((function(e){return ar(e,t)})).length)}));return r?((n={}).error=i,n.data=o.map((function(t){return t.arg})),n):i},sr=function(){try{var t=Zt(Object,"defineProperty");return t({},"",{}),t}catch(t){}}();function fr(t,e,r){"__proto__"==e&&sr?sr(t,e,{configurable:!0,enumerable:!0,value:r,writable:!0}):t[e]=r}function lr(t,e,r){(void 0===r||Ft(t[e],r))&&(void 0!==r||e in t)||fr(t,e,r)}var pr="object"==typeof exports&&exports&&!exports.nodeType&&exports,hr=pr&&"object"==typeof module&&module&&!module.nodeType&&module,vr=hr&&hr.exports===pr?i.Buffer:void 0,gr=vr?vr.allocUnsafe:void 0;function dr(t,e){var r,n,o=e?(r=t.buffer,n=new r.constructor(r.byteLength),new le(n).set(new le(r)),n):t.buffer;return new t.constructor(o,t.byteOffset,t.length)}var yr=Object.create,_r=function(){function t(){}return function(e){if(!Nt(e))return{};if(yr)return yr(e);t.prototype=e;var r=new t;return t.prototype=void 0,r}}();function br(t,e){if(("constructor"!==e||"function"!=typeof t[e])&&"__proto__"!=e)return t[e]}var mr=Object.prototype.hasOwnProperty;function jr(t,e,r){var n=t[e];mr.call(t,e)&&Ft(n,r)&&(void 0!==r||e in t)||fr(t,e,r)}var wr=Object.prototype.hasOwnProperty;function Or(t){if(!Nt(t))return function(t){var e=[];if(null!=t)for(var r in Object(t))e.push(r);return e}(t);var e=At(t),r=[];for(var n in t)("constructor"!=n||!e&&wr.call(t,n))&&r.push(n);return r}function Sr(t){return Ct(t)?$t(t,!0):Or(t)}function Er(t){return function(t,e,r,n){var o=!r;r||(r={});for(var i=-1,a=e.length;++i0){if(++e>=800)return arguments[0]}else e=0;return t.apply(void 0,arguments)}}(Pr);function zr(t,e){return Nr(function(t,e,r){return e=Ar(void 0===e?t.length-1:e,0),function(){for(var n=arguments,o=-1,i=Ar(n.length-e,0),a=Array(i);++o1?e[n-1]:void 0,i=n>2?e[2]:void 0;for(o=Cr.length>3&&"function"==typeof o?(n--,o):void 0,i&&function(t,e,r){if(!Nt(r))return!1;var n=typeof e;return!!("number"==n?Ct(r)&&dt(e,r.length):"string"==n&&e in r)&&Ft(r[e],t)}(e[0],e[1],i)&&(o=n<3?void 0:o,n=1),t=Object(t);++r0;)e[r]=arguments[r+1];if(this.logger("($queue) get called"),!0===this.__suspend_state__){if(un(this.__pattern__)){var n=this.__pattern__.test(t);if(!n)return!1}this.logger("($queue) added to $queue",e),this.queueStore.add([t].concat(e))}return!!this.__suspend_state__},fn.$queues.get=function(){var t=this.queueStore.size;return this.logger("($queues)","size: "+t),t>0?Array.from(this.queueStore):[]},sn.prototype.__suspend__=function(t){if("boolean"!=typeof t)throw new Error("$suspend only accept Boolean value! we got "+typeof t);var e=this.__suspend_state__;this.__suspend_state__=t,this.logger('($suspend) Change from "'+e+'" --\x3e "'+t+'"'),!0===e&&!1===t&&this.__release__()},sn.prototype.__release__=function(){var t=this,e=this.queueStore.size,r=this.__pattern__;if(this.__pattern__=null,this.logger("(release) was called with "+e+(r?' for "'+r+'"':"")+" item"+(e>1?"s":"")),e>0){var n=Array.from(this.queueStore);this.queueStore.clear(),this.logger("(release queue)",n),n.forEach((function(e){t.logger(e),Reflect.apply(t.$trigger,t,e)})),this.logger("Release size "+this.queueStore.size)}return e},Object.defineProperties(sn.prototype,fn);var ln=function(t){function e(e){if("function"!=typeof e)throw new Error("Just die here the logger is not a function!");e("---\x3e Create a new EventEmitter <---"),t.call(this,{logger:e})}t&&(e.__proto__=t),e.prototype=Object.create(t&&t.prototype),e.prototype.constructor=e;var r={name:{configurable:!0}};return r.name.get=function(){return"jsonql-ws-client-core"},Object.defineProperties(e.prototype,r),e}(function(t){function e(e){void 0===e&&(e={}),t.call(this,e)}t&&(e.__proto__=t),e.prototype=Object.create(t&&t.prototype),e.prototype.constructor=e;var r={$name:{configurable:!0},is:{configurable:!0},$done:{configurable:!0}};return e.prototype.logger=function(){},r.$name.get=function(){return"to1source-event"},r.is.get=function(){return this.$name},e.prototype.$on=function(t,e,r){var n=this;void 0===r&&(r=null);this.validate(t,e);var o=this.takeFromStore(t);if(!1===o)return this.logger('($on) "'+t+'" is not in lazy store'),this.addToNormalStore(t,"on",e,r);this.logger("($on) "+t+" found in lazy store");var i=0;return o.forEach((function(o){var a=o[0],u=o[1],c=o[2];if(c&&"on"!==c)throw new Error(nn+" "+c);n.logger("($on)",'call run "'+t+'"'),n.run(e,a,r||u),i+=n.addToNormalStore(t,"on",e,r||u)})),this.logger("($on) return size "+i),i},e.prototype.$once=function(t,e,r){void 0===r&&(r=null),this.validate(t,e);var n=this.takeFromStore(t);this.normalStore;if(!1===n)return this.logger('($once) "'+t+'" is not in the lazy store'),this.addToNormalStore(t,"once",e,r);this.logger("($once)",n);var o=Array.from(n)[0],i=o[0],a=o[1],u=o[2];if(u&&"once"!==u)throw new Error(nn+" "+u);this.logger("($once)",'call run "'+t+'"'),this.run(e,i,r||a),this.$off(t)},e.prototype.$only=function(t,e,r){var n=this;void 0===r&&(r=null),this.validate(t,e);var o=!1,i=this.takeFromStore(t);(this.normalStore.has(t)||(this.logger('($only) "'+t+'" add to normalStore'),o=this.addToNormalStore(t,"only",e,r)),!1!==i)&&(this.logger('($only) "'+t+'" found data in lazy store to execute'),Array.from(i).forEach((function(o){var i=o[0],a=o[1],u=o[2];if(u&&"only"!==u)throw new Error(nn+" "+u);n.logger('($only) call run "'+t+'"'),n.run(e,i,r||a)})));return o},e.prototype.$onlyOnce=function(t,e,r){void 0===r&&(r=null),this.validate(t,e);var n=!1,o=this.takeFromStore(t);if(this.normalStore.has(t)||(this.logger('($onlyOnce) "'+t+'" add to normalStore'),n=this.addToNormalStore(t,"onlyOnce",e,r)),!1!==o){this.logger("($onlyOnce)",o);var i=Array.from(o)[0],a=i[0],u=i[1],c=i[2];if(c&&"onlyOnce"!==c)throw new Error(nn+" "+c);this.logger('($onlyOnce) call run "'+t+'"'),this.run(e,a,r||u),this.$off(t)}return n},e.prototype.$replace=function(t,e,r,n){if(void 0===r&&(r=null),void 0===n&&(n="on"),this.validateType(n)){this.$off(t);var o=this["$"+n];return this.logger("($replace)",t,e),Reflect.apply(o,this,[t,e,r])}throw new Error(n+" is not supported!")},e.prototype.$trigger=function(t,e,r,n){void 0===e&&(e=[]),void 0===r&&(r=null),void 0===n&&(n=!1),this.validateEvt(t);var o=0,i=this.normalStore;if(this.logger("($trigger) normalStore",i),i.has(t)){if(this.logger('($trigger) "'+t+'" found'),this.$queue(t,e,r,n))return this.logger('($trigger) Currently suspended "'+t+'" added to queue, nothing executed. Exit now.'),!1;for(var a=Array.from(i.get(t)),u=a.length,c=!1,s=0;s0;)n[o]=arguments[o+2];if(t.has(e)?(this.logger('(addToStore) "'+e+'" existed'),r=t.get(e)):(this.logger('(addToStore) create new Set for "'+e+'"'),r=new Set),n.length>2)if(Array.isArray(n[0])){var i=n[2];this.checkTypeInLazyStore(e,i)||r.add(n)}else this.checkContentExist(n,r)||(this.logger("(addToStore) insert new",n),r.add(n));else r.add(n);return t.set(e,r),[t,r.size]},e.prototype.checkContentExist=function(t,e){return!!Array.from(e).filter((function(e){return e[0]===t[0]})).length},e.prototype.checkTypeInStore=function(t,e){this.validateEvt(t,e);var r=this.$get(t,!0);return!1===r||!r.filter((function(t){var r=t[3];return e!==r})).length},e.prototype.checkTypeInLazyStore=function(t,e){this.validateEvt(t,e);var r=this.lazyStore.get(t);return this.logger("(checkTypeInLazyStore)",r),!!r&&!!Array.from(r).filter((function(t){return t[2]!==e})).length},e.prototype.addToNormalStore=function(t,e,r,n){if(void 0===n&&(n=null),this.logger('(addToNormalStore) try to add "'+e+'" --\x3e "'+t+'" to normal store'),this.checkTypeInStore(t,e)){this.logger("(addToNormalStore)",'"'+e+'" --\x3e "'+t+'" can add to normal store');var o=this.hashFnToKey(r),i=[this.normalStore,t,o,r,n,e],a=Reflect.apply(this.addToStore,this,i),u=a[0],c=a[1];return this.normalStore=u,c}return!1},e.prototype.addToLazyStore=function(t,e,r,n){void 0===e&&(e=[]),void 0===r&&(r=null),void 0===n&&(n=!1);var o=[this.lazyStore,t,this.toArray(e),r];n&&o.push(n);var i=Reflect.apply(this.addToStore,this,o),a=i[0],u=i[1];return this.lazyStore=a,this.logger("(addToLazyStore) size: "+u),u},e.prototype.toArray=function(t){return Array.isArray(t)?t:[t]},r.normalStore.set=function(t){on.set(this,t)},r.normalStore.get=function(){return on.get(this)},r.lazyStore.set=function(t){an.set(this,t)},r.lazyStore.get=function(){return an.get(this)},e.prototype.hashFnToKey=function(t){return function(t){return t.split("").reduce((function(t,e){return(t=(t<<5)-t+e.charCodeAt(0))&t}),0)}(t.toString())+""},Object.defineProperties(e.prototype,r),e}(sn))),pn=function(t){return c(t)?t:[t]},hn=function(t,e){try{var r=Object.keys(t);return n=e,!!r.filter((function(t){return t===n})).length}catch(t){return!1}var n},vn=function(){for(var t=[],e=arguments.length;e--;)t[e]=arguments[e];return t.join("_")},gn=function(t){if("function"==typeof t)return!0;console.error("Expect to be Function type! Got "+typeof t)},dn=function(){return!1},yn=function(t){for(var e=[],r=arguments.length-1;r-- >0;)e[r]=arguments[r+1];return function(){for(var r=[],n=arguments.length;n--;)r[n]=arguments[n];return e.reduce((function(t,e){return Reflect.apply(e,null,pn(t))}),Reflect.apply(t,null,r))}};function _n(t,e,r,n){return void 0===n&&(n=null),void 0===Object.getOwnPropertyDescriptor(t,e)&&Object.defineProperty(t,e,{set:r,get:null===n?function(){return null}:n}),t}function bn(t,e,r,n){void 0===n&&(n=!1);var o=function(t,e){var r=Object.getOwnPropertyDescriptor(t,e);return void 0!==r&&r.value?r.value:r}(t,e);return!1===n&&void 0!==o||Object.defineProperty(t,e,{value:r,writable:n}),t}var mn=function(t){function e(){for(var r=[],n=arguments.length;n--;)r[n]=arguments[n];t.apply(this,r),this.message=r[0],this.detail=r[1],this.className=e.name,t.captureStackTrace&&t.captureStackTrace(this,e)}t&&(e.__proto__=t),e.prototype=Object.create(t&&t.prototype),e.prototype.constructor=e;var r={statusCode:{configurable:!0},name:{configurable:!0}};return r.statusCode.get=function(){return 406},r.name.get=function(){return"Jsonql406Error"},Object.defineProperties(e,r),e}(Error),jn=function(t){function e(){for(var r=[],n=arguments.length;n--;)r[n]=arguments[n];t.apply(this,r),this.message=r[0],this.detail=r[1],this.className=e.name,t.captureStackTrace&&t.captureStackTrace(this,e)}t&&(e.__proto__=t),e.prototype=Object.create(t&&t.prototype),e.prototype.constructor=e;var r={statusCode:{configurable:!0},name:{configurable:!0}};return r.statusCode.get=function(){return 500},r.name.get=function(){return"Jsonql500Error"},Object.defineProperties(e,r),e}(Error),wn=function(t){function e(){for(var r=[],n=arguments.length;n--;)r[n]=arguments[n];t.apply(this,r),this.message=r[0],this.detail=r[1],this.className=e.name,t.captureStackTrace&&t.captureStackTrace(this,e)}t&&(e.__proto__=t),e.prototype=Object.create(t&&t.prototype),e.prototype.constructor=e;var r={statusCode:{configurable:!0},name:{configurable:!0}};return r.statusCode.get=function(){return 403},r.name.get=function(){return"JsonqlForbiddenError"},Object.defineProperties(e,r),e}(Error),On=function(t){function e(){for(var r=[],n=arguments.length;n--;)r[n]=arguments[n];t.apply(this,r),this.message=r[0],this.detail=r[1],this.className=e.name,t.captureStackTrace&&t.captureStackTrace(this,e)}t&&(e.__proto__=t),e.prototype=Object.create(t&&t.prototype),e.prototype.constructor=e;var r={statusCode:{configurable:!0},name:{configurable:!0}};return r.statusCode.get=function(){return 401},r.name.get=function(){return"JsonqlAuthorisationError"},Object.defineProperties(e,r),e}(Error),Sn=function(t){function e(){for(var r=[],n=arguments.length;n--;)r[n]=arguments[n];t.apply(this,r),this.message=r[0],this.detail=r[1],this.className=e.name,t.captureStackTrace&&t.captureStackTrace(this,e)}t&&(e.__proto__=t),e.prototype=Object.create(t&&t.prototype),e.prototype.constructor=e;var r={statusCode:{configurable:!0},name:{configurable:!0}};return r.statusCode.get=function(){return 401},r.name.get=function(){return"JsonqlContractAuthError"},Object.defineProperties(e,r),e}(Error),En=function(t){function e(){for(var r=[],n=arguments.length;n--;)r[n]=arguments[n];t.apply(this,r),this.message=r[0],this.detail=r[1],this.className=e.name,t.captureStackTrace&&t.captureStackTrace(this,e)}t&&(e.__proto__=t),e.prototype=Object.create(t&&t.prototype),e.prototype.constructor=e;var r={statusCode:{configurable:!0},name:{configurable:!0}};return r.statusCode.get=function(){return 500},r.name.get=function(){return"JsonqlResolverAppError"},Object.defineProperties(e,r),e}(Error),kn=function(t){function e(){for(var r=[],n=arguments.length;n--;)r[n]=arguments[n];t.apply(this,r),this.message=r[0],this.detail=r[1],this.className=e.name,t.captureStackTrace&&t.captureStackTrace(this,e)}t&&(e.__proto__=t),e.prototype=Object.create(t&&t.prototype),e.prototype.constructor=e;var r={statusCode:{configurable:!0},name:{configurable:!0}};return r.statusCode.get=function(){return 404},r.name.get=function(){return"JsonqlResolverNotFoundError"},Object.defineProperties(e,r),e}(Error),$n=function(t){function e(r,n){t.call(this,n),this.statusCode=r,this.className=e.name}t&&(e.__proto__=t),e.prototype=Object.create(t&&t.prototype),e.prototype.constructor=e;var r={name:{configurable:!0}};return r.name.get=function(){return"JsonqlServerError"},Object.defineProperties(e,r),e}(Error);function Tn(t){if(Array.isArray(t))throw new or("",t);var e=t.message||"No message",r=t.detail||t;switch(!0){case t instanceof mn:throw new mn(e,r);case t instanceof jn:throw new jn(e,r);case t instanceof wn:throw new wn(e,r);case t instanceof On:throw new On(e,r);case t instanceof Sn:throw new Sn(e,r);case t instanceof En:throw new En(e,r);case t instanceof kn:throw new kn(e,r);case t instanceof Wr:throw new Wr(e,r);case t instanceof Gr:throw new Gr(e,r);case t instanceof Br:throw new Br(e,r);case t instanceof or:throw new or(e,r);case t instanceof $n:throw new $n(e,r);default:throw new ir(e,r)}}function An(t){var e=function(t){return!!hn(t,"socket")&&t.socket}(t);if(!1===e)throw new JsonqlError("groupByNamespace","socket not found in contract!");var r={nspGroup:{},publicNamespace:null,size:0};for(var n in e){var o=e[n],i=o.namespace;i&&(r.nspGroup[i]||(++r.size,r.nspGroup[i]={}),r.nspGroup[i][n]=o,!r.publicNamespace&&o.public&&(r.publicNamespace=i))}return r}var Pn=function(t){var e=t.toLowerCase();return e.indexOf("http")>-1?e.indexOf("https")>-1?e.replace("https","wss"):e.replace("http","ws"):e},xn=function(t,e){pn(e).forEach((function(e){t.$off(vn(e,"emit_reply"))}))},Nn=function(t,e,r){return[bn(t,e.loginHandlerName,(function(t){if(t&&Qr(t))return e.log("Received __login__ with "+t),r.$trigger("__login__",[t]);throw new or(e.loginHandlerName,"Unexpected token "+t)})),e,r]},zn=function(t,e,r){return[bn(t,e.logoutHandlerName,(function(){for(var t=[],e=arguments.length;e--;)t[e]=arguments[e];r.$trigger("__logout__",t)})),e,r]},Cn=function(t,e,r){return[_n(t,"onLogin",(function(t){gn(t)&&r.$only("onLogin",t)})),e,r]};function Rn(t,e,r){return yn(Nn,zn,Cn)(t,e,r)}function qn(t,e,r){hn(t,"error")?r(t.error):hn(t,"data")?e(t.data):r({message:"UKNNOWN RESULT!",error:t})}function Fn(t,e,r,n,o){void 0===n&&(n=[]);var i=vn(e,"emit_reply");return o("actionCall: "+i+" --\x3e "+r,n),t.$trigger(i,[r,pn(n)]),new Promise((function(n,i){var a=vn(e,r,"onResult");t.$on(a,(function(t){o("got the first result",t),qn(t,n,i)}))}))}var Ln,Mn,Jn,Un=function(t,e,r,n,o,i){return _n(t,"send",dn,(function(){return function(){for(var t=[],a=arguments.length;a--;)t[a]=arguments[a];return Xr(t,o.params,!0).then((function(t){return i(r,n,t),Fn(e,r,n,t,_log)})).catch((function(t){i("send error",t),e.$call(vn(r,n,"onError"),[new or(n,t)])}))}}))},Dn=function(t,e,r,n,o,i){return[bn(t,"myNamespace",r),e,r,n,o,i]},Hn=function(t,e,r,n,o,i){return[_n(t,"onResult",(function(t){gn(t)&&e.$on(vn(r,n,"onResult"),(function(o){qn(o,t,(function(t){i('Catch error: "'+n+'"',t),e.$trigger(vn(r,n,"onError"),t)}))}))})),e,r,n,o,i]},In=function(t,e,r,n,o,i){return[_n(t,"onMessage",(function(t){if(gn(t)){e.$only(vn(r,n,"onMessage"),(function(o){qn(o,t,(function(t){i('Catch error: "'+n+'"',t),e.$trigger(vn(r,n,"onError"),t)}))}))}})),e,r,n,o,i]},Wn=function(t,e,r,n,o,i){return[_n(t,"onError",(function(t){gn(t)&&e.$only(vn(r,n,"onError"),t)})),e,r,n,o,i]};function Gn(t,e,r,n,o,i){var a=[Dn,Hn,In,Wn,Un],u=Reflect.apply(yn,null,a),c=[n,o,t,e,r,i];return Reflect.apply(u,null,c)}function Bn(t,e,r,n,o){return function(){for(var i=[],a=arguments.length;a--;)i[a]=arguments[a];return Xr(i,n.params,!0).then((function(n){return Fn(t,e,r,n,o)})).catch(Tn)}}function Vn(t,e,r){var n={},o=t.log;for(var i in r){var a=r[i];for(var u in a){var c=a[u];n=bn(n,u,Gn(i,u,c,Bn(e,i,u,c,o),e,o))}}return[n,t,e,r]}function Yn(t,e,r,n){return[_n(t,"onError",(function(t){if(gn(t))for(var e in n)r.$on(vn(e,"onError"),t)})),e,r]}function Kn(t,e,r){return[_n(t,"onReady",(function(t){gn(t)&&r.$on("onReady",t)})),e,r]}function Qn(t,e,r){var n=function(t,e,r){return bn(t,e.disconnectHandlerName,(function(){for(var t=[],e=arguments.length;e--;)t[e]=arguments[e];r.$trigger("__disconnect__",t)}))}(t,e,r);return e.log("---\x3e The final step to return the ws-client <---"),n.verifyEventEmitter=function(){return r.is},n.eventEmitter=e.eventEmitter,n.log=e.log,n}var Xn=["roundtip","handshake"],Zn={standalone:Zr(!1,["boolean"]),debugOn:Zr(!1,["boolean"]),loginHandlerName:Zr("login",["string"]),logoutHandlerName:Zr("logout",["string"]),disconnectHandlerName:Zr("disconnect",["string"]),switchUserHandlerName:Zr("switch-user",["string"]),loginMethod:Zr("handshake",["string"],(Ln={},Ln.enumv=Xn,Ln)),useJwt:Zr(!0,["boolean","string"]),authStrKey:Zr(null,["string"]),hostname:Zr(!1,["string"]),namespace:Zr("jsonql",["string"]),wsOptions:Zr({},["object"]),contract:Zr({},["object"],(Mn={},Mn.checker=function(t){return!!function(t){return nt(t)&&(hn(t,"query")||hn(t,"mutation")||hn(t,"socket"))}(t)&&t},Mn)),enableAuth:Zr(!1,["boolean"]),token:Zr(!1,["string"])},to={};to.serverType=Zr(null,["string"],((Jn={}).alias="socketClientType",Jn));var eo=Object.assign(Zn,to);function ro(t){return Promise.resolve(t).then((function(t){return t.hostname||(t.hostname=function(){try{return[window.location.protocol,window.location.host].join("//")}catch(t){throw new or(t)}}()),t.wssPath=Pn([t.hostname,t.namespace].join("/"),t.serverType),t.log=rn(t),t.eventEmitter=function(t){var e=t.log,r=t.eventEmitter;return r?(e("eventEmitter is:",r.name),r):new ln(t.log)}(t),t}))}function no(t){return{opts:t,nspMap:(e=t,r=e.contract,n=e.enableAuth,o=function(t){var e="jsonql";return t.enableAuth?[[e,t.publicNamespace].join("/"),[e,t.privateNamespace].join("/")]:[e]}(e),i=n?An(r):function(t,e){var r,n={};for(var o in t){var i=t[o];n[o]=i}return{size:1,nspGroup:(r={},r[e]=n,r),publicNamespace:e}}(r.socket,o[0]),Object.assign(i,{namespaces:o})),ee:t.eventEmitter};var e,r,n,o,i}function oo(t,e){return ro(e).then(no).then((function(e){var r=e.opts,n=e.nspMap,o=e.ee;return t(r,n,o)})).then((function(t){return function(t,e,r){var n=[Vn,Yn,Kn];return t.enableAuth&&n.push(Rn),n.push(Qn),Reflect.apply(yn,null,n)(t,r,e.nspGroup)}(t.opts,t.nspMap,t.ee)})).catch((function(t){console.error("jsonql-ws-core-client init error",t)}))}function io(t,e){var r=e.hostname,n=e.wssPath,o=e.wsOptions;return(0,e.nspClient)(t?[r,t].join("/"):n,o)}function ao(t,e,r){e.forEach((function(e){t.$trigger(vn(e,"onError"),[{message:r,namespace:e}])}))}var uo=function(t,e,r){var n=r.log;e.$only(vn(t,"emit_reply"),(function(r,o){n("[notLoginHandler] hijack the ws call",t,r,o);var i={message:"NOT LOGIN"};e.$call(vn(t,r,"onError"),[i]),e.$call(vn(t,r,"onResult"),[{error:i}])}))},co=function(t){return t.length>1&&t[0]},so=function(t,e,r,n){var o=n.log;r.$on("__disconnect__",(function(){ao(r,e,"__disconnect__"),e.forEach((function(e){o("disconnect from "+e),xn(r,e),t[e]=null,function(t,e,r){var n=r.log;e.$only(vn(t,"emit_reply"),(function(r,o){n("[disconnectedHandler] hijack the ws call",t,r,o);var i={message:"You have disconnected from the socket server, please reconnect."};e.$call(vn(t,r,"onError"),[i]),e.$call(vn(t,r,"onResult"),[{error:i}])}))}(e,r,n)}))}))};function fo(t,e,r,n,o,i){var a=co(o),u=!1,c=!1,s=t.log;o.forEach((function(o){if(u=a===o,c||(c=u),i[o]){s("[call bindWsHandler]",u,o);var f=[o,i[o],r,u,t];if("socket.io"===t.serverType){var l=e.nspSet;f.push(l[o])}Reflect.apply(n,null,f)}else uo(o,r,t)})),c&&(s("Has private and add logoutEvtHandler"),function(t,e,r,n){var o=n.log;r.$on("__logout__",(function(){var i=co(e);o("__logout__ event triggered"),ao(r,[i],"__logout__"),o("logout from "+i),xn(r,i),t[i]=null,uo(i,r,n)}))}(i,o,r,t)),so(i,o,r,t)}var lo={version:"version: 1.1.1 module: cjs-module",serverType:"ws"},po=Object.assign({},eo,{}),ho=Object.assign({},{log:null,eventEmitter:null,nspClient:null,nspAuthClient:null,wssPath:""},lo);function vo(t,e){return void 0===e&&(e=!1),!1===e?function(e){return new t(Pn(e))}:function(e,r){var n=Pn(e),o=r&&"string"==typeof r?n+"?token="+r:n;try{return new t(o)}catch(t){return console.error("WebSocket Connection Error",t),!1}}}var go=Array.isArray,yo="object"==typeof r&&r&&r.Object===Object&&r,_o="object"==typeof self&&self&&self.Object===Object&&self,bo=(yo||_o||Function("return this")()).Symbol,mo=Object.prototype,jo=mo.hasOwnProperty,wo=mo.toString,Oo=bo?bo.toStringTag:void 0;var So=Object.prototype.toString;var Eo=bo?bo.toStringTag:void 0;function ko(t){return null==t?void 0===t?"[object Undefined]":"[object Null]":Eo&&Eo in Object(t)?function(t){var e=jo.call(t,Oo),r=t[Oo];try{t[Oo]=void 0;var n=!0}catch(t){}var o=wo.call(t);return n&&(e?t[Oo]=r:delete t[Oo]),o}(t):function(t){return So.call(t)}(t)}function $o(t){return null!=t&&"object"==typeof t}var To=bo?bo.prototype:void 0,Ao=To?To.toString:void 0;function Po(t){if("string"==typeof t)return t;if(go(t))return function(t,e){for(var r=-1,n=null==t?0:t.length,o=Array(n);++r=n?t:function(t,e,r){var n=-1,o=t.length;e<0&&(e=-e>o?0:o+e),(r=r>o?o:r)<0&&(r+=o),o=e>r?0:r-e>>>0,e>>>=0;for(var i=Array(o);++n-1;);return r}(o,i),function(t,e){for(var r=t.length;r--&&zo(e,t[r],0)>-1;);return r}(o,i)+1).join("")}var Vo=function(){for(var t=[],e=arguments.length;e--;)t[e]=arguments[e];return t.join("_")},Yo=function(t){function e(){for(var r=[],n=arguments.length;n--;)r[n]=arguments[n];t.apply(this,r),this.message=r[0],this.detail=r[1],this.className=e.name,t.captureStackTrace&&t.captureStackTrace(this,e)}t&&(e.__proto__=t),e.prototype=Object.create(t&&t.prototype),e.prototype.constructor=e;var r={name:{configurable:!0}};return r.name.get=function(){return"JsonqlValidationError"},Object.defineProperties(e,r),e}(Error),Ko=function(t){function e(){for(var r=[],n=arguments.length;n--;)r[n]=arguments[n];t.apply(this,r),this.message=r[0],this.detail=r[1],this.className=e.name,t.captureStackTrace&&t.captureStackTrace(this,e)}t&&(e.__proto__=t),e.prototype=Object.create(t&&t.prototype),e.prototype.constructor=e;var r={name:{configurable:!0},statusCode:{configurable:!0}};return r.name.get=function(){return"JsonqlError"},r.statusCode.get=function(){return-1},Object.defineProperties(e,r),e}(Error),Qo=function(t){void 0===t&&(t=!1);var e=Date.now();return t?Math.floor(e/1e3):e};function Xo(t){return"string"==typeof t||!go(t)&&$o(t)&&"[object String]"==ko(t)}function Zo(t,e,r){if(void 0===e&&(e=[]),void 0===r&&(r=!1),Xo(t)&&go(e)){var n=function(t){var e;return(e={}).args=t,e}(e);return!0===r?n:function(t,e){var r;return(r={})[t]=e,r.TS=[Qo()],r}(t,n)}throw new Yo("[createQuery] expect resolverName to be string and args to be array!",{resolverName:t,args:e})}var ti=function(t){return""!==Bo(t)&&Xo(t)},ei=["__reply__","__event__","__data__"],ri=function(t){var e=t.data;return!!e&&(ei.filter((function(t){return function(t,e){try{var r=Object.keys(t);return n=e,!!r.filter((function(t){return t===n})).length}catch(t){return!1}var n}(e,t)})).length===ei.length&&e)},ni=function(t,e,r,n,o){var i=[e];r&&i.push(r),i.push(o);var a=Reflect.apply(Vo,null,i),u=n.data||n;t.$trigger(a,[u])};function oi(t,e,r,n,o){var i=o.log;i("log test, isPrivate:",n),e.onopen=function(){i("ws.onopen listened"),r.$call("onReady",t),n&&(i("isPrivate and fire the onLogin"),r.$call("onLogin",t)),r.$only(Vo(t,"emit_reply"),(function(t,r){var n=function(t,e,r){return void 0===e&&(e=[]),void 0===r&&(r=!1),JSON.stringify(Zo(t,e,r))}(t,r);i("calling server",t,r,n),e.send(n)}))},e.onmessage=function(e){try{var n=function(t){var e,r=t.data,n=ti(r)?JSON.parse(r):r;if(!1!==(e=ri(n)))return{resolverName:e.__event__,data:e.__data__,type:e.__reply__};throw new Ko("payload can not be decoded",t)}(e),o=n.resolverName,a=n.type;switch(i("Hear from server",a,n),a){case"emit_reply":var u=Vo(t,o,"onMessage"),c=r.$trigger(u,[n]);i("EMIT_REPLY_TYPE",u,c);break;case"acknowledge_reply":var s=Vo(t,o,"onResult"),f=r.$trigger(s,[n]);i("ACKNOWLEDGE_REPLY_TYPE",s,f);break;case"error":i("ERROR_TYPE"),ni(r,t,o,n,"onError");break;default:i("Unhandled event!",n),ni(r,t,o,n,"onError")}}catch(e){console.error("ws.onmessage error",e),ni(r,t,!1,e,"onError")}},e.onclose=function(){i("ws.onclose callback")},e.onerror=function(e){i("ws.onerror",e),r.$trigger(Vo(t,"onError"),[e])},n&&r.$on("__logout__",(function(){try{i("terminate ws connection"),e.terminate()}catch(t){console.error("ws.terminate error",t)}}))}var ii=function(t,e,r){var n,o=t.log,i=e.nspGroup,a=e.publicNamespace,u=!1,c=[],s={};if(t.enableAuth)u=!0,s=(c=function(t,e){var r=[];for(var n in t)n===e?r[1]=n:r[0]=n;return r}(i,a)).map((function(e,n){var i,a,u;return 0===n?r?(t.token=r,o("create createNspAuthClient at run time"),(i={})[e]=function(t,e){var r=e.hostname,n=e.wssPath,o=e.token,i=e.wsOptions,a=e.nspAuthClient,u=t?[r,t].join("/"):n;if(o&&"string"!=typeof o)throw new Error("Expect token to be string, but got "+o);return a(u,o,i)}(e,t),i):((a={})[e]=!1,a):((u={})[e]=io(e,t),u)})).reduce((function(t,e){return Object.assign(t,e)}),{});else{var f=(n=i,console.error("This method is going to be deprectead in the next release, please use getResolverFromPayload instead"),Object.keys(n)[0]);c.push(f),s[f]=io(!1,t)}return{nsps:s,namespaces:c,loginRequired:u}};function ai(t,e,r,n){var o=n.log;t.$only("__login__",(function(i){o("createClient LOGIN_EVENT_NAME $only handler"),xn(t,e);var a=ii(n,r,i);Reflect.apply(fo,null,args.concat([a.namespaces,a.nsps]))}))}var ui,ci,si,fi,li=(ci=vo(ui=e),si=vo(ui,!0),function(t,e,r){t.nspClient=ci,t.nspAuthClient=si;var n=t.log;return n&&"function"==typeof n&&(n("@jsonql/ws ee",r.name),n("@jsonql/ws createClientResolver",t)),function(t,e,r){var n=[t,e,r,oi],o=t.token,i=(t.log,ii(t,e,o)),a=i.nsps,u=i.namespaces,c=i.loginRequired;return Reflect.apply(fo,null,n.concat([u,a])),c&&ai(r,u,e,t),{opts:t,nspMap:e,ee:r}}(t,e,r)}),pi=(fi=li,function(t){return Promise.resolve(t).then((function(t){return oo(fi,t)}))});exports.checkSocketClientType=function(t){return tn(t,to)},exports.createWsClient=pi,exports.jsonqlWsClientAppProps=po,exports.jsonqlWsConstProps=ho; //# sourceMappingURL=node.js.map diff --git a/packages/@jsonql/ws/package.json b/packages/@jsonql/ws/package.json index 7b8fa994..311b59b0 100644 --- a/packages/@jsonql/ws/package.json +++ b/packages/@jsonql/ws/package.json @@ -46,11 +46,11 @@ "license": "ISC", "homepage": "jsonql.org", "dependencies": { - "jsonql-constants": "^1.9.8", + "jsonql-constants": "^1.9.9", "jsonql-errors": "^1.1.10", "jsonql-jwt": "^1.3.9", "jsonql-params-validator": "^1.5.3", - "jsonql-utils": "^1.1.2", + "jsonql-utils": "^1.1.3", "jsonql-ws-client-core": "^0.8.4", "ws": "^7.2.3" }, @@ -62,11 +62,11 @@ "glob": "^7.1.6", "jsonql-contract": "^1.8.8", "jsonql-koa": "^1.6.2", - "jsonql-ws-server": "^1.7.1", + "jsonql-ws-server": "^1.7.2", "kefir": "^3.8.6", "koa": "^2.11.0", "koa-bodyparser": "^4.2.1", - "rollup": "^2.0.4", + "rollup": "^2.0.5", "rollup-plugin-alias": "^2.2.0", "rollup-plugin-async": "^1.2.0", "rollup-plugin-buble": "^0.19.8", diff --git a/packages/@jsonql/ws/src/core/create-nsp.js b/packages/@jsonql/ws/src/core/create-nsp.js index 152ca061..7a2cf045 100644 --- a/packages/@jsonql/ws/src/core/create-nsp.js +++ b/packages/@jsonql/ws/src/core/create-nsp.js @@ -26,14 +26,14 @@ import { socketEventHandler } from './socket-event-handler' */ const createNspAction = function(opts, nspMap, token) { const { log } = opts - let { nspSet, publicNamespace } = nspMap + let { nspGroup, publicNamespace } = nspMap let loginRequired = false let namespaces = [] let nsps = {} // first we need to binding all the events handler if (opts.enableAuth) { // && opts.useJwt loginRequired = true // just saying we need to listen to login event - namespaces = getNamespaceInOrder(nspSet, publicNamespace) + namespaces = getNamespaceInOrder(nspGroup, publicNamespace) nsps = namespaces.map((namespace, i) => { if (i === 0) { if (token) { @@ -46,7 +46,7 @@ const createNspAction = function(opts, nspMap, token) { return {[namespace]: createNspClient(namespace, opts)} }).reduce((first, next) => Object.assign(first, next), {}) } else { - let namespace = getNameFromPayload(nspSet) + let namespace = getNameFromPayload(nspGroup) namespaces.push(namespace) // standard without login // the stock version should not have a namespace diff --git a/packages/@jsonql/ws/src/core/extract-ws-payload.js b/packages/@jsonql/ws/src/core/extract-ws-payload.js deleted file mode 100644 index 037eae75..00000000 --- a/packages/@jsonql/ws/src/core/extract-ws-payload.js +++ /dev/null @@ -1,43 +0,0 @@ -// take the ws reply data for use -import { WS_EVT_NAME, WS_DATA_NAME, WS_REPLY_TYPE } from 'jsonql-constants' -import { isString } from 'jsonql-params-validator' -import { isObjectHasKey } from 'jsonql-utils/module' -import { JsonqlError } from 'jsonql-errors' - -const keys = [ WS_REPLY_TYPE, WS_EVT_NAME, WS_DATA_NAME ] - -/** - * Check if this is a ws reply type - * @param {object} payload should be string when reply but could be transformed - * @return {boolean} true is OK - */ -const isWsReply = payload => { - const { data } = payload - if (data) { - let result = keys.filter(key => isObjectHasKey(data, key)) - return (result.length === keys.length) ? data : false - } - return false -} - -/** - * Extract the payload from the ws message - * @param {object} payload This is the entire ws Event Object - * @return {object} false on failed - */ -const extractWsPayload = payload => { - const { data } = payload; - let json = isString(data) ? JSON.parse(data) : data - let fdata; - if ((fdata = isWsReply(json)) !== false) { - return { - resolverName: fdata[WS_EVT_NAME], - data: fdata[WS_DATA_NAME], - type: fdata[WS_REPLY_TYPE] - } - } - throw new JsonqlError('payload can not be decoded', payload) -} - -// export it -export default extractWsPayload diff --git a/packages/@jsonql/ws/src/core/generate-ws-client.js b/packages/@jsonql/ws/src/core/generate-ws-client.js new file mode 100644 index 00000000..de18e431 --- /dev/null +++ b/packages/@jsonql/ws/src/core/generate-ws-client.js @@ -0,0 +1,14 @@ +// take out from module, doesn't make sense to be there +import { wsClientCoreAction } from './modules' +/** + * Take the already checked options (using part of export here) + * then generate the ws client + * @param {function} wsClientResolver configuration + * @return {function} take config return the promise resolve the ws client + */ +export function generateWsClient(wsClientResolver) { + + return (config) => Promise + .resolve(config) + .then(opts => wsClientCoreAction(wsClientResolver, opts)) +} \ No newline at end of file diff --git a/packages/@jsonql/ws/src/core/modules.js b/packages/@jsonql/ws/src/core/modules.js index 2ce4955a..43e3015e 100644 --- a/packages/@jsonql/ws/src/core/modules.js +++ b/packages/@jsonql/ws/src/core/modules.js @@ -11,11 +11,7 @@ import { createNspAuthClient, clientEventHandler, clearMainEmitEvt -} from '../../../../ws-client-core/index' -// 'jsonql-ws-client-core' - - -// 'jsonql-ws-client-core' +} from '../../../../ws-client-core/index' // 'jsonql-ws-client-core' // this module options import { wsClientAppProps, @@ -25,17 +21,7 @@ import { const jsonqlWsClientAppProps = Object.assign({}, wsCoreDefaultOptions, wsClientAppProps) const jsonqlWsConstProps = Object.assign({}, wsCoreConstProps, wsClientConstProps) -/** - * Take the already checked options (using part of export here) - * then generate the ws client - * @param {function} wsClientResolver configuration - * @return {function} take config return the promise resolve the ws client - */ -function generateWsClient(wsClientResolver) { - return (config) => Promise - .resolve(config) - .then(opts => wsClientCoreAction(wsClientResolver, opts)) -} + // export export { @@ -44,13 +30,11 @@ export { createNspClient, createNspAuthClient, clientEventHandler, // <-- @BUG ? - // comment them out for now they are not in use - // triggerNamespacesOnError, - // disconnect - clearMainEmitEvt, + clearMainEmitEvt, + wsClientCore, + wsClientCoreAction, + // props jsonqlWsClientAppProps, - jsonqlWsConstProps, - generateWsClient, - wsClientCore + jsonqlWsConstProps } \ No newline at end of file diff --git a/packages/@jsonql/ws/src/core/socket-event-handler.js b/packages/@jsonql/ws/src/core/socket-event-handler.js index 34bd788f..1a78b184 100644 --- a/packages/@jsonql/ws/src/core/socket-event-handler.js +++ b/packages/@jsonql/ws/src/core/socket-event-handler.js @@ -47,8 +47,8 @@ const errorTypeHandler = (ee, namespace, resolverName, json, ON_ERROR_FN_NAME) = * @return {object} promise resolve after the onopen event */ export function socketEventHandler(namespace, ws, ee, isPrivate, opts) { - // const { log } = opts - const log = (...args) => Reflect.apply(console.info, console, ['[socketEventHandler]'].concat(args)) + const { log } = opts + // const log = (...args) => Reflect.apply(console.info, console, ['[socketEventHandler]'].concat(args)) log(`log test, isPrivate:`, isPrivate) @@ -68,7 +68,6 @@ export function socketEventHandler(namespace, ws, ee, isPrivate, opts) { createEvt(namespace, EMIT_REPLY_TYPE), function wsMainOnEvtHandler(resolverName, args) { - const payload = createQueryStr(resolverName, args) log('calling server', resolverName, args, payload) diff --git a/packages/@jsonql/ws/src/ws-client-resolver.js b/packages/@jsonql/ws/src/core/ws-client-resolver.js similarity index 80% rename from packages/@jsonql/ws/src/ws-client-resolver.js rename to packages/@jsonql/ws/src/core/ws-client-resolver.js index 6cb31c68..008e765b 100644 --- a/packages/@jsonql/ws/src/ws-client-resolver.js +++ b/packages/@jsonql/ws/src/core/ws-client-resolver.js @@ -1,8 +1,8 @@ // this will be the news style interface that will pass to the jsonql-ws-client // then return a function for accepting an opts to generate the final // client api -import WebSocket from './core/ws' -import { createClientBinding } from './core/create-client-binding' +import WebSocket from './ws' +import { createClientBinding } from './create-client-binding' /** * @param {object} opts configuration diff --git a/packages/@jsonql/ws/src/node/stream-api.js b/packages/@jsonql/ws/src/node/stream-api.js index 0cea2edc..dfe0e166 100644 --- a/packages/@jsonql/ws/src/node/stream-api.js +++ b/packages/@jsonql/ws/src/node/stream-api.js @@ -1,4 +1,4 @@ -// example +// @TODO NOT IN USE example function createNodeStream(ws) { const duplex = WebSocket.createWebSocketStream(ws, { encoding: 'utf8' }) diff --git a/packages/koa/src/middlewares/auth-middleware.js b/packages/koa/src/middlewares/auth-middleware.js index 6e8e3b3d..77e8d119 100644 --- a/packages/koa/src/middlewares/auth-middleware.js +++ b/packages/koa/src/middlewares/auth-middleware.js @@ -26,7 +26,7 @@ export default function authMiddleware(config) { // return middleware return async function(ctx, next) { // we should only care if there is api call involved - const { isReq, contract } = ctx.state.jsonql; + const { isReq, contract } = ctx.state.jsonql if (isReq && config.enableAuth) { try { const token = authHeaderParser(ctx) @@ -39,7 +39,7 @@ export default function authMiddleware(config) { if (isNotEmpty(userdata) && isObject(userdata)) { // here we add the userData to the global // @TODO need more testing to see if this is going to work or not - ctx.state.jsonql.userdata = userdata; + ctx.state.jsonql.userdata = userdata // debug('get user data result', userdata) await next() } else { -- Gitee From 88c45e346cca37cdff0988ddcc3330ac143f484a Mon Sep 17 00:00:00 2001 From: joelchu Date: Fri, 13 Mar 2020 10:44:42 +0800 Subject: [PATCH 08/45] Break up the create-nsp into several files and put in its own folder --- packages/@jsonql/ws/index.js | 2 +- .../ws/src/core/create-client-binding.js | 2 +- packages/@jsonql/ws/src/core/create-nsp.js | 111 ------------------ .../src/core/create-nsp/create-nsp-action.js | 45 +++++++ .../ws/src/core/create-nsp/create-nsp.js | 33 ++++++ .../@jsonql/ws/src/core/create-nsp/index.js | 4 + .../core/create-nsp/login-event-handler.js | 32 +++++ packages/@jsonql/ws/src/core/modules.js | 6 +- 8 files changed, 120 insertions(+), 115 deletions(-) delete mode 100644 packages/@jsonql/ws/src/core/create-nsp.js create mode 100644 packages/@jsonql/ws/src/core/create-nsp/create-nsp-action.js create mode 100644 packages/@jsonql/ws/src/core/create-nsp/create-nsp.js create mode 100644 packages/@jsonql/ws/src/core/create-nsp/index.js create mode 100644 packages/@jsonql/ws/src/core/create-nsp/login-event-handler.js diff --git a/packages/@jsonql/ws/index.js b/packages/@jsonql/ws/index.js index 48626975..04ee930a 100644 --- a/packages/@jsonql/ws/index.js +++ b/packages/@jsonql/ws/index.js @@ -5,7 +5,7 @@ import { jsonqlWsConstProps, wsClientCore } from './src/core/modules' -import wsClientResolver from './src/ws-client-resolver' +import wsClientResolver from './src/core/ws-client-resolver' // export back the function and that's it export default function wsBrowserClient(config = {}, constProps = {}) { diff --git a/packages/@jsonql/ws/src/core/create-client-binding.js b/packages/@jsonql/ws/src/core/create-client-binding.js index a5bf72bc..4a4f1375 100644 --- a/packages/@jsonql/ws/src/core/create-client-binding.js +++ b/packages/@jsonql/ws/src/core/create-client-binding.js @@ -1,7 +1,7 @@ // share method to create the wsClientResolver import { createFrameworkDepClient } from './create-framework-dep-client' -import { createNsp } from './create-nsp' +import { createNsp } from './create-nsp/create-nsp' /** * Create the framework <---> jsonql client binding diff --git a/packages/@jsonql/ws/src/core/create-nsp.js b/packages/@jsonql/ws/src/core/create-nsp.js deleted file mode 100644 index 7a2cf045..00000000 --- a/packages/@jsonql/ws/src/core/create-nsp.js +++ /dev/null @@ -1,111 +0,0 @@ -// actually binding the event client to the socket client -import { LOGIN_EVENT_NAME } from 'jsonql-constants' -import { - getNameFromPayload, - getNamespaceInOrder -} from 'jsonql-utils/module' -// internal -import { - createNspClient, - createNspAuthClient, - clientEventHandler, // <-- @BUG ? - // comment them out for now they are not in use - // triggerNamespacesOnError, - // disconnect - clearMainEmitEvt -} from './modules' -import { socketEventHandler } from './socket-event-handler' - -/** - * Because the nsps can be throw away so it doesn't matter the scope - * this will get reuse again - * @param {object} opts configuration - * @param {object} nspMap from contract - * @param {string|null} token whether we have the token at run time - * @return {object} nsps namespace with namespace as key - */ -const createNspAction = function(opts, nspMap, token) { - const { log } = opts - let { nspGroup, publicNamespace } = nspMap - let loginRequired = false - let namespaces = [] - let nsps = {} - // first we need to binding all the events handler - if (opts.enableAuth) { // && opts.useJwt - loginRequired = true // just saying we need to listen to login event - namespaces = getNamespaceInOrder(nspGroup, publicNamespace) - nsps = namespaces.map((namespace, i) => { - if (i === 0) { - if (token) { - opts.token = token - log('create createNspAuthClient at run time') - return {[namespace]: createNspAuthClient(namespace, opts)} - } - return {[namespace]: false} - } - return {[namespace]: createNspClient(namespace, opts)} - }).reduce((first, next) => Object.assign(first, next), {}) - } else { - let namespace = getNameFromPayload(nspGroup) - namespaces.push(namespace) - // standard without login - // the stock version should not have a namespace - nsps[namespace] = createNspClient(false, opts) - } - // return - return { nsps, namespaces, loginRequired } -} - -/** - * create a login event handler - * @param {*} ee - * @param {*} namespaces - * @param {*} nspMap - * @param {*} opts - */ -function loginEventHandler(ee, namespaces, nspMap, opts) { - const { log } = opts - ee.$only(LOGIN_EVENT_NAME, function loginEventHandlerCallback(tokenLater) { - log('createClient LOGIN_EVENT_NAME $only handler') - // @BUG 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 - // disconnect(nsps, JS_WS_NAME) - - // @TODO should we trigger error on this one? - // triggerNamespacesOnError(ee, namespaces, LOGIN_EVENT_NAME) - clearMainEmitEvt(ee, namespaces) - // console.log('LOGIN_EVENT_NAME', token) - const newNsps = createNspAction(opts, nspMap, tokenLater) - // rebind it - Reflect.apply( - clientEventHandler, // @NOTE is this the problem that cause the hang up? - null, - args.concat([newNsps.namespaces, newNsps.nsps]) - ) - }) -} - -/** - * 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 - * @return {object} what comes in what goes out - */ -export function createNsp(opts, nspMap, ee) { - // arguments for clientEventHandler - const args = [opts, nspMap, ee, socketEventHandler] - // now create the nsps - const { token, log } = opts - const { nsps, namespaces, loginRequired } = createNspAction(opts, nspMap, token) - // binding the listeners - and it will listen to LOGOUT event - // to unbind itself, and the above call will bind it again - Reflect.apply(clientEventHandler, null, args.concat([namespaces, nsps])) - // setup listener - if (loginRequired) { - loginEventHandler(ee, namespaces, nspMap, opts) - } - // return what input - return { opts, nspMap, ee } -} diff --git a/packages/@jsonql/ws/src/core/create-nsp/create-nsp-action.js b/packages/@jsonql/ws/src/core/create-nsp/create-nsp-action.js new file mode 100644 index 00000000..da97a57f --- /dev/null +++ b/packages/@jsonql/ws/src/core/create-nsp/create-nsp-action.js @@ -0,0 +1,45 @@ + +import { + createNspClient, + createNspAuthClient, +} from '../modules' + +/** + * Because the nsps can be throw away so it doesn't matter the scope + * this will get reuse again + * @param {object} opts configuration + * @param {object} nspMap from contract + * @param {string|null} token whether we have the token at run time + * @return {object} nsps namespace with namespace as key + */ +const createNspAction = function(opts, nspMap, token) { + const { log } = opts + let { nspGroup, publicNamespace, namespaces } = nspMap + + return { + nsps: (() => { + // first we need to binding all the events handler + if (opts.enableAuth) { // && opts.useJwt + + return namespaces.map((namespace, i) => { + if (i === 0) { + if (token) { + opts.token = token + log('create createNspAuthClient at run time') + return {[namespace]: createNspAuthClient(namespace, opts)} + } + return {[namespace]: false} + } + return {[namespace]: createNspClient(namespace, opts)} + }).reduce((first, next) => Object.assign(first, next), {}) + } + + // standard without login + return { + [publicNamespace]: createNspClient(false, opts) + } + })() + } +} + +export { createNspAction } \ 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 new file mode 100644 index 00000000..d99a190d --- /dev/null +++ b/packages/@jsonql/ws/src/core/create-nsp/create-nsp.js @@ -0,0 +1,33 @@ +// actually binding the event client to the socket client + +import { clientEventHandler } from '../modules' +import { createNspAction } from './create-nsp-action' +import { loginEventHandler } from './login-event-handler' +import { socketEventHandler } from '../socket-event-handler' + +/** + * 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 + * @return {object} what comes in what goes out + */ +function createNsp(opts, nspMap, ee) { + // arguments for clientEventHandler + const args = [opts, nspMap, ee, socketEventHandler] + // now create the nsps + const { namespaces } = nspMap + const { token } = opts + const { nsps } = createNspAction(opts, nspMap, token) + // binding the listeners - and it will listen to LOGOUT event + // to unbind itself, and the above call will bind it again + Reflect.apply(clientEventHandler, null, args.concat([namespaces, nsps])) + // setup listener for the login event + if (opts.enableAuth) { + loginEventHandler(ee, namespaces, nspMap, opts) + } + // return what input + return { opts, nspMap, ee } +} + +export { createNsp } \ No newline at end of file diff --git a/packages/@jsonql/ws/src/core/create-nsp/index.js b/packages/@jsonql/ws/src/core/create-nsp/index.js new file mode 100644 index 00000000..2c5709fc --- /dev/null +++ b/packages/@jsonql/ws/src/core/create-nsp/index.js @@ -0,0 +1,4 @@ +// breaking up the create-nsp.js file +// then regroup them back together here +import { createNsp } from './create-nsp' +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-handler.js new file mode 100644 index 00000000..07d0e7ba --- /dev/null +++ b/packages/@jsonql/ws/src/core/create-nsp/login-event-handler.js @@ -0,0 +1,32 @@ +// @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 +import { LOGIN_EVENT_NAME } from 'jsonql-constants' +import { clearMainEmitEvt } from '../modules'} +/** + * create a login event handler + * @param {object} opts configurations + * @param {object} nspMap contain all the required info + * @param {object} ee event emitter + * @return {void} + */ +export function loginEventHandler(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) + // 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, + args.concat([newNsps.namespaces, newNsps.nsps]) + ) + }) +} \ No newline at end of file diff --git a/packages/@jsonql/ws/src/core/modules.js b/packages/@jsonql/ws/src/core/modules.js index 43e3015e..7cb47965 100644 --- a/packages/@jsonql/ws/src/core/modules.js +++ b/packages/@jsonql/ws/src/core/modules.js @@ -25,10 +25,12 @@ const jsonqlWsConstProps = Object.assign({}, wsCoreConstProps, wsClientConstProp // export export { - fixWss, - checkSocketClientType, createNspClient, createNspAuthClient, + + fixWss, + checkSocketClientType, + clientEventHandler, // <-- @BUG ? clearMainEmitEvt, -- Gitee From 6a8df793ab726738622b029f832a76fa2402e8fa Mon Sep 17 00:00:00 2001 From: joelchu Date: Fri, 13 Mar 2020 11:41:02 +0800 Subject: [PATCH 09/45] clean up the import before continue --- .../ws/src/core/create-nsp/create-nsp-action.js | 13 +++++++++---- .../@jsonql/ws/src/core/create-nsp/create-nsp.js | 1 - packages/@jsonql/ws/src/core/modules.js | 12 +++++++----- 3 files changed, 16 insertions(+), 10 deletions(-) diff --git a/packages/@jsonql/ws/src/core/create-nsp/create-nsp-action.js b/packages/@jsonql/ws/src/core/create-nsp/create-nsp-action.js index da97a57f..efa53b15 100644 --- a/packages/@jsonql/ws/src/core/create-nsp/create-nsp-action.js +++ b/packages/@jsonql/ws/src/core/create-nsp/create-nsp-action.js @@ -1,4 +1,3 @@ - import { createNspClient, createNspAuthClient, @@ -26,11 +25,17 @@ const createNspAction = function(opts, nspMap, token) { if (token) { opts.token = token log('create createNspAuthClient at run time') - return {[namespace]: createNspAuthClient(namespace, opts)} + return { + [namespace]: createNspAuthClient(namespace, opts) + } } - return {[namespace]: false} + return { + [namespace]: false + } + } + return { + [namespace]: createNspClient(namespace, opts) } - return {[namespace]: createNspClient(namespace, opts)} }).reduce((first, next) => Object.assign(first, next), {}) } 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 d99a190d..0606ee19 100644 --- a/packages/@jsonql/ws/src/core/create-nsp/create-nsp.js +++ b/packages/@jsonql/ws/src/core/create-nsp/create-nsp.js @@ -1,5 +1,4 @@ // actually binding the event client to the socket client - import { clientEventHandler } from '../modules' import { createNspAction } from './create-nsp-action' import { loginEventHandler } from './login-event-handler' diff --git a/packages/@jsonql/ws/src/core/modules.js b/packages/@jsonql/ws/src/core/modules.js index 7cb47965..357ddb09 100644 --- a/packages/@jsonql/ws/src/core/modules.js +++ b/packages/@jsonql/ws/src/core/modules.js @@ -1,16 +1,18 @@ // We keep all the import from jsonql-ws-client-core in place // if we need to switch then just switch in one place +import { extractWsPayload } from 'jsonql-utils' import { fixWss, checkSocketClientType, - wsCoreDefaultOptions, - wsCoreConstProps, wsClientCoreAction, wsClientCore, createNspClient, createNspAuthClient, clientEventHandler, - clearMainEmitEvt + clearMainEmitEvt, + // props + wsCoreDefaultOptions, + wsCoreConstProps } from '../../../../ws-client-core/index' // 'jsonql-ws-client-core' // this module options import { @@ -21,10 +23,10 @@ import { const jsonqlWsClientAppProps = Object.assign({}, wsCoreDefaultOptions, wsClientAppProps) const jsonqlWsConstProps = Object.assign({}, wsCoreConstProps, wsClientConstProps) - - // export export { + extractWsPayload, + createNspClient, createNspAuthClient, -- Gitee From 663034b7a63122326091cd7bebfb889951d7fad5 Mon Sep 17 00:00:00 2001 From: joelchu Date: Fri, 13 Mar 2020 12:07:50 +0800 Subject: [PATCH 10/45] this editor is stupid piece of shit --- .../{ => create-jsonql-ws-client}/disconnect.js | 0 .../index.js} | 8 +++++--- .../socket-event-handler.js | 0 .../bind-framework-to-jsonql.js} | 17 +++++++++-------- .../src/core/create-websocket-client/index.js | 1 + .../init-websocket-client.js} | 6 +++--- .../ws/src/core/create-ws-client/index.js | 15 +++++++++++++++ .../ws/src/node/node-ws-client-resolver.js | 2 +- 8 files changed, 34 insertions(+), 15 deletions(-) rename packages/@jsonql/ws/src/core/{ => create-jsonql-ws-client}/disconnect.js (100%) rename packages/@jsonql/ws/src/core/{ws-client-resolver.js => create-jsonql-ws-client/index.js} (63%) rename packages/@jsonql/ws/src/core/{ => create-jsonql-ws-client}/socket-event-handler.js (100%) rename packages/@jsonql/ws/src/core/{create-client-binding.js => create-websocket-client/bind-framework-to-jsonql.js} (67%) create mode 100644 packages/@jsonql/ws/src/core/create-websocket-client/index.js rename packages/@jsonql/ws/src/core/{create-framework-dep-client.js => create-websocket-client/init-websocket-client.js} (89%) create mode 100644 packages/@jsonql/ws/src/core/create-ws-client/index.js diff --git a/packages/@jsonql/ws/src/core/disconnect.js b/packages/@jsonql/ws/src/core/create-jsonql-ws-client/disconnect.js similarity index 100% rename from packages/@jsonql/ws/src/core/disconnect.js rename to packages/@jsonql/ws/src/core/create-jsonql-ws-client/disconnect.js diff --git a/packages/@jsonql/ws/src/core/ws-client-resolver.js b/packages/@jsonql/ws/src/core/create-jsonql-ws-client/index.js similarity index 63% rename from packages/@jsonql/ws/src/core/ws-client-resolver.js rename to packages/@jsonql/ws/src/core/create-jsonql-ws-client/index.js index 008e765b..32c19a26 100644 --- a/packages/@jsonql/ws/src/core/ws-client-resolver.js +++ b/packages/@jsonql/ws/src/core/create-jsonql-ws-client/index.js @@ -1,8 +1,10 @@ +// rename from ws-client-resolver to create-ws-client + // this will be the news style interface that will pass to the jsonql-ws-client // then return a function for accepting an opts to generate the final // client api -import WebSocket from './ws' -import { createClientBinding } from './create-client-binding' +import WebSocket from '../ws' +import { createClientBinding } from '../create-websocket-client/create-client-binding' /** * @param {object} opts configuration @@ -10,4 +12,4 @@ import { createClientBinding } from './create-client-binding' * @param {object} ee instance of the eventEmitter * @return {object} passing the same 3 input out with additional in the opts */ -export default createClientBinding(WebSocket) +export default createClientBinding(WebSocket) \ No newline at end of file diff --git a/packages/@jsonql/ws/src/core/socket-event-handler.js b/packages/@jsonql/ws/src/core/create-jsonql-ws-client/socket-event-handler.js similarity index 100% rename from packages/@jsonql/ws/src/core/socket-event-handler.js rename to packages/@jsonql/ws/src/core/create-jsonql-ws-client/socket-event-handler.js diff --git a/packages/@jsonql/ws/src/core/create-client-binding.js b/packages/@jsonql/ws/src/core/create-websocket-client/bind-framework-to-jsonql.js similarity index 67% rename from packages/@jsonql/ws/src/core/create-client-binding.js rename to packages/@jsonql/ws/src/core/create-websocket-client/bind-framework-to-jsonql.js index 4a4f1375..51c24639 100644 --- a/packages/@jsonql/ws/src/core/create-client-binding.js +++ b/packages/@jsonql/ws/src/core/create-websocket-client/bind-framework-to-jsonql.js @@ -1,16 +1,17 @@ // share method to create the wsClientResolver -import { createFrameworkDepClient } from './create-framework-dep-client' -import { createNsp } from './create-nsp/create-nsp' +import { initWebSocketClient } from './init-websocket-client' +import { createNsp } from '../create-nsp' /** * Create the framework <---> jsonql client binding * @param {object} frameworkModule the different WebSocket module * @return {function} the wsClientResolver */ -function createClientBinding(frameworkModule) { - const client = createFrameworkDepClient(frameworkModule) - const authClient = createFrameworkDepClient(frameworkModule, true) +function bindFrameworkToJsonql(frameworkModule) { + + const publicClient = initWebSocketClient(frameworkModule) + const privateClient = initWebSocketClient(frameworkModule, true) /** * wsClientResolver @@ -20,8 +21,8 @@ function createClientBinding(frameworkModule) { * @return {object} passing the same 3 input out with additional in the opts */ return function createClientBindingAction(opts, nspMap, ee) { - opts.nspClient = client - opts.nspAuthClient = authClient + opts.nspClient = publicClient + opts.nspAuthClient = privateClient // @1.0.7 remove later once everything fixed const { log } = opts if (log && typeof log === 'function') { @@ -33,4 +34,4 @@ function createClientBinding(frameworkModule) { } } -export { createClientBinding } \ No newline at end of file +export { bindFrameworkToJsonql } \ No newline at end of file diff --git a/packages/@jsonql/ws/src/core/create-websocket-client/index.js b/packages/@jsonql/ws/src/core/create-websocket-client/index.js new file mode 100644 index 00000000..dff71ef0 --- /dev/null +++ b/packages/@jsonql/ws/src/core/create-websocket-client/index.js @@ -0,0 +1 @@ +import { bindFrameworkToJsonqlClient } from './init-websocket-client' \ No newline at end of file diff --git a/packages/@jsonql/ws/src/core/create-framework-dep-client.js b/packages/@jsonql/ws/src/core/create-websocket-client/init-websocket-client.js similarity index 89% rename from packages/@jsonql/ws/src/core/create-framework-dep-client.js rename to packages/@jsonql/ws/src/core/create-websocket-client/init-websocket-client.js index 6aad914a..16ced255 100644 --- a/packages/@jsonql/ws/src/core/create-framework-dep-client.js +++ b/packages/@jsonql/ws/src/core/create-websocket-client/init-websocket-client.js @@ -1,7 +1,7 @@ // pass the different type of ws to generate the client // this is where the framework specific code get injected import { TOKEN_PARAM_NAME } from 'jsonql-constants' -import { fixWss } from './modules' +import { fixWss } from '../modules' /** * The bug was in the wsOptions where ws don't need it but socket.io do @@ -9,7 +9,7 @@ import { fixWss } from './modules' * @param {object} WebSocket the client or node version of ws * @param {boolean} auth if it's auth then 3 param or just one */ -function createFrameworkDepClient(WebSocket, auth = false) { +function initWebSocketClient(WebSocket, auth = false) { if (auth === false) { return function createWsClientHandler(url) { return new WebSocket(fixWss(url)) @@ -35,4 +35,4 @@ function createFrameworkDepClient(WebSocket, auth = false) { } } -export { createFrameworkDepClient } \ No newline at end of file +export { initWebSocketClient } \ No newline at end of file diff --git a/packages/@jsonql/ws/src/core/create-ws-client/index.js b/packages/@jsonql/ws/src/core/create-ws-client/index.js new file mode 100644 index 00000000..a66045ce --- /dev/null +++ b/packages/@jsonql/ws/src/core/create-ws-client/index.js @@ -0,0 +1,15 @@ +// rename from ws-client-resolver to create-ws-client + +// this will be the news style interface that will pass to the jsonql-ws-client +// then return a function for accepting an opts to generate the final +// client api +import WebSocket from '../ws' +import { createClientBinding } from '../create-websocket-client/bind-framework-to-jsonql' + +/** + * @param {object} opts configuration + * @param {object} nspMap from the contract + * @param {object} ee instance of the eventEmitter + * @return {object} passing the same 3 input out with additional in the opts + */ +export default createClientBinding(WebSocket) \ No newline at end of file diff --git a/packages/@jsonql/ws/src/node/node-ws-client-resolver.js b/packages/@jsonql/ws/src/node/node-ws-client-resolver.js index e7453ff2..b5ba1bb6 100644 --- a/packages/@jsonql/ws/src/node/node-ws-client-resolver.js +++ b/packages/@jsonql/ws/src/node/node-ws-client-resolver.js @@ -2,7 +2,7 @@ // then return a function for accepting an opts to generate the final // client api import WebSocket from 'ws' -import { createClientBinding } from '../core/create-client-binding' +import { createClientBinding } from '../core/create-websocket-client/create-client-binding' /** * @param {object} opts configuration -- Gitee From 706a343a65bc694befa9772b8d3e948b6ba47d58 Mon Sep 17 00:00:00 2001 From: joelchu Date: Fri, 13 Mar 2020 12:31:04 +0800 Subject: [PATCH 11/45] rename it once again and it should make sense now --- packages/@jsonql/ws/src/core/create-jsonql-ws-client/index.js | 2 +- .../bind-framework-to-jsonql.js | 0 .../@jsonql/ws/src/core/create-websocket-binding/index.js | 3 +++ .../init-websocket-client.js | 0 packages/@jsonql/ws/src/core/create-websocket-client/index.js | 1 - packages/@jsonql/ws/src/core/create-ws-client/index.js | 4 ++-- 6 files changed, 6 insertions(+), 4 deletions(-) rename packages/@jsonql/ws/src/core/{create-websocket-client => create-websocket-binding}/bind-framework-to-jsonql.js (100%) create mode 100644 packages/@jsonql/ws/src/core/create-websocket-binding/index.js rename packages/@jsonql/ws/src/core/{create-websocket-client => create-websocket-binding}/init-websocket-client.js (100%) delete mode 100644 packages/@jsonql/ws/src/core/create-websocket-client/index.js diff --git a/packages/@jsonql/ws/src/core/create-jsonql-ws-client/index.js b/packages/@jsonql/ws/src/core/create-jsonql-ws-client/index.js index 32c19a26..b5609c11 100644 --- a/packages/@jsonql/ws/src/core/create-jsonql-ws-client/index.js +++ b/packages/@jsonql/ws/src/core/create-jsonql-ws-client/index.js @@ -4,7 +4,7 @@ // then return a function for accepting an opts to generate the final // client api import WebSocket from '../ws' -import { createClientBinding } from '../create-websocket-client/create-client-binding' +import createWebSocketBinding from '../create-websocket-binding' /** * @param {object} opts configuration diff --git a/packages/@jsonql/ws/src/core/create-websocket-client/bind-framework-to-jsonql.js b/packages/@jsonql/ws/src/core/create-websocket-binding/bind-framework-to-jsonql.js similarity index 100% rename from packages/@jsonql/ws/src/core/create-websocket-client/bind-framework-to-jsonql.js rename to packages/@jsonql/ws/src/core/create-websocket-binding/bind-framework-to-jsonql.js diff --git a/packages/@jsonql/ws/src/core/create-websocket-binding/index.js b/packages/@jsonql/ws/src/core/create-websocket-binding/index.js new file mode 100644 index 00000000..d1ab0b80 --- /dev/null +++ b/packages/@jsonql/ws/src/core/create-websocket-binding/index.js @@ -0,0 +1,3 @@ +import { bindFrameworkToJsonql } from './bind-framework-to-jsonql' + +export default bindFrameworkToJsonql \ No newline at end of file diff --git a/packages/@jsonql/ws/src/core/create-websocket-client/init-websocket-client.js b/packages/@jsonql/ws/src/core/create-websocket-binding/init-websocket-client.js similarity index 100% rename from packages/@jsonql/ws/src/core/create-websocket-client/init-websocket-client.js rename to packages/@jsonql/ws/src/core/create-websocket-binding/init-websocket-client.js diff --git a/packages/@jsonql/ws/src/core/create-websocket-client/index.js b/packages/@jsonql/ws/src/core/create-websocket-client/index.js deleted file mode 100644 index dff71ef0..00000000 --- a/packages/@jsonql/ws/src/core/create-websocket-client/index.js +++ /dev/null @@ -1 +0,0 @@ -import { bindFrameworkToJsonqlClient } from './init-websocket-client' \ No newline at end of file diff --git a/packages/@jsonql/ws/src/core/create-ws-client/index.js b/packages/@jsonql/ws/src/core/create-ws-client/index.js index a66045ce..4215b797 100644 --- a/packages/@jsonql/ws/src/core/create-ws-client/index.js +++ b/packages/@jsonql/ws/src/core/create-ws-client/index.js @@ -4,7 +4,7 @@ // then return a function for accepting an opts to generate the final // client api import WebSocket from '../ws' -import { createClientBinding } from '../create-websocket-client/bind-framework-to-jsonql' +import createWebcoketBinding from '../create-websocket-binding' /** * @param {object} opts configuration @@ -12,4 +12,4 @@ import { createClientBinding } from '../create-websocket-client/bind-framework-t * @param {object} ee instance of the eventEmitter * @return {object} passing the same 3 input out with additional in the opts */ -export default createClientBinding(WebSocket) \ No newline at end of file +export default createWebcoketBinding(WebSocket) \ No newline at end of file -- Gitee From e2fc34124d1fde0edfcead16f2b2c76fa0cb69a9 Mon Sep 17 00:00:00 2001 From: joelchu Date: Fri, 13 Mar 2020 12:34:26 +0800 Subject: [PATCH 12/45] move the socket-event-handler into the create-nsp because they are deps --- .../@jsonql/ws/src/core/create-nsp/create-nsp.js | 2 +- packages/@jsonql/ws/src/core/create-nsp/index.js | 3 ++- .../socket-event-handler.js | 8 +++++--- .../bind-framework-to-jsonql.js | 2 +- .../@jsonql/ws/src/core/create-ws-client/index.js | 15 --------------- packages/@jsonql/ws/src/core/modules.js | 4 +--- 6 files changed, 10 insertions(+), 24 deletions(-) rename packages/@jsonql/ws/src/core/{create-jsonql-ws-client => create-nsp}/socket-event-handler.js (97%) delete mode 100644 packages/@jsonql/ws/src/core/create-ws-client/index.js 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 0606ee19..cdd9c8e8 100644 --- a/packages/@jsonql/ws/src/core/create-nsp/create-nsp.js +++ b/packages/@jsonql/ws/src/core/create-nsp/create-nsp.js @@ -2,7 +2,7 @@ import { clientEventHandler } from '../modules' import { createNspAction } from './create-nsp-action' import { loginEventHandler } from './login-event-handler' -import { socketEventHandler } from '../socket-event-handler' +import { socketEventHandler } from './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/index.js b/packages/@jsonql/ws/src/core/create-nsp/index.js index 2c5709fc..076f18c4 100644 --- a/packages/@jsonql/ws/src/core/create-nsp/index.js +++ b/packages/@jsonql/ws/src/core/create-nsp/index.js @@ -1,4 +1,5 @@ // breaking up the create-nsp.js file // then regroup them back together here import { createNsp } from './create-nsp' -export { createNsp } + +export default createNsp diff --git a/packages/@jsonql/ws/src/core/create-jsonql-ws-client/socket-event-handler.js b/packages/@jsonql/ws/src/core/create-nsp/socket-event-handler.js similarity index 97% rename from packages/@jsonql/ws/src/core/create-jsonql-ws-client/socket-event-handler.js rename to packages/@jsonql/ws/src/core/create-nsp/socket-event-handler.js index 1a78b184..7b36f780 100644 --- a/packages/@jsonql/ws/src/core/create-jsonql-ws-client/socket-event-handler.js +++ b/packages/@jsonql/ws/src/core/create-nsp/socket-event-handler.js @@ -11,9 +11,11 @@ import { ON_READY_FN_NAME, ON_LOGIN_FN_NAME } from 'jsonql-constants' -import { createQueryStr, createEvt } from 'jsonql-utils/module' -import extractWsPayload from './extract-ws-payload' - +import { + createQueryStr, + createEvt, + extractWsPayload +} from 'jsonql-utils/module' /** * in some edge case we might not even have a resolverName, then diff --git a/packages/@jsonql/ws/src/core/create-websocket-binding/bind-framework-to-jsonql.js b/packages/@jsonql/ws/src/core/create-websocket-binding/bind-framework-to-jsonql.js index 51c24639..bcd4e36c 100644 --- a/packages/@jsonql/ws/src/core/create-websocket-binding/bind-framework-to-jsonql.js +++ b/packages/@jsonql/ws/src/core/create-websocket-binding/bind-framework-to-jsonql.js @@ -1,7 +1,7 @@ // share method to create the wsClientResolver import { initWebSocketClient } from './init-websocket-client' -import { createNsp } from '../create-nsp' +import createNsp from '../create-nsp' /** * Create the framework <---> jsonql client binding diff --git a/packages/@jsonql/ws/src/core/create-ws-client/index.js b/packages/@jsonql/ws/src/core/create-ws-client/index.js deleted file mode 100644 index 4215b797..00000000 --- a/packages/@jsonql/ws/src/core/create-ws-client/index.js +++ /dev/null @@ -1,15 +0,0 @@ -// rename from ws-client-resolver to create-ws-client - -// this will be the news style interface that will pass to the jsonql-ws-client -// then return a function for accepting an opts to generate the final -// client api -import WebSocket from '../ws' -import createWebcoketBinding from '../create-websocket-binding' - -/** - * @param {object} opts configuration - * @param {object} nspMap from the contract - * @param {object} ee instance of the eventEmitter - * @return {object} passing the same 3 input out with additional in the opts - */ -export default createWebcoketBinding(WebSocket) \ No newline at end of file diff --git a/packages/@jsonql/ws/src/core/modules.js b/packages/@jsonql/ws/src/core/modules.js index 357ddb09..fe3d9e21 100644 --- a/packages/@jsonql/ws/src/core/modules.js +++ b/packages/@jsonql/ws/src/core/modules.js @@ -1,6 +1,5 @@ // We keep all the import from jsonql-ws-client-core in place // if we need to switch then just switch in one place -import { extractWsPayload } from 'jsonql-utils' import { fixWss, checkSocketClientType, @@ -25,8 +24,7 @@ const jsonqlWsConstProps = Object.assign({}, wsCoreConstProps, wsClientConstProp // export export { - extractWsPayload, - + createNspClient, createNspAuthClient, -- Gitee From ce0e63c63f5516d5e9c2af594cea6cbba7cc4c3b Mon Sep 17 00:00:00 2001 From: joelchu Date: Fri, 13 Mar 2020 12:45:28 +0800 Subject: [PATCH 13/45] update the handle-socket-event internal and I think I found the cause of the bug --- .../ws/src/core/create-nsp/create-nsp.js | 3 + .../core/create-nsp/socket-event-handler.js | 61 +++++++++++++------ 2 files changed, 44 insertions(+), 20 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 cdd9c8e8..3eb493c5 100644 --- a/packages/@jsonql/ws/src/core/create-nsp/create-nsp.js +++ b/packages/@jsonql/ws/src/core/create-nsp/create-nsp.js @@ -1,5 +1,8 @@ // actually binding the event client to the socket client + +// from the jsonql-ws-client-core import { clientEventHandler } from '../modules' +// local import { createNspAction } from './create-nsp-action' import { loginEventHandler } from './login-event-handler' import { socketEventHandler } from './socket-event-handler' diff --git a/packages/@jsonql/ws/src/core/create-nsp/socket-event-handler.js b/packages/@jsonql/ws/src/core/create-nsp/socket-event-handler.js index 7b36f780..e68ae307 100644 --- a/packages/@jsonql/ws/src/core/create-nsp/socket-event-handler.js +++ b/packages/@jsonql/ws/src/core/create-nsp/socket-event-handler.js @@ -12,10 +12,11 @@ import { ON_LOGIN_FN_NAME } from 'jsonql-constants' import { - createQueryStr, + createReplyMsg, createEvt, extractWsPayload } from 'jsonql-utils/module' +import { createNamespaceErrorHandler } from '../../../../../ws-client-core/src/core/resolver-methods' /** * in some edge case we might not even have a resolverName, then @@ -39,6 +40,34 @@ const errorTypeHandler = (ee, namespace, resolverName, json, ON_ERROR_FN_NAME) = ee.$trigger(evtName, [payload]) } +/** + * Handle the logout event when it's enableAuth + * @param {object} ee eventEmitter + * @return {void} + */ +const logoutEventHandler = (ee) => { + // listen to the LOGOUT_EVENT_NAME when this is a private nsp + ee.$on(LOGOUT_EVENT_NAME, function closeEvtHandler() { + try { + log('terminate ws connection') + ws.terminate() + } catch(e) { + console.error('ws.terminate error', e) + } + }) +} + +/** + * Handle the onerror callback + * @param {object} ee event emitter + * @param {string} namespace which namespace has error + * @param {*} err error object + * @return {void} + */ +const handleNamespaceOnError = (ee, namespace, err) => { + ee.$trigger(createEvt(namespace, ON_ERROR_FN_NAME), [err]) +} + /** * Binding the event to socket normally * @param {string} namespace @@ -51,9 +80,7 @@ const errorTypeHandler = (ee, namespace, resolverName, json, ON_ERROR_FN_NAME) = export function socketEventHandler(namespace, ws, ee, isPrivate, opts) { const { log } = opts // const log = (...args) => Reflect.apply(console.info, console, ['[socketEventHandler]'].concat(args)) - log(`log test, isPrivate:`, isPrivate) - // connection open ws.onopen = function onOpenCallback() { @@ -68,12 +95,16 @@ export function socketEventHandler(namespace, ws, ee, isPrivate, opts) { // 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! + */ function wsMainOnEvtHandler(resolverName, args) { - const payload = createQueryStr(resolverName, args) - - log('calling server', resolverName, args, payload) - + const payload = createReplyMsg(resolverName, args) + log('ws.onopen.send', resolverName, args, payload) + ws.send(payload) } ) @@ -86,7 +117,7 @@ export function socketEventHandler(namespace, ws, ee, isPrivate, opts) { // console.log(`on.message`, typeof payload, payload) try { const json = extractWsPayload(payload) - const { resolverName, type } = json; + const { resolverName, type } = json log('Hear from server', type, json) @@ -99,9 +130,7 @@ export function socketEventHandler(namespace, ws, ee, isPrivate, opts) { case ACKNOWLEDGE_REPLY_TYPE: let e2 = createEvt(namespace, resolverName, ON_RESULT_FN_NAME) let x2 = ee.$trigger(e2, [json]) - log(`ACKNOWLEDGE_REPLY_TYPE`, e2, x2) - break case ERROR_TYPE: // this is handled error and we won't throw it @@ -132,18 +161,10 @@ export function socketEventHandler(namespace, ws, ee, isPrivate, opts) { ws.onerror = function onErrorCallback(err) { // trigger a global error event log(`ws.onerror`, err) - ee.$trigger(createEvt(namespace, ON_ERROR_FN_NAME), [err]) + handleNamespaceOnError(ee, namespace, err) } if (isPrivate) { - // listen to the LOGOUT_EVENT_NAME when this is a private nsp - ee.$on(LOGOUT_EVENT_NAME, function closeEvtHandler() { - try { - log('terminate ws connection') - ws.terminate() - } catch(e) { - console.error('ws.terminate error', e) - } - }) + logoutEventHandler(ee) } } -- Gitee From 52a30cc51d46fc2ff24158403022134321e1f6a7 Mon Sep 17 00:00:00 2001 From: joelchu Date: Fri, 13 Mar 2020 12:55:30 +0800 Subject: [PATCH 14/45] move ws into the creaet-jsonql-ws-client --- packages/@jsonql/ws/src/core/create-jsonql-ws-client/index.js | 4 ++-- .../@jsonql/ws/src/core/{ => create-jsonql-ws-client}/ws.js | 0 2 files changed, 2 insertions(+), 2 deletions(-) rename packages/@jsonql/ws/src/core/{ => create-jsonql-ws-client}/ws.js (100%) diff --git a/packages/@jsonql/ws/src/core/create-jsonql-ws-client/index.js b/packages/@jsonql/ws/src/core/create-jsonql-ws-client/index.js index b5609c11..f3020868 100644 --- a/packages/@jsonql/ws/src/core/create-jsonql-ws-client/index.js +++ b/packages/@jsonql/ws/src/core/create-jsonql-ws-client/index.js @@ -3,7 +3,7 @@ // this will be the news style interface that will pass to the jsonql-ws-client // then return a function for accepting an opts to generate the final // client api -import WebSocket from '../ws' +import WebSocket from './ws' import createWebSocketBinding from '../create-websocket-binding' /** @@ -12,4 +12,4 @@ import createWebSocketBinding from '../create-websocket-binding' * @param {object} ee instance of the eventEmitter * @return {object} passing the same 3 input out with additional in the opts */ -export default createClientBinding(WebSocket) \ No newline at end of file +export default createWebSocketBinding(WebSocket) \ No newline at end of file diff --git a/packages/@jsonql/ws/src/core/ws.js b/packages/@jsonql/ws/src/core/create-jsonql-ws-client/ws.js similarity index 100% rename from packages/@jsonql/ws/src/core/ws.js rename to packages/@jsonql/ws/src/core/create-jsonql-ws-client/ws.js -- Gitee From e20cad98c0326902cd00113ec5288c45d8647565 Mon Sep 17 00:00:00 2001 From: joelchu Date: Fri, 13 Mar 2020 12:56:31 +0800 Subject: [PATCH 15/45] disconnect should be associate with nsp --- .../core/{create-jsonql-ws-client => create-nsp}/disconnect.js | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename packages/@jsonql/ws/src/core/{create-jsonql-ws-client => create-nsp}/disconnect.js (100%) diff --git a/packages/@jsonql/ws/src/core/create-jsonql-ws-client/disconnect.js b/packages/@jsonql/ws/src/core/create-nsp/disconnect.js similarity index 100% rename from packages/@jsonql/ws/src/core/create-jsonql-ws-client/disconnect.js rename to packages/@jsonql/ws/src/core/create-nsp/disconnect.js -- Gitee From a820d9e2e39f9e89d3d3830c843bded18ceaabe2 Mon Sep 17 00:00:00 2001 From: joelchu Date: Fri, 13 Mar 2020 13:36:12 +0800 Subject: [PATCH 16/45] still very confusing how to make it more flow in one direction instead of round about like now --- .../@jsonql/ws/src/core/generate-ws-client.js | 3 +++ packages/@jsonql/ws/src/node/index.js | 5 +++-- packages/@jsonql/ws/src/node/module.js | 20 ------------------- .../ws/src/node/node-ws-client-resolver.js | 5 ++--- 4 files changed, 8 insertions(+), 25 deletions(-) delete mode 100644 packages/@jsonql/ws/src/node/module.js diff --git a/packages/@jsonql/ws/src/core/generate-ws-client.js b/packages/@jsonql/ws/src/core/generate-ws-client.js index de18e431..1e6e44d2 100644 --- a/packages/@jsonql/ws/src/core/generate-ws-client.js +++ b/packages/@jsonql/ws/src/core/generate-ws-client.js @@ -1,5 +1,8 @@ // take out from module, doesn't make sense to be there +// This method is ONLY for integration use only which means +// the options are already checked import { wsClientCoreAction } from './modules' + /** * Take the already checked options (using part of export here) * then generate the ws client diff --git a/packages/@jsonql/ws/src/node/index.js b/packages/@jsonql/ws/src/node/index.js index 4e1cd719..65b74d43 100644 --- a/packages/@jsonql/ws/src/node/index.js +++ b/packages/@jsonql/ws/src/node/index.js @@ -4,12 +4,13 @@ import { jsonqlWsConstProps, wsClientCore } from '../core/modules' -import wsClientResolver from './node-ws-client-resolver' + +import nodeWsClientResolver from './node-ws-client-resolver' // export back the function and that's it export default function wsNodeClient(config = {}, constProps = {}) { const initClientMethod = wsClientCore( - wsClientResolver, + nodeWsClientResolver, jsonqlWsClientAppProps, Object.assign({}, jsonqlWsConstProps, constProps) ) diff --git a/packages/@jsonql/ws/src/node/module.js b/packages/@jsonql/ws/src/node/module.js deleted file mode 100644 index d950c40f..00000000 --- a/packages/@jsonql/ws/src/node/module.js +++ /dev/null @@ -1,20 +0,0 @@ -// modular client creation for node -import nodeWsClientResolver from './node-ws-client-resolver' -import { - jsonqlWsClientAppProps, - jsonqlWsConstProps, - checkSocketClientType, - // the core function to create client to accept already checked config - generateWsClient -} from '../core/modules' - -const createWsClient = generateWsClient(nodeWsClientResolver) - -// export done -export { - jsonqlWsClientAppProps, - jsonqlWsConstProps, - checkSocketClientType, - // the main method to call - createWsClient -} \ No newline at end of file diff --git a/packages/@jsonql/ws/src/node/node-ws-client-resolver.js b/packages/@jsonql/ws/src/node/node-ws-client-resolver.js index b5ba1bb6..c685ce7f 100644 --- a/packages/@jsonql/ws/src/node/node-ws-client-resolver.js +++ b/packages/@jsonql/ws/src/node/node-ws-client-resolver.js @@ -2,12 +2,11 @@ // then return a function for accepting an opts to generate the final // client api import WebSocket from 'ws' -import { createClientBinding } from '../core/create-websocket-client/create-client-binding' - +import createWebSocketBinding from '../create-websocket-binding' /** * @param {object} opts configuration * @param {object} nspMap from the contract * @param {object} ee instance of the eventEmitter * @return {object} passing the same 3 input out with additional in the opts */ -export default createClientBinding(WebSocket) +export default createWebSocketBinding(WebSocket) -- Gitee From cfefdd4b2667e8091697392959574c244695ebd9 Mon Sep 17 00:00:00 2001 From: joelchu Date: Fri, 13 Mar 2020 13:38:18 +0800 Subject: [PATCH 17/45] Take the files out because they are suppose ot be the final step to ensemble the ws client for browser --- .../@jsonql/ws/src/core/{create-jsonql-ws-client => }/index.js | 0 packages/@jsonql/ws/src/core/{create-jsonql-ws-client => }/ws.js | 0 2 files changed, 0 insertions(+), 0 deletions(-) rename packages/@jsonql/ws/src/core/{create-jsonql-ws-client => }/index.js (100%) rename packages/@jsonql/ws/src/core/{create-jsonql-ws-client => }/ws.js (100%) diff --git a/packages/@jsonql/ws/src/core/create-jsonql-ws-client/index.js b/packages/@jsonql/ws/src/core/index.js similarity index 100% rename from packages/@jsonql/ws/src/core/create-jsonql-ws-client/index.js rename to packages/@jsonql/ws/src/core/index.js diff --git a/packages/@jsonql/ws/src/core/create-jsonql-ws-client/ws.js b/packages/@jsonql/ws/src/core/ws.js similarity index 100% rename from packages/@jsonql/ws/src/core/create-jsonql-ws-client/ws.js rename to packages/@jsonql/ws/src/core/ws.js -- Gitee From 7f4314c8ff87a4fe9d1e3e05a12961194d0e6456 Mon Sep 17 00:00:00 2001 From: joelchu Date: Fri, 13 Mar 2020 13:39:50 +0800 Subject: [PATCH 18/45] just spell out what it does in the file name to ws-client-for-integration --- .../{generate-ws-client.js => ws-client-for-integration.js} | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) rename packages/@jsonql/ws/src/core/{generate-ws-client.js => ws-client-for-integration.js} (90%) diff --git a/packages/@jsonql/ws/src/core/generate-ws-client.js b/packages/@jsonql/ws/src/core/ws-client-for-integration.js similarity index 90% rename from packages/@jsonql/ws/src/core/generate-ws-client.js rename to packages/@jsonql/ws/src/core/ws-client-for-integration.js index 1e6e44d2..2853c821 100644 --- a/packages/@jsonql/ws/src/core/generate-ws-client.js +++ b/packages/@jsonql/ws/src/core/ws-client-for-integration.js @@ -9,7 +9,7 @@ import { wsClientCoreAction } from './modules' * @param {function} wsClientResolver configuration * @return {function} take config return the promise resolve the ws client */ -export function generateWsClient(wsClientResolver) { +export function wsClientForIntegration(wsClientResolver) { return (config) => Promise .resolve(config) -- Gitee From aee7df395b37e1b13a14467dc3a277813f9d6cfa Mon Sep 17 00:00:00 2001 From: joelchu Date: Fri, 13 Mar 2020 13:43:32 +0800 Subject: [PATCH 19/45] I hope the renaming make more sense now --- packages/@jsonql/ws/{index.js => src/browser-ws-client.js} | 5 +++-- .../@jsonql/ws/src/core/{index.js => ws-client-resolver.js} | 0 packages/@jsonql/ws/src/{node/index.js => node-ws-client.js} | 2 +- 3 files changed, 4 insertions(+), 3 deletions(-) rename packages/@jsonql/ws/{index.js => src/browser-ws-client.js} (83%) rename packages/@jsonql/ws/src/core/{index.js => ws-client-resolver.js} (100%) rename packages/@jsonql/ws/src/{node/index.js => node-ws-client.js} (87%) diff --git a/packages/@jsonql/ws/index.js b/packages/@jsonql/ws/src/browser-ws-client.js similarity index 83% rename from packages/@jsonql/ws/index.js rename to packages/@jsonql/ws/src/browser-ws-client.js index 04ee930a..60284d76 100644 --- a/packages/@jsonql/ws/index.js +++ b/packages/@jsonql/ws/src/browser-ws-client.js @@ -4,8 +4,9 @@ import { jsonqlWsClientAppProps, jsonqlWsConstProps, wsClientCore -} from './src/core/modules' -import wsClientResolver from './src/core/ws-client-resolver' +} from './core/modules' + +import wsClientResolver from './core/ws-client-resolver' // export back the function and that's it export default function wsBrowserClient(config = {}, constProps = {}) { diff --git a/packages/@jsonql/ws/src/core/index.js b/packages/@jsonql/ws/src/core/ws-client-resolver.js similarity index 100% rename from packages/@jsonql/ws/src/core/index.js rename to packages/@jsonql/ws/src/core/ws-client-resolver.js diff --git a/packages/@jsonql/ws/src/node/index.js b/packages/@jsonql/ws/src/node-ws-client.js similarity index 87% rename from packages/@jsonql/ws/src/node/index.js rename to packages/@jsonql/ws/src/node-ws-client.js index 65b74d43..c45a30bc 100644 --- a/packages/@jsonql/ws/src/node/index.js +++ b/packages/@jsonql/ws/src/node-ws-client.js @@ -5,7 +5,7 @@ import { wsClientCore } from '../core/modules' -import nodeWsClientResolver from './node-ws-client-resolver' +import nodeWsClientResolver from './node/node-ws-client-resolver' // export back the function and that's it export default function wsNodeClient(config = {}, constProps = {}) { -- Gitee From fcb06dfa82c6b0067b941a90dbdb41c8a3819ed3 Mon Sep 17 00:00:00 2001 From: joelchu Date: Fri, 13 Mar 2020 13:46:17 +0800 Subject: [PATCH 20/45] the indexjs now is just import and export --- packages/@jsonql/ws/index.js | 4 ++++ packages/@jsonql/ws/module.js | 9 ++++----- 2 files changed, 8 insertions(+), 5 deletions(-) create mode 100644 packages/@jsonql/ws/index.js diff --git a/packages/@jsonql/ws/index.js b/packages/@jsonql/ws/index.js new file mode 100644 index 00000000..04163dcf --- /dev/null +++ b/packages/@jsonql/ws/index.js @@ -0,0 +1,4 @@ +// just export interface for browser +import wsBrowserClient from './src/browser-ws-client' + +export default wsBrowserClient \ No newline at end of file diff --git a/packages/@jsonql/ws/module.js b/packages/@jsonql/ws/module.js index afc586a8..5cfc83db 100644 --- a/packages/@jsonql/ws/module.js +++ b/packages/@jsonql/ws/module.js @@ -6,18 +6,17 @@ import wsClientResolver from './src/ws-client-resolver' import { jsonqlWsClientAppProps, jsonqlWsConstProps, - checkSocketClientType, - generateWsClient + checkSocketClientType + // generateWsClient } from './src/core/modules' -const createWsClient = generateWsClient(wsClientResolver) +// const createWsClient = generateWsClient(wsClientResolver) // export done export { jsonqlWsClientAppProps, jsonqlWsConstProps, - checkSocketClientType, + checkSocketClientType // export from this module - createWsClient } -- Gitee From c94626d6b762134f6befc4c0c752318070cf0eea Mon Sep 17 00:00:00 2001 From: joelchu Date: Fri, 13 Mar 2020 14:16:23 +0800 Subject: [PATCH 21/45] rename it to frameworkSocketEngine that make more sense now --- packages/@jsonql/ws/src/browser-ws-client.js | 4 ++-- .../{ws-client-resolver.js => framework-socket-engine.js} | 0 packages/@jsonql/ws/src/node-ws-client.js | 4 ++-- ...-ws-client-resolver.js => node-framework-socket-engine.js} | 0 4 files changed, 4 insertions(+), 4 deletions(-) rename packages/@jsonql/ws/src/core/{ws-client-resolver.js => framework-socket-engine.js} (100%) rename packages/@jsonql/ws/src/node/{node-ws-client-resolver.js => node-framework-socket-engine.js} (100%) diff --git a/packages/@jsonql/ws/src/browser-ws-client.js b/packages/@jsonql/ws/src/browser-ws-client.js index 60284d76..08e9699f 100644 --- a/packages/@jsonql/ws/src/browser-ws-client.js +++ b/packages/@jsonql/ws/src/browser-ws-client.js @@ -6,12 +6,12 @@ import { wsClientCore } from './core/modules' -import wsClientResolver from './core/ws-client-resolver' +import frameworkSocketEngine from './core/framework-socket-engine' // export back the function and that's it export default function wsBrowserClient(config = {}, constProps = {}) { const initMethod = wsClientCore( - wsClientResolver, + frameworkSocketEngine, jsonqlWsClientAppProps, Object.assign({}, jsonqlWsConstProps, constProps) ) diff --git a/packages/@jsonql/ws/src/core/ws-client-resolver.js b/packages/@jsonql/ws/src/core/framework-socket-engine.js similarity index 100% rename from packages/@jsonql/ws/src/core/ws-client-resolver.js rename to packages/@jsonql/ws/src/core/framework-socket-engine.js diff --git a/packages/@jsonql/ws/src/node-ws-client.js b/packages/@jsonql/ws/src/node-ws-client.js index c45a30bc..823f8795 100644 --- a/packages/@jsonql/ws/src/node-ws-client.js +++ b/packages/@jsonql/ws/src/node-ws-client.js @@ -5,12 +5,12 @@ import { wsClientCore } from '../core/modules' -import nodeWsClientResolver from './node/node-ws-client-resolver' +import nodeFrameworkSocketEngine from './node/node-framework-socket-engine' // export back the function and that's it export default function wsNodeClient(config = {}, constProps = {}) { const initClientMethod = wsClientCore( - nodeWsClientResolver, + nodeFrameworkSocketEngine, jsonqlWsClientAppProps, Object.assign({}, jsonqlWsConstProps, constProps) ) diff --git a/packages/@jsonql/ws/src/node/node-ws-client-resolver.js b/packages/@jsonql/ws/src/node/node-framework-socket-engine.js similarity index 100% rename from packages/@jsonql/ws/src/node/node-ws-client-resolver.js rename to packages/@jsonql/ws/src/node/node-framework-socket-engine.js -- Gitee From 018ca89aa85c41b2c6f41be16bcc3cfc943931d0 Mon Sep 17 00:00:00 2001 From: joelchu Date: Fri, 13 Mar 2020 14:18:56 +0800 Subject: [PATCH 22/45] rename the import from the client to frameworkSocketEngine that should make more sense now --- packages/ws-client-core/index.js | 3 +++ packages/ws-client-core/package.json | 2 +- packages/ws-client-core/src/api.js | 12 ++++++------ 3 files changed, 10 insertions(+), 7 deletions(-) diff --git a/packages/ws-client-core/index.js b/packages/ws-client-core/index.js index c1618deb..49631d69 100644 --- a/packages/ws-client-core/index.js +++ b/packages/ws-client-core/index.js @@ -39,9 +39,12 @@ export { checkSocketClientType, // from share.js jsonqlWsConstants, + createNspClient, createNspAuthClient, + triggerNamespacesOnError, + clientEventHandler, fixWss, clearMainEmitEvt, diff --git a/packages/ws-client-core/package.json b/packages/ws-client-core/package.json index 01d6649a..4bf344bf 100644 --- a/packages/ws-client-core/package.json +++ b/packages/ws-client-core/package.json @@ -1,6 +1,6 @@ { "name": "jsonql-ws-client-core", - "version": "0.8.5", + "version": "0.8.6", "description": "This is the jsonql Web Socket client core library for Node and Browser. Not for direct use.", "main": "main.js", "module": "index.js", diff --git a/packages/ws-client-core/src/api.js b/packages/ws-client-core/src/api.js index 8351a768..92aa6cbc 100644 --- a/packages/ws-client-core/src/api.js +++ b/packages/ws-client-core/src/api.js @@ -12,15 +12,15 @@ import { /** * 0.5.0 we break up the wsClientCore in two parts one without the config check - * @param {function} socketClientResolver + * @param {function} frameworkSocketEngine * @param {object} config the already checked config */ -export function wsClientCoreAction(socketClientResolver, config) { +export function wsClientCoreAction(frameworkSocketEngine, config) { return postCheckInjectOpts(config) // the following two moved to wsPostConfig .then(createRequiredParams) .then( - ({opts, nspMap, ee}) => socketClientResolver(opts, nspMap, ee) + ({opts, nspMap, ee}) => frameworkSocketEngine(opts, nspMap, ee) ) .then( ({opts, nspMap, ee}) => generator(opts, nspMap, ee) @@ -32,13 +32,13 @@ export function wsClientCoreAction(socketClientResolver, config) { /** * The main interface which will generate the socket clients and map all events - * @param {object} socketClientResolver this is the one method export by various clients + * @param {object} frameworkSocketEngine this is the one method export by various clients * @param {object} [defaultOptions={}] we should do all the checking in the core instead of the client * @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(socketClientResolver, defaultOptions = {}, constProps = {}) { +export function wsClientCore(frameworkSocketEngine, defaultOptions = {}, constProps = {}) { // we need to inject property to this client later return (config = {}) => checkConfiguration(config, defaultOptions, constProps) - .then(opts => wsClientCoreAction(socketClientResolver, opts)) + .then(opts => wsClientCoreAction(frameworkSocketEngine, opts)) } -- Gitee From 01499143aad2aaaa990bc32ae4b79d0045281ef6 Mon Sep 17 00:00:00 2001 From: joelchu Date: Fri, 13 Mar 2020 14:30:30 +0800 Subject: [PATCH 23/45] add back the module --- packages/@jsonql/ws/module.js | 1 - packages/@jsonql/ws/package.json | 9 +++++---- packages/@jsonql/ws/rollup.config.js | 6 +++--- packages/@jsonql/ws/src/node/module.js | 17 +++++++++++++++++ .../ws/src/node/node-framework-socket-engine.js | 3 ++- 5 files changed, 27 insertions(+), 9 deletions(-) create mode 100644 packages/@jsonql/ws/src/node/module.js diff --git a/packages/@jsonql/ws/module.js b/packages/@jsonql/ws/module.js index 5cfc83db..e94436d8 100644 --- a/packages/@jsonql/ws/module.js +++ b/packages/@jsonql/ws/module.js @@ -1,7 +1,6 @@ // this is a new interface that takes the already check config // and init the ws client -import wsClientResolver from './src/ws-client-resolver' import { jsonqlWsClientAppProps, diff --git a/packages/@jsonql/ws/package.json b/packages/@jsonql/ws/package.json index 311b59b0..61309814 100644 --- a/packages/@jsonql/ws/package.json +++ b/packages/@jsonql/ws/package.json @@ -17,11 +17,12 @@ "scripts": { "test": "ava", "prepare": "npm run build", + "build": "NODE_ENV=production npm run build:cjs && NODE_ENV=production npm run build:umd", "build:cjs": "TARGET=cjs rollup -c", "build:umd": "TARGET=umd rollup -c", "build:cjs:module": "TARGET=cjs-module rollup -c", - "build:test": "npm run build:cjs && npm run build:umd && npm run build:cjs:module", - "build": "NODE_ENV=production npm run build:cjs && NODE_ENV=production npm run build:cjs:module && NODE_ENV=production npm run build:umd", + "build:cjs:module:prod": "NODE_ENV=production npm run build:cjs:module", + "build:test": "npm run build:cjs && npm run build:umd", "test:browser:basic": "npm run build:umd && DEBUG=jsonql-ws-client*,server-io-core* node ./tests/browser/run-qunit.js", "test:browser:auth": "npm run build:umd && DEBUG=jsonql-ws-* NODE_ENV=ws-auth node ./tests/browser/run-qunit.js", "test:opt": "ava ./tests/opt.test.js", @@ -51,7 +52,7 @@ "jsonql-jwt": "^1.3.9", "jsonql-params-validator": "^1.5.3", "jsonql-utils": "^1.1.3", - "jsonql-ws-client-core": "^0.8.4", + "jsonql-ws-client-core": "^0.8.6", "ws": "^7.2.3" }, "devDependencies": { @@ -66,7 +67,7 @@ "kefir": "^3.8.6", "koa": "^2.11.0", "koa-bodyparser": "^4.2.1", - "rollup": "^2.0.5", + "rollup": "^2.0.6", "rollup-plugin-alias": "^2.2.0", "rollup-plugin-async": "^1.2.0", "rollup-plugin-buble": "^0.19.8", diff --git a/packages/@jsonql/ws/rollup.config.js b/packages/@jsonql/ws/rollup.config.js index 76a3027f..f116a9ce 100644 --- a/packages/@jsonql/ws/rollup.config.js +++ b/packages/@jsonql/ws/rollup.config.js @@ -46,8 +46,8 @@ let plugins = [ }) ] -if (process.env.NODE_ENV === 'production') { - plugins.push( terser() ) +if (env === 'production') { + plugins.push( terser() ) } plugins.push( size() ) @@ -55,7 +55,7 @@ let inFile, outFile, _target switch (target) { case 'cjs': - inFile = 'src/node/index.js' + inFile = 'src/node-ws-client.js' outFile = join(__dirname, 'main.js') _target = 'cjs' break diff --git a/packages/@jsonql/ws/src/node/module.js b/packages/@jsonql/ws/src/node/module.js new file mode 100644 index 00000000..f1933061 --- /dev/null +++ b/packages/@jsonql/ws/src/node/module.js @@ -0,0 +1,17 @@ +// this is for node upstream client to include and construct their own client +import { + jsonqlWsClientAppProps, + jsonqlWsConstProps, + checkSocketClientType + // generateWsClient +} from './src/core/modules' + + + +export { + jsonqlWsClientAppProps, + jsonqlWsConstProps, + + checkSocketClientType + // export from this module +} \ No newline at end of file diff --git a/packages/@jsonql/ws/src/node/node-framework-socket-engine.js b/packages/@jsonql/ws/src/node/node-framework-socket-engine.js index c685ce7f..cf9d0a27 100644 --- a/packages/@jsonql/ws/src/node/node-framework-socket-engine.js +++ b/packages/@jsonql/ws/src/node/node-framework-socket-engine.js @@ -2,7 +2,8 @@ // then return a function for accepting an opts to generate the final // client api import WebSocket from 'ws' -import createWebSocketBinding from '../create-websocket-binding' +import createWebSocketBinding from '../core/create-websocket-binding' + /** * @param {object} opts configuration * @param {object} nspMap from the contract -- Gitee From adbd27b58153aa33df21ab46102de41ee6447f01 Mon Sep 17 00:00:00 2001 From: joelchu Date: Fri, 13 Mar 2020 14:37:15 +0800 Subject: [PATCH 24/45] rethink about the architect how to deal with the http-client combine client --- ...-for-integration.js => create-combine-client.js} | 13 ++++++++++++- packages/@jsonql/ws/src/node-ws-client.js | 2 +- 2 files changed, 13 insertions(+), 2 deletions(-) rename packages/@jsonql/ws/src/{core/ws-client-for-integration.js => create-combine-client.js} (49%) diff --git a/packages/@jsonql/ws/src/core/ws-client-for-integration.js b/packages/@jsonql/ws/src/create-combine-client.js similarity index 49% rename from packages/@jsonql/ws/src/core/ws-client-for-integration.js rename to packages/@jsonql/ws/src/create-combine-client.js index 2853c821..4b1c4fee 100644 --- a/packages/@jsonql/ws/src/core/ws-client-for-integration.js +++ b/packages/@jsonql/ws/src/create-combine-client.js @@ -1,7 +1,18 @@ +// @NOTE how to deal with the integration with http client +// instead of using http client as a host +// we could pass the http-client into the ws client +// let the ws client to deal with the combine configuration check +// then generate the http-client --> generate the ws client +// this way, it won't be so messy, the http client just pass their +// appProps and constProps, and their main constructor api +// and here we deal with it and create less confusion what goes where +// everything will just flow one way + + // take out from module, doesn't make sense to be there // This method is ONLY for integration use only which means // the options are already checked -import { wsClientCoreAction } from './modules' +import { wsClientCoreAction } from './core/modules' /** * Take the already checked options (using part of export here) diff --git a/packages/@jsonql/ws/src/node-ws-client.js b/packages/@jsonql/ws/src/node-ws-client.js index 823f8795..88f74375 100644 --- a/packages/@jsonql/ws/src/node-ws-client.js +++ b/packages/@jsonql/ws/src/node-ws-client.js @@ -3,7 +3,7 @@ import { jsonqlWsClientAppProps, jsonqlWsConstProps, wsClientCore -} from '../core/modules' +} from './core/modules' import nodeFrameworkSocketEngine from './node/node-framework-socket-engine' -- Gitee From 7e366c993bb6b790fda8d7c2a6d066ca8096195c Mon Sep 17 00:00:00 2001 From: joelchu Date: Fri, 13 Mar 2020 15:16:02 +0800 Subject: [PATCH 25/45] rename internal and create the new combine client generator --- packages/ws-client-core/README.md | 27 +++++++++++-- packages/ws-client-core/index.js | 10 ++--- .../src/create-combine-client.js | 39 +++++++++++++++++++ .../ws-client-core/src/options/defaults.js | 8 ++-- packages/ws-client-core/src/options/index.js | 26 ++++++++++--- .../src/share/trigger-namespaces-on-error.js | 11 ++++++ .../src/utils/{ee.js => get-event-emitter.js} | 0 .../src/utils/{log.js => get-log-fn.js} | 0 packages/ws-client-core/src/utils/index.js | 4 +- 9 files changed, 104 insertions(+), 21 deletions(-) create mode 100644 packages/ws-client-core/src/create-combine-client.js rename packages/ws-client-core/src/utils/{ee.js => get-event-emitter.js} (100%) rename packages/ws-client-core/src/utils/{log.js => get-log-fn.js} (100%) diff --git a/packages/ws-client-core/README.md b/packages/ws-client-core/README.md index 3f8f49b6..6e33db26 100644 --- a/packages/ws-client-core/README.md +++ b/packages/ws-client-core/README.md @@ -11,11 +11,32 @@ Please check the following - [@jsonql/socketio](https://npmjs.com/package/@jsonql/socketio) for [Socket.io](https://npmjs.com/package/socketio) client / server - ~~@jsonql/primus for Primus client / server~~ (planning stage) -## Share methods +## Create combine client -This module also export several share methods via `jsonql-ws-client/share` but this is mainly for the -down stream client to use. +2020-03-13 +After a long period of struggle with the architect problem. Comes to a conclusion - it was shit. + +Instead of think of it from a host / slave structure. Should take a higher approach to look at it like +onion skins. + +At the moment, the ws client module export back the `configCheckMap` and `constProps` then back in here +which is very messy. Instead, I am going to change it to something like this + +```js +import { httpClient, configCheckMap, constProps } from 'jsonql-http-client/module' +import { createCombineClient } from '@jsonql/ws/combine' + +const clientConstructor = createCombineClient(httpClient, configCheckMap, constProps) + +clientConstructor(config) + .then(client => { + // now you will get http-client as well as socket client as one + }) + +``` + +This will be a much cleaner approach, although you won't see it. But we write it here as a note to somebody else might be facing the same issue (modular, architect). Well, it will be in the book. Please check [jsonql.org](https://jsonql.org) for further information diff --git a/packages/ws-client-core/index.js b/packages/ws-client-core/index.js index 49631d69..76a3c9f4 100644 --- a/packages/ws-client-core/index.js +++ b/packages/ws-client-core/index.js @@ -4,8 +4,6 @@ import { wsClientCoreAction } from './src/api' import { - wsCoreDefaultOptions, - wsCoreConstProps, checkSocketClientType } from './src/options' // these were in the share.js and now we combine into one @@ -15,7 +13,10 @@ import { createNspClient, createNspAuthClient } from './src/share/create-nsp-client' -import { triggerNamespacesOnError } from './src/share/trigger-namespaces-on-error' +import { + triggerNamespacesOnError + +} from './src/share/trigger-namespaces-on-error' import { clientEventHandler } from './src/share/client-event-handler' import { getEventEmitter, @@ -29,9 +30,6 @@ import { // export export { - // props - wsCoreDefaultOptions, - wsCoreConstProps, // generator methods wsClientCore, wsClientCoreAction, diff --git a/packages/ws-client-core/src/create-combine-client.js b/packages/ws-client-core/src/create-combine-client.js new file mode 100644 index 00000000..11fb0e7f --- /dev/null +++ b/packages/ws-client-core/src/create-combine-client.js @@ -0,0 +1,39 @@ +/** + * After a long period of struggle with the architect problem. Comes to a conclusion - it was shit. + * + * Instead of think of it from a host / slave structure. Should take a higher approach to look at it like + * onion skins. + * + * At the moment, the ws client module export back the `configCheckMap` and `constProps` then back in here + * which is very messy. + */ + +import { createCombineCheckConfig } from './options' +import { wsClientCoreAction } from './api' +import { SOCKET_NAME } from 'jsonql-constants' + +/** + * Create a combine client + * @param {*} httpClientConstructor + * @param {*} wsClientEngine + * @param {*} configCheckMap + * @param {*} constProps + */ +function createCombineClient(httpClientConstructor, wsClientEngine, configCheckMap, constProps) { + const checkConfigFn = createCombineCheckConfig(configCheckMap, constProps) + /** + * This will become the final interace facing the app to use + */ + return (config = {}) => checkConfigFn(config) + .then(opts => { + // this constructor should not need to check the config again + return httpClientConstructor(opts) + }) + .then(httpClient => { + const socketClient = wsClientCoreAction(wsClientEngine, opts) + httpClient[SOCKET_NAME] = socketClient + return httpClient + }) +} + +export { createCombineClient } diff --git a/packages/ws-client-core/src/options/defaults.js b/packages/ws-client-core/src/options/defaults.js index 770bbdde..fb99d77a 100644 --- a/packages/ws-client-core/src/options/defaults.js +++ b/packages/ws-client-core/src/options/defaults.js @@ -22,7 +22,7 @@ import { // import { AVAILABLE_SERVERS } from './constants' const AVAILABLE_METHODS = [IO_ROUNDTRIP_LOGIN, IO_HANDSHAKE_LOGIN] -const wsBaseOptions = { +const configCheckMap = { standalone: createConfig(false, [BOOLEAN_TYPE]), // to turn on or off some of the features debugOn: createConfig(false, [BOOLEAN_TYPE]), // useCallbackStyle: createConfig(false, [BOOLEAN_TYPE]), abandoned in 0.6.0 @@ -51,13 +51,13 @@ const wsBaseOptions = { } // socket client -const socketAppProps = { +const socketCheckMap = { // new prop for socket client [SOCKET_TYPE_KEY]: createConfig(null, [STRING_TYPE], {[ALIAS_KEY]: SOCKET_TYPE_CLIENT_ALIAS}) // [ENUM_KEY]: [JS_WS_NAME, JS_WS_SOCKET_IO_NAME, JS_PRIMUS_NAME], } -const wsCoreDefaultOptions = Object.assign(wsBaseOptions, socketAppProps) +const wsCoreCheckMap = Object.assign(configCheckMap, socketAppProps) // constant props const wsCoreConstProps = { @@ -72,4 +72,4 @@ const wsCoreConstProps = { wssPath: '' } -export { wsCoreDefaultOptions, wsCoreConstProps, socketAppProps } +export { wsCoreCheckMap, wsCoreConstProps, socketCheckMap } diff --git a/packages/ws-client-core/src/options/index.js b/packages/ws-client-core/src/options/index.js index 3a0d1f42..30c6e880 100644 --- a/packages/ws-client-core/src/options/index.js +++ b/packages/ws-client-core/src/options/index.js @@ -4,9 +4,9 @@ import { checkConfig } from 'jsonql-params-validator' import { - wsCoreDefaultOptions, + wsCoreCheckMap, wsCoreConstProps, - socketAppProps + sockeCheckMap } from './defaults' import { fixWss, @@ -22,9 +22,22 @@ import { * @return {string} the name of the socket server if any */ function checkSocketClientType(config) { - return checkConfig(config, socketAppProps) + return checkConfig(config, sockeCheckMap) } +/** + * 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 + */ +function createCombineConfigCheck(configCheckMap, constProps) { + const combineCheckMap = Object.assign({}, configCheckMap, wsCoreCheckMap) + const combineConstProps = Object.assign({}, constProps, wsCoreConstProps) + return config => checkConfigAsync(config, combineCheckMap, combineConstProps) +} + + /** * wrapper method to check this already did the pre check * @param {object} config user supply config @@ -34,7 +47,7 @@ function checkSocketClientType(config) { */ function checkConfiguration(config, defaultOptions, constProps) { const wsConstProps = Object.assign(wsCoreConstProps, constProps) - const defaultCheckOptions = Object.assign(wsCoreDefaultOptions, defaultOptions) + const defaultCheckOptions = Object.assign(wsCoreCheckMap, defaultOptions) return checkConfigAsync(config, defaultCheckOptions, wsConstProps) } @@ -79,12 +92,13 @@ function createRequiredParams(opts) { export { // properties - wsCoreDefaultOptions, + wsCoreCheckMap, wsCoreConstProps, // functions checkConfiguration, postCheckInjectOpts, createRequiredParams, // this will just get export for integration - checkSocketClientType + checkSocketClientType, + createCombineConfigCheck } diff --git a/packages/ws-client-core/src/share/trigger-namespaces-on-error.js b/packages/ws-client-core/src/share/trigger-namespaces-on-error.js index 3a6430be..10dfc92f 100644 --- a/packages/ws-client-core/src/share/trigger-namespaces-on-error.js +++ b/packages/ws-client-core/src/share/trigger-namespaces-on-error.js @@ -17,3 +17,14 @@ export function triggerNamespacesOnError(ee, namespaces, message) { ) }) } + +/** + * Handle the onerror callback + * @param {object} ee event emitter + * @param {string} namespace which namespace has error + * @param {*} err error object + * @return {void} + */ +export const handleNamespaceOnError = (ee, namespace, err) => { + ee.$trigger(createEvt(namespace, ON_ERROR_FN_NAME), [err]) +} \ No newline at end of file diff --git a/packages/ws-client-core/src/utils/ee.js b/packages/ws-client-core/src/utils/get-event-emitter.js similarity index 100% rename from packages/ws-client-core/src/utils/ee.js rename to packages/ws-client-core/src/utils/get-event-emitter.js diff --git a/packages/ws-client-core/src/utils/log.js b/packages/ws-client-core/src/utils/get-log-fn.js similarity index 100% rename from packages/ws-client-core/src/utils/log.js rename to packages/ws-client-core/src/utils/get-log-fn.js diff --git a/packages/ws-client-core/src/utils/index.js b/packages/ws-client-core/src/utils/index.js index 1784e698..6aa032a4 100644 --- a/packages/ws-client-core/src/utils/index.js +++ b/packages/ws-client-core/src/utils/index.js @@ -1,7 +1,7 @@ // export the util methods import { isArray, isString } from 'jsonql-params-validator' -import { getLogFn } from './log' -import { getEventEmitter } from './ee' +import { getLogFn } from './get-log-fn' +import { getEventEmitter } from './get-event-emitter' // moved to jsonql-utils // some of these are unnecessary export should get rip of them import { -- Gitee From 7338779efd241391cb6203c478a08f5dacc23b43 Mon Sep 17 00:00:00 2001 From: joelchu Date: Fri, 13 Mar 2020 15:19:51 +0800 Subject: [PATCH 26/45] sort out the export with new methods --- packages/ws-client-core/index.js | 16 ++++++++++++---- packages/ws-client-core/package.json | 2 +- 2 files changed, 13 insertions(+), 5 deletions(-) diff --git a/packages/ws-client-core/index.js b/packages/ws-client-core/index.js index 76a3c9f4..fa0a8ddf 100644 --- a/packages/ws-client-core/index.js +++ b/packages/ws-client-core/index.js @@ -14,19 +14,24 @@ import { createNspAuthClient } from './src/share/create-nsp-client' import { - triggerNamespacesOnError - + triggerNamespacesOnError, + handleNamespaceOnError } from './src/share/trigger-namespaces-on-error' import { clientEventHandler } from './src/share/client-event-handler' import { getEventEmitter, EventEmitterClass -} from './src/utils/ee' +} from './src/utils/get-event-emitter' // also export some of the util methods import { fixWss, clearMainEmitEvt } from './src/utils/helpers' +// The onion skin cooker +import { + createCombineClient +} from './src/create-combine-client' + // export export { @@ -42,10 +47,13 @@ export { createNspAuthClient, triggerNamespacesOnError, + handleNamespaceOnError, clientEventHandler, fixWss, clearMainEmitEvt, getEventEmitter, - EventEmitterClass + EventEmitterClass, + + createCombineClient } diff --git a/packages/ws-client-core/package.json b/packages/ws-client-core/package.json index 4bf344bf..6b5276eb 100644 --- a/packages/ws-client-core/package.json +++ b/packages/ws-client-core/package.json @@ -1,6 +1,6 @@ { "name": "jsonql-ws-client-core", - "version": "0.8.6", + "version": "0.9.0", "description": "This is the jsonql Web Socket client core library for Node and Browser. Not for direct use.", "main": "main.js", "module": "index.js", -- Gitee From 339c37f97fdeaf08d7cea512a0f71a8342f882f9 Mon Sep 17 00:00:00 2001 From: joelchu Date: Fri, 13 Mar 2020 15:29:29 +0800 Subject: [PATCH 27/45] breaking change on the client-event-handler --- packages/ws-client-core/index.js | 7 +++-- .../src/share/client-event-handler.js | 27 +++++-------------- 2 files changed, 12 insertions(+), 22 deletions(-) diff --git a/packages/ws-client-core/index.js b/packages/ws-client-core/index.js index fa0a8ddf..17bf1102 100644 --- a/packages/ws-client-core/index.js +++ b/packages/ws-client-core/index.js @@ -17,7 +17,6 @@ import { triggerNamespacesOnError, handleNamespaceOnError } from './src/share/trigger-namespaces-on-error' -import { clientEventHandler } from './src/share/client-event-handler' import { getEventEmitter, EventEmitterClass @@ -27,6 +26,10 @@ import { fixWss, clearMainEmitEvt } from './src/utils/helpers' +// this one bind the framework engine and our event engine together +import { + clientEventHandler +} from './src/share/client-event-handler' // The onion skin cooker import { createCombineClient @@ -49,11 +52,11 @@ export { triggerNamespacesOnError, handleNamespaceOnError, - clientEventHandler, fixWss, clearMainEmitEvt, getEventEmitter, EventEmitterClass, + clientEventHandler, createCombineClient } diff --git a/packages/ws-client-core/src/share/client-event-handler.js b/packages/ws-client-core/src/share/client-event-handler.js index 21fada08..2a93e38c 100644 --- a/packages/ws-client-core/src/share/client-event-handler.js +++ b/packages/ws-client-core/src/share/client-event-handler.js @@ -61,7 +61,6 @@ const disconnectedHandler = (namespace, ee, opts) => { ) } - /** * get the private namespace * @param {array} namespaces array @@ -100,18 +99,6 @@ const logoutEvtHandler = (nsps, namespaces, ee, opts) => { nsps[privateNamespace] = null // add a NOT LOGIN error if call notLoginWsHandler(privateNamespace, ee, opts) - - /* - we don't loop it anymore - but what if we want to create private room features - therefore we keep it here for now - namespaces.forEach( namespace => { - // We should ONLY logout from the private nsp - if (privateNamespace === namespace) { - - } - }) - */ }) } @@ -141,20 +128,20 @@ const disconnectHandler = (nsps, namespaces, ee, opts) => { /** * centralize all the comm in one place * @param {object} opts configuration - * @param {array} namespaces namespace(s) * @param {object} ee Event Emitter instance * @param {function} bindWsHandler binding the ee to ws --> this is the core bit - * @param {array} namespaces array of namespace available * @param {object} nsps namespaced nsp * @return {void} nothing */ -export function clientEventHandler(opts, nspMap, ee, bindWsHandler, namespaces, nsps) { +export function clientEventHandler(opts, ee, bindSocketEventHandler, nsps) { + // since all these params already in the opts + const { nspMap, log } = opts + const { namespaces } = nspMap // @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) let isPrivate = false let hasPrivate = false - const { log } = opts // loop // @BUG for io this has to be in order the one with auth need to get call first // The order of login is very import we need to run in order here to make sure @@ -170,10 +157,10 @@ export function clientEventHandler(opts, nspMap, ee, bindWsHandler, namespaces, let args = [namespace, nsps[namespace], ee, isPrivate, opts] if (opts.serverType === SOCKET_IO) { - let { nspSet } = nspMap - args.push(nspSet[namespace]) + let { nspGroup } = nspMap + args.push(nspGroup[namespace]) } - Reflect.apply(bindWsHandler, null, args) + Reflect.apply(bindSocketEventHandler, null, args) } else { // a dummy placeholder // @TODO but it should be a not connect handler -- Gitee From 9a2ec2f8caa4e3970f729bfea02722bf99f59d3f Mon Sep 17 00:00:00 2001 From: joelchu Date: Fri, 13 Mar 2020 16:32:18 +0800 Subject: [PATCH 28/45] test fixed --- packages/ws-client-core/src/options/defaults.js | 2 +- packages/ws-client-core/src/options/index.js | 4 ++-- packages/ws-client-core/tests/event.test.js | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/packages/ws-client-core/src/options/defaults.js b/packages/ws-client-core/src/options/defaults.js index fb99d77a..752b813c 100644 --- a/packages/ws-client-core/src/options/defaults.js +++ b/packages/ws-client-core/src/options/defaults.js @@ -57,7 +57,7 @@ const socketCheckMap = { // [ENUM_KEY]: [JS_WS_NAME, JS_WS_SOCKET_IO_NAME, JS_PRIMUS_NAME], } -const wsCoreCheckMap = Object.assign(configCheckMap, socketAppProps) +const wsCoreCheckMap = Object.assign(configCheckMap, socketCheckMap) // constant props const wsCoreConstProps = { diff --git a/packages/ws-client-core/src/options/index.js b/packages/ws-client-core/src/options/index.js index 30c6e880..b6103330 100644 --- a/packages/ws-client-core/src/options/index.js +++ b/packages/ws-client-core/src/options/index.js @@ -6,7 +6,7 @@ import { import { wsCoreCheckMap, wsCoreConstProps, - sockeCheckMap + socketCheckMap } from './defaults' import { fixWss, @@ -22,7 +22,7 @@ import { * @return {string} the name of the socket server if any */ function checkSocketClientType(config) { - return checkConfig(config, sockeCheckMap) + return checkConfig(config, socketCheckMap) } /** diff --git a/packages/ws-client-core/tests/event.test.js b/packages/ws-client-core/tests/event.test.js index 73c4829c..4ee9b6fc 100644 --- a/packages/ws-client-core/tests/event.test.js +++ b/packages/ws-client-core/tests/event.test.js @@ -3,7 +3,7 @@ const test = require('ava') const NbEventService = require('nb-event-service') const debug = require('debug')('jsonql-ws-client:test:event') const { objDefineProps, injectToFn } = require('jsonql-utils') -const { getEventEmitter } = require('../src/utils/ee') +const { getEventEmitter } = require('../src/utils/get-event-emitter') // share methods between two test const getter = function() { return function(...args) { -- Gitee From 39c85caf181c11b672cfb776ab65711c4e981280 Mon Sep 17 00:00:00 2001 From: joelchu Date: Fri, 13 Mar 2020 20:23:57 +0800 Subject: [PATCH 29/45] update all the build script point --- packages/@jsonql/ws/module.js | 28 ++++----- packages/@jsonql/ws/package.json | 2 +- packages/@jsonql/ws/src/core/modules.js | 58 +++++++++++-------- .../@jsonql/ws/src/create-combine-client.js | 57 +++++++++++------- packages/@jsonql/ws/src/node/module.js | 23 ++++---- packages/@jsonql/ws/src/options/index.js | 4 +- 6 files changed, 96 insertions(+), 76 deletions(-) diff --git a/packages/@jsonql/ws/module.js b/packages/@jsonql/ws/module.js index e94436d8..be621141 100644 --- a/packages/@jsonql/ws/module.js +++ b/packages/@jsonql/ws/module.js @@ -1,21 +1,21 @@ // this is a new interface that takes the already check config // and init the ws client - - +// this is the new interface that will create the combine client import { - jsonqlWsClientAppProps, - jsonqlWsConstProps, - checkSocketClientType - // generateWsClient -} from './src/core/modules' + createCombineWsClientConstructor, + // straight export + checkSocketClientType, + getEventEmitter, + EventEmitterClass +} from './src/create-combine-client' +import frameworkSocketEngine from './src/core/framework-socket-engine' -// const createWsClient = generateWsClient(wsClientResolver) +const createCombineWsClient = createCombineWsClientConstructor(frameworkSocketEngine) -// export done export { - jsonqlWsClientAppProps, - jsonqlWsConstProps, - - checkSocketClientType - // export from this module + createCombineWsClient, + checkSocketClientType, + getEventEmitter, + EventEmitterClass } + diff --git a/packages/@jsonql/ws/package.json b/packages/@jsonql/ws/package.json index 61309814..c07346a2 100644 --- a/packages/@jsonql/ws/package.json +++ b/packages/@jsonql/ws/package.json @@ -52,7 +52,7 @@ "jsonql-jwt": "^1.3.9", "jsonql-params-validator": "^1.5.3", "jsonql-utils": "^1.1.3", - "jsonql-ws-client-core": "^0.8.6", + "jsonql-ws-client-core": "^0.9.0", "ws": "^7.2.3" }, "devDependencies": { diff --git a/packages/@jsonql/ws/src/core/modules.js b/packages/@jsonql/ws/src/core/modules.js index fe3d9e21..4e18596f 100644 --- a/packages/@jsonql/ws/src/core/modules.js +++ b/packages/@jsonql/ws/src/core/modules.js @@ -1,42 +1,50 @@ // We keep all the import from jsonql-ws-client-core in place // if we need to switch then just switch in one place import { - fixWss, - checkSocketClientType, - wsClientCoreAction, + // generator methods wsClientCore, + wsClientCoreAction, + // helper methods + checkSocketClientType, + // from share.js + jsonqlWsConstants, + createNspClient, createNspAuthClient, - clientEventHandler, + + triggerNamespacesOnError, + handleNamespaceOnError, + + fixWss, clearMainEmitEvt, - // props - wsCoreDefaultOptions, - wsCoreConstProps -} from '../../../../ws-client-core/index' // 'jsonql-ws-client-core' -// this module options -import { - wsClientAppProps, - wsClientConstProps -} from '../options' + getEventEmitter, + EventEmitterClass, -const jsonqlWsClientAppProps = Object.assign({}, wsCoreDefaultOptions, wsClientAppProps) -const jsonqlWsConstProps = Object.assign({}, wsCoreConstProps, wsClientConstProps) + clientEventHandler, + createCombineClient +} from '../../../../ws-client-core/index' // 'jsonql-ws-client-core' // export export { - + // generator methods + wsClientCore, + wsClientCoreAction, + // helper methods + checkSocketClientType, + // from share.js + jsonqlWsConstants, + createNspClient, createNspAuthClient, - fixWss, - checkSocketClientType, - - clientEventHandler, // <-- @BUG ? + triggerNamespacesOnError, + handleNamespaceOnError, + fixWss, clearMainEmitEvt, - wsClientCore, - wsClientCoreAction, - // props - jsonqlWsClientAppProps, - jsonqlWsConstProps + getEventEmitter, + EventEmitterClass, + + clientEventHandler, + createCombineClient } \ No newline at end of file diff --git a/packages/@jsonql/ws/src/create-combine-client.js b/packages/@jsonql/ws/src/create-combine-client.js index 4b1c4fee..5fa7ffe4 100644 --- a/packages/@jsonql/ws/src/create-combine-client.js +++ b/packages/@jsonql/ws/src/create-combine-client.js @@ -1,28 +1,41 @@ -// @NOTE how to deal with the integration with http client -// instead of using http client as a host -// we could pass the http-client into the ws client -// let the ws client to deal with the combine configuration check -// then generate the http-client --> generate the ws client -// this way, it won't be so messy, the http client just pass their -// appProps and constProps, and their main constructor api -// and here we deal with it and create less confusion what goes where -// everything will just flow one way +// this is a wrapper +// then different version (e.g. node or browser) +// just pass the engine here to create the client - -// take out from module, doesn't make sense to be there -// This method is ONLY for integration use only which means -// the options are already checked -import { wsClientCoreAction } from './core/modules' +import { + wsClientConstProps +} from './options' +import { + checkSocketClientType, + createCombineClient, + getEventEmitter, + EventEmitterClass +} from './core/modules' /** - * Take the already checked options (using part of export here) - * then generate the ws client - * @param {function} wsClientResolver configuration - * @return {function} take config return the promise resolve the ws client + * Overload the createCombineCreate to create a combine http / ws client + * @param {object} configCheckMap + * @param {object} constProps + * @return {function} to accept config then generate the client */ -export function wsClientForIntegration(wsClientResolver) { +function createCombineWsClientConstructor(frameworkSocketEngine) { + + return function createCombineWsClient(httpClientConstructor, configCheckMap, constProps) { + const localConstProps = Object.assign({}, constProps, wsClientConstProps) + + return createCombineClient( + httpClientConstructor, + frameworkSocketEngine, + configCheckMap, + localConstProps + ) + } +} - return (config) => Promise - .resolve(config) - .then(opts => wsClientCoreAction(wsClientResolver, opts)) +export { + createCombineWsClientConstructor, + // straight export + checkSocketClientType, + getEventEmitter, + EventEmitterClass } \ No newline at end of file diff --git a/packages/@jsonql/ws/src/node/module.js b/packages/@jsonql/ws/src/node/module.js index f1933061..db9a2f7c 100644 --- a/packages/@jsonql/ws/src/node/module.js +++ b/packages/@jsonql/ws/src/node/module.js @@ -1,17 +1,18 @@ // this is for node upstream client to include and construct their own client import { - jsonqlWsClientAppProps, - jsonqlWsConstProps, - checkSocketClientType - // generateWsClient -} from './src/core/modules' - + createCombineWsClientConstructor, + // straight export + checkSocketClientType, + getEventEmitter, + EventEmitterClass +} from './src/create-combine-client' +import nodeFrameworkSocketEngine from './node-framework-socket-engine' +const createCombineWsClient = createCombineWsClientConstructor(nodeFrameworkSocketEngine) export { - jsonqlWsClientAppProps, - jsonqlWsConstProps, - - checkSocketClientType - // export from this module + createCombineWsClient, + checkSocketClientType, + getEventEmitter, + EventEmitterClass } \ No newline at end of file diff --git a/packages/@jsonql/ws/src/options/index.js b/packages/@jsonql/ws/src/options/index.js index 87d30d5c..31b5a1e7 100644 --- a/packages/@jsonql/ws/src/options/index.js +++ b/packages/@jsonql/ws/src/options/index.js @@ -8,6 +8,4 @@ const wsClientConstProps = { serverType: JS_WS_NAME } -const wsClientAppProps = {} - -export { wsClientAppProps, wsClientConstProps } +export { wsClientConstProps } -- Gitee From df63a4ca0d3163bc8db126aebbf72012efadeead Mon Sep 17 00:00:00 2001 From: joelchu Date: Fri, 13 Mar 2020 20:33:03 +0800 Subject: [PATCH 30/45] update several input parameters to match the new function signatures --- packages/@jsonql/ws/package.json | 8 +++--- .../src/core/create-nsp/create-nsp-action.js | 2 +- .../ws/src/core/create-nsp/create-nsp.js | 3 ++- .../core/create-nsp/login-event-handler.js | 3 ++- .../core/create-nsp/socket-event-handler.js | 26 ++++++------------- 5 files changed, 18 insertions(+), 24 deletions(-) diff --git a/packages/@jsonql/ws/package.json b/packages/@jsonql/ws/package.json index c07346a2..dececd9a 100644 --- a/packages/@jsonql/ws/package.json +++ b/packages/@jsonql/ws/package.json @@ -1,6 +1,6 @@ { "name": "@jsonql/ws", - "version": "1.1.1", + "version": "1.2.0", "description": "jsonql WS (WebSocket) client module for browser / node", "main": "main.js", "browser": "dist/jsonql-ws.umd.js", @@ -17,12 +17,14 @@ "scripts": { "test": "ava", "prepare": "npm run build", - "build": "NODE_ENV=production npm run build:cjs && NODE_ENV=production npm run build:umd", + "build": "npm run build:cjs:prod && npm run build:umd:prod && npm run build:cjs:module:prod", "build:cjs": "TARGET=cjs rollup -c", "build:umd": "TARGET=umd rollup -c", "build:cjs:module": "TARGET=cjs-module rollup -c", + "build:cjs:prod": "NODE_ENV=production TARGET=cjs rollup -c", + "build:umd:prod": "NODE_ENV=production TARGET=umd rollup -c", "build:cjs:module:prod": "NODE_ENV=production npm run build:cjs:module", - "build:test": "npm run build:cjs && npm run build:umd", + "build:test": "npm run build:cjs && npm run build:umd && build:cjs:module", "test:browser:basic": "npm run build:umd && DEBUG=jsonql-ws-client*,server-io-core* node ./tests/browser/run-qunit.js", "test:browser:auth": "npm run build:umd && DEBUG=jsonql-ws-* NODE_ENV=ws-auth node ./tests/browser/run-qunit.js", "test:opt": "ava ./tests/opt.test.js", diff --git a/packages/@jsonql/ws/src/core/create-nsp/create-nsp-action.js b/packages/@jsonql/ws/src/core/create-nsp/create-nsp-action.js index efa53b15..c3b50b39 100644 --- a/packages/@jsonql/ws/src/core/create-nsp/create-nsp-action.js +++ b/packages/@jsonql/ws/src/core/create-nsp/create-nsp-action.js @@ -13,7 +13,7 @@ import { */ const createNspAction = function(opts, nspMap, token) { const { log } = opts - let { nspGroup, publicNamespace, namespaces } = nspMap + let { publicNamespace, namespaces } = nspMap return { nsps: (() => { 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 3eb493c5..79e1fe5a 100644 --- a/packages/@jsonql/ws/src/core/create-nsp/create-nsp.js +++ b/packages/@jsonql/ws/src/core/create-nsp/create-nsp.js @@ -16,7 +16,8 @@ import { socketEventHandler } from './socket-event-handler' */ function createNsp(opts, nspMap, ee) { // arguments for clientEventHandler - const args = [opts, nspMap, ee, socketEventHandler] + const args = [opts, ee, socketEventHandler] + // now create the nsps const { namespaces } = nspMap const { token } = opts diff --git a/packages/@jsonql/ws/src/core/create-nsp/login-event-handler.js b/packages/@jsonql/ws/src/core/create-nsp/login-event-handler.js index 07d0e7ba..89f83bce 100644 --- a/packages/@jsonql/ws/src/core/create-nsp/login-event-handler.js +++ b/packages/@jsonql/ws/src/core/create-nsp/login-event-handler.js @@ -3,7 +3,8 @@ // I think that is because it's not login then it can not be disconnect // how do we track this state globally import { LOGIN_EVENT_NAME } from 'jsonql-constants' -import { clearMainEmitEvt } from '../modules'} +import { clearMainEmitEvt } from '../modules' + /** * create a login event handler * @param {object} opts configurations diff --git a/packages/@jsonql/ws/src/core/create-nsp/socket-event-handler.js b/packages/@jsonql/ws/src/core/create-nsp/socket-event-handler.js index e68ae307..59ef2933 100644 --- a/packages/@jsonql/ws/src/core/create-nsp/socket-event-handler.js +++ b/packages/@jsonql/ws/src/core/create-nsp/socket-event-handler.js @@ -16,7 +16,9 @@ import { createEvt, extractWsPayload } from 'jsonql-utils/module' -import { createNamespaceErrorHandler } from '../../../../../ws-client-core/src/core/resolver-methods' +import { + handleNamespaceOnError +} from '../modules' /** * in some edge case we might not even have a resolverName, then @@ -25,10 +27,9 @@ import { createNamespaceErrorHandler } from '../../../../../ws-client-core/src/c * @param {string} namespace nsp * @param {string} resolverName resolver * @param {object} json decoded payload or error object - * @param {string} ON_ERROR_FN_NAME the error event name * @return {undefined} nothing return */ -const errorTypeHandler = (ee, namespace, resolverName, json, ON_ERROR_FN_NAME) => { +const errorTypeHandler = (ee, namespace, resolverName, json) => { let evt = [namespace] if (resolverName) { evt.push(resolverName) @@ -57,17 +58,6 @@ const logoutEventHandler = (ee) => { }) } -/** - * Handle the onerror callback - * @param {object} ee event emitter - * @param {string} namespace which namespace has error - * @param {*} err error object - * @return {void} - */ -const handleNamespaceOnError = (ee, namespace, err) => { - ee.$trigger(createEvt(namespace, ON_ERROR_FN_NAME), [err]) -} - /** * Binding the event to socket normally * @param {string} namespace @@ -79,7 +69,7 @@ const handleNamespaceOnError = (ee, namespace, err) => { */ export function socketEventHandler(namespace, ws, ee, isPrivate, opts) { const { log } = opts - // const log = (...args) => Reflect.apply(console.info, console, ['[socketEventHandler]'].concat(args)) + log(`log test, isPrivate:`, isPrivate) // connection open ws.onopen = function onOpenCallback() { @@ -136,19 +126,19 @@ export function socketEventHandler(namespace, ws, ee, isPrivate, opts) { // this is handled error and we won't throw it // we need to extract the error from json log(`ERROR_TYPE`) - errorTypeHandler(ee, namespace, resolverName, json, ON_ERROR_FN_NAME) + errorTypeHandler(ee, namespace, resolverName, json) 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 log('Unhandled event!', json) - errorTypeHandler(ee, namespace, resolverName, json, ON_ERROR_FN_NAME) + errorTypeHandler(ee, namespace, resolverName, json) // let error = {error: {'message': 'Unhandled event!', type}}; // ee.$trigger(createEvt(namespace, resolverName, ON_RESULT_FN_NAME), [error]) } } catch(e) { console.error(`ws.onmessage error`, e) - errorTypeHandler(ee, namespace, false, e, ON_ERROR_FN_NAME) + errorTypeHandler(ee, namespace, false, e) } } // when the server close the connection -- Gitee From d43b6aab357f7b3be9cc0c13d3aeae38b9fe3ffd Mon Sep 17 00:00:00 2001 From: joelchu Date: Fri, 13 Mar 2020 20:36:35 +0800 Subject: [PATCH 31/45] Fix the wrong naming in export --- .../ws-client-core/src/create-combine-client.js | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/packages/ws-client-core/src/create-combine-client.js b/packages/ws-client-core/src/create-combine-client.js index 11fb0e7f..676abf8a 100644 --- a/packages/ws-client-core/src/create-combine-client.js +++ b/packages/ws-client-core/src/create-combine-client.js @@ -7,20 +7,20 @@ * At the moment, the ws client module export back the `configCheckMap` and `constProps` then back in here * which is very messy. */ - -import { createCombineCheckConfig } from './options' +import { createCombineConfigCheck } from './options' import { wsClientCoreAction } from './api' import { SOCKET_NAME } from 'jsonql-constants' /** * Create a combine client - * @param {*} httpClientConstructor - * @param {*} wsClientEngine - * @param {*} configCheckMap - * @param {*} constProps + * @param {function} httpClientConstructor the method generate the http client + * @param {function} wsClientEngine the core socket engine + * @param {object} configCheckMap the configuration check map + * @param {object} constProps props that add to the config post check + * @return {function} (config) => combine client */ function createCombineClient(httpClientConstructor, wsClientEngine, configCheckMap, constProps) { - const checkConfigFn = createCombineCheckConfig(configCheckMap, constProps) + const checkConfigFn = createCombineConfigCheck(configCheckMap, constProps) /** * This will become the final interace facing the app to use */ -- Gitee From d8092e481b75c41b7a5346d939d3f6cec44e56b0 Mon Sep 17 00:00:00 2001 From: joelchu Date: Fri, 13 Mar 2020 20:58:37 +0800 Subject: [PATCH 32/45] update all the properties import and params --- packages/@jsonql/ws/src/browser-ws-client.js | 8 ++++---- packages/@jsonql/ws/src/core/modules.js | 4 ++++ packages/@jsonql/ws/src/node-ws-client.js | 7 +++---- packages/ws-client-core/index.js | 11 ++++++++++- packages/ws-client-core/src/api.js | 6 +++--- packages/ws-client-core/src/options/index.js | 4 ++-- 6 files changed, 26 insertions(+), 14 deletions(-) diff --git a/packages/@jsonql/ws/src/browser-ws-client.js b/packages/@jsonql/ws/src/browser-ws-client.js index 08e9699f..ec3757d0 100644 --- a/packages/@jsonql/ws/src/browser-ws-client.js +++ b/packages/@jsonql/ws/src/browser-ws-client.js @@ -1,10 +1,10 @@ // this is the module entry point for ES6 for client // the main will point to the node.js server side setup import { - jsonqlWsClientAppProps, - jsonqlWsConstProps, wsClientCore } from './core/modules' +import { wsClientConstProps } from './options' + import frameworkSocketEngine from './core/framework-socket-engine' @@ -12,8 +12,8 @@ import frameworkSocketEngine from './core/framework-socket-engine' export default function wsBrowserClient(config = {}, constProps = {}) { const initMethod = wsClientCore( frameworkSocketEngine, - jsonqlWsClientAppProps, - Object.assign({}, jsonqlWsConstProps, constProps) + {}, + Object.assign({}, wsClientConstProps, constProps) ) return initMethod(config) } diff --git a/packages/@jsonql/ws/src/core/modules.js b/packages/@jsonql/ws/src/core/modules.js index 4e18596f..bb9a2abf 100644 --- a/packages/@jsonql/ws/src/core/modules.js +++ b/packages/@jsonql/ws/src/core/modules.js @@ -1,6 +1,8 @@ // We keep all the import from jsonql-ws-client-core in place // if we need to switch then just switch in one place import { + wsCoreCheckMap, + wsCoreConstProps, // generator methods wsClientCore, wsClientCoreAction, @@ -26,6 +28,8 @@ import { // export export { + wsCoreCheckMap, + wsCoreConstProps, // generator methods wsClientCore, wsClientCoreAction, diff --git a/packages/@jsonql/ws/src/node-ws-client.js b/packages/@jsonql/ws/src/node-ws-client.js index 88f74375..8d1384b2 100644 --- a/packages/@jsonql/ws/src/node-ws-client.js +++ b/packages/@jsonql/ws/src/node-ws-client.js @@ -1,9 +1,8 @@ // this is the module entry point for node client import { - jsonqlWsClientAppProps, - jsonqlWsConstProps, wsClientCore } from './core/modules' +import { wsClientConstProps } from './options' import nodeFrameworkSocketEngine from './node/node-framework-socket-engine' @@ -11,8 +10,8 @@ import nodeFrameworkSocketEngine from './node/node-framework-socket-engine' export default function wsNodeClient(config = {}, constProps = {}) { const initClientMethod = wsClientCore( nodeFrameworkSocketEngine, - jsonqlWsClientAppProps, - Object.assign({}, jsonqlWsConstProps, constProps) + {}, + Object.assign({}, wsClientConstProps, constProps) ) return initClientMethod(config) } diff --git a/packages/ws-client-core/index.js b/packages/ws-client-core/index.js index 17bf1102..fadc99e2 100644 --- a/packages/ws-client-core/index.js +++ b/packages/ws-client-core/index.js @@ -1,9 +1,13 @@ // This is the module entry point + import { wsClientCore, wsClientCoreAction } from './src/api' + import { + wsCoreCheckMap, + wsCoreConstProps, checkSocketClientType } from './src/options' // these were in the share.js and now we combine into one @@ -38,13 +42,18 @@ import { // export export { + // props + wsCoreCheckMap, + wsCoreConstProps, + jsonqlWsConstants, // generator methods wsClientCore, wsClientCoreAction, // helper methods + checkSocketClientType, // from share.js - jsonqlWsConstants, + createNspClient, createNspAuthClient, diff --git a/packages/ws-client-core/src/api.js b/packages/ws-client-core/src/api.js index 92aa6cbc..c5ef2359 100644 --- a/packages/ws-client-core/src/api.js +++ b/packages/ws-client-core/src/api.js @@ -33,12 +33,12 @@ export function wsClientCoreAction(frameworkSocketEngine, config) { /** * The main interface which will generate the socket clients and map all events * @param {object} frameworkSocketEngine this is the one method export by various clients - * @param {object} [defaultOptions={}] we should do all the checking in the core instead of the client + * @param {object} [configCheckMap={}] we should do all the checking in the core instead of the client * @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(frameworkSocketEngine, defaultOptions = {}, constProps = {}) { +export function wsClientCore(frameworkSocketEngine, configCheckMap = {}, constProps = {}) { // we need to inject property to this client later - return (config = {}) => checkConfiguration(config, defaultOptions, constProps) + return (config = {}) => checkConfiguration(config, configCheckMap, constProps) .then(opts => wsClientCoreAction(frameworkSocketEngine, opts)) } diff --git a/packages/ws-client-core/src/options/index.js b/packages/ws-client-core/src/options/index.js index b6103330..33676b28 100644 --- a/packages/ws-client-core/src/options/index.js +++ b/packages/ws-client-core/src/options/index.js @@ -46,10 +46,10 @@ function createCombineConfigCheck(configCheckMap, constProps) { * @return {promise} resolve to the checked opitons */ function checkConfiguration(config, defaultOptions, constProps) { + const defaultCheckMap= Object.assign(wsCoreCheckMap, defaultOptions) const wsConstProps = Object.assign(wsCoreConstProps, constProps) - const defaultCheckOptions = Object.assign(wsCoreCheckMap, defaultOptions) - return checkConfigAsync(config, defaultCheckOptions, wsConstProps) + return checkConfigAsync(config, defaultCheckMap, wsConstProps) } /** -- Gitee From 4584e893bd21a23beb832e6a79ed10309473ba8d Mon Sep 17 00:00:00 2001 From: joelchu Date: Fri, 13 Mar 2020 21:04:20 +0800 Subject: [PATCH 33/45] build succeed --- .../@jsonql/ws/dist/jsonql-ws-client.umd.js | 8565 +++++++++++++++- .../ws/dist/jsonql-ws-client.umd.js.map | 2 +- packages/@jsonql/ws/main.js | 8544 +++++++++++++++- packages/@jsonql/ws/main.js.map | 2 +- packages/@jsonql/ws/node.js | 8620 ++++++++++++++++- packages/@jsonql/ws/node.js.map | 2 +- packages/@jsonql/ws/package.json | 2 +- .../ws/src/core/framework-socket-engine.js | 2 +- packages/@jsonql/ws/src/node/module.js | 2 +- 9 files changed, 25732 insertions(+), 9 deletions(-) diff --git a/packages/@jsonql/ws/dist/jsonql-ws-client.umd.js b/packages/@jsonql/ws/dist/jsonql-ws-client.umd.js index f0602f89..608a0761 100644 --- a/packages/@jsonql/ws/dist/jsonql-ws-client.umd.js +++ b/packages/@jsonql/ws/dist/jsonql-ws-client.umd.js @@ -1,2 +1,8565 @@ -!function(t,e){"object"==typeof exports&&"undefined"!=typeof module?module.exports=e():"function"==typeof define&&define.amd?define(e):(t=t||self).jsonqlWsClient=e()}(this,(function(){"use strict";var t="undefined"!=typeof global?global:"undefined"!=typeof self?self:"undefined"!=typeof window?window:{},e="object"==typeof t&&t&&t.Object===Object&&t,r="object"==typeof self&&self&&self.Object===Object&&self,n=e||r||Function("return this")(),o=n.Symbol;function i(t,e){for(var r=-1,n=null==t?0:t.length,o=Array(n);++r=n?t:function(t,e,r){var n=-1,o=t.length;e<0&&(e=-e>o?0:o+e),(r=r>o?o:r)<0&&(r+=o),o=e>r?0:r-e>>>0,e>>>=0;for(var i=Array(o);++n-1;);return r}(n,o),function(t,e){for(var r=t.length;r--&&j(e,t[r],0)>-1;);return r}(n,o)+1).join("")}var F=function(t){return!!a(t)||null!=t&&""!==q(t)};function M(t){return function(t){return"number"==typeof t||v(t)&&"[object Number]"==h(t)}(t)&&t!=+t}function L(t){return"string"==typeof t||!a(t)&&v(t)&&"[object String]"==h(t)}var W=function(t){return!L(t)&&!M(parseFloat(t))},J=function(t){return""!==q(t)&&L(t)},U=function(t){return null!=t&&"boolean"==typeof t},D=function(t,e){return void 0===e&&(e=!0),void 0!==t&&""!==t&&""!==q(t)&&(!1===e||!0===e&&null!==t)},H=function(t){switch(t){case"number":return W;case"string":return J;case"boolean":return U;default:return D}},I=function(t,e){return void 0===e&&(e=""),!!a(t)&&(""===e||""===q(e)||!(t.filter((function(t){return!H(e)(t)})).length>0))},G=function(t){if(t.indexOf("array.<")>-1&&t.indexOf(">")>-1){var e=t.replace("array.<","").replace(">","");return e.indexOf("|")?e.split("|"):[e]}return!1},B=function(t,e){var r=t.arg;return e.length>1?!r.filter((function(t){return!(e.length>e.filter((function(e){return!H(e)(t)})).length)})).length:e.length>e.filter((function(t){return!I(r,t)})).length};function V(t,e){return function(r){return t(e(r))}}var Y=V(Object.getPrototypeOf,Object),K=Function.prototype,Q=Object.prototype,X=K.toString,Z=Q.hasOwnProperty,tt=X.call(Object);function et(t){if(!v(t)||"[object Object]"!=h(t))return!1;var e=Y(t);if(null===e)return!0;var r=Z.call(e,"constructor")&&e.constructor;return"function"==typeof r&&r instanceof r&&X.call(r)==tt}var rt,nt=function(t,e,r){for(var n=-1,o=Object(t),i=r(t),a=i.length;a--;){var u=i[rt?a:++n];if(!1===e(o[u],u,o))break}return t};function ot(t){return v(t)&&"[object Arguments]"==h(t)}var it=Object.prototype,at=it.hasOwnProperty,ut=it.propertyIsEnumerable,ct=ot(function(){return arguments}())?ot:function(t){return v(t)&&at.call(t,"callee")&&!ut.call(t,"callee")};var st="object"==typeof exports&&exports&&!exports.nodeType&&exports,ft=st&&"object"==typeof module&&module&&!module.nodeType&&module,lt=ft&&ft.exports===st?n.Buffer:void 0,pt=(lt?lt.isBuffer:void 0)||function(){return!1},ht=/^(?:0|[1-9]\d*)$/;function vt(t,e){var r=typeof t;return!!(e=null==e?9007199254740991:e)&&("number"==r||"symbol"!=r&&ht.test(t))&&t>-1&&t%1==0&&t-1&&t%1==0&&t<=9007199254740991}var dt={};dt["[object Float32Array]"]=dt["[object Float64Array]"]=dt["[object Int8Array]"]=dt["[object Int16Array]"]=dt["[object Int32Array]"]=dt["[object Uint8Array]"]=dt["[object Uint8ClampedArray]"]=dt["[object Uint16Array]"]=dt["[object Uint32Array]"]=!0,dt["[object Arguments]"]=dt["[object Array]"]=dt["[object ArrayBuffer]"]=dt["[object Boolean]"]=dt["[object DataView]"]=dt["[object Date]"]=dt["[object Error]"]=dt["[object Function]"]=dt["[object Map]"]=dt["[object Number]"]=dt["[object Object]"]=dt["[object RegExp]"]=dt["[object Set]"]=dt["[object String]"]=dt["[object WeakMap]"]=!1;var yt,_t="object"==typeof exports&&exports&&!exports.nodeType&&exports,bt=_t&&"object"==typeof module&&module&&!module.nodeType&&module,mt=bt&&bt.exports===_t&&e.process,jt=function(){try{var t=bt&&bt.require&&bt.require("util").types;return t||mt&&mt.binding&&mt.binding("util")}catch(t){}}(),wt=jt&&jt.isTypedArray,Ot=wt?(yt=wt,function(t){return yt(t)}):function(t){return v(t)&>(t.length)&&!!dt[h(t)]},St=Object.prototype.hasOwnProperty;function Et(t,e){var r=a(t),n=!r&&ct(t),o=!r&&!n&&pt(t),i=!r&&!n&&!o&&Ot(t),u=r||n||o||i,c=u?function(t,e){for(var r=-1,n=Array(t);++r-1},Mt.prototype.set=function(t,e){var r=this.__data__,n=qt(r,t);return n<0?(++this.size,r.push([t,e])):r[n][1]=e,this};var Lt,Wt=n["__core-js_shared__"],Jt=(Lt=/[^.]+$/.exec(Wt&&Wt.keys&&Wt.keys.IE_PROTO||""))?"Symbol(src)_1."+Lt:"";var Ut=Function.prototype.toString;function Dt(t){if(null!=t){try{return Ut.call(t)}catch(t){}try{return t+""}catch(t){}}return""}var Ht=/^\[object .+?Constructor\]$/,It=Function.prototype,Gt=Object.prototype,Bt=It.toString,Vt=Gt.hasOwnProperty,Yt=RegExp("^"+Bt.call(Vt).replace(/[\\^$.*+?()[\]{}|]/g,"\\$&").replace(/hasOwnProperty|(function).*?(?=\\\()| for .+?(?=\\\])/g,"$1.*?")+"$");function Kt(t){return!(!Pt(t)||function(t){return!!Jt&&Jt in t}(t))&&(Nt(t)?Yt:Ht).test(Dt(t))}function Qt(t,e){var r=function(t,e){return null==t?void 0:t[e]}(t,e);return Kt(r)?r:void 0}var Xt=Qt(n,"Map"),Zt=Qt(Object,"create");var te=Object.prototype.hasOwnProperty;var ee=Object.prototype.hasOwnProperty;function re(t){var e=-1,r=null==t?0:t.length;for(this.clear();++eu))return!1;var s=i.get(t);if(s&&i.get(e))return s==e;var f=-1,l=!0,p=2&r?new ae:void 0;for(i.set(t,e),i.set(e,t);++fe.type.filter((function(t){var e;return void 0===r||(!1!==(e=G(t))?!B({arg:r},e):!H(t)(r))})).length)})).length}return!1},rr=function(t){function e(){for(var r=[],n=arguments.length;n--;)r[n]=arguments[n];t.apply(this,r),this.message=r[0],this.detail=r[1],this.className=e.name,t.captureStackTrace&&t.captureStackTrace(this,e)}t&&(e.__proto__=t),e.prototype=Object.create(t&&t.prototype),e.prototype.constructor=e;var r={name:{configurable:!0}};return r.name.get=function(){return"JsonqlValidationError"},Object.defineProperties(e,r),e}(Error),nr=function(t){function e(){for(var r=[],n=arguments.length;n--;)r[n]=arguments[n];t.apply(this,r),this.message=r[0],this.detail=r[1],this.className=e.name,t.captureStackTrace&&t.captureStackTrace(this,e)}t&&(e.__proto__=t),e.prototype=Object.create(t&&t.prototype),e.prototype.constructor=e;var r={name:{configurable:!0},statusCode:{configurable:!0}};return r.name.get=function(){return"JsonqlError"},r.statusCode.get=function(){return-1},Object.defineProperties(e,r),e}(Error),or=function(t,e){var r,n,o,i,a;switch(!0){case"object"===t:return o=(n=e).arg,i=n.param,a=[o],Array.isArray(i.keys)&&i.keys.length&&a.push(i.keys),!Reflect.apply(er,null,a);case"array"===t:return!I(e.arg);case!1!==(r=G(t)):return!B(e,r);default:return!H(t)(e.arg)}},ir=function(t,e){return void 0!==t?t:!0===e.optional&&void 0!==e.defaultvalue?e.defaultvalue:null},ar=function(t,e,r){var n;void 0===r&&(r=!1);var o=function(t,e){if(!I(e))throw new rr("params is not an array! Did something gone wrong when you generate the contract.json?");if(0===e.length)return[];if(!I(t))throw new rr("args is not an array! You might want to do: ES6 Array.from(arguments) or ES5 Array.prototype.slice.call(arguments)");switch(!0){case t.length==e.length:return t.map((function(t,r){return{arg:t,index:r,param:e[r]}}));case!0===e[0].variable:var r=e[0].type;return t.map((function(t,n){return{arg:t,index:n,param:e[n]||{type:r,name:"_"}}}));case t.lengthe.length:var n=e.length,o=["any"];return t.map((function(t,r){var i=r>=n||!!e[r].optional,a=e[r]||{type:o,name:"_"+r};return{arg:i?ir(t,a):t,index:r,param:a,optional:i}}));default:throw new nr("Could not understand your arguments and parameter structure!",{args:t,params:e})}}(t,e),i=o.filter((function(t){return!0===t.optional||!0===t.param.optional?function(t){var e=t.arg,r=t.param;return!!F(e)&&!(r.type.length>r.type.filter((function(e){return or(e,t)})).length)}(t):!(t.param.type.length>t.param.type.filter((function(e){return or(e,t)})).length)}));return r?((n={}).error=i,n.data=o.map((function(t){return t.arg})),n):i},ur=function(){try{var t=Qt(Object,"defineProperty");return t({},"",{}),t}catch(t){}}();function cr(t,e,r){"__proto__"==e&&ur?ur(t,e,{configurable:!0,enumerable:!0,value:r,writable:!0}):t[e]=r}function sr(t,e,r){(void 0===r||Ct(t[e],r))&&(void 0!==r||e in t)||cr(t,e,r)}var fr="object"==typeof exports&&exports&&!exports.nodeType&&exports,lr=fr&&"object"==typeof module&&module&&!module.nodeType&&module,pr=lr&&lr.exports===fr?n.Buffer:void 0,hr=pr?pr.allocUnsafe:void 0;function vr(t,e){var r,n,o=e?(r=t.buffer,n=new r.constructor(r.byteLength),new se(n).set(new se(r)),n):t.buffer;return new t.constructor(o,t.byteOffset,t.length)}var gr=Object.create,dr=function(){function t(){}return function(e){if(!Pt(e))return{};if(gr)return gr(e);t.prototype=e;var r=new t;return t.prototype=void 0,r}}();function yr(t,e){if(("constructor"!==e||"function"!=typeof t[e])&&"__proto__"!=e)return t[e]}var _r=Object.prototype.hasOwnProperty;function br(t,e,r){var n=t[e];_r.call(t,e)&&Ct(n,r)&&(void 0!==r||e in t)||cr(t,e,r)}var mr=Object.prototype.hasOwnProperty;function jr(t){if(!Pt(t))return function(t){var e=[];if(null!=t)for(var r in Object(t))e.push(r);return e}(t);var e=$t(t),r=[];for(var n in t)("constructor"!=n||!e&&mr.call(t,n))&&r.push(n);return r}function wr(t){return xt(t)?Et(t,!0):jr(t)}function Or(t){return function(t,e,r,n){var o=!r;r||(r={});for(var i=-1,a=e.length;++i0){if(++e>=800)return arguments[0]}else e=0;return t.apply(void 0,arguments)}}(Tr);function Nr(t,e){return Pr(function(t,e,r){return e=$r(void 0===e?t.length-1:e,0),function(){for(var n=arguments,o=-1,i=$r(n.length-e,0),a=Array(i);++o1?e[n-1]:void 0,i=n>2?e[2]:void 0;for(o=xr.length>3&&"function"==typeof o?(n--,o):void 0,i&&function(t,e,r){if(!Pt(r))return!1;var n=typeof e;return!!("number"==n?xt(r)&&vt(e,r.length):"string"==n&&e in r)&&Ct(r[e],t)}(e[0],e[1],i)&&(o=n<3?void 0:o,n=1),t=Object(t);++r0;)e[r]=arguments[r+1];if(this.logger("($queue) get called"),!0===this.__suspend_state__){if(on(this.__pattern__)){var n=this.__pattern__.test(t);if(!n)return!1}this.logger("($queue) added to $queue",e),this.queueStore.add([t].concat(e))}return!!this.__suspend_state__},cn.$queues.get=function(){var t=this.queueStore.size;return this.logger("($queues)","size: "+t),t>0?Array.from(this.queueStore):[]},un.prototype.__suspend__=function(t){if("boolean"!=typeof t)throw new Error("$suspend only accept Boolean value! we got "+typeof t);var e=this.__suspend_state__;this.__suspend_state__=t,this.logger('($suspend) Change from "'+e+'" --\x3e "'+t+'"'),!0===e&&!1===t&&this.__release__()},un.prototype.__release__=function(){var t=this,e=this.queueStore.size,r=this.__pattern__;if(this.__pattern__=null,this.logger("(release) was called with "+e+(r?' for "'+r+'"':"")+" item"+(e>1?"s":"")),e>0){var n=Array.from(this.queueStore);this.queueStore.clear(),this.logger("(release queue)",n),n.forEach((function(e){t.logger(e),Reflect.apply(t.$trigger,t,e)})),this.logger("Release size "+this.queueStore.size)}return e},Object.defineProperties(un.prototype,cn);var sn=function(t){function e(e){if("function"!=typeof e)throw new Error("Just die here the logger is not a function!");e("---\x3e Create a new EventEmitter <---"),t.call(this,{logger:e})}t&&(e.__proto__=t),e.prototype=Object.create(t&&t.prototype),e.prototype.constructor=e;var r={name:{configurable:!0}};return r.name.get=function(){return"jsonql-ws-client-core"},Object.defineProperties(e.prototype,r),e}(function(t){function e(e){void 0===e&&(e={}),t.call(this,e)}t&&(e.__proto__=t),e.prototype=Object.create(t&&t.prototype),e.prototype.constructor=e;var r={$name:{configurable:!0},is:{configurable:!0},$done:{configurable:!0}};return e.prototype.logger=function(){},r.$name.get=function(){return"to1source-event"},r.is.get=function(){return this.$name},e.prototype.$on=function(t,e,r){var n=this;void 0===r&&(r=null);this.validate(t,e);var o=this.takeFromStore(t);if(!1===o)return this.logger('($on) "'+t+'" is not in lazy store'),this.addToNormalStore(t,"on",e,r);this.logger("($on) "+t+" found in lazy store");var i=0;return o.forEach((function(o){var a=o[0],u=o[1],c=o[2];if(c&&"on"!==c)throw new Error(en+" "+c);n.logger("($on)",'call run "'+t+'"'),n.run(e,a,r||u),i+=n.addToNormalStore(t,"on",e,r||u)})),this.logger("($on) return size "+i),i},e.prototype.$once=function(t,e,r){void 0===r&&(r=null),this.validate(t,e);var n=this.takeFromStore(t);this.normalStore;if(!1===n)return this.logger('($once) "'+t+'" is not in the lazy store'),this.addToNormalStore(t,"once",e,r);this.logger("($once)",n);var o=Array.from(n)[0],i=o[0],a=o[1],u=o[2];if(u&&"once"!==u)throw new Error(en+" "+u);this.logger("($once)",'call run "'+t+'"'),this.run(e,i,r||a),this.$off(t)},e.prototype.$only=function(t,e,r){var n=this;void 0===r&&(r=null),this.validate(t,e);var o=!1,i=this.takeFromStore(t);(this.normalStore.has(t)||(this.logger('($only) "'+t+'" add to normalStore'),o=this.addToNormalStore(t,"only",e,r)),!1!==i)&&(this.logger('($only) "'+t+'" found data in lazy store to execute'),Array.from(i).forEach((function(o){var i=o[0],a=o[1],u=o[2];if(u&&"only"!==u)throw new Error(en+" "+u);n.logger('($only) call run "'+t+'"'),n.run(e,i,r||a)})));return o},e.prototype.$onlyOnce=function(t,e,r){void 0===r&&(r=null),this.validate(t,e);var n=!1,o=this.takeFromStore(t);if(this.normalStore.has(t)||(this.logger('($onlyOnce) "'+t+'" add to normalStore'),n=this.addToNormalStore(t,"onlyOnce",e,r)),!1!==o){this.logger("($onlyOnce)",o);var i=Array.from(o)[0],a=i[0],u=i[1],c=i[2];if(c&&"onlyOnce"!==c)throw new Error(en+" "+c);this.logger('($onlyOnce) call run "'+t+'"'),this.run(e,a,r||u),this.$off(t)}return n},e.prototype.$replace=function(t,e,r,n){if(void 0===r&&(r=null),void 0===n&&(n="on"),this.validateType(n)){this.$off(t);var o=this["$"+n];return this.logger("($replace)",t,e),Reflect.apply(o,this,[t,e,r])}throw new Error(n+" is not supported!")},e.prototype.$trigger=function(t,e,r,n){void 0===e&&(e=[]),void 0===r&&(r=null),void 0===n&&(n=!1),this.validateEvt(t);var o=0,i=this.normalStore;if(this.logger("($trigger) normalStore",i),i.has(t)){if(this.logger('($trigger) "'+t+'" found'),this.$queue(t,e,r,n))return this.logger('($trigger) Currently suspended "'+t+'" added to queue, nothing executed. Exit now.'),!1;for(var a=Array.from(i.get(t)),u=a.length,c=!1,s=0;s0;)n[o]=arguments[o+2];if(t.has(e)?(this.logger('(addToStore) "'+e+'" existed'),r=t.get(e)):(this.logger('(addToStore) create new Set for "'+e+'"'),r=new Set),n.length>2)if(Array.isArray(n[0])){var i=n[2];this.checkTypeInLazyStore(e,i)||r.add(n)}else this.checkContentExist(n,r)||(this.logger("(addToStore) insert new",n),r.add(n));else r.add(n);return t.set(e,r),[t,r.size]},e.prototype.checkContentExist=function(t,e){return!!Array.from(e).filter((function(e){return e[0]===t[0]})).length},e.prototype.checkTypeInStore=function(t,e){this.validateEvt(t,e);var r=this.$get(t,!0);return!1===r||!r.filter((function(t){var r=t[3];return e!==r})).length},e.prototype.checkTypeInLazyStore=function(t,e){this.validateEvt(t,e);var r=this.lazyStore.get(t);return this.logger("(checkTypeInLazyStore)",r),!!r&&!!Array.from(r).filter((function(t){return t[2]!==e})).length},e.prototype.addToNormalStore=function(t,e,r,n){if(void 0===n&&(n=null),this.logger('(addToNormalStore) try to add "'+e+'" --\x3e "'+t+'" to normal store'),this.checkTypeInStore(t,e)){this.logger("(addToNormalStore)",'"'+e+'" --\x3e "'+t+'" can add to normal store');var o=this.hashFnToKey(r),i=[this.normalStore,t,o,r,n,e],a=Reflect.apply(this.addToStore,this,i),u=a[0],c=a[1];return this.normalStore=u,c}return!1},e.prototype.addToLazyStore=function(t,e,r,n){void 0===e&&(e=[]),void 0===r&&(r=null),void 0===n&&(n=!1);var o=[this.lazyStore,t,this.toArray(e),r];n&&o.push(n);var i=Reflect.apply(this.addToStore,this,o),a=i[0],u=i[1];return this.lazyStore=a,this.logger("(addToLazyStore) size: "+u),u},e.prototype.toArray=function(t){return Array.isArray(t)?t:[t]},r.normalStore.set=function(t){rn.set(this,t)},r.normalStore.get=function(){return rn.get(this)},r.lazyStore.set=function(t){nn.set(this,t)},r.lazyStore.get=function(){return nn.get(this)},e.prototype.hashFnToKey=function(t){return function(t){return t.split("").reduce((function(t,e){return(t=(t<<5)-t+e.charCodeAt(0))&t}),0)}(t.toString())+""},Object.defineProperties(e.prototype,r),e}(un))),fn=function(t){return a(t)?t:[t]},ln=function(t,e){try{var r=Object.keys(t);return n=e,!!r.filter((function(t){return t===n})).length}catch(t){return!1}var n},pn=function(){for(var t=[],e=arguments.length;e--;)t[e]=arguments[e];return t.join("_")},hn=function(t){if("function"==typeof t)return!0;console.error("Expect to be Function type! Got "+typeof t)},vn=function(){return!1},gn=function(t){for(var e=[],r=arguments.length-1;r-- >0;)e[r]=arguments[r+1];return function(){for(var r=[],n=arguments.length;n--;)r[n]=arguments[n];return e.reduce((function(t,e){return Reflect.apply(e,null,fn(t))}),Reflect.apply(t,null,r))}};function dn(t,e,r,n){return void 0===n&&(n=null),void 0===Object.getOwnPropertyDescriptor(t,e)&&Object.defineProperty(t,e,{set:r,get:null===n?function(){return null}:n}),t}function yn(t,e,r,n){void 0===n&&(n=!1);var o=function(t,e){var r=Object.getOwnPropertyDescriptor(t,e);return void 0!==r&&r.value?r.value:r}(t,e);return!1===n&&void 0!==o||Object.defineProperty(t,e,{value:r,writable:n}),t}var _n=function(t){function e(){for(var r=[],n=arguments.length;n--;)r[n]=arguments[n];t.apply(this,r),this.message=r[0],this.detail=r[1],this.className=e.name,t.captureStackTrace&&t.captureStackTrace(this,e)}t&&(e.__proto__=t),e.prototype=Object.create(t&&t.prototype),e.prototype.constructor=e;var r={statusCode:{configurable:!0},name:{configurable:!0}};return r.statusCode.get=function(){return 406},r.name.get=function(){return"Jsonql406Error"},Object.defineProperties(e,r),e}(Error),bn=function(t){function e(){for(var r=[],n=arguments.length;n--;)r[n]=arguments[n];t.apply(this,r),this.message=r[0],this.detail=r[1],this.className=e.name,t.captureStackTrace&&t.captureStackTrace(this,e)}t&&(e.__proto__=t),e.prototype=Object.create(t&&t.prototype),e.prototype.constructor=e;var r={statusCode:{configurable:!0},name:{configurable:!0}};return r.statusCode.get=function(){return 500},r.name.get=function(){return"Jsonql500Error"},Object.defineProperties(e,r),e}(Error),mn=function(t){function e(){for(var r=[],n=arguments.length;n--;)r[n]=arguments[n];t.apply(this,r),this.message=r[0],this.detail=r[1],this.className=e.name,t.captureStackTrace&&t.captureStackTrace(this,e)}t&&(e.__proto__=t),e.prototype=Object.create(t&&t.prototype),e.prototype.constructor=e;var r={statusCode:{configurable:!0},name:{configurable:!0}};return r.statusCode.get=function(){return 403},r.name.get=function(){return"JsonqlForbiddenError"},Object.defineProperties(e,r),e}(Error),jn=function(t){function e(){for(var r=[],n=arguments.length;n--;)r[n]=arguments[n];t.apply(this,r),this.message=r[0],this.detail=r[1],this.className=e.name,t.captureStackTrace&&t.captureStackTrace(this,e)}t&&(e.__proto__=t),e.prototype=Object.create(t&&t.prototype),e.prototype.constructor=e;var r={statusCode:{configurable:!0},name:{configurable:!0}};return r.statusCode.get=function(){return 401},r.name.get=function(){return"JsonqlAuthorisationError"},Object.defineProperties(e,r),e}(Error),wn=function(t){function e(){for(var r=[],n=arguments.length;n--;)r[n]=arguments[n];t.apply(this,r),this.message=r[0],this.detail=r[1],this.className=e.name,t.captureStackTrace&&t.captureStackTrace(this,e)}t&&(e.__proto__=t),e.prototype=Object.create(t&&t.prototype),e.prototype.constructor=e;var r={statusCode:{configurable:!0},name:{configurable:!0}};return r.statusCode.get=function(){return 401},r.name.get=function(){return"JsonqlContractAuthError"},Object.defineProperties(e,r),e}(Error),On=function(t){function e(){for(var r=[],n=arguments.length;n--;)r[n]=arguments[n];t.apply(this,r),this.message=r[0],this.detail=r[1],this.className=e.name,t.captureStackTrace&&t.captureStackTrace(this,e)}t&&(e.__proto__=t),e.prototype=Object.create(t&&t.prototype),e.prototype.constructor=e;var r={statusCode:{configurable:!0},name:{configurable:!0}};return r.statusCode.get=function(){return 500},r.name.get=function(){return"JsonqlResolverAppError"},Object.defineProperties(e,r),e}(Error),Sn=function(t){function e(){for(var r=[],n=arguments.length;n--;)r[n]=arguments[n];t.apply(this,r),this.message=r[0],this.detail=r[1],this.className=e.name,t.captureStackTrace&&t.captureStackTrace(this,e)}t&&(e.__proto__=t),e.prototype=Object.create(t&&t.prototype),e.prototype.constructor=e;var r={statusCode:{configurable:!0},name:{configurable:!0}};return r.statusCode.get=function(){return 404},r.name.get=function(){return"JsonqlResolverNotFoundError"},Object.defineProperties(e,r),e}(Error),En=function(t){function e(r,n){t.call(this,n),this.statusCode=r,this.className=e.name}t&&(e.__proto__=t),e.prototype=Object.create(t&&t.prototype),e.prototype.constructor=e;var r={name:{configurable:!0}};return r.name.get=function(){return"JsonqlServerError"},Object.defineProperties(e,r),e}(Error);function kn(t){if(Array.isArray(t))throw new rr("",t);var e=t.message||"No message",r=t.detail||t;switch(!0){case t instanceof _n:throw new _n(e,r);case t instanceof bn:throw new bn(e,r);case t instanceof mn:throw new mn(e,r);case t instanceof jn:throw new jn(e,r);case t instanceof wn:throw new wn(e,r);case t instanceof On:throw new On(e,r);case t instanceof Sn:throw new Sn(e,r);case t instanceof Dr:throw new Dr(e,r);case t instanceof Hr:throw new Hr(e,r);case t instanceof Ir:throw new Ir(e,r);case t instanceof rr:throw new rr(e,r);case t instanceof En:throw new En(e,r);default:throw new nr(e,r)}}function $n(t){var e=function(t){return!!ln(t,"socket")&&t.socket}(t);if(!1===e)throw new JsonqlError("groupByNamespace","socket not found in contract!");var r={nspGroup:{},publicNamespace:null,size:0};for(var n in e){var o=e[n],i=o.namespace;i&&(r.nspGroup[i]||(++r.size,r.nspGroup[i]={}),r.nspGroup[i][n]=o,!r.publicNamespace&&o.public&&(r.publicNamespace=i))}return r}var Tn=function(t){var e=t.toLowerCase();return e.indexOf("http")>-1?e.indexOf("https")>-1?e.replace("https","wss"):e.replace("http","ws"):e},An=function(t,e){fn(e).forEach((function(e){t.$off(pn(e,"emit_reply"))}))},Pn=function(t,e,r){return[yn(t,e.loginHandlerName,(function(t){if(t&&Yr(t))return e.log("Received __login__ with "+t),r.$trigger("__login__",[t]);throw new rr(e.loginHandlerName,"Unexpected token "+t)})),e,r]},Nn=function(t,e,r){return[yn(t,e.logoutHandlerName,(function(){for(var t=[],e=arguments.length;e--;)t[e]=arguments[e];r.$trigger("__logout__",t)})),e,r]},xn=function(t,e,r){return[dn(t,"onLogin",(function(t){hn(t)&&r.$only("onLogin",t)})),e,r]};function zn(t,e,r){return gn(Pn,Nn,xn)(t,e,r)}function Rn(t,e,r){ln(t,"error")?r(t.error):ln(t,"data")?e(t.data):r({message:"UKNNOWN RESULT!",error:t})}function Cn(t,e,r,n,o){void 0===n&&(n=[]);var i=pn(e,"emit_reply");return o("actionCall: "+i+" --\x3e "+r,n),t.$trigger(i,[r,fn(n)]),new Promise((function(n,i){var a=pn(e,r,"onResult");t.$on(a,(function(t){o("got the first result",t),Rn(t,n,i)}))}))}var qn,Fn,Mn,Ln=function(t,e,r,n,o,i){return dn(t,"send",vn,(function(){return function(){for(var t=[],a=arguments.length;a--;)t[a]=arguments[a];return Kr(t,o.params,!0).then((function(t){return i(r,n,t),Cn(e,r,n,t,_log)})).catch((function(t){i("send error",t),e.$call(pn(r,n,"onError"),[new rr(n,t)])}))}}))},Wn=function(t,e,r,n,o,i){return[yn(t,"myNamespace",r),e,r,n,o,i]},Jn=function(t,e,r,n,o,i){return[dn(t,"onResult",(function(t){hn(t)&&e.$on(pn(r,n,"onResult"),(function(o){Rn(o,t,(function(t){i('Catch error: "'+n+'"',t),e.$trigger(pn(r,n,"onError"),t)}))}))})),e,r,n,o,i]},Un=function(t,e,r,n,o,i){return[dn(t,"onMessage",(function(t){if(hn(t)){e.$only(pn(r,n,"onMessage"),(function(o){Rn(o,t,(function(t){i('Catch error: "'+n+'"',t),e.$trigger(pn(r,n,"onError"),t)}))}))}})),e,r,n,o,i]},Dn=function(t,e,r,n,o,i){return[dn(t,"onError",(function(t){hn(t)&&e.$only(pn(r,n,"onError"),t)})),e,r,n,o,i]};function Hn(t,e,r,n,o,i){var a=[Wn,Jn,Un,Dn,Ln],u=Reflect.apply(gn,null,a),c=[n,o,t,e,r,i];return Reflect.apply(u,null,c)}function In(t,e,r,n,o){return function(){for(var i=[],a=arguments.length;a--;)i[a]=arguments[a];return Kr(i,n.params,!0).then((function(n){return Cn(t,e,r,n,o)})).catch(kn)}}function Gn(t,e,r){var n={},o=t.log;for(var i in r){var a=r[i];for(var u in a){var c=a[u];n=yn(n,u,Hn(i,u,c,In(e,i,u,c,o),e,o))}}return[n,t,e,r]}function Bn(t,e,r,n){return[dn(t,"onError",(function(t){if(hn(t))for(var e in n)r.$on(pn(e,"onError"),t)})),e,r]}function Vn(t,e,r){return[dn(t,"onReady",(function(t){hn(t)&&r.$on("onReady",t)})),e,r]}function Yn(t,e,r){var n=function(t,e,r){return yn(t,e.disconnectHandlerName,(function(){for(var t=[],e=arguments.length;e--;)t[e]=arguments[e];r.$trigger("__disconnect__",t)}))}(t,e,r);return e.log("---\x3e The final step to return the ws-client <---"),n.verifyEventEmitter=function(){return r.is},n.eventEmitter=e.eventEmitter,n.log=e.log,n}var Kn=["roundtip","handshake"],Qn={standalone:Qr(!1,["boolean"]),debugOn:Qr(!1,["boolean"]),loginHandlerName:Qr("login",["string"]),logoutHandlerName:Qr("logout",["string"]),disconnectHandlerName:Qr("disconnect",["string"]),switchUserHandlerName:Qr("switch-user",["string"]),loginMethod:Qr("handshake",["string"],(qn={},qn.enumv=Kn,qn)),useJwt:Qr(!0,["boolean","string"]),authStrKey:Qr(null,["string"]),hostname:Qr(!1,["string"]),namespace:Qr("jsonql",["string"]),wsOptions:Qr({},["object"]),contract:Qr({},["object"],(Fn={},Fn.checker=function(t){return!!function(t){return et(t)&&(ln(t,"query")||ln(t,"mutation")||ln(t,"socket"))}(t)&&t},Fn)),enableAuth:Qr(!1,["boolean"]),token:Qr(!1,["string"])},Xn={};Xn.serverType=Qr(null,["string"],((Mn={}).alias="socketClientType",Mn));var Zn=Object.assign(Qn,Xn),to={log:null,eventEmitter:null,nspClient:null,nspAuthClient:null,wssPath:""};function eo(t){return Promise.resolve(t).then((function(t){return t.hostname||(t.hostname=function(){try{return[window.location.protocol,window.location.host].join("//")}catch(t){throw new rr(t)}}()),t.wssPath=Tn([t.hostname,t.namespace].join("/"),t.serverType),t.log=tn(t),t.eventEmitter=function(t){var e=t.log,r=t.eventEmitter;return r?(e("eventEmitter is:",r.name),r):new sn(t.log)}(t),t}))}function ro(t){return{opts:t,nspMap:(e=t,r=e.contract,n=e.enableAuth,o=function(t){var e="jsonql";return t.enableAuth?[[e,t.publicNamespace].join("/"),[e,t.privateNamespace].join("/")]:[e]}(e),i=n?$n(r):function(t,e){var r,n={};for(var o in t){var i=t[o];n[o]=i}return{size:1,nspGroup:(r={},r[e]=n,r),publicNamespace:e}}(r.socket,o[0]),Object.assign(i,{namespaces:o})),ee:t.eventEmitter};var e,r,n,o,i}function no(t,e){return eo(e).then(ro).then((function(e){var r=e.opts,n=e.nspMap,o=e.ee;return t(r,n,o)})).then((function(t){return function(t,e,r){var n=[Gn,Bn,Vn];return t.enableAuth&&n.push(zn),n.push(Yn),Reflect.apply(gn,null,n)(t,r,e.nspGroup)}(t.opts,t.nspMap,t.ee)})).catch((function(t){console.error("jsonql-ws-core-client init error",t)}))}function oo(t,e,r){return void 0===e&&(e={}),void 0===r&&(r={}),function(n){return void 0===n&&(n={}),function(t,e,r){var n=Object.assign(to,r),o=Object.assign(Zn,e);return Xr(t,o,n)}(n,e,r).then((function(e){return no(t,e)}))}}function io(t,e){var r=e.hostname,n=e.wssPath,o=e.wsOptions;return(0,e.nspClient)(t?[r,t].join("/"):n,o)}function ao(t,e,r){e.forEach((function(e){t.$trigger(pn(e,"onError"),[{message:r,namespace:e}])}))}var uo=function(t,e,r){var n=r.log;e.$only(pn(t,"emit_reply"),(function(r,o){n("[notLoginHandler] hijack the ws call",t,r,o);var i={message:"NOT LOGIN"};e.$call(pn(t,r,"onError"),[i]),e.$call(pn(t,r,"onResult"),[{error:i}])}))},co=function(t){return t.length>1&&t[0]},so=function(t,e,r,n){var o=n.log;r.$on("__disconnect__",(function(){ao(r,e,"__disconnect__"),e.forEach((function(e){o("disconnect from "+e),An(r,e),t[e]=null,function(t,e,r){var n=r.log;e.$only(pn(t,"emit_reply"),(function(r,o){n("[disconnectedHandler] hijack the ws call",t,r,o);var i={message:"You have disconnected from the socket server, please reconnect."};e.$call(pn(t,r,"onError"),[i]),e.$call(pn(t,r,"onResult"),[{error:i}])}))}(e,r,n)}))}))};function fo(t,e,r,n,o,i){var a=co(o),u=!1,c=!1,s=t.log;o.forEach((function(o){if(u=a===o,c||(c=u),i[o]){s("[call bindWsHandler]",u,o);var f=[o,i[o],r,u,t];if("socket.io"===t.serverType){var l=e.nspSet;f.push(l[o])}Reflect.apply(n,null,f)}else uo(o,r,t)})),c&&(s("Has private and add logoutEvtHandler"),function(t,e,r,n){var o=n.log;r.$on("__logout__",(function(){var i=co(e);o("__logout__ event triggered"),ao(r,[i],"__logout__"),o("logout from "+i),An(r,i),t[i]=null,uo(i,r,n)}))}(i,o,r,t)),so(i,o,r,t)}var lo={version:"version: 1.1.1 module: umd",serverType:"ws"},po=Object.assign({},Zn,{}),ho=Object.assign({},to,lo),vo=null;"undefined"!=typeof WebSocket?vo=WebSocket:"undefined"!=typeof MozWebSocket?vo=MozWebSocket:void 0!==t?vo=t.WebSocket||t.MozWebSocket:"undefined"!=typeof window?vo=window.WebSocket||window.MozWebSocket:"undefined"!=typeof self&&(vo=self.WebSocket||self.MozWebSocket);var go=vo;function yo(t,e){return void 0===e&&(e=!1),!1===e?function(e){return new t(Tn(e))}:function(e,r){var n=Tn(e),o=r&&"string"==typeof r?n+"?token="+r:n;try{return new t(o)}catch(t){return console.error("WebSocket Connection Error",t),!1}}}var _o=Array.isArray,bo="object"==typeof t&&t&&t.Object===Object&&t,mo="object"==typeof self&&self&&self.Object===Object&&self,jo=(bo||mo||Function("return this")()).Symbol,wo=Object.prototype,Oo=wo.hasOwnProperty,So=wo.toString,Eo=jo?jo.toStringTag:void 0;var ko=Object.prototype.toString;var $o=jo?jo.toStringTag:void 0;function To(t){return null==t?void 0===t?"[object Undefined]":"[object Null]":$o&&$o in Object(t)?function(t){var e=Oo.call(t,Eo),r=t[Eo];try{t[Eo]=void 0;var n=!0}catch(t){}var o=So.call(t);return n&&(e?t[Eo]=r:delete t[Eo]),o}(t):function(t){return ko.call(t)}(t)}function Ao(t){return null!=t&&"object"==typeof t}var Po=jo?jo.prototype:void 0,No=Po?Po.toString:void 0;function xo(t){if("string"==typeof t)return t;if(_o(t))return function(t,e){for(var r=-1,n=null==t?0:t.length,o=Array(n);++r=n?t:function(t,e,r){var n=-1,o=t.length;e<0&&(e=-e>o?0:o+e),(r=r>o?o:r)<0&&(r+=o),o=e>r?0:r-e>>>0,e>>>=0;for(var i=Array(o);++n-1;);return r}(o,i),function(t,e){for(var r=t.length;r--&&Co(e,t[r],0)>-1;);return r}(o,i)+1).join("")}var Ko=function(){for(var t=[],e=arguments.length;e--;)t[e]=arguments[e];return t.join("_")},Qo=function(t){function e(){for(var r=[],n=arguments.length;n--;)r[n]=arguments[n];t.apply(this,r),this.message=r[0],this.detail=r[1],this.className=e.name,t.captureStackTrace&&t.captureStackTrace(this,e)}t&&(e.__proto__=t),e.prototype=Object.create(t&&t.prototype),e.prototype.constructor=e;var r={name:{configurable:!0}};return r.name.get=function(){return"JsonqlValidationError"},Object.defineProperties(e,r),e}(Error),Xo=function(t){function e(){for(var r=[],n=arguments.length;n--;)r[n]=arguments[n];t.apply(this,r),this.message=r[0],this.detail=r[1],this.className=e.name,t.captureStackTrace&&t.captureStackTrace(this,e)}t&&(e.__proto__=t),e.prototype=Object.create(t&&t.prototype),e.prototype.constructor=e;var r={name:{configurable:!0},statusCode:{configurable:!0}};return r.name.get=function(){return"JsonqlError"},r.statusCode.get=function(){return-1},Object.defineProperties(e,r),e}(Error),Zo=function(t){void 0===t&&(t=!1);var e=Date.now();return t?Math.floor(e/1e3):e};function ti(t){return"string"==typeof t||!_o(t)&&Ao(t)&&"[object String]"==To(t)}function ei(t,e,r){if(void 0===e&&(e=[]),void 0===r&&(r=!1),ti(t)&&_o(e)){var n=function(t){var e;return(e={}).args=t,e}(e);return!0===r?n:function(t,e){var r;return(r={})[t]=e,r.TS=[Zo()],r}(t,n)}throw new Qo("[createQuery] expect resolverName to be string and args to be array!",{resolverName:t,args:e})}var ri=function(t){return""!==Yo(t)&&ti(t)},ni=["__reply__","__event__","__data__"],oi=function(t){var e=t.data;return!!e&&(ni.filter((function(t){return function(t,e){try{var r=Object.keys(t);return n=e,!!r.filter((function(t){return t===n})).length}catch(t){return!1}var n}(e,t)})).length===ni.length&&e)},ii=function(t,e,r,n,o){var i=[e];r&&i.push(r),i.push(o);var a=Reflect.apply(Ko,null,i),u=n.data||n;t.$trigger(a,[u])};function ai(t,e,r,n,o){var i=o.log;i("log test, isPrivate:",n),e.onopen=function(){i("ws.onopen listened"),r.$call("onReady",t),n&&(i("isPrivate and fire the onLogin"),r.$call("onLogin",t)),r.$only(Ko(t,"emit_reply"),(function(t,r){var n=function(t,e,r){return void 0===e&&(e=[]),void 0===r&&(r=!1),JSON.stringify(ei(t,e,r))}(t,r);i("calling server",t,r,n),e.send(n)}))},e.onmessage=function(e){try{var n=function(t){var e,r=t.data,n=ri(r)?JSON.parse(r):r;if(!1!==(e=oi(n)))return{resolverName:e.__event__,data:e.__data__,type:e.__reply__};throw new Xo("payload can not be decoded",t)}(e),o=n.resolverName,a=n.type;switch(i("Hear from server",a,n),a){case"emit_reply":var u=Ko(t,o,"onMessage"),c=r.$trigger(u,[n]);i("EMIT_REPLY_TYPE",u,c);break;case"acknowledge_reply":var s=Ko(t,o,"onResult"),f=r.$trigger(s,[n]);i("ACKNOWLEDGE_REPLY_TYPE",s,f);break;case"error":i("ERROR_TYPE"),ii(r,t,o,n,"onError");break;default:i("Unhandled event!",n),ii(r,t,o,n,"onError")}}catch(e){console.error("ws.onmessage error",e),ii(r,t,!1,e,"onError")}},e.onclose=function(){i("ws.onclose callback")},e.onerror=function(e){i("ws.onerror",e),r.$trigger(Ko(t,"onError"),[e])},n&&r.$on("__logout__",(function(){try{i("terminate ws connection"),e.terminate()}catch(t){console.error("ws.terminate error",t)}}))}var ui=function(t,e,r){var n,o=t.log,i=e.nspGroup,a=e.publicNamespace,u=!1,c=[],s={};if(t.enableAuth)u=!0,s=(c=function(t,e){var r=[];for(var n in t)n===e?r[1]=n:r[0]=n;return r}(i,a)).map((function(e,n){var i,a,u;return 0===n?r?(t.token=r,o("create createNspAuthClient at run time"),(i={})[e]=function(t,e){var r=e.hostname,n=e.wssPath,o=e.token,i=e.wsOptions,a=e.nspAuthClient,u=t?[r,t].join("/"):n;if(o&&"string"!=typeof o)throw new Error("Expect token to be string, but got "+o);return a(u,o,i)}(e,t),i):((a={})[e]=!1,a):((u={})[e]=io(e,t),u)})).reduce((function(t,e){return Object.assign(t,e)}),{});else{var f=(n=i,console.error("This method is going to be deprectead in the next release, please use getResolverFromPayload instead"),Object.keys(n)[0]);c.push(f),s[f]=io(!1,t)}return{nsps:s,namespaces:c,loginRequired:u}};function ci(t,e,r,n){var o=n.log;t.$only("__login__",(function(i){o("createClient LOGIN_EVENT_NAME $only handler"),An(t,e);var a=ui(n,r,i);Reflect.apply(fo,null,args.concat([a.namespaces,a.nsps]))}))}var si,fi,li,pi=(fi=yo(si=go),li=yo(si,!0),function(t,e,r){t.nspClient=fi,t.nspAuthClient=li;var n=t.log;return n&&"function"==typeof n&&(n("@jsonql/ws ee",r.name),n("@jsonql/ws createClientResolver",t)),function(t,e,r){var n=[t,e,r,ai],o=t.token,i=(t.log,ui(t,e,o)),a=i.nsps,u=i.namespaces,c=i.loginRequired;return Reflect.apply(fo,null,n.concat([u,a])),c&&ci(r,u,e,t),{opts:t,nspMap:e,ee:r}}(t,e,r)});return function(t,e){return void 0===t&&(t={}),void 0===e&&(e={}),oo(pi,po,Object.assign({},ho,e))(t)}})); +(function (global, factory) { + typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory() : + typeof define === 'function' && define.amd ? define(factory) : + (global = global || self, global.jsonqlWsClient = factory()); +}(this, (function () { 'use strict'; + + var global$1 = (typeof global !== "undefined" ? global : + typeof self !== "undefined" ? self : + typeof window !== "undefined" ? window : {}); + + /** Detect free variable `global` from Node.js. */ + var freeGlobal = typeof global$1 == 'object' && global$1 && global$1.Object === Object && global$1; + + /** Detect free variable `self`. */ + var freeSelf = typeof self == 'object' && self && self.Object === Object && self; + + /** Used as a reference to the global object. */ + var root = freeGlobal || freeSelf || Function('return this')(); + + /** Built-in value references. */ + var Symbol = root.Symbol; + + /** + * A specialized version of `_.map` for arrays without support for iteratee + * shorthands. + * + * @private + * @param {Array} [array] The array to iterate over. + * @param {Function} iteratee The function invoked per iteration. + * @returns {Array} Returns the new mapped array. + */ + function arrayMap(array, iteratee) { + var index = -1, + length = array == null ? 0 : array.length, + result = Array(length); + + while (++index < length) { + result[index] = iteratee(array[index], index, array); + } + return result; + } + + /** + * Checks if `value` is classified as an `Array` object. + * + * @static + * @memberOf _ + * @since 0.1.0 + * @category Lang + * @param {*} value The value to check. + * @returns {boolean} Returns `true` if `value` is an array, else `false`. + * @example + * + * _.isArray([1, 2, 3]); + * // => true + * + * _.isArray(document.body.children); + * // => false + * + * _.isArray('abc'); + * // => false + * + * _.isArray(_.noop); + * // => false + */ + var isArray = Array.isArray; + + /** Used for built-in method references. */ + var objectProto = Object.prototype; + + /** Used to check objects for own properties. */ + var hasOwnProperty = objectProto.hasOwnProperty; + + /** + * Used to resolve the + * [`toStringTag`](http://ecma-international.org/ecma-262/7.0/#sec-object.prototype.tostring) + * of values. + */ + var nativeObjectToString = objectProto.toString; + + /** Built-in value references. */ + var symToStringTag = Symbol ? Symbol.toStringTag : undefined; + + /** + * A specialized version of `baseGetTag` which ignores `Symbol.toStringTag` values. + * + * @private + * @param {*} value The value to query. + * @returns {string} Returns the raw `toStringTag`. + */ + function getRawTag(value) { + var isOwn = hasOwnProperty.call(value, symToStringTag), + tag = value[symToStringTag]; + + try { + value[symToStringTag] = undefined; + var unmasked = true; + } catch (e) {} + + var result = nativeObjectToString.call(value); + if (unmasked) { + if (isOwn) { + value[symToStringTag] = tag; + } else { + delete value[symToStringTag]; + } + } + return result; + } + + /** Used for built-in method references. */ + var objectProto$1 = Object.prototype; + + /** + * Used to resolve the + * [`toStringTag`](http://ecma-international.org/ecma-262/7.0/#sec-object.prototype.tostring) + * of values. + */ + var nativeObjectToString$1 = objectProto$1.toString; + + /** + * Converts `value` to a string using `Object.prototype.toString`. + * + * @private + * @param {*} value The value to convert. + * @returns {string} Returns the converted string. + */ + function objectToString(value) { + return nativeObjectToString$1.call(value); + } + + /** `Object#toString` result references. */ + var nullTag = '[object Null]', + undefinedTag = '[object Undefined]'; + + /** Built-in value references. */ + var symToStringTag$1 = Symbol ? Symbol.toStringTag : undefined; + + /** + * The base implementation of `getTag` without fallbacks for buggy environments. + * + * @private + * @param {*} value The value to query. + * @returns {string} Returns the `toStringTag`. + */ + function baseGetTag(value) { + if (value == null) { + return value === undefined ? undefinedTag : nullTag; + } + return (symToStringTag$1 && symToStringTag$1 in Object(value)) + ? getRawTag(value) + : objectToString(value); + } + + /** + * Checks if `value` is object-like. A value is object-like if it's not `null` + * and has a `typeof` result of "object". + * + * @static + * @memberOf _ + * @since 4.0.0 + * @category Lang + * @param {*} value The value to check. + * @returns {boolean} Returns `true` if `value` is object-like, else `false`. + * @example + * + * _.isObjectLike({}); + * // => true + * + * _.isObjectLike([1, 2, 3]); + * // => true + * + * _.isObjectLike(_.noop); + * // => false + * + * _.isObjectLike(null); + * // => false + */ + function isObjectLike(value) { + return value != null && typeof value == 'object'; + } + + /** `Object#toString` result references. */ + var symbolTag = '[object Symbol]'; + + /** + * Checks if `value` is classified as a `Symbol` primitive or object. + * + * @static + * @memberOf _ + * @since 4.0.0 + * @category Lang + * @param {*} value The value to check. + * @returns {boolean} Returns `true` if `value` is a symbol, else `false`. + * @example + * + * _.isSymbol(Symbol.iterator); + * // => true + * + * _.isSymbol('abc'); + * // => false + */ + function isSymbol(value) { + return typeof value == 'symbol' || + (isObjectLike(value) && baseGetTag(value) == symbolTag); + } + + /** Used as references for various `Number` constants. */ + var INFINITY = 1 / 0; + + /** Used to convert symbols to primitives and strings. */ + var symbolProto = Symbol ? Symbol.prototype : undefined, + symbolToString = symbolProto ? symbolProto.toString : undefined; + + /** + * The base implementation of `_.toString` which doesn't convert nullish + * values to empty strings. + * + * @private + * @param {*} value The value to process. + * @returns {string} Returns the string. + */ + function baseToString(value) { + // Exit early for strings to avoid a performance hit in some environments. + if (typeof value == 'string') { + return value; + } + if (isArray(value)) { + // Recursively convert values (susceptible to call stack limits). + return arrayMap(value, baseToString) + ''; + } + if (isSymbol(value)) { + return symbolToString ? symbolToString.call(value) : ''; + } + var result = (value + ''); + return (result == '0' && (1 / value) == -INFINITY) ? '-0' : result; + } + + /** + * The base implementation of `_.slice` without an iteratee call guard. + * + * @private + * @param {Array} array The array to slice. + * @param {number} [start=0] The start position. + * @param {number} [end=array.length] The end position. + * @returns {Array} Returns the slice of `array`. + */ + function baseSlice(array, start, end) { + var index = -1, + length = array.length; + + if (start < 0) { + start = -start > length ? 0 : (length + start); + } + end = end > length ? length : end; + if (end < 0) { + end += length; + } + length = start > end ? 0 : ((end - start) >>> 0); + start >>>= 0; + + var result = Array(length); + while (++index < length) { + result[index] = array[index + start]; + } + return result; + } + + /** + * Casts `array` to a slice if it's needed. + * + * @private + * @param {Array} array The array to inspect. + * @param {number} start The start position. + * @param {number} [end=array.length] The end position. + * @returns {Array} Returns the cast slice. + */ + function castSlice(array, start, end) { + var length = array.length; + end = end === undefined ? length : end; + return (!start && end >= length) ? array : baseSlice(array, start, end); + } + + /** + * The base implementation of `_.findIndex` and `_.findLastIndex` without + * support for iteratee shorthands. + * + * @private + * @param {Array} array The array to inspect. + * @param {Function} predicate The function invoked per iteration. + * @param {number} fromIndex The index to search from. + * @param {boolean} [fromRight] Specify iterating from right to left. + * @returns {number} Returns the index of the matched value, else `-1`. + */ + function baseFindIndex(array, predicate, fromIndex, fromRight) { + var length = array.length, + index = fromIndex + (fromRight ? 1 : -1); + + while ((fromRight ? index-- : ++index < length)) { + if (predicate(array[index], index, array)) { + return index; + } + } + return -1; + } + + /** + * The base implementation of `_.isNaN` without support for number objects. + * + * @private + * @param {*} value The value to check. + * @returns {boolean} Returns `true` if `value` is `NaN`, else `false`. + */ + function baseIsNaN(value) { + return value !== value; + } + + /** + * A specialized version of `_.indexOf` which performs strict equality + * comparisons of values, i.e. `===`. + * + * @private + * @param {Array} array The array to inspect. + * @param {*} value The value to search for. + * @param {number} fromIndex The index to search from. + * @returns {number} Returns the index of the matched value, else `-1`. + */ + function strictIndexOf(array, value, fromIndex) { + var index = fromIndex - 1, + length = array.length; + + while (++index < length) { + if (array[index] === value) { + return index; + } + } + return -1; + } + + /** + * The base implementation of `_.indexOf` without `fromIndex` bounds checks. + * + * @private + * @param {Array} array The array to inspect. + * @param {*} value The value to search for. + * @param {number} fromIndex The index to search from. + * @returns {number} Returns the index of the matched value, else `-1`. + */ + function baseIndexOf(array, value, fromIndex) { + return value === value + ? strictIndexOf(array, value, fromIndex) + : baseFindIndex(array, baseIsNaN, fromIndex); + } + + /** + * Used by `_.trim` and `_.trimEnd` to get the index of the last string symbol + * that is not found in the character symbols. + * + * @private + * @param {Array} strSymbols The string symbols to inspect. + * @param {Array} chrSymbols The character symbols to find. + * @returns {number} Returns the index of the last unmatched string symbol. + */ + function charsEndIndex(strSymbols, chrSymbols) { + var index = strSymbols.length; + + while (index-- && baseIndexOf(chrSymbols, strSymbols[index], 0) > -1) {} + return index; + } + + /** + * Used by `_.trim` and `_.trimStart` to get the index of the first string symbol + * that is not found in the character symbols. + * + * @private + * @param {Array} strSymbols The string symbols to inspect. + * @param {Array} chrSymbols The character symbols to find. + * @returns {number} Returns the index of the first unmatched string symbol. + */ + function charsStartIndex(strSymbols, chrSymbols) { + var index = -1, + length = strSymbols.length; + + while (++index < length && baseIndexOf(chrSymbols, strSymbols[index], 0) > -1) {} + return index; + } + + /** + * Converts an ASCII `string` to an array. + * + * @private + * @param {string} string The string to convert. + * @returns {Array} Returns the converted array. + */ + function asciiToArray(string) { + return string.split(''); + } + + /** Used to compose unicode character classes. */ + var rsAstralRange = '\\ud800-\\udfff', + rsComboMarksRange = '\\u0300-\\u036f', + reComboHalfMarksRange = '\\ufe20-\\ufe2f', + rsComboSymbolsRange = '\\u20d0-\\u20ff', + rsComboRange = rsComboMarksRange + reComboHalfMarksRange + rsComboSymbolsRange, + rsVarRange = '\\ufe0e\\ufe0f'; + + /** Used to compose unicode capture groups. */ + var rsZWJ = '\\u200d'; + + /** 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/). */ + var reHasUnicode = RegExp('[' + rsZWJ + rsAstralRange + rsComboRange + rsVarRange + ']'); + + /** + * Checks if `string` contains Unicode symbols. + * + * @private + * @param {string} string The string to inspect. + * @returns {boolean} Returns `true` if a symbol is found, else `false`. + */ + function hasUnicode(string) { + return reHasUnicode.test(string); + } + + /** Used to compose unicode character classes. */ + var rsAstralRange$1 = '\\ud800-\\udfff', + rsComboMarksRange$1 = '\\u0300-\\u036f', + reComboHalfMarksRange$1 = '\\ufe20-\\ufe2f', + rsComboSymbolsRange$1 = '\\u20d0-\\u20ff', + rsComboRange$1 = rsComboMarksRange$1 + reComboHalfMarksRange$1 + rsComboSymbolsRange$1, + rsVarRange$1 = '\\ufe0e\\ufe0f'; + + /** Used to compose unicode capture groups. */ + var rsAstral = '[' + rsAstralRange$1 + ']', + rsCombo = '[' + rsComboRange$1 + ']', + rsFitz = '\\ud83c[\\udffb-\\udfff]', + rsModifier = '(?:' + rsCombo + '|' + rsFitz + ')', + rsNonAstral = '[^' + rsAstralRange$1 + ']', + rsRegional = '(?:\\ud83c[\\udde6-\\uddff]){2}', + rsSurrPair = '[\\ud800-\\udbff][\\udc00-\\udfff]', + rsZWJ$1 = '\\u200d'; + + /** Used to compose unicode regexes. */ + var reOptMod = rsModifier + '?', + rsOptVar = '[' + rsVarRange$1 + ']?', + rsOptJoin = '(?:' + rsZWJ$1 + '(?:' + [rsNonAstral, rsRegional, rsSurrPair].join('|') + ')' + rsOptVar + reOptMod + ')*', + rsSeq = rsOptVar + reOptMod + rsOptJoin, + rsSymbol = '(?:' + [rsNonAstral + rsCombo + '?', rsCombo, rsRegional, rsSurrPair, rsAstral].join('|') + ')'; + + /** Used to match [string symbols](https://mathiasbynens.be/notes/javascript-unicode). */ + var reUnicode = RegExp(rsFitz + '(?=' + rsFitz + ')|' + rsSymbol + rsSeq, 'g'); + + /** + * Converts a Unicode `string` to an array. + * + * @private + * @param {string} string The string to convert. + * @returns {Array} Returns the converted array. + */ + function unicodeToArray(string) { + return string.match(reUnicode) || []; + } + + /** + * Converts `string` to an array. + * + * @private + * @param {string} string The string to convert. + * @returns {Array} Returns the converted array. + */ + function stringToArray(string) { + return hasUnicode(string) + ? unicodeToArray(string) + : asciiToArray(string); + } + + /** + * Converts `value` to a string. An empty string is returned for `null` + * and `undefined` values. The sign of `-0` is preserved. + * + * @static + * @memberOf _ + * @since 4.0.0 + * @category Lang + * @param {*} value The value to convert. + * @returns {string} Returns the converted string. + * @example + * + * _.toString(null); + * // => '' + * + * _.toString(-0); + * // => '-0' + * + * _.toString([1, 2, 3]); + * // => '1,2,3' + */ + function toString(value) { + return value == null ? '' : baseToString(value); + } + + /** Used to match leading and trailing whitespace. */ + var reTrim = /^\s+|\s+$/g; + + /** + * Removes leading and trailing whitespace or specified characters from `string`. + * + * @static + * @memberOf _ + * @since 3.0.0 + * @category String + * @param {string} [string=''] The string to trim. + * @param {string} [chars=whitespace] The characters to trim. + * @param- {Object} [guard] Enables use as an iteratee for methods like `_.map`. + * @returns {string} Returns the trimmed string. + * @example + * + * _.trim(' abc '); + * // => 'abc' + * + * _.trim('-_-abc-_-', '_-'); + * // => 'abc' + * + * _.map([' foo ', ' bar '], _.trim); + * // => ['foo', 'bar'] + */ + function trim(string, chars, guard) { + string = toString(string); + if (string && (guard || chars === undefined)) { + return string.replace(reTrim, ''); + } + if (!string || !(chars = baseToString(chars))) { + return string; + } + var strSymbols = stringToArray(string), + chrSymbols = stringToArray(chars), + start = charsStartIndex(strSymbols, chrSymbols), + end = charsEndIndex(strSymbols, chrSymbols) + 1; + + return castSlice(strSymbols, start, end).join(''); + } + + /** + * Check several parameter that there is something in the param + * @param {*} param input + * @return {boolean} + */ + var isNotEmpty = function (a) { + if (isArray(a)) { + return true; + } + return a !== undefined && a !== null && trim(a) !== '' + }; + + /** `Object#toString` result references. */ + var numberTag = '[object Number]'; + + /** + * Checks if `value` is classified as a `Number` primitive or object. + * + * **Note:** To exclude `Infinity`, `-Infinity`, and `NaN`, which are + * classified as numbers, use the `_.isFinite` method. + * + * @static + * @memberOf _ + * @since 0.1.0 + * @category Lang + * @param {*} value The value to check. + * @returns {boolean} Returns `true` if `value` is a number, else `false`. + * @example + * + * _.isNumber(3); + * // => true + * + * _.isNumber(Number.MIN_VALUE); + * // => true + * + * _.isNumber(Infinity); + * // => true + * + * _.isNumber('3'); + * // => false + */ + function isNumber(value) { + return typeof value == 'number' || + (isObjectLike(value) && baseGetTag(value) == numberTag); + } + + /** + * Checks if `value` is `NaN`. + * + * **Note:** This method is based on + * [`Number.isNaN`](https://mdn.io/Number/isNaN) and is not the same as + * global [`isNaN`](https://mdn.io/isNaN) which returns `true` for + * `undefined` and other non-number values. + * + * @static + * @memberOf _ + * @since 0.1.0 + * @category Lang + * @param {*} value The value to check. + * @returns {boolean} Returns `true` if `value` is `NaN`, else `false`. + * @example + * + * _.isNaN(NaN); + * // => true + * + * _.isNaN(new Number(NaN)); + * // => true + * + * isNaN(undefined); + * // => true + * + * _.isNaN(undefined); + * // => false + */ + function isNaN(value) { + // An `NaN` primitive is the only value that is not equal to itself. + // Perform the `toStringTag` check first to avoid errors with some + // ActiveX objects in IE. + return isNumber(value) && value != +value; + } + + /** `Object#toString` result references. */ + var stringTag = '[object String]'; + + /** + * Checks if `value` is classified as a `String` primitive or object. + * + * @static + * @since 0.1.0 + * @memberOf _ + * @category Lang + * @param {*} value The value to check. + * @returns {boolean} Returns `true` if `value` is a string, else `false`. + * @example + * + * _.isString('abc'); + * // => true + * + * _.isString(1); + * // => false + */ + function isString(value) { + return typeof value == 'string' || + (!isArray(value) && isObjectLike(value) && baseGetTag(value) == stringTag); + } + + // validator numbers + /** + * @2015-05-04 found a problem if the value is a number like string + * it will pass, so add a chck if it's string before we pass to next + * @param {number} value expected value + * @return {boolean} true if OK + */ + var checkIsNumber = function(value) { + return isString(value) ? false : !isNaN( parseFloat(value) ) + }; + + // validate string type + /** + * @param {string} value expected value + * @return {boolean} true if OK + */ + var checkIsString = function(value) { + return (trim(value) !== '') ? isString(value) : false + }; + + // check for boolean + + /** + * @param {boolean} value expected + * @return {boolean} true if OK + */ + var checkIsBoolean = function(value) { + return value !== null && value !== undefined && typeof value === 'boolean' + }; + + // validate any thing only check if there is something + + /** + * @param {*} value the value + * @param {boolean} [checkNull=true] strict check if there is null value + * @return {boolean} true is OK + */ + var checkIsAny = function(value, checkNull) { + if ( checkNull === void 0 ) checkNull = true; + + if (value !== undefined && value !== '' && trim(value) !== '') { + if (checkNull === false || (checkNull === true && value !== null)) { + return true; + } + } + return false; + }; + + // the core stuff to id if it's calling with jsonql + var DATA_KEY = 'data'; + var ERROR_KEY = 'error'; + + var JSONQL_PATH = 'jsonql'; + + // export const INDEX = 'index' use INDEX_KEY instead + var DEFAULT_TYPE = 'any'; + + // @TODO remove this is not in use + // export const CLIENT_CONFIG_FILE = '.clients.json' + // export const CONTRACT_CONFIG_FILE = 'jsonql-contract-config.js' + // type of resolvers + var QUERY_NAME = 'query'; + var MUTATION_NAME = 'mutation'; + var SOCKET_NAME = 'socket'; + // for contract-cli + var KEY_WORD = 'continue'; + var PUBLIC_KEY = 'public'; + + var TYPE_KEY = 'type'; + var OPTIONAL_KEY = 'optional'; + var ENUM_KEY = 'enumv'; // need to change this because enum is a reserved word + var ARGS_KEY = 'args'; + var CHECKER_KEY = 'checker'; + var ALIAS_KEY = 'alias'; + var LOGIN_NAME = 'login'; + // export const ISSUER_NAME = LOGIN_NAME // legacy issue need to replace them later + var LOGOUT_NAME = 'logout'; + var DISCONNECT_FN_NAME = 'disconnect'; + var SWITCH_USER_FN_NAME = 'switch-user'; + + var OR_SEPERATOR = '|'; + var STRING_TYPE = 'string'; + var BOOLEAN_TYPE = 'boolean'; + var ARRAY_TYPE = 'array'; + var OBJECT_TYPE = 'object'; + + var NUMBER_TYPE = 'number'; + var ARRAY_TYPE_LFT = 'array.<'; + var ARRAY_TYPE_RGT = '>'; + + var NO_ERROR_MSG = 'No message'; + var NO_STATUS_CODE = -1; + var LOGIN_EVENT_NAME = '__login__'; + var LOGOUT_EVENT_NAME = '__logout__'; + var DISCONNECT_EVENT_NAME = '__disconnect__'; + // this is somewhat vague about what is suppose to do + var EMIT_REPLY_TYPE = 'emit_reply'; + + var NSP_GROUP = 'nspGroup'; + var PUBLIC_NAMESPACE = 'publicNamespace'; + + var JS_WS_SOCKET_IO_NAME = 'socket.io'; + // type name and Alias + var SOCKET_TYPE_KEY = 'serverType'; //1.9.1 + var SOCKET_TYPE_CLIENT_ALIAS = 'socketClientType'; // 1.9.0 + + // for ws client, 1.9.3 breaking change to name them as FN instead of PROP + 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'; + var NOT_LOGIN_ERR_MSG = 'NOT LOGIN'; + var IO_ROUNDTRIP_LOGIN = 'roundtip'; + var IO_HANDSHAKE_LOGIN = 'handshake'; + + // Good practice rule - No magic number + + var 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)"; + var PARAMS_NOT_ARRAY_ERR = "params is not an array! Did something gone wrong when you generate the contract.json?"; + var EXCEPTION_CASE_ERR = 'Could not understand your arguments and parameter structure!'; + // @TODO the jsdoc return array. and we should also allow array syntax + var DEFAULT_TYPE$1 = DEFAULT_TYPE; + var ARRAY_TYPE_LFT$1 = ARRAY_TYPE_LFT; + var ARRAY_TYPE_RGT$1 = ARRAY_TYPE_RGT; + + var TYPE_KEY$1 = TYPE_KEY; + var OPTIONAL_KEY$1 = OPTIONAL_KEY; + var ENUM_KEY$1 = ENUM_KEY; + var ARGS_KEY$1 = ARGS_KEY; + var CHECKER_KEY$1 = CHECKER_KEY; + var ALIAS_KEY$1 = ALIAS_KEY; + + var ARRAY_TYPE$1 = ARRAY_TYPE; + var OBJECT_TYPE$1 = OBJECT_TYPE; + var STRING_TYPE$1 = STRING_TYPE; + var BOOLEAN_TYPE$1 = BOOLEAN_TYPE; + var NUMBER_TYPE$1 = NUMBER_TYPE; + var KEY_WORD$1 = KEY_WORD; + var OR_SEPERATOR$1 = OR_SEPERATOR; + + // not actually in use + // export const NUMBER_TYPES = JSONQL_CONSTANTS.NUMBER_TYPES; + + // primitive types + + /** + * this is a wrapper method to call different one based on their type + * @param {string} type to check + * @return {function} a function to handle the type + */ + var combineFn = function(type) { + switch (type) { + case NUMBER_TYPE$1: + return checkIsNumber + case STRING_TYPE$1: + return checkIsString + case BOOLEAN_TYPE$1: + return checkIsBoolean + default: + return checkIsAny + } + }; + + // validate array type + + /** + * @param {array} value expected + * @param {string} [type=''] pass the type if we encounter array. then we need to check the value as well + * @return {boolean} true if OK + */ + var checkIsArray = function(value, type) { + if ( type === void 0 ) type=''; + + if (isArray(value)) { + if (type === '' || trim(type)==='') { + return true; + } + // we test it in reverse + // @TODO if the type is an array (OR) then what? + // we need to take into account this could be an array + var c = value.filter(function (v) { return !combineFn(type)(v); }); + return !(c.length > 0) + } + return false + }; + + /** + * check if it matches the array. pattern + * @param {string} type + * @return {boolean|array} false means NO, always return array + */ + var isArrayLike = function(type) { + // @TODO could that have something like array<> instead of array.<>? missing the dot? + // because type script is Array without the dot + if (type.indexOf(ARRAY_TYPE_LFT$1) > -1 && type.indexOf(ARRAY_TYPE_RGT$1) > -1) { + var _type = type.replace(ARRAY_TYPE_LFT$1, '').replace(ARRAY_TYPE_RGT$1, ''); + if (_type.indexOf(OR_SEPERATOR$1)) { + return _type.split(OR_SEPERATOR$1) + } + return [_type] + } + return false + }; + + /** + * we might encounter something like array. then we need to take it apart + * @param {object} p the prepared object for processing + * @param {string|array} type the type came from + * @return {boolean} for the filter to operate on + */ + var arrayTypeHandler = function(p, type) { + var arg = p.arg; + // need a special case to handle the OR type + // we need to test the args instead of the type(s) + if (type.length > 1) { + return !arg.filter(function (v) { return ( + !(type.length > type.filter(function (t) { return !combineFn(t)(v); }).length) + ); }).length + } + // type is array so this will be or! + return type.length > type.filter(function (t) { return !checkIsArray(arg, t); }).length + }; + + /** + * Creates a unary function that invokes `func` with its argument transformed. + * + * @private + * @param {Function} func The function to wrap. + * @param {Function} transform The argument transform. + * @returns {Function} Returns the new function. + */ + function overArg(func, transform) { + return function(arg) { + return func(transform(arg)); + }; + } + + /** Built-in value references. */ + var getPrototype = overArg(Object.getPrototypeOf, Object); + + /** `Object#toString` result references. */ + var objectTag = '[object Object]'; + + /** Used for built-in method references. */ + var funcProto = Function.prototype, + objectProto$2 = Object.prototype; + + /** Used to resolve the decompiled source of functions. */ + var funcToString = funcProto.toString; + + /** Used to check objects for own properties. */ + var hasOwnProperty$1 = objectProto$2.hasOwnProperty; + + /** Used to infer the `Object` constructor. */ + var objectCtorString = funcToString.call(Object); + + /** + * Checks if `value` is a plain object, that is, an object created by the + * `Object` constructor or one with a `[[Prototype]]` of `null`. + * + * @static + * @memberOf _ + * @since 0.8.0 + * @category Lang + * @param {*} value The value to check. + * @returns {boolean} Returns `true` if `value` is a plain object, else `false`. + * @example + * + * function Foo() { + * this.a = 1; + * } + * + * _.isPlainObject(new Foo); + * // => false + * + * _.isPlainObject([1, 2, 3]); + * // => false + * + * _.isPlainObject({ 'x': 0, 'y': 0 }); + * // => true + * + * _.isPlainObject(Object.create(null)); + * // => true + */ + function isPlainObject(value) { + if (!isObjectLike(value) || baseGetTag(value) != objectTag) { + return false; + } + var proto = getPrototype(value); + if (proto === null) { + return true; + } + var Ctor = hasOwnProperty$1.call(proto, 'constructor') && proto.constructor; + return typeof Ctor == 'function' && Ctor instanceof Ctor && + funcToString.call(Ctor) == objectCtorString; + } + + /** + * A specialized version of `_.filter` for arrays without support for + * iteratee shorthands. + * + * @private + * @param {Array} [array] The array to iterate over. + * @param {Function} predicate The function invoked per iteration. + * @returns {Array} Returns the new filtered array. + */ + function arrayFilter(array, predicate) { + var index = -1, + length = array == null ? 0 : array.length, + resIndex = 0, + result = []; + + while (++index < length) { + var value = array[index]; + if (predicate(value, index, array)) { + result[resIndex++] = value; + } + } + return result; + } + + /** + * Creates a base function for methods like `_.forIn` and `_.forOwn`. + * + * @private + * @param {boolean} [fromRight] Specify iterating from right to left. + * @returns {Function} Returns the new base function. + */ + function createBaseFor(fromRight) { + return function(object, iteratee, keysFunc) { + var index = -1, + iterable = Object(object), + props = keysFunc(object), + length = props.length; + + while (length--) { + var key = props[fromRight ? length : ++index]; + if (iteratee(iterable[key], key, iterable) === false) { + break; + } + } + return object; + }; + } + + /** + * The base implementation of `baseForOwn` which iterates over `object` + * properties returned by `keysFunc` and invokes `iteratee` for each property. + * Iteratee functions may exit iteration early by explicitly returning `false`. + * + * @private + * @param {Object} object The object to iterate over. + * @param {Function} iteratee The function invoked per iteration. + * @param {Function} keysFunc The function to get the keys of `object`. + * @returns {Object} Returns `object`. + */ + var baseFor = createBaseFor(); + + /** + * The base implementation of `_.times` without support for iteratee shorthands + * or max array length checks. + * + * @private + * @param {number} n The number of times to invoke `iteratee`. + * @param {Function} iteratee The function invoked per iteration. + * @returns {Array} Returns the array of results. + */ + function baseTimes(n, iteratee) { + var index = -1, + result = Array(n); + + while (++index < n) { + result[index] = iteratee(index); + } + return result; + } + + /** `Object#toString` result references. */ + var argsTag = '[object Arguments]'; + + /** + * The base implementation of `_.isArguments`. + * + * @private + * @param {*} value The value to check. + * @returns {boolean} Returns `true` if `value` is an `arguments` object, + */ + function baseIsArguments(value) { + return isObjectLike(value) && baseGetTag(value) == argsTag; + } + + /** Used for built-in method references. */ + var objectProto$3 = Object.prototype; + + /** Used to check objects for own properties. */ + var hasOwnProperty$2 = objectProto$3.hasOwnProperty; + + /** Built-in value references. */ + var propertyIsEnumerable = objectProto$3.propertyIsEnumerable; + + /** + * Checks if `value` is likely an `arguments` object. + * + * @static + * @memberOf _ + * @since 0.1.0 + * @category Lang + * @param {*} value The value to check. + * @returns {boolean} Returns `true` if `value` is an `arguments` object, + * else `false`. + * @example + * + * _.isArguments(function() { return arguments; }()); + * // => true + * + * _.isArguments([1, 2, 3]); + * // => false + */ + var isArguments = baseIsArguments(function() { return arguments; }()) ? baseIsArguments : function(value) { + return isObjectLike(value) && hasOwnProperty$2.call(value, 'callee') && + !propertyIsEnumerable.call(value, 'callee'); + }; + + /** + * This method returns `false`. + * + * @static + * @memberOf _ + * @since 4.13.0 + * @category Util + * @returns {boolean} Returns `false`. + * @example + * + * _.times(2, _.stubFalse); + * // => [false, false] + */ + function stubFalse() { + return false; + } + + /** Detect free variable `exports`. */ + var freeExports = typeof exports == 'object' && exports && !exports.nodeType && exports; + + /** Detect free variable `module`. */ + var freeModule = freeExports && typeof module == 'object' && module && !module.nodeType && module; + + /** Detect the popular CommonJS extension `module.exports`. */ + var moduleExports = freeModule && freeModule.exports === freeExports; + + /** Built-in value references. */ + var Buffer = moduleExports ? root.Buffer : undefined; + + /* Built-in method references for those with the same name as other `lodash` methods. */ + var nativeIsBuffer = Buffer ? Buffer.isBuffer : undefined; + + /** + * Checks if `value` is a buffer. + * + * @static + * @memberOf _ + * @since 4.3.0 + * @category Lang + * @param {*} value The value to check. + * @returns {boolean} Returns `true` if `value` is a buffer, else `false`. + * @example + * + * _.isBuffer(new Buffer(2)); + * // => true + * + * _.isBuffer(new Uint8Array(2)); + * // => false + */ + var isBuffer = nativeIsBuffer || stubFalse; + + /** Used as references for various `Number` constants. */ + var MAX_SAFE_INTEGER = 9007199254740991; + + /** Used to detect unsigned integer values. */ + var reIsUint = /^(?:0|[1-9]\d*)$/; + + /** + * Checks if `value` is a valid array-like index. + * + * @private + * @param {*} value The value to check. + * @param {number} [length=MAX_SAFE_INTEGER] The upper bounds of a valid index. + * @returns {boolean} Returns `true` if `value` is a valid index, else `false`. + */ + function isIndex(value, length) { + var type = typeof value; + length = length == null ? MAX_SAFE_INTEGER : length; + + return !!length && + (type == 'number' || + (type != 'symbol' && reIsUint.test(value))) && + (value > -1 && value % 1 == 0 && value < length); + } + + /** Used as references for various `Number` constants. */ + var MAX_SAFE_INTEGER$1 = 9007199254740991; + + /** + * Checks if `value` is a valid array-like length. + * + * **Note:** This method is loosely based on + * [`ToLength`](http://ecma-international.org/ecma-262/7.0/#sec-tolength). + * + * @static + * @memberOf _ + * @since 4.0.0 + * @category Lang + * @param {*} value The value to check. + * @returns {boolean} Returns `true` if `value` is a valid length, else `false`. + * @example + * + * _.isLength(3); + * // => true + * + * _.isLength(Number.MIN_VALUE); + * // => false + * + * _.isLength(Infinity); + * // => false + * + * _.isLength('3'); + * // => false + */ + function isLength(value) { + return typeof value == 'number' && + value > -1 && value % 1 == 0 && value <= MAX_SAFE_INTEGER$1; + } + + /** `Object#toString` result references. */ + var argsTag$1 = '[object Arguments]', + arrayTag = '[object Array]', + boolTag = '[object Boolean]', + dateTag = '[object Date]', + errorTag = '[object Error]', + funcTag = '[object Function]', + mapTag = '[object Map]', + numberTag$1 = '[object Number]', + objectTag$1 = '[object Object]', + regexpTag = '[object RegExp]', + setTag = '[object Set]', + stringTag$1 = '[object String]', + weakMapTag = '[object WeakMap]'; + + var arrayBufferTag = '[object ArrayBuffer]', + dataViewTag = '[object DataView]', + float32Tag = '[object Float32Array]', + float64Tag = '[object Float64Array]', + int8Tag = '[object Int8Array]', + int16Tag = '[object Int16Array]', + int32Tag = '[object Int32Array]', + uint8Tag = '[object Uint8Array]', + uint8ClampedTag = '[object Uint8ClampedArray]', + uint16Tag = '[object Uint16Array]', + uint32Tag = '[object Uint32Array]'; + + /** Used to identify `toStringTag` values of typed arrays. */ + var typedArrayTags = {}; + typedArrayTags[float32Tag] = typedArrayTags[float64Tag] = + typedArrayTags[int8Tag] = typedArrayTags[int16Tag] = + typedArrayTags[int32Tag] = typedArrayTags[uint8Tag] = + typedArrayTags[uint8ClampedTag] = typedArrayTags[uint16Tag] = + typedArrayTags[uint32Tag] = true; + typedArrayTags[argsTag$1] = typedArrayTags[arrayTag] = + typedArrayTags[arrayBufferTag] = typedArrayTags[boolTag] = + typedArrayTags[dataViewTag] = typedArrayTags[dateTag] = + typedArrayTags[errorTag] = typedArrayTags[funcTag] = + typedArrayTags[mapTag] = typedArrayTags[numberTag$1] = + typedArrayTags[objectTag$1] = typedArrayTags[regexpTag] = + typedArrayTags[setTag] = typedArrayTags[stringTag$1] = + typedArrayTags[weakMapTag] = false; + + /** + * The base implementation of `_.isTypedArray` without Node.js optimizations. + * + * @private + * @param {*} value The value to check. + * @returns {boolean} Returns `true` if `value` is a typed array, else `false`. + */ + function baseIsTypedArray(value) { + return isObjectLike(value) && + isLength(value.length) && !!typedArrayTags[baseGetTag(value)]; + } + + /** + * The base implementation of `_.unary` without support for storing metadata. + * + * @private + * @param {Function} func The function to cap arguments for. + * @returns {Function} Returns the new capped function. + */ + function baseUnary(func) { + return function(value) { + return func(value); + }; + } + + /** Detect free variable `exports`. */ + var freeExports$1 = typeof exports == 'object' && exports && !exports.nodeType && exports; + + /** Detect free variable `module`. */ + var freeModule$1 = freeExports$1 && typeof module == 'object' && module && !module.nodeType && module; + + /** Detect the popular CommonJS extension `module.exports`. */ + var moduleExports$1 = freeModule$1 && freeModule$1.exports === freeExports$1; + + /** Detect free variable `process` from Node.js. */ + var freeProcess = moduleExports$1 && freeGlobal.process; + + /** Used to access faster Node.js helpers. */ + var nodeUtil = (function() { + try { + // Use `util.types` for Node.js 10+. + var types = freeModule$1 && freeModule$1.require && freeModule$1.require('util').types; + + if (types) { + return types; + } + + // Legacy `process.binding('util')` for Node.js < 10. + return freeProcess && freeProcess.binding && freeProcess.binding('util'); + } catch (e) {} + }()); + + /* Node.js helper references. */ + var nodeIsTypedArray = nodeUtil && nodeUtil.isTypedArray; + + /** + * Checks if `value` is classified as a typed array. + * + * @static + * @memberOf _ + * @since 3.0.0 + * @category Lang + * @param {*} value The value to check. + * @returns {boolean} Returns `true` if `value` is a typed array, else `false`. + * @example + * + * _.isTypedArray(new Uint8Array); + * // => true + * + * _.isTypedArray([]); + * // => false + */ + var isTypedArray = nodeIsTypedArray ? baseUnary(nodeIsTypedArray) : baseIsTypedArray; + + /** Used for built-in method references. */ + var objectProto$4 = Object.prototype; + + /** Used to check objects for own properties. */ + var hasOwnProperty$3 = objectProto$4.hasOwnProperty; + + /** + * Creates an array of the enumerable property names of the array-like `value`. + * + * @private + * @param {*} value The value to query. + * @param {boolean} inherited Specify returning inherited property names. + * @returns {Array} Returns the array of property names. + */ + function arrayLikeKeys(value, inherited) { + var isArr = isArray(value), + isArg = !isArr && isArguments(value), + isBuff = !isArr && !isArg && isBuffer(value), + isType = !isArr && !isArg && !isBuff && isTypedArray(value), + skipIndexes = isArr || isArg || isBuff || isType, + result = skipIndexes ? baseTimes(value.length, String) : [], + length = result.length; + + for (var key in value) { + if ((inherited || hasOwnProperty$3.call(value, key)) && + !(skipIndexes && ( + // Safari 9 has enumerable `arguments.length` in strict mode. + key == 'length' || + // Node.js 0.10 has enumerable non-index properties on buffers. + (isBuff && (key == 'offset' || key == 'parent')) || + // PhantomJS 2 has enumerable non-index properties on typed arrays. + (isType && (key == 'buffer' || key == 'byteLength' || key == 'byteOffset')) || + // Skip index properties. + isIndex(key, length) + ))) { + result.push(key); + } + } + return result; + } + + /** Used for built-in method references. */ + var objectProto$5 = Object.prototype; + + /** + * Checks if `value` is likely a prototype object. + * + * @private + * @param {*} value The value to check. + * @returns {boolean} Returns `true` if `value` is a prototype, else `false`. + */ + function isPrototype(value) { + var Ctor = value && value.constructor, + proto = (typeof Ctor == 'function' && Ctor.prototype) || objectProto$5; + + return value === proto; + } + + /* Built-in method references for those with the same name as other `lodash` methods. */ + var nativeKeys = overArg(Object.keys, Object); + + /** Used for built-in method references. */ + var objectProto$6 = Object.prototype; + + /** Used to check objects for own properties. */ + var hasOwnProperty$4 = objectProto$6.hasOwnProperty; + + /** + * The base implementation of `_.keys` which doesn't treat sparse arrays as dense. + * + * @private + * @param {Object} object The object to query. + * @returns {Array} Returns the array of property names. + */ + function baseKeys(object) { + if (!isPrototype(object)) { + return nativeKeys(object); + } + var result = []; + for (var key in Object(object)) { + if (hasOwnProperty$4.call(object, key) && key != 'constructor') { + result.push(key); + } + } + return result; + } + + /** + * Checks if `value` is the + * [language type](http://www.ecma-international.org/ecma-262/7.0/#sec-ecmascript-language-types) + * of `Object`. (e.g. arrays, functions, objects, regexes, `new Number(0)`, and `new String('')`) + * + * @static + * @memberOf _ + * @since 0.1.0 + * @category Lang + * @param {*} value The value to check. + * @returns {boolean} Returns `true` if `value` is an object, else `false`. + * @example + * + * _.isObject({}); + * // => true + * + * _.isObject([1, 2, 3]); + * // => true + * + * _.isObject(_.noop); + * // => true + * + * _.isObject(null); + * // => false + */ + function isObject(value) { + var type = typeof value; + return value != null && (type == 'object' || type == 'function'); + } + + /** `Object#toString` result references. */ + var asyncTag = '[object AsyncFunction]', + funcTag$1 = '[object Function]', + genTag = '[object GeneratorFunction]', + proxyTag = '[object Proxy]'; + + /** + * Checks if `value` is classified as a `Function` object. + * + * @static + * @memberOf _ + * @since 0.1.0 + * @category Lang + * @param {*} value The value to check. + * @returns {boolean} Returns `true` if `value` is a function, else `false`. + * @example + * + * _.isFunction(_); + * // => true + * + * _.isFunction(/abc/); + * // => false + */ + function isFunction(value) { + if (!isObject(value)) { + return false; + } + // The use of `Object#toString` avoids issues with the `typeof` operator + // in Safari 9 which returns 'object' for typed arrays and other constructors. + var tag = baseGetTag(value); + return tag == funcTag$1 || tag == genTag || tag == asyncTag || tag == proxyTag; + } + + /** + * Checks if `value` is array-like. A value is considered array-like if it's + * not a function and has a `value.length` that's an integer greater than or + * equal to `0` and less than or equal to `Number.MAX_SAFE_INTEGER`. + * + * @static + * @memberOf _ + * @since 4.0.0 + * @category Lang + * @param {*} value The value to check. + * @returns {boolean} Returns `true` if `value` is array-like, else `false`. + * @example + * + * _.isArrayLike([1, 2, 3]); + * // => true + * + * _.isArrayLike(document.body.children); + * // => true + * + * _.isArrayLike('abc'); + * // => true + * + * _.isArrayLike(_.noop); + * // => false + */ + function isArrayLike$1(value) { + return value != null && isLength(value.length) && !isFunction(value); + } + + /** + * Creates an array of the own enumerable property names of `object`. + * + * **Note:** Non-object values are coerced to objects. See the + * [ES spec](http://ecma-international.org/ecma-262/7.0/#sec-object.keys) + * for more details. + * + * @static + * @since 0.1.0 + * @memberOf _ + * @category Object + * @param {Object} object The object to query. + * @returns {Array} Returns the array of property names. + * @example + * + * function Foo() { + * this.a = 1; + * this.b = 2; + * } + * + * Foo.prototype.c = 3; + * + * _.keys(new Foo); + * // => ['a', 'b'] (iteration order is not guaranteed) + * + * _.keys('hi'); + * // => ['0', '1'] + */ + function keys(object) { + return isArrayLike$1(object) ? arrayLikeKeys(object) : baseKeys(object); + } + + /** + * The base implementation of `_.forOwn` without support for iteratee shorthands. + * + * @private + * @param {Object} object The object to iterate over. + * @param {Function} iteratee The function invoked per iteration. + * @returns {Object} Returns `object`. + */ + function baseForOwn(object, iteratee) { + return object && baseFor(object, iteratee, keys); + } + + /** + * Removes all key-value entries from the list cache. + * + * @private + * @name clear + * @memberOf ListCache + */ + function listCacheClear() { + this.__data__ = []; + this.size = 0; + } + + /** + * Performs a + * [`SameValueZero`](http://ecma-international.org/ecma-262/7.0/#sec-samevaluezero) + * comparison between two values to determine if they are equivalent. + * + * @static + * @memberOf _ + * @since 4.0.0 + * @category Lang + * @param {*} value The value to compare. + * @param {*} other The other value to compare. + * @returns {boolean} Returns `true` if the values are equivalent, else `false`. + * @example + * + * var object = { 'a': 1 }; + * var other = { 'a': 1 }; + * + * _.eq(object, object); + * // => true + * + * _.eq(object, other); + * // => false + * + * _.eq('a', 'a'); + * // => true + * + * _.eq('a', Object('a')); + * // => false + * + * _.eq(NaN, NaN); + * // => true + */ + function eq(value, other) { + return value === other || (value !== value && other !== other); + } + + /** + * Gets the index at which the `key` is found in `array` of key-value pairs. + * + * @private + * @param {Array} array The array to inspect. + * @param {*} key The key to search for. + * @returns {number} Returns the index of the matched value, else `-1`. + */ + function assocIndexOf(array, key) { + var length = array.length; + while (length--) { + if (eq(array[length][0], key)) { + return length; + } + } + return -1; + } + + /** Used for built-in method references. */ + var arrayProto = Array.prototype; + + /** Built-in value references. */ + var splice = arrayProto.splice; + + /** + * Removes `key` and its value from the list cache. + * + * @private + * @name delete + * @memberOf ListCache + * @param {string} key The key of the value to remove. + * @returns {boolean} Returns `true` if the entry was removed, else `false`. + */ + function listCacheDelete(key) { + var data = this.__data__, + index = assocIndexOf(data, key); + + if (index < 0) { + return false; + } + var lastIndex = data.length - 1; + if (index == lastIndex) { + data.pop(); + } else { + splice.call(data, index, 1); + } + --this.size; + return true; + } + + /** + * Gets the list cache value for `key`. + * + * @private + * @name get + * @memberOf ListCache + * @param {string} key The key of the value to get. + * @returns {*} Returns the entry value. + */ + function listCacheGet(key) { + var data = this.__data__, + index = assocIndexOf(data, key); + + return index < 0 ? undefined : data[index][1]; + } + + /** + * Checks if a list cache value for `key` exists. + * + * @private + * @name has + * @memberOf ListCache + * @param {string} key The key of the entry to check. + * @returns {boolean} Returns `true` if an entry for `key` exists, else `false`. + */ + function listCacheHas(key) { + return assocIndexOf(this.__data__, key) > -1; + } + + /** + * Sets the list cache `key` to `value`. + * + * @private + * @name set + * @memberOf ListCache + * @param {string} key The key of the value to set. + * @param {*} value The value to set. + * @returns {Object} Returns the list cache instance. + */ + function listCacheSet(key, value) { + var data = this.__data__, + index = assocIndexOf(data, key); + + if (index < 0) { + ++this.size; + data.push([key, value]); + } else { + data[index][1] = value; + } + return this; + } + + /** + * Creates an list cache object. + * + * @private + * @constructor + * @param {Array} [entries] The key-value pairs to cache. + */ + function ListCache(entries) { + var index = -1, + length = entries == null ? 0 : entries.length; + + this.clear(); + while (++index < length) { + var entry = entries[index]; + this.set(entry[0], entry[1]); + } + } + + // Add methods to `ListCache`. + ListCache.prototype.clear = listCacheClear; + ListCache.prototype['delete'] = listCacheDelete; + ListCache.prototype.get = listCacheGet; + ListCache.prototype.has = listCacheHas; + ListCache.prototype.set = listCacheSet; + + /** + * Removes all key-value entries from the stack. + * + * @private + * @name clear + * @memberOf Stack + */ + function stackClear() { + this.__data__ = new ListCache; + this.size = 0; + } + + /** + * Removes `key` and its value from the stack. + * + * @private + * @name delete + * @memberOf Stack + * @param {string} key The key of the value to remove. + * @returns {boolean} Returns `true` if the entry was removed, else `false`. + */ + function stackDelete(key) { + var data = this.__data__, + result = data['delete'](key); + + this.size = data.size; + return result; + } + + /** + * Gets the stack value for `key`. + * + * @private + * @name get + * @memberOf Stack + * @param {string} key The key of the value to get. + * @returns {*} Returns the entry value. + */ + function stackGet(key) { + return this.__data__.get(key); + } + + /** + * Checks if a stack value for `key` exists. + * + * @private + * @name has + * @memberOf Stack + * @param {string} key The key of the entry to check. + * @returns {boolean} Returns `true` if an entry for `key` exists, else `false`. + */ + function stackHas(key) { + return this.__data__.has(key); + } + + /** Used to detect overreaching core-js shims. */ + var coreJsData = root['__core-js_shared__']; + + /** Used to detect methods masquerading as native. */ + var maskSrcKey = (function() { + var uid = /[^.]+$/.exec(coreJsData && coreJsData.keys && coreJsData.keys.IE_PROTO || ''); + return uid ? ('Symbol(src)_1.' + uid) : ''; + }()); + + /** + * Checks if `func` has its source masked. + * + * @private + * @param {Function} func The function to check. + * @returns {boolean} Returns `true` if `func` is masked, else `false`. + */ + function isMasked(func) { + return !!maskSrcKey && (maskSrcKey in func); + } + + /** Used for built-in method references. */ + var funcProto$1 = Function.prototype; + + /** Used to resolve the decompiled source of functions. */ + var funcToString$1 = funcProto$1.toString; + + /** + * Converts `func` to its source code. + * + * @private + * @param {Function} func The function to convert. + * @returns {string} Returns the source code. + */ + function toSource(func) { + if (func != null) { + try { + return funcToString$1.call(func); + } catch (e) {} + try { + return (func + ''); + } catch (e) {} + } + return ''; + } + + /** + * Used to match `RegExp` + * [syntax characters](http://ecma-international.org/ecma-262/7.0/#sec-patterns). + */ + var reRegExpChar = /[\\^$.*+?()[\]{}|]/g; + + /** Used to detect host constructors (Safari). */ + var reIsHostCtor = /^\[object .+?Constructor\]$/; + + /** Used for built-in method references. */ + var funcProto$2 = Function.prototype, + objectProto$7 = Object.prototype; + + /** Used to resolve the decompiled source of functions. */ + var funcToString$2 = funcProto$2.toString; + + /** Used to check objects for own properties. */ + var hasOwnProperty$5 = objectProto$7.hasOwnProperty; + + /** Used to detect if a method is native. */ + var reIsNative = RegExp('^' + + funcToString$2.call(hasOwnProperty$5).replace(reRegExpChar, '\\$&') + .replace(/hasOwnProperty|(function).*?(?=\\\()| for .+?(?=\\\])/g, '$1.*?') + '$' + ); + + /** + * The base implementation of `_.isNative` without bad shim checks. + * + * @private + * @param {*} value The value to check. + * @returns {boolean} Returns `true` if `value` is a native function, + * else `false`. + */ + function baseIsNative(value) { + if (!isObject(value) || isMasked(value)) { + return false; + } + var pattern = isFunction(value) ? reIsNative : reIsHostCtor; + return pattern.test(toSource(value)); + } + + /** + * Gets the value at `key` of `object`. + * + * @private + * @param {Object} [object] The object to query. + * @param {string} key The key of the property to get. + * @returns {*} Returns the property value. + */ + function getValue(object, key) { + return object == null ? undefined : object[key]; + } + + /** + * Gets the native function at `key` of `object`. + * + * @private + * @param {Object} object The object to query. + * @param {string} key The key of the method to get. + * @returns {*} Returns the function if it's native, else `undefined`. + */ + function getNative(object, key) { + var value = getValue(object, key); + return baseIsNative(value) ? value : undefined; + } + + /* Built-in method references that are verified to be native. */ + var Map$1 = getNative(root, 'Map'); + + /* Built-in method references that are verified to be native. */ + var nativeCreate = getNative(Object, 'create'); + + /** + * Removes all key-value entries from the hash. + * + * @private + * @name clear + * @memberOf Hash + */ + function hashClear() { + this.__data__ = nativeCreate ? nativeCreate(null) : {}; + this.size = 0; + } + + /** + * Removes `key` and its value from the hash. + * + * @private + * @name delete + * @memberOf Hash + * @param {Object} hash The hash to modify. + * @param {string} key The key of the value to remove. + * @returns {boolean} Returns `true` if the entry was removed, else `false`. + */ + function hashDelete(key) { + var result = this.has(key) && delete this.__data__[key]; + this.size -= result ? 1 : 0; + return result; + } + + /** Used to stand-in for `undefined` hash values. */ + var HASH_UNDEFINED = '__lodash_hash_undefined__'; + + /** Used for built-in method references. */ + var objectProto$8 = Object.prototype; + + /** Used to check objects for own properties. */ + var hasOwnProperty$6 = objectProto$8.hasOwnProperty; + + /** + * Gets the hash value for `key`. + * + * @private + * @name get + * @memberOf Hash + * @param {string} key The key of the value to get. + * @returns {*} Returns the entry value. + */ + function hashGet(key) { + var data = this.__data__; + if (nativeCreate) { + var result = data[key]; + return result === HASH_UNDEFINED ? undefined : result; + } + return hasOwnProperty$6.call(data, key) ? data[key] : undefined; + } + + /** Used for built-in method references. */ + var objectProto$9 = Object.prototype; + + /** Used to check objects for own properties. */ + var hasOwnProperty$7 = objectProto$9.hasOwnProperty; + + /** + * Checks if a hash value for `key` exists. + * + * @private + * @name has + * @memberOf Hash + * @param {string} key The key of the entry to check. + * @returns {boolean} Returns `true` if an entry for `key` exists, else `false`. + */ + function hashHas(key) { + var data = this.__data__; + return nativeCreate ? (data[key] !== undefined) : hasOwnProperty$7.call(data, key); + } + + /** Used to stand-in for `undefined` hash values. */ + var HASH_UNDEFINED$1 = '__lodash_hash_undefined__'; + + /** + * Sets the hash `key` to `value`. + * + * @private + * @name set + * @memberOf Hash + * @param {string} key The key of the value to set. + * @param {*} value The value to set. + * @returns {Object} Returns the hash instance. + */ + function hashSet(key, value) { + var data = this.__data__; + this.size += this.has(key) ? 0 : 1; + data[key] = (nativeCreate && value === undefined) ? HASH_UNDEFINED$1 : value; + return this; + } + + /** + * Creates a hash object. + * + * @private + * @constructor + * @param {Array} [entries] The key-value pairs to cache. + */ + function Hash(entries) { + var index = -1, + length = entries == null ? 0 : entries.length; + + this.clear(); + while (++index < length) { + var entry = entries[index]; + this.set(entry[0], entry[1]); + } + } + + // Add methods to `Hash`. + Hash.prototype.clear = hashClear; + Hash.prototype['delete'] = hashDelete; + Hash.prototype.get = hashGet; + Hash.prototype.has = hashHas; + Hash.prototype.set = hashSet; + + /** + * Removes all key-value entries from the map. + * + * @private + * @name clear + * @memberOf MapCache + */ + function mapCacheClear() { + this.size = 0; + this.__data__ = { + 'hash': new Hash, + 'map': new (Map$1 || ListCache), + 'string': new Hash + }; + } + + /** + * Checks if `value` is suitable for use as unique object key. + * + * @private + * @param {*} value The value to check. + * @returns {boolean} Returns `true` if `value` is suitable, else `false`. + */ + function isKeyable(value) { + var type = typeof value; + return (type == 'string' || type == 'number' || type == 'symbol' || type == 'boolean') + ? (value !== '__proto__') + : (value === null); + } + + /** + * Gets the data for `map`. + * + * @private + * @param {Object} map The map to query. + * @param {string} key The reference key. + * @returns {*} Returns the map data. + */ + function getMapData(map, key) { + var data = map.__data__; + return isKeyable(key) + ? data[typeof key == 'string' ? 'string' : 'hash'] + : data.map; + } + + /** + * Removes `key` and its value from the map. + * + * @private + * @name delete + * @memberOf MapCache + * @param {string} key The key of the value to remove. + * @returns {boolean} Returns `true` if the entry was removed, else `false`. + */ + function mapCacheDelete(key) { + var result = getMapData(this, key)['delete'](key); + this.size -= result ? 1 : 0; + return result; + } + + /** + * Gets the map value for `key`. + * + * @private + * @name get + * @memberOf MapCache + * @param {string} key The key of the value to get. + * @returns {*} Returns the entry value. + */ + function mapCacheGet(key) { + return getMapData(this, key).get(key); + } + + /** + * Checks if a map value for `key` exists. + * + * @private + * @name has + * @memberOf MapCache + * @param {string} key The key of the entry to check. + * @returns {boolean} Returns `true` if an entry for `key` exists, else `false`. + */ + function mapCacheHas(key) { + return getMapData(this, key).has(key); + } + + /** + * Sets the map `key` to `value`. + * + * @private + * @name set + * @memberOf MapCache + * @param {string} key The key of the value to set. + * @param {*} value The value to set. + * @returns {Object} Returns the map cache instance. + */ + function mapCacheSet(key, value) { + var data = getMapData(this, key), + size = data.size; + + data.set(key, value); + this.size += data.size == size ? 0 : 1; + return this; + } + + /** + * Creates a map cache object to store key-value pairs. + * + * @private + * @constructor + * @param {Array} [entries] The key-value pairs to cache. + */ + function MapCache(entries) { + var index = -1, + length = entries == null ? 0 : entries.length; + + this.clear(); + while (++index < length) { + var entry = entries[index]; + this.set(entry[0], entry[1]); + } + } + + // Add methods to `MapCache`. + MapCache.prototype.clear = mapCacheClear; + MapCache.prototype['delete'] = mapCacheDelete; + MapCache.prototype.get = mapCacheGet; + MapCache.prototype.has = mapCacheHas; + MapCache.prototype.set = mapCacheSet; + + /** Used as the size to enable large array optimizations. */ + var LARGE_ARRAY_SIZE = 200; + + /** + * Sets the stack `key` to `value`. + * + * @private + * @name set + * @memberOf Stack + * @param {string} key The key of the value to set. + * @param {*} value The value to set. + * @returns {Object} Returns the stack cache instance. + */ + function stackSet(key, value) { + var data = this.__data__; + if (data instanceof ListCache) { + var pairs = data.__data__; + if (!Map$1 || (pairs.length < LARGE_ARRAY_SIZE - 1)) { + pairs.push([key, value]); + this.size = ++data.size; + return this; + } + data = this.__data__ = new MapCache(pairs); + } + data.set(key, value); + this.size = data.size; + return this; + } + + /** + * Creates a stack cache object to store key-value pairs. + * + * @private + * @constructor + * @param {Array} [entries] The key-value pairs to cache. + */ + function Stack(entries) { + var data = this.__data__ = new ListCache(entries); + this.size = data.size; + } + + // Add methods to `Stack`. + Stack.prototype.clear = stackClear; + Stack.prototype['delete'] = stackDelete; + Stack.prototype.get = stackGet; + Stack.prototype.has = stackHas; + Stack.prototype.set = stackSet; + + /** Used to stand-in for `undefined` hash values. */ + var HASH_UNDEFINED$2 = '__lodash_hash_undefined__'; + + /** + * Adds `value` to the array cache. + * + * @private + * @name add + * @memberOf SetCache + * @alias push + * @param {*} value The value to cache. + * @returns {Object} Returns the cache instance. + */ + function setCacheAdd(value) { + this.__data__.set(value, HASH_UNDEFINED$2); + return this; + } + + /** + * Checks if `value` is in the array cache. + * + * @private + * @name has + * @memberOf SetCache + * @param {*} value The value to search for. + * @returns {number} Returns `true` if `value` is found, else `false`. + */ + function setCacheHas(value) { + return this.__data__.has(value); + } + + /** + * + * Creates an array cache object to store unique values. + * + * @private + * @constructor + * @param {Array} [values] The values to cache. + */ + function SetCache(values) { + var index = -1, + length = values == null ? 0 : values.length; + + this.__data__ = new MapCache; + while (++index < length) { + this.add(values[index]); + } + } + + // Add methods to `SetCache`. + SetCache.prototype.add = SetCache.prototype.push = setCacheAdd; + SetCache.prototype.has = setCacheHas; + + /** + * A specialized version of `_.some` for arrays without support for iteratee + * shorthands. + * + * @private + * @param {Array} [array] The array to iterate over. + * @param {Function} predicate The function invoked per iteration. + * @returns {boolean} Returns `true` if any element passes the predicate check, + * else `false`. + */ + function arraySome(array, predicate) { + var index = -1, + length = array == null ? 0 : array.length; + + while (++index < length) { + if (predicate(array[index], index, array)) { + return true; + } + } + return false; + } + + /** + * Checks if a `cache` value for `key` exists. + * + * @private + * @param {Object} cache The cache to query. + * @param {string} key The key of the entry to check. + * @returns {boolean} Returns `true` if an entry for `key` exists, else `false`. + */ + function cacheHas(cache, key) { + return cache.has(key); + } + + /** Used to compose bitmasks for value comparisons. */ + var COMPARE_PARTIAL_FLAG = 1, + COMPARE_UNORDERED_FLAG = 2; + + /** + * A specialized version of `baseIsEqualDeep` for arrays with support for + * partial deep comparisons. + * + * @private + * @param {Array} array The array to compare. + * @param {Array} other The other array to compare. + * @param {number} bitmask The bitmask flags. See `baseIsEqual` for more details. + * @param {Function} customizer The function to customize comparisons. + * @param {Function} equalFunc The function to determine equivalents of values. + * @param {Object} stack Tracks traversed `array` and `other` objects. + * @returns {boolean} Returns `true` if the arrays are equivalent, else `false`. + */ + function equalArrays(array, other, bitmask, customizer, equalFunc, stack) { + var isPartial = bitmask & COMPARE_PARTIAL_FLAG, + arrLength = array.length, + othLength = other.length; + + if (arrLength != othLength && !(isPartial && othLength > arrLength)) { + return false; + } + // Assume cyclic values are equal. + var stacked = stack.get(array); + if (stacked && stack.get(other)) { + return stacked == other; + } + var index = -1, + result = true, + seen = (bitmask & COMPARE_UNORDERED_FLAG) ? new SetCache : undefined; + + stack.set(array, other); + stack.set(other, array); + + // Ignore non-index properties. + while (++index < arrLength) { + var arrValue = array[index], + othValue = other[index]; + + if (customizer) { + var compared = isPartial + ? customizer(othValue, arrValue, index, other, array, stack) + : customizer(arrValue, othValue, index, array, other, stack); + } + if (compared !== undefined) { + if (compared) { + continue; + } + result = false; + break; + } + // Recursively compare arrays (susceptible to call stack limits). + if (seen) { + if (!arraySome(other, function(othValue, othIndex) { + if (!cacheHas(seen, othIndex) && + (arrValue === othValue || equalFunc(arrValue, othValue, bitmask, customizer, stack))) { + return seen.push(othIndex); + } + })) { + result = false; + break; + } + } else if (!( + arrValue === othValue || + equalFunc(arrValue, othValue, bitmask, customizer, stack) + )) { + result = false; + break; + } + } + stack['delete'](array); + stack['delete'](other); + return result; + } + + /** Built-in value references. */ + var Uint8Array = root.Uint8Array; + + /** + * Converts `map` to its key-value pairs. + * + * @private + * @param {Object} map The map to convert. + * @returns {Array} Returns the key-value pairs. + */ + function mapToArray(map) { + var index = -1, + result = Array(map.size); + + map.forEach(function(value, key) { + result[++index] = [key, value]; + }); + return result; + } + + /** + * Converts `set` to an array of its values. + * + * @private + * @param {Object} set The set to convert. + * @returns {Array} Returns the values. + */ + function setToArray(set) { + var index = -1, + result = Array(set.size); + + set.forEach(function(value) { + result[++index] = value; + }); + return result; + } + + /** Used to compose bitmasks for value comparisons. */ + var COMPARE_PARTIAL_FLAG$1 = 1, + COMPARE_UNORDERED_FLAG$1 = 2; + + /** `Object#toString` result references. */ + var boolTag$1 = '[object Boolean]', + dateTag$1 = '[object Date]', + errorTag$1 = '[object Error]', + mapTag$1 = '[object Map]', + numberTag$2 = '[object Number]', + regexpTag$1 = '[object RegExp]', + setTag$1 = '[object Set]', + stringTag$2 = '[object String]', + symbolTag$1 = '[object Symbol]'; + + var arrayBufferTag$1 = '[object ArrayBuffer]', + dataViewTag$1 = '[object DataView]'; + + /** Used to convert symbols to primitives and strings. */ + var symbolProto$1 = Symbol ? Symbol.prototype : undefined, + symbolValueOf = symbolProto$1 ? symbolProto$1.valueOf : undefined; + + /** + * A specialized version of `baseIsEqualDeep` for comparing objects of + * the same `toStringTag`. + * + * **Note:** This function only supports comparing values with tags of + * `Boolean`, `Date`, `Error`, `Number`, `RegExp`, or `String`. + * + * @private + * @param {Object} object The object to compare. + * @param {Object} other The other object to compare. + * @param {string} tag The `toStringTag` of the objects to compare. + * @param {number} bitmask The bitmask flags. See `baseIsEqual` for more details. + * @param {Function} customizer The function to customize comparisons. + * @param {Function} equalFunc The function to determine equivalents of values. + * @param {Object} stack Tracks traversed `object` and `other` objects. + * @returns {boolean} Returns `true` if the objects are equivalent, else `false`. + */ + function equalByTag(object, other, tag, bitmask, customizer, equalFunc, stack) { + switch (tag) { + case dataViewTag$1: + if ((object.byteLength != other.byteLength) || + (object.byteOffset != other.byteOffset)) { + return false; + } + object = object.buffer; + other = other.buffer; + + case arrayBufferTag$1: + if ((object.byteLength != other.byteLength) || + !equalFunc(new Uint8Array(object), new Uint8Array(other))) { + return false; + } + return true; + + case boolTag$1: + case dateTag$1: + case numberTag$2: + // Coerce booleans to `1` or `0` and dates to milliseconds. + // Invalid dates are coerced to `NaN`. + return eq(+object, +other); + + case errorTag$1: + return object.name == other.name && object.message == other.message; + + case regexpTag$1: + case stringTag$2: + // Coerce regexes to strings and treat strings, primitives and objects, + // as equal. See http://www.ecma-international.org/ecma-262/7.0/#sec-regexp.prototype.tostring + // for more details. + return object == (other + ''); + + case mapTag$1: + var convert = mapToArray; + + case setTag$1: + var isPartial = bitmask & COMPARE_PARTIAL_FLAG$1; + convert || (convert = setToArray); + + if (object.size != other.size && !isPartial) { + return false; + } + // Assume cyclic values are equal. + var stacked = stack.get(object); + if (stacked) { + return stacked == other; + } + bitmask |= COMPARE_UNORDERED_FLAG$1; + + // Recursively compare objects (susceptible to call stack limits). + stack.set(object, other); + var result = equalArrays(convert(object), convert(other), bitmask, customizer, equalFunc, stack); + stack['delete'](object); + return result; + + case symbolTag$1: + if (symbolValueOf) { + return symbolValueOf.call(object) == symbolValueOf.call(other); + } + } + return false; + } + + /** + * Appends the elements of `values` to `array`. + * + * @private + * @param {Array} array The array to modify. + * @param {Array} values The values to append. + * @returns {Array} Returns `array`. + */ + function arrayPush(array, values) { + var index = -1, + length = values.length, + offset = array.length; + + while (++index < length) { + array[offset + index] = values[index]; + } + return array; + } + + /** + * The base implementation of `getAllKeys` and `getAllKeysIn` which uses + * `keysFunc` and `symbolsFunc` to get the enumerable property names and + * symbols of `object`. + * + * @private + * @param {Object} object The object to query. + * @param {Function} keysFunc The function to get the keys of `object`. + * @param {Function} symbolsFunc The function to get the symbols of `object`. + * @returns {Array} Returns the array of property names and symbols. + */ + function baseGetAllKeys(object, keysFunc, symbolsFunc) { + var result = keysFunc(object); + return isArray(object) ? result : arrayPush(result, symbolsFunc(object)); + } + + /** + * This method returns a new empty array. + * + * @static + * @memberOf _ + * @since 4.13.0 + * @category Util + * @returns {Array} Returns the new empty array. + * @example + * + * var arrays = _.times(2, _.stubArray); + * + * console.log(arrays); + * // => [[], []] + * + * console.log(arrays[0] === arrays[1]); + * // => false + */ + function stubArray() { + return []; + } + + /** Used for built-in method references. */ + var objectProto$a = Object.prototype; + + /** Built-in value references. */ + var propertyIsEnumerable$1 = objectProto$a.propertyIsEnumerable; + + /* Built-in method references for those with the same name as other `lodash` methods. */ + var nativeGetSymbols = Object.getOwnPropertySymbols; + + /** + * Creates an array of the own enumerable symbols of `object`. + * + * @private + * @param {Object} object The object to query. + * @returns {Array} Returns the array of symbols. + */ + var getSymbols = !nativeGetSymbols ? stubArray : function(object) { + if (object == null) { + return []; + } + object = Object(object); + return arrayFilter(nativeGetSymbols(object), function(symbol) { + return propertyIsEnumerable$1.call(object, symbol); + }); + }; + + /** + * Creates an array of own enumerable property names and symbols of `object`. + * + * @private + * @param {Object} object The object to query. + * @returns {Array} Returns the array of property names and symbols. + */ + function getAllKeys(object) { + return baseGetAllKeys(object, keys, getSymbols); + } + + /** Used to compose bitmasks for value comparisons. */ + var COMPARE_PARTIAL_FLAG$2 = 1; + + /** Used for built-in method references. */ + var objectProto$b = Object.prototype; + + /** Used to check objects for own properties. */ + var hasOwnProperty$8 = objectProto$b.hasOwnProperty; + + /** + * A specialized version of `baseIsEqualDeep` for objects with support for + * partial deep comparisons. + * + * @private + * @param {Object} object The object to compare. + * @param {Object} other The other object to compare. + * @param {number} bitmask The bitmask flags. See `baseIsEqual` for more details. + * @param {Function} customizer The function to customize comparisons. + * @param {Function} equalFunc The function to determine equivalents of values. + * @param {Object} stack Tracks traversed `object` and `other` objects. + * @returns {boolean} Returns `true` if the objects are equivalent, else `false`. + */ + function equalObjects(object, other, bitmask, customizer, equalFunc, stack) { + var isPartial = bitmask & COMPARE_PARTIAL_FLAG$2, + objProps = getAllKeys(object), + objLength = objProps.length, + othProps = getAllKeys(other), + othLength = othProps.length; + + if (objLength != othLength && !isPartial) { + return false; + } + var index = objLength; + while (index--) { + var key = objProps[index]; + if (!(isPartial ? key in other : hasOwnProperty$8.call(other, key))) { + return false; + } + } + // Assume cyclic values are equal. + var stacked = stack.get(object); + if (stacked && stack.get(other)) { + return stacked == other; + } + var result = true; + stack.set(object, other); + stack.set(other, object); + + var skipCtor = isPartial; + while (++index < objLength) { + key = objProps[index]; + var objValue = object[key], + othValue = other[key]; + + if (customizer) { + var compared = isPartial + ? customizer(othValue, objValue, key, other, object, stack) + : customizer(objValue, othValue, key, object, other, stack); + } + // Recursively compare objects (susceptible to call stack limits). + if (!(compared === undefined + ? (objValue === othValue || equalFunc(objValue, othValue, bitmask, customizer, stack)) + : compared + )) { + result = false; + break; + } + skipCtor || (skipCtor = key == 'constructor'); + } + if (result && !skipCtor) { + var objCtor = object.constructor, + othCtor = other.constructor; + + // Non `Object` object instances with different constructors are not equal. + if (objCtor != othCtor && + ('constructor' in object && 'constructor' in other) && + !(typeof objCtor == 'function' && objCtor instanceof objCtor && + typeof othCtor == 'function' && othCtor instanceof othCtor)) { + result = false; + } + } + stack['delete'](object); + stack['delete'](other); + return result; + } + + /* Built-in method references that are verified to be native. */ + var DataView = getNative(root, 'DataView'); + + /* Built-in method references that are verified to be native. */ + var Promise$1 = getNative(root, 'Promise'); + + /* Built-in method references that are verified to be native. */ + var Set$1 = getNative(root, 'Set'); + + /* Built-in method references that are verified to be native. */ + var WeakMap$1 = getNative(root, 'WeakMap'); + + /** `Object#toString` result references. */ + var mapTag$2 = '[object Map]', + objectTag$2 = '[object Object]', + promiseTag = '[object Promise]', + setTag$2 = '[object Set]', + weakMapTag$1 = '[object WeakMap]'; + + var dataViewTag$2 = '[object DataView]'; + + /** Used to detect maps, sets, and weakmaps. */ + var dataViewCtorString = toSource(DataView), + mapCtorString = toSource(Map$1), + promiseCtorString = toSource(Promise$1), + setCtorString = toSource(Set$1), + weakMapCtorString = toSource(WeakMap$1); + + /** + * Gets the `toStringTag` of `value`. + * + * @private + * @param {*} value The value to query. + * @returns {string} Returns the `toStringTag`. + */ + var getTag = baseGetTag; + + // Fallback for data views, maps, sets, and weak maps in IE 11 and promises in Node.js < 6. + if ((DataView && getTag(new DataView(new ArrayBuffer(1))) != dataViewTag$2) || + (Map$1 && getTag(new Map$1) != mapTag$2) || + (Promise$1 && getTag(Promise$1.resolve()) != promiseTag) || + (Set$1 && getTag(new Set$1) != setTag$2) || + (WeakMap$1 && getTag(new WeakMap$1) != weakMapTag$1)) { + getTag = function(value) { + var result = baseGetTag(value), + Ctor = result == objectTag$2 ? value.constructor : undefined, + ctorString = Ctor ? toSource(Ctor) : ''; + + if (ctorString) { + switch (ctorString) { + case dataViewCtorString: return dataViewTag$2; + case mapCtorString: return mapTag$2; + case promiseCtorString: return promiseTag; + case setCtorString: return setTag$2; + case weakMapCtorString: return weakMapTag$1; + } + } + return result; + }; + } + + var getTag$1 = getTag; + + /** Used to compose bitmasks for value comparisons. */ + var COMPARE_PARTIAL_FLAG$3 = 1; + + /** `Object#toString` result references. */ + var argsTag$2 = '[object Arguments]', + arrayTag$1 = '[object Array]', + objectTag$3 = '[object Object]'; + + /** Used for built-in method references. */ + var objectProto$c = Object.prototype; + + /** Used to check objects for own properties. */ + var hasOwnProperty$9 = objectProto$c.hasOwnProperty; + + /** + * A specialized version of `baseIsEqual` for arrays and objects which performs + * deep comparisons and tracks traversed objects enabling objects with circular + * references to be compared. + * + * @private + * @param {Object} object The object to compare. + * @param {Object} other The other object to compare. + * @param {number} bitmask The bitmask flags. See `baseIsEqual` for more details. + * @param {Function} customizer The function to customize comparisons. + * @param {Function} equalFunc The function to determine equivalents of values. + * @param {Object} [stack] Tracks traversed `object` and `other` objects. + * @returns {boolean} Returns `true` if the objects are equivalent, else `false`. + */ + function baseIsEqualDeep(object, other, bitmask, customizer, equalFunc, stack) { + var objIsArr = isArray(object), + othIsArr = isArray(other), + objTag = objIsArr ? arrayTag$1 : getTag$1(object), + othTag = othIsArr ? arrayTag$1 : getTag$1(other); + + objTag = objTag == argsTag$2 ? objectTag$3 : objTag; + othTag = othTag == argsTag$2 ? objectTag$3 : othTag; + + var objIsObj = objTag == objectTag$3, + othIsObj = othTag == objectTag$3, + isSameTag = objTag == othTag; + + if (isSameTag && isBuffer(object)) { + if (!isBuffer(other)) { + return false; + } + objIsArr = true; + objIsObj = false; + } + if (isSameTag && !objIsObj) { + stack || (stack = new Stack); + return (objIsArr || isTypedArray(object)) + ? equalArrays(object, other, bitmask, customizer, equalFunc, stack) + : equalByTag(object, other, objTag, bitmask, customizer, equalFunc, stack); + } + if (!(bitmask & COMPARE_PARTIAL_FLAG$3)) { + var objIsWrapped = objIsObj && hasOwnProperty$9.call(object, '__wrapped__'), + othIsWrapped = othIsObj && hasOwnProperty$9.call(other, '__wrapped__'); + + if (objIsWrapped || othIsWrapped) { + var objUnwrapped = objIsWrapped ? object.value() : object, + othUnwrapped = othIsWrapped ? other.value() : other; + + stack || (stack = new Stack); + return equalFunc(objUnwrapped, othUnwrapped, bitmask, customizer, stack); + } + } + if (!isSameTag) { + return false; + } + stack || (stack = new Stack); + return equalObjects(object, other, bitmask, customizer, equalFunc, stack); + } + + /** + * The base implementation of `_.isEqual` which supports partial comparisons + * and tracks traversed objects. + * + * @private + * @param {*} value The value to compare. + * @param {*} other The other value to compare. + * @param {boolean} bitmask The bitmask flags. + * 1 - Unordered comparison + * 2 - Partial comparison + * @param {Function} [customizer] The function to customize comparisons. + * @param {Object} [stack] Tracks traversed `value` and `other` objects. + * @returns {boolean} Returns `true` if the values are equivalent, else `false`. + */ + function baseIsEqual(value, other, bitmask, customizer, stack) { + if (value === other) { + return true; + } + if (value == null || other == null || (!isObjectLike(value) && !isObjectLike(other))) { + return value !== value && other !== other; + } + return baseIsEqualDeep(value, other, bitmask, customizer, baseIsEqual, stack); + } + + /** Used to compose bitmasks for value comparisons. */ + var COMPARE_PARTIAL_FLAG$4 = 1, + COMPARE_UNORDERED_FLAG$2 = 2; + + /** + * The base implementation of `_.isMatch` without support for iteratee shorthands. + * + * @private + * @param {Object} object The object to inspect. + * @param {Object} source The object of property values to match. + * @param {Array} matchData The property names, values, and compare flags to match. + * @param {Function} [customizer] The function to customize comparisons. + * @returns {boolean} Returns `true` if `object` is a match, else `false`. + */ + function baseIsMatch(object, source, matchData, customizer) { + var index = matchData.length, + length = index, + noCustomizer = !customizer; + + if (object == null) { + return !length; + } + object = Object(object); + while (index--) { + var data = matchData[index]; + if ((noCustomizer && data[2]) + ? data[1] !== object[data[0]] + : !(data[0] in object) + ) { + return false; + } + } + while (++index < length) { + data = matchData[index]; + var key = data[0], + objValue = object[key], + srcValue = data[1]; + + if (noCustomizer && data[2]) { + if (objValue === undefined && !(key in object)) { + return false; + } + } else { + var stack = new Stack; + if (customizer) { + var result = customizer(objValue, srcValue, key, object, source, stack); + } + if (!(result === undefined + ? baseIsEqual(srcValue, objValue, COMPARE_PARTIAL_FLAG$4 | COMPARE_UNORDERED_FLAG$2, customizer, stack) + : result + )) { + return false; + } + } + } + return true; + } + + /** + * Checks if `value` is suitable for strict equality comparisons, i.e. `===`. + * + * @private + * @param {*} value The value to check. + * @returns {boolean} Returns `true` if `value` if suitable for strict + * equality comparisons, else `false`. + */ + function isStrictComparable(value) { + return value === value && !isObject(value); + } + + /** + * Gets the property names, values, and compare flags of `object`. + * + * @private + * @param {Object} object The object to query. + * @returns {Array} Returns the match data of `object`. + */ + function getMatchData(object) { + var result = keys(object), + length = result.length; + + while (length--) { + var key = result[length], + value = object[key]; + + result[length] = [key, value, isStrictComparable(value)]; + } + return result; + } + + /** + * A specialized version of `matchesProperty` for source values suitable + * for strict equality comparisons, i.e. `===`. + * + * @private + * @param {string} key The key of the property to get. + * @param {*} srcValue The value to match. + * @returns {Function} Returns the new spec function. + */ + function matchesStrictComparable(key, srcValue) { + return function(object) { + if (object == null) { + return false; + } + return object[key] === srcValue && + (srcValue !== undefined || (key in Object(object))); + }; + } + + /** + * The base implementation of `_.matches` which doesn't clone `source`. + * + * @private + * @param {Object} source The object of property values to match. + * @returns {Function} Returns the new spec function. + */ + function baseMatches(source) { + var matchData = getMatchData(source); + if (matchData.length == 1 && matchData[0][2]) { + return matchesStrictComparable(matchData[0][0], matchData[0][1]); + } + return function(object) { + return object === source || baseIsMatch(object, source, matchData); + }; + } + + /** Used to match property names within property paths. */ + var reIsDeepProp = /\.|\[(?:[^[\]]*|(["'])(?:(?!\1)[^\\]|\\.)*?\1)\]/, + reIsPlainProp = /^\w*$/; + + /** + * Checks if `value` is a property name and not a property path. + * + * @private + * @param {*} value The value to check. + * @param {Object} [object] The object to query keys on. + * @returns {boolean} Returns `true` if `value` is a property name, else `false`. + */ + function isKey(value, object) { + if (isArray(value)) { + return false; + } + var type = typeof value; + if (type == 'number' || type == 'symbol' || type == 'boolean' || + value == null || isSymbol(value)) { + return true; + } + return reIsPlainProp.test(value) || !reIsDeepProp.test(value) || + (object != null && value in Object(object)); + } + + /** Error message constants. */ + var FUNC_ERROR_TEXT = 'Expected a function'; + + /** + * Creates a function that memoizes the result of `func`. If `resolver` is + * provided, it determines the cache key for storing the result based on the + * arguments provided to the memoized function. By default, the first argument + * provided to the memoized function is used as the map cache key. The `func` + * is invoked with the `this` binding of the memoized function. + * + * **Note:** The cache is exposed as the `cache` property on the memoized + * function. Its creation may be customized by replacing the `_.memoize.Cache` + * constructor with one whose instances implement the + * [`Map`](http://ecma-international.org/ecma-262/7.0/#sec-properties-of-the-map-prototype-object) + * method interface of `clear`, `delete`, `get`, `has`, and `set`. + * + * @static + * @memberOf _ + * @since 0.1.0 + * @category Function + * @param {Function} func The function to have its output memoized. + * @param {Function} [resolver] The function to resolve the cache key. + * @returns {Function} Returns the new memoized function. + * @example + * + * var object = { 'a': 1, 'b': 2 }; + * var other = { 'c': 3, 'd': 4 }; + * + * var values = _.memoize(_.values); + * values(object); + * // => [1, 2] + * + * values(other); + * // => [3, 4] + * + * object.a = 2; + * values(object); + * // => [1, 2] + * + * // Modify the result cache. + * values.cache.set(object, ['a', 'b']); + * values(object); + * // => ['a', 'b'] + * + * // Replace `_.memoize.Cache`. + * _.memoize.Cache = WeakMap; + */ + function memoize(func, resolver) { + if (typeof func != 'function' || (resolver != null && typeof resolver != 'function')) { + throw new TypeError(FUNC_ERROR_TEXT); + } + var memoized = function() { + var args = arguments, + key = resolver ? resolver.apply(this, args) : args[0], + cache = memoized.cache; + + if (cache.has(key)) { + return cache.get(key); + } + var result = func.apply(this, args); + memoized.cache = cache.set(key, result) || cache; + return result; + }; + memoized.cache = new (memoize.Cache || MapCache); + return memoized; + } + + // Expose `MapCache`. + memoize.Cache = MapCache; + + /** Used as the maximum memoize cache size. */ + var MAX_MEMOIZE_SIZE = 500; + + /** + * A specialized version of `_.memoize` which clears the memoized function's + * cache when it exceeds `MAX_MEMOIZE_SIZE`. + * + * @private + * @param {Function} func The function to have its output memoized. + * @returns {Function} Returns the new memoized function. + */ + function memoizeCapped(func) { + var result = memoize(func, function(key) { + if (cache.size === MAX_MEMOIZE_SIZE) { + cache.clear(); + } + return key; + }); + + var cache = result.cache; + return result; + } + + /** Used to match property names within property paths. */ + var rePropName = /[^.[\]]+|\[(?:(-?\d+(?:\.\d+)?)|(["'])((?:(?!\2)[^\\]|\\.)*?)\2)\]|(?=(?:\.|\[\])(?:\.|\[\]|$))/g; + + /** Used to match backslashes in property paths. */ + var reEscapeChar = /\\(\\)?/g; + + /** + * Converts `string` to a property path array. + * + * @private + * @param {string} string The string to convert. + * @returns {Array} Returns the property path array. + */ + var stringToPath = memoizeCapped(function(string) { + var result = []; + if (string.charCodeAt(0) === 46 /* . */) { + result.push(''); + } + string.replace(rePropName, function(match, number, quote, subString) { + result.push(quote ? subString.replace(reEscapeChar, '$1') : (number || match)); + }); + return result; + }); + + /** + * Casts `value` to a path array if it's not one. + * + * @private + * @param {*} value The value to inspect. + * @param {Object} [object] The object to query keys on. + * @returns {Array} Returns the cast property path array. + */ + function castPath(value, object) { + if (isArray(value)) { + return value; + } + return isKey(value, object) ? [value] : stringToPath(toString(value)); + } + + /** Used as references for various `Number` constants. */ + var INFINITY$1 = 1 / 0; + + /** + * Converts `value` to a string key if it's not a string or symbol. + * + * @private + * @param {*} value The value to inspect. + * @returns {string|symbol} Returns the key. + */ + function toKey(value) { + if (typeof value == 'string' || isSymbol(value)) { + return value; + } + var result = (value + ''); + return (result == '0' && (1 / value) == -INFINITY$1) ? '-0' : result; + } + + /** + * The base implementation of `_.get` without support for default values. + * + * @private + * @param {Object} object The object to query. + * @param {Array|string} path The path of the property to get. + * @returns {*} Returns the resolved value. + */ + function baseGet(object, path) { + path = castPath(path, object); + + var index = 0, + length = path.length; + + while (object != null && index < length) { + object = object[toKey(path[index++])]; + } + return (index && index == length) ? object : undefined; + } + + /** + * Gets the value at `path` of `object`. If the resolved value is + * `undefined`, the `defaultValue` is returned in its place. + * + * @static + * @memberOf _ + * @since 3.7.0 + * @category Object + * @param {Object} object The object to query. + * @param {Array|string} path The path of the property to get. + * @param {*} [defaultValue] The value returned for `undefined` resolved values. + * @returns {*} Returns the resolved value. + * @example + * + * var object = { 'a': [{ 'b': { 'c': 3 } }] }; + * + * _.get(object, 'a[0].b.c'); + * // => 3 + * + * _.get(object, ['a', '0', 'b', 'c']); + * // => 3 + * + * _.get(object, 'a.b.c', 'default'); + * // => 'default' + */ + function get(object, path, defaultValue) { + var result = object == null ? undefined : baseGet(object, path); + return result === undefined ? defaultValue : result; + } + + /** + * The base implementation of `_.hasIn` without support for deep paths. + * + * @private + * @param {Object} [object] The object to query. + * @param {Array|string} key The key to check. + * @returns {boolean} Returns `true` if `key` exists, else `false`. + */ + function baseHasIn(object, key) { + return object != null && key in Object(object); + } + + /** + * Checks if `path` exists on `object`. + * + * @private + * @param {Object} object The object to query. + * @param {Array|string} path The path to check. + * @param {Function} hasFunc The function to check properties. + * @returns {boolean} Returns `true` if `path` exists, else `false`. + */ + function hasPath(object, path, hasFunc) { + path = castPath(path, object); + + var index = -1, + length = path.length, + result = false; + + while (++index < length) { + var key = toKey(path[index]); + if (!(result = object != null && hasFunc(object, key))) { + break; + } + object = object[key]; + } + if (result || ++index != length) { + return result; + } + length = object == null ? 0 : object.length; + return !!length && isLength(length) && isIndex(key, length) && + (isArray(object) || isArguments(object)); + } + + /** + * Checks if `path` is a direct or inherited property of `object`. + * + * @static + * @memberOf _ + * @since 4.0.0 + * @category Object + * @param {Object} object The object to query. + * @param {Array|string} path The path to check. + * @returns {boolean} Returns `true` if `path` exists, else `false`. + * @example + * + * var object = _.create({ 'a': _.create({ 'b': 2 }) }); + * + * _.hasIn(object, 'a'); + * // => true + * + * _.hasIn(object, 'a.b'); + * // => true + * + * _.hasIn(object, ['a', 'b']); + * // => true + * + * _.hasIn(object, 'b'); + * // => false + */ + function hasIn(object, path) { + return object != null && hasPath(object, path, baseHasIn); + } + + /** Used to compose bitmasks for value comparisons. */ + var COMPARE_PARTIAL_FLAG$5 = 1, + COMPARE_UNORDERED_FLAG$3 = 2; + + /** + * The base implementation of `_.matchesProperty` which doesn't clone `srcValue`. + * + * @private + * @param {string} path The path of the property to get. + * @param {*} srcValue The value to match. + * @returns {Function} Returns the new spec function. + */ + function baseMatchesProperty(path, srcValue) { + if (isKey(path) && isStrictComparable(srcValue)) { + return matchesStrictComparable(toKey(path), srcValue); + } + return function(object) { + var objValue = get(object, path); + return (objValue === undefined && objValue === srcValue) + ? hasIn(object, path) + : baseIsEqual(srcValue, objValue, COMPARE_PARTIAL_FLAG$5 | COMPARE_UNORDERED_FLAG$3); + }; + } + + /** + * This method returns the first argument it receives. + * + * @static + * @since 0.1.0 + * @memberOf _ + * @category Util + * @param {*} value Any value. + * @returns {*} Returns `value`. + * @example + * + * var object = { 'a': 1 }; + * + * console.log(_.identity(object) === object); + * // => true + */ + function identity(value) { + return value; + } + + /** + * The base implementation of `_.property` without support for deep paths. + * + * @private + * @param {string} key The key of the property to get. + * @returns {Function} Returns the new accessor function. + */ + function baseProperty(key) { + return function(object) { + return object == null ? undefined : object[key]; + }; + } + + /** + * A specialized version of `baseProperty` which supports deep paths. + * + * @private + * @param {Array|string} path The path of the property to get. + * @returns {Function} Returns the new accessor function. + */ + function basePropertyDeep(path) { + return function(object) { + return baseGet(object, path); + }; + } + + /** + * Creates a function that returns the value at `path` of a given object. + * + * @static + * @memberOf _ + * @since 2.4.0 + * @category Util + * @param {Array|string} path The path of the property to get. + * @returns {Function} Returns the new accessor function. + * @example + * + * var objects = [ + * { 'a': { 'b': 2 } }, + * { 'a': { 'b': 1 } } + * ]; + * + * _.map(objects, _.property('a.b')); + * // => [2, 1] + * + * _.map(_.sortBy(objects, _.property(['a', 'b'])), 'a.b'); + * // => [1, 2] + */ + function property(path) { + return isKey(path) ? baseProperty(toKey(path)) : basePropertyDeep(path); + } + + /** + * The base implementation of `_.iteratee`. + * + * @private + * @param {*} [value=_.identity] The value to convert to an iteratee. + * @returns {Function} Returns the iteratee. + */ + function baseIteratee(value) { + // Don't store the `typeof` result in a variable to avoid a JIT bug in Safari 9. + // See https://bugs.webkit.org/show_bug.cgi?id=156034 for more details. + if (typeof value == 'function') { + return value; + } + if (value == null) { + return identity; + } + if (typeof value == 'object') { + return isArray(value) + ? baseMatchesProperty(value[0], value[1]) + : baseMatches(value); + } + return property(value); + } + + // validate object type + /** + * @TODO if provide with the keys then we need to check if the key:value type as well + * @param {object} value expected + * @param {array} [keys=null] if it has the keys array to compare as well + * @return {boolean} true if OK + */ + var checkIsObject = function(value, keys) { + if ( keys === void 0 ) keys=null; + + if (isPlainObject(value)) { + if (!keys) { + return true + } + if (checkIsArray(keys)) { + // please note we DON'T care if some is optional + // plese refer to the contract.json for the keys + return !keys.filter(function (key) { + var _value = value[key.name]; + return !(key.type.length > key.type.filter(function (type) { + var tmp; + if (_value !== undefined) { + if ((tmp = isArrayLike(type)) !== false) { + return !arrayTypeHandler({arg: _value}, tmp) + // return tmp.filter(t => !checkIsArray(_value, t)).length; + // @TODO there might be an object within an object with keys as well :S + } + return !combineFn(type)(_value) + } + return true + }).length) + }).length; + } + } + return false + }; + + /** + * fold this into it's own function to handler different object type + * @param {object} p the prepared object for process + * @return {boolean} + */ + var objectTypeHandler = function(p) { + var arg = p.arg; + var param = p.param; + var _args = [arg]; + if (Array.isArray(param.keys) && param.keys.length) { + _args.push(param.keys); + } + // just simple check + return Reflect.apply(checkIsObject, null, _args) + }; + + // custom validation error class + // when validaton failed + var JsonqlValidationError = /*@__PURE__*/(function (Error) { + function JsonqlValidationError() { + var args = [], len = arguments.length; + while ( len-- ) args[ len ] = arguments[ len ]; + + Error.apply(this, args); + + this.message = args[0]; + this.detail = args[1]; + + this.className = JsonqlValidationError.name; + + if (Error.captureStackTrace) { + Error.captureStackTrace(this, JsonqlValidationError); + } + } + + if ( Error ) JsonqlValidationError.__proto__ = Error; + JsonqlValidationError.prototype = Object.create( Error && Error.prototype ); + JsonqlValidationError.prototype.constructor = JsonqlValidationError; + + var staticAccessors = { name: { configurable: true } }; + + staticAccessors.name.get = function () { + return 'JsonqlValidationError'; + }; + + Object.defineProperties( JsonqlValidationError, staticAccessors ); + + return JsonqlValidationError; + }(Error)); + + /** + * This is a custom error to throw whenever a error happen inside the jsonql + * This help us to capture the right error, due to the call happens in sequence + * @param {string} message to tell what happen + * @param {mixed} extra things we want to add, 500? + */ + var JsonqlError$1 = /*@__PURE__*/(function (Error) { + function JsonqlError() { + var args = [], len = arguments.length; + while ( len-- ) args[ len ] = arguments[ len ]; + + Error.apply(this, args); + + this.message = args[0]; + this.detail = args[1]; + + this.className = JsonqlError.name; + + if (Error.captureStackTrace) { + Error.captureStackTrace(this, JsonqlError); + // this.detail = this.stack; + } + } + + if ( Error ) JsonqlError.__proto__ = Error; + JsonqlError.prototype = Object.create( Error && Error.prototype ); + JsonqlError.prototype.constructor = JsonqlError; + + var staticAccessors = { name: { configurable: true },statusCode: { configurable: true } }; + + staticAccessors.name.get = function () { + return 'JsonqlError'; + }; + + staticAccessors.statusCode.get = function () { + return NO_STATUS_CODE; + }; + + Object.defineProperties( JsonqlError, staticAccessors ); + + return JsonqlError; + }(Error)); + + // move the index.js code here that make more sense to find where things are + // import debug from 'debug' + // const debugFn = debug('jsonql-params-validator:validator') + // also export this for use in other places + + /** + * We need to handle those optional parameter without a default value + * @param {object} params from contract.json + * @return {boolean} for filter operation false is actually OK + */ + var optionalHandler = function( params ) { + var arg = params.arg; + var param = params.param; + if (isNotEmpty(arg)) { + // debug('call optional handler', arg, params); + // loop through the type in param + return !(param.type.length > param.type.filter(function (type) { return validateHandler(type, params); } + ).length) + } + return false + }; + + /** + * actually picking the validator + * @param {*} type for checking + * @param {*} value for checking + * @return {boolean} true on OK + */ + var validateHandler = function(type, value) { + var tmp; + switch (true) { + case type === OBJECT_TYPE$1: + // debugFn('call OBJECT_TYPE') + return !objectTypeHandler(value) + case type === ARRAY_TYPE$1: + // debugFn('call ARRAY_TYPE') + return !checkIsArray(value.arg) + // @TODO when the type is not present, it always fall through here + // so we need to find a way to actually pre-check the type first + // AKA check the contract.json map before running here + case (tmp = isArrayLike(type)) !== false: + // debugFn('call ARRAY_LIKE: %O', value) + return !arrayTypeHandler(value, tmp) + default: + return !combineFn(type)(value.arg) + } + }; + + /** + * it get too longer to fit in one line so break it out from the fn below + * @param {*} arg value + * @param {object} param config + * @return {*} value or apply default value + */ + var getOptionalValue = function(arg, param) { + if (arg !== undefined) { + return arg + } + return (param.optional === true && param.defaultvalue !== undefined ? param.defaultvalue : null) + }; + + /** + * padding the arguments with defaultValue if the arguments did not provide the value + * this will be the name export + * @param {array} args normalized arguments + * @param {array} params from contract.json + * @return {array} merge the two together + */ + var normalizeArgs = function(args, params) { + // first we should check if this call require a validation at all + // there will be situation where the function doesn't need args and params + if (!checkIsArray(params)) { + // debugFn('params value', params) + throw new JsonqlValidationError(PARAMS_NOT_ARRAY_ERR) + } + if (params.length === 0) { + return [] + } + if (!checkIsArray(args)) { + throw new JsonqlValidationError(ARGS_NOT_ARRAY_ERR) + } + // debugFn(args, params); + // fall through switch + switch(true) { + case args.length == params.length: // standard + return args.map(function (arg, i) { return ( + { + arg: arg, + index: i, + param: params[i] + } + ); }) + case params[0].variable === true: // using spread syntax + var type = params[0].type; + return args.map(function (arg, i) { return ( + { + arg: arg, + index: i, // keep the index for reference + param: params[i] || { type: type, name: '_' } + } + ); }) + // with optional defaultValue parameters + case args.length < params.length: + return params.map(function (param, i) { return ( + { + param: param, + index: i, + arg: getOptionalValue(args[i], param), + optional: param.optional || false + } + ); }) + // this one pass more than it should have anything after the args.length will be cast as any type + case args.length > params.length: + var ctn = params.length; + // this happens when we have those array. type + var _type = [ DEFAULT_TYPE$1 ]; + // we only looking at the first one, this might be a @BUG + /* + if ((tmp = isArrayLike(params[0].type[0])) !== false) { + _type = tmp; + } */ + // if we use the params as guide then the rest will get throw out + // which is not what we want, instead, anything without the param + // will get a any type and optional flag + return args.map(function (arg, i) { + var optional = i >= ctn ? true : !!params[i].optional; + var param = params[i] || { type: _type, name: ("_" + i) }; + return { + arg: optional ? getOptionalValue(arg, param) : arg, + index: i, + param: param, + optional: optional + } + }) + // @TODO find out if there is more cases not cover + default: // this should never happen + // debugFn('args', args) + // debugFn('params', params) + // this is unknown therefore we just throw it! + throw new JsonqlError$1(EXCEPTION_CASE_ERR, { args: args, params: params }) + } + }; + + // what we want is after the validaton we also get the normalized result + // which is with the optional property if the argument didn't provide it + /** + * process the array of params back to their arguments + * @param {array} result the params result + * @return {array} arguments + */ + var processReturn = function (result) { return result.map(function (r) { return r.arg; }); }; + + /** + * validator main interface + * @param {array} args the arguments pass to the method call + * @param {array} params from the contract for that method + * @param {boolean} [withResul=false] if true then this will return the normalize result as well + * @return {array} empty array on success, or failed parameter and reasons + */ + var validateSync = function(args, params, withResult) { + var obj; + + if ( withResult === void 0 ) withResult = false; + var cleanArgs = normalizeArgs(args, params); + var checkResult = cleanArgs.filter(function (p) { + // v1.4.4 this fixed the problem, the root level optional is from the last fn + if (p.optional === true || p.param.optional === true) { + return optionalHandler(p) + } + // because array of types means OR so if one pass means pass + return !(p.param.type.length > p.param.type.filter( + function (type) { return validateHandler(type, p); } + ).length) + }); + // using the same convention we been using all this time + return !withResult ? checkResult : ( obj = {}, obj[ERROR_KEY] = checkResult, obj[DATA_KEY] = processReturn(cleanArgs), obj ) + }; + + /** + * A wrapper method that return promise + * @param {array} args arguments + * @param {array} params from contract.json + * @param {boolean} [withResul=false] if true then this will return the normalize result as well + * @return {object} promise.then or catch + */ + var validateAsync = function(args, params, withResult) { + if ( withResult === void 0 ) withResult = false; + + return new Promise(function (resolver, rejecter) { + var result = validateSync(args, params, withResult); + if (withResult) { + return result[ERROR_KEY].length ? rejecter(result[ERROR_KEY]) + : resolver(result[DATA_KEY]) + } + // the different is just in the then or catch phrase + return result.length ? rejecter(result) : resolver([]) + }) + }; + + var defineProperty = (function() { + try { + var func = getNative(Object, 'defineProperty'); + func({}, '', {}); + return func; + } catch (e) {} + }()); + + /** + * The base implementation of `assignValue` and `assignMergeValue` without + * value checks. + * + * @private + * @param {Object} object The object to modify. + * @param {string} key The key of the property to assign. + * @param {*} value The value to assign. + */ + function baseAssignValue(object, key, value) { + if (key == '__proto__' && defineProperty) { + defineProperty(object, key, { + 'configurable': true, + 'enumerable': true, + 'value': value, + 'writable': true + }); + } else { + object[key] = value; + } + } + + /** + * This function is like `assignValue` except that it doesn't assign + * `undefined` values. + * + * @private + * @param {Object} object The object to modify. + * @param {string} key The key of the property to assign. + * @param {*} value The value to assign. + */ + function assignMergeValue(object, key, value) { + if ((value !== undefined && !eq(object[key], value)) || + (value === undefined && !(key in object))) { + baseAssignValue(object, key, value); + } + } + + /** Detect free variable `exports`. */ + var freeExports$2 = typeof exports == 'object' && exports && !exports.nodeType && exports; + + /** Detect free variable `module`. */ + var freeModule$2 = freeExports$2 && typeof module == 'object' && module && !module.nodeType && module; + + /** Detect the popular CommonJS extension `module.exports`. */ + var moduleExports$2 = freeModule$2 && freeModule$2.exports === freeExports$2; + + /** Built-in value references. */ + var Buffer$1 = moduleExports$2 ? root.Buffer : undefined, + allocUnsafe = Buffer$1 ? Buffer$1.allocUnsafe : undefined; + + /** + * Creates a clone of `buffer`. + * + * @private + * @param {Buffer} buffer The buffer to clone. + * @param {boolean} [isDeep] Specify a deep clone. + * @returns {Buffer} Returns the cloned buffer. + */ + function cloneBuffer(buffer, isDeep) { + if (isDeep) { + return buffer.slice(); + } + var length = buffer.length, + result = allocUnsafe ? allocUnsafe(length) : new buffer.constructor(length); + + buffer.copy(result); + return result; + } + + /** + * Creates a clone of `arrayBuffer`. + * + * @private + * @param {ArrayBuffer} arrayBuffer The array buffer to clone. + * @returns {ArrayBuffer} Returns the cloned array buffer. + */ + function cloneArrayBuffer(arrayBuffer) { + var result = new arrayBuffer.constructor(arrayBuffer.byteLength); + new Uint8Array(result).set(new Uint8Array(arrayBuffer)); + return result; + } + + /** + * Creates a clone of `typedArray`. + * + * @private + * @param {Object} typedArray The typed array to clone. + * @param {boolean} [isDeep] Specify a deep clone. + * @returns {Object} Returns the cloned typed array. + */ + function cloneTypedArray(typedArray, isDeep) { + var buffer = isDeep ? cloneArrayBuffer(typedArray.buffer) : typedArray.buffer; + return new typedArray.constructor(buffer, typedArray.byteOffset, typedArray.length); + } + + /** + * Copies the values of `source` to `array`. + * + * @private + * @param {Array} source The array to copy values from. + * @param {Array} [array=[]] The array to copy values to. + * @returns {Array} Returns `array`. + */ + function copyArray(source, array) { + var index = -1, + length = source.length; + + array || (array = Array(length)); + while (++index < length) { + array[index] = source[index]; + } + return array; + } + + /** Built-in value references. */ + var objectCreate = Object.create; + + /** + * The base implementation of `_.create` without support for assigning + * properties to the created object. + * + * @private + * @param {Object} proto The object to inherit from. + * @returns {Object} Returns the new object. + */ + var baseCreate = (function() { + function object() {} + return function(proto) { + if (!isObject(proto)) { + return {}; + } + if (objectCreate) { + return objectCreate(proto); + } + object.prototype = proto; + var result = new object; + object.prototype = undefined; + return result; + }; + }()); + + /** + * Initializes an object clone. + * + * @private + * @param {Object} object The object to clone. + * @returns {Object} Returns the initialized clone. + */ + function initCloneObject(object) { + return (typeof object.constructor == 'function' && !isPrototype(object)) + ? baseCreate(getPrototype(object)) + : {}; + } + + /** + * This method is like `_.isArrayLike` except that it also checks if `value` + * is an object. + * + * @static + * @memberOf _ + * @since 4.0.0 + * @category Lang + * @param {*} value The value to check. + * @returns {boolean} Returns `true` if `value` is an array-like object, + * else `false`. + * @example + * + * _.isArrayLikeObject([1, 2, 3]); + * // => true + * + * _.isArrayLikeObject(document.body.children); + * // => true + * + * _.isArrayLikeObject('abc'); + * // => false + * + * _.isArrayLikeObject(_.noop); + * // => false + */ + function isArrayLikeObject(value) { + return isObjectLike(value) && isArrayLike$1(value); + } + + /** + * Gets the value at `key`, unless `key` is "__proto__" or "constructor". + * + * @private + * @param {Object} object The object to query. + * @param {string} key The key of the property to get. + * @returns {*} Returns the property value. + */ + function safeGet(object, key) { + if (key === 'constructor' && typeof object[key] === 'function') { + return; + } + + if (key == '__proto__') { + return; + } + + return object[key]; + } + + /** Used for built-in method references. */ + var objectProto$d = Object.prototype; + + /** Used to check objects for own properties. */ + var hasOwnProperty$a = objectProto$d.hasOwnProperty; + + /** + * Assigns `value` to `key` of `object` if the existing value is not equivalent + * using [`SameValueZero`](http://ecma-international.org/ecma-262/7.0/#sec-samevaluezero) + * for equality comparisons. + * + * @private + * @param {Object} object The object to modify. + * @param {string} key The key of the property to assign. + * @param {*} value The value to assign. + */ + function assignValue(object, key, value) { + var objValue = object[key]; + if (!(hasOwnProperty$a.call(object, key) && eq(objValue, value)) || + (value === undefined && !(key in object))) { + baseAssignValue(object, key, value); + } + } + + /** + * Copies properties of `source` to `object`. + * + * @private + * @param {Object} source The object to copy properties from. + * @param {Array} props The property identifiers to copy. + * @param {Object} [object={}] The object to copy properties to. + * @param {Function} [customizer] The function to customize copied values. + * @returns {Object} Returns `object`. + */ + function copyObject(source, props, object, customizer) { + var isNew = !object; + object || (object = {}); + + var index = -1, + length = props.length; + + while (++index < length) { + var key = props[index]; + + var newValue = customizer + ? customizer(object[key], source[key], key, object, source) + : undefined; + + if (newValue === undefined) { + newValue = source[key]; + } + if (isNew) { + baseAssignValue(object, key, newValue); + } else { + assignValue(object, key, newValue); + } + } + return object; + } + + /** + * This function is like + * [`Object.keys`](http://ecma-international.org/ecma-262/7.0/#sec-object.keys) + * except that it includes inherited enumerable properties. + * + * @private + * @param {Object} object The object to query. + * @returns {Array} Returns the array of property names. + */ + function nativeKeysIn(object) { + var result = []; + if (object != null) { + for (var key in Object(object)) { + result.push(key); + } + } + return result; + } + + /** Used for built-in method references. */ + var objectProto$e = Object.prototype; + + /** Used to check objects for own properties. */ + var hasOwnProperty$b = objectProto$e.hasOwnProperty; + + /** + * The base implementation of `_.keysIn` which doesn't treat sparse arrays as dense. + * + * @private + * @param {Object} object The object to query. + * @returns {Array} Returns the array of property names. + */ + function baseKeysIn(object) { + if (!isObject(object)) { + return nativeKeysIn(object); + } + var isProto = isPrototype(object), + result = []; + + for (var key in object) { + if (!(key == 'constructor' && (isProto || !hasOwnProperty$b.call(object, key)))) { + result.push(key); + } + } + return result; + } + + /** + * Creates an array of the own and inherited enumerable property names of `object`. + * + * **Note:** Non-object values are coerced to objects. + * + * @static + * @memberOf _ + * @since 3.0.0 + * @category Object + * @param {Object} object The object to query. + * @returns {Array} Returns the array of property names. + * @example + * + * function Foo() { + * this.a = 1; + * this.b = 2; + * } + * + * Foo.prototype.c = 3; + * + * _.keysIn(new Foo); + * // => ['a', 'b', 'c'] (iteration order is not guaranteed) + */ + function keysIn(object) { + return isArrayLike$1(object) ? arrayLikeKeys(object, true) : baseKeysIn(object); + } + + /** + * Converts `value` to a plain object flattening inherited enumerable string + * keyed properties of `value` to own properties of the plain object. + * + * @static + * @memberOf _ + * @since 3.0.0 + * @category Lang + * @param {*} value The value to convert. + * @returns {Object} Returns the converted plain object. + * @example + * + * function Foo() { + * this.b = 2; + * } + * + * Foo.prototype.c = 3; + * + * _.assign({ 'a': 1 }, new Foo); + * // => { 'a': 1, 'b': 2 } + * + * _.assign({ 'a': 1 }, _.toPlainObject(new Foo)); + * // => { 'a': 1, 'b': 2, 'c': 3 } + */ + function toPlainObject(value) { + return copyObject(value, keysIn(value)); + } + + /** + * A specialized version of `baseMerge` for arrays and objects which performs + * deep merges and tracks traversed objects enabling objects with circular + * references to be merged. + * + * @private + * @param {Object} object The destination object. + * @param {Object} source The source object. + * @param {string} key The key of the value to merge. + * @param {number} srcIndex The index of `source`. + * @param {Function} mergeFunc The function to merge values. + * @param {Function} [customizer] The function to customize assigned values. + * @param {Object} [stack] Tracks traversed source values and their merged + * counterparts. + */ + function baseMergeDeep(object, source, key, srcIndex, mergeFunc, customizer, stack) { + var objValue = safeGet(object, key), + srcValue = safeGet(source, key), + stacked = stack.get(srcValue); + + if (stacked) { + assignMergeValue(object, key, stacked); + return; + } + var newValue = customizer + ? customizer(objValue, srcValue, (key + ''), object, source, stack) + : undefined; + + var isCommon = newValue === undefined; + + if (isCommon) { + var isArr = isArray(srcValue), + isBuff = !isArr && isBuffer(srcValue), + isTyped = !isArr && !isBuff && isTypedArray(srcValue); + + newValue = srcValue; + if (isArr || isBuff || isTyped) { + if (isArray(objValue)) { + newValue = objValue; + } + else if (isArrayLikeObject(objValue)) { + newValue = copyArray(objValue); + } + else if (isBuff) { + isCommon = false; + newValue = cloneBuffer(srcValue, true); + } + else if (isTyped) { + isCommon = false; + newValue = cloneTypedArray(srcValue, true); + } + else { + newValue = []; + } + } + else if (isPlainObject(srcValue) || isArguments(srcValue)) { + newValue = objValue; + if (isArguments(objValue)) { + newValue = toPlainObject(objValue); + } + else if (!isObject(objValue) || isFunction(objValue)) { + newValue = initCloneObject(srcValue); + } + } + else { + isCommon = false; + } + } + if (isCommon) { + // Recursively merge objects and arrays (susceptible to call stack limits). + stack.set(srcValue, newValue); + mergeFunc(newValue, srcValue, srcIndex, customizer, stack); + stack['delete'](srcValue); + } + assignMergeValue(object, key, newValue); + } + + /** + * The base implementation of `_.merge` without support for multiple sources. + * + * @private + * @param {Object} object The destination object. + * @param {Object} source The source object. + * @param {number} srcIndex The index of `source`. + * @param {Function} [customizer] The function to customize merged values. + * @param {Object} [stack] Tracks traversed source values and their merged + * counterparts. + */ + function baseMerge(object, source, srcIndex, customizer, stack) { + if (object === source) { + return; + } + baseFor(source, function(srcValue, key) { + stack || (stack = new Stack); + if (isObject(srcValue)) { + baseMergeDeep(object, source, key, srcIndex, baseMerge, customizer, stack); + } + else { + var newValue = customizer + ? customizer(safeGet(object, key), srcValue, (key + ''), object, source, stack) + : undefined; + + if (newValue === undefined) { + newValue = srcValue; + } + assignMergeValue(object, key, newValue); + } + }, keysIn); + } + + /** + * A faster alternative to `Function#apply`, this function invokes `func` + * with the `this` binding of `thisArg` and the arguments of `args`. + * + * @private + * @param {Function} func The function to invoke. + * @param {*} thisArg The `this` binding of `func`. + * @param {Array} args The arguments to invoke `func` with. + * @returns {*} Returns the result of `func`. + */ + function apply(func, thisArg, args) { + switch (args.length) { + case 0: return func.call(thisArg); + case 1: return func.call(thisArg, args[0]); + case 2: return func.call(thisArg, args[0], args[1]); + case 3: return func.call(thisArg, args[0], args[1], args[2]); + } + return func.apply(thisArg, args); + } + + /* Built-in method references for those with the same name as other `lodash` methods. */ + var nativeMax = Math.max; + + /** + * A specialized version of `baseRest` which transforms the rest array. + * + * @private + * @param {Function} func The function to apply a rest parameter to. + * @param {number} [start=func.length-1] The start position of the rest parameter. + * @param {Function} transform The rest array transform. + * @returns {Function} Returns the new function. + */ + function overRest(func, start, transform) { + start = nativeMax(start === undefined ? (func.length - 1) : start, 0); + return function() { + var args = arguments, + index = -1, + length = nativeMax(args.length - start, 0), + array = Array(length); + + while (++index < length) { + array[index] = args[start + index]; + } + index = -1; + var otherArgs = Array(start + 1); + while (++index < start) { + otherArgs[index] = args[index]; + } + otherArgs[start] = transform(array); + return apply(func, this, otherArgs); + }; + } + + /** + * Creates a function that returns `value`. + * + * @static + * @memberOf _ + * @since 2.4.0 + * @category Util + * @param {*} value The value to return from the new function. + * @returns {Function} Returns the new constant function. + * @example + * + * var objects = _.times(2, _.constant({ 'a': 1 })); + * + * console.log(objects); + * // => [{ 'a': 1 }, { 'a': 1 }] + * + * console.log(objects[0] === objects[1]); + * // => true + */ + function constant(value) { + return function() { + return value; + }; + } + + /** + * The base implementation of `setToString` without support for hot loop shorting. + * + * @private + * @param {Function} func The function to modify. + * @param {Function} string The `toString` result. + * @returns {Function} Returns `func`. + */ + var baseSetToString = !defineProperty ? identity : function(func, string) { + return defineProperty(func, 'toString', { + 'configurable': true, + 'enumerable': false, + 'value': constant(string), + 'writable': true + }); + }; + + /** Used to detect hot functions by number of calls within a span of milliseconds. */ + var HOT_COUNT = 800, + HOT_SPAN = 16; + + /* Built-in method references for those with the same name as other `lodash` methods. */ + var nativeNow = Date.now; + + /** + * Creates a function that'll short out and invoke `identity` instead + * of `func` when it's called `HOT_COUNT` or more times in `HOT_SPAN` + * milliseconds. + * + * @private + * @param {Function} func The function to restrict. + * @returns {Function} Returns the new shortable function. + */ + function shortOut(func) { + var count = 0, + lastCalled = 0; + + return function() { + var stamp = nativeNow(), + remaining = HOT_SPAN - (stamp - lastCalled); + + lastCalled = stamp; + if (remaining > 0) { + if (++count >= HOT_COUNT) { + return arguments[0]; + } + } else { + count = 0; + } + return func.apply(undefined, arguments); + }; + } + + /** + * Sets the `toString` method of `func` to return `string`. + * + * @private + * @param {Function} func The function to modify. + * @param {Function} string The `toString` result. + * @returns {Function} Returns `func`. + */ + var setToString = shortOut(baseSetToString); + + /** + * The base implementation of `_.rest` which doesn't validate or coerce arguments. + * + * @private + * @param {Function} func The function to apply a rest parameter to. + * @param {number} [start=func.length-1] The start position of the rest parameter. + * @returns {Function} Returns the new function. + */ + function baseRest(func, start) { + return setToString(overRest(func, start, identity), func + ''); + } + + /** + * Checks if the given arguments are from an iteratee call. + * + * @private + * @param {*} value The potential iteratee value argument. + * @param {*} index The potential iteratee index or key argument. + * @param {*} object The potential iteratee object argument. + * @returns {boolean} Returns `true` if the arguments are from an iteratee call, + * else `false`. + */ + function isIterateeCall(value, index, object) { + if (!isObject(object)) { + return false; + } + var type = typeof index; + if (type == 'number' + ? (isArrayLike$1(object) && isIndex(index, object.length)) + : (type == 'string' && index in object) + ) { + return eq(object[index], value); + } + return false; + } + + /** + * Creates a function like `_.assign`. + * + * @private + * @param {Function} assigner The function to assign values. + * @returns {Function} Returns the new assigner function. + */ + function createAssigner(assigner) { + return baseRest(function(object, sources) { + var index = -1, + length = sources.length, + customizer = length > 1 ? sources[length - 1] : undefined, + guard = length > 2 ? sources[2] : undefined; + + customizer = (assigner.length > 3 && typeof customizer == 'function') + ? (length--, customizer) + : undefined; + + if (guard && isIterateeCall(sources[0], sources[1], guard)) { + customizer = length < 3 ? undefined : customizer; + length = 1; + } + object = Object(object); + while (++index < length) { + var source = sources[index]; + if (source) { + assigner(object, source, index, customizer); + } + } + return object; + }); + } + + /** + * This method is like `_.assign` except that it recursively merges own and + * inherited enumerable string keyed properties of source objects into the + * destination object. Source properties that resolve to `undefined` are + * skipped if a destination value exists. Array and plain object properties + * are merged recursively. Other objects and value types are overridden by + * assignment. Source objects are applied from left to right. Subsequent + * sources overwrite property assignments of previous sources. + * + * **Note:** This method mutates `object`. + * + * @static + * @memberOf _ + * @since 0.5.0 + * @category Object + * @param {Object} object The destination object. + * @param {...Object} [sources] The source objects. + * @returns {Object} Returns `object`. + * @example + * + * var object = { + * 'a': [{ 'b': 2 }, { 'd': 4 }] + * }; + * + * var other = { + * 'a': [{ 'c': 3 }, { 'e': 5 }] + * }; + * + * _.merge(object, other); + * // => { 'a': [{ 'b': 2, 'c': 3 }, { 'd': 4, 'e': 5 }] } + */ + var merge = createAssigner(function(object, source, srcIndex) { + baseMerge(object, source, srcIndex); + }); + + /** + * Creates an object with the same keys as `object` and values generated + * by running each own enumerable string keyed property of `object` thru + * `iteratee`. The iteratee is invoked with three arguments: + * (value, key, object). + * + * @static + * @memberOf _ + * @since 2.4.0 + * @category Object + * @param {Object} object The object to iterate over. + * @param {Function} [iteratee=_.identity] The function invoked per iteration. + * @returns {Object} Returns the new mapped object. + * @see _.mapKeys + * @example + * + * var users = { + * 'fred': { 'user': 'fred', 'age': 40 }, + * 'pebbles': { 'user': 'pebbles', 'age': 1 } + * }; + * + * _.mapValues(users, function(o) { return o.age; }); + * // => { 'fred': 40, 'pebbles': 1 } (iteration order is not guaranteed) + * + * // The `_.property` iteratee shorthand. + * _.mapValues(users, 'age'); + * // => { 'fred': 40, 'pebbles': 1 } (iteration order is not guaranteed) + */ + function mapValues(object, iteratee) { + var result = {}; + iteratee = baseIteratee(iteratee); + + baseForOwn(object, function(value, key, object) { + baseAssignValue(result, key, iteratee(value, key, object)); + }); + return result; + } + + /** + * The opposite of `_.mapValues`; this method creates an object with the + * same values as `object` and keys generated by running each own enumerable + * string keyed property of `object` thru `iteratee`. The iteratee is invoked + * with three arguments: (value, key, object). + * + * @static + * @memberOf _ + * @since 3.8.0 + * @category Object + * @param {Object} object The object to iterate over. + * @param {Function} [iteratee=_.identity] The function invoked per iteration. + * @returns {Object} Returns the new mapped object. + * @see _.mapValues + * @example + * + * _.mapKeys({ 'a': 1, 'b': 2 }, function(value, key) { + * return key + value; + * }); + * // => { 'a1': 1, 'b2': 2 } + */ + function mapKeys(object, iteratee) { + var result = {}; + iteratee = baseIteratee(iteratee); + + baseForOwn(object, function(value, key, object) { + baseAssignValue(result, iteratee(value, key, object), value); + }); + return result; + } + + /** Error message constants. */ + var FUNC_ERROR_TEXT$1 = 'Expected a function'; + + /** + * Creates a function that negates the result of the predicate `func`. The + * `func` predicate is invoked with the `this` binding and arguments of the + * created function. + * + * @static + * @memberOf _ + * @since 3.0.0 + * @category Function + * @param {Function} predicate The predicate to negate. + * @returns {Function} Returns the new negated function. + * @example + * + * function isEven(n) { + * return n % 2 == 0; + * } + * + * _.filter([1, 2, 3, 4, 5, 6], _.negate(isEven)); + * // => [1, 3, 5] + */ + function negate(predicate) { + if (typeof predicate != 'function') { + throw new TypeError(FUNC_ERROR_TEXT$1); + } + return function() { + var args = arguments; + switch (args.length) { + case 0: return !predicate.call(this); + case 1: return !predicate.call(this, args[0]); + case 2: return !predicate.call(this, args[0], args[1]); + case 3: return !predicate.call(this, args[0], args[1], args[2]); + } + return !predicate.apply(this, args); + }; + } + + /** + * The base implementation of `_.set`. + * + * @private + * @param {Object} object The object to modify. + * @param {Array|string} path The path of the property to set. + * @param {*} value The value to set. + * @param {Function} [customizer] The function to customize path creation. + * @returns {Object} Returns `object`. + */ + function baseSet(object, path, value, customizer) { + if (!isObject(object)) { + return object; + } + path = castPath(path, object); + + var index = -1, + length = path.length, + lastIndex = length - 1, + nested = object; + + while (nested != null && ++index < length) { + var key = toKey(path[index]), + newValue = value; + + if (index != lastIndex) { + var objValue = nested[key]; + newValue = customizer ? customizer(objValue, key, nested) : undefined; + if (newValue === undefined) { + newValue = isObject(objValue) + ? objValue + : (isIndex(path[index + 1]) ? [] : {}); + } + } + assignValue(nested, key, newValue); + nested = nested[key]; + } + return object; + } + + /** + * The base implementation of `_.pickBy` without support for iteratee shorthands. + * + * @private + * @param {Object} object The source object. + * @param {string[]} paths The property paths to pick. + * @param {Function} predicate The function invoked per property. + * @returns {Object} Returns the new object. + */ + function basePickBy(object, paths, predicate) { + var index = -1, + length = paths.length, + result = {}; + + while (++index < length) { + var path = paths[index], + value = baseGet(object, path); + + if (predicate(value, path)) { + baseSet(result, castPath(path, object), value); + } + } + return result; + } + + /* Built-in method references for those with the same name as other `lodash` methods. */ + var nativeGetSymbols$1 = Object.getOwnPropertySymbols; + + /** + * Creates an array of the own and inherited enumerable symbols of `object`. + * + * @private + * @param {Object} object The object to query. + * @returns {Array} Returns the array of symbols. + */ + var getSymbolsIn = !nativeGetSymbols$1 ? stubArray : function(object) { + var result = []; + while (object) { + arrayPush(result, getSymbols(object)); + object = getPrototype(object); + } + return result; + }; + + /** + * Creates an array of own and inherited enumerable property names and + * symbols of `object`. + * + * @private + * @param {Object} object The object to query. + * @returns {Array} Returns the array of property names and symbols. + */ + function getAllKeysIn(object) { + return baseGetAllKeys(object, keysIn, getSymbolsIn); + } + + /** + * Creates an object composed of the `object` properties `predicate` returns + * truthy for. The predicate is invoked with two arguments: (value, key). + * + * @static + * @memberOf _ + * @since 4.0.0 + * @category Object + * @param {Object} object The source object. + * @param {Function} [predicate=_.identity] The function invoked per property. + * @returns {Object} Returns the new object. + * @example + * + * var object = { 'a': 1, 'b': '2', 'c': 3 }; + * + * _.pickBy(object, _.isNumber); + * // => { 'a': 1, 'c': 3 } + */ + function pickBy(object, predicate) { + if (object == null) { + return {}; + } + var props = arrayMap(getAllKeysIn(object), function(prop) { + return [prop]; + }); + predicate = baseIteratee(predicate); + return basePickBy(object, props, function(value, path) { + return predicate(value, path[0]); + }); + } + + /** + * The opposite of `_.pickBy`; this method creates an object composed of + * the own and inherited enumerable string keyed properties of `object` that + * `predicate` doesn't return truthy for. The predicate is invoked with two + * arguments: (value, key). + * + * @static + * @memberOf _ + * @since 4.0.0 + * @category Object + * @param {Object} object The source object. + * @param {Function} [predicate=_.identity] The function invoked per property. + * @returns {Object} Returns the new object. + * @example + * + * var object = { 'a': 1, 'b': '2', 'c': 3 }; + * + * _.omitBy(object, _.isNumber); + * // => { 'b': '2' } + */ + function omitBy(object, predicate) { + return pickBy(object, negate(baseIteratee(predicate))); + } + + /** + * Performs a deep comparison between two values to determine if they are + * equivalent. + * + * **Note:** This method supports comparing arrays, array buffers, booleans, + * date objects, error objects, maps, numbers, `Object` objects, regexes, + * sets, strings, symbols, and typed arrays. `Object` objects are compared + * by their own, not inherited, enumerable properties. Functions and DOM + * nodes are compared by strict equality, i.e. `===`. + * + * @static + * @memberOf _ + * @since 0.1.0 + * @category Lang + * @param {*} value The value to compare. + * @param {*} other The other value to compare. + * @returns {boolean} Returns `true` if the values are equivalent, else `false`. + * @example + * + * var object = { 'a': 1 }; + * var other = { 'a': 1 }; + * + * _.isEqual(object, other); + * // => true + * + * object === other; + * // => false + */ + function isEqual(value, other) { + return baseIsEqual(value, other); + } + + /** + * The base implementation of methods like `_.findKey` and `_.findLastKey`, + * without support for iteratee shorthands, which iterates over `collection` + * using `eachFunc`. + * + * @private + * @param {Array|Object} collection The collection to inspect. + * @param {Function} predicate The function invoked per iteration. + * @param {Function} eachFunc The function to iterate over `collection`. + * @returns {*} Returns the found element or its key, else `undefined`. + */ + function baseFindKey(collection, predicate, eachFunc) { + var result; + eachFunc(collection, function(value, key, collection) { + if (predicate(value, key, collection)) { + result = key; + return false; + } + }); + return result; + } + + /** + * This method is like `_.find` except that it returns the key of the first + * element `predicate` returns truthy for instead of the element itself. + * + * @static + * @memberOf _ + * @since 1.1.0 + * @category Object + * @param {Object} object The object to inspect. + * @param {Function} [predicate=_.identity] The function invoked per iteration. + * @returns {string|undefined} Returns the key of the matched element, + * else `undefined`. + * @example + * + * var users = { + * 'barney': { 'age': 36, 'active': true }, + * 'fred': { 'age': 40, 'active': false }, + * 'pebbles': { 'age': 1, 'active': true } + * }; + * + * _.findKey(users, function(o) { return o.age < 40; }); + * // => 'barney' (iteration order is not guaranteed) + * + * // The `_.matches` iteratee shorthand. + * _.findKey(users, { 'age': 1, 'active': true }); + * // => 'pebbles' + * + * // The `_.matchesProperty` iteratee shorthand. + * _.findKey(users, ['active', false]); + * // => 'fred' + * + * // The `_.property` iteratee shorthand. + * _.findKey(users, 'active'); + * // => 'barney' + */ + function findKey(object, predicate) { + return baseFindKey(object, baseIteratee(predicate), baseForOwn); + } + + /** + * @param {array} arr Array for check + * @param {*} value target + * @return {boolean} true on successs + */ + var isInArray = function(arr, value) { + return !!arr.filter(function (a) { return a === value; }).length + }; + + var isObjectHasKey = function(obj, key) { + var keys = Object.keys(obj); + return isInArray(keys, key) + }; + + // just not to make my head hurt + var isEmpty = function (value) { return !isNotEmpty(value); }; + + /** + * Map the alias to their key then grab their value over + * @param {object} config the user supplied config + * @param {object} appProps the default option map + * @return {object} the config keys replaced with the appProps key by the ALIAS + */ + function mapAliasConfigKeys(config, appProps) { + // need to do two steps + // 1. take key with alias key + var aliasMap = omitBy(appProps, function (value, k) { return !value[ALIAS_KEY$1]; } ); + if (isEqual(aliasMap, {})) { + return config; + } + return mapKeys(config, function (v, key) { return findKey(aliasMap, function (o) { return o.alias === key; }) || key; }) + } + + /** + * We only want to run the valdiation against the config (user supplied) value + * but keep the defaultOptions untouch + * @param {object} config configuraton supplied by user + * @param {object} appProps the default options map + * @return {object} the pristine values that will add back to the final output + */ + function preservePristineValues(config, appProps) { + // @BUG this will filter out those that is alias key + // we need to first map the alias keys back to their full key + var _config = mapAliasConfigKeys(config, appProps); + // take the default value out + var pristineValues = mapValues( + omitBy(appProps, function (value, key) { return isObjectHasKey(_config, key); }), + function (value) { return value.args; } + ); + // for testing the value + var checkAgainstAppProps = omitBy(appProps, function (value, key) { return !isObjectHasKey(_config, key); }); + // output + return { + pristineValues: pristineValues, + checkAgainstAppProps: checkAgainstAppProps, + config: _config // passing this correct values back + } + } + + /** + * This will take the value that is ONLY need to check + * @param {object} config that one + * @param {object} props map for creating checking + * @return {object} put that arg into the args + */ + function processConfigAction(config, props) { + // debugFn('processConfigAction', props) + // v.1.2.0 add checking if its mark optional and the value is empty then pass + return mapValues(props, function (value, key) { + var obj, obj$1; + + return ( + config[key] === undefined || (value[OPTIONAL_KEY$1] === true && isEmpty(config[key])) + ? merge({}, value, ( obj = {}, obj[KEY_WORD$1] = true, obj )) + : ( obj$1 = {}, obj$1[ARGS_KEY$1] = config[key], obj$1[TYPE_KEY$1] = value[TYPE_KEY$1], obj$1[OPTIONAL_KEY$1] = value[OPTIONAL_KEY$1] || false, obj$1[ENUM_KEY$1] = value[ENUM_KEY$1] || false, obj$1[CHECKER_KEY$1] = value[CHECKER_KEY$1] || false, obj$1 ) + ); + } + ) + } + + /** + * Quick transform + * @TODO we should only validate those that is pass from the config + * and pass through those values that is from the defaultOptions + * @param {object} opts that one + * @param {object} appProps mutation configuration options + * @return {object} put that arg into the args + */ + function prepareArgsForValidation(opts, appProps) { + var ref = preservePristineValues(opts, appProps); + var config = ref.config; + var pristineValues = ref.pristineValues; + var checkAgainstAppProps = ref.checkAgainstAppProps; + // output + return [ + processConfigAction(config, checkAgainstAppProps), + pristineValues + ] + } + + // this get throw from within the checkOptions when run through the enum failed + var JsonqlEnumError = /*@__PURE__*/(function (Error) { + function JsonqlEnumError() { + var args = [], len = arguments.length; + while ( len-- ) args[ len ] = arguments[ len ]; + + Error.apply(this, args); + + this.message = args[0]; + this.detail = args[1]; + + this.className = JsonqlEnumError.name; + + if (Error.captureStackTrace) { + Error.captureStackTrace(this, JsonqlEnumError); + } + } + + if ( Error ) JsonqlEnumError.__proto__ = Error; + JsonqlEnumError.prototype = Object.create( Error && Error.prototype ); + JsonqlEnumError.prototype.constructor = JsonqlEnumError; + + var staticAccessors = { name: { configurable: true } }; + + staticAccessors.name.get = function () { + return 'JsonqlEnumError'; + }; + + Object.defineProperties( JsonqlEnumError, staticAccessors ); + + return JsonqlEnumError; + }(Error)); + + // this will throw from inside the checkOptions + var JsonqlTypeError = /*@__PURE__*/(function (Error) { + function JsonqlTypeError() { + var args = [], len = arguments.length; + while ( len-- ) args[ len ] = arguments[ len ]; + + Error.apply(this, args); + + this.message = args[0]; + this.detail = args[1]; + + this.className = JsonqlTypeError.name; + + if (Error.captureStackTrace) { + Error.captureStackTrace(this, JsonqlTypeError); + } + } + + if ( Error ) JsonqlTypeError.__proto__ = Error; + JsonqlTypeError.prototype = Object.create( Error && Error.prototype ); + JsonqlTypeError.prototype.constructor = JsonqlTypeError; + + var staticAccessors = { name: { configurable: true } }; + + staticAccessors.name.get = function () { + return 'JsonqlTypeError'; + }; + + Object.defineProperties( JsonqlTypeError, staticAccessors ); + + return JsonqlTypeError; + }(Error)); + + // allow supply a custom checker function + // if that failed then we throw this error + var JsonqlCheckerError = /*@__PURE__*/(function (Error) { + function JsonqlCheckerError() { + var args = [], len = arguments.length; + while ( len-- ) args[ len ] = arguments[ len ]; + + Error.apply(this, args); + this.message = args[0]; + this.detail = args[1]; + + this.className = JsonqlCheckerError.name; + + if (Error.captureStackTrace) { + Error.captureStackTrace(this, JsonqlCheckerError); + } + } + + if ( Error ) JsonqlCheckerError.__proto__ = Error; + JsonqlCheckerError.prototype = Object.create( Error && Error.prototype ); + JsonqlCheckerError.prototype.constructor = JsonqlCheckerError; + + var staticAccessors = { name: { configurable: true } }; + + staticAccessors.name.get = function () { + return 'JsonqlCheckerError'; + }; + + Object.defineProperties( JsonqlCheckerError, staticAccessors ); + + return JsonqlCheckerError; + }(Error)); + + // breaking the whole thing up to see what cause the multiple calls issue + + // import debug from 'debug'; + // const debugFn = debug('jsonql-params-validator:options:validation') + + /** + * just make sure it returns an array to use + * @param {*} arg input + * @return {array} output + */ + var toArray = function (arg) { return checkIsArray(arg) ? arg : [arg]; }; + + /** + * DIY in array + * @param {array} arr to check against + * @param {*} value to check + * @return {boolean} true on OK + */ + var inArray = function (arr, value) { return ( + !!arr.filter(function (v) { return v === value; }).length + ); }; + + /** + * break out to make the code easier to read + * @param {object} value to process + * @param {function} cb the validateSync + * @return {array} empty on success + */ + function validateHandler$1(value, cb) { + var obj; + + // cb is the validateSync methods + var args = [ + [ value[ARGS_KEY$1] ], + [( obj = {}, obj[TYPE_KEY$1] = toArray(value[TYPE_KEY$1]), obj[OPTIONAL_KEY$1] = value[OPTIONAL_KEY$1], obj )] + ]; + // debugFn('validateHandler', args) + return Reflect.apply(cb, null, args) + } + + /** + * Check against the enum value if it's provided + * @param {*} value to check + * @param {*} enumv to check against if it's not false + * @return {boolean} true on OK + */ + var enumHandler = function (value, enumv) { + if (checkIsArray(enumv)) { + return inArray(enumv, value) + } + return true + }; + + /** + * Allow passing a function to check the value + * There might be a problem here if the function is incorrect + * and that will makes it hard to debug what is going on inside + * @TODO there could be a few feature add to this one under different circumstance + * @param {*} value to check + * @param {function} checker for checking + */ + var checkerHandler = function (value, checker) { + try { + return isFunction(checker) ? checker.apply(null, [value]) : false + } catch (e) { + return false + } + }; + + /** + * Taken out from the runValidaton this only validate the required values + * @param {array} args from the config2argsAction + * @param {function} cb validateSync + * @return {array} of configuration values + */ + function runValidationAction(cb) { + return function (value, key) { + // debugFn('runValidationAction', key, value) + if (value[KEY_WORD$1]) { + return value[ARGS_KEY$1] + } + var check = validateHandler$1(value, cb); + if (check.length) { + // log('runValidationAction', key, value) + throw new JsonqlTypeError(key, check) + } + if (value[ENUM_KEY$1] !== false && !enumHandler(value[ARGS_KEY$1], value[ENUM_KEY$1])) { + // log(ENUM_KEY, value[ENUM_KEY]) + throw new JsonqlEnumError(key) + } + if (value[CHECKER_KEY$1] !== false && !checkerHandler(value[ARGS_KEY$1], value[CHECKER_KEY$1])) { + // log(CHECKER_KEY, value[CHECKER_KEY]) + throw new JsonqlCheckerError(key) + } + return value[ARGS_KEY$1] + } + } + + /** + * @param {object} args from the config2argsAction + * @param {function} cb validateSync + * @return {object} of configuration values + */ + function runValidation(args, cb) { + var argsForValidate = args[0]; + var pristineValues = args[1]; + // turn the thing into an array and see what happen here + // debugFn('_args', argsForValidate) + var result = mapValues(argsForValidate, runValidationAction(cb)); + return merge(result, pristineValues) + } + + /// this is port back from the client to share across all projects + + // import debug from 'debug' + // const debugFn = debug('jsonql-params-validator:check-options-async') + + /** + * Quick transform + * @param {object} config that one + * @param {object} appProps mutation configuration options + * @return {object} put that arg into the args + */ + var configToArgs = function (config, appProps) { + return Promise.resolve( + prepareArgsForValidation(config, appProps) + ) + }; + + /** + * @param {object} config user provide configuration option + * @param {object} appProps mutation configuration options + * @param {object} constProps the immutable configuration options + * @param {function} cb the validateSync method + * @return {object} Promise resolve merge config object + */ + function checkOptionsAsync(config, appProps, constProps, cb) { + if ( config === void 0 ) config = {}; + + return configToArgs(config, appProps) + .then(function (args1) { return runValidation(args1, cb); }) + // next if every thing good then pass to final merging + .then(function (args2) { return merge({}, args2, constProps); }) + } + + // create function to construct the config entry so we don't need to keep building object + // import checkIsBoolean from '../boolean' + // import debug from 'debug'; + // const debugFn = debug('jsonql-params-validator:construct-config'); + /** + * @param {*} args value + * @param {string} type for value + * @param {boolean} [optional=false] + * @param {boolean|array} [enumv=false] + * @param {boolean|function} [checker=false] + * @return {object} config entry + */ + function constructConfig(args, type, optional, enumv, checker, alias) { + if ( optional === void 0 ) optional=false; + if ( enumv === void 0 ) enumv=false; + if ( checker === void 0 ) checker=false; + if ( alias === void 0 ) alias=false; + + var base = {}; + base[ARGS_KEY] = args; + base[TYPE_KEY] = type; + if (optional === true) { + base[OPTIONAL_KEY] = true; + } + if (checkIsArray(enumv)) { + base[ENUM_KEY] = enumv; + } + if (isFunction(checker)) { + base[CHECKER_KEY] = checker; + } + if (isString(alias)) { + base[ALIAS_KEY] = alias; + } + return base + } + + // export also create wrapper methods + + /** + * This has a different interface + * @param {*} value to supply + * @param {string|array} type for checking + * @param {object} params to map against the config check + * @param {array} params.enumv NOT enum + * @param {boolean} params.optional false then nothing + * @param {function} params.checker need more work on this one later + * @param {string} params.alias mostly for cmd + */ + var createConfig = function (value, type, params) { + if ( params === void 0 ) params = {}; + + // Note the enumv not ENUM + // const { enumv, optional, checker, alias } = params; + // let args = [value, type, optional, enumv, checker, alias]; + var o = params[OPTIONAL_KEY]; + var e = params[ENUM_KEY]; + var c = params[CHECKER_KEY]; + var a = params[ALIAS_KEY]; + return constructConfig.apply(null, [value, type, o, e, c, a]) + }; + + /** + * construct the actual end user method, rename with prefix get since 1.5.2 + * @param {function} validateSync validation method + * @return {function} for performaning the actual valdiation + */ + var getCheckConfigAsync = function(validateSync) { + /** + * We recreate the method here to avoid the circlar import + * @param {object} config user supply configuration + * @param {object} appProps mutation options + * @param {object} [constantProps={}] optional: immutation options + * @return {object} all checked configuration + */ + return function(config, appProps, constantProps) { + if ( constantProps === void 0 ) constantProps= {}; + + return checkOptionsAsync(config, appProps, constantProps, validateSync) + } + }; + + // export + var isString$1 = checkIsString; + var validateAsync$1 = validateAsync; + + var createConfig$1 = createConfig; + // construct the final output 1.5.2 + var checkConfigAsync = getCheckConfigAsync(validateSync); + + // move the get logger stuff here + + // it does nothing + var dummyLogger = function () {}; + + /** + * re-use the debugOn prop to control this log method + * @param {object} opts configuration + * @return {function} the log function + */ + var getLogger = function (opts) { + var debugOn = opts.debugOn; + if (debugOn) { + return function () { + var args = [], len = arguments.length; + while ( len-- ) args[ len ] = arguments[ len ]; + + Reflect.apply(console.info, console, ['[jsonql-ws-client-core]' ].concat( args)); + } + } + return dummyLogger + }; + + /** + * Make sure there is a log method + * @param {object} opts configuration + * @return {object} opts + */ + var getLogFn = function (opts) { + var log = opts.log; // 1.3.9 if we pass a log method here then we use this + if (!log || typeof log !== 'function') { + return getLogger(opts) + } + opts.log('---> getLogFn user supplied log function <---', opts); + return log + }; + + // group all the repetitive message here + + var TAKEN_BY_OTHER_TYPE_ERR = 'You are trying to register an event already been taken by other type:'; + + // Create two WeakMap store as a private keys + var NB_EVENT_SERVICE_PRIVATE_STORE = new WeakMap(); + var NB_EVENT_SERVICE_PRIVATE_LAZY = new WeakMap(); + + /** + * generate a 32bit hash based on the function.toString() + * _from http://stackoverflow.com/questions/7616461/generate-a-hash-_from-string-in-javascript-jquery + * @param {string} s the converted to string function + * @return {string} the hashed function string + */ + function hashCode(s) { + return s.split("").reduce(function(a,b){a=((a<<5)-a)+b.charCodeAt(0);return a&a},0) + } + + /** + * wrapper to make sure it string + * @param {*} input whatever + * @return {string} output + */ + function hashCode2Str(s) { + return hashCode(s) + '' + } + + /** + * Just check if a pattern is an RegExp object + * @param {*} pat whatever + * @return {boolean} false when its not + */ + function isRegExp(pat) { + return pat instanceof RegExp + } + + /** + * check if its string + * @param {*} arg whatever + * @return {boolean} false when it's not + */ + function isString$2(arg) { + return typeof arg === 'string' + } + + /** + * Find from the array by matching the pattern + * @param {*} pattern a string or RegExp object + * @return {object} regex object or false when we can not id the input + */ + function getRegex(pattern) { + switch (true) { + case isRegExp(pattern) === true: + return pattern + case isString$2(pattern) === true: + return new RegExp(pattern) + default: + return false + } + } + + // making all the functionality on it's own + + var SuspendClass = function SuspendClass() { + // suspend, release and queue + this.__suspend_state__ = null; + // to do this proper we don't use a new prop to hold the event name pattern + this.__pattern__ = null; + this.queueStore = new Set(); + }; + + var prototypeAccessors = { $queues: { configurable: true } }; + + /** + * start suspend + * @return {void} + */ + SuspendClass.prototype.$suspend = function $suspend () { + this.logger("---> SUSPEND ALL OPS <---"); + this.__suspend__(true); + }; + + /** + * release the queue + * @return {void} + */ + SuspendClass.prototype.$release = function $release () { + this.logger("---> RELEASE SUSPENDED QUEUE <---"); + this.__suspend__(false); + }; + + /** + * suspend event by pattern + * @param {string} pattern the pattern search matches the event name + * @return {void} + */ + SuspendClass.prototype.$suspendEvent = function $suspendEvent (pattern) { + var regex = getRegex(pattern); + if (isRegExp(regex)) { + this.__pattern__ = regex; + return this.$suspend() + } + throw new Error(("We expect a pattern variable to be string or RegExp, but we got \"" + (typeof regex) + "\" instead")) + }; + + /** + * queuing call up when it's in suspend mode + * @param {string} evt the event name + * @param {*} args unknown number of arguments + * @return {boolean} true when added or false when it's not + */ + SuspendClass.prototype.$queue = function $queue (evt) { + var args = [], len = arguments.length - 1; + while ( len-- > 0 ) args[ len ] = arguments[ len + 1 ]; + + this.logger('($queue) get called'); + if (this.__suspend_state__ === true) { + if (isRegExp(this.__pattern__)) { // it's better then check if its not null + // check the pattern and decide if we want to suspend it or not + var found = this.__pattern__.test(evt); + if (!found) { + return false + } + } + this.logger('($queue) added to $queue', args); + // @TODO there shouldn't be any duplicate, but how to make sure? + this.queueStore.add([evt].concat(args)); + // return this.queueStore.size + } + return !!this.__suspend_state__ + }; + + /** + * a getter to get all the store queue + * @return {array} Set turn into Array before return + */ + prototypeAccessors.$queues.get = function () { + var size = this.queueStore.size; + this.logger('($queues)', ("size: " + size)); + if (size > 0) { + return Array.from(this.queueStore) + } + return [] + }; + + /** + * to set the suspend and check if it's boolean value + * @param {boolean} value to trigger + */ + SuspendClass.prototype.__suspend__ = function __suspend__ (value) { + if (typeof value === 'boolean') { + var lastValue = this.__suspend_state__; + this.__suspend_state__ = value; + this.logger(("($suspend) Change from \"" + lastValue + "\" --> \"" + value + "\"")); + if (lastValue === true && value === false) { + this.__release__(); + } + } else { + throw new Error(("$suspend only accept Boolean value! we got " + (typeof value))) + } + }; + + /** + * Release the queue + * @return {int} size if any + */ + SuspendClass.prototype.__release__ = function __release__ () { + var this$1 = this; + + var size = this.queueStore.size; + var pattern = this.__pattern__; + this.__pattern__ = null; + this.logger(("(release) was called with " + size + (pattern ? ' for "' + pattern + '"': '') + " item" + (size > 1 ? 's' : ''))); + if (size > 0) { + var queue = Array.from(this.queueStore); + this.queueStore.clear(); + this.logger('(release queue)', queue); + queue.forEach(function (args) { + this$1.logger(args); + Reflect.apply(this$1.$trigger, this$1, args); + }); + this.logger(("Release size " + (this.queueStore.size))); + } + + return size + }; + + Object.defineProperties( SuspendClass.prototype, prototypeAccessors ); + + // break up the main file because its getting way too long + + var StoreService = /*@__PURE__*/(function (SuspendClass) { + function StoreService(config) { + if ( config === void 0 ) config = {}; + + SuspendClass.call(this); + if (config.logger && typeof config.logger === 'function') { + this.logger = config.logger; + } + this.keep = config.keep; + // for the $done setter + this.result = config.keep ? [] : null; + // we need to init the store first otherwise it could be a lot of checking later + this.normalStore = new Map(); + this.lazyStore = new Map(); + } + + if ( SuspendClass ) StoreService.__proto__ = SuspendClass; + StoreService.prototype = Object.create( SuspendClass && SuspendClass.prototype ); + StoreService.prototype.constructor = StoreService; + + var prototypeAccessors = { normalStore: { configurable: true },lazyStore: { configurable: true } }; + + /** + * validate the event name(s) + * @param {string[]} evt event name + * @return {boolean} true when OK + */ + StoreService.prototype.validateEvt = function validateEvt () { + var this$1 = this; + var evt = [], len = arguments.length; + while ( len-- ) evt[ len ] = arguments[ len ]; + + evt.forEach(function (e) { + if (!isString$2(e)) { + this$1.logger('(validateEvt)', e); + throw new Error(("Event name must be string type! we got " + (typeof e))) + } + }); + return true + }; + + /** + * Simple quick check on the two main parameters + * @param {string} evt event name + * @param {function} callback function to call + * @return {boolean} true when OK + */ + StoreService.prototype.validate = function validate (evt, callback) { + if (this.validateEvt(evt)) { + if (typeof callback === 'function') { + return true + } + } + throw new Error(("callback required to be function type! we got " + (typeof callback))) + }; + + /** + * Check if this type is correct or not added in V1.5.0 + * @param {string} type for checking + * @return {boolean} true on OK + */ + StoreService.prototype.validateType = function validateType (type) { + this.validateEvt(type); + var types = ['on', 'only', 'once', 'onlyOnce']; + return !!types.filter(function (t) { return type === t; }).length + }; + + /** + * Run the callback + * @param {function} callback function to execute + * @param {array} payload for callback + * @param {object} ctx context or null + * @return {void} the result store in $done + */ + StoreService.prototype.run = function run (callback, payload, ctx) { + this.logger('(run) callback:', callback, 'payload:', payload, 'context:', ctx); + this.$done = Reflect.apply(callback, ctx, this.toArray(payload)); + }; + + /** + * Take the content out and remove it from store id by the name + * @param {string} evt event name + * @param {string} [storeName = lazyStore] name of store + * @return {object|boolean} content or false on not found + */ + StoreService.prototype.takeFromStore = function takeFromStore (evt, storeName) { + if ( storeName === void 0 ) storeName = 'lazyStore'; + + var store = this[storeName]; // it could be empty at this point + if (store) { + this.logger('(takeFromStore)', storeName, store); + if (store.has(evt)) { + var content = store.get(evt); + this.logger(("(takeFromStore) has \"" + evt + "\""), content); + store.delete(evt); + return content + } + return false + } + throw new Error(("\"" + storeName + "\" is not supported!")) + }; + + /** + * This was part of the $get. We take it out + * so we could use a regex to remove more than one event + * @param {object} store the store to return from + * @param {string} evt event name + * @param {boolean} full return just the callback or everything + * @return {array|boolean} false when not found + */ + StoreService.prototype.findFromStore = function findFromStore (evt, store, full) { + if ( full === void 0 ) full = false; + + if (store.has(evt)) { + return Array + .from(store.get(evt)) + .map( function (l) { + if (full) { + return l + } + var key = l[0]; + var callback = l[1]; + return callback + }) + } + return false + }; + + /** + * Similar to the findFromStore, but remove + * @param {string} evt event name + * @param {object} store the store to remove from + * @return {boolean} false when not found + */ + StoreService.prototype.removeFromStore = function removeFromStore (evt, store) { + if (store.has(evt)) { + this.logger('($off)', evt); + store.delete(evt); + return true + } + return false + }; + + /** + * The add to store step is similar so make it generic for resuse + * @param {object} store which store to use + * @param {string} evt event name + * @param {spread} args because the lazy store and normal store store different things + * @return {array} store and the size of the store + */ + StoreService.prototype.addToStore = function addToStore (store, evt) { + var args = [], len = arguments.length - 2; + while ( len-- > 0 ) args[ len ] = arguments[ len + 2 ]; + + var fnSet; + if (store.has(evt)) { + this.logger(("(addToStore) \"" + evt + "\" existed")); + fnSet = store.get(evt); + } else { + this.logger(("(addToStore) create new Set for \"" + evt + "\"")); + // this is new + fnSet = new Set(); + } + // lazy only store 2 items - this is not the case in V1.6.0 anymore + // we need to check the first parameter is string or not + if (args.length > 2) { + if (Array.isArray(args[0])) { // lazy store + // check if this type of this event already register in the lazy store + var t = args[2]; + if (!this.checkTypeInLazyStore(evt, t)) { + fnSet.add(args); + } + } else { + if (!this.checkContentExist(args, fnSet)) { + this.logger("(addToStore) insert new", args); + fnSet.add(args); + } + } + } else { // add straight to lazy store + fnSet.add(args); + } + store.set(evt, fnSet); + return [store, fnSet.size] + }; + + /** + * @param {array} args for compare + * @param {object} fnSet A Set to search from + * @return {boolean} true on exist + */ + StoreService.prototype.checkContentExist = function checkContentExist (args, fnSet) { + var list = Array.from(fnSet); + return !!list.filter(function (li) { + var hash = li[0]; + return hash === args[0] + }).length + }; + + /** + * get the existing type to make sure no mix type add to the same store + * @param {string} evtName event name + * @param {string} type the type to check + * @return {boolean} true you can add, false then you can't add this type + */ + StoreService.prototype.checkTypeInStore = function checkTypeInStore (evtName, type) { + this.validateEvt(evtName, type); + var all = this.$get(evtName, true); + if (all === false) { + // pristine it means you can add + return true + } + // it should only have ONE type in ONE event store + return !all.filter(function (list) { + var t = list[3]; + return type !== t + }).length + }; + + /** + * This is checking just the lazy store because the structure is different + * therefore we need to use a new method to check it + */ + StoreService.prototype.checkTypeInLazyStore = function checkTypeInLazyStore (evtName, type) { + this.validateEvt(evtName, type); + var store = this.lazyStore.get(evtName); + this.logger('(checkTypeInLazyStore)', store); + if (store) { + return !!Array + .from(store) + .filter(function (li) { + var t = li[2]; + return t !== type + }).length + } + return false + }; + + /** + * wrapper to re-use the addToStore, + * V1.3.0 add extra check to see if this type can add to this evt + * @param {string} evt event name + * @param {string} type on or once + * @param {function} callback function + * @param {object} context the context the function execute in or null + * @return {number} size of the store + */ + StoreService.prototype.addToNormalStore = function addToNormalStore (evt, type, callback, context) { + if ( context === void 0 ) context = null; + + this.logger(("(addToNormalStore) try to add \"" + type + "\" --> \"" + evt + "\" to normal store")); + // @TODO we need to check the existing store for the type first! + if (this.checkTypeInStore(evt, type)) { + this.logger('(addToNormalStore)', ("\"" + type + "\" --> \"" + evt + "\" can add to normal store")); + var key = this.hashFnToKey(callback); + var args = [this.normalStore, evt, key, callback, context, type]; + var ref = Reflect.apply(this.addToStore, this, args); + var _store = ref[0]; + var size = ref[1]; + this.normalStore = _store; + return size + } + return false + }; + + /** + * Add to lazy store this get calls when the callback is not register yet + * so we only get a payload object or even nothing + * @param {string} evt event name + * @param {array} payload of arguments or empty if there is none + * @param {object} [context=null] the context the callback execute in + * @param {string} [type=false] register a type so no other type can add to this evt + * @return {number} size of the store + */ + StoreService.prototype.addToLazyStore = function addToLazyStore (evt, payload, context, type) { + if ( payload === void 0 ) payload = []; + if ( context === void 0 ) context = null; + if ( type === void 0 ) type = false; + + // this is add in V1.6.0 + // when there is type then we will need to check if this already added in lazy store + // and no other type can add to this lazy store + var args = [this.lazyStore, evt, this.toArray(payload), context]; + if (type) { + args.push(type); + } + var ref = Reflect.apply(this.addToStore, this, args); + var _store = ref[0]; + var size = ref[1]; + this.lazyStore = _store; + this.logger(("(addToLazyStore) size: " + size)); + return size + }; + + /** + * make sure we store the argument correctly + * @param {*} arg could be array + * @return {array} make sured + */ + StoreService.prototype.toArray = function toArray (arg) { + return Array.isArray(arg) ? arg : [arg] + }; + + /** + * setter to store the Set in private + * @param {object} obj a Set + */ + prototypeAccessors.normalStore.set = function (obj) { + NB_EVENT_SERVICE_PRIVATE_STORE.set(this, obj); + }; + + /** + * @return {object} Set object + */ + prototypeAccessors.normalStore.get = function () { + return NB_EVENT_SERVICE_PRIVATE_STORE.get(this) + }; + + /** + * setter to store the Set in lazy store + * @param {object} obj a Set + */ + prototypeAccessors.lazyStore.set = function (obj) { + NB_EVENT_SERVICE_PRIVATE_LAZY.set(this , obj); + }; + + /** + * @return {object} the lazy store Set + */ + prototypeAccessors.lazyStore.get = function () { + return NB_EVENT_SERVICE_PRIVATE_LAZY.get(this) + }; + + /** + * generate a hashKey to identify the function call + * The build-in store some how could store the same values! + * @param {function} fn the converted to string function + * @return {string} hashKey + */ + StoreService.prototype.hashFnToKey = function hashFnToKey (fn) { + return hashCode2Str(fn.toString()) + }; + + Object.defineProperties( StoreService.prototype, prototypeAccessors ); + + return StoreService; + }(SuspendClass)); + + // The top level + // export + var EventService = /*@__PURE__*/(function (StoreService) { + function EventService(config) { + if ( config === void 0 ) config = {}; + + StoreService.call(this, config); + } + + if ( StoreService ) EventService.__proto__ = StoreService; + EventService.prototype = Object.create( StoreService && StoreService.prototype ); + EventService.prototype.constructor = EventService; + + var prototypeAccessors = { $name: { configurable: true },is: { configurable: true },$done: { configurable: true } }; + + /** + * logger function for overwrite + */ + EventService.prototype.logger = function logger () {}; + + // for id if the instance is this class + prototypeAccessors.$name.get = function () { + return 'to1source-event' + }; + + // take this down in the next release + prototypeAccessors.is.get = function () { + return this.$name + }; + + ////////////////////////// + // PUBLIC METHODS // + ////////////////////////// + + /** + * Register your evt handler, note we don't check the type here, + * we expect you to be sensible and know what you are doing. + * @param {string} evt name of event + * @param {function} callback bind method --> if it's array or not + * @param {object} [context=null] to execute this call in + * @return {number} the size of the store + */ + EventService.prototype.$on = function $on (evt , callback , context) { + var this$1 = this; + if ( context === void 0 ) context = null; + + var type = 'on'; + this.validate(evt, callback); + // first need to check if this evt is in lazy store + var lazyStoreContent = this.takeFromStore(evt); + // this is normal register first then call later + if (lazyStoreContent === false) { + this.logger(("($on) \"" + evt + "\" is not in lazy store")); + // @TODO we need to check if there was other listener to this + // event and are they the same type then we could solve that + // register the different type to the same event name + return this.addToNormalStore(evt, type, callback, context) + } + this.logger(("($on) " + evt + " found in lazy store")); + // this is when they call $trigger before register this callback + var size = 0; + lazyStoreContent.forEach(function (content) { + var payload = content[0]; + var ctx = content[1]; + var t = content[2]; + if (t && t !== type) { + throw new Error((TAKEN_BY_OTHER_TYPE_ERR + " " + t)) + } + this$1.logger("($on)", ("call run \"" + evt + "\"")); + this$1.run(callback, payload, context || ctx); + size += this$1.addToNormalStore(evt, type, callback, context || ctx); + }); + + this.logger(("($on) return size " + size)); + return size + }; + + /** + * once only registered it once, there is no overwrite option here + * @NOTE change in v1.3.0 $once can add multiple listeners + * but once the event fired, it will remove this event (see $only) + * @param {string} evt name + * @param {function} callback to execute + * @param {object} [context=null] the handler execute in + * @return {boolean} result + */ + EventService.prototype.$once = function $once (evt , callback , context) { + if ( context === void 0 ) context = null; + + this.validate(evt, callback); + var type = 'once'; + var lazyStoreContent = this.takeFromStore(evt); + // this is normal register before call $trigger + var nStore = this.normalStore; + if (lazyStoreContent === false) { + this.logger(("($once) \"" + evt + "\" is not in the lazy store")); + // v1.3.0 $once now allow to add multiple listeners + return this.addToNormalStore(evt, type, callback, context) + } else { + // now this is the tricky bit + // there is a potential bug here that cause by the developer + // if they call $trigger first, the lazy won't know it's a once call + // so if in the middle they register any call with the same evt name + // then this $once call will be fucked - add this to the documentation + this.logger('($once)', lazyStoreContent); + var list = Array.from(lazyStoreContent); + // should never have more than 1 + var ref = list[0]; + var payload = ref[0]; + var ctx = ref[1]; + var t = ref[2]; + if (t && t !== type) { + throw new Error((TAKEN_BY_OTHER_TYPE_ERR + " " + t)) + } + this.logger('($once)', ("call run \"" + evt + "\"")); + this.run(callback, payload, context || ctx); + // remove this evt from store + this.$off(evt); + } + }; + + /** + * This one event can only bind one callbackback + * @param {string} evt event name + * @param {function} callback event handler + * @param {object} [context=null] the context the event handler execute in + * @return {boolean} true bind for first time, false already existed + */ + EventService.prototype.$only = function $only (evt, callback, context) { + var this$1 = this; + if ( context === void 0 ) context = null; + + this.validate(evt, callback); + var type = 'only'; + var added = false; + var lazyStoreContent = this.takeFromStore(evt); + // this is normal register before call $trigger + var nStore = this.normalStore; + if (!nStore.has(evt)) { + this.logger(("($only) \"" + evt + "\" add to normalStore")); + added = this.addToNormalStore(evt, type, callback, context); + } + if (lazyStoreContent !== false) { + // there are data store in lazy store + this.logger(("($only) \"" + evt + "\" found data in lazy store to execute")); + var list = Array.from(lazyStoreContent); + // $only allow to trigger this multiple time on the single handler + list.forEach( function (li) { + var payload = li[0]; + var ctx = li[1]; + var t = li[2]; + if (t && t !== type) { + throw new Error((TAKEN_BY_OTHER_TYPE_ERR + " " + t)) + } + this$1.logger(("($only) call run \"" + evt + "\"")); + this$1.run(callback, payload, context || ctx); + }); + } + return added + }; + + /** + * $only + $once this is because I found a very subtile bug when we pass a + * resolver, rejecter - and it never fire because that's OLD added in v1.4.0 + * @param {string} evt event name + * @param {function} callback to call later + * @param {object} [context=null] exeucte context + * @return {void} + */ + EventService.prototype.$onlyOnce = function $onlyOnce (evt, callback, context) { + if ( context === void 0 ) context = null; + + this.validate(evt, callback); + var type = 'onlyOnce'; + var added = false; + var lazyStoreContent = this.takeFromStore(evt); + // this is normal register before call $trigger + var nStore = this.normalStore; + if (!nStore.has(evt)) { + this.logger(("($onlyOnce) \"" + evt + "\" add to normalStore")); + added = this.addToNormalStore(evt, type, callback, context); + } + if (lazyStoreContent !== false) { + // there are data store in lazy store + this.logger('($onlyOnce)', lazyStoreContent); + var list = Array.from(lazyStoreContent); + // should never have more than 1 + var ref = list[0]; + var payload = ref[0]; + var ctx = ref[1]; + var t = ref[2]; + if (t && t !== 'onlyOnce') { + throw new Error((TAKEN_BY_OTHER_TYPE_ERR + " " + t)) + } + this.logger(("($onlyOnce) call run \"" + evt + "\"")); + this.run(callback, payload, context || ctx); + // remove this evt from store + this.$off(evt); + } + return added + }; + + /** + * This is a shorthand of $off + $on added in V1.5.0 + * @param {string} evt event name + * @param {function} callback to exeucte + * @param {object} [context = null] or pass a string as type + * @param {string} [type=on] what type of method to replace + * @return {*} + */ + EventService.prototype.$replace = function $replace (evt, callback, context, type) { + if ( context === void 0 ) context = null; + if ( type === void 0 ) type = 'on'; + + if (this.validateType(type)) { + this.$off(evt); + var method = this['$' + type]; + this.logger("($replace)", evt, callback); + return Reflect.apply(method, this, [evt, callback, context]) + } + throw new Error((type + " is not supported!")) + }; + + /** + * trigger the event + * @param {string} evt name NOT allow array anymore! + * @param {mixed} [payload = []] pass to fn + * @param {object|string} [context = null] overwrite what stored + * @param {string} [type=false] if pass this then we need to add type to store too + * @return {number} if it has been execute how many times + */ + EventService.prototype.$trigger = function $trigger (evt , payload , context, type) { + if ( payload === void 0 ) payload = []; + if ( context === void 0 ) context = null; + if ( type === void 0 ) type = false; + + this.validateEvt(evt); + var found = 0; + // first check the normal store + var nStore = this.normalStore; + this.logger('($trigger) normalStore', nStore); + if (nStore.has(evt)) { + this.logger(("($trigger) \"" + evt + "\" found")); + // @1.8.0 to add the suspend queue + var added = this.$queue(evt, payload, context, type); + if (added) { + this.logger(("($trigger) Currently suspended \"" + evt + "\" added to queue, nothing executed. Exit now.")); + return false // not executed + } + var nSet = Array.from(nStore.get(evt)); + var ctn = nSet.length; + var hasOnce = false; + for (var i=0; i < ctn; ++i) { + ++found; + // this.logger('found', found) + var ref = nSet[i]; + var _ = ref[0]; + var callback = ref[1]; + var ctx = ref[2]; + var type$1 = ref[3]; + this.logger(("($trigger) call run for " + evt)); + this.run(callback, payload, context || ctx); + if (type$1 === 'once' || type$1 === 'onlyOnce') { + hasOnce = true; + } + } + if (hasOnce) { + nStore.delete(evt); + } + return found + } + // now this is not register yet + this.addToLazyStore(evt, payload, context, type); + return found + }; + + /** + * this is an alias to the $trigger + * @NOTE breaking change in V1.6.0 we swap the parameter aroun + * @NOTE breaking change: v1.9.1 it return an function to accept the params as spread + * @param {string} evt event name + * @param {string} type of call + * @param {object} context what context callback execute in + * @return {*} from $trigger + */ + EventService.prototype.$call = function $call (evt, type, context) { + if ( type === void 0 ) type = false; + if ( context === void 0 ) context = null; + + var ctx = this; + + return function () { + var args = [], len = arguments.length; + while ( len-- ) args[ len ] = arguments[ len ]; + + var _args = [evt, args, context, type]; + return Reflect.apply(ctx.$trigger, ctx, _args) + } + }; + + /** + * remove the evt from all the stores + * @param {string} evt name + * @return {boolean} true actually delete something + */ + EventService.prototype.$off = function $off (evt) { + var this$1 = this; + + // @TODO we will allow a regex pattern to mass remove event + this.validateEvt(evt); + var stores = [ this.lazyStore, this.normalStore ]; + + return !!stores + .filter(function (store) { return store.has(evt); }) + .map(function (store) { return this$1.removeFromStore(evt, store); }) + .length + }; + + /** + * return all the listener bind to that event name + * @param {string} evtName event name + * @param {boolean} [full=false] if true then return the entire content + * @return {array|boolean} listerner(s) or false when not found + */ + EventService.prototype.$get = function $get (evt, full) { + if ( full === void 0 ) full = false; + + // @TODO should we allow the same Regex to search for all? + this.validateEvt(evt); + var store = this.normalStore; + return this.findFromStore(evt, store, full) + }; + + /** + * store the return result from the run + * @param {*} value whatever return from callback + */ + prototypeAccessors.$done.set = function (value) { + this.logger('($done) set value: ', value); + if (this.keep) { + this.result.push(value); + } else { + this.result = value; + } + }; + + /** + * @TODO is there any real use with the keep prop? + * getter for $done + * @return {*} whatever last store result + */ + prototypeAccessors.$done.get = function () { + this.logger('($done) get result:', this.result); + if (this.keep) { + return this.result[this.result.length - 1] + } + return this.result + }; + + /** + * Take a look inside the stores + * @param {number|null} idx of the store, null means all + * @return {void} + */ + EventService.prototype.$debug = function $debug (idx) { + var this$1 = this; + if ( idx === void 0 ) idx = null; + + var names = ['lazyStore', 'normalStore']; + var stores = [this.lazyStore, this.normalStore]; + if (stores[idx]) { + this.logger(names[idx], stores[idx]); + } else { + stores.map(function (store, i) { + this$1.logger(names[i], store); + }); + } + }; + + Object.defineProperties( EventService.prototype, prototypeAccessors ); + + return EventService; + }(StoreService)); + + // default + + // this will generate a event emitter and will be use everywhere + // create a clone version so we know which one we actually is using + var JsonqlWsEvt = /*@__PURE__*/(function (EventEmitterClass) { + function JsonqlWsEvt(logger) { + if (typeof logger !== 'function') { + throw new Error("Just die here the logger is not a function!") + } + logger("---> Create a new EventEmitter <---"); + // this ee will always come with the logger + // because we should take the ee from the configuration + EventEmitterClass.call(this, { logger: logger }); + } + + if ( EventEmitterClass ) JsonqlWsEvt.__proto__ = EventEmitterClass; + JsonqlWsEvt.prototype = Object.create( EventEmitterClass && EventEmitterClass.prototype ); + JsonqlWsEvt.prototype.constructor = JsonqlWsEvt; + + var prototypeAccessors = { name: { configurable: true } }; + + prototypeAccessors.name.get = function () { + return 'jsonql-ws-client-core' + }; + + Object.defineProperties( JsonqlWsEvt.prototype, prototypeAccessors ); + + return JsonqlWsEvt; + }(EventService)); + + /** + * getting the event emitter + * @param {object} opts configuration + * @return {object} the event emitter instance + */ + var getEventEmitter = function (opts) { + var log = opts.log; + var eventEmitter = opts.eventEmitter; + + if (eventEmitter) { + log("eventEmitter is:", eventEmitter.name); + return eventEmitter + } + + return new JsonqlWsEvt( opts.log ) + }; + + // bunch of generic helpers + + /** + * DIY in Array + * @param {array} arr to check from + * @param {*} value to check against + * @return {boolean} true on found + */ + var inArray$1 = function (arr, value) { return !!arr.filter(function (a) { return a === value; }).length; }; + + // quick and dirty to turn non array to array + var toArray$1 = function (arg) { return isArray(arg) ? arg : [arg]; }; + + /** + * @param {object} obj for search + * @param {string} key target + * @return {boolean} true on success + */ + var isObjectHasKey$1 = function(obj, key) { + try { + var keys = Object.keys(obj); + return inArray$1(keys, key) + } catch(e) { + // @BUG when the obj is not an OBJECT we got some weird output + return false + } + }; + + /** + * create a event name + * @param {string[]} args + * @return {string} event name for use + */ + var createEvt = function () { + var args = [], len = arguments.length; + while ( len-- ) args[ len ] = arguments[ len ]; + + return args.join('_'); + }; + + /** + * Simple check if the prop is function + * @param {*} prop input + * @return {boolean} true on success + */ + var isFunc = function (prop) { + if (typeof prop === 'function') { + return true; + } + console.error(("Expect to be Function type! Got " + (typeof prop))); + }; + + // generic placeholder function + var nil = function () { return false; }; + + /** + * using just the map reduce to chain multiple functions together + * @param {function} mainFn the init function + * @param {array} moreFns as many as you want to take the last value and return a new one + * @return {function} accept value for the mainFn + */ + var chainFns = function (mainFn) { + var moreFns = [], len = arguments.length - 1; + while ( len-- > 0 ) moreFns[ len ] = arguments[ len + 1 ]; + + return ( + function () { + var args = [], len = arguments.length; + while ( len-- ) args[ len ] = arguments[ len ]; + + return ( + moreFns.reduce(function (value, nextFn) { return ( + // change here to check if the return value is array then we spread it + Reflect.apply(nextFn, null, toArray$1(value)) + ); }, Reflect.apply(mainFn, null, args)) + ); + } + ); + }; + + /** + * this is essentially the same as the injectToFn + * but this will not allow overwrite and set the setter and getter + * @param {object} obj to get injected + * @param {string} name of the property + * @param {function} setter for set + * @param {function} [getter=null] for get default return null fn + * @return {object} the injected obj + */ + function objDefineProps(obj, name, setter, getter) { + if ( getter === void 0 ) getter = null; + + if (Object.getOwnPropertyDescriptor(obj, name) === undefined) { + Object.defineProperty(obj, name, { + set: setter, + get: getter === null ? function() { return null; } : getter + }); + } + return obj + } + + /** + * check if the object has name property + * @param {object} obj the object to check + * @param {string} name the prop name + * @return {*} the value or undefined + */ + function objHasProp(obj, name) { + var prop = Object.getOwnPropertyDescriptor(obj, name); + return prop !== undefined && prop.value ? prop.value : prop + } + + /** + * After the user login we will use this Object.define add a new property + * to the resolver with the decoded user data + * @param {function} resolver target resolver + * @param {string} name the name of the object to get inject also for checking + * @param {object} data to inject into the function static interface + * @param {boolean} [overwrite=false] if we want to overwrite the existing data + * @return {function} added property resolver + */ + function injectToFn(resolver, name, data, overwrite) { + if ( overwrite === void 0 ) overwrite = false; + + var check = objHasProp(resolver, name); + if (overwrite === false && check !== undefined) { + // console.info(`NOT INJECTED`) + return resolver + } + /* this will throw error! @TODO how to remove props? + if (overwrite === true && check !== undefined) { + delete resolver[name] // delete this property + } + */ + // console.info(`INJECTED`) + Object.defineProperty(resolver, name, { + value: data, + writable: overwrite // if its set to true then we should able to overwrite it + }); + + return resolver + } + + /** + * This is a custom error to throw when server throw a 406 + * This help us to capture the right error, due to the call happens in sequence + * @param {string} message to tell what happen + * @param {mixed} extra things we want to add, 500? + */ + var Jsonql406Error = /*@__PURE__*/(function (Error) { + function Jsonql406Error() { + var args = [], len = arguments.length; + while ( len-- ) args[ len ] = arguments[ len ]; + + Error.apply(this, args); + this.message = args[0]; + this.detail = args[1]; + // We can't access the static name from an instance + // but we can do it like this + this.className = Jsonql406Error.name; + + if (Error.captureStackTrace) { + Error.captureStackTrace(this, Jsonql406Error); + } + } + + if ( Error ) Jsonql406Error.__proto__ = Error; + Jsonql406Error.prototype = Object.create( Error && Error.prototype ); + Jsonql406Error.prototype.constructor = Jsonql406Error; + + var staticAccessors = { statusCode: { configurable: true },name: { configurable: true } }; + + staticAccessors.statusCode.get = function () { + return 406; + }; + + staticAccessors.name.get = function () { + return 'Jsonql406Error'; + }; + + Object.defineProperties( Jsonql406Error, staticAccessors ); + + return Jsonql406Error; + }(Error)); + + /** + * This is a custom error to throw when server throw a 500 + * This help us to capture the right error, due to the call happens in sequence + * @param {string} message to tell what happen + * @param {mixed} extra things we want to add, 500? + */ + var Jsonql500Error = /*@__PURE__*/(function (Error) { + function Jsonql500Error() { + var args = [], len = arguments.length; + while ( len-- ) args[ len ] = arguments[ len ]; + + Error.apply(this, args); + + this.message = args[0]; + this.detail = args[1]; + + this.className = Jsonql500Error.name; + + if (Error.captureStackTrace) { + Error.captureStackTrace(this, Jsonql500Error); + } + } + + if ( Error ) Jsonql500Error.__proto__ = Error; + Jsonql500Error.prototype = Object.create( Error && Error.prototype ); + Jsonql500Error.prototype.constructor = Jsonql500Error; + + var staticAccessors = { statusCode: { configurable: true },name: { configurable: true } }; + + staticAccessors.statusCode.get = function () { + return 500; + }; + + staticAccessors.name.get = function () { + return 'Jsonql500Error'; + }; + + Object.defineProperties( Jsonql500Error, staticAccessors ); + + return Jsonql500Error; + }(Error)); + + /** + * this is the 403 Forbidden error + * that means this user is not login + * use the 401 for try to login and failed + * @param {string} message to tell what happen + * @param {mixed} extra things we want to add, 500? + */ + var JsonqlForbiddenError = /*@__PURE__*/(function (Error) { + function JsonqlForbiddenError() { + var args = [], len = arguments.length; + while ( len-- ) args[ len ] = arguments[ len ]; + + Error.apply(this, args); + this.message = args[0]; + this.detail = args[1]; + + this.className = JsonqlForbiddenError.name; + + if (Error.captureStackTrace) { + Error.captureStackTrace(this, JsonqlForbiddenError); + } + } + + if ( Error ) JsonqlForbiddenError.__proto__ = Error; + JsonqlForbiddenError.prototype = Object.create( Error && Error.prototype ); + JsonqlForbiddenError.prototype.constructor = JsonqlForbiddenError; + + var staticAccessors = { statusCode: { configurable: true },name: { configurable: true } }; + + staticAccessors.statusCode.get = function () { + return 403; + }; + + staticAccessors.name.get = function () { + return 'JsonqlForbiddenError'; + }; + + Object.defineProperties( JsonqlForbiddenError, staticAccessors ); + + return JsonqlForbiddenError; + }(Error)); + + /** + * This is a custom error to throw when pass credential but fail + * This help us to capture the right error, due to the call happens in sequence + * @param {string} message to tell what happen + * @param {mixed} extra things we want to add, 500? + */ + var JsonqlAuthorisationError = /*@__PURE__*/(function (Error) { + function JsonqlAuthorisationError() { + var args = [], len = arguments.length; + while ( len-- ) args[ len ] = arguments[ len ]; + + Error.apply(this, args); + this.message = args[0]; + this.detail = args[1]; + + this.className = JsonqlAuthorisationError.name; + + if (Error.captureStackTrace) { + Error.captureStackTrace(this, JsonqlAuthorisationError); + } + } + + if ( Error ) JsonqlAuthorisationError.__proto__ = Error; + JsonqlAuthorisationError.prototype = Object.create( Error && Error.prototype ); + JsonqlAuthorisationError.prototype.constructor = JsonqlAuthorisationError; + + var staticAccessors = { statusCode: { configurable: true },name: { configurable: true } }; + + staticAccessors.statusCode.get = function () { + return 401; + }; + + staticAccessors.name.get = function () { + return 'JsonqlAuthorisationError'; + }; + + Object.defineProperties( JsonqlAuthorisationError, staticAccessors ); + + return JsonqlAuthorisationError; + }(Error)); + + /** + * This is a custom error when not supply the credential and try to get contract + * This help us to capture the right error, due to the call happens in sequence + * @param {string} message to tell what happen + * @param {mixed} extra things we want to add, 500? + */ + var JsonqlContractAuthError = /*@__PURE__*/(function (Error) { + function JsonqlContractAuthError() { + var args = [], len = arguments.length; + while ( len-- ) args[ len ] = arguments[ len ]; + + Error.apply(this, args); + this.message = args[0]; + this.detail = args[1]; + + this.className = JsonqlContractAuthError.name; + + if (Error.captureStackTrace) { + Error.captureStackTrace(this, JsonqlContractAuthError); + } + } + + if ( Error ) JsonqlContractAuthError.__proto__ = Error; + JsonqlContractAuthError.prototype = Object.create( Error && Error.prototype ); + JsonqlContractAuthError.prototype.constructor = JsonqlContractAuthError; + + var staticAccessors = { statusCode: { configurable: true },name: { configurable: true } }; + + staticAccessors.statusCode.get = function () { + return 401; + }; + + staticAccessors.name.get = function () { + return 'JsonqlContractAuthError'; + }; + + Object.defineProperties( JsonqlContractAuthError, staticAccessors ); + + return JsonqlContractAuthError; + }(Error)); + + /** + * This is a custom error to throw when the resolver throw error and capture inside the middleware + * This help us to capture the right error, due to the call happens in sequence + * @param {string} message to tell what happen + * @param {mixed} extra things we want to add, 500? + */ + var JsonqlResolverAppError = /*@__PURE__*/(function (Error) { + function JsonqlResolverAppError() { + var args = [], len = arguments.length; + while ( len-- ) args[ len ] = arguments[ len ]; + + Error.apply(this, args); + + this.message = args[0]; + this.detail = args[1]; + + this.className = JsonqlResolverAppError.name; + + if (Error.captureStackTrace) { + Error.captureStackTrace(this, JsonqlResolverAppError); + } + } + + if ( Error ) JsonqlResolverAppError.__proto__ = Error; + JsonqlResolverAppError.prototype = Object.create( Error && Error.prototype ); + JsonqlResolverAppError.prototype.constructor = JsonqlResolverAppError; + + var staticAccessors = { statusCode: { configurable: true },name: { configurable: true } }; + + staticAccessors.statusCode.get = function () { + return 500; + }; + + staticAccessors.name.get = function () { + return 'JsonqlResolverAppError'; + }; + + Object.defineProperties( JsonqlResolverAppError, staticAccessors ); + + return JsonqlResolverAppError; + }(Error)); + + /** + * This is a custom error to throw when could not find the resolver + * This help us to capture the right error, due to the call happens in sequence + * @param {string} message to tell what happen + * @param {mixed} extra things we want to add, 500? + */ + var JsonqlResolverNotFoundError = /*@__PURE__*/(function (Error) { + function JsonqlResolverNotFoundError() { + var args = [], len = arguments.length; + while ( len-- ) args[ len ] = arguments[ len ]; + + Error.apply(this, args); + + this.message = args[0]; + this.detail = args[1]; + + this.className = JsonqlResolverNotFoundError.name; + + if (Error.captureStackTrace) { + Error.captureStackTrace(this, JsonqlResolverNotFoundError); + } + } + + if ( Error ) JsonqlResolverNotFoundError.__proto__ = Error; + JsonqlResolverNotFoundError.prototype = Object.create( Error && Error.prototype ); + JsonqlResolverNotFoundError.prototype.constructor = JsonqlResolverNotFoundError; + + var staticAccessors = { statusCode: { configurable: true },name: { configurable: true } }; + + staticAccessors.statusCode.get = function () { + return 404; + }; + + staticAccessors.name.get = function () { + return 'JsonqlResolverNotFoundError'; + }; + + Object.defineProperties( JsonqlResolverNotFoundError, staticAccessors ); + + return JsonqlResolverNotFoundError; + }(Error)); + + // this is from an example from Koa team to use for internal middleware ctx.throw + // but after the test the res.body part is unable to extract the required data + // I keep this one here for future reference + + var JsonqlServerError = /*@__PURE__*/(function (Error) { + function JsonqlServerError(statusCode, message) { + Error.call(this, message); + this.statusCode = statusCode; + this.className = JsonqlServerError.name; + } + + if ( Error ) JsonqlServerError.__proto__ = Error; + JsonqlServerError.prototype = Object.create( Error && Error.prototype ); + JsonqlServerError.prototype.constructor = JsonqlServerError; + + var staticAccessors = { name: { configurable: true } }; + + staticAccessors.name.get = function () { + return 'JsonqlServerError'; + }; + + Object.defineProperties( JsonqlServerError, staticAccessors ); + + return JsonqlServerError; + }(Error)); + + /** + * this will put into generator call at the very end and catch + * the error throw from inside then throw again + * this is necessary because we split calls inside and the throw + * will not reach the actual client unless we do it this way + * @param {object} e Error + * @return {void} just throw + */ + function finalCatch(e) { + // this is a hack to get around the validateAsync not actually throw error + // instead it just rejected it with the array of failed parameters + if (Array.isArray(e)) { + // if we want the message then I will have to create yet another function + // to wrap this function to provide the name prop + throw new JsonqlValidationError('', e) + } + var msg = e.message || NO_ERROR_MSG; + var detail = e.detail || e; + // @BUG the instance of not always work for some reason! + // need to figure out a better way to find out the type of the error + switch (true) { + case e instanceof Jsonql406Error: + throw new Jsonql406Error(msg, detail) + case e instanceof Jsonql500Error: + throw new Jsonql500Error(msg, detail) + case e instanceof JsonqlForbiddenError: + throw new JsonqlForbiddenError(msg, detail) + case e instanceof JsonqlAuthorisationError: + throw new JsonqlAuthorisationError(msg, detail) + case e instanceof JsonqlContractAuthError: + throw new JsonqlContractAuthError(msg, detail) + case e instanceof JsonqlResolverAppError: + throw new JsonqlResolverAppError(msg, detail) + case e instanceof JsonqlResolverNotFoundError: + throw new JsonqlResolverNotFoundError(msg, detail) + case e instanceof JsonqlEnumError: + throw new JsonqlEnumError(msg, detail) + case e instanceof JsonqlTypeError: + throw new JsonqlTypeError(msg, detail) + case e instanceof JsonqlCheckerError: + throw new JsonqlCheckerError(msg, detail) + case e instanceof JsonqlValidationError: + throw new JsonqlValidationError(msg, detail) + case e instanceof JsonqlServerError: + throw new JsonqlServerError(msg, detail) + default: + throw new JsonqlError$1(msg, detail) + } + } + + // split the contract into the node side and the generic side + /** + * Check if the json is a contract file or not + * @param {object} contract json object + * @return {boolean} true + */ + function checkIsContract(contract) { + return isPlainObject(contract) + && ( + isObjectHasKey$1(contract, QUERY_NAME) + || isObjectHasKey$1(contract, MUTATION_NAME) + || isObjectHasKey$1(contract, SOCKET_NAME) + ) + } + + /** + * Wrapper method that check if it's contract then return the contract or false + * @param {object} contract the object to check + * @return {boolean | object} false when it's not + */ + function isContract(contract) { + return checkIsContract(contract) ? contract : false + } + + /** + * Ported from jsonql-params-validator but different + * if we don't find the socket part then return false + * @param {object} contract the contract object + * @return {object|boolean} false on failed + */ + function extractSocketPart(contract) { + if (isObjectHasKey$1(contract, SOCKET_NAME)) { + return contract[SOCKET_NAME] + } + return false + } + + // take out all the namespace related methods in one place for easy to find + var SOCKET_NOT_FOUND_ERR = "socket not found in contract!"; + var SIZE = 'size'; + + /** + * create the group using publicNamespace when there is only public + * @param {object} socket from contract + * @param {string} publicNamespace + */ + function groupPublicNamespace(socket, publicNamespace) { + var obj; + + var g = {}; + for (var resolverName in socket) { + var params = socket[resolverName]; + g[resolverName] = params; + } + return { size: 1, nspGroup: ( obj = {}, obj[publicNamespace] = g, obj ), publicNamespace: publicNamespace} + } + + + /** + * @BUG we should check the socket part instead of expect the downstream to read the menu! + * We only need this when the enableAuth is true otherwise there is only one namespace + * @param {object} contract the socket part of the contract file + * @return {object} 1. remap the contract using the namespace --> resolvers + * 2. the size of the object (1 all private, 2 mixed public with private) + * 3. which namespace is public + */ + function groupByNamespace(contract) { + var socket = extractSocketPart(contract); + if (socket === false) { + throw new JsonqlError('groupByNamespace', SOCKET_NOT_FOUND_ERR) + } + var prop = {}; + prop[NSP_GROUP] = {}; + prop[PUBLIC_NAMESPACE] = null; + prop[SIZE] = 0; + + for (var resolverName in socket) { + var params = socket[resolverName]; + var namespace = params.namespace; + if (namespace) { + if (!prop[NSP_GROUP][namespace]) { + ++prop[SIZE]; + prop[NSP_GROUP][namespace] = {}; + } + prop[NSP_GROUP][namespace][resolverName] = params; + // get the public namespace + if (!prop[PUBLIC_NAMESPACE] && params[PUBLIC_KEY]) { + prop[PUBLIC_NAMESPACE] = namespace; + } + } + } + + return prop + } + + /** + * @TODO this might change, what if we want to do room with ws + * 1. there will only be max two namespace + * 2. when it's normal we will have the stock path as namespace + * 3. when enableAuth then we will have two, one is jsonql/public + private + * @param {object} config options + * @return {array} of namespace(s) + */ + function getNamespace(config) { + var base = JSONQL_PATH; + if (config.enableAuth) { + // the public come first @1.0.1 we use the constants instead of the user supplied value + // @1.0.4 we use the config value again, because we could control this via the post init + return [ + [ base , config.publicNamespace ].join('/'), + [ base , config.privateNamespace ].join('/') + ] + } + return [ base ] + } + + /** + * Got a problem with a contract that is public only the groupByNamespace is wrong + * which is actually not a problem when using a fallback, but to be sure things in order + * we could combine with the config to group it + * @param {object} config configuration + * @return {object} nspInfo object + */ + function getNspInfoByConfig(config) { + var contract = config.contract; + var enableAuth = config.enableAuth; + var namespaces = getNamespace(config); + var nspInfo = enableAuth ? groupByNamespace(contract) + : groupPublicNamespace(contract.socket, namespaces[0]); + // add the namespaces into it as well + return Object.assign(nspInfo, { namespaces: namespaces }) + } + + // group all the small functions here + + + /** + * WebSocket is strict about the path, therefore we need to make sure before it goes in + * @param {string} url input url + * @return {string} url with correct path name + */ + var fixWss = function (url) { + var uri = url.toLowerCase(); + if (uri.indexOf('http') > -1) { + if (uri.indexOf('https') > -1) { + return uri.replace('https', 'wss') + } + return uri.replace('http', 'ws') + } + return uri + }; + + + /** + * get a stock host name from browser + */ + var getHostName = function () { + try { + return [window.location.protocol, window.location.host].join('//') + } catch(e) { + throw new JsonqlValidationError(e) + } + }; + + /** + * Unbind the event + * @param {object} ee EventEmitter + * @param {string} namespace + * @return {void} + */ + var clearMainEmitEvt = function (ee, namespace) { + var nsps = toArray$1(namespace); + nsps.forEach(function (n) { + ee.$off(createEvt(n, EMIT_REPLY_TYPE)); + }); + }; + + // 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 SOCKET_IO = JS_WS_SOCKET_IO_NAME; + + var EMIT_EVT = EMIT_REPLY_TYPE; + + var UNKNOWN_RESULT = 'UKNNOWN RESULT!'; + + var MY_NAMESPACE = 'myNamespace'; + // this is a socket only (for now) feature so we just put it here + var DISCONNECTED_ERROR_MSG = "You have disconnected from the socket server, please reconnect."; + + // breaking it up further to share between methods + + /** + * break out to use in different places to handle the return from server + * @param {object} data from server + * @param {function} resolver NOT from promise + * @param {function} rejecter NOT from promise + * @return {void} nothing + */ + function respondHandler(data, resolver, rejecter) { + if (isObjectHasKey$1(data, ERROR_KEY)) { + // debugFn('-- rejecter called --', data[ERROR_KEY]) + rejecter(data[ERROR_KEY]); + } else if (isObjectHasKey$1(data, DATA_KEY)) { + // debugFn('-- resolver called --', data[DATA_KEY]) + resolver(data[DATA_KEY]); + } else { + // debugFn('-- UNKNOWN_RESULT --', data) + rejecter({message: UNKNOWN_RESULT, error: data}); + } + } + + // the actual trigger call method + + /** + * just wrapper + * @param {object} ee EventEmitter + * @param {string} namespace where this belongs + * @param {string} resolverName resolver + * @param {array} args arguments + * @param {function} log function + * @return {void} nothing + */ + function actionCall(ee, namespace, resolverName, args, log) { + if ( args === void 0 ) args = []; + + // reply event + var outEventName = createEvt(namespace, EMIT_REPLY_TYPE); + + log(("actionCall: " + outEventName + " --> " + resolverName), args); + // This is the out going call + ee.$trigger(outEventName, [resolverName, toArray$1(args)]); + + // then we need to listen to the event callback here as well + return new Promise(function (resolver, rejecter) { + var inEventName = createEvt(namespace, resolverName, ON_RESULT_FN_NAME); + // this cause the onResult got the result back first + // and it should be the promise resolve first + // @TODO we need to rewrote the respondHandler to change the problem stated above + ee.$on( + inEventName, + function actionCallResultHandler(result) { + log("got the first result", result); + respondHandler(result, resolver, rejecter); + } + ); + }) + } + + // setting up the send method + + /** + * pairing with the server vesrion SEND_MSG_FN_NAME + * last of the chain so only return the resolver (fn) + * This is now change to a getter / setter method + * and call like this: resolver.send(...args) + * @param {function} fn the resolver function + * @param {object} ee event emitter instance + * @param {string} namespace the namespace it belongs to + * @param {string} resolverName name of the resolver + * @param {object} params from contract + * @param {function} log a logger function + * @return {function} return the resolver itself + */ + var setupSendMethod = function (fn, ee, namespace, resolverName, params, log) { return ( + objDefineProps( + fn, + SEND_MSG_FN_NAME, + nil, + function sendHandler() { + // let _log = (...args) => Reflect.apply(console.info, console, ['[SEND]'].concat(args)) + /** + * This will follow the same pattern like the resolver + * @param {array} args list of unknown argument follow the resolver + * @return {promise} resolve the result + */ + return function sendCallback() { + var args = [], len = arguments.length; + while ( len-- ) args[ len ] = arguments[ len ]; + + return validateAsync$1(args, params.params, true) + .then(function (_args) { + // @TODO check the result + // because the validation could failed with the list of fail properties + log(namespace, resolverName, _args); + return actionCall(ee, namespace, resolverName, _args, _log) + }) + .catch(function (err) { + // @TODO it shouldn't be just a validation error + // it could be server return error, so we need to check + // what error we got back here first + log('send error', err); + // @TODO it might not an validation error need the finalCatch here + ee.$call( + createEvt(namespace, resolverName, ON_ERROR_FN_NAME), + [new JsonqlValidationError(resolverName, err)] + ); + }) + } + }) + ); }; + + // break up the original setup resolver method here + + /** + * The first one in the chain, just setup a namespace prop + * the rest are passing through + * @param {function} fn the resolver function + * @param {object} ee the event emitter + * @param {string} resolverName what it said + * @param {object} params for resolver from contract + * @param {function} log the logger function + * @return {array} + */ + var setupNamespace = function (fn, ee, namespace, resolverName, params, log) { return [ + injectToFn(fn, MY_NAMESPACE, namespace), + ee, + namespace, + resolverName, + params, + log + ]; }; + + /** + * onResult handler + */ + var setupOnResult = function (fn, ee, namespace, resolverName, params, log) { return [ + objDefineProps(fn, ON_RESULT_FN_NAME, function(resultCallback) { + if (isFunc(resultCallback)) { + ee.$on( + createEvt(namespace, resolverName, ON_RESULT_FN_NAME), + function resultHandler(result) { + respondHandler(result, resultCallback, function (error) { + log(("Catch error: \"" + resolverName + "\""), error); + ee.$trigger( + createEvt(namespace, resolverName, ON_ERROR_FN_NAME), + error + ); + }); + } + ); + } + }), + ee, + namespace, + resolverName, + params, + log + ]; }; + + /** + * we do need to add the send prop back because it's the only way to deal with + * bi-directional data stream + */ + var setupOnMessage = function (fn, ee, namespace, resolverName, params, log) { return [ + objDefineProps(fn, ON_MESSAGE_FN_NAME, function(messageCallback) { + // we expect this to be a function + if (isFunc(messageCallback)) { + // did that add to the callback + var onMessageCallback = function (args) { + respondHandler(args, messageCallback, function (error) { + log(("Catch error: \"" + resolverName + "\""), error); + ee.$trigger( + createEvt(namespace, resolverName, ON_ERROR_FN_NAME), + error + ); + }); + }; + // register the handler for this message event + ee.$only( + createEvt(namespace, resolverName, ON_MESSAGE_FN_NAME), + onMessageCallback + ); + } + }), + ee, + namespace, + resolverName, + params, + log + ]; }; + + /** + * ON_ERROR_FN_NAME handler + */ + var setupOnError = function (fn, ee, namespace, resolverName, params, log) { return [ + objDefineProps(fn, ON_ERROR_FN_NAME, function(resolverErrorHandler) { + if (isFunc(resolverErrorHandler)) { + // please note ON_ERROR_FN_NAME can add multiple listners + ee.$only( + createEvt(namespace, resolverName, ON_ERROR_FN_NAME), + resolverErrorHandler + ); + } + }), + ee, + namespace, + resolverName, + params, + log + ]; }; + + /** + * Add extra property / listeners to the resolver + * @param {string} namespace where this belongs + * @param {string} resolverName name as event name + * @param {object} params from contract + * @param {function} fn resolver function + * @param {object} ee EventEmitter + * @param {function} log function + * @return {function} resolver + */ + function setupResolver(namespace, resolverName, params, fn, ee, log) { + var fns = [ + setupNamespace, + setupOnResult, + setupOnMessage, + setupOnError, + setupSendMethod + ]; + + // get the executor + var executor = Reflect.apply(chainFns, null, fns); + var args = [fn, ee, namespace, resolverName, params, log]; + + return Reflect.apply(executor, null, args) + } + + // put all the resolver related methods here to make it more clear + + /** + * create the actual function to send message to server + * @param {object} ee EventEmitter instance + * @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 + * @return {function} resolver + */ + function createResolver(ee, namespace, resolverName, params, log) { + // note we pass the new withResult=true option + return function resolver() { + var args = [], len = arguments.length; + while ( len-- ) args[ len ] = arguments[ len ]; + + return validateAsync$1(args, params.params, true) + .then(function (_args) { return actionCall(ee, namespace, resolverName, _args, log); }) + .catch(finalCatch) + } + } + + /** + * step one get the clientmap with the namespace + * @param {object} opts configuration + * @param {object} ee EventEmitter + * @param {object} nspGroup resolvers index by their namespace + * @return {promise} resolve the clientmapped, and start the chain + */ + 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) { + // resolverNames.push(resolverName) + var params = list[resolverName]; + var fn = createResolver(ee, namespace, resolverName, params, log); + // 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, setupResolver(namespace, resolverName, params, fn, ee, log)); + } + } + // resolve the clientto start the chain + // chain the result to allow the chain processing + return [ client, opts, ee, nspGroup ] + } + + /** + * The problem is the namespace can have more than one + * and we only have on onError message + * @param {object} clientthe client itself + * @param {object} opts configuration + * @param {object} ee Event Emitter + * @param {object} nspGroup namespace keys + * @return {array} [obj, opts, ee] + */ + function createNamespaceErrorHandler(client, opts, ee, nspGroup) { + return [ + // using the onError as name + // @TODO we should follow the convention earlier + // make this a setter for the clientitself + objDefineProps(client, ON_ERROR_FN_NAME, function namespaceErrorCallbackHandler(namespaceErrorHandler) { + if (isFunc(namespaceErrorHandler)) { + // please note ON_ERROR_FN_NAME can add multiple listners + for (var namespace in nspGroup) { + // this one is very tricky, we need to make sure the trigger is calling + // with the namespace as well as the error + ee.$on(createEvt(namespace, ON_ERROR_FN_NAME), namespaceErrorHandler); + } + } + }), + opts, + ee + ] + } + + /** + * This event will fire when the socket.io.on('connection') and ws.onopen + * @param {object} client client itself + * @param {object} opts configuration + * @param {object} ee Event Emitter + * @return {array} [ obj, opts, ee ] + */ + function createOnReadyHandler(client, opts, ee) { + return [ + objDefineProps(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); + } + }), + opts, + ee + ] + } + + // 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 + * output the client + * @param {object} client the client + * @param {object} opts configuration + * @param {object} ee the event emitter + * @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); + }) + } + + /** + * 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 + */ + 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 + 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 + client.eventEmitter = opts.eventEmitter; + client.log = opts.log; + 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 generator(opts, nspMap, ee) { + + var args = [ + generateResolvers, + createNamespaceErrorHandler, + createOnReadyHandler + ]; + if (opts.enableAuth) { + args.push( + createAuthMethods + ); + } + // we will always get back the [ obj, opts, ee ] + // then we only return the obj (wsClient) + args.push(setupFinalStep); + // run it + var fn = Reflect.apply(chainFns, null, args); + + return fn(opts, ee, nspMap[NSP_GROUP]) + } + + var obj, obj$1, obj$2; + // import { AVAILABLE_SERVERS } from './constants' + var AVAILABLE_METHODS = [IO_ROUNDTRIP_LOGIN, IO_HANDSHAKE_LOGIN]; + + var configCheckMap = { + standalone: createConfig$1(false, [BOOLEAN_TYPE]), // to turn on or off some of the features + debugOn: createConfig$1(false, [BOOLEAN_TYPE]), + // useCallbackStyle: createConfig(false, [BOOLEAN_TYPE]), abandoned in 0.6.0 + // Please note the login method will be a public available always + // what if the developer wants to have a socket only setup to do a CORS SPA site + loginHandlerName: createConfig$1(LOGIN_NAME, [STRING_TYPE]), + logoutHandlerName: createConfig$1(LOGOUT_NAME, [STRING_TYPE]), + // just matching the server side + disconnectHandlerName: createConfig$1(DISCONNECT_FN_NAME, [STRING_TYPE]), + switchUserHandlerName: createConfig$1(SWITCH_USER_FN_NAME, [STRING_TYPE]), + // this is for socket.io + loginMethod: createConfig$1(IO_HANDSHAKE_LOGIN, [STRING_TYPE], ( obj = {}, obj[ENUM_KEY] = AVAILABLE_METHODS, obj )), + // we will use this for determine the socket.io client type as well - @TODO remove or rename + useJwt: createConfig$1(true, [BOOLEAN_TYPE, STRING_TYPE]), + // this is going to replace the use of useJwt === string next + authStrKey: createConfig$1(null, [STRING_TYPE]), + hostname: createConfig$1(false, [STRING_TYPE]), + namespace: createConfig$1(JSONQL_PATH, [STRING_TYPE]), + wsOptions: createConfig$1({}, [OBJECT_TYPE]), + // make this null as default don't set this here, only set in the down stream + // serverType: createConfig(null, [STRING_TYPE], {[ENUM_KEY]: AVAILABLE_SERVERS}), + // we require the contract already generated and pass here + contract: createConfig$1({}, [OBJECT_TYPE], ( obj$1 = {}, obj$1[CHECKER_KEY] = isContract, obj$1 )), + enableAuth: createConfig$1(false, [BOOLEAN_TYPE]), + token: createConfig$1(false, [STRING_TYPE]) + }; + + // socket client + var socketCheckMap = {}; + socketCheckMap[SOCKET_TYPE_KEY] = createConfig$1(null, [STRING_TYPE], ( obj$2 = {}, obj$2[ALIAS_KEY] = SOCKET_TYPE_CLIENT_ALIAS, obj$2 )); + + var wsCoreCheckMap = Object.assign(configCheckMap, socketCheckMap); + + // constant props + var wsCoreConstProps = { + log: null, + // contract: null, + eventEmitter: null, + // we unify the two different client into one now + // only expect different parameter + nspClient: null, + nspAuthClient: null, + // contructed path + wssPath: '' + }; + + // create options + + + /** + * wrapper method to check this already did the pre check + * @param {object} config user supply config + * @param {object} defaultOptions for checking + * @param {object} constProps user supply const props + * @return {promise} resolve to the checked opitons + */ + function checkConfiguration(config, defaultOptions, constProps) { + var defaultCheckMap= Object.assign(wsCoreCheckMap, defaultOptions); + var wsConstProps = Object.assign(wsCoreConstProps, constProps); + + return checkConfigAsync(config, defaultCheckMap, wsConstProps) + } + + /** + * Taking the `then` part from the method below + * @param {object} opts + * @return {promise} opts all done + */ + function postCheckInjectOpts(opts) { + return Promise.resolve(opts) + .then(function (opts) { + if (!opts.hostname) { + opts.hostname = getHostName(); + } + // @TODO the contract now will supply the namespace information + // and we need to use that to group the namespace call + opts.wssPath = fixWss([opts.hostname, opts.namespace].join('/'), opts.serverType); + // get the log function here + opts.log = getLogFn(opts); + + opts.eventEmitter = getEventEmitter(opts); + + return 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} + */ + function createRequiredParams(opts) { + return { + opts: opts, + nspMap: getNspInfoByConfig(opts), + ee: opts.eventEmitter + } + } + + // the top level API + + + /** + * 0.5.0 we break up the wsClientCore in two parts one without the config check + * @param {function} frameworkSocketEngine + * @param {object} config the already checked config + */ + function wsClientCoreAction(frameworkSocketEngine, config) { + return postCheckInjectOpts(config) + // the following two moved to wsPostConfig + .then(createRequiredParams) + .then( + function (ref) { + var opts = ref.opts; + var nspMap = ref.nspMap; + var ee = ref.ee; + + return frameworkSocketEngine(opts, nspMap, ee); + } + ) + .then( + function (ref) { + var opts = ref.opts; + var nspMap = ref.nspMap; + var ee = ref.ee; + + return generator(opts, nspMap, ee); + } + ) + .catch(function (err) { + console.error("jsonql-ws-core-client init error", err); + }) + } + + /** + * The main interface which will generate the socket clients and map all events + * @param {object} frameworkSocketEngine this is the one method export by various clients + * @param {object} [configCheckMap={}] we should do all the checking in the core instead of the client + * @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(frameworkSocketEngine, configCheckMap, constProps) { + if ( configCheckMap === void 0 ) configCheckMap = {}; + if ( constProps === void 0 ) constProps = {}; + + // we need to inject property to this client later + return function (config) { + if ( config === void 0 ) config = {}; + + return checkConfiguration(config, configCheckMap, constProps) + .then(function (opts) { return wsClientCoreAction(frameworkSocketEngine, opts); }); + } + } + + // since both the ws and io version are + // pre-defined in the client-generator + // and this one will have the same parameters + // and the callback is identical + + /** + * wrapper method to create a nsp without login + * @param {string|boolean} namespace namespace url could be false + * @param {object} opts configuration + * @return {object} ws client instance + */ + function createNspClient(namespace, opts) { + var hostname = opts.hostname; + var wssPath = opts.wssPath; + var wsOptions = opts.wsOptions; + var nspClient = opts.nspClient; + var url = namespace ? [hostname, namespace].join('/') : wssPath; + return nspClient(url, wsOptions) + } + + /** + * wrapper method to create a nsp with token auth + * @param {string} namespace namespace url + * @param {object} opts configuration + * @return {object} ws client instance + */ + function createNspAuthClient(namespace, opts) { + var hostname = opts.hostname; + var wssPath = opts.wssPath; + var token = opts.token; + var wsOptions = opts.wsOptions; + var nspAuthClient = opts.nspAuthClient; + var url = namespace ? [hostname, namespace].join('/') : wssPath; + if (token && typeof token !== 'string') { + throw new Error(("Expect token to be string, but got " + token)) + } + return nspAuthClient(url, token, wsOptions) + } + + // this use by client-event-handler + + /** + * trigger errors on all the namespace onError handler + * @param {object} ee Event Emitter + * @param {array} namespaces nsps string + * @param {string} message optional + * @return {void} + */ + function triggerNamespacesOnError(ee, namespaces, message) { + namespaces.forEach( function (namespace) { + ee.$trigger( + createEvt(namespace, ON_ERROR_FN_NAME), + [{ message: message, namespace: namespace }] + ); + }); + } + + /** + * Handle the onerror callback + * @param {object} ee event emitter + * @param {string} namespace which namespace has error + * @param {*} err error object + * @return {void} + */ + var handleNamespaceOnError = function (ee, namespace, err) { + ee.$trigger(createEvt(namespace, ON_ERROR_FN_NAME), [err]); + }; + + // This is share between different clients so we export it + + /** + * A Event handler placeholder when it's not connect to the private nsp + * @param {string} namespace nsp + * @param {object} ee EventEmitter + * @param {object} opts configuration + * @return {void} + */ + var notLoginWsHandler = function (namespace, ee, opts) { + var log = opts.log; + ee.$only( + createEvt(namespace, EMIT_EVT), + function notLoginHandlerCallback(resolverName, args) { + log('[notLoginHandler] hijack the ws call', namespace, resolverName, args); + var error = { + message: NOT_LOGIN_ERR_MSG + }; + // It should just throw error here and should not call the result + // because that's channel for handling normal event not the fake one + ee.$call(createEvt(namespace, resolverName, ON_ERROR_FN_NAME), [ error ]); + // also trigger the result handler, but wrap inside the error key + ee.$call(createEvt(namespace, resolverName, ON_RESULT_FN_NAME), [{ error: error }]); + } + ); + }; + + /** + * A Event handler placeholder when it's not connect to any nsp + * @param {string} namespace nsp + * @param {object} ee EventEmitter + * @param {object} opts configuration + * @return {void} + */ + var disconnectedHandler = function (namespace, ee, opts) { + var log = opts.log; + ee.$only( + createEvt(namespace, EMIT_EVT), + function disconnectedHandlerCallback(resolverName, args) { + log("[disconnectedHandler] hijack the ws call", namespace, resolverName, args); + var error = { + message: DISCONNECTED_ERROR_MSG + }; + ee.$call(createEvt(namespace, resolverName, ON_ERROR_FN_NAME), [ error ]); + // also trigger the result handler, but wrap inside the error key + ee.$call(createEvt(namespace, resolverName, ON_RESULT_FN_NAME), [{ error: error }]); + } + ); + }; + + /** + * get the private namespace + * @param {array} namespaces array + * @return {*} string on success + */ + var getPrivateNamespace = function (namespaces) { return ( + namespaces.length > 1 ? namespaces[0] : false + ); }; + + /** + * Only when there is a private namespace then we bind to this event + * @param {object} nsps the available nsp(s) + * @param {array} namespaces available namespace + * @param {object} ee eventEmitter + * @param {object} opts configuration + * @return {void} + */ + var logoutEvtHandler = function (nsps, namespaces, ee, opts) { + var log = opts.log; + // this will be available regardless enableAuth + // because the server can log the client out + ee.$on(LOGOUT_EVENT_NAME, function logoutEvtHandlerAction() { + var privateNamespace = getPrivateNamespace(namespaces); + log((LOGOUT_EVENT_NAME + " event triggered")); + // disconnect(nsps, opts.serverType) + // we need to issue error to all the namespace onError handler + triggerNamespacesOnError(ee, [privateNamespace], LOGOUT_EVENT_NAME); + // rebind all of the handler to the fake one + log(("logout from " + privateNamespace)); + + clearMainEmitEvt(ee, privateNamespace); + // we need to issue one more call to the server before we disconnect + // now this is a catch 22, here we are not suppose to do anything platform specific + // so that should fire before trigger this event + // clear out the nsp + nsps[privateNamespace] = null; + // add a NOT LOGIN error if call + notLoginWsHandler(privateNamespace, ee, opts); + }); + }; + + /** + * The disconnect event handler, now we log the client out from everything + * @TODO now we are another problem they disconnect, how to reconnect + * @param {object} nsps the available nsp(s) + * @param {array} namespaces available namespace + * @param {object} ee eventEmitter + * @param {object} opts configuration + * @return {void} + */ + var disconnectHandler = function (nsps, namespaces, ee, opts) { + var log = opts.log; + ee.$on(DISCONNECT_EVENT_NAME, function disconnectEvtHandler() { + triggerNamespacesOnError(ee, namespaces, DISCONNECT_EVENT_NAME); + namespaces.forEach( function (namespace) { + log(("disconnect from " + namespace)); + + clearMainEmitEvt(ee, namespace); + nsps[namespace] = null; + disconnectedHandler(namespace, ee, opts); + }); + }); + }; + + /** + * centralize all the comm in one place + * @param {object} opts configuration + * @param {object} ee Event Emitter instance + * @param {function} bindWsHandler binding the ee to ws --> this is the core bit + * @param {object} nsps namespaced nsp + * @return {void} nothing + */ + function clientEventHandler$1(opts, ee, bindSocketEventHandler, nsps) { + // since all these params already in the opts + var nspMap = opts.nspMap; + var log = opts.log; + var namespaces = nspMap.namespaces; + // @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 + var privateNamespace = getPrivateNamespace(namespaces); + var isPrivate = false; + var hasPrivate = false; + // loop + // @BUG for io this has to be in order the one with auth need to get call first + // The order of login is very import we need to run in order here to make sure + // one is execute then the other + namespaces.forEach(function (namespace) { + isPrivate = privateNamespace === namespace; + if (!hasPrivate) { + hasPrivate = isPrivate; + } + if (nsps[namespace]) { + + log('[call bindWsHandler]', isPrivate, namespace); + var args = [namespace, nsps[namespace], ee, isPrivate, opts]; + + if (opts.serverType === SOCKET_IO) { + var nspGroup = nspMap.nspGroup; + args.push(nspGroup[namespace]); + } + Reflect.apply(bindSocketEventHandler, null, args); + } else { + // a dummy placeholder + // @TODO but it should be a not connect handler + // when it's not login (or fail) this should be handle differently + notLoginWsHandler(namespace, ee, opts); + } + }); + // logout event handler + if (hasPrivate) { + log("Has private and add logoutEvtHandler"); + + logoutEvtHandler(nsps, namespaces, ee, opts); + } + // finally the disconnect event handlers + disconnectHandler(nsps, namespaces, ee, opts); + } + + var ERROR_KEY$1 = 'error'; + var TIMESTAMP_PARAM_NAME = 'TS'; + var NO_STATUS_CODE$1 = -1; + var LOGIN_EVENT_NAME$1 = '__login__'; + var LOGOUT_EVENT_NAME$1 = '__logout__'; + // for ws servers + var WS_REPLY_TYPE = '__reply__'; + var WS_EVT_NAME = '__event__'; + var WS_DATA_NAME = '__data__'; + // this is somewhat vague about what is suppose to do + var EMIT_REPLY_TYPE$1 = 'emit_reply'; + var ACKNOWLEDGE_REPLY_TYPE = 'acknowledge_reply'; + var ERROR_TYPE = ERROR_KEY$1; // Should replace with ERROR_KEY + var JS_WS_NAME = 'ws'; + + // for ws client, 1.9.3 breaking change to name them as FN instead of PROP + 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 TOKEN_PARAM_NAME = 'token'; + + // jsonql-ws-core takes over the check configuration + // constant props + var wsClientConstProps = { + version: 'version: 1.2.0 module: umd', // will get replace + serverType: JS_WS_NAME + }; + + // this is all the isormophic-ws is + var ws$1 = null; + + if (typeof WebSocket !== 'undefined') { + ws$1 = WebSocket; + } else if (typeof MozWebSocket !== 'undefined') { + ws$1 = MozWebSocket; + } else if (typeof global$1 !== 'undefined') { + ws$1 = global$1.WebSocket || global$1.MozWebSocket; + } else if (typeof window !== 'undefined') { + ws$1 = window.WebSocket || window.MozWebSocket; + } else if (typeof self !== 'undefined') { + ws$1 = self.WebSocket || self.MozWebSocket; + } + + var WebSocket$1 = ws$1; + + // pass the different type of ws to generate the client + + /** + * The bug was in the wsOptions where ws don't need it but socket.io do + * therefore the object was pass as second parameter! + * @param {object} WebSocket the client or node version of ws + * @param {boolean} auth if it's auth then 3 param or just one + */ + function initWebSocketClient(WebSocket, auth) { + if ( auth === void 0 ) auth = false; + + if (auth === false) { + return function createWsClientHandler(url) { + return new WebSocket(fixWss(url)) + } + } + + /** + * Create a client with auth token + * @param {string} url start with ws:// @TODO check this? + * @param {string} token the jwt token + * @return {object} ws instance + */ + return function createWsAuthClientHandler(url, token) { + var ws_url = fixWss(url); + // console.log('what happen here?', url, ws_url, token) + var uri = token && typeof token === 'string' ? (ws_url + "?" + TOKEN_PARAM_NAME + "=" + token) : ws_url; + try { + return new WebSocket(uri) + } catch(e) { + console.error('WebSocket Connection Error', e); + return false + } + } + } + + /** + * Because the nsps can be throw away so it doesn't matter the scope + * this will get reuse again + * @param {object} opts configuration + * @param {object} nspMap from contract + * @param {string|null} token whether we have the token at run time + * @return {object} nsps namespace with namespace as key + */ + var createNspAction$1 = function(opts, nspMap, token) { + var log = opts.log; + var publicNamespace = nspMap.publicNamespace; + var namespaces = nspMap.namespaces; + + return { + nsps: (function () { + var obj; + + // first we need to binding all the events handler + if (opts.enableAuth) { // && opts.useJwt + + return namespaces.map(function (namespace, i) { + var obj, obj$1, obj$2; + + if (i === 0) { + if (token) { + opts.token = token; + log('create createNspAuthClient at run time'); + return ( obj = {}, obj[namespace] = createNspAuthClient(namespace, opts), obj ) + } + return ( obj$1 = {}, obj$1[namespace] = false, obj$1 ) + } + return ( obj$2 = {}, obj$2[namespace] = createNspClient(namespace, opts), obj$2 ) + }).reduce(function (first, next) { return Object.assign(first, next); }, {}) + } + + // standard without login + return ( obj = {}, obj[publicNamespace] = createNspClient(false, opts), obj ) + })() + } + }; + + // @BUG when call disconnected + + /** + * create a login event handler + * @param {object} opts configurations + * @param {object} nspMap contain all the required info + * @param {object} ee event emitter + * @return {void} + */ + function loginEventHandler(opts, nspMap, ee) { + var log = opts.log; + var namespaces = nspMap.namespaces; + + ee.$only(LOGIN_EVENT_NAME$1, function loginEventHandlerCallback(tokenFromLoginAction) { + + log('createClient LOGIN_EVENT_NAME $only handler'); + + clearMainEmitEvt(ee, namespaces); + // console.log('LOGIN_EVENT_NAME', token) + var newNsps = createNspAction(opts, nspMap, tokenFromLoginAction); + // rebind it + Reflect.apply( + clientEventHandler, // @NOTE is this the problem that cause the hang up? + null, + args.concat([newNsps.namespaces, newNsps.nsps]) + ); + }); + } + + /** + * Checks if `value` is classified as an `Array` object. + * + * @static + * @memberOf _ + * @since 0.1.0 + * @category Lang + * @param {*} value The value to check. + * @returns {boolean} Returns `true` if `value` is an array, else `false`. + * @example + * + * _.isArray([1, 2, 3]); + * // => true + * + * _.isArray(document.body.children); + * // => false + * + * _.isArray('abc'); + * // => false + * + * _.isArray(_.noop); + * // => false + */ + var isArray$1 = Array.isArray; + + /** Detect free variable `global` from Node.js. */ + var freeGlobal$1 = typeof global$1 == 'object' && global$1 && global$1.Object === Object && global$1; + + /** Detect free variable `self`. */ + var freeSelf$1 = typeof self == 'object' && self && self.Object === Object && self; + + /** Used as a reference to the global object. */ + var root$1 = freeGlobal$1 || freeSelf$1 || Function('return this')(); + + /** Built-in value references. */ + var Symbol$1 = root$1.Symbol; + + /** Used for built-in method references. */ + var objectProto$f = Object.prototype; + + /** Used to check objects for own properties. */ + var hasOwnProperty$c = objectProto$f.hasOwnProperty; + + /** + * Used to resolve the + * [`toStringTag`](http://ecma-international.org/ecma-262/7.0/#sec-object.prototype.tostring) + * of values. + */ + var nativeObjectToString$2 = objectProto$f.toString; + + /** Built-in value references. */ + var symToStringTag$2 = Symbol$1 ? Symbol$1.toStringTag : undefined; + + /** + * A specialized version of `baseGetTag` which ignores `Symbol.toStringTag` values. + * + * @private + * @param {*} value The value to query. + * @returns {string} Returns the raw `toStringTag`. + */ + function getRawTag$1(value) { + var isOwn = hasOwnProperty$c.call(value, symToStringTag$2), + tag = value[symToStringTag$2]; + + try { + value[symToStringTag$2] = undefined; + var unmasked = true; + } catch (e) {} + + var result = nativeObjectToString$2.call(value); + if (unmasked) { + if (isOwn) { + value[symToStringTag$2] = tag; + } else { + delete value[symToStringTag$2]; + } + } + return result; + } + + /** Used for built-in method references. */ + var objectProto$g = Object.prototype; + + /** + * Used to resolve the + * [`toStringTag`](http://ecma-international.org/ecma-262/7.0/#sec-object.prototype.tostring) + * of values. + */ + var nativeObjectToString$3 = objectProto$g.toString; + + /** + * Converts `value` to a string using `Object.prototype.toString`. + * + * @private + * @param {*} value The value to convert. + * @returns {string} Returns the converted string. + */ + function objectToString$1(value) { + return nativeObjectToString$3.call(value); + } + + /** `Object#toString` result references. */ + var nullTag$1 = '[object Null]', + undefinedTag$1 = '[object Undefined]'; + + /** Built-in value references. */ + var symToStringTag$3 = Symbol$1 ? Symbol$1.toStringTag : undefined; + + /** + * The base implementation of `getTag` without fallbacks for buggy environments. + * + * @private + * @param {*} value The value to query. + * @returns {string} Returns the `toStringTag`. + */ + function baseGetTag$1(value) { + if (value == null) { + return value === undefined ? undefinedTag$1 : nullTag$1; + } + return (symToStringTag$3 && symToStringTag$3 in Object(value)) + ? getRawTag$1(value) + : objectToString$1(value); + } + + /** + * Checks if `value` is object-like. A value is object-like if it's not `null` + * and has a `typeof` result of "object". + * + * @static + * @memberOf _ + * @since 4.0.0 + * @category Lang + * @param {*} value The value to check. + * @returns {boolean} Returns `true` if `value` is object-like, else `false`. + * @example + * + * _.isObjectLike({}); + * // => true + * + * _.isObjectLike([1, 2, 3]); + * // => true + * + * _.isObjectLike(_.noop); + * // => false + * + * _.isObjectLike(null); + * // => false + */ + function isObjectLike$1(value) { + return value != null && typeof value == 'object'; + } + + // bunch of generic helpers + + /** + * DIY in Array + * @param {array} arr to check from + * @param {*} value to check against + * @return {boolean} true on found + */ + var inArray$2 = function (arr, value) { return !!arr.filter(function (a) { return a === value; }).length; }; + + /** + * parse string to json or just return the original value if error happened + * @param {*} n input + * @param {boolean} [t=true] or throw + * @return {*} json object on success + */ + var parseJson = function(n, t) { + if ( t === void 0 ) t=true; + + try { + return JSON.parse(n) + } catch(e) { + if (t) { + return n + } + throw new Error(e) + } + }; + + /** + * @param {object} obj for search + * @param {string} key target + * @return {boolean} true on success + */ + var isObjectHasKey$2 = function(obj, key) { + try { + var keys = Object.keys(obj); + return inArray$2(keys, key) + } catch(e) { + // @BUG when the obj is not an OBJECT we got some weird output + return false + } + }; + + /** + * create a event name + * @param {string[]} args + * @return {string} event name for use + */ + var createEvt$1 = function () { + var args = [], len = arguments.length; + while ( len-- ) args[ len ] = arguments[ len ]; + + return args.join('_'); + }; + + /** + * small util to make sure the return value is valid JSON object + * @param {*} n input + * @return {object} correct JSON object + */ + var toJson = function (n) { + if (typeof n === 'string') { + return parseJson(n) + } + return parseJson(JSON.stringify(n)) + }; + + // generic placeholder function + var nil$1 = function () { return false; }; + + /** + * This is a custom error to throw whenever a error happen inside the jsonql + * This help us to capture the right error, due to the call happens in sequence + * @param {string} message to tell what happen + * @param {mixed} extra things we want to add, 500? + */ + var JsonqlError$2 = /*@__PURE__*/(function (Error) { + function JsonqlError() { + var args = [], len = arguments.length; + while ( len-- ) args[ len ] = arguments[ len ]; + + Error.apply(this, args); + + this.message = args[0]; + this.detail = args[1]; + + this.className = JsonqlError.name; + + if (Error.captureStackTrace) { + Error.captureStackTrace(this, JsonqlError); + // this.detail = this.stack; + } + } + + if ( Error ) JsonqlError.__proto__ = Error; + JsonqlError.prototype = Object.create( Error && Error.prototype ); + JsonqlError.prototype.constructor = JsonqlError; + + var staticAccessors = { name: { configurable: true },statusCode: { configurable: true } }; + + staticAccessors.name.get = function () { + return 'JsonqlError'; + }; + + staticAccessors.statusCode.get = function () { + return NO_STATUS_CODE$1; + }; + + Object.defineProperties( JsonqlError, staticAccessors ); + + return JsonqlError; + }(Error)); + + /** + * @param {boolean} sec return in second or not + * @return {number} timestamp + */ + var timestamp = function (sec) { + if ( sec === void 0 ) sec = false; + + var time = Date.now(); + return sec ? Math.floor( time / 1000 ) : time + }; + + /** `Object#toString` result references. */ + var stringTag$3 = '[object String]'; + + /** + * Checks if `value` is classified as a `String` primitive or object. + * + * @static + * @since 0.1.0 + * @memberOf _ + * @category Lang + * @param {*} value The value to check. + * @returns {boolean} Returns `true` if `value` is a string, else `false`. + * @example + * + * _.isString('abc'); + * // => true + * + * _.isString(1); + * // => false + */ + function isString$3(value) { + return typeof value == 'string' || + (!isArray$1(value) && isObjectLike$1(value) && baseGetTag$1(value) == stringTag$3); + } + + // There are the socket related methods ported back from + + var WS_KEYS = [ + WS_REPLY_TYPE, + WS_EVT_NAME, + WS_DATA_NAME + ]; + + /** + * The ws doesn't have a acknowledge callback like socket.io + * so we have to DIY one for ws and other that doesn't have it + * @param {string} type of reply + * @param {string} resolverName which is replying + * @param {*} data payload + * @param {array} [ts= []] the last received ts, if any + * @return {string} stringify json + */ + var createWsReply = function (type, resolverName, data, ts) { + var obj, obj$1; + + if ( ts === void 0 ) ts = []; + ts.push(timestamp()); + return JSON.stringify(( obj$1 = { + data: ( obj = {}, obj[WS_REPLY_TYPE] = type, obj[WS_EVT_NAME] = resolverName, obj[WS_DATA_NAME] = toJson(data), obj ) + }, obj$1[TIMESTAMP_PARAM_NAME] = ts, obj$1 )) + }; + + // extended function + var createReplyMsg = function (resolverName, data, ts) { + if ( ts === void 0 ) ts = []; + + return ( + createWsReply(EMIT_REPLY_TYPE$1, resolverName, data, ts) + ); + }; + + /** + * @param {string|object} payload should be string when reply but could be transformed + * @return {boolean} true is OK + */ + var isWsReply = function (payload) { + var json = isString$3(payload) ? toJson(payload) : payload; + var data = json.data; + if (data) { + var result = WS_KEYS.filter(function (key) { return isObjectHasKey$2(data, key); }); + return (result.length === WS_KEYS.length) ? data : false + } + return false + }; + + /** + * @param {string|object} data received data + * @param {function} [cb=nil] this is for extracting the TS field or when it's error + * @return {object} false on failed + */ + var extractWsPayload = function (payload, cb) { + if ( cb === void 0 ) cb = nil$1; + + try { + var json = toJson(payload); + // now handle the data + var _data; + if ((_data = isWsReply(json)) !== false) { + // note the ts property is on its own + cb(TIMESTAMP_PARAM_NAME, json[TIMESTAMP_PARAM_NAME]); + + return { + data: toJson(_data[WS_DATA_NAME]), + resolverName: _data[WS_EVT_NAME], + type: _data[WS_REPLY_TYPE] + } + } + throw new JsonqlError$2('payload can not decoded', payload) + } catch(e) { + return cb(ERROR_KEY$1, e) + } + }; + + // the WebSocket main handler + + /** + * in some edge case we might not even have a resolverName, then + * we issue a global error for the developer to catch it + * @param {object} ee event emitter + * @param {string} namespace nsp + * @param {string} resolverName resolver + * @param {object} json decoded payload or error object + * @return {undefined} nothing return + */ + var errorTypeHandler = function (ee, namespace, resolverName, json) { + var evt = [namespace]; + if (resolverName) { + evt.push(resolverName); + } + evt.push(ON_ERROR_FN_NAME$1); + var evtName = Reflect.apply(createEvt$1, null, evt); + // test if there is a data field + var payload = json.data || json; + ee.$trigger(evtName, [payload]); + }; + + /** + * Handle the logout event when it's enableAuth + * @param {object} ee eventEmitter + * @return {void} + */ + var logoutEventHandler = function (ee) { + // listen to the LOGOUT_EVENT_NAME when this is a private nsp + ee.$on(LOGOUT_EVENT_NAME$1, function closeEvtHandler() { + try { + log('terminate ws connection'); + ws.terminate(); + } catch(e) { + console.error('ws.terminate error', e); + } + }); + }; + + /** + * Binding the event to socket normally + * @param {string} namespace + * @param {object} ws the nsp + * @param {object} ee EventEmitter + * @param {boolean} isPrivate to id if this namespace is private or not + * @param {object} opts configuration + * @return {object} promise resolve after the onopen event + */ + function socketEventHandler(namespace, ws, ee, isPrivate, opts) { + var log = opts.log; + + log("log test, isPrivate:", isPrivate); + // connection open + ws.onopen = function onOpenCallback() { + + log('ws.onopen listened'); + // we just call the onReady + 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); + } + // 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! + */ + function wsMainOnEvtHandler(resolverName, args) { + + var payload = createReplyMsg(resolverName, args); + log('ws.onopen.send', resolverName, args, payload); + + ws.send(payload); + } + ); + }; + + // reply + // If we change it to the event callback style + // then the payload will just be the payload and fucks up the extractWsPayload call @TODO + ws.onmessage = function onMessageCallback(payload) { + // console.log(`on.message`, typeof payload, payload) + try { + var json = extractWsPayload(payload); + var resolverName = json.resolverName; + var type = json.type; + + log('Hear from server', type, json); + + switch (type) { + case EMIT_REPLY_TYPE$1: + var e1 = createEvt$1(namespace, resolverName, ON_MESSAGE_FN_NAME$1); + var r = ee.$trigger(e1, [json]); + log("EMIT_REPLY_TYPE", e1, r); + break + case ACKNOWLEDGE_REPLY_TYPE: + var e2 = createEvt$1(namespace, resolverName, ON_RESULT_FN_NAME$1); + var x2 = ee.$trigger(e2, [json]); + log("ACKNOWLEDGE_REPLY_TYPE", e2, x2); + break + case ERROR_TYPE: + // this is handled error and we won't throw it + // we need to extract the error from json + log("ERROR_TYPE"); + errorTypeHandler(ee, namespace, resolverName, json); + 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 + log('Unhandled event!', json); + errorTypeHandler(ee, namespace, resolverName, json); + // let error = {error: {'message': 'Unhandled event!', type}}; + // ee.$trigger(createEvt(namespace, resolverName, ON_RESULT_FN_NAME), [error]) + } + } catch(e) { + console.error("ws.onmessage error", e); + errorTypeHandler(ee, namespace, false, e); + } + }; + // when the server close the connection + ws.onclose = function onCloseCallback() { + log('ws.onclose callback'); + // @TODO what to do with this + // ee.$trigger(LOGOUT_EVENT_NAME, [namespace]) + }; + // add a onerror event handler here + ws.onerror = function onErrorCallback(err) { + // trigger a global error event + log("ws.onerror", err); + handleNamespaceOnError(ee, namespace, err); + }; + + if (isPrivate) { + logoutEventHandler(ee); + } + } + + // actually binding the event client to the socket client + + /** + * 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 + * @return {object} what comes in what goes out + */ + function createNsp(opts, nspMap, ee) { + // arguments for clientEventHandler + var args = [opts, ee, socketEventHandler]; + + // now create the nsps + var namespaces = nspMap.namespaces; + var token = opts.token; + var ref = createNspAction$1(opts, nspMap, token); + var nsps = ref.nsps; + // binding the listeners - and it will listen to LOGOUT event + // to unbind itself, and the above call will bind it again + Reflect.apply(clientEventHandler$1, null, args.concat([namespaces, nsps])); + // setup listener for the login event + if (opts.enableAuth) { + loginEventHandler(ee, namespaces, nspMap); + } + // return what input + return { opts: opts, nspMap: nspMap, ee: ee } + } + + // breaking up the create-nsp.js file + + // share method to create the wsClientResolver + + /** + * Create the framework <---> jsonql client binding + * @param {object} frameworkModule the different WebSocket module + * @return {function} the wsClientResolver + */ + function bindFrameworkToJsonql(frameworkModule) { + + var publicClient = initWebSocketClient(frameworkModule); + var privateClient = initWebSocketClient(frameworkModule, true); + + /** + * wsClientResolver + * @param {object} opts configuration + * @param {object} nspMap from the contract + * @param {object} ee instance of the eventEmitter + * @return {object} passing the same 3 input out with additional in the opts + */ + return function createClientBindingAction(opts, nspMap, ee) { + opts.nspClient = publicClient; + opts.nspAuthClient = privateClient; + // @1.0.7 remove later once everything fixed + var log = opts.log; + if (log && typeof log === 'function') { + log('@jsonql/ws ee', ee.name); + log('@jsonql/ws createClientResolver', opts); + } + // console.log(`contract`, opts.contract) + return createNsp(opts, nspMap, ee) + } + } + + // rename from ws-client-resolver to create-ws-client + + /** + * @param {object} opts configuration + * @param {object} nspMap from the contract + * @param {object} ee instance of the eventEmitter + * @return {object} passing the same 3 input out with additional in the opts + */ + var frameworkSocketEngine = bindFrameworkToJsonql(WebSocket$1); + + // this is the module entry point for ES6 for client + + // export back the function and that's it + function wsBrowserClient(config, constProps) { + if ( config === void 0 ) config = {}; + if ( constProps === void 0 ) constProps = {}; + + var initMethod = wsClientCore( + frameworkSocketEngine, + {}, + Object.assign({}, wsClientConstProps, constProps) + ); + return initMethod(config) + } + + // just export interface for browser + + return wsBrowserClient; + +}))); //# sourceMappingURL=jsonql-ws-client.umd.js.map diff --git a/packages/@jsonql/ws/dist/jsonql-ws-client.umd.js.map b/packages/@jsonql/ws/dist/jsonql-ws-client.umd.js.map index fa3cdb54..9287880d 100644 --- a/packages/@jsonql/ws/dist/jsonql-ws-client.umd.js.map +++ b/packages/@jsonql/ws/dist/jsonql-ws-client.umd.js.map @@ -1 +1 @@ -{"version":3,"file":"jsonql-ws-client.umd.js","sources":[],"sourcesContent":[],"names":[],"mappings":""} \ No newline at end of file +{"version":3,"file":"jsonql-ws-client.umd.js","sources":["../node_modules/_rollup-plugin-node-globals@1.4.0@rollup-plugin-node-globals/src/global.js","../../../ws-client-core/node_modules/lodash-es/_arrayMap.js","../../../ws-client-core/node_modules/lodash-es/isArray.js","../../../ws-client-core/node_modules/lodash-es/_objectToString.js","../../../ws-client-core/node_modules/lodash-es/isObjectLike.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-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/lodash-es/_overArg.js","../../../ws-client-core/node_modules/lodash-es/_arrayFilter.js","../../../ws-client-core/node_modules/lodash-es/_createBaseFor.js","../../../ws-client-core/node_modules/lodash-es/_baseTimes.js","../../../ws-client-core/node_modules/lodash-es/stubFalse.js","../../../ws-client-core/node_modules/lodash-es/_isIndex.js","../../../ws-client-core/node_modules/lodash-es/isLength.js","../../../ws-client-core/node_modules/lodash-es/_baseUnary.js","../../../ws-client-core/node_modules/lodash-es/_isPrototype.js","../../../ws-client-core/node_modules/lodash-es/isObject.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/_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/_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/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/identity.js","../../../ws-client-core/node_modules/lodash-es/_baseProperty.js","../../../ws-client-core/node_modules/jsonql-params-validator/src/object.js","../../../ws-client-core/node_modules/jsonql-errors/src/validation-error.js","../../../ws-client-core/node_modules/jsonql-params-validator/src/validator.js","../../../ws-client-core/node_modules/lodash-es/_copyArray.js","../../../ws-client-core/node_modules/lodash-es/_safeGet.js","../../../ws-client-core/node_modules/lodash-es/_nativeKeysIn.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/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-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-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/node_modules/jsonql-utils/src/generic.js","../../../ws-client-core/node_modules/jsonql-errors/src/500-error.js","../../../ws-client-core/node_modules/jsonql-errors/src/resolver-not-found-error.js","../../../ws-client-core/node_modules/jsonql-errors/src/server-error.js","../../../ws-client-core/node_modules/jsonql-utils/src/contract.js","../../../ws-client-core/node_modules/jsonql-utils/src/namespace.js","../../../ws-client-core/src/utils/helpers.js","../../../ws-client-core/src/core/setup-auth-methods.js","../../../ws-client-core/src/options/constants.js","../../../ws-client-core/src/core/respond-handler.js","../../../ws-client-core/src/core/action-call.js","../../../ws-client-core/src/core/setup-send-method.js","../../../ws-client-core/src/core/setup-resolver.js","../../../ws-client-core/src/core/resolver-methods.js","../../../ws-client-core/src/core/setup-intercom.js","../../../ws-client-core/src/core/generator.js","../../../ws-client-core/src/options/index.js","../../../ws-client-core/src/api.js","../../../ws-client-core/src/share/create-nsp-client.js","../../../ws-client-core/src/share/trigger-namespaces-on-error.js","../../../ws-client-core/src/share/client-event-handler.js","../src/options/index.js","../src/core/create-websocket-binding/init-websocket-client.js","../src/core/create-nsp/login-event-handler.js","../node_modules/_lodash-es@4.17.15@lodash-es/isArray.js","../node_modules/_lodash-es@4.17.15@lodash-es/_objectToString.js","../node_modules/_lodash-es@4.17.15@lodash-es/isObjectLike.js","../node_modules/_jsonql-utils@1.1.3@jsonql-utils/src/generic.js","../node_modules/_jsonql-utils@1.1.3@jsonql-utils/src/timestamp.js","../node_modules/_jsonql-utils@1.1.3@jsonql-utils/src/socket.js","../src/core/create-nsp/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/core/framework-socket-engine.js","../src/browser-ws-client.js","../index.js"],"sourcesContent":["export default (typeof global !== \"undefined\" ? global :\n typeof self !== \"undefined\" ? self :\n typeof window !== \"undefined\" ? window : {});\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 * 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 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 * 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 * 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","// 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\nexport const 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)`\nexport const PARAMS_NOT_ARRAY_ERR = `params is not an array! Did something gone wrong when you generate the contract.json?`\nexport const EXCEPTION_CASE_ERR = 'Could not understand your arguments and parameter structure!'\nexport const UNUSUAL_CASE_ERR = 'This is an unusual situation where the arguments are more than the params, but not mark as spread'\n\n// re-export\nimport * as JSONQL_CONSTANTS from 'jsonql-constants'\n// @TODO the jsdoc return array. and we should also allow array syntax\nexport const DEFAULT_TYPE = JSONQL_CONSTANTS.DEFAULT_TYPE\nexport const ARRAY_TYPE_LFT = JSONQL_CONSTANTS.ARRAY_TYPE_LFT\nexport const ARRAY_TYPE_RGT = JSONQL_CONSTANTS.ARRAY_TYPE_RGT\n\nexport const TYPE_KEY = JSONQL_CONSTANTS.TYPE_KEY\nexport const OPTIONAL_KEY = JSONQL_CONSTANTS.OPTIONAL_KEY\nexport const ENUM_KEY = JSONQL_CONSTANTS.ENUM_KEY\nexport const ARGS_KEY = JSONQL_CONSTANTS.ARGS_KEY\nexport const CHECKER_KEY = JSONQL_CONSTANTS.CHECKER_KEY\nexport const ALIAS_KEY = JSONQL_CONSTANTS.ALIAS_KEY\n\nexport const ARRAY_TYPE = JSONQL_CONSTANTS.ARRAY_TYPE\nexport const OBJECT_TYPE = JSONQL_CONSTANTS.OBJECT_TYPE\nexport const STRING_TYPE = JSONQL_CONSTANTS.STRING_TYPE\nexport const BOOLEAN_TYPE = JSONQL_CONSTANTS.BOOLEAN_TYPE\nexport const NUMBER_TYPE = JSONQL_CONSTANTS.NUMBER_TYPE\nexport const KEY_WORD = JSONQL_CONSTANTS.KEY_WORD\nexport const OR_SEPERATOR = JSONQL_CONSTANTS.OR_SEPERATOR\n\n// not actually in use\n// export const NUMBER_TYPES = JSONQL_CONSTANTS.NUMBER_TYPES;\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","/**\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 * 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 * 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 * 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","/**\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","/** 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","/** 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 * 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","/** 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 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","/**\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","/** 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","/** 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 * 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 * 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 * 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","// validate object type\n\nimport isPlainObject from 'lodash-es/isPlainObject'\nimport filter from 'lodash-es/filter'\n\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","// 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","// 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 // checkIsObject,\n combineFn,\n notEmpty\n} from './index'\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 // UNUSUAL_CASE_ERR\n} from './constants'\nimport { DATA_KEY, ERROR_KEY } from 'jsonql-constants'\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","/**\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","/**\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 * 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 * 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","/** 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","// 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","// 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'\n// PIA syntax\nexport const isObject = checkIsObject\nexport const isAny = checkIsAny\nexport const isString = checkIsString\nexport const isBoolean = checkIsBoolean\nexport const isNumber = checkIsNumber\nexport const isArray = checkIsArray\nexport const isNotEmpty = notEmpty\n\nimport * as validator from './src/validator'\n\nexport const normalizeArgs = validator.normalizeArgs\nexport const validateSync = validator.validateSync\nexport const validateAsync = validator.validateAsync\n\n// configuration checking\n\nimport * as jsonqlOptions from './src/options'\n\nexport const JSONQL_PARAMS_VALIDATOR_INFO = jsonqlOptions.JSONQL_PARAMS_VALIDATOR_INFO\n\nexport const createConfig = jsonqlOptions.createConfig\nexport const constructConfig = jsonqlOptions.constructConfigFn\n// construct the final output 1.5.2\nexport const checkConfigAsync = jsonqlOptions.getCheckConfigAsync(validator.validateSync)\nexport const checkConfig = jsonqlOptions.getCheckConfig(validator.validateSync)\n\n// export the two extra functions\nimport isInArray from './src/is-in-array'\nimport isObjectHasKeyFn from './src/is-key-in-object'\n\nexport const inArray = isInArray\nexport const isObjectHasKey = isObjectHasKeyFn\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","// 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","/**\n * This is a custom error to throw when server throw a 500\n * This help us to capture the right error, due to the call happens in sequence\n * @param {string} message to tell what happen\n * @param {mixed} extra things we want to add, 500?\n */\nexport default class Jsonql500Error extends Error {\n constructor(...args) {\n super(...args)\n\n this.message = args[0]\n this.detail = args[1]\n\n this.className = Jsonql500Error.name;\n\n if (Error.captureStackTrace) {\n Error.captureStackTrace(this, Jsonql500Error)\n }\n }\n\n static get statusCode() {\n return 500;\n }\n\n static get name() {\n return 'Jsonql500Error';\n }\n\n}\n","/**\n * This is a custom error to throw when could not find the resolver\n * This help us to capture the right error, due to the call happens in sequence\n * @param {string} message to tell what happen\n * @param {mixed} extra things we want to add, 500?\n */\nexport default class JsonqlResolverNotFoundError extends Error {\n constructor(...args) {\n super(...args)\n\n this.message = args[0]\n this.detail = args[1]\n\n this.className = JsonqlResolverNotFoundError.name;\n\n if (Error.captureStackTrace) {\n Error.captureStackTrace(this, JsonqlResolverNotFoundError);\n }\n }\n\n static get statusCode() {\n return 404;\n }\n\n static get name() {\n return 'JsonqlResolverNotFoundError';\n }\n}\n","// this is from an example from Koa team to use for internal middleware ctx.throw\n// but after the test the res.body part is unable to extract the required data\n// I keep this one here for future reference\n\nexport default class JsonqlServerError extends Error {\n\n constructor(statusCode, message) {\n super(message)\n this.statusCode = statusCode;\n this.className = JsonqlServerError.name;\n }\n\n static get name() {\n return 'JsonqlServerError';\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","// 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.publicNamespace ].join('/'),\n [ base , config.privateNamespace ].join('/')\n ]\n }\n return [ base ]\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","// 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(client, resolverName, setupResolver(namespace, resolverName, params, fn, ee, log))\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 createNamespaceErrorHandler(client, opts, ee, nspGroup) {\n return [\n // using the onError as name\n // @TODO we should follow the convention earlier\n // make this a setter for the clientitself\n objDefineProps(client, ON_ERROR_FN_NAME, 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 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 createOnReadyHandler(client, opts, ee) {\n return [\n objDefineProps(client, ON_READY_FN_NAME, 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 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} ","// 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 createNamespaceErrorHandler,\n createOnReadyHandler\n} from './resolver-methods'\nimport {\n setupFinalStep \n} from './setup-final-step'\nimport {\n NSP_GROUP\n} from 'jsonql-constants'\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 generator(opts, nspMap, ee) {\n\n let args = [\n generateResolvers,\n createNamespaceErrorHandler,\n createOnReadyHandler\n ]\n if (opts.enableAuth) {\n args.push(\n createAuthMethods\n )\n } \n // we will always get back the [ obj, opts, ee ]\n // then we only return the obj (wsClient)\n args.push(setupFinalStep)\n // run it\n const fn = Reflect.apply(chainFns, null, args)\n\n return fn(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 { generator } from './core'\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} frameworkSocketEngine \n * @param {object} config the already checked config \n */\nexport function wsClientCoreAction(frameworkSocketEngine, config) {\n return postCheckInjectOpts(config)\n // the following two moved to wsPostConfig\n .then(createRequiredParams)\n .then(\n ({opts, nspMap, ee}) => frameworkSocketEngine(opts, nspMap, ee)\n )\n .then(\n ({opts, nspMap, ee}) => generator(opts, nspMap, ee)\n )\n .catch(err => {\n console.error(`jsonql-ws-core-client init error`, err)\n })\n}\n\n/**\n * The main interface which will generate the socket clients and map all events\n * @param {object} frameworkSocketEngine 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(frameworkSocketEngine, configCheckMap = {}, constProps = {}) {\n // we need to inject property to this client later\n return (config = {}) => checkConfiguration(config, configCheckMap, constProps)\n .then(opts => wsClientCoreAction(frameworkSocketEngine, opts))\n}\n","// since both the ws and io version are\n// pre-defined in the client-generator\n// and this one will have the same parameters\n// and the callback is identical\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 } = opts\n const url = namespace ? [hostname, namespace].join('/') : wssPath\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 } = opts\n const url = namespace ? [hostname, namespace].join('/') : wssPath\n if (token && typeof token !== 'string') {\n throw new Error(`Expect token to be string, but got ${token}`)\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}","// 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\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, SOCKET_IO, DISCONNECTED_ERROR_MSG } from '../options/constants'\nimport { createEvt, clearMainEmitEvt } from '../utils'\nimport { triggerNamespacesOnError } from './trigger-namespaces-on-error'\n\n/**\n * A Event handler 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 */\nconst notLoginWsHandler = (namespace, ee, opts) => {\n const { log } = opts \n ee.$only(\n createEvt(namespace, EMIT_EVT),\n function notLoginHandlerCallback(resolverName, args) {\n log('[notLoginHandler] hijack the ws call', namespace, resolverName, args)\n const error = {\n message: NOT_LOGIN_ERR_MSG\n }\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 handler, but wrap inside the error key\n ee.$call(createEvt(namespace, resolverName, ON_RESULT_FN_NAME), [{ error }])\n }\n )\n}\n\n/**\n * A Event handler 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 */\nconst disconnectedHandler = (namespace, ee, opts) => {\n const { log } = opts \n ee.$only(\n createEvt(namespace, EMIT_EVT),\n function disconnectedHandlerCallback(resolverName, args) {\n log(`[disconnectedHandler] 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 handler, but wrap inside the error key\n ee.$call(createEvt(namespace, resolverName, ON_RESULT_FN_NAME), [{ error }])\n }\n )\n}\n\n/**\n * get the private namespace\n * @param {array} namespaces array\n * @return {*} string on success\n */\nconst getPrivateNamespace = (namespaces) => (\n namespaces.length > 1 ? namespaces[0] : false\n)\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 */\nconst logoutEvtHandler = (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(LOGOUT_EVENT_NAME, function logoutEvtHandlerAction() {\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 handler\n triggerNamespacesOnError(ee, [privateNamespace], LOGOUT_EVENT_NAME)\n // rebind all of the handler 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 notLoginWsHandler(privateNamespace, ee, opts)\n })\n}\n\n/**\n * The disconnect event handler, 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 */\nconst disconnectHandler = (nsps, namespaces, ee, opts) => {\n const { log } = opts \n ee.$on(DISCONNECT_EVENT_NAME, function disconnectEvtHandler() {\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 disconnectedHandler(namespace, ee, opts)\n })\n })\n}\n\n/**\n * centralize all the comm in one place\n * @param {object} opts configuration\n * @param {object} ee Event Emitter instance\n * @param {function} bindWsHandler binding the ee to ws --> this is the core bit\n * @param {object} nsps namespaced nsp\n * @return {void} nothing\n */\nexport function clientEventHandler(opts, ee, bindSocketEventHandler, nsps) {\n // since all these params already in the opts\n const { nspMap, 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 let isPrivate = false\n let hasPrivate = false\n // loop\n // @BUG for io this has to be in order the one with auth need to get call first\n // The order of login is very import we need to run in order here to make sure\n // one is execute then the other\n namespaces.forEach(namespace => {\n isPrivate = privateNamespace === namespace\n if (!hasPrivate) {\n hasPrivate = isPrivate\n }\n if (nsps[namespace]) {\n\n log('[call bindWsHandler]', isPrivate, namespace)\n let args = [namespace, nsps[namespace], ee, isPrivate, opts]\n \n if (opts.serverType === SOCKET_IO) {\n let { nspGroup } = nspMap\n args.push(nspGroup[namespace])\n }\n Reflect.apply(bindSocketEventHandler, null, args)\n } else {\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 notLoginWsHandler(namespace, ee, opts)\n }\n })\n // logout event handler \n if (hasPrivate) {\n log(`Has private and add logoutEvtHandler`)\n\n logoutEvtHandler(nsps, namespaces, ee, opts)\n }\n // finally the disconnect event handlers\n disconnectHandler(nsps, namespaces, ee, opts) \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'\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 * @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 */\nfunction initWebSocketClient(WebSocket, auth = false) {\n if (auth === false) {\n return function createWsClientHandler(url) {\n return new WebSocket(fixWss(url))\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 * @return {object} ws instance\n */\n return function createWsAuthClientHandler(url, token) {\n const ws_url = fixWss(url)\n // console.log('what happen here?', url, ws_url, token)\n const uri = token && typeof token === 'string' ? `${ws_url}?${TOKEN_PARAM_NAME}=${token}` : ws_url\n try {\n return new WebSocket(uri)\n } catch(e) {\n console.error('WebSocket Connection Error', e)\n return false\n }\n }\n}\n\nexport { initWebSocketClient }","// @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}","/**\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 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 * 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","// 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","/**\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","// 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' \n\nconst WS_KEYS = [\n WS_REPLY_TYPE,\n WS_EVT_NAME,\n WS_DATA_NAME\n]\nimport isString from 'lodash-es/isString'\nimport { toJson, isFunc, isObjectHasKey, nil } from './generic'\nimport { timestamp } from './timestamp'\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 can not decoded', 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_TYPE,\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 createReplyMsg, \n createEvt, \n extractWsPayload \n} from 'jsonql-utils/module'\nimport {\n handleNamespaceOnError\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 * @return {void}\n */\nconst logoutEventHandler = (ee) => {\n // listen to the LOGOUT_EVENT_NAME when this is a private nsp\n ee.$on(LOGOUT_EVENT_NAME, function closeEvtHandler() {\n try {\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 socketEventHandler(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 = createReplyMsg(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 const json = extractWsPayload(payload)\n const { resolverName, type } = json\n \n log('Hear 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_TYPE:\n // this is handled error and we won't throw it\n // we need to extract the error from json\n log(`ERROR_TYPE`)\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 logoutEventHandler(ee)\n }\n}\n","// actually binding the event client to the socket client\n\n// from the jsonql-ws-client-core\nimport { clientEventHandler } from '../modules'\n// local \nimport { createNspAction } from './create-nsp-action'\nimport { loginEventHandler } from './login-event-handler'\nimport { socketEventHandler } from './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 // arguments for clientEventHandler\n const args = [opts, ee, socketEventHandler]\n\n // now create the nsps\n const { namespaces } = nspMap\n const { token } = opts\n const { nsps } = createNspAction(opts, nspMap, token)\n // binding the listeners - and it will listen to LOGOUT event\n // to unbind itself, and the above call will bind it again\n Reflect.apply(clientEventHandler, null, args.concat([namespaces, nsps]))\n // setup listener for the login event\n if (opts.enableAuth) {\n loginEventHandler(ee, namespaces, nspMap, opts)\n }\n // return what input\n return { opts, nspMap, ee }\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\n\nimport { initWebSocketClient } from './init-websocket-client'\nimport createNsp from '../create-nsp'\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 const publicClient = initWebSocketClient(frameworkModule)\n const privateClient = initWebSocketClient(frameworkModule, true)\n\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 opts.nspClient = publicClient\n opts.nspAuthClient = privateClient \n // @1.0.7 remove later once everything fixed \n const { log } = opts\n if (log && typeof log === 'function') {\n log('@jsonql/ws ee', ee.name)\n log('@jsonql/ws createClientResolver', opts)\n }\n // console.log(`contract`, opts.contract)\n return createNsp(opts, nspMap, ee)\n }\n}\n\nexport { bindFrameworkToJsonql }","// rename from ws-client-resolver to create-ws-client \n\n// 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 './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)","// this is the module entry point for ES6 for client\n// the main will point to the node.js server side setup\nimport { \n wsClientCore\n} from './core/modules' \nimport { wsClientConstProps } from './options'\n\n\nimport frameworkSocketEngine from './core/framework-socket-engine'\n\n// export back the function and that's it\nexport default function wsBrowserClient(config = {}, constProps = {}) {\n const initMethod = wsClientCore(\n frameworkSocketEngine, \n {}, \n Object.assign({}, wsClientConstProps, constProps)\n )\n return initMethod(config)\n}\n","// just export interface for browser\nimport wsBrowserClient from './src/browser-ws-client'\n\nexport default wsBrowserClient"],"names":[],"mappings":";;;;;;AAAA;;;;;;;;;;;;;;;;YCAA;;;;;;;;;;;;;;;;;;;;YCAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;YCAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;YCAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;YCAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;YCAA;;;;;;;;;;;;;;;;;;;;;;;YCAA;;;;;;;;;;;YCAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;YCAA;;;;;;;;;;;YCAA;;;;;;;;;;;;;;;;;;;;;;;;;YCAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;YCAA;;;;;;;;;;;YCAA;;;;;;;;;YCAA;;;;;;;;;;YCAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;YCAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;YCAA;;;;;;;;;;;;;;;;;;;;YCAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;YCAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;YCAA;;;;;;;;;;;;;;;;;;;;;;;;YCAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;YCAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;YCAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;YCAA;;;;;;;;;;;;;;;;;;;;;;;;YCAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;YCAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;YCAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;YCAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;YCAA;;;;;;;;;;;;YCAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;YCAA;;;;;;;;;;;;;;;;;YCAA;;;;;;;;;;;;;YCAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;YCAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;YCAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;YCAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;YCAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;YCAA;;;;;;;;;;;;;;;;;;YCAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;YCAA;;;;;;;;;;;;;;;;;;;;;;YCAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;YCAA;;;;;;;;;;;;;;;;;YCAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;YCAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;YCAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;YCAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;YCAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;YCAA;;;;;;;;;;;;;;;;;;;;YCAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;YCAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;YCAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;YCAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;YCAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;YCAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;YCAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;YCAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;YCAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;YCAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;YCAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;YCAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;YCAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;YCAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;YCAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;YCAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;YCAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;YCAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;YCAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;YCAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;YCAA;;;;;;;;YCAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;YCAA;;;;YCAA;;;;YCAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;YCAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;YCAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;YCAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;YCAA;;YCAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;YCAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;YCAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;YCAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;YCAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;YCAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;YCAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;YCAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;YCAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;YCAA;;;;;;;;;;;;YCAA;;;;;;;;;;;;;;;;;;;;;;YCAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;YCAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;YCAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;YCAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;YCAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;YCAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;YCAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;YCAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;YCAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;YCAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;YCAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;YCAA;;;;;;;;;;;;;;;;;;;;;;;;YCAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;YCAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;YCAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;YCAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;YCAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;YCAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;YCAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;YCAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;YCAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;YCAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;YCAA;;YCAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;YCAA;;;;;;;;;;YCAA;;;;;;;;;;;;;;;YCAA;;;;;;;;"} \ No newline at end of file diff --git a/packages/@jsonql/ws/main.js b/packages/@jsonql/ws/main.js index 8fea0722..8e532770 100644 --- a/packages/@jsonql/ws/main.js +++ b/packages/@jsonql/ws/main.js @@ -1,2 +1,8544 @@ -"use strict";var t,e=(t=require("ws"))&&"object"==typeof t&&"default"in t?t.default:t,r="undefined"!=typeof global?global:"undefined"!=typeof self?self:"undefined"!=typeof window?window:{},n="object"==typeof r&&r&&r.Object===Object&&r,o="object"==typeof self&&self&&self.Object===Object&&self,i=n||o||Function("return this")(),a=i.Symbol;function u(t,e){for(var r=-1,n=null==t?0:t.length,o=Array(n);++r=n?t:function(t,e,r){var n=-1,o=t.length;e<0&&(e=-e>o?0:o+e),(r=r>o?o:r)<0&&(r+=o),o=e>r?0:r-e>>>0,e>>>=0;for(var i=Array(o);++n-1;);return r}(n,o),function(t,e){for(var r=t.length;r--&&O(e,t[r],0)>-1;);return r}(n,o)+1).join("")}var M=function(t){return!!c(t)||null!=t&&""!==L(t)};function J(t){return function(t){return"number"==typeof t||d(t)&&"[object Number]"==g(t)}(t)&&t!=+t}function U(t){return"string"==typeof t||!c(t)&&d(t)&&"[object String]"==g(t)}var D=function(t){return!U(t)&&!J(parseFloat(t))},H=function(t){return""!==L(t)&&U(t)},I=function(t){return null!=t&&"boolean"==typeof t},G=function(t,e){return void 0===e&&(e=!0),void 0!==t&&""!==t&&""!==L(t)&&(!1===e||!0===e&&null!==t)},W=function(t){switch(t){case"number":return D;case"string":return H;case"boolean":return I;default:return G}},B=function(t,e){return void 0===e&&(e=""),!!c(t)&&(""===e||""===L(e)||!(t.filter((function(t){return!W(e)(t)})).length>0))},V=function(t){if(t.indexOf("array.<")>-1&&t.indexOf(">")>-1){var e=t.replace("array.<","").replace(">","");return e.indexOf("|")?e.split("|"):[e]}return!1},Y=function(t,e){var r=t.arg;return e.length>1?!r.filter((function(t){return!(e.length>e.filter((function(e){return!W(e)(t)})).length)})).length:e.length>e.filter((function(t){return!B(r,t)})).length};function K(t,e){return function(r){return t(e(r))}}var Q=K(Object.getPrototypeOf,Object),X=Function.prototype,Z=Object.prototype,tt=X.toString,et=Z.hasOwnProperty,rt=tt.call(Object);function nt(t){if(!d(t)||"[object Object]"!=g(t))return!1;var e=Q(t);if(null===e)return!0;var r=et.call(e,"constructor")&&e.constructor;return"function"==typeof r&&r instanceof r&&tt.call(r)==rt}var ot,it=function(t,e,r){for(var n=-1,o=Object(t),i=r(t),a=i.length;a--;){var u=i[ot?a:++n];if(!1===e(o[u],u,o))break}return t};function at(t){return d(t)&&"[object Arguments]"==g(t)}var ut=Object.prototype,ct=ut.hasOwnProperty,st=ut.propertyIsEnumerable,ft=at(function(){return arguments}())?at:function(t){return d(t)&&ct.call(t,"callee")&&!st.call(t,"callee")};var lt="object"==typeof exports&&exports&&!exports.nodeType&&exports,pt=lt&&"object"==typeof module&&module&&!module.nodeType&&module,ht=pt&&pt.exports===lt?i.Buffer:void 0,vt=(ht?ht.isBuffer:void 0)||function(){return!1},gt=/^(?:0|[1-9]\d*)$/;function dt(t,e){var r=typeof t;return!!(e=null==e?9007199254740991:e)&&("number"==r||"symbol"!=r&>.test(t))&&t>-1&&t%1==0&&t-1&&t%1==0&&t<=9007199254740991}var _t={};_t["[object Float32Array]"]=_t["[object Float64Array]"]=_t["[object Int8Array]"]=_t["[object Int16Array]"]=_t["[object Int32Array]"]=_t["[object Uint8Array]"]=_t["[object Uint8ClampedArray]"]=_t["[object Uint16Array]"]=_t["[object Uint32Array]"]=!0,_t["[object Arguments]"]=_t["[object Array]"]=_t["[object ArrayBuffer]"]=_t["[object Boolean]"]=_t["[object DataView]"]=_t["[object Date]"]=_t["[object Error]"]=_t["[object Function]"]=_t["[object Map]"]=_t["[object Number]"]=_t["[object Object]"]=_t["[object RegExp]"]=_t["[object Set]"]=_t["[object String]"]=_t["[object WeakMap]"]=!1;var bt,mt="object"==typeof exports&&exports&&!exports.nodeType&&exports,jt=mt&&"object"==typeof module&&module&&!module.nodeType&&module,wt=jt&&jt.exports===mt&&n.process,Ot=function(){try{var t=jt&&jt.require&&jt.require("util").types;return t||wt&&wt.binding&&wt.binding("util")}catch(t){}}(),St=Ot&&Ot.isTypedArray,Et=St?(bt=St,function(t){return bt(t)}):function(t){return d(t)&&yt(t.length)&&!!_t[g(t)]},kt=Object.prototype.hasOwnProperty;function $t(t,e){var r=c(t),n=!r&&ft(t),o=!r&&!n&&vt(t),i=!r&&!n&&!o&&Et(t),a=r||n||o||i,u=a?function(t,e){for(var r=-1,n=Array(t);++r-1},Jt.prototype.set=function(t,e){var r=this.__data__,n=Lt(r,t);return n<0?(++this.size,r.push([t,e])):r[n][1]=e,this};var Ut,Dt=i["__core-js_shared__"],Ht=(Ut=/[^.]+$/.exec(Dt&&Dt.keys&&Dt.keys.IE_PROTO||""))?"Symbol(src)_1."+Ut:"";var It=Function.prototype.toString;function Gt(t){if(null!=t){try{return It.call(t)}catch(t){}try{return t+""}catch(t){}}return""}var Wt=/^\[object .+?Constructor\]$/,Bt=Function.prototype,Vt=Object.prototype,Yt=Bt.toString,Kt=Vt.hasOwnProperty,Qt=RegExp("^"+Yt.call(Kt).replace(/[\\^$.*+?()[\]{}|]/g,"\\$&").replace(/hasOwnProperty|(function).*?(?=\\\()| for .+?(?=\\\])/g,"$1.*?")+"$");function Xt(t){return!(!xt(t)||function(t){return!!Ht&&Ht in t}(t))&&(zt(t)?Qt:Wt).test(Gt(t))}function Zt(t,e){var r=function(t,e){return null==t?void 0:t[e]}(t,e);return Xt(r)?r:void 0}var te=Zt(i,"Map"),ee=Zt(Object,"create");var re=Object.prototype.hasOwnProperty;var ne=Object.prototype.hasOwnProperty;function oe(t){var e=-1,r=null==t?0:t.length;for(this.clear();++eu))return!1;var s=i.get(t);if(s&&i.get(e))return s==e;var f=-1,l=!0,p=2&r?new ce:void 0;for(i.set(t,e),i.set(e,t);++fe.type.filter((function(t){var e;return void 0===r||(!1!==(e=V(t))?!Y({arg:r},e):!W(t)(r))})).length)})).length}return!1},or=function(t){function e(){for(var r=[],n=arguments.length;n--;)r[n]=arguments[n];t.apply(this,r),this.message=r[0],this.detail=r[1],this.className=e.name,t.captureStackTrace&&t.captureStackTrace(this,e)}t&&(e.__proto__=t),e.prototype=Object.create(t&&t.prototype),e.prototype.constructor=e;var r={name:{configurable:!0}};return r.name.get=function(){return"JsonqlValidationError"},Object.defineProperties(e,r),e}(Error),ir=function(t){function e(){for(var r=[],n=arguments.length;n--;)r[n]=arguments[n];t.apply(this,r),this.message=r[0],this.detail=r[1],this.className=e.name,t.captureStackTrace&&t.captureStackTrace(this,e)}t&&(e.__proto__=t),e.prototype=Object.create(t&&t.prototype),e.prototype.constructor=e;var r={name:{configurable:!0},statusCode:{configurable:!0}};return r.name.get=function(){return"JsonqlError"},r.statusCode.get=function(){return-1},Object.defineProperties(e,r),e}(Error),ar=function(t,e){var r,n,o,i,a;switch(!0){case"object"===t:return o=(n=e).arg,i=n.param,a=[o],Array.isArray(i.keys)&&i.keys.length&&a.push(i.keys),!Reflect.apply(nr,null,a);case"array"===t:return!B(e.arg);case!1!==(r=V(t)):return!Y(e,r);default:return!W(t)(e.arg)}},ur=function(t,e){return void 0!==t?t:!0===e.optional&&void 0!==e.defaultvalue?e.defaultvalue:null},cr=function(t,e,r){var n;void 0===r&&(r=!1);var o=function(t,e){if(!B(e))throw new or("params is not an array! Did something gone wrong when you generate the contract.json?");if(0===e.length)return[];if(!B(t))throw new or("args is not an array! You might want to do: ES6 Array.from(arguments) or ES5 Array.prototype.slice.call(arguments)");switch(!0){case t.length==e.length:return t.map((function(t,r){return{arg:t,index:r,param:e[r]}}));case!0===e[0].variable:var r=e[0].type;return t.map((function(t,n){return{arg:t,index:n,param:e[n]||{type:r,name:"_"}}}));case t.lengthe.length:var n=e.length,o=["any"];return t.map((function(t,r){var i=r>=n||!!e[r].optional,a=e[r]||{type:o,name:"_"+r};return{arg:i?ur(t,a):t,index:r,param:a,optional:i}}));default:throw new ir("Could not understand your arguments and parameter structure!",{args:t,params:e})}}(t,e),i=o.filter((function(t){return!0===t.optional||!0===t.param.optional?function(t){var e=t.arg,r=t.param;return!!M(e)&&!(r.type.length>r.type.filter((function(e){return ar(e,t)})).length)}(t):!(t.param.type.length>t.param.type.filter((function(e){return ar(e,t)})).length)}));return r?((n={}).error=i,n.data=o.map((function(t){return t.arg})),n):i},sr=function(){try{var t=Zt(Object,"defineProperty");return t({},"",{}),t}catch(t){}}();function fr(t,e,r){"__proto__"==e&&sr?sr(t,e,{configurable:!0,enumerable:!0,value:r,writable:!0}):t[e]=r}function lr(t,e,r){(void 0===r||Ft(t[e],r))&&(void 0!==r||e in t)||fr(t,e,r)}var pr="object"==typeof exports&&exports&&!exports.nodeType&&exports,hr=pr&&"object"==typeof module&&module&&!module.nodeType&&module,vr=hr&&hr.exports===pr?i.Buffer:void 0,gr=vr?vr.allocUnsafe:void 0;function dr(t,e){var r,n,o=e?(r=t.buffer,n=new r.constructor(r.byteLength),new le(n).set(new le(r)),n):t.buffer;return new t.constructor(o,t.byteOffset,t.length)}var yr=Object.create,_r=function(){function t(){}return function(e){if(!xt(e))return{};if(yr)return yr(e);t.prototype=e;var r=new t;return t.prototype=void 0,r}}();function br(t,e){if(("constructor"!==e||"function"!=typeof t[e])&&"__proto__"!=e)return t[e]}var mr=Object.prototype.hasOwnProperty;function jr(t,e,r){var n=t[e];mr.call(t,e)&&Ft(n,r)&&(void 0!==r||e in t)||fr(t,e,r)}var wr=Object.prototype.hasOwnProperty;function Or(t){if(!xt(t))return function(t){var e=[];if(null!=t)for(var r in Object(t))e.push(r);return e}(t);var e=At(t),r=[];for(var n in t)("constructor"!=n||!e&&wr.call(t,n))&&r.push(n);return r}function Sr(t){return Rt(t)?$t(t,!0):Or(t)}function Er(t){return function(t,e,r,n){var o=!r;r||(r={});for(var i=-1,a=e.length;++i0){if(++e>=800)return arguments[0]}else e=0;return t.apply(void 0,arguments)}}(Pr);function zr(t,e){return xr(function(t,e,r){return e=Ar(void 0===e?t.length-1:e,0),function(){for(var n=arguments,o=-1,i=Ar(n.length-e,0),a=Array(i);++o1?e[n-1]:void 0,i=n>2?e[2]:void 0;for(o=Rr.length>3&&"function"==typeof o?(n--,o):void 0,i&&function(t,e,r){if(!xt(r))return!1;var n=typeof e;return!!("number"==n?Rt(r)&&dt(e,r.length):"string"==n&&e in r)&&Ft(r[e],t)}(e[0],e[1],i)&&(o=n<3?void 0:o,n=1),t=Object(t);++r0;)e[r]=arguments[r+1];if(this.logger("($queue) get called"),!0===this.__suspend_state__){if(un(this.__pattern__)){var n=this.__pattern__.test(t);if(!n)return!1}this.logger("($queue) added to $queue",e),this.queueStore.add([t].concat(e))}return!!this.__suspend_state__},fn.$queues.get=function(){var t=this.queueStore.size;return this.logger("($queues)","size: "+t),t>0?Array.from(this.queueStore):[]},sn.prototype.__suspend__=function(t){if("boolean"!=typeof t)throw new Error("$suspend only accept Boolean value! we got "+typeof t);var e=this.__suspend_state__;this.__suspend_state__=t,this.logger('($suspend) Change from "'+e+'" --\x3e "'+t+'"'),!0===e&&!1===t&&this.__release__()},sn.prototype.__release__=function(){var t=this,e=this.queueStore.size,r=this.__pattern__;if(this.__pattern__=null,this.logger("(release) was called with "+e+(r?' for "'+r+'"':"")+" item"+(e>1?"s":"")),e>0){var n=Array.from(this.queueStore);this.queueStore.clear(),this.logger("(release queue)",n),n.forEach((function(e){t.logger(e),Reflect.apply(t.$trigger,t,e)})),this.logger("Release size "+this.queueStore.size)}return e},Object.defineProperties(sn.prototype,fn);var ln=function(t){function e(e){if("function"!=typeof e)throw new Error("Just die here the logger is not a function!");e("---\x3e Create a new EventEmitter <---"),t.call(this,{logger:e})}t&&(e.__proto__=t),e.prototype=Object.create(t&&t.prototype),e.prototype.constructor=e;var r={name:{configurable:!0}};return r.name.get=function(){return"jsonql-ws-client-core"},Object.defineProperties(e.prototype,r),e}(function(t){function e(e){void 0===e&&(e={}),t.call(this,e)}t&&(e.__proto__=t),e.prototype=Object.create(t&&t.prototype),e.prototype.constructor=e;var r={$name:{configurable:!0},is:{configurable:!0},$done:{configurable:!0}};return e.prototype.logger=function(){},r.$name.get=function(){return"to1source-event"},r.is.get=function(){return this.$name},e.prototype.$on=function(t,e,r){var n=this;void 0===r&&(r=null);this.validate(t,e);var o=this.takeFromStore(t);if(!1===o)return this.logger('($on) "'+t+'" is not in lazy store'),this.addToNormalStore(t,"on",e,r);this.logger("($on) "+t+" found in lazy store");var i=0;return o.forEach((function(o){var a=o[0],u=o[1],c=o[2];if(c&&"on"!==c)throw new Error(nn+" "+c);n.logger("($on)",'call run "'+t+'"'),n.run(e,a,r||u),i+=n.addToNormalStore(t,"on",e,r||u)})),this.logger("($on) return size "+i),i},e.prototype.$once=function(t,e,r){void 0===r&&(r=null),this.validate(t,e);var n=this.takeFromStore(t);this.normalStore;if(!1===n)return this.logger('($once) "'+t+'" is not in the lazy store'),this.addToNormalStore(t,"once",e,r);this.logger("($once)",n);var o=Array.from(n)[0],i=o[0],a=o[1],u=o[2];if(u&&"once"!==u)throw new Error(nn+" "+u);this.logger("($once)",'call run "'+t+'"'),this.run(e,i,r||a),this.$off(t)},e.prototype.$only=function(t,e,r){var n=this;void 0===r&&(r=null),this.validate(t,e);var o=!1,i=this.takeFromStore(t);(this.normalStore.has(t)||(this.logger('($only) "'+t+'" add to normalStore'),o=this.addToNormalStore(t,"only",e,r)),!1!==i)&&(this.logger('($only) "'+t+'" found data in lazy store to execute'),Array.from(i).forEach((function(o){var i=o[0],a=o[1],u=o[2];if(u&&"only"!==u)throw new Error(nn+" "+u);n.logger('($only) call run "'+t+'"'),n.run(e,i,r||a)})));return o},e.prototype.$onlyOnce=function(t,e,r){void 0===r&&(r=null),this.validate(t,e);var n=!1,o=this.takeFromStore(t);if(this.normalStore.has(t)||(this.logger('($onlyOnce) "'+t+'" add to normalStore'),n=this.addToNormalStore(t,"onlyOnce",e,r)),!1!==o){this.logger("($onlyOnce)",o);var i=Array.from(o)[0],a=i[0],u=i[1],c=i[2];if(c&&"onlyOnce"!==c)throw new Error(nn+" "+c);this.logger('($onlyOnce) call run "'+t+'"'),this.run(e,a,r||u),this.$off(t)}return n},e.prototype.$replace=function(t,e,r,n){if(void 0===r&&(r=null),void 0===n&&(n="on"),this.validateType(n)){this.$off(t);var o=this["$"+n];return this.logger("($replace)",t,e),Reflect.apply(o,this,[t,e,r])}throw new Error(n+" is not supported!")},e.prototype.$trigger=function(t,e,r,n){void 0===e&&(e=[]),void 0===r&&(r=null),void 0===n&&(n=!1),this.validateEvt(t);var o=0,i=this.normalStore;if(this.logger("($trigger) normalStore",i),i.has(t)){if(this.logger('($trigger) "'+t+'" found'),this.$queue(t,e,r,n))return this.logger('($trigger) Currently suspended "'+t+'" added to queue, nothing executed. Exit now.'),!1;for(var a=Array.from(i.get(t)),u=a.length,c=!1,s=0;s0;)n[o]=arguments[o+2];if(t.has(e)?(this.logger('(addToStore) "'+e+'" existed'),r=t.get(e)):(this.logger('(addToStore) create new Set for "'+e+'"'),r=new Set),n.length>2)if(Array.isArray(n[0])){var i=n[2];this.checkTypeInLazyStore(e,i)||r.add(n)}else this.checkContentExist(n,r)||(this.logger("(addToStore) insert new",n),r.add(n));else r.add(n);return t.set(e,r),[t,r.size]},e.prototype.checkContentExist=function(t,e){return!!Array.from(e).filter((function(e){return e[0]===t[0]})).length},e.prototype.checkTypeInStore=function(t,e){this.validateEvt(t,e);var r=this.$get(t,!0);return!1===r||!r.filter((function(t){var r=t[3];return e!==r})).length},e.prototype.checkTypeInLazyStore=function(t,e){this.validateEvt(t,e);var r=this.lazyStore.get(t);return this.logger("(checkTypeInLazyStore)",r),!!r&&!!Array.from(r).filter((function(t){return t[2]!==e})).length},e.prototype.addToNormalStore=function(t,e,r,n){if(void 0===n&&(n=null),this.logger('(addToNormalStore) try to add "'+e+'" --\x3e "'+t+'" to normal store'),this.checkTypeInStore(t,e)){this.logger("(addToNormalStore)",'"'+e+'" --\x3e "'+t+'" can add to normal store');var o=this.hashFnToKey(r),i=[this.normalStore,t,o,r,n,e],a=Reflect.apply(this.addToStore,this,i),u=a[0],c=a[1];return this.normalStore=u,c}return!1},e.prototype.addToLazyStore=function(t,e,r,n){void 0===e&&(e=[]),void 0===r&&(r=null),void 0===n&&(n=!1);var o=[this.lazyStore,t,this.toArray(e),r];n&&o.push(n);var i=Reflect.apply(this.addToStore,this,o),a=i[0],u=i[1];return this.lazyStore=a,this.logger("(addToLazyStore) size: "+u),u},e.prototype.toArray=function(t){return Array.isArray(t)?t:[t]},r.normalStore.set=function(t){on.set(this,t)},r.normalStore.get=function(){return on.get(this)},r.lazyStore.set=function(t){an.set(this,t)},r.lazyStore.get=function(){return an.get(this)},e.prototype.hashFnToKey=function(t){return function(t){return t.split("").reduce((function(t,e){return(t=(t<<5)-t+e.charCodeAt(0))&t}),0)}(t.toString())+""},Object.defineProperties(e.prototype,r),e}(sn))),pn=function(t){return c(t)?t:[t]},hn=function(t,e){try{var r=Object.keys(t);return n=e,!!r.filter((function(t){return t===n})).length}catch(t){return!1}var n},vn=function(){for(var t=[],e=arguments.length;e--;)t[e]=arguments[e];return t.join("_")},gn=function(t){if("function"==typeof t)return!0;console.error("Expect to be Function type! Got "+typeof t)},dn=function(){return!1},yn=function(t){for(var e=[],r=arguments.length-1;r-- >0;)e[r]=arguments[r+1];return function(){for(var r=[],n=arguments.length;n--;)r[n]=arguments[n];return e.reduce((function(t,e){return Reflect.apply(e,null,pn(t))}),Reflect.apply(t,null,r))}};function _n(t,e,r,n){return void 0===n&&(n=null),void 0===Object.getOwnPropertyDescriptor(t,e)&&Object.defineProperty(t,e,{set:r,get:null===n?function(){return null}:n}),t}function bn(t,e,r,n){void 0===n&&(n=!1);var o=function(t,e){var r=Object.getOwnPropertyDescriptor(t,e);return void 0!==r&&r.value?r.value:r}(t,e);return!1===n&&void 0!==o||Object.defineProperty(t,e,{value:r,writable:n}),t}var mn=function(t){function e(){for(var r=[],n=arguments.length;n--;)r[n]=arguments[n];t.apply(this,r),this.message=r[0],this.detail=r[1],this.className=e.name,t.captureStackTrace&&t.captureStackTrace(this,e)}t&&(e.__proto__=t),e.prototype=Object.create(t&&t.prototype),e.prototype.constructor=e;var r={statusCode:{configurable:!0},name:{configurable:!0}};return r.statusCode.get=function(){return 406},r.name.get=function(){return"Jsonql406Error"},Object.defineProperties(e,r),e}(Error),jn=function(t){function e(){for(var r=[],n=arguments.length;n--;)r[n]=arguments[n];t.apply(this,r),this.message=r[0],this.detail=r[1],this.className=e.name,t.captureStackTrace&&t.captureStackTrace(this,e)}t&&(e.__proto__=t),e.prototype=Object.create(t&&t.prototype),e.prototype.constructor=e;var r={statusCode:{configurable:!0},name:{configurable:!0}};return r.statusCode.get=function(){return 500},r.name.get=function(){return"Jsonql500Error"},Object.defineProperties(e,r),e}(Error),wn=function(t){function e(){for(var r=[],n=arguments.length;n--;)r[n]=arguments[n];t.apply(this,r),this.message=r[0],this.detail=r[1],this.className=e.name,t.captureStackTrace&&t.captureStackTrace(this,e)}t&&(e.__proto__=t),e.prototype=Object.create(t&&t.prototype),e.prototype.constructor=e;var r={statusCode:{configurable:!0},name:{configurable:!0}};return r.statusCode.get=function(){return 403},r.name.get=function(){return"JsonqlForbiddenError"},Object.defineProperties(e,r),e}(Error),On=function(t){function e(){for(var r=[],n=arguments.length;n--;)r[n]=arguments[n];t.apply(this,r),this.message=r[0],this.detail=r[1],this.className=e.name,t.captureStackTrace&&t.captureStackTrace(this,e)}t&&(e.__proto__=t),e.prototype=Object.create(t&&t.prototype),e.prototype.constructor=e;var r={statusCode:{configurable:!0},name:{configurable:!0}};return r.statusCode.get=function(){return 401},r.name.get=function(){return"JsonqlAuthorisationError"},Object.defineProperties(e,r),e}(Error),Sn=function(t){function e(){for(var r=[],n=arguments.length;n--;)r[n]=arguments[n];t.apply(this,r),this.message=r[0],this.detail=r[1],this.className=e.name,t.captureStackTrace&&t.captureStackTrace(this,e)}t&&(e.__proto__=t),e.prototype=Object.create(t&&t.prototype),e.prototype.constructor=e;var r={statusCode:{configurable:!0},name:{configurable:!0}};return r.statusCode.get=function(){return 401},r.name.get=function(){return"JsonqlContractAuthError"},Object.defineProperties(e,r),e}(Error),En=function(t){function e(){for(var r=[],n=arguments.length;n--;)r[n]=arguments[n];t.apply(this,r),this.message=r[0],this.detail=r[1],this.className=e.name,t.captureStackTrace&&t.captureStackTrace(this,e)}t&&(e.__proto__=t),e.prototype=Object.create(t&&t.prototype),e.prototype.constructor=e;var r={statusCode:{configurable:!0},name:{configurable:!0}};return r.statusCode.get=function(){return 500},r.name.get=function(){return"JsonqlResolverAppError"},Object.defineProperties(e,r),e}(Error),kn=function(t){function e(){for(var r=[],n=arguments.length;n--;)r[n]=arguments[n];t.apply(this,r),this.message=r[0],this.detail=r[1],this.className=e.name,t.captureStackTrace&&t.captureStackTrace(this,e)}t&&(e.__proto__=t),e.prototype=Object.create(t&&t.prototype),e.prototype.constructor=e;var r={statusCode:{configurable:!0},name:{configurable:!0}};return r.statusCode.get=function(){return 404},r.name.get=function(){return"JsonqlResolverNotFoundError"},Object.defineProperties(e,r),e}(Error),$n=function(t){function e(r,n){t.call(this,n),this.statusCode=r,this.className=e.name}t&&(e.__proto__=t),e.prototype=Object.create(t&&t.prototype),e.prototype.constructor=e;var r={name:{configurable:!0}};return r.name.get=function(){return"JsonqlServerError"},Object.defineProperties(e,r),e}(Error);function Tn(t){if(Array.isArray(t))throw new or("",t);var e=t.message||"No message",r=t.detail||t;switch(!0){case t instanceof mn:throw new mn(e,r);case t instanceof jn:throw new jn(e,r);case t instanceof wn:throw new wn(e,r);case t instanceof On:throw new On(e,r);case t instanceof Sn:throw new Sn(e,r);case t instanceof En:throw new En(e,r);case t instanceof kn:throw new kn(e,r);case t instanceof Gr:throw new Gr(e,r);case t instanceof Wr:throw new Wr(e,r);case t instanceof Br:throw new Br(e,r);case t instanceof or:throw new or(e,r);case t instanceof $n:throw new $n(e,r);default:throw new ir(e,r)}}function An(t){var e=function(t){return!!hn(t,"socket")&&t.socket}(t);if(!1===e)throw new JsonqlError("groupByNamespace","socket not found in contract!");var r={nspGroup:{},publicNamespace:null,size:0};for(var n in e){var o=e[n],i=o.namespace;i&&(r.nspGroup[i]||(++r.size,r.nspGroup[i]={}),r.nspGroup[i][n]=o,!r.publicNamespace&&o.public&&(r.publicNamespace=i))}return r}var Pn=function(t){var e=t.toLowerCase();return e.indexOf("http")>-1?e.indexOf("https")>-1?e.replace("https","wss"):e.replace("http","ws"):e},Nn=function(t,e){pn(e).forEach((function(e){t.$off(vn(e,"emit_reply"))}))},xn=function(t,e,r){return[bn(t,e.loginHandlerName,(function(t){if(t&&Qr(t))return e.log("Received __login__ with "+t),r.$trigger("__login__",[t]);throw new or(e.loginHandlerName,"Unexpected token "+t)})),e,r]},zn=function(t,e,r){return[bn(t,e.logoutHandlerName,(function(){for(var t=[],e=arguments.length;e--;)t[e]=arguments[e];r.$trigger("__logout__",t)})),e,r]},Rn=function(t,e,r){return[_n(t,"onLogin",(function(t){gn(t)&&r.$only("onLogin",t)})),e,r]};function Cn(t,e,r){return yn(xn,zn,Rn)(t,e,r)}function qn(t,e,r){hn(t,"error")?r(t.error):hn(t,"data")?e(t.data):r({message:"UKNNOWN RESULT!",error:t})}function Fn(t,e,r,n,o){void 0===n&&(n=[]);var i=vn(e,"emit_reply");return o("actionCall: "+i+" --\x3e "+r,n),t.$trigger(i,[r,pn(n)]),new Promise((function(n,i){var a=vn(e,r,"onResult");t.$on(a,(function(t){o("got the first result",t),qn(t,n,i)}))}))}var Ln,Mn,Jn,Un=function(t,e,r,n,o,i){return _n(t,"send",dn,(function(){return function(){for(var t=[],a=arguments.length;a--;)t[a]=arguments[a];return Xr(t,o.params,!0).then((function(t){return i(r,n,t),Fn(e,r,n,t,_log)})).catch((function(t){i("send error",t),e.$call(vn(r,n,"onError"),[new or(n,t)])}))}}))},Dn=function(t,e,r,n,o,i){return[bn(t,"myNamespace",r),e,r,n,o,i]},Hn=function(t,e,r,n,o,i){return[_n(t,"onResult",(function(t){gn(t)&&e.$on(vn(r,n,"onResult"),(function(o){qn(o,t,(function(t){i('Catch error: "'+n+'"',t),e.$trigger(vn(r,n,"onError"),t)}))}))})),e,r,n,o,i]},In=function(t,e,r,n,o,i){return[_n(t,"onMessage",(function(t){if(gn(t)){e.$only(vn(r,n,"onMessage"),(function(o){qn(o,t,(function(t){i('Catch error: "'+n+'"',t),e.$trigger(vn(r,n,"onError"),t)}))}))}})),e,r,n,o,i]},Gn=function(t,e,r,n,o,i){return[_n(t,"onError",(function(t){gn(t)&&e.$only(vn(r,n,"onError"),t)})),e,r,n,o,i]};function Wn(t,e,r,n,o,i){var a=[Dn,Hn,In,Gn,Un],u=Reflect.apply(yn,null,a),c=[n,o,t,e,r,i];return Reflect.apply(u,null,c)}function Bn(t,e,r,n,o){return function(){for(var i=[],a=arguments.length;a--;)i[a]=arguments[a];return Xr(i,n.params,!0).then((function(n){return Fn(t,e,r,n,o)})).catch(Tn)}}function Vn(t,e,r){var n={},o=t.log;for(var i in r){var a=r[i];for(var u in a){var c=a[u];n=bn(n,u,Wn(i,u,c,Bn(e,i,u,c,o),e,o))}}return[n,t,e,r]}function Yn(t,e,r,n){return[_n(t,"onError",(function(t){if(gn(t))for(var e in n)r.$on(vn(e,"onError"),t)})),e,r]}function Kn(t,e,r){return[_n(t,"onReady",(function(t){gn(t)&&r.$on("onReady",t)})),e,r]}function Qn(t,e,r){var n=function(t,e,r){return bn(t,e.disconnectHandlerName,(function(){for(var t=[],e=arguments.length;e--;)t[e]=arguments[e];r.$trigger("__disconnect__",t)}))}(t,e,r);return e.log("---\x3e The final step to return the ws-client <---"),n.verifyEventEmitter=function(){return r.is},n.eventEmitter=e.eventEmitter,n.log=e.log,n}var Xn=["roundtip","handshake"],Zn={standalone:Zr(!1,["boolean"]),debugOn:Zr(!1,["boolean"]),loginHandlerName:Zr("login",["string"]),logoutHandlerName:Zr("logout",["string"]),disconnectHandlerName:Zr("disconnect",["string"]),switchUserHandlerName:Zr("switch-user",["string"]),loginMethod:Zr("handshake",["string"],(Ln={},Ln.enumv=Xn,Ln)),useJwt:Zr(!0,["boolean","string"]),authStrKey:Zr(null,["string"]),hostname:Zr(!1,["string"]),namespace:Zr("jsonql",["string"]),wsOptions:Zr({},["object"]),contract:Zr({},["object"],(Mn={},Mn.checker=function(t){return!!function(t){return nt(t)&&(hn(t,"query")||hn(t,"mutation")||hn(t,"socket"))}(t)&&t},Mn)),enableAuth:Zr(!1,["boolean"]),token:Zr(!1,["string"])},to={};to.serverType=Zr(null,["string"],((Jn={}).alias="socketClientType",Jn));var eo=Object.assign(Zn,to),ro={log:null,eventEmitter:null,nspClient:null,nspAuthClient:null,wssPath:""};function no(t){return Promise.resolve(t).then((function(t){return t.hostname||(t.hostname=function(){try{return[window.location.protocol,window.location.host].join("//")}catch(t){throw new or(t)}}()),t.wssPath=Pn([t.hostname,t.namespace].join("/"),t.serverType),t.log=rn(t),t.eventEmitter=function(t){var e=t.log,r=t.eventEmitter;return r?(e("eventEmitter is:",r.name),r):new ln(t.log)}(t),t}))}function oo(t){return{opts:t,nspMap:(e=t,r=e.contract,n=e.enableAuth,o=function(t){var e="jsonql";return t.enableAuth?[[e,t.publicNamespace].join("/"),[e,t.privateNamespace].join("/")]:[e]}(e),i=n?An(r):function(t,e){var r,n={};for(var o in t){var i=t[o];n[o]=i}return{size:1,nspGroup:(r={},r[e]=n,r),publicNamespace:e}}(r.socket,o[0]),Object.assign(i,{namespaces:o})),ee:t.eventEmitter};var e,r,n,o,i}function io(t,e){return no(e).then(oo).then((function(e){var r=e.opts,n=e.nspMap,o=e.ee;return t(r,n,o)})).then((function(t){return function(t,e,r){var n=[Vn,Yn,Kn];return t.enableAuth&&n.push(Cn),n.push(Qn),Reflect.apply(yn,null,n)(t,r,e.nspGroup)}(t.opts,t.nspMap,t.ee)})).catch((function(t){console.error("jsonql-ws-core-client init error",t)}))}function ao(t,e,r){return void 0===e&&(e={}),void 0===r&&(r={}),function(n){return void 0===n&&(n={}),function(t,e,r){var n=Object.assign(ro,r),o=Object.assign(eo,e);return tn(t,o,n)}(n,e,r).then((function(e){return io(t,e)}))}}function uo(t,e){var r=e.hostname,n=e.wssPath,o=e.wsOptions;return(0,e.nspClient)(t?[r,t].join("/"):n,o)}function co(t,e,r){e.forEach((function(e){t.$trigger(vn(e,"onError"),[{message:r,namespace:e}])}))}var so=function(t,e,r){var n=r.log;e.$only(vn(t,"emit_reply"),(function(r,o){n("[notLoginHandler] hijack the ws call",t,r,o);var i={message:"NOT LOGIN"};e.$call(vn(t,r,"onError"),[i]),e.$call(vn(t,r,"onResult"),[{error:i}])}))},fo=function(t){return t.length>1&&t[0]},lo=function(t,e,r,n){var o=n.log;r.$on("__disconnect__",(function(){co(r,e,"__disconnect__"),e.forEach((function(e){o("disconnect from "+e),Nn(r,e),t[e]=null,function(t,e,r){var n=r.log;e.$only(vn(t,"emit_reply"),(function(r,o){n("[disconnectedHandler] hijack the ws call",t,r,o);var i={message:"You have disconnected from the socket server, please reconnect."};e.$call(vn(t,r,"onError"),[i]),e.$call(vn(t,r,"onResult"),[{error:i}])}))}(e,r,n)}))}))};function po(t,e,r,n,o,i){var a=fo(o),u=!1,c=!1,s=t.log;o.forEach((function(o){if(u=a===o,c||(c=u),i[o]){s("[call bindWsHandler]",u,o);var f=[o,i[o],r,u,t];if("socket.io"===t.serverType){var l=e.nspSet;f.push(l[o])}Reflect.apply(n,null,f)}else so(o,r,t)})),c&&(s("Has private and add logoutEvtHandler"),function(t,e,r,n){var o=n.log;r.$on("__logout__",(function(){var i=fo(e);o("__logout__ event triggered"),co(r,[i],"__logout__"),o("logout from "+i),Nn(r,i),t[i]=null,so(i,r,n)}))}(i,o,r,t)),lo(i,o,r,t)}var ho={version:"version: 1.1.1 module: cjs",serverType:"ws"},vo=Object.assign({},eo,{}),go=Object.assign({},ro,ho);function yo(t,e){return void 0===e&&(e=!1),!1===e?function(e){return new t(Pn(e))}:function(e,r){var n=Pn(e),o=r&&"string"==typeof r?n+"?token="+r:n;try{return new t(o)}catch(t){return console.error("WebSocket Connection Error",t),!1}}}var _o=Array.isArray,bo="object"==typeof r&&r&&r.Object===Object&&r,mo="object"==typeof self&&self&&self.Object===Object&&self,jo=(bo||mo||Function("return this")()).Symbol,wo=Object.prototype,Oo=wo.hasOwnProperty,So=wo.toString,Eo=jo?jo.toStringTag:void 0;var ko=Object.prototype.toString;var $o=jo?jo.toStringTag:void 0;function To(t){return null==t?void 0===t?"[object Undefined]":"[object Null]":$o&&$o in Object(t)?function(t){var e=Oo.call(t,Eo),r=t[Eo];try{t[Eo]=void 0;var n=!0}catch(t){}var o=So.call(t);return n&&(e?t[Eo]=r:delete t[Eo]),o}(t):function(t){return ko.call(t)}(t)}function Ao(t){return null!=t&&"object"==typeof t}var Po=jo?jo.prototype:void 0,No=Po?Po.toString:void 0;function xo(t){if("string"==typeof t)return t;if(_o(t))return function(t,e){for(var r=-1,n=null==t?0:t.length,o=Array(n);++r=n?t:function(t,e,r){var n=-1,o=t.length;e<0&&(e=-e>o?0:o+e),(r=r>o?o:r)<0&&(r+=o),o=e>r?0:r-e>>>0,e>>>=0;for(var i=Array(o);++n-1;);return r}(o,i),function(t,e){for(var r=t.length;r--&&Co(e,t[r],0)>-1;);return r}(o,i)+1).join("")}var Ko=function(){for(var t=[],e=arguments.length;e--;)t[e]=arguments[e];return t.join("_")},Qo=function(t){function e(){for(var r=[],n=arguments.length;n--;)r[n]=arguments[n];t.apply(this,r),this.message=r[0],this.detail=r[1],this.className=e.name,t.captureStackTrace&&t.captureStackTrace(this,e)}t&&(e.__proto__=t),e.prototype=Object.create(t&&t.prototype),e.prototype.constructor=e;var r={name:{configurable:!0}};return r.name.get=function(){return"JsonqlValidationError"},Object.defineProperties(e,r),e}(Error),Xo=function(t){function e(){for(var r=[],n=arguments.length;n--;)r[n]=arguments[n];t.apply(this,r),this.message=r[0],this.detail=r[1],this.className=e.name,t.captureStackTrace&&t.captureStackTrace(this,e)}t&&(e.__proto__=t),e.prototype=Object.create(t&&t.prototype),e.prototype.constructor=e;var r={name:{configurable:!0},statusCode:{configurable:!0}};return r.name.get=function(){return"JsonqlError"},r.statusCode.get=function(){return-1},Object.defineProperties(e,r),e}(Error),Zo=function(t){void 0===t&&(t=!1);var e=Date.now();return t?Math.floor(e/1e3):e};function ti(t){return"string"==typeof t||!_o(t)&&Ao(t)&&"[object String]"==To(t)}function ei(t,e,r){if(void 0===e&&(e=[]),void 0===r&&(r=!1),ti(t)&&_o(e)){var n=function(t){var e;return(e={}).args=t,e}(e);return!0===r?n:function(t,e){var r;return(r={})[t]=e,r.TS=[Zo()],r}(t,n)}throw new Qo("[createQuery] expect resolverName to be string and args to be array!",{resolverName:t,args:e})}var ri=function(t){return""!==Yo(t)&&ti(t)},ni=["__reply__","__event__","__data__"],oi=function(t){var e=t.data;return!!e&&(ni.filter((function(t){return function(t,e){try{var r=Object.keys(t);return n=e,!!r.filter((function(t){return t===n})).length}catch(t){return!1}var n}(e,t)})).length===ni.length&&e)},ii=function(t,e,r,n,o){var i=[e];r&&i.push(r),i.push(o);var a=Reflect.apply(Ko,null,i),u=n.data||n;t.$trigger(a,[u])};function ai(t,e,r,n,o){var i=o.log;i("log test, isPrivate:",n),e.onopen=function(){i("ws.onopen listened"),r.$call("onReady",t),n&&(i("isPrivate and fire the onLogin"),r.$call("onLogin",t)),r.$only(Ko(t,"emit_reply"),(function(t,r){var n=function(t,e,r){return void 0===e&&(e=[]),void 0===r&&(r=!1),JSON.stringify(ei(t,e,r))}(t,r);i("calling server",t,r,n),e.send(n)}))},e.onmessage=function(e){try{var n=function(t){var e,r=t.data,n=ri(r)?JSON.parse(r):r;if(!1!==(e=oi(n)))return{resolverName:e.__event__,data:e.__data__,type:e.__reply__};throw new Xo("payload can not be decoded",t)}(e),o=n.resolverName,a=n.type;switch(i("Hear from server",a,n),a){case"emit_reply":var u=Ko(t,o,"onMessage"),c=r.$trigger(u,[n]);i("EMIT_REPLY_TYPE",u,c);break;case"acknowledge_reply":var s=Ko(t,o,"onResult"),f=r.$trigger(s,[n]);i("ACKNOWLEDGE_REPLY_TYPE",s,f);break;case"error":i("ERROR_TYPE"),ii(r,t,o,n,"onError");break;default:i("Unhandled event!",n),ii(r,t,o,n,"onError")}}catch(e){console.error("ws.onmessage error",e),ii(r,t,!1,e,"onError")}},e.onclose=function(){i("ws.onclose callback")},e.onerror=function(e){i("ws.onerror",e),r.$trigger(Ko(t,"onError"),[e])},n&&r.$on("__logout__",(function(){try{i("terminate ws connection"),e.terminate()}catch(t){console.error("ws.terminate error",t)}}))}var ui=function(t,e,r){var n,o=t.log,i=e.nspGroup,a=e.publicNamespace,u=!1,c=[],s={};if(t.enableAuth)u=!0,s=(c=function(t,e){var r=[];for(var n in t)n===e?r[1]=n:r[0]=n;return r}(i,a)).map((function(e,n){var i,a,u;return 0===n?r?(t.token=r,o("create createNspAuthClient at run time"),(i={})[e]=function(t,e){var r=e.hostname,n=e.wssPath,o=e.token,i=e.wsOptions,a=e.nspAuthClient,u=t?[r,t].join("/"):n;if(o&&"string"!=typeof o)throw new Error("Expect token to be string, but got "+o);return a(u,o,i)}(e,t),i):((a={})[e]=!1,a):((u={})[e]=uo(e,t),u)})).reduce((function(t,e){return Object.assign(t,e)}),{});else{var f=(n=i,console.error("This method is going to be deprectead in the next release, please use getResolverFromPayload instead"),Object.keys(n)[0]);c.push(f),s[f]=uo(!1,t)}return{nsps:s,namespaces:c,loginRequired:u}};function ci(t,e,r,n){var o=n.log;t.$only("__login__",(function(i){o("createClient LOGIN_EVENT_NAME $only handler"),Nn(t,e);var a=ui(n,r,i);Reflect.apply(po,null,args.concat([a.namespaces,a.nsps]))}))}var si,fi,li,pi=(fi=yo(si=e),li=yo(si,!0),function(t,e,r){t.nspClient=fi,t.nspAuthClient=li;var n=t.log;return n&&"function"==typeof n&&(n("@jsonql/ws ee",r.name),n("@jsonql/ws createClientResolver",t)),function(t,e,r){var n=[t,e,r,ai],o=t.token,i=(t.log,ui(t,e,o)),a=i.nsps,u=i.namespaces,c=i.loginRequired;return Reflect.apply(po,null,n.concat([u,a])),c&&ci(r,u,e,t),{opts:t,nspMap:e,ee:r}}(t,e,r)});module.exports=function(t,e){return void 0===t&&(t={}),void 0===e&&(e={}),ao(pi,vo,Object.assign({},go,e))(t)}; +'use strict'; + +function _interopDefault (ex) { return (ex && (typeof ex === 'object') && 'default' in ex) ? ex['default'] : ex; } + +var WebSocket = _interopDefault(require('ws')); + +var global$1 = (typeof global !== "undefined" ? global : + typeof self !== "undefined" ? self : + typeof window !== "undefined" ? window : {}); + +/** Detect free variable `global` from Node.js. */ +var freeGlobal = typeof global$1 == 'object' && global$1 && global$1.Object === Object && global$1; + +/** Detect free variable `self`. */ +var freeSelf = typeof self == 'object' && self && self.Object === Object && self; + +/** Used as a reference to the global object. */ +var root = freeGlobal || freeSelf || Function('return this')(); + +/** Built-in value references. */ +var Symbol = root.Symbol; + +/** + * A specialized version of `_.map` for arrays without support for iteratee + * shorthands. + * + * @private + * @param {Array} [array] The array to iterate over. + * @param {Function} iteratee The function invoked per iteration. + * @returns {Array} Returns the new mapped array. + */ +function arrayMap(array, iteratee) { + var index = -1, + length = array == null ? 0 : array.length, + result = Array(length); + + while (++index < length) { + result[index] = iteratee(array[index], index, array); + } + return result; +} + +/** + * Checks if `value` is classified as an `Array` object. + * + * @static + * @memberOf _ + * @since 0.1.0 + * @category Lang + * @param {*} value The value to check. + * @returns {boolean} Returns `true` if `value` is an array, else `false`. + * @example + * + * _.isArray([1, 2, 3]); + * // => true + * + * _.isArray(document.body.children); + * // => false + * + * _.isArray('abc'); + * // => false + * + * _.isArray(_.noop); + * // => false + */ +var isArray = Array.isArray; + +/** Used for built-in method references. */ +var objectProto = Object.prototype; + +/** Used to check objects for own properties. */ +var hasOwnProperty = objectProto.hasOwnProperty; + +/** + * Used to resolve the + * [`toStringTag`](http://ecma-international.org/ecma-262/7.0/#sec-object.prototype.tostring) + * of values. + */ +var nativeObjectToString = objectProto.toString; + +/** Built-in value references. */ +var symToStringTag = Symbol ? Symbol.toStringTag : undefined; + +/** + * A specialized version of `baseGetTag` which ignores `Symbol.toStringTag` values. + * + * @private + * @param {*} value The value to query. + * @returns {string} Returns the raw `toStringTag`. + */ +function getRawTag(value) { + var isOwn = hasOwnProperty.call(value, symToStringTag), + tag = value[symToStringTag]; + + try { + value[symToStringTag] = undefined; + var unmasked = true; + } catch (e) {} + + var result = nativeObjectToString.call(value); + if (unmasked) { + if (isOwn) { + value[symToStringTag] = tag; + } else { + delete value[symToStringTag]; + } + } + return result; +} + +/** Used for built-in method references. */ +var objectProto$1 = Object.prototype; + +/** + * Used to resolve the + * [`toStringTag`](http://ecma-international.org/ecma-262/7.0/#sec-object.prototype.tostring) + * of values. + */ +var nativeObjectToString$1 = objectProto$1.toString; + +/** + * Converts `value` to a string using `Object.prototype.toString`. + * + * @private + * @param {*} value The value to convert. + * @returns {string} Returns the converted string. + */ +function objectToString(value) { + return nativeObjectToString$1.call(value); +} + +/** `Object#toString` result references. */ +var nullTag = '[object Null]', + undefinedTag = '[object Undefined]'; + +/** Built-in value references. */ +var symToStringTag$1 = Symbol ? Symbol.toStringTag : undefined; + +/** + * The base implementation of `getTag` without fallbacks for buggy environments. + * + * @private + * @param {*} value The value to query. + * @returns {string} Returns the `toStringTag`. + */ +function baseGetTag(value) { + if (value == null) { + return value === undefined ? undefinedTag : nullTag; + } + return (symToStringTag$1 && symToStringTag$1 in Object(value)) + ? getRawTag(value) + : objectToString(value); +} + +/** + * Checks if `value` is object-like. A value is object-like if it's not `null` + * and has a `typeof` result of "object". + * + * @static + * @memberOf _ + * @since 4.0.0 + * @category Lang + * @param {*} value The value to check. + * @returns {boolean} Returns `true` if `value` is object-like, else `false`. + * @example + * + * _.isObjectLike({}); + * // => true + * + * _.isObjectLike([1, 2, 3]); + * // => true + * + * _.isObjectLike(_.noop); + * // => false + * + * _.isObjectLike(null); + * // => false + */ +function isObjectLike(value) { + return value != null && typeof value == 'object'; +} + +/** `Object#toString` result references. */ +var symbolTag = '[object Symbol]'; + +/** + * Checks if `value` is classified as a `Symbol` primitive or object. + * + * @static + * @memberOf _ + * @since 4.0.0 + * @category Lang + * @param {*} value The value to check. + * @returns {boolean} Returns `true` if `value` is a symbol, else `false`. + * @example + * + * _.isSymbol(Symbol.iterator); + * // => true + * + * _.isSymbol('abc'); + * // => false + */ +function isSymbol(value) { + return typeof value == 'symbol' || + (isObjectLike(value) && baseGetTag(value) == symbolTag); +} + +/** Used as references for various `Number` constants. */ +var INFINITY = 1 / 0; + +/** Used to convert symbols to primitives and strings. */ +var symbolProto = Symbol ? Symbol.prototype : undefined, + symbolToString = symbolProto ? symbolProto.toString : undefined; + +/** + * The base implementation of `_.toString` which doesn't convert nullish + * values to empty strings. + * + * @private + * @param {*} value The value to process. + * @returns {string} Returns the string. + */ +function baseToString(value) { + // Exit early for strings to avoid a performance hit in some environments. + if (typeof value == 'string') { + return value; + } + if (isArray(value)) { + // Recursively convert values (susceptible to call stack limits). + return arrayMap(value, baseToString) + ''; + } + if (isSymbol(value)) { + return symbolToString ? symbolToString.call(value) : ''; + } + var result = (value + ''); + return (result == '0' && (1 / value) == -INFINITY) ? '-0' : result; +} + +/** + * The base implementation of `_.slice` without an iteratee call guard. + * + * @private + * @param {Array} array The array to slice. + * @param {number} [start=0] The start position. + * @param {number} [end=array.length] The end position. + * @returns {Array} Returns the slice of `array`. + */ +function baseSlice(array, start, end) { + var index = -1, + length = array.length; + + if (start < 0) { + start = -start > length ? 0 : (length + start); + } + end = end > length ? length : end; + if (end < 0) { + end += length; + } + length = start > end ? 0 : ((end - start) >>> 0); + start >>>= 0; + + var result = Array(length); + while (++index < length) { + result[index] = array[index + start]; + } + return result; +} + +/** + * Casts `array` to a slice if it's needed. + * + * @private + * @param {Array} array The array to inspect. + * @param {number} start The start position. + * @param {number} [end=array.length] The end position. + * @returns {Array} Returns the cast slice. + */ +function castSlice(array, start, end) { + var length = array.length; + end = end === undefined ? length : end; + return (!start && end >= length) ? array : baseSlice(array, start, end); +} + +/** + * The base implementation of `_.findIndex` and `_.findLastIndex` without + * support for iteratee shorthands. + * + * @private + * @param {Array} array The array to inspect. + * @param {Function} predicate The function invoked per iteration. + * @param {number} fromIndex The index to search from. + * @param {boolean} [fromRight] Specify iterating from right to left. + * @returns {number} Returns the index of the matched value, else `-1`. + */ +function baseFindIndex(array, predicate, fromIndex, fromRight) { + var length = array.length, + index = fromIndex + (fromRight ? 1 : -1); + + while ((fromRight ? index-- : ++index < length)) { + if (predicate(array[index], index, array)) { + return index; + } + } + return -1; +} + +/** + * The base implementation of `_.isNaN` without support for number objects. + * + * @private + * @param {*} value The value to check. + * @returns {boolean} Returns `true` if `value` is `NaN`, else `false`. + */ +function baseIsNaN(value) { + return value !== value; +} + +/** + * A specialized version of `_.indexOf` which performs strict equality + * comparisons of values, i.e. `===`. + * + * @private + * @param {Array} array The array to inspect. + * @param {*} value The value to search for. + * @param {number} fromIndex The index to search from. + * @returns {number} Returns the index of the matched value, else `-1`. + */ +function strictIndexOf(array, value, fromIndex) { + var index = fromIndex - 1, + length = array.length; + + while (++index < length) { + if (array[index] === value) { + return index; + } + } + return -1; +} + +/** + * The base implementation of `_.indexOf` without `fromIndex` bounds checks. + * + * @private + * @param {Array} array The array to inspect. + * @param {*} value The value to search for. + * @param {number} fromIndex The index to search from. + * @returns {number} Returns the index of the matched value, else `-1`. + */ +function baseIndexOf(array, value, fromIndex) { + return value === value + ? strictIndexOf(array, value, fromIndex) + : baseFindIndex(array, baseIsNaN, fromIndex); +} + +/** + * Used by `_.trim` and `_.trimEnd` to get the index of the last string symbol + * that is not found in the character symbols. + * + * @private + * @param {Array} strSymbols The string symbols to inspect. + * @param {Array} chrSymbols The character symbols to find. + * @returns {number} Returns the index of the last unmatched string symbol. + */ +function charsEndIndex(strSymbols, chrSymbols) { + var index = strSymbols.length; + + while (index-- && baseIndexOf(chrSymbols, strSymbols[index], 0) > -1) {} + return index; +} + +/** + * Used by `_.trim` and `_.trimStart` to get the index of the first string symbol + * that is not found in the character symbols. + * + * @private + * @param {Array} strSymbols The string symbols to inspect. + * @param {Array} chrSymbols The character symbols to find. + * @returns {number} Returns the index of the first unmatched string symbol. + */ +function charsStartIndex(strSymbols, chrSymbols) { + var index = -1, + length = strSymbols.length; + + while (++index < length && baseIndexOf(chrSymbols, strSymbols[index], 0) > -1) {} + return index; +} + +/** + * Converts an ASCII `string` to an array. + * + * @private + * @param {string} string The string to convert. + * @returns {Array} Returns the converted array. + */ +function asciiToArray(string) { + return string.split(''); +} + +/** Used to compose unicode character classes. */ +var rsAstralRange = '\\ud800-\\udfff', + rsComboMarksRange = '\\u0300-\\u036f', + reComboHalfMarksRange = '\\ufe20-\\ufe2f', + rsComboSymbolsRange = '\\u20d0-\\u20ff', + rsComboRange = rsComboMarksRange + reComboHalfMarksRange + rsComboSymbolsRange, + rsVarRange = '\\ufe0e\\ufe0f'; + +/** Used to compose unicode capture groups. */ +var rsZWJ = '\\u200d'; + +/** 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/). */ +var reHasUnicode = RegExp('[' + rsZWJ + rsAstralRange + rsComboRange + rsVarRange + ']'); + +/** + * Checks if `string` contains Unicode symbols. + * + * @private + * @param {string} string The string to inspect. + * @returns {boolean} Returns `true` if a symbol is found, else `false`. + */ +function hasUnicode(string) { + return reHasUnicode.test(string); +} + +/** Used to compose unicode character classes. */ +var rsAstralRange$1 = '\\ud800-\\udfff', + rsComboMarksRange$1 = '\\u0300-\\u036f', + reComboHalfMarksRange$1 = '\\ufe20-\\ufe2f', + rsComboSymbolsRange$1 = '\\u20d0-\\u20ff', + rsComboRange$1 = rsComboMarksRange$1 + reComboHalfMarksRange$1 + rsComboSymbolsRange$1, + rsVarRange$1 = '\\ufe0e\\ufe0f'; + +/** Used to compose unicode capture groups. */ +var rsAstral = '[' + rsAstralRange$1 + ']', + rsCombo = '[' + rsComboRange$1 + ']', + rsFitz = '\\ud83c[\\udffb-\\udfff]', + rsModifier = '(?:' + rsCombo + '|' + rsFitz + ')', + rsNonAstral = '[^' + rsAstralRange$1 + ']', + rsRegional = '(?:\\ud83c[\\udde6-\\uddff]){2}', + rsSurrPair = '[\\ud800-\\udbff][\\udc00-\\udfff]', + rsZWJ$1 = '\\u200d'; + +/** Used to compose unicode regexes. */ +var reOptMod = rsModifier + '?', + rsOptVar = '[' + rsVarRange$1 + ']?', + rsOptJoin = '(?:' + rsZWJ$1 + '(?:' + [rsNonAstral, rsRegional, rsSurrPair].join('|') + ')' + rsOptVar + reOptMod + ')*', + rsSeq = rsOptVar + reOptMod + rsOptJoin, + rsSymbol = '(?:' + [rsNonAstral + rsCombo + '?', rsCombo, rsRegional, rsSurrPair, rsAstral].join('|') + ')'; + +/** Used to match [string symbols](https://mathiasbynens.be/notes/javascript-unicode). */ +var reUnicode = RegExp(rsFitz + '(?=' + rsFitz + ')|' + rsSymbol + rsSeq, 'g'); + +/** + * Converts a Unicode `string` to an array. + * + * @private + * @param {string} string The string to convert. + * @returns {Array} Returns the converted array. + */ +function unicodeToArray(string) { + return string.match(reUnicode) || []; +} + +/** + * Converts `string` to an array. + * + * @private + * @param {string} string The string to convert. + * @returns {Array} Returns the converted array. + */ +function stringToArray(string) { + return hasUnicode(string) + ? unicodeToArray(string) + : asciiToArray(string); +} + +/** + * Converts `value` to a string. An empty string is returned for `null` + * and `undefined` values. The sign of `-0` is preserved. + * + * @static + * @memberOf _ + * @since 4.0.0 + * @category Lang + * @param {*} value The value to convert. + * @returns {string} Returns the converted string. + * @example + * + * _.toString(null); + * // => '' + * + * _.toString(-0); + * // => '-0' + * + * _.toString([1, 2, 3]); + * // => '1,2,3' + */ +function toString(value) { + return value == null ? '' : baseToString(value); +} + +/** Used to match leading and trailing whitespace. */ +var reTrim = /^\s+|\s+$/g; + +/** + * Removes leading and trailing whitespace or specified characters from `string`. + * + * @static + * @memberOf _ + * @since 3.0.0 + * @category String + * @param {string} [string=''] The string to trim. + * @param {string} [chars=whitespace] The characters to trim. + * @param- {Object} [guard] Enables use as an iteratee for methods like `_.map`. + * @returns {string} Returns the trimmed string. + * @example + * + * _.trim(' abc '); + * // => 'abc' + * + * _.trim('-_-abc-_-', '_-'); + * // => 'abc' + * + * _.map([' foo ', ' bar '], _.trim); + * // => ['foo', 'bar'] + */ +function trim(string, chars, guard) { + string = toString(string); + if (string && (guard || chars === undefined)) { + return string.replace(reTrim, ''); + } + if (!string || !(chars = baseToString(chars))) { + return string; + } + var strSymbols = stringToArray(string), + chrSymbols = stringToArray(chars), + start = charsStartIndex(strSymbols, chrSymbols), + end = charsEndIndex(strSymbols, chrSymbols) + 1; + + return castSlice(strSymbols, start, end).join(''); +} + +/** + * Check several parameter that there is something in the param + * @param {*} param input + * @return {boolean} + */ + var isNotEmpty = function (a) { + if (isArray(a)) { + return true; + } + return a !== undefined && a !== null && trim(a) !== '' +}; + +/** `Object#toString` result references. */ +var numberTag = '[object Number]'; + +/** + * Checks if `value` is classified as a `Number` primitive or object. + * + * **Note:** To exclude `Infinity`, `-Infinity`, and `NaN`, which are + * classified as numbers, use the `_.isFinite` method. + * + * @static + * @memberOf _ + * @since 0.1.0 + * @category Lang + * @param {*} value The value to check. + * @returns {boolean} Returns `true` if `value` is a number, else `false`. + * @example + * + * _.isNumber(3); + * // => true + * + * _.isNumber(Number.MIN_VALUE); + * // => true + * + * _.isNumber(Infinity); + * // => true + * + * _.isNumber('3'); + * // => false + */ +function isNumber(value) { + return typeof value == 'number' || + (isObjectLike(value) && baseGetTag(value) == numberTag); +} + +/** + * Checks if `value` is `NaN`. + * + * **Note:** This method is based on + * [`Number.isNaN`](https://mdn.io/Number/isNaN) and is not the same as + * global [`isNaN`](https://mdn.io/isNaN) which returns `true` for + * `undefined` and other non-number values. + * + * @static + * @memberOf _ + * @since 0.1.0 + * @category Lang + * @param {*} value The value to check. + * @returns {boolean} Returns `true` if `value` is `NaN`, else `false`. + * @example + * + * _.isNaN(NaN); + * // => true + * + * _.isNaN(new Number(NaN)); + * // => true + * + * isNaN(undefined); + * // => true + * + * _.isNaN(undefined); + * // => false + */ +function isNaN(value) { + // An `NaN` primitive is the only value that is not equal to itself. + // Perform the `toStringTag` check first to avoid errors with some + // ActiveX objects in IE. + return isNumber(value) && value != +value; +} + +/** `Object#toString` result references. */ +var stringTag = '[object String]'; + +/** + * Checks if `value` is classified as a `String` primitive or object. + * + * @static + * @since 0.1.0 + * @memberOf _ + * @category Lang + * @param {*} value The value to check. + * @returns {boolean} Returns `true` if `value` is a string, else `false`. + * @example + * + * _.isString('abc'); + * // => true + * + * _.isString(1); + * // => false + */ +function isString(value) { + return typeof value == 'string' || + (!isArray(value) && isObjectLike(value) && baseGetTag(value) == stringTag); +} + +// validator numbers +/** + * @2015-05-04 found a problem if the value is a number like string + * it will pass, so add a chck if it's string before we pass to next + * @param {number} value expected value + * @return {boolean} true if OK + */ +var checkIsNumber = function(value) { + return isString(value) ? false : !isNaN( parseFloat(value) ) +}; + +// validate string type +/** + * @param {string} value expected value + * @return {boolean} true if OK + */ +var checkIsString = function(value) { + return (trim(value) !== '') ? isString(value) : false +}; + +// check for boolean + +/** + * @param {boolean} value expected + * @return {boolean} true if OK + */ +var checkIsBoolean = function(value) { + return value !== null && value !== undefined && typeof value === 'boolean' +}; + +// validate any thing only check if there is something + +/** + * @param {*} value the value + * @param {boolean} [checkNull=true] strict check if there is null value + * @return {boolean} true is OK + */ +var checkIsAny = function(value, checkNull) { + if ( checkNull === void 0 ) checkNull = true; + + if (value !== undefined && value !== '' && trim(value) !== '') { + if (checkNull === false || (checkNull === true && value !== null)) { + return true; + } + } + return false; +}; + +// the core stuff to id if it's calling with jsonql +var DATA_KEY = 'data'; +var ERROR_KEY = 'error'; + +var JSONQL_PATH = 'jsonql'; + +// export const INDEX = 'index' use INDEX_KEY instead +var DEFAULT_TYPE = 'any'; + +// @TODO remove this is not in use +// export const CLIENT_CONFIG_FILE = '.clients.json' +// export const CONTRACT_CONFIG_FILE = 'jsonql-contract-config.js' +// type of resolvers +var QUERY_NAME = 'query'; +var MUTATION_NAME = 'mutation'; +var SOCKET_NAME = 'socket'; +// for contract-cli +var KEY_WORD = 'continue'; +var PUBLIC_KEY = 'public'; + +var TYPE_KEY = 'type'; +var OPTIONAL_KEY = 'optional'; +var ENUM_KEY = 'enumv'; // need to change this because enum is a reserved word +var ARGS_KEY = 'args'; +var CHECKER_KEY = 'checker'; +var ALIAS_KEY = 'alias'; +var LOGIN_NAME = 'login'; +// export const ISSUER_NAME = LOGIN_NAME // legacy issue need to replace them later +var LOGOUT_NAME = 'logout'; +var DISCONNECT_FN_NAME = 'disconnect'; +var SWITCH_USER_FN_NAME = 'switch-user'; + +var OR_SEPERATOR = '|'; +var STRING_TYPE = 'string'; +var BOOLEAN_TYPE = 'boolean'; +var ARRAY_TYPE = 'array'; +var OBJECT_TYPE = 'object'; + +var NUMBER_TYPE = 'number'; +var ARRAY_TYPE_LFT = 'array.<'; +var ARRAY_TYPE_RGT = '>'; + +var NO_ERROR_MSG = 'No message'; +var NO_STATUS_CODE = -1; +var LOGIN_EVENT_NAME = '__login__'; +var LOGOUT_EVENT_NAME = '__logout__'; +var DISCONNECT_EVENT_NAME = '__disconnect__'; +// this is somewhat vague about what is suppose to do +var EMIT_REPLY_TYPE = 'emit_reply'; + +var NSP_GROUP = 'nspGroup'; +var PUBLIC_NAMESPACE = 'publicNamespace'; + +var JS_WS_SOCKET_IO_NAME = 'socket.io'; +// type name and Alias +var SOCKET_TYPE_KEY = 'serverType'; //1.9.1 +var SOCKET_TYPE_CLIENT_ALIAS = 'socketClientType'; // 1.9.0 + +// for ws client, 1.9.3 breaking change to name them as FN instead of PROP +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'; +var NOT_LOGIN_ERR_MSG = 'NOT LOGIN'; +var IO_ROUNDTRIP_LOGIN = 'roundtip'; +var IO_HANDSHAKE_LOGIN = 'handshake'; + +// Good practice rule - No magic number + +var 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)"; +var PARAMS_NOT_ARRAY_ERR = "params is not an array! Did something gone wrong when you generate the contract.json?"; +var EXCEPTION_CASE_ERR = 'Could not understand your arguments and parameter structure!'; +// @TODO the jsdoc return array. and we should also allow array syntax +var DEFAULT_TYPE$1 = DEFAULT_TYPE; +var ARRAY_TYPE_LFT$1 = ARRAY_TYPE_LFT; +var ARRAY_TYPE_RGT$1 = ARRAY_TYPE_RGT; + +var TYPE_KEY$1 = TYPE_KEY; +var OPTIONAL_KEY$1 = OPTIONAL_KEY; +var ENUM_KEY$1 = ENUM_KEY; +var ARGS_KEY$1 = ARGS_KEY; +var CHECKER_KEY$1 = CHECKER_KEY; +var ALIAS_KEY$1 = ALIAS_KEY; + +var ARRAY_TYPE$1 = ARRAY_TYPE; +var OBJECT_TYPE$1 = OBJECT_TYPE; +var STRING_TYPE$1 = STRING_TYPE; +var BOOLEAN_TYPE$1 = BOOLEAN_TYPE; +var NUMBER_TYPE$1 = NUMBER_TYPE; +var KEY_WORD$1 = KEY_WORD; +var OR_SEPERATOR$1 = OR_SEPERATOR; + +// not actually in use +// export const NUMBER_TYPES = JSONQL_CONSTANTS.NUMBER_TYPES; + +// primitive types + +/** + * this is a wrapper method to call different one based on their type + * @param {string} type to check + * @return {function} a function to handle the type + */ +var combineFn = function(type) { + switch (type) { + case NUMBER_TYPE$1: + return checkIsNumber + case STRING_TYPE$1: + return checkIsString + case BOOLEAN_TYPE$1: + return checkIsBoolean + default: + return checkIsAny + } +}; + +// validate array type + +/** + * @param {array} value expected + * @param {string} [type=''] pass the type if we encounter array. then we need to check the value as well + * @return {boolean} true if OK + */ +var checkIsArray = function(value, type) { + if ( type === void 0 ) type=''; + + if (isArray(value)) { + if (type === '' || trim(type)==='') { + return true; + } + // we test it in reverse + // @TODO if the type is an array (OR) then what? + // we need to take into account this could be an array + var c = value.filter(function (v) { return !combineFn(type)(v); }); + return !(c.length > 0) + } + return false +}; + +/** + * check if it matches the array. pattern + * @param {string} type + * @return {boolean|array} false means NO, always return array + */ +var isArrayLike = function(type) { + // @TODO could that have something like array<> instead of array.<>? missing the dot? + // because type script is Array without the dot + if (type.indexOf(ARRAY_TYPE_LFT$1) > -1 && type.indexOf(ARRAY_TYPE_RGT$1) > -1) { + var _type = type.replace(ARRAY_TYPE_LFT$1, '').replace(ARRAY_TYPE_RGT$1, ''); + if (_type.indexOf(OR_SEPERATOR$1)) { + return _type.split(OR_SEPERATOR$1) + } + return [_type] + } + return false +}; + +/** + * we might encounter something like array. then we need to take it apart + * @param {object} p the prepared object for processing + * @param {string|array} type the type came from + * @return {boolean} for the filter to operate on + */ +var arrayTypeHandler = function(p, type) { + var arg = p.arg; + // need a special case to handle the OR type + // we need to test the args instead of the type(s) + if (type.length > 1) { + return !arg.filter(function (v) { return ( + !(type.length > type.filter(function (t) { return !combineFn(t)(v); }).length) + ); }).length + } + // type is array so this will be or! + return type.length > type.filter(function (t) { return !checkIsArray(arg, t); }).length +}; + +/** + * Creates a unary function that invokes `func` with its argument transformed. + * + * @private + * @param {Function} func The function to wrap. + * @param {Function} transform The argument transform. + * @returns {Function} Returns the new function. + */ +function overArg(func, transform) { + return function(arg) { + return func(transform(arg)); + }; +} + +/** Built-in value references. */ +var getPrototype = overArg(Object.getPrototypeOf, Object); + +/** `Object#toString` result references. */ +var objectTag = '[object Object]'; + +/** Used for built-in method references. */ +var funcProto = Function.prototype, + objectProto$2 = Object.prototype; + +/** Used to resolve the decompiled source of functions. */ +var funcToString = funcProto.toString; + +/** Used to check objects for own properties. */ +var hasOwnProperty$1 = objectProto$2.hasOwnProperty; + +/** Used to infer the `Object` constructor. */ +var objectCtorString = funcToString.call(Object); + +/** + * Checks if `value` is a plain object, that is, an object created by the + * `Object` constructor or one with a `[[Prototype]]` of `null`. + * + * @static + * @memberOf _ + * @since 0.8.0 + * @category Lang + * @param {*} value The value to check. + * @returns {boolean} Returns `true` if `value` is a plain object, else `false`. + * @example + * + * function Foo() { + * this.a = 1; + * } + * + * _.isPlainObject(new Foo); + * // => false + * + * _.isPlainObject([1, 2, 3]); + * // => false + * + * _.isPlainObject({ 'x': 0, 'y': 0 }); + * // => true + * + * _.isPlainObject(Object.create(null)); + * // => true + */ +function isPlainObject(value) { + if (!isObjectLike(value) || baseGetTag(value) != objectTag) { + return false; + } + var proto = getPrototype(value); + if (proto === null) { + return true; + } + var Ctor = hasOwnProperty$1.call(proto, 'constructor') && proto.constructor; + return typeof Ctor == 'function' && Ctor instanceof Ctor && + funcToString.call(Ctor) == objectCtorString; +} + +/** + * A specialized version of `_.filter` for arrays without support for + * iteratee shorthands. + * + * @private + * @param {Array} [array] The array to iterate over. + * @param {Function} predicate The function invoked per iteration. + * @returns {Array} Returns the new filtered array. + */ +function arrayFilter(array, predicate) { + var index = -1, + length = array == null ? 0 : array.length, + resIndex = 0, + result = []; + + while (++index < length) { + var value = array[index]; + if (predicate(value, index, array)) { + result[resIndex++] = value; + } + } + return result; +} + +/** + * Creates a base function for methods like `_.forIn` and `_.forOwn`. + * + * @private + * @param {boolean} [fromRight] Specify iterating from right to left. + * @returns {Function} Returns the new base function. + */ +function createBaseFor(fromRight) { + return function(object, iteratee, keysFunc) { + var index = -1, + iterable = Object(object), + props = keysFunc(object), + length = props.length; + + while (length--) { + var key = props[fromRight ? length : ++index]; + if (iteratee(iterable[key], key, iterable) === false) { + break; + } + } + return object; + }; +} + +/** + * The base implementation of `baseForOwn` which iterates over `object` + * properties returned by `keysFunc` and invokes `iteratee` for each property. + * Iteratee functions may exit iteration early by explicitly returning `false`. + * + * @private + * @param {Object} object The object to iterate over. + * @param {Function} iteratee The function invoked per iteration. + * @param {Function} keysFunc The function to get the keys of `object`. + * @returns {Object} Returns `object`. + */ +var baseFor = createBaseFor(); + +/** + * The base implementation of `_.times` without support for iteratee shorthands + * or max array length checks. + * + * @private + * @param {number} n The number of times to invoke `iteratee`. + * @param {Function} iteratee The function invoked per iteration. + * @returns {Array} Returns the array of results. + */ +function baseTimes(n, iteratee) { + var index = -1, + result = Array(n); + + while (++index < n) { + result[index] = iteratee(index); + } + return result; +} + +/** `Object#toString` result references. */ +var argsTag = '[object Arguments]'; + +/** + * The base implementation of `_.isArguments`. + * + * @private + * @param {*} value The value to check. + * @returns {boolean} Returns `true` if `value` is an `arguments` object, + */ +function baseIsArguments(value) { + return isObjectLike(value) && baseGetTag(value) == argsTag; +} + +/** Used for built-in method references. */ +var objectProto$3 = Object.prototype; + +/** Used to check objects for own properties. */ +var hasOwnProperty$2 = objectProto$3.hasOwnProperty; + +/** Built-in value references. */ +var propertyIsEnumerable = objectProto$3.propertyIsEnumerable; + +/** + * Checks if `value` is likely an `arguments` object. + * + * @static + * @memberOf _ + * @since 0.1.0 + * @category Lang + * @param {*} value The value to check. + * @returns {boolean} Returns `true` if `value` is an `arguments` object, + * else `false`. + * @example + * + * _.isArguments(function() { return arguments; }()); + * // => true + * + * _.isArguments([1, 2, 3]); + * // => false + */ +var isArguments = baseIsArguments(function() { return arguments; }()) ? baseIsArguments : function(value) { + return isObjectLike(value) && hasOwnProperty$2.call(value, 'callee') && + !propertyIsEnumerable.call(value, 'callee'); +}; + +/** + * This method returns `false`. + * + * @static + * @memberOf _ + * @since 4.13.0 + * @category Util + * @returns {boolean} Returns `false`. + * @example + * + * _.times(2, _.stubFalse); + * // => [false, false] + */ +function stubFalse() { + return false; +} + +/** Detect free variable `exports`. */ +var freeExports = typeof exports == 'object' && exports && !exports.nodeType && exports; + +/** Detect free variable `module`. */ +var freeModule = freeExports && typeof module == 'object' && module && !module.nodeType && module; + +/** Detect the popular CommonJS extension `module.exports`. */ +var moduleExports = freeModule && freeModule.exports === freeExports; + +/** Built-in value references. */ +var Buffer = moduleExports ? root.Buffer : undefined; + +/* Built-in method references for those with the same name as other `lodash` methods. */ +var nativeIsBuffer = Buffer ? Buffer.isBuffer : undefined; + +/** + * Checks if `value` is a buffer. + * + * @static + * @memberOf _ + * @since 4.3.0 + * @category Lang + * @param {*} value The value to check. + * @returns {boolean} Returns `true` if `value` is a buffer, else `false`. + * @example + * + * _.isBuffer(new Buffer(2)); + * // => true + * + * _.isBuffer(new Uint8Array(2)); + * // => false + */ +var isBuffer = nativeIsBuffer || stubFalse; + +/** Used as references for various `Number` constants. */ +var MAX_SAFE_INTEGER = 9007199254740991; + +/** Used to detect unsigned integer values. */ +var reIsUint = /^(?:0|[1-9]\d*)$/; + +/** + * Checks if `value` is a valid array-like index. + * + * @private + * @param {*} value The value to check. + * @param {number} [length=MAX_SAFE_INTEGER] The upper bounds of a valid index. + * @returns {boolean} Returns `true` if `value` is a valid index, else `false`. + */ +function isIndex(value, length) { + var type = typeof value; + length = length == null ? MAX_SAFE_INTEGER : length; + + return !!length && + (type == 'number' || + (type != 'symbol' && reIsUint.test(value))) && + (value > -1 && value % 1 == 0 && value < length); +} + +/** Used as references for various `Number` constants. */ +var MAX_SAFE_INTEGER$1 = 9007199254740991; + +/** + * Checks if `value` is a valid array-like length. + * + * **Note:** This method is loosely based on + * [`ToLength`](http://ecma-international.org/ecma-262/7.0/#sec-tolength). + * + * @static + * @memberOf _ + * @since 4.0.0 + * @category Lang + * @param {*} value The value to check. + * @returns {boolean} Returns `true` if `value` is a valid length, else `false`. + * @example + * + * _.isLength(3); + * // => true + * + * _.isLength(Number.MIN_VALUE); + * // => false + * + * _.isLength(Infinity); + * // => false + * + * _.isLength('3'); + * // => false + */ +function isLength(value) { + return typeof value == 'number' && + value > -1 && value % 1 == 0 && value <= MAX_SAFE_INTEGER$1; +} + +/** `Object#toString` result references. */ +var argsTag$1 = '[object Arguments]', + arrayTag = '[object Array]', + boolTag = '[object Boolean]', + dateTag = '[object Date]', + errorTag = '[object Error]', + funcTag = '[object Function]', + mapTag = '[object Map]', + numberTag$1 = '[object Number]', + objectTag$1 = '[object Object]', + regexpTag = '[object RegExp]', + setTag = '[object Set]', + stringTag$1 = '[object String]', + weakMapTag = '[object WeakMap]'; + +var arrayBufferTag = '[object ArrayBuffer]', + dataViewTag = '[object DataView]', + float32Tag = '[object Float32Array]', + float64Tag = '[object Float64Array]', + int8Tag = '[object Int8Array]', + int16Tag = '[object Int16Array]', + int32Tag = '[object Int32Array]', + uint8Tag = '[object Uint8Array]', + uint8ClampedTag = '[object Uint8ClampedArray]', + uint16Tag = '[object Uint16Array]', + uint32Tag = '[object Uint32Array]'; + +/** Used to identify `toStringTag` values of typed arrays. */ +var typedArrayTags = {}; +typedArrayTags[float32Tag] = typedArrayTags[float64Tag] = +typedArrayTags[int8Tag] = typedArrayTags[int16Tag] = +typedArrayTags[int32Tag] = typedArrayTags[uint8Tag] = +typedArrayTags[uint8ClampedTag] = typedArrayTags[uint16Tag] = +typedArrayTags[uint32Tag] = true; +typedArrayTags[argsTag$1] = typedArrayTags[arrayTag] = +typedArrayTags[arrayBufferTag] = typedArrayTags[boolTag] = +typedArrayTags[dataViewTag] = typedArrayTags[dateTag] = +typedArrayTags[errorTag] = typedArrayTags[funcTag] = +typedArrayTags[mapTag] = typedArrayTags[numberTag$1] = +typedArrayTags[objectTag$1] = typedArrayTags[regexpTag] = +typedArrayTags[setTag] = typedArrayTags[stringTag$1] = +typedArrayTags[weakMapTag] = false; + +/** + * The base implementation of `_.isTypedArray` without Node.js optimizations. + * + * @private + * @param {*} value The value to check. + * @returns {boolean} Returns `true` if `value` is a typed array, else `false`. + */ +function baseIsTypedArray(value) { + return isObjectLike(value) && + isLength(value.length) && !!typedArrayTags[baseGetTag(value)]; +} + +/** + * The base implementation of `_.unary` without support for storing metadata. + * + * @private + * @param {Function} func The function to cap arguments for. + * @returns {Function} Returns the new capped function. + */ +function baseUnary(func) { + return function(value) { + return func(value); + }; +} + +/** Detect free variable `exports`. */ +var freeExports$1 = typeof exports == 'object' && exports && !exports.nodeType && exports; + +/** Detect free variable `module`. */ +var freeModule$1 = freeExports$1 && typeof module == 'object' && module && !module.nodeType && module; + +/** Detect the popular CommonJS extension `module.exports`. */ +var moduleExports$1 = freeModule$1 && freeModule$1.exports === freeExports$1; + +/** Detect free variable `process` from Node.js. */ +var freeProcess = moduleExports$1 && freeGlobal.process; + +/** Used to access faster Node.js helpers. */ +var nodeUtil = (function() { + try { + // Use `util.types` for Node.js 10+. + var types = freeModule$1 && freeModule$1.require && freeModule$1.require('util').types; + + if (types) { + return types; + } + + // Legacy `process.binding('util')` for Node.js < 10. + return freeProcess && freeProcess.binding && freeProcess.binding('util'); + } catch (e) {} +}()); + +/* Node.js helper references. */ +var nodeIsTypedArray = nodeUtil && nodeUtil.isTypedArray; + +/** + * Checks if `value` is classified as a typed array. + * + * @static + * @memberOf _ + * @since 3.0.0 + * @category Lang + * @param {*} value The value to check. + * @returns {boolean} Returns `true` if `value` is a typed array, else `false`. + * @example + * + * _.isTypedArray(new Uint8Array); + * // => true + * + * _.isTypedArray([]); + * // => false + */ +var isTypedArray = nodeIsTypedArray ? baseUnary(nodeIsTypedArray) : baseIsTypedArray; + +/** Used for built-in method references. */ +var objectProto$4 = Object.prototype; + +/** Used to check objects for own properties. */ +var hasOwnProperty$3 = objectProto$4.hasOwnProperty; + +/** + * Creates an array of the enumerable property names of the array-like `value`. + * + * @private + * @param {*} value The value to query. + * @param {boolean} inherited Specify returning inherited property names. + * @returns {Array} Returns the array of property names. + */ +function arrayLikeKeys(value, inherited) { + var isArr = isArray(value), + isArg = !isArr && isArguments(value), + isBuff = !isArr && !isArg && isBuffer(value), + isType = !isArr && !isArg && !isBuff && isTypedArray(value), + skipIndexes = isArr || isArg || isBuff || isType, + result = skipIndexes ? baseTimes(value.length, String) : [], + length = result.length; + + for (var key in value) { + if ((inherited || hasOwnProperty$3.call(value, key)) && + !(skipIndexes && ( + // Safari 9 has enumerable `arguments.length` in strict mode. + key == 'length' || + // Node.js 0.10 has enumerable non-index properties on buffers. + (isBuff && (key == 'offset' || key == 'parent')) || + // PhantomJS 2 has enumerable non-index properties on typed arrays. + (isType && (key == 'buffer' || key == 'byteLength' || key == 'byteOffset')) || + // Skip index properties. + isIndex(key, length) + ))) { + result.push(key); + } + } + return result; +} + +/** Used for built-in method references. */ +var objectProto$5 = Object.prototype; + +/** + * Checks if `value` is likely a prototype object. + * + * @private + * @param {*} value The value to check. + * @returns {boolean} Returns `true` if `value` is a prototype, else `false`. + */ +function isPrototype(value) { + var Ctor = value && value.constructor, + proto = (typeof Ctor == 'function' && Ctor.prototype) || objectProto$5; + + return value === proto; +} + +/* Built-in method references for those with the same name as other `lodash` methods. */ +var nativeKeys = overArg(Object.keys, Object); + +/** Used for built-in method references. */ +var objectProto$6 = Object.prototype; + +/** Used to check objects for own properties. */ +var hasOwnProperty$4 = objectProto$6.hasOwnProperty; + +/** + * The base implementation of `_.keys` which doesn't treat sparse arrays as dense. + * + * @private + * @param {Object} object The object to query. + * @returns {Array} Returns the array of property names. + */ +function baseKeys(object) { + if (!isPrototype(object)) { + return nativeKeys(object); + } + var result = []; + for (var key in Object(object)) { + if (hasOwnProperty$4.call(object, key) && key != 'constructor') { + result.push(key); + } + } + return result; +} + +/** + * Checks if `value` is the + * [language type](http://www.ecma-international.org/ecma-262/7.0/#sec-ecmascript-language-types) + * of `Object`. (e.g. arrays, functions, objects, regexes, `new Number(0)`, and `new String('')`) + * + * @static + * @memberOf _ + * @since 0.1.0 + * @category Lang + * @param {*} value The value to check. + * @returns {boolean} Returns `true` if `value` is an object, else `false`. + * @example + * + * _.isObject({}); + * // => true + * + * _.isObject([1, 2, 3]); + * // => true + * + * _.isObject(_.noop); + * // => true + * + * _.isObject(null); + * // => false + */ +function isObject(value) { + var type = typeof value; + return value != null && (type == 'object' || type == 'function'); +} + +/** `Object#toString` result references. */ +var asyncTag = '[object AsyncFunction]', + funcTag$1 = '[object Function]', + genTag = '[object GeneratorFunction]', + proxyTag = '[object Proxy]'; + +/** + * Checks if `value` is classified as a `Function` object. + * + * @static + * @memberOf _ + * @since 0.1.0 + * @category Lang + * @param {*} value The value to check. + * @returns {boolean} Returns `true` if `value` is a function, else `false`. + * @example + * + * _.isFunction(_); + * // => true + * + * _.isFunction(/abc/); + * // => false + */ +function isFunction(value) { + if (!isObject(value)) { + return false; + } + // The use of `Object#toString` avoids issues with the `typeof` operator + // in Safari 9 which returns 'object' for typed arrays and other constructors. + var tag = baseGetTag(value); + return tag == funcTag$1 || tag == genTag || tag == asyncTag || tag == proxyTag; +} + +/** + * Checks if `value` is array-like. A value is considered array-like if it's + * not a function and has a `value.length` that's an integer greater than or + * equal to `0` and less than or equal to `Number.MAX_SAFE_INTEGER`. + * + * @static + * @memberOf _ + * @since 4.0.0 + * @category Lang + * @param {*} value The value to check. + * @returns {boolean} Returns `true` if `value` is array-like, else `false`. + * @example + * + * _.isArrayLike([1, 2, 3]); + * // => true + * + * _.isArrayLike(document.body.children); + * // => true + * + * _.isArrayLike('abc'); + * // => true + * + * _.isArrayLike(_.noop); + * // => false + */ +function isArrayLike$1(value) { + return value != null && isLength(value.length) && !isFunction(value); +} + +/** + * Creates an array of the own enumerable property names of `object`. + * + * **Note:** Non-object values are coerced to objects. See the + * [ES spec](http://ecma-international.org/ecma-262/7.0/#sec-object.keys) + * for more details. + * + * @static + * @since 0.1.0 + * @memberOf _ + * @category Object + * @param {Object} object The object to query. + * @returns {Array} Returns the array of property names. + * @example + * + * function Foo() { + * this.a = 1; + * this.b = 2; + * } + * + * Foo.prototype.c = 3; + * + * _.keys(new Foo); + * // => ['a', 'b'] (iteration order is not guaranteed) + * + * _.keys('hi'); + * // => ['0', '1'] + */ +function keys(object) { + return isArrayLike$1(object) ? arrayLikeKeys(object) : baseKeys(object); +} + +/** + * The base implementation of `_.forOwn` without support for iteratee shorthands. + * + * @private + * @param {Object} object The object to iterate over. + * @param {Function} iteratee The function invoked per iteration. + * @returns {Object} Returns `object`. + */ +function baseForOwn(object, iteratee) { + return object && baseFor(object, iteratee, keys); +} + +/** + * Removes all key-value entries from the list cache. + * + * @private + * @name clear + * @memberOf ListCache + */ +function listCacheClear() { + this.__data__ = []; + this.size = 0; +} + +/** + * Performs a + * [`SameValueZero`](http://ecma-international.org/ecma-262/7.0/#sec-samevaluezero) + * comparison between two values to determine if they are equivalent. + * + * @static + * @memberOf _ + * @since 4.0.0 + * @category Lang + * @param {*} value The value to compare. + * @param {*} other The other value to compare. + * @returns {boolean} Returns `true` if the values are equivalent, else `false`. + * @example + * + * var object = { 'a': 1 }; + * var other = { 'a': 1 }; + * + * _.eq(object, object); + * // => true + * + * _.eq(object, other); + * // => false + * + * _.eq('a', 'a'); + * // => true + * + * _.eq('a', Object('a')); + * // => false + * + * _.eq(NaN, NaN); + * // => true + */ +function eq(value, other) { + return value === other || (value !== value && other !== other); +} + +/** + * Gets the index at which the `key` is found in `array` of key-value pairs. + * + * @private + * @param {Array} array The array to inspect. + * @param {*} key The key to search for. + * @returns {number} Returns the index of the matched value, else `-1`. + */ +function assocIndexOf(array, key) { + var length = array.length; + while (length--) { + if (eq(array[length][0], key)) { + return length; + } + } + return -1; +} + +/** Used for built-in method references. */ +var arrayProto = Array.prototype; + +/** Built-in value references. */ +var splice = arrayProto.splice; + +/** + * Removes `key` and its value from the list cache. + * + * @private + * @name delete + * @memberOf ListCache + * @param {string} key The key of the value to remove. + * @returns {boolean} Returns `true` if the entry was removed, else `false`. + */ +function listCacheDelete(key) { + var data = this.__data__, + index = assocIndexOf(data, key); + + if (index < 0) { + return false; + } + var lastIndex = data.length - 1; + if (index == lastIndex) { + data.pop(); + } else { + splice.call(data, index, 1); + } + --this.size; + return true; +} + +/** + * Gets the list cache value for `key`. + * + * @private + * @name get + * @memberOf ListCache + * @param {string} key The key of the value to get. + * @returns {*} Returns the entry value. + */ +function listCacheGet(key) { + var data = this.__data__, + index = assocIndexOf(data, key); + + return index < 0 ? undefined : data[index][1]; +} + +/** + * Checks if a list cache value for `key` exists. + * + * @private + * @name has + * @memberOf ListCache + * @param {string} key The key of the entry to check. + * @returns {boolean} Returns `true` if an entry for `key` exists, else `false`. + */ +function listCacheHas(key) { + return assocIndexOf(this.__data__, key) > -1; +} + +/** + * Sets the list cache `key` to `value`. + * + * @private + * @name set + * @memberOf ListCache + * @param {string} key The key of the value to set. + * @param {*} value The value to set. + * @returns {Object} Returns the list cache instance. + */ +function listCacheSet(key, value) { + var data = this.__data__, + index = assocIndexOf(data, key); + + if (index < 0) { + ++this.size; + data.push([key, value]); + } else { + data[index][1] = value; + } + return this; +} + +/** + * Creates an list cache object. + * + * @private + * @constructor + * @param {Array} [entries] The key-value pairs to cache. + */ +function ListCache(entries) { + var index = -1, + length = entries == null ? 0 : entries.length; + + this.clear(); + while (++index < length) { + var entry = entries[index]; + this.set(entry[0], entry[1]); + } +} + +// Add methods to `ListCache`. +ListCache.prototype.clear = listCacheClear; +ListCache.prototype['delete'] = listCacheDelete; +ListCache.prototype.get = listCacheGet; +ListCache.prototype.has = listCacheHas; +ListCache.prototype.set = listCacheSet; + +/** + * Removes all key-value entries from the stack. + * + * @private + * @name clear + * @memberOf Stack + */ +function stackClear() { + this.__data__ = new ListCache; + this.size = 0; +} + +/** + * Removes `key` and its value from the stack. + * + * @private + * @name delete + * @memberOf Stack + * @param {string} key The key of the value to remove. + * @returns {boolean} Returns `true` if the entry was removed, else `false`. + */ +function stackDelete(key) { + var data = this.__data__, + result = data['delete'](key); + + this.size = data.size; + return result; +} + +/** + * Gets the stack value for `key`. + * + * @private + * @name get + * @memberOf Stack + * @param {string} key The key of the value to get. + * @returns {*} Returns the entry value. + */ +function stackGet(key) { + return this.__data__.get(key); +} + +/** + * Checks if a stack value for `key` exists. + * + * @private + * @name has + * @memberOf Stack + * @param {string} key The key of the entry to check. + * @returns {boolean} Returns `true` if an entry for `key` exists, else `false`. + */ +function stackHas(key) { + return this.__data__.has(key); +} + +/** Used to detect overreaching core-js shims. */ +var coreJsData = root['__core-js_shared__']; + +/** Used to detect methods masquerading as native. */ +var maskSrcKey = (function() { + var uid = /[^.]+$/.exec(coreJsData && coreJsData.keys && coreJsData.keys.IE_PROTO || ''); + return uid ? ('Symbol(src)_1.' + uid) : ''; +}()); + +/** + * Checks if `func` has its source masked. + * + * @private + * @param {Function} func The function to check. + * @returns {boolean} Returns `true` if `func` is masked, else `false`. + */ +function isMasked(func) { + return !!maskSrcKey && (maskSrcKey in func); +} + +/** Used for built-in method references. */ +var funcProto$1 = Function.prototype; + +/** Used to resolve the decompiled source of functions. */ +var funcToString$1 = funcProto$1.toString; + +/** + * Converts `func` to its source code. + * + * @private + * @param {Function} func The function to convert. + * @returns {string} Returns the source code. + */ +function toSource(func) { + if (func != null) { + try { + return funcToString$1.call(func); + } catch (e) {} + try { + return (func + ''); + } catch (e) {} + } + return ''; +} + +/** + * Used to match `RegExp` + * [syntax characters](http://ecma-international.org/ecma-262/7.0/#sec-patterns). + */ +var reRegExpChar = /[\\^$.*+?()[\]{}|]/g; + +/** Used to detect host constructors (Safari). */ +var reIsHostCtor = /^\[object .+?Constructor\]$/; + +/** Used for built-in method references. */ +var funcProto$2 = Function.prototype, + objectProto$7 = Object.prototype; + +/** Used to resolve the decompiled source of functions. */ +var funcToString$2 = funcProto$2.toString; + +/** Used to check objects for own properties. */ +var hasOwnProperty$5 = objectProto$7.hasOwnProperty; + +/** Used to detect if a method is native. */ +var reIsNative = RegExp('^' + + funcToString$2.call(hasOwnProperty$5).replace(reRegExpChar, '\\$&') + .replace(/hasOwnProperty|(function).*?(?=\\\()| for .+?(?=\\\])/g, '$1.*?') + '$' +); + +/** + * The base implementation of `_.isNative` without bad shim checks. + * + * @private + * @param {*} value The value to check. + * @returns {boolean} Returns `true` if `value` is a native function, + * else `false`. + */ +function baseIsNative(value) { + if (!isObject(value) || isMasked(value)) { + return false; + } + var pattern = isFunction(value) ? reIsNative : reIsHostCtor; + return pattern.test(toSource(value)); +} + +/** + * Gets the value at `key` of `object`. + * + * @private + * @param {Object} [object] The object to query. + * @param {string} key The key of the property to get. + * @returns {*} Returns the property value. + */ +function getValue(object, key) { + return object == null ? undefined : object[key]; +} + +/** + * Gets the native function at `key` of `object`. + * + * @private + * @param {Object} object The object to query. + * @param {string} key The key of the method to get. + * @returns {*} Returns the function if it's native, else `undefined`. + */ +function getNative(object, key) { + var value = getValue(object, key); + return baseIsNative(value) ? value : undefined; +} + +/* Built-in method references that are verified to be native. */ +var Map$1 = getNative(root, 'Map'); + +/* Built-in method references that are verified to be native. */ +var nativeCreate = getNative(Object, 'create'); + +/** + * Removes all key-value entries from the hash. + * + * @private + * @name clear + * @memberOf Hash + */ +function hashClear() { + this.__data__ = nativeCreate ? nativeCreate(null) : {}; + this.size = 0; +} + +/** + * Removes `key` and its value from the hash. + * + * @private + * @name delete + * @memberOf Hash + * @param {Object} hash The hash to modify. + * @param {string} key The key of the value to remove. + * @returns {boolean} Returns `true` if the entry was removed, else `false`. + */ +function hashDelete(key) { + var result = this.has(key) && delete this.__data__[key]; + this.size -= result ? 1 : 0; + return result; +} + +/** Used to stand-in for `undefined` hash values. */ +var HASH_UNDEFINED = '__lodash_hash_undefined__'; + +/** Used for built-in method references. */ +var objectProto$8 = Object.prototype; + +/** Used to check objects for own properties. */ +var hasOwnProperty$6 = objectProto$8.hasOwnProperty; + +/** + * Gets the hash value for `key`. + * + * @private + * @name get + * @memberOf Hash + * @param {string} key The key of the value to get. + * @returns {*} Returns the entry value. + */ +function hashGet(key) { + var data = this.__data__; + if (nativeCreate) { + var result = data[key]; + return result === HASH_UNDEFINED ? undefined : result; + } + return hasOwnProperty$6.call(data, key) ? data[key] : undefined; +} + +/** Used for built-in method references. */ +var objectProto$9 = Object.prototype; + +/** Used to check objects for own properties. */ +var hasOwnProperty$7 = objectProto$9.hasOwnProperty; + +/** + * Checks if a hash value for `key` exists. + * + * @private + * @name has + * @memberOf Hash + * @param {string} key The key of the entry to check. + * @returns {boolean} Returns `true` if an entry for `key` exists, else `false`. + */ +function hashHas(key) { + var data = this.__data__; + return nativeCreate ? (data[key] !== undefined) : hasOwnProperty$7.call(data, key); +} + +/** Used to stand-in for `undefined` hash values. */ +var HASH_UNDEFINED$1 = '__lodash_hash_undefined__'; + +/** + * Sets the hash `key` to `value`. + * + * @private + * @name set + * @memberOf Hash + * @param {string} key The key of the value to set. + * @param {*} value The value to set. + * @returns {Object} Returns the hash instance. + */ +function hashSet(key, value) { + var data = this.__data__; + this.size += this.has(key) ? 0 : 1; + data[key] = (nativeCreate && value === undefined) ? HASH_UNDEFINED$1 : value; + return this; +} + +/** + * Creates a hash object. + * + * @private + * @constructor + * @param {Array} [entries] The key-value pairs to cache. + */ +function Hash(entries) { + var index = -1, + length = entries == null ? 0 : entries.length; + + this.clear(); + while (++index < length) { + var entry = entries[index]; + this.set(entry[0], entry[1]); + } +} + +// Add methods to `Hash`. +Hash.prototype.clear = hashClear; +Hash.prototype['delete'] = hashDelete; +Hash.prototype.get = hashGet; +Hash.prototype.has = hashHas; +Hash.prototype.set = hashSet; + +/** + * Removes all key-value entries from the map. + * + * @private + * @name clear + * @memberOf MapCache + */ +function mapCacheClear() { + this.size = 0; + this.__data__ = { + 'hash': new Hash, + 'map': new (Map$1 || ListCache), + 'string': new Hash + }; +} + +/** + * Checks if `value` is suitable for use as unique object key. + * + * @private + * @param {*} value The value to check. + * @returns {boolean} Returns `true` if `value` is suitable, else `false`. + */ +function isKeyable(value) { + var type = typeof value; + return (type == 'string' || type == 'number' || type == 'symbol' || type == 'boolean') + ? (value !== '__proto__') + : (value === null); +} + +/** + * Gets the data for `map`. + * + * @private + * @param {Object} map The map to query. + * @param {string} key The reference key. + * @returns {*} Returns the map data. + */ +function getMapData(map, key) { + var data = map.__data__; + return isKeyable(key) + ? data[typeof key == 'string' ? 'string' : 'hash'] + : data.map; +} + +/** + * Removes `key` and its value from the map. + * + * @private + * @name delete + * @memberOf MapCache + * @param {string} key The key of the value to remove. + * @returns {boolean} Returns `true` if the entry was removed, else `false`. + */ +function mapCacheDelete(key) { + var result = getMapData(this, key)['delete'](key); + this.size -= result ? 1 : 0; + return result; +} + +/** + * Gets the map value for `key`. + * + * @private + * @name get + * @memberOf MapCache + * @param {string} key The key of the value to get. + * @returns {*} Returns the entry value. + */ +function mapCacheGet(key) { + return getMapData(this, key).get(key); +} + +/** + * Checks if a map value for `key` exists. + * + * @private + * @name has + * @memberOf MapCache + * @param {string} key The key of the entry to check. + * @returns {boolean} Returns `true` if an entry for `key` exists, else `false`. + */ +function mapCacheHas(key) { + return getMapData(this, key).has(key); +} + +/** + * Sets the map `key` to `value`. + * + * @private + * @name set + * @memberOf MapCache + * @param {string} key The key of the value to set. + * @param {*} value The value to set. + * @returns {Object} Returns the map cache instance. + */ +function mapCacheSet(key, value) { + var data = getMapData(this, key), + size = data.size; + + data.set(key, value); + this.size += data.size == size ? 0 : 1; + return this; +} + +/** + * Creates a map cache object to store key-value pairs. + * + * @private + * @constructor + * @param {Array} [entries] The key-value pairs to cache. + */ +function MapCache(entries) { + var index = -1, + length = entries == null ? 0 : entries.length; + + this.clear(); + while (++index < length) { + var entry = entries[index]; + this.set(entry[0], entry[1]); + } +} + +// Add methods to `MapCache`. +MapCache.prototype.clear = mapCacheClear; +MapCache.prototype['delete'] = mapCacheDelete; +MapCache.prototype.get = mapCacheGet; +MapCache.prototype.has = mapCacheHas; +MapCache.prototype.set = mapCacheSet; + +/** Used as the size to enable large array optimizations. */ +var LARGE_ARRAY_SIZE = 200; + +/** + * Sets the stack `key` to `value`. + * + * @private + * @name set + * @memberOf Stack + * @param {string} key The key of the value to set. + * @param {*} value The value to set. + * @returns {Object} Returns the stack cache instance. + */ +function stackSet(key, value) { + var data = this.__data__; + if (data instanceof ListCache) { + var pairs = data.__data__; + if (!Map$1 || (pairs.length < LARGE_ARRAY_SIZE - 1)) { + pairs.push([key, value]); + this.size = ++data.size; + return this; + } + data = this.__data__ = new MapCache(pairs); + } + data.set(key, value); + this.size = data.size; + return this; +} + +/** + * Creates a stack cache object to store key-value pairs. + * + * @private + * @constructor + * @param {Array} [entries] The key-value pairs to cache. + */ +function Stack(entries) { + var data = this.__data__ = new ListCache(entries); + this.size = data.size; +} + +// Add methods to `Stack`. +Stack.prototype.clear = stackClear; +Stack.prototype['delete'] = stackDelete; +Stack.prototype.get = stackGet; +Stack.prototype.has = stackHas; +Stack.prototype.set = stackSet; + +/** Used to stand-in for `undefined` hash values. */ +var HASH_UNDEFINED$2 = '__lodash_hash_undefined__'; + +/** + * Adds `value` to the array cache. + * + * @private + * @name add + * @memberOf SetCache + * @alias push + * @param {*} value The value to cache. + * @returns {Object} Returns the cache instance. + */ +function setCacheAdd(value) { + this.__data__.set(value, HASH_UNDEFINED$2); + return this; +} + +/** + * Checks if `value` is in the array cache. + * + * @private + * @name has + * @memberOf SetCache + * @param {*} value The value to search for. + * @returns {number} Returns `true` if `value` is found, else `false`. + */ +function setCacheHas(value) { + return this.__data__.has(value); +} + +/** + * + * Creates an array cache object to store unique values. + * + * @private + * @constructor + * @param {Array} [values] The values to cache. + */ +function SetCache(values) { + var index = -1, + length = values == null ? 0 : values.length; + + this.__data__ = new MapCache; + while (++index < length) { + this.add(values[index]); + } +} + +// Add methods to `SetCache`. +SetCache.prototype.add = SetCache.prototype.push = setCacheAdd; +SetCache.prototype.has = setCacheHas; + +/** + * A specialized version of `_.some` for arrays without support for iteratee + * shorthands. + * + * @private + * @param {Array} [array] The array to iterate over. + * @param {Function} predicate The function invoked per iteration. + * @returns {boolean} Returns `true` if any element passes the predicate check, + * else `false`. + */ +function arraySome(array, predicate) { + var index = -1, + length = array == null ? 0 : array.length; + + while (++index < length) { + if (predicate(array[index], index, array)) { + return true; + } + } + return false; +} + +/** + * Checks if a `cache` value for `key` exists. + * + * @private + * @param {Object} cache The cache to query. + * @param {string} key The key of the entry to check. + * @returns {boolean} Returns `true` if an entry for `key` exists, else `false`. + */ +function cacheHas(cache, key) { + return cache.has(key); +} + +/** Used to compose bitmasks for value comparisons. */ +var COMPARE_PARTIAL_FLAG = 1, + COMPARE_UNORDERED_FLAG = 2; + +/** + * A specialized version of `baseIsEqualDeep` for arrays with support for + * partial deep comparisons. + * + * @private + * @param {Array} array The array to compare. + * @param {Array} other The other array to compare. + * @param {number} bitmask The bitmask flags. See `baseIsEqual` for more details. + * @param {Function} customizer The function to customize comparisons. + * @param {Function} equalFunc The function to determine equivalents of values. + * @param {Object} stack Tracks traversed `array` and `other` objects. + * @returns {boolean} Returns `true` if the arrays are equivalent, else `false`. + */ +function equalArrays(array, other, bitmask, customizer, equalFunc, stack) { + var isPartial = bitmask & COMPARE_PARTIAL_FLAG, + arrLength = array.length, + othLength = other.length; + + if (arrLength != othLength && !(isPartial && othLength > arrLength)) { + return false; + } + // Assume cyclic values are equal. + var stacked = stack.get(array); + if (stacked && stack.get(other)) { + return stacked == other; + } + var index = -1, + result = true, + seen = (bitmask & COMPARE_UNORDERED_FLAG) ? new SetCache : undefined; + + stack.set(array, other); + stack.set(other, array); + + // Ignore non-index properties. + while (++index < arrLength) { + var arrValue = array[index], + othValue = other[index]; + + if (customizer) { + var compared = isPartial + ? customizer(othValue, arrValue, index, other, array, stack) + : customizer(arrValue, othValue, index, array, other, stack); + } + if (compared !== undefined) { + if (compared) { + continue; + } + result = false; + break; + } + // Recursively compare arrays (susceptible to call stack limits). + if (seen) { + if (!arraySome(other, function(othValue, othIndex) { + if (!cacheHas(seen, othIndex) && + (arrValue === othValue || equalFunc(arrValue, othValue, bitmask, customizer, stack))) { + return seen.push(othIndex); + } + })) { + result = false; + break; + } + } else if (!( + arrValue === othValue || + equalFunc(arrValue, othValue, bitmask, customizer, stack) + )) { + result = false; + break; + } + } + stack['delete'](array); + stack['delete'](other); + return result; +} + +/** Built-in value references. */ +var Uint8Array = root.Uint8Array; + +/** + * Converts `map` to its key-value pairs. + * + * @private + * @param {Object} map The map to convert. + * @returns {Array} Returns the key-value pairs. + */ +function mapToArray(map) { + var index = -1, + result = Array(map.size); + + map.forEach(function(value, key) { + result[++index] = [key, value]; + }); + return result; +} + +/** + * Converts `set` to an array of its values. + * + * @private + * @param {Object} set The set to convert. + * @returns {Array} Returns the values. + */ +function setToArray(set) { + var index = -1, + result = Array(set.size); + + set.forEach(function(value) { + result[++index] = value; + }); + return result; +} + +/** Used to compose bitmasks for value comparisons. */ +var COMPARE_PARTIAL_FLAG$1 = 1, + COMPARE_UNORDERED_FLAG$1 = 2; + +/** `Object#toString` result references. */ +var boolTag$1 = '[object Boolean]', + dateTag$1 = '[object Date]', + errorTag$1 = '[object Error]', + mapTag$1 = '[object Map]', + numberTag$2 = '[object Number]', + regexpTag$1 = '[object RegExp]', + setTag$1 = '[object Set]', + stringTag$2 = '[object String]', + symbolTag$1 = '[object Symbol]'; + +var arrayBufferTag$1 = '[object ArrayBuffer]', + dataViewTag$1 = '[object DataView]'; + +/** Used to convert symbols to primitives and strings. */ +var symbolProto$1 = Symbol ? Symbol.prototype : undefined, + symbolValueOf = symbolProto$1 ? symbolProto$1.valueOf : undefined; + +/** + * A specialized version of `baseIsEqualDeep` for comparing objects of + * the same `toStringTag`. + * + * **Note:** This function only supports comparing values with tags of + * `Boolean`, `Date`, `Error`, `Number`, `RegExp`, or `String`. + * + * @private + * @param {Object} object The object to compare. + * @param {Object} other The other object to compare. + * @param {string} tag The `toStringTag` of the objects to compare. + * @param {number} bitmask The bitmask flags. See `baseIsEqual` for more details. + * @param {Function} customizer The function to customize comparisons. + * @param {Function} equalFunc The function to determine equivalents of values. + * @param {Object} stack Tracks traversed `object` and `other` objects. + * @returns {boolean} Returns `true` if the objects are equivalent, else `false`. + */ +function equalByTag(object, other, tag, bitmask, customizer, equalFunc, stack) { + switch (tag) { + case dataViewTag$1: + if ((object.byteLength != other.byteLength) || + (object.byteOffset != other.byteOffset)) { + return false; + } + object = object.buffer; + other = other.buffer; + + case arrayBufferTag$1: + if ((object.byteLength != other.byteLength) || + !equalFunc(new Uint8Array(object), new Uint8Array(other))) { + return false; + } + return true; + + case boolTag$1: + case dateTag$1: + case numberTag$2: + // Coerce booleans to `1` or `0` and dates to milliseconds. + // Invalid dates are coerced to `NaN`. + return eq(+object, +other); + + case errorTag$1: + return object.name == other.name && object.message == other.message; + + case regexpTag$1: + case stringTag$2: + // Coerce regexes to strings and treat strings, primitives and objects, + // as equal. See http://www.ecma-international.org/ecma-262/7.0/#sec-regexp.prototype.tostring + // for more details. + return object == (other + ''); + + case mapTag$1: + var convert = mapToArray; + + case setTag$1: + var isPartial = bitmask & COMPARE_PARTIAL_FLAG$1; + convert || (convert = setToArray); + + if (object.size != other.size && !isPartial) { + return false; + } + // Assume cyclic values are equal. + var stacked = stack.get(object); + if (stacked) { + return stacked == other; + } + bitmask |= COMPARE_UNORDERED_FLAG$1; + + // Recursively compare objects (susceptible to call stack limits). + stack.set(object, other); + var result = equalArrays(convert(object), convert(other), bitmask, customizer, equalFunc, stack); + stack['delete'](object); + return result; + + case symbolTag$1: + if (symbolValueOf) { + return symbolValueOf.call(object) == symbolValueOf.call(other); + } + } + return false; +} + +/** + * Appends the elements of `values` to `array`. + * + * @private + * @param {Array} array The array to modify. + * @param {Array} values The values to append. + * @returns {Array} Returns `array`. + */ +function arrayPush(array, values) { + var index = -1, + length = values.length, + offset = array.length; + + while (++index < length) { + array[offset + index] = values[index]; + } + return array; +} + +/** + * The base implementation of `getAllKeys` and `getAllKeysIn` which uses + * `keysFunc` and `symbolsFunc` to get the enumerable property names and + * symbols of `object`. + * + * @private + * @param {Object} object The object to query. + * @param {Function} keysFunc The function to get the keys of `object`. + * @param {Function} symbolsFunc The function to get the symbols of `object`. + * @returns {Array} Returns the array of property names and symbols. + */ +function baseGetAllKeys(object, keysFunc, symbolsFunc) { + var result = keysFunc(object); + return isArray(object) ? result : arrayPush(result, symbolsFunc(object)); +} + +/** + * This method returns a new empty array. + * + * @static + * @memberOf _ + * @since 4.13.0 + * @category Util + * @returns {Array} Returns the new empty array. + * @example + * + * var arrays = _.times(2, _.stubArray); + * + * console.log(arrays); + * // => [[], []] + * + * console.log(arrays[0] === arrays[1]); + * // => false + */ +function stubArray() { + return []; +} + +/** Used for built-in method references. */ +var objectProto$a = Object.prototype; + +/** Built-in value references. */ +var propertyIsEnumerable$1 = objectProto$a.propertyIsEnumerable; + +/* Built-in method references for those with the same name as other `lodash` methods. */ +var nativeGetSymbols = Object.getOwnPropertySymbols; + +/** + * Creates an array of the own enumerable symbols of `object`. + * + * @private + * @param {Object} object The object to query. + * @returns {Array} Returns the array of symbols. + */ +var getSymbols = !nativeGetSymbols ? stubArray : function(object) { + if (object == null) { + return []; + } + object = Object(object); + return arrayFilter(nativeGetSymbols(object), function(symbol) { + return propertyIsEnumerable$1.call(object, symbol); + }); +}; + +/** + * Creates an array of own enumerable property names and symbols of `object`. + * + * @private + * @param {Object} object The object to query. + * @returns {Array} Returns the array of property names and symbols. + */ +function getAllKeys(object) { + return baseGetAllKeys(object, keys, getSymbols); +} + +/** Used to compose bitmasks for value comparisons. */ +var COMPARE_PARTIAL_FLAG$2 = 1; + +/** Used for built-in method references. */ +var objectProto$b = Object.prototype; + +/** Used to check objects for own properties. */ +var hasOwnProperty$8 = objectProto$b.hasOwnProperty; + +/** + * A specialized version of `baseIsEqualDeep` for objects with support for + * partial deep comparisons. + * + * @private + * @param {Object} object The object to compare. + * @param {Object} other The other object to compare. + * @param {number} bitmask The bitmask flags. See `baseIsEqual` for more details. + * @param {Function} customizer The function to customize comparisons. + * @param {Function} equalFunc The function to determine equivalents of values. + * @param {Object} stack Tracks traversed `object` and `other` objects. + * @returns {boolean} Returns `true` if the objects are equivalent, else `false`. + */ +function equalObjects(object, other, bitmask, customizer, equalFunc, stack) { + var isPartial = bitmask & COMPARE_PARTIAL_FLAG$2, + objProps = getAllKeys(object), + objLength = objProps.length, + othProps = getAllKeys(other), + othLength = othProps.length; + + if (objLength != othLength && !isPartial) { + return false; + } + var index = objLength; + while (index--) { + var key = objProps[index]; + if (!(isPartial ? key in other : hasOwnProperty$8.call(other, key))) { + return false; + } + } + // Assume cyclic values are equal. + var stacked = stack.get(object); + if (stacked && stack.get(other)) { + return stacked == other; + } + var result = true; + stack.set(object, other); + stack.set(other, object); + + var skipCtor = isPartial; + while (++index < objLength) { + key = objProps[index]; + var objValue = object[key], + othValue = other[key]; + + if (customizer) { + var compared = isPartial + ? customizer(othValue, objValue, key, other, object, stack) + : customizer(objValue, othValue, key, object, other, stack); + } + // Recursively compare objects (susceptible to call stack limits). + if (!(compared === undefined + ? (objValue === othValue || equalFunc(objValue, othValue, bitmask, customizer, stack)) + : compared + )) { + result = false; + break; + } + skipCtor || (skipCtor = key == 'constructor'); + } + if (result && !skipCtor) { + var objCtor = object.constructor, + othCtor = other.constructor; + + // Non `Object` object instances with different constructors are not equal. + if (objCtor != othCtor && + ('constructor' in object && 'constructor' in other) && + !(typeof objCtor == 'function' && objCtor instanceof objCtor && + typeof othCtor == 'function' && othCtor instanceof othCtor)) { + result = false; + } + } + stack['delete'](object); + stack['delete'](other); + return result; +} + +/* Built-in method references that are verified to be native. */ +var DataView = getNative(root, 'DataView'); + +/* Built-in method references that are verified to be native. */ +var Promise$1 = getNative(root, 'Promise'); + +/* Built-in method references that are verified to be native. */ +var Set$1 = getNative(root, 'Set'); + +/* Built-in method references that are verified to be native. */ +var WeakMap$1 = getNative(root, 'WeakMap'); + +/** `Object#toString` result references. */ +var mapTag$2 = '[object Map]', + objectTag$2 = '[object Object]', + promiseTag = '[object Promise]', + setTag$2 = '[object Set]', + weakMapTag$1 = '[object WeakMap]'; + +var dataViewTag$2 = '[object DataView]'; + +/** Used to detect maps, sets, and weakmaps. */ +var dataViewCtorString = toSource(DataView), + mapCtorString = toSource(Map$1), + promiseCtorString = toSource(Promise$1), + setCtorString = toSource(Set$1), + weakMapCtorString = toSource(WeakMap$1); + +/** + * Gets the `toStringTag` of `value`. + * + * @private + * @param {*} value The value to query. + * @returns {string} Returns the `toStringTag`. + */ +var getTag = baseGetTag; + +// Fallback for data views, maps, sets, and weak maps in IE 11 and promises in Node.js < 6. +if ((DataView && getTag(new DataView(new ArrayBuffer(1))) != dataViewTag$2) || + (Map$1 && getTag(new Map$1) != mapTag$2) || + (Promise$1 && getTag(Promise$1.resolve()) != promiseTag) || + (Set$1 && getTag(new Set$1) != setTag$2) || + (WeakMap$1 && getTag(new WeakMap$1) != weakMapTag$1)) { + getTag = function(value) { + var result = baseGetTag(value), + Ctor = result == objectTag$2 ? value.constructor : undefined, + ctorString = Ctor ? toSource(Ctor) : ''; + + if (ctorString) { + switch (ctorString) { + case dataViewCtorString: return dataViewTag$2; + case mapCtorString: return mapTag$2; + case promiseCtorString: return promiseTag; + case setCtorString: return setTag$2; + case weakMapCtorString: return weakMapTag$1; + } + } + return result; + }; +} + +var getTag$1 = getTag; + +/** Used to compose bitmasks for value comparisons. */ +var COMPARE_PARTIAL_FLAG$3 = 1; + +/** `Object#toString` result references. */ +var argsTag$2 = '[object Arguments]', + arrayTag$1 = '[object Array]', + objectTag$3 = '[object Object]'; + +/** Used for built-in method references. */ +var objectProto$c = Object.prototype; + +/** Used to check objects for own properties. */ +var hasOwnProperty$9 = objectProto$c.hasOwnProperty; + +/** + * A specialized version of `baseIsEqual` for arrays and objects which performs + * deep comparisons and tracks traversed objects enabling objects with circular + * references to be compared. + * + * @private + * @param {Object} object The object to compare. + * @param {Object} other The other object to compare. + * @param {number} bitmask The bitmask flags. See `baseIsEqual` for more details. + * @param {Function} customizer The function to customize comparisons. + * @param {Function} equalFunc The function to determine equivalents of values. + * @param {Object} [stack] Tracks traversed `object` and `other` objects. + * @returns {boolean} Returns `true` if the objects are equivalent, else `false`. + */ +function baseIsEqualDeep(object, other, bitmask, customizer, equalFunc, stack) { + var objIsArr = isArray(object), + othIsArr = isArray(other), + objTag = objIsArr ? arrayTag$1 : getTag$1(object), + othTag = othIsArr ? arrayTag$1 : getTag$1(other); + + objTag = objTag == argsTag$2 ? objectTag$3 : objTag; + othTag = othTag == argsTag$2 ? objectTag$3 : othTag; + + var objIsObj = objTag == objectTag$3, + othIsObj = othTag == objectTag$3, + isSameTag = objTag == othTag; + + if (isSameTag && isBuffer(object)) { + if (!isBuffer(other)) { + return false; + } + objIsArr = true; + objIsObj = false; + } + if (isSameTag && !objIsObj) { + stack || (stack = new Stack); + return (objIsArr || isTypedArray(object)) + ? equalArrays(object, other, bitmask, customizer, equalFunc, stack) + : equalByTag(object, other, objTag, bitmask, customizer, equalFunc, stack); + } + if (!(bitmask & COMPARE_PARTIAL_FLAG$3)) { + var objIsWrapped = objIsObj && hasOwnProperty$9.call(object, '__wrapped__'), + othIsWrapped = othIsObj && hasOwnProperty$9.call(other, '__wrapped__'); + + if (objIsWrapped || othIsWrapped) { + var objUnwrapped = objIsWrapped ? object.value() : object, + othUnwrapped = othIsWrapped ? other.value() : other; + + stack || (stack = new Stack); + return equalFunc(objUnwrapped, othUnwrapped, bitmask, customizer, stack); + } + } + if (!isSameTag) { + return false; + } + stack || (stack = new Stack); + return equalObjects(object, other, bitmask, customizer, equalFunc, stack); +} + +/** + * The base implementation of `_.isEqual` which supports partial comparisons + * and tracks traversed objects. + * + * @private + * @param {*} value The value to compare. + * @param {*} other The other value to compare. + * @param {boolean} bitmask The bitmask flags. + * 1 - Unordered comparison + * 2 - Partial comparison + * @param {Function} [customizer] The function to customize comparisons. + * @param {Object} [stack] Tracks traversed `value` and `other` objects. + * @returns {boolean} Returns `true` if the values are equivalent, else `false`. + */ +function baseIsEqual(value, other, bitmask, customizer, stack) { + if (value === other) { + return true; + } + if (value == null || other == null || (!isObjectLike(value) && !isObjectLike(other))) { + return value !== value && other !== other; + } + return baseIsEqualDeep(value, other, bitmask, customizer, baseIsEqual, stack); +} + +/** Used to compose bitmasks for value comparisons. */ +var COMPARE_PARTIAL_FLAG$4 = 1, + COMPARE_UNORDERED_FLAG$2 = 2; + +/** + * The base implementation of `_.isMatch` without support for iteratee shorthands. + * + * @private + * @param {Object} object The object to inspect. + * @param {Object} source The object of property values to match. + * @param {Array} matchData The property names, values, and compare flags to match. + * @param {Function} [customizer] The function to customize comparisons. + * @returns {boolean} Returns `true` if `object` is a match, else `false`. + */ +function baseIsMatch(object, source, matchData, customizer) { + var index = matchData.length, + length = index, + noCustomizer = !customizer; + + if (object == null) { + return !length; + } + object = Object(object); + while (index--) { + var data = matchData[index]; + if ((noCustomizer && data[2]) + ? data[1] !== object[data[0]] + : !(data[0] in object) + ) { + return false; + } + } + while (++index < length) { + data = matchData[index]; + var key = data[0], + objValue = object[key], + srcValue = data[1]; + + if (noCustomizer && data[2]) { + if (objValue === undefined && !(key in object)) { + return false; + } + } else { + var stack = new Stack; + if (customizer) { + var result = customizer(objValue, srcValue, key, object, source, stack); + } + if (!(result === undefined + ? baseIsEqual(srcValue, objValue, COMPARE_PARTIAL_FLAG$4 | COMPARE_UNORDERED_FLAG$2, customizer, stack) + : result + )) { + return false; + } + } + } + return true; +} + +/** + * Checks if `value` is suitable for strict equality comparisons, i.e. `===`. + * + * @private + * @param {*} value The value to check. + * @returns {boolean} Returns `true` if `value` if suitable for strict + * equality comparisons, else `false`. + */ +function isStrictComparable(value) { + return value === value && !isObject(value); +} + +/** + * Gets the property names, values, and compare flags of `object`. + * + * @private + * @param {Object} object The object to query. + * @returns {Array} Returns the match data of `object`. + */ +function getMatchData(object) { + var result = keys(object), + length = result.length; + + while (length--) { + var key = result[length], + value = object[key]; + + result[length] = [key, value, isStrictComparable(value)]; + } + return result; +} + +/** + * A specialized version of `matchesProperty` for source values suitable + * for strict equality comparisons, i.e. `===`. + * + * @private + * @param {string} key The key of the property to get. + * @param {*} srcValue The value to match. + * @returns {Function} Returns the new spec function. + */ +function matchesStrictComparable(key, srcValue) { + return function(object) { + if (object == null) { + return false; + } + return object[key] === srcValue && + (srcValue !== undefined || (key in Object(object))); + }; +} + +/** + * The base implementation of `_.matches` which doesn't clone `source`. + * + * @private + * @param {Object} source The object of property values to match. + * @returns {Function} Returns the new spec function. + */ +function baseMatches(source) { + var matchData = getMatchData(source); + if (matchData.length == 1 && matchData[0][2]) { + return matchesStrictComparable(matchData[0][0], matchData[0][1]); + } + return function(object) { + return object === source || baseIsMatch(object, source, matchData); + }; +} + +/** Used to match property names within property paths. */ +var reIsDeepProp = /\.|\[(?:[^[\]]*|(["'])(?:(?!\1)[^\\]|\\.)*?\1)\]/, + reIsPlainProp = /^\w*$/; + +/** + * Checks if `value` is a property name and not a property path. + * + * @private + * @param {*} value The value to check. + * @param {Object} [object] The object to query keys on. + * @returns {boolean} Returns `true` if `value` is a property name, else `false`. + */ +function isKey(value, object) { + if (isArray(value)) { + return false; + } + var type = typeof value; + if (type == 'number' || type == 'symbol' || type == 'boolean' || + value == null || isSymbol(value)) { + return true; + } + return reIsPlainProp.test(value) || !reIsDeepProp.test(value) || + (object != null && value in Object(object)); +} + +/** Error message constants. */ +var FUNC_ERROR_TEXT = 'Expected a function'; + +/** + * Creates a function that memoizes the result of `func`. If `resolver` is + * provided, it determines the cache key for storing the result based on the + * arguments provided to the memoized function. By default, the first argument + * provided to the memoized function is used as the map cache key. The `func` + * is invoked with the `this` binding of the memoized function. + * + * **Note:** The cache is exposed as the `cache` property on the memoized + * function. Its creation may be customized by replacing the `_.memoize.Cache` + * constructor with one whose instances implement the + * [`Map`](http://ecma-international.org/ecma-262/7.0/#sec-properties-of-the-map-prototype-object) + * method interface of `clear`, `delete`, `get`, `has`, and `set`. + * + * @static + * @memberOf _ + * @since 0.1.0 + * @category Function + * @param {Function} func The function to have its output memoized. + * @param {Function} [resolver] The function to resolve the cache key. + * @returns {Function} Returns the new memoized function. + * @example + * + * var object = { 'a': 1, 'b': 2 }; + * var other = { 'c': 3, 'd': 4 }; + * + * var values = _.memoize(_.values); + * values(object); + * // => [1, 2] + * + * values(other); + * // => [3, 4] + * + * object.a = 2; + * values(object); + * // => [1, 2] + * + * // Modify the result cache. + * values.cache.set(object, ['a', 'b']); + * values(object); + * // => ['a', 'b'] + * + * // Replace `_.memoize.Cache`. + * _.memoize.Cache = WeakMap; + */ +function memoize(func, resolver) { + if (typeof func != 'function' || (resolver != null && typeof resolver != 'function')) { + throw new TypeError(FUNC_ERROR_TEXT); + } + var memoized = function() { + var args = arguments, + key = resolver ? resolver.apply(this, args) : args[0], + cache = memoized.cache; + + if (cache.has(key)) { + return cache.get(key); + } + var result = func.apply(this, args); + memoized.cache = cache.set(key, result) || cache; + return result; + }; + memoized.cache = new (memoize.Cache || MapCache); + return memoized; +} + +// Expose `MapCache`. +memoize.Cache = MapCache; + +/** Used as the maximum memoize cache size. */ +var MAX_MEMOIZE_SIZE = 500; + +/** + * A specialized version of `_.memoize` which clears the memoized function's + * cache when it exceeds `MAX_MEMOIZE_SIZE`. + * + * @private + * @param {Function} func The function to have its output memoized. + * @returns {Function} Returns the new memoized function. + */ +function memoizeCapped(func) { + var result = memoize(func, function(key) { + if (cache.size === MAX_MEMOIZE_SIZE) { + cache.clear(); + } + return key; + }); + + var cache = result.cache; + return result; +} + +/** Used to match property names within property paths. */ +var rePropName = /[^.[\]]+|\[(?:(-?\d+(?:\.\d+)?)|(["'])((?:(?!\2)[^\\]|\\.)*?)\2)\]|(?=(?:\.|\[\])(?:\.|\[\]|$))/g; + +/** Used to match backslashes in property paths. */ +var reEscapeChar = /\\(\\)?/g; + +/** + * Converts `string` to a property path array. + * + * @private + * @param {string} string The string to convert. + * @returns {Array} Returns the property path array. + */ +var stringToPath = memoizeCapped(function(string) { + var result = []; + if (string.charCodeAt(0) === 46 /* . */) { + result.push(''); + } + string.replace(rePropName, function(match, number, quote, subString) { + result.push(quote ? subString.replace(reEscapeChar, '$1') : (number || match)); + }); + return result; +}); + +/** + * Casts `value` to a path array if it's not one. + * + * @private + * @param {*} value The value to inspect. + * @param {Object} [object] The object to query keys on. + * @returns {Array} Returns the cast property path array. + */ +function castPath(value, object) { + if (isArray(value)) { + return value; + } + return isKey(value, object) ? [value] : stringToPath(toString(value)); +} + +/** Used as references for various `Number` constants. */ +var INFINITY$1 = 1 / 0; + +/** + * Converts `value` to a string key if it's not a string or symbol. + * + * @private + * @param {*} value The value to inspect. + * @returns {string|symbol} Returns the key. + */ +function toKey(value) { + if (typeof value == 'string' || isSymbol(value)) { + return value; + } + var result = (value + ''); + return (result == '0' && (1 / value) == -INFINITY$1) ? '-0' : result; +} + +/** + * The base implementation of `_.get` without support for default values. + * + * @private + * @param {Object} object The object to query. + * @param {Array|string} path The path of the property to get. + * @returns {*} Returns the resolved value. + */ +function baseGet(object, path) { + path = castPath(path, object); + + var index = 0, + length = path.length; + + while (object != null && index < length) { + object = object[toKey(path[index++])]; + } + return (index && index == length) ? object : undefined; +} + +/** + * Gets the value at `path` of `object`. If the resolved value is + * `undefined`, the `defaultValue` is returned in its place. + * + * @static + * @memberOf _ + * @since 3.7.0 + * @category Object + * @param {Object} object The object to query. + * @param {Array|string} path The path of the property to get. + * @param {*} [defaultValue] The value returned for `undefined` resolved values. + * @returns {*} Returns the resolved value. + * @example + * + * var object = { 'a': [{ 'b': { 'c': 3 } }] }; + * + * _.get(object, 'a[0].b.c'); + * // => 3 + * + * _.get(object, ['a', '0', 'b', 'c']); + * // => 3 + * + * _.get(object, 'a.b.c', 'default'); + * // => 'default' + */ +function get(object, path, defaultValue) { + var result = object == null ? undefined : baseGet(object, path); + return result === undefined ? defaultValue : result; +} + +/** + * The base implementation of `_.hasIn` without support for deep paths. + * + * @private + * @param {Object} [object] The object to query. + * @param {Array|string} key The key to check. + * @returns {boolean} Returns `true` if `key` exists, else `false`. + */ +function baseHasIn(object, key) { + return object != null && key in Object(object); +} + +/** + * Checks if `path` exists on `object`. + * + * @private + * @param {Object} object The object to query. + * @param {Array|string} path The path to check. + * @param {Function} hasFunc The function to check properties. + * @returns {boolean} Returns `true` if `path` exists, else `false`. + */ +function hasPath(object, path, hasFunc) { + path = castPath(path, object); + + var index = -1, + length = path.length, + result = false; + + while (++index < length) { + var key = toKey(path[index]); + if (!(result = object != null && hasFunc(object, key))) { + break; + } + object = object[key]; + } + if (result || ++index != length) { + return result; + } + length = object == null ? 0 : object.length; + return !!length && isLength(length) && isIndex(key, length) && + (isArray(object) || isArguments(object)); +} + +/** + * Checks if `path` is a direct or inherited property of `object`. + * + * @static + * @memberOf _ + * @since 4.0.0 + * @category Object + * @param {Object} object The object to query. + * @param {Array|string} path The path to check. + * @returns {boolean} Returns `true` if `path` exists, else `false`. + * @example + * + * var object = _.create({ 'a': _.create({ 'b': 2 }) }); + * + * _.hasIn(object, 'a'); + * // => true + * + * _.hasIn(object, 'a.b'); + * // => true + * + * _.hasIn(object, ['a', 'b']); + * // => true + * + * _.hasIn(object, 'b'); + * // => false + */ +function hasIn(object, path) { + return object != null && hasPath(object, path, baseHasIn); +} + +/** Used to compose bitmasks for value comparisons. */ +var COMPARE_PARTIAL_FLAG$5 = 1, + COMPARE_UNORDERED_FLAG$3 = 2; + +/** + * The base implementation of `_.matchesProperty` which doesn't clone `srcValue`. + * + * @private + * @param {string} path The path of the property to get. + * @param {*} srcValue The value to match. + * @returns {Function} Returns the new spec function. + */ +function baseMatchesProperty(path, srcValue) { + if (isKey(path) && isStrictComparable(srcValue)) { + return matchesStrictComparable(toKey(path), srcValue); + } + return function(object) { + var objValue = get(object, path); + return (objValue === undefined && objValue === srcValue) + ? hasIn(object, path) + : baseIsEqual(srcValue, objValue, COMPARE_PARTIAL_FLAG$5 | COMPARE_UNORDERED_FLAG$3); + }; +} + +/** + * This method returns the first argument it receives. + * + * @static + * @since 0.1.0 + * @memberOf _ + * @category Util + * @param {*} value Any value. + * @returns {*} Returns `value`. + * @example + * + * var object = { 'a': 1 }; + * + * console.log(_.identity(object) === object); + * // => true + */ +function identity(value) { + return value; +} + +/** + * The base implementation of `_.property` without support for deep paths. + * + * @private + * @param {string} key The key of the property to get. + * @returns {Function} Returns the new accessor function. + */ +function baseProperty(key) { + return function(object) { + return object == null ? undefined : object[key]; + }; +} + +/** + * A specialized version of `baseProperty` which supports deep paths. + * + * @private + * @param {Array|string} path The path of the property to get. + * @returns {Function} Returns the new accessor function. + */ +function basePropertyDeep(path) { + return function(object) { + return baseGet(object, path); + }; +} + +/** + * Creates a function that returns the value at `path` of a given object. + * + * @static + * @memberOf _ + * @since 2.4.0 + * @category Util + * @param {Array|string} path The path of the property to get. + * @returns {Function} Returns the new accessor function. + * @example + * + * var objects = [ + * { 'a': { 'b': 2 } }, + * { 'a': { 'b': 1 } } + * ]; + * + * _.map(objects, _.property('a.b')); + * // => [2, 1] + * + * _.map(_.sortBy(objects, _.property(['a', 'b'])), 'a.b'); + * // => [1, 2] + */ +function property(path) { + return isKey(path) ? baseProperty(toKey(path)) : basePropertyDeep(path); +} + +/** + * The base implementation of `_.iteratee`. + * + * @private + * @param {*} [value=_.identity] The value to convert to an iteratee. + * @returns {Function} Returns the iteratee. + */ +function baseIteratee(value) { + // Don't store the `typeof` result in a variable to avoid a JIT bug in Safari 9. + // See https://bugs.webkit.org/show_bug.cgi?id=156034 for more details. + if (typeof value == 'function') { + return value; + } + if (value == null) { + return identity; + } + if (typeof value == 'object') { + return isArray(value) + ? baseMatchesProperty(value[0], value[1]) + : baseMatches(value); + } + return property(value); +} + +// validate object type +/** + * @TODO if provide with the keys then we need to check if the key:value type as well + * @param {object} value expected + * @param {array} [keys=null] if it has the keys array to compare as well + * @return {boolean} true if OK + */ +var checkIsObject = function(value, keys) { + if ( keys === void 0 ) keys=null; + + if (isPlainObject(value)) { + if (!keys) { + return true + } + if (checkIsArray(keys)) { + // please note we DON'T care if some is optional + // plese refer to the contract.json for the keys + return !keys.filter(function (key) { + var _value = value[key.name]; + return !(key.type.length > key.type.filter(function (type) { + var tmp; + if (_value !== undefined) { + if ((tmp = isArrayLike(type)) !== false) { + return !arrayTypeHandler({arg: _value}, tmp) + // return tmp.filter(t => !checkIsArray(_value, t)).length; + // @TODO there might be an object within an object with keys as well :S + } + return !combineFn(type)(_value) + } + return true + }).length) + }).length; + } + } + return false +}; + +/** + * fold this into it's own function to handler different object type + * @param {object} p the prepared object for process + * @return {boolean} + */ +var objectTypeHandler = function(p) { + var arg = p.arg; + var param = p.param; + var _args = [arg]; + if (Array.isArray(param.keys) && param.keys.length) { + _args.push(param.keys); + } + // just simple check + return Reflect.apply(checkIsObject, null, _args) +}; + +// custom validation error class +// when validaton failed +var JsonqlValidationError = /*@__PURE__*/(function (Error) { + function JsonqlValidationError() { + var args = [], len = arguments.length; + while ( len-- ) args[ len ] = arguments[ len ]; + + Error.apply(this, args); + + this.message = args[0]; + this.detail = args[1]; + + this.className = JsonqlValidationError.name; + + if (Error.captureStackTrace) { + Error.captureStackTrace(this, JsonqlValidationError); + } + } + + if ( Error ) JsonqlValidationError.__proto__ = Error; + JsonqlValidationError.prototype = Object.create( Error && Error.prototype ); + JsonqlValidationError.prototype.constructor = JsonqlValidationError; + + var staticAccessors = { name: { configurable: true } }; + + staticAccessors.name.get = function () { + return 'JsonqlValidationError'; + }; + + Object.defineProperties( JsonqlValidationError, staticAccessors ); + + return JsonqlValidationError; +}(Error)); + +/** + * This is a custom error to throw whenever a error happen inside the jsonql + * This help us to capture the right error, due to the call happens in sequence + * @param {string} message to tell what happen + * @param {mixed} extra things we want to add, 500? + */ +var JsonqlError$1 = /*@__PURE__*/(function (Error) { + function JsonqlError() { + var args = [], len = arguments.length; + while ( len-- ) args[ len ] = arguments[ len ]; + + Error.apply(this, args); + + this.message = args[0]; + this.detail = args[1]; + + this.className = JsonqlError.name; + + if (Error.captureStackTrace) { + Error.captureStackTrace(this, JsonqlError); + // this.detail = this.stack; + } + } + + if ( Error ) JsonqlError.__proto__ = Error; + JsonqlError.prototype = Object.create( Error && Error.prototype ); + JsonqlError.prototype.constructor = JsonqlError; + + var staticAccessors = { name: { configurable: true },statusCode: { configurable: true } }; + + staticAccessors.name.get = function () { + return 'JsonqlError'; + }; + + staticAccessors.statusCode.get = function () { + return NO_STATUS_CODE; + }; + + Object.defineProperties( JsonqlError, staticAccessors ); + + return JsonqlError; +}(Error)); + +// move the index.js code here that make more sense to find where things are +// import debug from 'debug' +// const debugFn = debug('jsonql-params-validator:validator') +// also export this for use in other places + +/** + * We need to handle those optional parameter without a default value + * @param {object} params from contract.json + * @return {boolean} for filter operation false is actually OK + */ +var optionalHandler = function( params ) { + var arg = params.arg; + var param = params.param; + if (isNotEmpty(arg)) { + // debug('call optional handler', arg, params); + // loop through the type in param + return !(param.type.length > param.type.filter(function (type) { return validateHandler(type, params); } + ).length) + } + return false +}; + +/** + * actually picking the validator + * @param {*} type for checking + * @param {*} value for checking + * @return {boolean} true on OK + */ +var validateHandler = function(type, value) { + var tmp; + switch (true) { + case type === OBJECT_TYPE$1: + // debugFn('call OBJECT_TYPE') + return !objectTypeHandler(value) + case type === ARRAY_TYPE$1: + // debugFn('call ARRAY_TYPE') + return !checkIsArray(value.arg) + // @TODO when the type is not present, it always fall through here + // so we need to find a way to actually pre-check the type first + // AKA check the contract.json map before running here + case (tmp = isArrayLike(type)) !== false: + // debugFn('call ARRAY_LIKE: %O', value) + return !arrayTypeHandler(value, tmp) + default: + return !combineFn(type)(value.arg) + } +}; + +/** + * it get too longer to fit in one line so break it out from the fn below + * @param {*} arg value + * @param {object} param config + * @return {*} value or apply default value + */ +var getOptionalValue = function(arg, param) { + if (arg !== undefined) { + return arg + } + return (param.optional === true && param.defaultvalue !== undefined ? param.defaultvalue : null) +}; + +/** + * padding the arguments with defaultValue if the arguments did not provide the value + * this will be the name export + * @param {array} args normalized arguments + * @param {array} params from contract.json + * @return {array} merge the two together + */ +var normalizeArgs = function(args, params) { + // first we should check if this call require a validation at all + // there will be situation where the function doesn't need args and params + if (!checkIsArray(params)) { + // debugFn('params value', params) + throw new JsonqlValidationError(PARAMS_NOT_ARRAY_ERR) + } + if (params.length === 0) { + return [] + } + if (!checkIsArray(args)) { + throw new JsonqlValidationError(ARGS_NOT_ARRAY_ERR) + } + // debugFn(args, params); + // fall through switch + switch(true) { + case args.length == params.length: // standard + return args.map(function (arg, i) { return ( + { + arg: arg, + index: i, + param: params[i] + } + ); }) + case params[0].variable === true: // using spread syntax + var type = params[0].type; + return args.map(function (arg, i) { return ( + { + arg: arg, + index: i, // keep the index for reference + param: params[i] || { type: type, name: '_' } + } + ); }) + // with optional defaultValue parameters + case args.length < params.length: + return params.map(function (param, i) { return ( + { + param: param, + index: i, + arg: getOptionalValue(args[i], param), + optional: param.optional || false + } + ); }) + // this one pass more than it should have anything after the args.length will be cast as any type + case args.length > params.length: + var ctn = params.length; + // this happens when we have those array. type + var _type = [ DEFAULT_TYPE$1 ]; + // we only looking at the first one, this might be a @BUG + /* + if ((tmp = isArrayLike(params[0].type[0])) !== false) { + _type = tmp; + } */ + // if we use the params as guide then the rest will get throw out + // which is not what we want, instead, anything without the param + // will get a any type and optional flag + return args.map(function (arg, i) { + var optional = i >= ctn ? true : !!params[i].optional; + var param = params[i] || { type: _type, name: ("_" + i) }; + return { + arg: optional ? getOptionalValue(arg, param) : arg, + index: i, + param: param, + optional: optional + } + }) + // @TODO find out if there is more cases not cover + default: // this should never happen + // debugFn('args', args) + // debugFn('params', params) + // this is unknown therefore we just throw it! + throw new JsonqlError$1(EXCEPTION_CASE_ERR, { args: args, params: params }) + } +}; + +// what we want is after the validaton we also get the normalized result +// which is with the optional property if the argument didn't provide it +/** + * process the array of params back to their arguments + * @param {array} result the params result + * @return {array} arguments + */ +var processReturn = function (result) { return result.map(function (r) { return r.arg; }); }; + +/** + * validator main interface + * @param {array} args the arguments pass to the method call + * @param {array} params from the contract for that method + * @param {boolean} [withResul=false] if true then this will return the normalize result as well + * @return {array} empty array on success, or failed parameter and reasons + */ +var validateSync = function(args, params, withResult) { + var obj; + + if ( withResult === void 0 ) withResult = false; + var cleanArgs = normalizeArgs(args, params); + var checkResult = cleanArgs.filter(function (p) { + // v1.4.4 this fixed the problem, the root level optional is from the last fn + if (p.optional === true || p.param.optional === true) { + return optionalHandler(p) + } + // because array of types means OR so if one pass means pass + return !(p.param.type.length > p.param.type.filter( + function (type) { return validateHandler(type, p); } + ).length) + }); + // using the same convention we been using all this time + return !withResult ? checkResult : ( obj = {}, obj[ERROR_KEY] = checkResult, obj[DATA_KEY] = processReturn(cleanArgs), obj ) +}; + +/** + * A wrapper method that return promise + * @param {array} args arguments + * @param {array} params from contract.json + * @param {boolean} [withResul=false] if true then this will return the normalize result as well + * @return {object} promise.then or catch + */ +var validateAsync = function(args, params, withResult) { + if ( withResult === void 0 ) withResult = false; + + return new Promise(function (resolver, rejecter) { + var result = validateSync(args, params, withResult); + if (withResult) { + return result[ERROR_KEY].length ? rejecter(result[ERROR_KEY]) + : resolver(result[DATA_KEY]) + } + // the different is just in the then or catch phrase + return result.length ? rejecter(result) : resolver([]) + }) +}; + +var defineProperty = (function() { + try { + var func = getNative(Object, 'defineProperty'); + func({}, '', {}); + return func; + } catch (e) {} +}()); + +/** + * The base implementation of `assignValue` and `assignMergeValue` without + * value checks. + * + * @private + * @param {Object} object The object to modify. + * @param {string} key The key of the property to assign. + * @param {*} value The value to assign. + */ +function baseAssignValue(object, key, value) { + if (key == '__proto__' && defineProperty) { + defineProperty(object, key, { + 'configurable': true, + 'enumerable': true, + 'value': value, + 'writable': true + }); + } else { + object[key] = value; + } +} + +/** + * This function is like `assignValue` except that it doesn't assign + * `undefined` values. + * + * @private + * @param {Object} object The object to modify. + * @param {string} key The key of the property to assign. + * @param {*} value The value to assign. + */ +function assignMergeValue(object, key, value) { + if ((value !== undefined && !eq(object[key], value)) || + (value === undefined && !(key in object))) { + baseAssignValue(object, key, value); + } +} + +/** Detect free variable `exports`. */ +var freeExports$2 = typeof exports == 'object' && exports && !exports.nodeType && exports; + +/** Detect free variable `module`. */ +var freeModule$2 = freeExports$2 && typeof module == 'object' && module && !module.nodeType && module; + +/** Detect the popular CommonJS extension `module.exports`. */ +var moduleExports$2 = freeModule$2 && freeModule$2.exports === freeExports$2; + +/** Built-in value references. */ +var Buffer$1 = moduleExports$2 ? root.Buffer : undefined, + allocUnsafe = Buffer$1 ? Buffer$1.allocUnsafe : undefined; + +/** + * Creates a clone of `buffer`. + * + * @private + * @param {Buffer} buffer The buffer to clone. + * @param {boolean} [isDeep] Specify a deep clone. + * @returns {Buffer} Returns the cloned buffer. + */ +function cloneBuffer(buffer, isDeep) { + if (isDeep) { + return buffer.slice(); + } + var length = buffer.length, + result = allocUnsafe ? allocUnsafe(length) : new buffer.constructor(length); + + buffer.copy(result); + return result; +} + +/** + * Creates a clone of `arrayBuffer`. + * + * @private + * @param {ArrayBuffer} arrayBuffer The array buffer to clone. + * @returns {ArrayBuffer} Returns the cloned array buffer. + */ +function cloneArrayBuffer(arrayBuffer) { + var result = new arrayBuffer.constructor(arrayBuffer.byteLength); + new Uint8Array(result).set(new Uint8Array(arrayBuffer)); + return result; +} + +/** + * Creates a clone of `typedArray`. + * + * @private + * @param {Object} typedArray The typed array to clone. + * @param {boolean} [isDeep] Specify a deep clone. + * @returns {Object} Returns the cloned typed array. + */ +function cloneTypedArray(typedArray, isDeep) { + var buffer = isDeep ? cloneArrayBuffer(typedArray.buffer) : typedArray.buffer; + return new typedArray.constructor(buffer, typedArray.byteOffset, typedArray.length); +} + +/** + * Copies the values of `source` to `array`. + * + * @private + * @param {Array} source The array to copy values from. + * @param {Array} [array=[]] The array to copy values to. + * @returns {Array} Returns `array`. + */ +function copyArray(source, array) { + var index = -1, + length = source.length; + + array || (array = Array(length)); + while (++index < length) { + array[index] = source[index]; + } + return array; +} + +/** Built-in value references. */ +var objectCreate = Object.create; + +/** + * The base implementation of `_.create` without support for assigning + * properties to the created object. + * + * @private + * @param {Object} proto The object to inherit from. + * @returns {Object} Returns the new object. + */ +var baseCreate = (function() { + function object() {} + return function(proto) { + if (!isObject(proto)) { + return {}; + } + if (objectCreate) { + return objectCreate(proto); + } + object.prototype = proto; + var result = new object; + object.prototype = undefined; + return result; + }; +}()); + +/** + * Initializes an object clone. + * + * @private + * @param {Object} object The object to clone. + * @returns {Object} Returns the initialized clone. + */ +function initCloneObject(object) { + return (typeof object.constructor == 'function' && !isPrototype(object)) + ? baseCreate(getPrototype(object)) + : {}; +} + +/** + * This method is like `_.isArrayLike` except that it also checks if `value` + * is an object. + * + * @static + * @memberOf _ + * @since 4.0.0 + * @category Lang + * @param {*} value The value to check. + * @returns {boolean} Returns `true` if `value` is an array-like object, + * else `false`. + * @example + * + * _.isArrayLikeObject([1, 2, 3]); + * // => true + * + * _.isArrayLikeObject(document.body.children); + * // => true + * + * _.isArrayLikeObject('abc'); + * // => false + * + * _.isArrayLikeObject(_.noop); + * // => false + */ +function isArrayLikeObject(value) { + return isObjectLike(value) && isArrayLike$1(value); +} + +/** + * Gets the value at `key`, unless `key` is "__proto__" or "constructor". + * + * @private + * @param {Object} object The object to query. + * @param {string} key The key of the property to get. + * @returns {*} Returns the property value. + */ +function safeGet(object, key) { + if (key === 'constructor' && typeof object[key] === 'function') { + return; + } + + if (key == '__proto__') { + return; + } + + return object[key]; +} + +/** Used for built-in method references. */ +var objectProto$d = Object.prototype; + +/** Used to check objects for own properties. */ +var hasOwnProperty$a = objectProto$d.hasOwnProperty; + +/** + * Assigns `value` to `key` of `object` if the existing value is not equivalent + * using [`SameValueZero`](http://ecma-international.org/ecma-262/7.0/#sec-samevaluezero) + * for equality comparisons. + * + * @private + * @param {Object} object The object to modify. + * @param {string} key The key of the property to assign. + * @param {*} value The value to assign. + */ +function assignValue(object, key, value) { + var objValue = object[key]; + if (!(hasOwnProperty$a.call(object, key) && eq(objValue, value)) || + (value === undefined && !(key in object))) { + baseAssignValue(object, key, value); + } +} + +/** + * Copies properties of `source` to `object`. + * + * @private + * @param {Object} source The object to copy properties from. + * @param {Array} props The property identifiers to copy. + * @param {Object} [object={}] The object to copy properties to. + * @param {Function} [customizer] The function to customize copied values. + * @returns {Object} Returns `object`. + */ +function copyObject(source, props, object, customizer) { + var isNew = !object; + object || (object = {}); + + var index = -1, + length = props.length; + + while (++index < length) { + var key = props[index]; + + var newValue = customizer + ? customizer(object[key], source[key], key, object, source) + : undefined; + + if (newValue === undefined) { + newValue = source[key]; + } + if (isNew) { + baseAssignValue(object, key, newValue); + } else { + assignValue(object, key, newValue); + } + } + return object; +} + +/** + * This function is like + * [`Object.keys`](http://ecma-international.org/ecma-262/7.0/#sec-object.keys) + * except that it includes inherited enumerable properties. + * + * @private + * @param {Object} object The object to query. + * @returns {Array} Returns the array of property names. + */ +function nativeKeysIn(object) { + var result = []; + if (object != null) { + for (var key in Object(object)) { + result.push(key); + } + } + return result; +} + +/** Used for built-in method references. */ +var objectProto$e = Object.prototype; + +/** Used to check objects for own properties. */ +var hasOwnProperty$b = objectProto$e.hasOwnProperty; + +/** + * The base implementation of `_.keysIn` which doesn't treat sparse arrays as dense. + * + * @private + * @param {Object} object The object to query. + * @returns {Array} Returns the array of property names. + */ +function baseKeysIn(object) { + if (!isObject(object)) { + return nativeKeysIn(object); + } + var isProto = isPrototype(object), + result = []; + + for (var key in object) { + if (!(key == 'constructor' && (isProto || !hasOwnProperty$b.call(object, key)))) { + result.push(key); + } + } + return result; +} + +/** + * Creates an array of the own and inherited enumerable property names of `object`. + * + * **Note:** Non-object values are coerced to objects. + * + * @static + * @memberOf _ + * @since 3.0.0 + * @category Object + * @param {Object} object The object to query. + * @returns {Array} Returns the array of property names. + * @example + * + * function Foo() { + * this.a = 1; + * this.b = 2; + * } + * + * Foo.prototype.c = 3; + * + * _.keysIn(new Foo); + * // => ['a', 'b', 'c'] (iteration order is not guaranteed) + */ +function keysIn(object) { + return isArrayLike$1(object) ? arrayLikeKeys(object, true) : baseKeysIn(object); +} + +/** + * Converts `value` to a plain object flattening inherited enumerable string + * keyed properties of `value` to own properties of the plain object. + * + * @static + * @memberOf _ + * @since 3.0.0 + * @category Lang + * @param {*} value The value to convert. + * @returns {Object} Returns the converted plain object. + * @example + * + * function Foo() { + * this.b = 2; + * } + * + * Foo.prototype.c = 3; + * + * _.assign({ 'a': 1 }, new Foo); + * // => { 'a': 1, 'b': 2 } + * + * _.assign({ 'a': 1 }, _.toPlainObject(new Foo)); + * // => { 'a': 1, 'b': 2, 'c': 3 } + */ +function toPlainObject(value) { + return copyObject(value, keysIn(value)); +} + +/** + * A specialized version of `baseMerge` for arrays and objects which performs + * deep merges and tracks traversed objects enabling objects with circular + * references to be merged. + * + * @private + * @param {Object} object The destination object. + * @param {Object} source The source object. + * @param {string} key The key of the value to merge. + * @param {number} srcIndex The index of `source`. + * @param {Function} mergeFunc The function to merge values. + * @param {Function} [customizer] The function to customize assigned values. + * @param {Object} [stack] Tracks traversed source values and their merged + * counterparts. + */ +function baseMergeDeep(object, source, key, srcIndex, mergeFunc, customizer, stack) { + var objValue = safeGet(object, key), + srcValue = safeGet(source, key), + stacked = stack.get(srcValue); + + if (stacked) { + assignMergeValue(object, key, stacked); + return; + } + var newValue = customizer + ? customizer(objValue, srcValue, (key + ''), object, source, stack) + : undefined; + + var isCommon = newValue === undefined; + + if (isCommon) { + var isArr = isArray(srcValue), + isBuff = !isArr && isBuffer(srcValue), + isTyped = !isArr && !isBuff && isTypedArray(srcValue); + + newValue = srcValue; + if (isArr || isBuff || isTyped) { + if (isArray(objValue)) { + newValue = objValue; + } + else if (isArrayLikeObject(objValue)) { + newValue = copyArray(objValue); + } + else if (isBuff) { + isCommon = false; + newValue = cloneBuffer(srcValue, true); + } + else if (isTyped) { + isCommon = false; + newValue = cloneTypedArray(srcValue, true); + } + else { + newValue = []; + } + } + else if (isPlainObject(srcValue) || isArguments(srcValue)) { + newValue = objValue; + if (isArguments(objValue)) { + newValue = toPlainObject(objValue); + } + else if (!isObject(objValue) || isFunction(objValue)) { + newValue = initCloneObject(srcValue); + } + } + else { + isCommon = false; + } + } + if (isCommon) { + // Recursively merge objects and arrays (susceptible to call stack limits). + stack.set(srcValue, newValue); + mergeFunc(newValue, srcValue, srcIndex, customizer, stack); + stack['delete'](srcValue); + } + assignMergeValue(object, key, newValue); +} + +/** + * The base implementation of `_.merge` without support for multiple sources. + * + * @private + * @param {Object} object The destination object. + * @param {Object} source The source object. + * @param {number} srcIndex The index of `source`. + * @param {Function} [customizer] The function to customize merged values. + * @param {Object} [stack] Tracks traversed source values and their merged + * counterparts. + */ +function baseMerge(object, source, srcIndex, customizer, stack) { + if (object === source) { + return; + } + baseFor(source, function(srcValue, key) { + stack || (stack = new Stack); + if (isObject(srcValue)) { + baseMergeDeep(object, source, key, srcIndex, baseMerge, customizer, stack); + } + else { + var newValue = customizer + ? customizer(safeGet(object, key), srcValue, (key + ''), object, source, stack) + : undefined; + + if (newValue === undefined) { + newValue = srcValue; + } + assignMergeValue(object, key, newValue); + } + }, keysIn); +} + +/** + * A faster alternative to `Function#apply`, this function invokes `func` + * with the `this` binding of `thisArg` and the arguments of `args`. + * + * @private + * @param {Function} func The function to invoke. + * @param {*} thisArg The `this` binding of `func`. + * @param {Array} args The arguments to invoke `func` with. + * @returns {*} Returns the result of `func`. + */ +function apply(func, thisArg, args) { + switch (args.length) { + case 0: return func.call(thisArg); + case 1: return func.call(thisArg, args[0]); + case 2: return func.call(thisArg, args[0], args[1]); + case 3: return func.call(thisArg, args[0], args[1], args[2]); + } + return func.apply(thisArg, args); +} + +/* Built-in method references for those with the same name as other `lodash` methods. */ +var nativeMax = Math.max; + +/** + * A specialized version of `baseRest` which transforms the rest array. + * + * @private + * @param {Function} func The function to apply a rest parameter to. + * @param {number} [start=func.length-1] The start position of the rest parameter. + * @param {Function} transform The rest array transform. + * @returns {Function} Returns the new function. + */ +function overRest(func, start, transform) { + start = nativeMax(start === undefined ? (func.length - 1) : start, 0); + return function() { + var args = arguments, + index = -1, + length = nativeMax(args.length - start, 0), + array = Array(length); + + while (++index < length) { + array[index] = args[start + index]; + } + index = -1; + var otherArgs = Array(start + 1); + while (++index < start) { + otherArgs[index] = args[index]; + } + otherArgs[start] = transform(array); + return apply(func, this, otherArgs); + }; +} + +/** + * Creates a function that returns `value`. + * + * @static + * @memberOf _ + * @since 2.4.0 + * @category Util + * @param {*} value The value to return from the new function. + * @returns {Function} Returns the new constant function. + * @example + * + * var objects = _.times(2, _.constant({ 'a': 1 })); + * + * console.log(objects); + * // => [{ 'a': 1 }, { 'a': 1 }] + * + * console.log(objects[0] === objects[1]); + * // => true + */ +function constant(value) { + return function() { + return value; + }; +} + +/** + * The base implementation of `setToString` without support for hot loop shorting. + * + * @private + * @param {Function} func The function to modify. + * @param {Function} string The `toString` result. + * @returns {Function} Returns `func`. + */ +var baseSetToString = !defineProperty ? identity : function(func, string) { + return defineProperty(func, 'toString', { + 'configurable': true, + 'enumerable': false, + 'value': constant(string), + 'writable': true + }); +}; + +/** Used to detect hot functions by number of calls within a span of milliseconds. */ +var HOT_COUNT = 800, + HOT_SPAN = 16; + +/* Built-in method references for those with the same name as other `lodash` methods. */ +var nativeNow = Date.now; + +/** + * Creates a function that'll short out and invoke `identity` instead + * of `func` when it's called `HOT_COUNT` or more times in `HOT_SPAN` + * milliseconds. + * + * @private + * @param {Function} func The function to restrict. + * @returns {Function} Returns the new shortable function. + */ +function shortOut(func) { + var count = 0, + lastCalled = 0; + + return function() { + var stamp = nativeNow(), + remaining = HOT_SPAN - (stamp - lastCalled); + + lastCalled = stamp; + if (remaining > 0) { + if (++count >= HOT_COUNT) { + return arguments[0]; + } + } else { + count = 0; + } + return func.apply(undefined, arguments); + }; +} + +/** + * Sets the `toString` method of `func` to return `string`. + * + * @private + * @param {Function} func The function to modify. + * @param {Function} string The `toString` result. + * @returns {Function} Returns `func`. + */ +var setToString = shortOut(baseSetToString); + +/** + * The base implementation of `_.rest` which doesn't validate or coerce arguments. + * + * @private + * @param {Function} func The function to apply a rest parameter to. + * @param {number} [start=func.length-1] The start position of the rest parameter. + * @returns {Function} Returns the new function. + */ +function baseRest(func, start) { + return setToString(overRest(func, start, identity), func + ''); +} + +/** + * Checks if the given arguments are from an iteratee call. + * + * @private + * @param {*} value The potential iteratee value argument. + * @param {*} index The potential iteratee index or key argument. + * @param {*} object The potential iteratee object argument. + * @returns {boolean} Returns `true` if the arguments are from an iteratee call, + * else `false`. + */ +function isIterateeCall(value, index, object) { + if (!isObject(object)) { + return false; + } + var type = typeof index; + if (type == 'number' + ? (isArrayLike$1(object) && isIndex(index, object.length)) + : (type == 'string' && index in object) + ) { + return eq(object[index], value); + } + return false; +} + +/** + * Creates a function like `_.assign`. + * + * @private + * @param {Function} assigner The function to assign values. + * @returns {Function} Returns the new assigner function. + */ +function createAssigner(assigner) { + return baseRest(function(object, sources) { + var index = -1, + length = sources.length, + customizer = length > 1 ? sources[length - 1] : undefined, + guard = length > 2 ? sources[2] : undefined; + + customizer = (assigner.length > 3 && typeof customizer == 'function') + ? (length--, customizer) + : undefined; + + if (guard && isIterateeCall(sources[0], sources[1], guard)) { + customizer = length < 3 ? undefined : customizer; + length = 1; + } + object = Object(object); + while (++index < length) { + var source = sources[index]; + if (source) { + assigner(object, source, index, customizer); + } + } + return object; + }); +} + +/** + * This method is like `_.assign` except that it recursively merges own and + * inherited enumerable string keyed properties of source objects into the + * destination object. Source properties that resolve to `undefined` are + * skipped if a destination value exists. Array and plain object properties + * are merged recursively. Other objects and value types are overridden by + * assignment. Source objects are applied from left to right. Subsequent + * sources overwrite property assignments of previous sources. + * + * **Note:** This method mutates `object`. + * + * @static + * @memberOf _ + * @since 0.5.0 + * @category Object + * @param {Object} object The destination object. + * @param {...Object} [sources] The source objects. + * @returns {Object} Returns `object`. + * @example + * + * var object = { + * 'a': [{ 'b': 2 }, { 'd': 4 }] + * }; + * + * var other = { + * 'a': [{ 'c': 3 }, { 'e': 5 }] + * }; + * + * _.merge(object, other); + * // => { 'a': [{ 'b': 2, 'c': 3 }, { 'd': 4, 'e': 5 }] } + */ +var merge = createAssigner(function(object, source, srcIndex) { + baseMerge(object, source, srcIndex); +}); + +/** + * Creates an object with the same keys as `object` and values generated + * by running each own enumerable string keyed property of `object` thru + * `iteratee`. The iteratee is invoked with three arguments: + * (value, key, object). + * + * @static + * @memberOf _ + * @since 2.4.0 + * @category Object + * @param {Object} object The object to iterate over. + * @param {Function} [iteratee=_.identity] The function invoked per iteration. + * @returns {Object} Returns the new mapped object. + * @see _.mapKeys + * @example + * + * var users = { + * 'fred': { 'user': 'fred', 'age': 40 }, + * 'pebbles': { 'user': 'pebbles', 'age': 1 } + * }; + * + * _.mapValues(users, function(o) { return o.age; }); + * // => { 'fred': 40, 'pebbles': 1 } (iteration order is not guaranteed) + * + * // The `_.property` iteratee shorthand. + * _.mapValues(users, 'age'); + * // => { 'fred': 40, 'pebbles': 1 } (iteration order is not guaranteed) + */ +function mapValues(object, iteratee) { + var result = {}; + iteratee = baseIteratee(iteratee); + + baseForOwn(object, function(value, key, object) { + baseAssignValue(result, key, iteratee(value, key, object)); + }); + return result; +} + +/** + * The opposite of `_.mapValues`; this method creates an object with the + * same values as `object` and keys generated by running each own enumerable + * string keyed property of `object` thru `iteratee`. The iteratee is invoked + * with three arguments: (value, key, object). + * + * @static + * @memberOf _ + * @since 3.8.0 + * @category Object + * @param {Object} object The object to iterate over. + * @param {Function} [iteratee=_.identity] The function invoked per iteration. + * @returns {Object} Returns the new mapped object. + * @see _.mapValues + * @example + * + * _.mapKeys({ 'a': 1, 'b': 2 }, function(value, key) { + * return key + value; + * }); + * // => { 'a1': 1, 'b2': 2 } + */ +function mapKeys(object, iteratee) { + var result = {}; + iteratee = baseIteratee(iteratee); + + baseForOwn(object, function(value, key, object) { + baseAssignValue(result, iteratee(value, key, object), value); + }); + return result; +} + +/** Error message constants. */ +var FUNC_ERROR_TEXT$1 = 'Expected a function'; + +/** + * Creates a function that negates the result of the predicate `func`. The + * `func` predicate is invoked with the `this` binding and arguments of the + * created function. + * + * @static + * @memberOf _ + * @since 3.0.0 + * @category Function + * @param {Function} predicate The predicate to negate. + * @returns {Function} Returns the new negated function. + * @example + * + * function isEven(n) { + * return n % 2 == 0; + * } + * + * _.filter([1, 2, 3, 4, 5, 6], _.negate(isEven)); + * // => [1, 3, 5] + */ +function negate(predicate) { + if (typeof predicate != 'function') { + throw new TypeError(FUNC_ERROR_TEXT$1); + } + return function() { + var args = arguments; + switch (args.length) { + case 0: return !predicate.call(this); + case 1: return !predicate.call(this, args[0]); + case 2: return !predicate.call(this, args[0], args[1]); + case 3: return !predicate.call(this, args[0], args[1], args[2]); + } + return !predicate.apply(this, args); + }; +} + +/** + * The base implementation of `_.set`. + * + * @private + * @param {Object} object The object to modify. + * @param {Array|string} path The path of the property to set. + * @param {*} value The value to set. + * @param {Function} [customizer] The function to customize path creation. + * @returns {Object} Returns `object`. + */ +function baseSet(object, path, value, customizer) { + if (!isObject(object)) { + return object; + } + path = castPath(path, object); + + var index = -1, + length = path.length, + lastIndex = length - 1, + nested = object; + + while (nested != null && ++index < length) { + var key = toKey(path[index]), + newValue = value; + + if (index != lastIndex) { + var objValue = nested[key]; + newValue = customizer ? customizer(objValue, key, nested) : undefined; + if (newValue === undefined) { + newValue = isObject(objValue) + ? objValue + : (isIndex(path[index + 1]) ? [] : {}); + } + } + assignValue(nested, key, newValue); + nested = nested[key]; + } + return object; +} + +/** + * The base implementation of `_.pickBy` without support for iteratee shorthands. + * + * @private + * @param {Object} object The source object. + * @param {string[]} paths The property paths to pick. + * @param {Function} predicate The function invoked per property. + * @returns {Object} Returns the new object. + */ +function basePickBy(object, paths, predicate) { + var index = -1, + length = paths.length, + result = {}; + + while (++index < length) { + var path = paths[index], + value = baseGet(object, path); + + if (predicate(value, path)) { + baseSet(result, castPath(path, object), value); + } + } + return result; +} + +/* Built-in method references for those with the same name as other `lodash` methods. */ +var nativeGetSymbols$1 = Object.getOwnPropertySymbols; + +/** + * Creates an array of the own and inherited enumerable symbols of `object`. + * + * @private + * @param {Object} object The object to query. + * @returns {Array} Returns the array of symbols. + */ +var getSymbolsIn = !nativeGetSymbols$1 ? stubArray : function(object) { + var result = []; + while (object) { + arrayPush(result, getSymbols(object)); + object = getPrototype(object); + } + return result; +}; + +/** + * Creates an array of own and inherited enumerable property names and + * symbols of `object`. + * + * @private + * @param {Object} object The object to query. + * @returns {Array} Returns the array of property names and symbols. + */ +function getAllKeysIn(object) { + return baseGetAllKeys(object, keysIn, getSymbolsIn); +} + +/** + * Creates an object composed of the `object` properties `predicate` returns + * truthy for. The predicate is invoked with two arguments: (value, key). + * + * @static + * @memberOf _ + * @since 4.0.0 + * @category Object + * @param {Object} object The source object. + * @param {Function} [predicate=_.identity] The function invoked per property. + * @returns {Object} Returns the new object. + * @example + * + * var object = { 'a': 1, 'b': '2', 'c': 3 }; + * + * _.pickBy(object, _.isNumber); + * // => { 'a': 1, 'c': 3 } + */ +function pickBy(object, predicate) { + if (object == null) { + return {}; + } + var props = arrayMap(getAllKeysIn(object), function(prop) { + return [prop]; + }); + predicate = baseIteratee(predicate); + return basePickBy(object, props, function(value, path) { + return predicate(value, path[0]); + }); +} + +/** + * The opposite of `_.pickBy`; this method creates an object composed of + * the own and inherited enumerable string keyed properties of `object` that + * `predicate` doesn't return truthy for. The predicate is invoked with two + * arguments: (value, key). + * + * @static + * @memberOf _ + * @since 4.0.0 + * @category Object + * @param {Object} object The source object. + * @param {Function} [predicate=_.identity] The function invoked per property. + * @returns {Object} Returns the new object. + * @example + * + * var object = { 'a': 1, 'b': '2', 'c': 3 }; + * + * _.omitBy(object, _.isNumber); + * // => { 'b': '2' } + */ +function omitBy(object, predicate) { + return pickBy(object, negate(baseIteratee(predicate))); +} + +/** + * Performs a deep comparison between two values to determine if they are + * equivalent. + * + * **Note:** This method supports comparing arrays, array buffers, booleans, + * date objects, error objects, maps, numbers, `Object` objects, regexes, + * sets, strings, symbols, and typed arrays. `Object` objects are compared + * by their own, not inherited, enumerable properties. Functions and DOM + * nodes are compared by strict equality, i.e. `===`. + * + * @static + * @memberOf _ + * @since 0.1.0 + * @category Lang + * @param {*} value The value to compare. + * @param {*} other The other value to compare. + * @returns {boolean} Returns `true` if the values are equivalent, else `false`. + * @example + * + * var object = { 'a': 1 }; + * var other = { 'a': 1 }; + * + * _.isEqual(object, other); + * // => true + * + * object === other; + * // => false + */ +function isEqual(value, other) { + return baseIsEqual(value, other); +} + +/** + * The base implementation of methods like `_.findKey` and `_.findLastKey`, + * without support for iteratee shorthands, which iterates over `collection` + * using `eachFunc`. + * + * @private + * @param {Array|Object} collection The collection to inspect. + * @param {Function} predicate The function invoked per iteration. + * @param {Function} eachFunc The function to iterate over `collection`. + * @returns {*} Returns the found element or its key, else `undefined`. + */ +function baseFindKey(collection, predicate, eachFunc) { + var result; + eachFunc(collection, function(value, key, collection) { + if (predicate(value, key, collection)) { + result = key; + return false; + } + }); + return result; +} + +/** + * This method is like `_.find` except that it returns the key of the first + * element `predicate` returns truthy for instead of the element itself. + * + * @static + * @memberOf _ + * @since 1.1.0 + * @category Object + * @param {Object} object The object to inspect. + * @param {Function} [predicate=_.identity] The function invoked per iteration. + * @returns {string|undefined} Returns the key of the matched element, + * else `undefined`. + * @example + * + * var users = { + * 'barney': { 'age': 36, 'active': true }, + * 'fred': { 'age': 40, 'active': false }, + * 'pebbles': { 'age': 1, 'active': true } + * }; + * + * _.findKey(users, function(o) { return o.age < 40; }); + * // => 'barney' (iteration order is not guaranteed) + * + * // The `_.matches` iteratee shorthand. + * _.findKey(users, { 'age': 1, 'active': true }); + * // => 'pebbles' + * + * // The `_.matchesProperty` iteratee shorthand. + * _.findKey(users, ['active', false]); + * // => 'fred' + * + * // The `_.property` iteratee shorthand. + * _.findKey(users, 'active'); + * // => 'barney' + */ +function findKey(object, predicate) { + return baseFindKey(object, baseIteratee(predicate), baseForOwn); +} + +/** + * @param {array} arr Array for check + * @param {*} value target + * @return {boolean} true on successs + */ +var isInArray = function(arr, value) { + return !!arr.filter(function (a) { return a === value; }).length +}; + +var isObjectHasKey = function(obj, key) { + var keys = Object.keys(obj); + return isInArray(keys, key) +}; + +// just not to make my head hurt +var isEmpty = function (value) { return !isNotEmpty(value); }; + +/** + * Map the alias to their key then grab their value over + * @param {object} config the user supplied config + * @param {object} appProps the default option map + * @return {object} the config keys replaced with the appProps key by the ALIAS + */ +function mapAliasConfigKeys(config, appProps) { + // need to do two steps + // 1. take key with alias key + var aliasMap = omitBy(appProps, function (value, k) { return !value[ALIAS_KEY$1]; } ); + if (isEqual(aliasMap, {})) { + return config; + } + return mapKeys(config, function (v, key) { return findKey(aliasMap, function (o) { return o.alias === key; }) || key; }) +} + +/** + * We only want to run the valdiation against the config (user supplied) value + * but keep the defaultOptions untouch + * @param {object} config configuraton supplied by user + * @param {object} appProps the default options map + * @return {object} the pristine values that will add back to the final output + */ +function preservePristineValues(config, appProps) { + // @BUG this will filter out those that is alias key + // we need to first map the alias keys back to their full key + var _config = mapAliasConfigKeys(config, appProps); + // take the default value out + var pristineValues = mapValues( + omitBy(appProps, function (value, key) { return isObjectHasKey(_config, key); }), + function (value) { return value.args; } + ); + // for testing the value + var checkAgainstAppProps = omitBy(appProps, function (value, key) { return !isObjectHasKey(_config, key); }); + // output + return { + pristineValues: pristineValues, + checkAgainstAppProps: checkAgainstAppProps, + config: _config // passing this correct values back + } +} + +/** + * This will take the value that is ONLY need to check + * @param {object} config that one + * @param {object} props map for creating checking + * @return {object} put that arg into the args + */ +function processConfigAction(config, props) { + // debugFn('processConfigAction', props) + // v.1.2.0 add checking if its mark optional and the value is empty then pass + return mapValues(props, function (value, key) { + var obj, obj$1; + + return ( + config[key] === undefined || (value[OPTIONAL_KEY$1] === true && isEmpty(config[key])) + ? merge({}, value, ( obj = {}, obj[KEY_WORD$1] = true, obj )) + : ( obj$1 = {}, obj$1[ARGS_KEY$1] = config[key], obj$1[TYPE_KEY$1] = value[TYPE_KEY$1], obj$1[OPTIONAL_KEY$1] = value[OPTIONAL_KEY$1] || false, obj$1[ENUM_KEY$1] = value[ENUM_KEY$1] || false, obj$1[CHECKER_KEY$1] = value[CHECKER_KEY$1] || false, obj$1 ) + ); + } + ) +} + +/** + * Quick transform + * @TODO we should only validate those that is pass from the config + * and pass through those values that is from the defaultOptions + * @param {object} opts that one + * @param {object} appProps mutation configuration options + * @return {object} put that arg into the args + */ +function prepareArgsForValidation(opts, appProps) { + var ref = preservePristineValues(opts, appProps); + var config = ref.config; + var pristineValues = ref.pristineValues; + var checkAgainstAppProps = ref.checkAgainstAppProps; + // output + return [ + processConfigAction(config, checkAgainstAppProps), + pristineValues + ] +} + +// this get throw from within the checkOptions when run through the enum failed +var JsonqlEnumError = /*@__PURE__*/(function (Error) { + function JsonqlEnumError() { + var args = [], len = arguments.length; + while ( len-- ) args[ len ] = arguments[ len ]; + + Error.apply(this, args); + + this.message = args[0]; + this.detail = args[1]; + + this.className = JsonqlEnumError.name; + + if (Error.captureStackTrace) { + Error.captureStackTrace(this, JsonqlEnumError); + } + } + + if ( Error ) JsonqlEnumError.__proto__ = Error; + JsonqlEnumError.prototype = Object.create( Error && Error.prototype ); + JsonqlEnumError.prototype.constructor = JsonqlEnumError; + + var staticAccessors = { name: { configurable: true } }; + + staticAccessors.name.get = function () { + return 'JsonqlEnumError'; + }; + + Object.defineProperties( JsonqlEnumError, staticAccessors ); + + return JsonqlEnumError; +}(Error)); + +// this will throw from inside the checkOptions +var JsonqlTypeError = /*@__PURE__*/(function (Error) { + function JsonqlTypeError() { + var args = [], len = arguments.length; + while ( len-- ) args[ len ] = arguments[ len ]; + + Error.apply(this, args); + + this.message = args[0]; + this.detail = args[1]; + + this.className = JsonqlTypeError.name; + + if (Error.captureStackTrace) { + Error.captureStackTrace(this, JsonqlTypeError); + } + } + + if ( Error ) JsonqlTypeError.__proto__ = Error; + JsonqlTypeError.prototype = Object.create( Error && Error.prototype ); + JsonqlTypeError.prototype.constructor = JsonqlTypeError; + + var staticAccessors = { name: { configurable: true } }; + + staticAccessors.name.get = function () { + return 'JsonqlTypeError'; + }; + + Object.defineProperties( JsonqlTypeError, staticAccessors ); + + return JsonqlTypeError; +}(Error)); + +// allow supply a custom checker function +// if that failed then we throw this error +var JsonqlCheckerError = /*@__PURE__*/(function (Error) { + function JsonqlCheckerError() { + var args = [], len = arguments.length; + while ( len-- ) args[ len ] = arguments[ len ]; + + Error.apply(this, args); + this.message = args[0]; + this.detail = args[1]; + + this.className = JsonqlCheckerError.name; + + if (Error.captureStackTrace) { + Error.captureStackTrace(this, JsonqlCheckerError); + } + } + + if ( Error ) JsonqlCheckerError.__proto__ = Error; + JsonqlCheckerError.prototype = Object.create( Error && Error.prototype ); + JsonqlCheckerError.prototype.constructor = JsonqlCheckerError; + + var staticAccessors = { name: { configurable: true } }; + + staticAccessors.name.get = function () { + return 'JsonqlCheckerError'; + }; + + Object.defineProperties( JsonqlCheckerError, staticAccessors ); + + return JsonqlCheckerError; +}(Error)); + +// breaking the whole thing up to see what cause the multiple calls issue + +// import debug from 'debug'; +// const debugFn = debug('jsonql-params-validator:options:validation') + +/** + * just make sure it returns an array to use + * @param {*} arg input + * @return {array} output + */ +var toArray = function (arg) { return checkIsArray(arg) ? arg : [arg]; }; + +/** + * DIY in array + * @param {array} arr to check against + * @param {*} value to check + * @return {boolean} true on OK + */ +var inArray = function (arr, value) { return ( + !!arr.filter(function (v) { return v === value; }).length +); }; + +/** + * break out to make the code easier to read + * @param {object} value to process + * @param {function} cb the validateSync + * @return {array} empty on success + */ +function validateHandler$1(value, cb) { + var obj; + + // cb is the validateSync methods + var args = [ + [ value[ARGS_KEY$1] ], + [( obj = {}, obj[TYPE_KEY$1] = toArray(value[TYPE_KEY$1]), obj[OPTIONAL_KEY$1] = value[OPTIONAL_KEY$1], obj )] + ]; + // debugFn('validateHandler', args) + return Reflect.apply(cb, null, args) +} + +/** + * Check against the enum value if it's provided + * @param {*} value to check + * @param {*} enumv to check against if it's not false + * @return {boolean} true on OK + */ +var enumHandler = function (value, enumv) { + if (checkIsArray(enumv)) { + return inArray(enumv, value) + } + return true +}; + +/** + * Allow passing a function to check the value + * There might be a problem here if the function is incorrect + * and that will makes it hard to debug what is going on inside + * @TODO there could be a few feature add to this one under different circumstance + * @param {*} value to check + * @param {function} checker for checking + */ +var checkerHandler = function (value, checker) { + try { + return isFunction(checker) ? checker.apply(null, [value]) : false + } catch (e) { + return false + } +}; + +/** + * Taken out from the runValidaton this only validate the required values + * @param {array} args from the config2argsAction + * @param {function} cb validateSync + * @return {array} of configuration values + */ +function runValidationAction(cb) { + return function (value, key) { + // debugFn('runValidationAction', key, value) + if (value[KEY_WORD$1]) { + return value[ARGS_KEY$1] + } + var check = validateHandler$1(value, cb); + if (check.length) { + // log('runValidationAction', key, value) + throw new JsonqlTypeError(key, check) + } + if (value[ENUM_KEY$1] !== false && !enumHandler(value[ARGS_KEY$1], value[ENUM_KEY$1])) { + // log(ENUM_KEY, value[ENUM_KEY]) + throw new JsonqlEnumError(key) + } + if (value[CHECKER_KEY$1] !== false && !checkerHandler(value[ARGS_KEY$1], value[CHECKER_KEY$1])) { + // log(CHECKER_KEY, value[CHECKER_KEY]) + throw new JsonqlCheckerError(key) + } + return value[ARGS_KEY$1] + } +} + +/** + * @param {object} args from the config2argsAction + * @param {function} cb validateSync + * @return {object} of configuration values + */ +function runValidation(args, cb) { + var argsForValidate = args[0]; + var pristineValues = args[1]; + // turn the thing into an array and see what happen here + // debugFn('_args', argsForValidate) + var result = mapValues(argsForValidate, runValidationAction(cb)); + return merge(result, pristineValues) +} + +/// this is port back from the client to share across all projects + +// import debug from 'debug' +// const debugFn = debug('jsonql-params-validator:check-options-async') + +/** + * Quick transform + * @param {object} config that one + * @param {object} appProps mutation configuration options + * @return {object} put that arg into the args + */ +var configToArgs = function (config, appProps) { + return Promise.resolve( + prepareArgsForValidation(config, appProps) + ) +}; + +/** + * @param {object} config user provide configuration option + * @param {object} appProps mutation configuration options + * @param {object} constProps the immutable configuration options + * @param {function} cb the validateSync method + * @return {object} Promise resolve merge config object + */ +function checkOptionsAsync(config, appProps, constProps, cb) { + if ( config === void 0 ) config = {}; + + return configToArgs(config, appProps) + .then(function (args1) { return runValidation(args1, cb); }) + // next if every thing good then pass to final merging + .then(function (args2) { return merge({}, args2, constProps); }) +} + +// create function to construct the config entry so we don't need to keep building object +// import checkIsBoolean from '../boolean' +// import debug from 'debug'; +// const debugFn = debug('jsonql-params-validator:construct-config'); +/** + * @param {*} args value + * @param {string} type for value + * @param {boolean} [optional=false] + * @param {boolean|array} [enumv=false] + * @param {boolean|function} [checker=false] + * @return {object} config entry + */ +function constructConfig(args, type, optional, enumv, checker, alias) { + if ( optional === void 0 ) optional=false; + if ( enumv === void 0 ) enumv=false; + if ( checker === void 0 ) checker=false; + if ( alias === void 0 ) alias=false; + + var base = {}; + base[ARGS_KEY] = args; + base[TYPE_KEY] = type; + if (optional === true) { + base[OPTIONAL_KEY] = true; + } + if (checkIsArray(enumv)) { + base[ENUM_KEY] = enumv; + } + if (isFunction(checker)) { + base[CHECKER_KEY] = checker; + } + if (isString(alias)) { + base[ALIAS_KEY] = alias; + } + return base +} + +// export also create wrapper methods + +/** + * This has a different interface + * @param {*} value to supply + * @param {string|array} type for checking + * @param {object} params to map against the config check + * @param {array} params.enumv NOT enum + * @param {boolean} params.optional false then nothing + * @param {function} params.checker need more work on this one later + * @param {string} params.alias mostly for cmd + */ +var createConfig = function (value, type, params) { + if ( params === void 0 ) params = {}; + + // Note the enumv not ENUM + // const { enumv, optional, checker, alias } = params; + // let args = [value, type, optional, enumv, checker, alias]; + var o = params[OPTIONAL_KEY]; + var e = params[ENUM_KEY]; + var c = params[CHECKER_KEY]; + var a = params[ALIAS_KEY]; + return constructConfig.apply(null, [value, type, o, e, c, a]) +}; + +/** + * construct the actual end user method, rename with prefix get since 1.5.2 + * @param {function} validateSync validation method + * @return {function} for performaning the actual valdiation + */ +var getCheckConfigAsync = function(validateSync) { + /** + * We recreate the method here to avoid the circlar import + * @param {object} config user supply configuration + * @param {object} appProps mutation options + * @param {object} [constantProps={}] optional: immutation options + * @return {object} all checked configuration + */ + return function(config, appProps, constantProps) { + if ( constantProps === void 0 ) constantProps= {}; + + return checkOptionsAsync(config, appProps, constantProps, validateSync) + } +}; + +// export +var isString$1 = checkIsString; +var validateAsync$1 = validateAsync; + +var createConfig$1 = createConfig; +// construct the final output 1.5.2 +var checkConfigAsync = getCheckConfigAsync(validateSync); + +// move the get logger stuff here + +// it does nothing +var dummyLogger = function () {}; + +/** + * re-use the debugOn prop to control this log method + * @param {object} opts configuration + * @return {function} the log function + */ +var getLogger = function (opts) { + var debugOn = opts.debugOn; + if (debugOn) { + return function () { + var args = [], len = arguments.length; + while ( len-- ) args[ len ] = arguments[ len ]; + + Reflect.apply(console.info, console, ['[jsonql-ws-client-core]' ].concat( args)); + } + } + return dummyLogger +}; + +/** + * Make sure there is a log method + * @param {object} opts configuration + * @return {object} opts + */ +var getLogFn = function (opts) { + var log = opts.log; // 1.3.9 if we pass a log method here then we use this + if (!log || typeof log !== 'function') { + return getLogger(opts) + } + opts.log('---> getLogFn user supplied log function <---', opts); + return log +}; + +// group all the repetitive message here + +var TAKEN_BY_OTHER_TYPE_ERR = 'You are trying to register an event already been taken by other type:'; + +// Create two WeakMap store as a private keys +var NB_EVENT_SERVICE_PRIVATE_STORE = new WeakMap(); +var NB_EVENT_SERVICE_PRIVATE_LAZY = new WeakMap(); + +/** + * generate a 32bit hash based on the function.toString() + * _from http://stackoverflow.com/questions/7616461/generate-a-hash-_from-string-in-javascript-jquery + * @param {string} s the converted to string function + * @return {string} the hashed function string + */ +function hashCode(s) { + return s.split("").reduce(function(a,b){a=((a<<5)-a)+b.charCodeAt(0);return a&a},0) +} + +/** + * wrapper to make sure it string + * @param {*} input whatever + * @return {string} output + */ +function hashCode2Str(s) { + return hashCode(s) + '' +} + +/** + * Just check if a pattern is an RegExp object + * @param {*} pat whatever + * @return {boolean} false when its not + */ +function isRegExp(pat) { + return pat instanceof RegExp +} + +/** + * check if its string + * @param {*} arg whatever + * @return {boolean} false when it's not + */ +function isString$2(arg) { + return typeof arg === 'string' +} + +/** + * Find from the array by matching the pattern + * @param {*} pattern a string or RegExp object + * @return {object} regex object or false when we can not id the input + */ +function getRegex(pattern) { + switch (true) { + case isRegExp(pattern) === true: + return pattern + case isString$2(pattern) === true: + return new RegExp(pattern) + default: + return false + } +} + +// making all the functionality on it's own + +var SuspendClass = function SuspendClass() { + // suspend, release and queue + this.__suspend_state__ = null; + // to do this proper we don't use a new prop to hold the event name pattern + this.__pattern__ = null; + this.queueStore = new Set(); +}; + +var prototypeAccessors = { $queues: { configurable: true } }; + +/** + * start suspend + * @return {void} + */ +SuspendClass.prototype.$suspend = function $suspend () { + this.logger("---> SUSPEND ALL OPS <---"); + this.__suspend__(true); +}; + +/** + * release the queue + * @return {void} + */ +SuspendClass.prototype.$release = function $release () { + this.logger("---> RELEASE SUSPENDED QUEUE <---"); + this.__suspend__(false); +}; + +/** + * suspend event by pattern + * @param {string} pattern the pattern search matches the event name + * @return {void} + */ +SuspendClass.prototype.$suspendEvent = function $suspendEvent (pattern) { + var regex = getRegex(pattern); + if (isRegExp(regex)) { + this.__pattern__ = regex; + return this.$suspend() + } + throw new Error(("We expect a pattern variable to be string or RegExp, but we got \"" + (typeof regex) + "\" instead")) +}; + +/** + * queuing call up when it's in suspend mode + * @param {string} evt the event name + * @param {*} args unknown number of arguments + * @return {boolean} true when added or false when it's not + */ +SuspendClass.prototype.$queue = function $queue (evt) { + var args = [], len = arguments.length - 1; + while ( len-- > 0 ) args[ len ] = arguments[ len + 1 ]; + + this.logger('($queue) get called'); + if (this.__suspend_state__ === true) { + if (isRegExp(this.__pattern__)) { // it's better then check if its not null + // check the pattern and decide if we want to suspend it or not + var found = this.__pattern__.test(evt); + if (!found) { + return false + } + } + this.logger('($queue) added to $queue', args); + // @TODO there shouldn't be any duplicate, but how to make sure? + this.queueStore.add([evt].concat(args)); + // return this.queueStore.size + } + return !!this.__suspend_state__ +}; + +/** + * a getter to get all the store queue + * @return {array} Set turn into Array before return + */ +prototypeAccessors.$queues.get = function () { + var size = this.queueStore.size; + this.logger('($queues)', ("size: " + size)); + if (size > 0) { + return Array.from(this.queueStore) + } + return [] +}; + +/** + * to set the suspend and check if it's boolean value + * @param {boolean} value to trigger + */ +SuspendClass.prototype.__suspend__ = function __suspend__ (value) { + if (typeof value === 'boolean') { + var lastValue = this.__suspend_state__; + this.__suspend_state__ = value; + this.logger(("($suspend) Change from \"" + lastValue + "\" --> \"" + value + "\"")); + if (lastValue === true && value === false) { + this.__release__(); + } + } else { + throw new Error(("$suspend only accept Boolean value! we got " + (typeof value))) + } +}; + +/** + * Release the queue + * @return {int} size if any + */ +SuspendClass.prototype.__release__ = function __release__ () { + var this$1 = this; + + var size = this.queueStore.size; + var pattern = this.__pattern__; + this.__pattern__ = null; + this.logger(("(release) was called with " + size + (pattern ? ' for "' + pattern + '"': '') + " item" + (size > 1 ? 's' : ''))); + if (size > 0) { + var queue = Array.from(this.queueStore); + this.queueStore.clear(); + this.logger('(release queue)', queue); + queue.forEach(function (args) { + this$1.logger(args); + Reflect.apply(this$1.$trigger, this$1, args); + }); + this.logger(("Release size " + (this.queueStore.size))); + } + + return size +}; + +Object.defineProperties( SuspendClass.prototype, prototypeAccessors ); + +// break up the main file because its getting way too long + +var StoreService = /*@__PURE__*/(function (SuspendClass) { + function StoreService(config) { + if ( config === void 0 ) config = {}; + + SuspendClass.call(this); + if (config.logger && typeof config.logger === 'function') { + this.logger = config.logger; + } + this.keep = config.keep; + // for the $done setter + this.result = config.keep ? [] : null; + // we need to init the store first otherwise it could be a lot of checking later + this.normalStore = new Map(); + this.lazyStore = new Map(); + } + + if ( SuspendClass ) StoreService.__proto__ = SuspendClass; + StoreService.prototype = Object.create( SuspendClass && SuspendClass.prototype ); + StoreService.prototype.constructor = StoreService; + + var prototypeAccessors = { normalStore: { configurable: true },lazyStore: { configurable: true } }; + + /** + * validate the event name(s) + * @param {string[]} evt event name + * @return {boolean} true when OK + */ + StoreService.prototype.validateEvt = function validateEvt () { + var this$1 = this; + var evt = [], len = arguments.length; + while ( len-- ) evt[ len ] = arguments[ len ]; + + evt.forEach(function (e) { + if (!isString$2(e)) { + this$1.logger('(validateEvt)', e); + throw new Error(("Event name must be string type! we got " + (typeof e))) + } + }); + return true + }; + + /** + * Simple quick check on the two main parameters + * @param {string} evt event name + * @param {function} callback function to call + * @return {boolean} true when OK + */ + StoreService.prototype.validate = function validate (evt, callback) { + if (this.validateEvt(evt)) { + if (typeof callback === 'function') { + return true + } + } + throw new Error(("callback required to be function type! we got " + (typeof callback))) + }; + + /** + * Check if this type is correct or not added in V1.5.0 + * @param {string} type for checking + * @return {boolean} true on OK + */ + StoreService.prototype.validateType = function validateType (type) { + this.validateEvt(type); + var types = ['on', 'only', 'once', 'onlyOnce']; + return !!types.filter(function (t) { return type === t; }).length + }; + + /** + * Run the callback + * @param {function} callback function to execute + * @param {array} payload for callback + * @param {object} ctx context or null + * @return {void} the result store in $done + */ + StoreService.prototype.run = function run (callback, payload, ctx) { + this.logger('(run) callback:', callback, 'payload:', payload, 'context:', ctx); + this.$done = Reflect.apply(callback, ctx, this.toArray(payload)); + }; + + /** + * Take the content out and remove it from store id by the name + * @param {string} evt event name + * @param {string} [storeName = lazyStore] name of store + * @return {object|boolean} content or false on not found + */ + StoreService.prototype.takeFromStore = function takeFromStore (evt, storeName) { + if ( storeName === void 0 ) storeName = 'lazyStore'; + + var store = this[storeName]; // it could be empty at this point + if (store) { + this.logger('(takeFromStore)', storeName, store); + if (store.has(evt)) { + var content = store.get(evt); + this.logger(("(takeFromStore) has \"" + evt + "\""), content); + store.delete(evt); + return content + } + return false + } + throw new Error(("\"" + storeName + "\" is not supported!")) + }; + + /** + * This was part of the $get. We take it out + * so we could use a regex to remove more than one event + * @param {object} store the store to return from + * @param {string} evt event name + * @param {boolean} full return just the callback or everything + * @return {array|boolean} false when not found + */ + StoreService.prototype.findFromStore = function findFromStore (evt, store, full) { + if ( full === void 0 ) full = false; + + if (store.has(evt)) { + return Array + .from(store.get(evt)) + .map( function (l) { + if (full) { + return l + } + var key = l[0]; + var callback = l[1]; + return callback + }) + } + return false + }; + + /** + * Similar to the findFromStore, but remove + * @param {string} evt event name + * @param {object} store the store to remove from + * @return {boolean} false when not found + */ + StoreService.prototype.removeFromStore = function removeFromStore (evt, store) { + if (store.has(evt)) { + this.logger('($off)', evt); + store.delete(evt); + return true + } + return false + }; + + /** + * The add to store step is similar so make it generic for resuse + * @param {object} store which store to use + * @param {string} evt event name + * @param {spread} args because the lazy store and normal store store different things + * @return {array} store and the size of the store + */ + StoreService.prototype.addToStore = function addToStore (store, evt) { + var args = [], len = arguments.length - 2; + while ( len-- > 0 ) args[ len ] = arguments[ len + 2 ]; + + var fnSet; + if (store.has(evt)) { + this.logger(("(addToStore) \"" + evt + "\" existed")); + fnSet = store.get(evt); + } else { + this.logger(("(addToStore) create new Set for \"" + evt + "\"")); + // this is new + fnSet = new Set(); + } + // lazy only store 2 items - this is not the case in V1.6.0 anymore + // we need to check the first parameter is string or not + if (args.length > 2) { + if (Array.isArray(args[0])) { // lazy store + // check if this type of this event already register in the lazy store + var t = args[2]; + if (!this.checkTypeInLazyStore(evt, t)) { + fnSet.add(args); + } + } else { + if (!this.checkContentExist(args, fnSet)) { + this.logger("(addToStore) insert new", args); + fnSet.add(args); + } + } + } else { // add straight to lazy store + fnSet.add(args); + } + store.set(evt, fnSet); + return [store, fnSet.size] + }; + + /** + * @param {array} args for compare + * @param {object} fnSet A Set to search from + * @return {boolean} true on exist + */ + StoreService.prototype.checkContentExist = function checkContentExist (args, fnSet) { + var list = Array.from(fnSet); + return !!list.filter(function (li) { + var hash = li[0]; + return hash === args[0] + }).length + }; + + /** + * get the existing type to make sure no mix type add to the same store + * @param {string} evtName event name + * @param {string} type the type to check + * @return {boolean} true you can add, false then you can't add this type + */ + StoreService.prototype.checkTypeInStore = function checkTypeInStore (evtName, type) { + this.validateEvt(evtName, type); + var all = this.$get(evtName, true); + if (all === false) { + // pristine it means you can add + return true + } + // it should only have ONE type in ONE event store + return !all.filter(function (list) { + var t = list[3]; + return type !== t + }).length + }; + + /** + * This is checking just the lazy store because the structure is different + * therefore we need to use a new method to check it + */ + StoreService.prototype.checkTypeInLazyStore = function checkTypeInLazyStore (evtName, type) { + this.validateEvt(evtName, type); + var store = this.lazyStore.get(evtName); + this.logger('(checkTypeInLazyStore)', store); + if (store) { + return !!Array + .from(store) + .filter(function (li) { + var t = li[2]; + return t !== type + }).length + } + return false + }; + + /** + * wrapper to re-use the addToStore, + * V1.3.0 add extra check to see if this type can add to this evt + * @param {string} evt event name + * @param {string} type on or once + * @param {function} callback function + * @param {object} context the context the function execute in or null + * @return {number} size of the store + */ + StoreService.prototype.addToNormalStore = function addToNormalStore (evt, type, callback, context) { + if ( context === void 0 ) context = null; + + this.logger(("(addToNormalStore) try to add \"" + type + "\" --> \"" + evt + "\" to normal store")); + // @TODO we need to check the existing store for the type first! + if (this.checkTypeInStore(evt, type)) { + this.logger('(addToNormalStore)', ("\"" + type + "\" --> \"" + evt + "\" can add to normal store")); + var key = this.hashFnToKey(callback); + var args = [this.normalStore, evt, key, callback, context, type]; + var ref = Reflect.apply(this.addToStore, this, args); + var _store = ref[0]; + var size = ref[1]; + this.normalStore = _store; + return size + } + return false + }; + + /** + * Add to lazy store this get calls when the callback is not register yet + * so we only get a payload object or even nothing + * @param {string} evt event name + * @param {array} payload of arguments or empty if there is none + * @param {object} [context=null] the context the callback execute in + * @param {string} [type=false] register a type so no other type can add to this evt + * @return {number} size of the store + */ + StoreService.prototype.addToLazyStore = function addToLazyStore (evt, payload, context, type) { + if ( payload === void 0 ) payload = []; + if ( context === void 0 ) context = null; + if ( type === void 0 ) type = false; + + // this is add in V1.6.0 + // when there is type then we will need to check if this already added in lazy store + // and no other type can add to this lazy store + var args = [this.lazyStore, evt, this.toArray(payload), context]; + if (type) { + args.push(type); + } + var ref = Reflect.apply(this.addToStore, this, args); + var _store = ref[0]; + var size = ref[1]; + this.lazyStore = _store; + this.logger(("(addToLazyStore) size: " + size)); + return size + }; + + /** + * make sure we store the argument correctly + * @param {*} arg could be array + * @return {array} make sured + */ + StoreService.prototype.toArray = function toArray (arg) { + return Array.isArray(arg) ? arg : [arg] + }; + + /** + * setter to store the Set in private + * @param {object} obj a Set + */ + prototypeAccessors.normalStore.set = function (obj) { + NB_EVENT_SERVICE_PRIVATE_STORE.set(this, obj); + }; + + /** + * @return {object} Set object + */ + prototypeAccessors.normalStore.get = function () { + return NB_EVENT_SERVICE_PRIVATE_STORE.get(this) + }; + + /** + * setter to store the Set in lazy store + * @param {object} obj a Set + */ + prototypeAccessors.lazyStore.set = function (obj) { + NB_EVENT_SERVICE_PRIVATE_LAZY.set(this , obj); + }; + + /** + * @return {object} the lazy store Set + */ + prototypeAccessors.lazyStore.get = function () { + return NB_EVENT_SERVICE_PRIVATE_LAZY.get(this) + }; + + /** + * generate a hashKey to identify the function call + * The build-in store some how could store the same values! + * @param {function} fn the converted to string function + * @return {string} hashKey + */ + StoreService.prototype.hashFnToKey = function hashFnToKey (fn) { + return hashCode2Str(fn.toString()) + }; + + Object.defineProperties( StoreService.prototype, prototypeAccessors ); + + return StoreService; +}(SuspendClass)); + +// The top level +// export +var EventService = /*@__PURE__*/(function (StoreService) { + function EventService(config) { + if ( config === void 0 ) config = {}; + + StoreService.call(this, config); + } + + if ( StoreService ) EventService.__proto__ = StoreService; + EventService.prototype = Object.create( StoreService && StoreService.prototype ); + EventService.prototype.constructor = EventService; + + var prototypeAccessors = { $name: { configurable: true },is: { configurable: true },$done: { configurable: true } }; + + /** + * logger function for overwrite + */ + EventService.prototype.logger = function logger () {}; + + // for id if the instance is this class + prototypeAccessors.$name.get = function () { + return 'to1source-event' + }; + + // take this down in the next release + prototypeAccessors.is.get = function () { + return this.$name + }; + + ////////////////////////// + // PUBLIC METHODS // + ////////////////////////// + + /** + * Register your evt handler, note we don't check the type here, + * we expect you to be sensible and know what you are doing. + * @param {string} evt name of event + * @param {function} callback bind method --> if it's array or not + * @param {object} [context=null] to execute this call in + * @return {number} the size of the store + */ + EventService.prototype.$on = function $on (evt , callback , context) { + var this$1 = this; + if ( context === void 0 ) context = null; + + var type = 'on'; + this.validate(evt, callback); + // first need to check if this evt is in lazy store + var lazyStoreContent = this.takeFromStore(evt); + // this is normal register first then call later + if (lazyStoreContent === false) { + this.logger(("($on) \"" + evt + "\" is not in lazy store")); + // @TODO we need to check if there was other listener to this + // event and are they the same type then we could solve that + // register the different type to the same event name + return this.addToNormalStore(evt, type, callback, context) + } + this.logger(("($on) " + evt + " found in lazy store")); + // this is when they call $trigger before register this callback + var size = 0; + lazyStoreContent.forEach(function (content) { + var payload = content[0]; + var ctx = content[1]; + var t = content[2]; + if (t && t !== type) { + throw new Error((TAKEN_BY_OTHER_TYPE_ERR + " " + t)) + } + this$1.logger("($on)", ("call run \"" + evt + "\"")); + this$1.run(callback, payload, context || ctx); + size += this$1.addToNormalStore(evt, type, callback, context || ctx); + }); + + this.logger(("($on) return size " + size)); + return size + }; + + /** + * once only registered it once, there is no overwrite option here + * @NOTE change in v1.3.0 $once can add multiple listeners + * but once the event fired, it will remove this event (see $only) + * @param {string} evt name + * @param {function} callback to execute + * @param {object} [context=null] the handler execute in + * @return {boolean} result + */ + EventService.prototype.$once = function $once (evt , callback , context) { + if ( context === void 0 ) context = null; + + this.validate(evt, callback); + var type = 'once'; + var lazyStoreContent = this.takeFromStore(evt); + // this is normal register before call $trigger + var nStore = this.normalStore; + if (lazyStoreContent === false) { + this.logger(("($once) \"" + evt + "\" is not in the lazy store")); + // v1.3.0 $once now allow to add multiple listeners + return this.addToNormalStore(evt, type, callback, context) + } else { + // now this is the tricky bit + // there is a potential bug here that cause by the developer + // if they call $trigger first, the lazy won't know it's a once call + // so if in the middle they register any call with the same evt name + // then this $once call will be fucked - add this to the documentation + this.logger('($once)', lazyStoreContent); + var list = Array.from(lazyStoreContent); + // should never have more than 1 + var ref = list[0]; + var payload = ref[0]; + var ctx = ref[1]; + var t = ref[2]; + if (t && t !== type) { + throw new Error((TAKEN_BY_OTHER_TYPE_ERR + " " + t)) + } + this.logger('($once)', ("call run \"" + evt + "\"")); + this.run(callback, payload, context || ctx); + // remove this evt from store + this.$off(evt); + } + }; + + /** + * This one event can only bind one callbackback + * @param {string} evt event name + * @param {function} callback event handler + * @param {object} [context=null] the context the event handler execute in + * @return {boolean} true bind for first time, false already existed + */ + EventService.prototype.$only = function $only (evt, callback, context) { + var this$1 = this; + if ( context === void 0 ) context = null; + + this.validate(evt, callback); + var type = 'only'; + var added = false; + var lazyStoreContent = this.takeFromStore(evt); + // this is normal register before call $trigger + var nStore = this.normalStore; + if (!nStore.has(evt)) { + this.logger(("($only) \"" + evt + "\" add to normalStore")); + added = this.addToNormalStore(evt, type, callback, context); + } + if (lazyStoreContent !== false) { + // there are data store in lazy store + this.logger(("($only) \"" + evt + "\" found data in lazy store to execute")); + var list = Array.from(lazyStoreContent); + // $only allow to trigger this multiple time on the single handler + list.forEach( function (li) { + var payload = li[0]; + var ctx = li[1]; + var t = li[2]; + if (t && t !== type) { + throw new Error((TAKEN_BY_OTHER_TYPE_ERR + " " + t)) + } + this$1.logger(("($only) call run \"" + evt + "\"")); + this$1.run(callback, payload, context || ctx); + }); + } + return added + }; + + /** + * $only + $once this is because I found a very subtile bug when we pass a + * resolver, rejecter - and it never fire because that's OLD added in v1.4.0 + * @param {string} evt event name + * @param {function} callback to call later + * @param {object} [context=null] exeucte context + * @return {void} + */ + EventService.prototype.$onlyOnce = function $onlyOnce (evt, callback, context) { + if ( context === void 0 ) context = null; + + this.validate(evt, callback); + var type = 'onlyOnce'; + var added = false; + var lazyStoreContent = this.takeFromStore(evt); + // this is normal register before call $trigger + var nStore = this.normalStore; + if (!nStore.has(evt)) { + this.logger(("($onlyOnce) \"" + evt + "\" add to normalStore")); + added = this.addToNormalStore(evt, type, callback, context); + } + if (lazyStoreContent !== false) { + // there are data store in lazy store + this.logger('($onlyOnce)', lazyStoreContent); + var list = Array.from(lazyStoreContent); + // should never have more than 1 + var ref = list[0]; + var payload = ref[0]; + var ctx = ref[1]; + var t = ref[2]; + if (t && t !== 'onlyOnce') { + throw new Error((TAKEN_BY_OTHER_TYPE_ERR + " " + t)) + } + this.logger(("($onlyOnce) call run \"" + evt + "\"")); + this.run(callback, payload, context || ctx); + // remove this evt from store + this.$off(evt); + } + return added + }; + + /** + * This is a shorthand of $off + $on added in V1.5.0 + * @param {string} evt event name + * @param {function} callback to exeucte + * @param {object} [context = null] or pass a string as type + * @param {string} [type=on] what type of method to replace + * @return {*} + */ + EventService.prototype.$replace = function $replace (evt, callback, context, type) { + if ( context === void 0 ) context = null; + if ( type === void 0 ) type = 'on'; + + if (this.validateType(type)) { + this.$off(evt); + var method = this['$' + type]; + this.logger("($replace)", evt, callback); + return Reflect.apply(method, this, [evt, callback, context]) + } + throw new Error((type + " is not supported!")) + }; + + /** + * trigger the event + * @param {string} evt name NOT allow array anymore! + * @param {mixed} [payload = []] pass to fn + * @param {object|string} [context = null] overwrite what stored + * @param {string} [type=false] if pass this then we need to add type to store too + * @return {number} if it has been execute how many times + */ + EventService.prototype.$trigger = function $trigger (evt , payload , context, type) { + if ( payload === void 0 ) payload = []; + if ( context === void 0 ) context = null; + if ( type === void 0 ) type = false; + + this.validateEvt(evt); + var found = 0; + // first check the normal store + var nStore = this.normalStore; + this.logger('($trigger) normalStore', nStore); + if (nStore.has(evt)) { + this.logger(("($trigger) \"" + evt + "\" found")); + // @1.8.0 to add the suspend queue + var added = this.$queue(evt, payload, context, type); + if (added) { + this.logger(("($trigger) Currently suspended \"" + evt + "\" added to queue, nothing executed. Exit now.")); + return false // not executed + } + var nSet = Array.from(nStore.get(evt)); + var ctn = nSet.length; + var hasOnce = false; + for (var i=0; i < ctn; ++i) { + ++found; + // this.logger('found', found) + var ref = nSet[i]; + var _ = ref[0]; + var callback = ref[1]; + var ctx = ref[2]; + var type$1 = ref[3]; + this.logger(("($trigger) call run for " + evt)); + this.run(callback, payload, context || ctx); + if (type$1 === 'once' || type$1 === 'onlyOnce') { + hasOnce = true; + } + } + if (hasOnce) { + nStore.delete(evt); + } + return found + } + // now this is not register yet + this.addToLazyStore(evt, payload, context, type); + return found + }; + + /** + * this is an alias to the $trigger + * @NOTE breaking change in V1.6.0 we swap the parameter aroun + * @NOTE breaking change: v1.9.1 it return an function to accept the params as spread + * @param {string} evt event name + * @param {string} type of call + * @param {object} context what context callback execute in + * @return {*} from $trigger + */ + EventService.prototype.$call = function $call (evt, type, context) { + if ( type === void 0 ) type = false; + if ( context === void 0 ) context = null; + + var ctx = this; + + return function () { + var args = [], len = arguments.length; + while ( len-- ) args[ len ] = arguments[ len ]; + + var _args = [evt, args, context, type]; + return Reflect.apply(ctx.$trigger, ctx, _args) + } + }; + + /** + * remove the evt from all the stores + * @param {string} evt name + * @return {boolean} true actually delete something + */ + EventService.prototype.$off = function $off (evt) { + var this$1 = this; + + // @TODO we will allow a regex pattern to mass remove event + this.validateEvt(evt); + var stores = [ this.lazyStore, this.normalStore ]; + + return !!stores + .filter(function (store) { return store.has(evt); }) + .map(function (store) { return this$1.removeFromStore(evt, store); }) + .length + }; + + /** + * return all the listener bind to that event name + * @param {string} evtName event name + * @param {boolean} [full=false] if true then return the entire content + * @return {array|boolean} listerner(s) or false when not found + */ + EventService.prototype.$get = function $get (evt, full) { + if ( full === void 0 ) full = false; + + // @TODO should we allow the same Regex to search for all? + this.validateEvt(evt); + var store = this.normalStore; + return this.findFromStore(evt, store, full) + }; + + /** + * store the return result from the run + * @param {*} value whatever return from callback + */ + prototypeAccessors.$done.set = function (value) { + this.logger('($done) set value: ', value); + if (this.keep) { + this.result.push(value); + } else { + this.result = value; + } + }; + + /** + * @TODO is there any real use with the keep prop? + * getter for $done + * @return {*} whatever last store result + */ + prototypeAccessors.$done.get = function () { + this.logger('($done) get result:', this.result); + if (this.keep) { + return this.result[this.result.length - 1] + } + return this.result + }; + + /** + * Take a look inside the stores + * @param {number|null} idx of the store, null means all + * @return {void} + */ + EventService.prototype.$debug = function $debug (idx) { + var this$1 = this; + if ( idx === void 0 ) idx = null; + + var names = ['lazyStore', 'normalStore']; + var stores = [this.lazyStore, this.normalStore]; + if (stores[idx]) { + this.logger(names[idx], stores[idx]); + } else { + stores.map(function (store, i) { + this$1.logger(names[i], store); + }); + } + }; + + Object.defineProperties( EventService.prototype, prototypeAccessors ); + + return EventService; +}(StoreService)); + +// default + +// this will generate a event emitter and will be use everywhere +// create a clone version so we know which one we actually is using +var JsonqlWsEvt = /*@__PURE__*/(function (EventEmitterClass) { + function JsonqlWsEvt(logger) { + if (typeof logger !== 'function') { + throw new Error("Just die here the logger is not a function!") + } + logger("---> Create a new EventEmitter <---"); + // this ee will always come with the logger + // because we should take the ee from the configuration + EventEmitterClass.call(this, { logger: logger }); + } + + if ( EventEmitterClass ) JsonqlWsEvt.__proto__ = EventEmitterClass; + JsonqlWsEvt.prototype = Object.create( EventEmitterClass && EventEmitterClass.prototype ); + JsonqlWsEvt.prototype.constructor = JsonqlWsEvt; + + var prototypeAccessors = { name: { configurable: true } }; + + prototypeAccessors.name.get = function () { + return 'jsonql-ws-client-core' + }; + + Object.defineProperties( JsonqlWsEvt.prototype, prototypeAccessors ); + + return JsonqlWsEvt; +}(EventService)); + +/** + * getting the event emitter + * @param {object} opts configuration + * @return {object} the event emitter instance + */ +var getEventEmitter = function (opts) { + var log = opts.log; + var eventEmitter = opts.eventEmitter; + + if (eventEmitter) { + log("eventEmitter is:", eventEmitter.name); + return eventEmitter + } + + return new JsonqlWsEvt( opts.log ) +}; + +// bunch of generic helpers + +/** + * DIY in Array + * @param {array} arr to check from + * @param {*} value to check against + * @return {boolean} true on found + */ +var inArray$1 = function (arr, value) { return !!arr.filter(function (a) { return a === value; }).length; }; + +// quick and dirty to turn non array to array +var toArray$1 = function (arg) { return isArray(arg) ? arg : [arg]; }; + +/** + * @param {object} obj for search + * @param {string} key target + * @return {boolean} true on success + */ +var isObjectHasKey$1 = function(obj, key) { + try { + var keys = Object.keys(obj); + return inArray$1(keys, key) + } catch(e) { + // @BUG when the obj is not an OBJECT we got some weird output + return false + } +}; + +/** + * create a event name + * @param {string[]} args + * @return {string} event name for use + */ +var createEvt = function () { + var args = [], len = arguments.length; + while ( len-- ) args[ len ] = arguments[ len ]; + + return args.join('_'); +}; + +/** + * Simple check if the prop is function + * @param {*} prop input + * @return {boolean} true on success + */ +var isFunc = function (prop) { + if (typeof prop === 'function') { + return true; + } + console.error(("Expect to be Function type! Got " + (typeof prop))); +}; + +// generic placeholder function +var nil = function () { return false; }; + +/** + * using just the map reduce to chain multiple functions together + * @param {function} mainFn the init function + * @param {array} moreFns as many as you want to take the last value and return a new one + * @return {function} accept value for the mainFn + */ +var chainFns = function (mainFn) { + var moreFns = [], len = arguments.length - 1; + while ( len-- > 0 ) moreFns[ len ] = arguments[ len + 1 ]; + + return ( + function () { + var args = [], len = arguments.length; + while ( len-- ) args[ len ] = arguments[ len ]; + + return ( + moreFns.reduce(function (value, nextFn) { return ( + // change here to check if the return value is array then we spread it + Reflect.apply(nextFn, null, toArray$1(value)) + ); }, Reflect.apply(mainFn, null, args)) + ); + } +); +}; + +/** + * this is essentially the same as the injectToFn + * but this will not allow overwrite and set the setter and getter + * @param {object} obj to get injected + * @param {string} name of the property + * @param {function} setter for set + * @param {function} [getter=null] for get default return null fn + * @return {object} the injected obj + */ +function objDefineProps(obj, name, setter, getter) { + if ( getter === void 0 ) getter = null; + + if (Object.getOwnPropertyDescriptor(obj, name) === undefined) { + Object.defineProperty(obj, name, { + set: setter, + get: getter === null ? function() { return null; } : getter + }); + } + return obj +} + +/** + * check if the object has name property + * @param {object} obj the object to check + * @param {string} name the prop name + * @return {*} the value or undefined + */ +function objHasProp(obj, name) { + var prop = Object.getOwnPropertyDescriptor(obj, name); + return prop !== undefined && prop.value ? prop.value : prop +} + +/** + * After the user login we will use this Object.define add a new property + * to the resolver with the decoded user data + * @param {function} resolver target resolver + * @param {string} name the name of the object to get inject also for checking + * @param {object} data to inject into the function static interface + * @param {boolean} [overwrite=false] if we want to overwrite the existing data + * @return {function} added property resolver + */ +function injectToFn(resolver, name, data, overwrite) { + if ( overwrite === void 0 ) overwrite = false; + + var check = objHasProp(resolver, name); + if (overwrite === false && check !== undefined) { + // console.info(`NOT INJECTED`) + return resolver + } + /* this will throw error! @TODO how to remove props? + if (overwrite === true && check !== undefined) { + delete resolver[name] // delete this property + } + */ + // console.info(`INJECTED`) + Object.defineProperty(resolver, name, { + value: data, + writable: overwrite // if its set to true then we should able to overwrite it + }); + + return resolver +} + +/** + * This is a custom error to throw when server throw a 406 + * This help us to capture the right error, due to the call happens in sequence + * @param {string} message to tell what happen + * @param {mixed} extra things we want to add, 500? + */ +var Jsonql406Error = /*@__PURE__*/(function (Error) { + function Jsonql406Error() { + var args = [], len = arguments.length; + while ( len-- ) args[ len ] = arguments[ len ]; + + Error.apply(this, args); + this.message = args[0]; + this.detail = args[1]; + // We can't access the static name from an instance + // but we can do it like this + this.className = Jsonql406Error.name; + + if (Error.captureStackTrace) { + Error.captureStackTrace(this, Jsonql406Error); + } + } + + if ( Error ) Jsonql406Error.__proto__ = Error; + Jsonql406Error.prototype = Object.create( Error && Error.prototype ); + Jsonql406Error.prototype.constructor = Jsonql406Error; + + var staticAccessors = { statusCode: { configurable: true },name: { configurable: true } }; + + staticAccessors.statusCode.get = function () { + return 406; + }; + + staticAccessors.name.get = function () { + return 'Jsonql406Error'; + }; + + Object.defineProperties( Jsonql406Error, staticAccessors ); + + return Jsonql406Error; +}(Error)); + +/** + * This is a custom error to throw when server throw a 500 + * This help us to capture the right error, due to the call happens in sequence + * @param {string} message to tell what happen + * @param {mixed} extra things we want to add, 500? + */ +var Jsonql500Error = /*@__PURE__*/(function (Error) { + function Jsonql500Error() { + var args = [], len = arguments.length; + while ( len-- ) args[ len ] = arguments[ len ]; + + Error.apply(this, args); + + this.message = args[0]; + this.detail = args[1]; + + this.className = Jsonql500Error.name; + + if (Error.captureStackTrace) { + Error.captureStackTrace(this, Jsonql500Error); + } + } + + if ( Error ) Jsonql500Error.__proto__ = Error; + Jsonql500Error.prototype = Object.create( Error && Error.prototype ); + Jsonql500Error.prototype.constructor = Jsonql500Error; + + var staticAccessors = { statusCode: { configurable: true },name: { configurable: true } }; + + staticAccessors.statusCode.get = function () { + return 500; + }; + + staticAccessors.name.get = function () { + return 'Jsonql500Error'; + }; + + Object.defineProperties( Jsonql500Error, staticAccessors ); + + return Jsonql500Error; +}(Error)); + +/** + * this is the 403 Forbidden error + * that means this user is not login + * use the 401 for try to login and failed + * @param {string} message to tell what happen + * @param {mixed} extra things we want to add, 500? + */ +var JsonqlForbiddenError = /*@__PURE__*/(function (Error) { + function JsonqlForbiddenError() { + var args = [], len = arguments.length; + while ( len-- ) args[ len ] = arguments[ len ]; + + Error.apply(this, args); + this.message = args[0]; + this.detail = args[1]; + + this.className = JsonqlForbiddenError.name; + + if (Error.captureStackTrace) { + Error.captureStackTrace(this, JsonqlForbiddenError); + } + } + + if ( Error ) JsonqlForbiddenError.__proto__ = Error; + JsonqlForbiddenError.prototype = Object.create( Error && Error.prototype ); + JsonqlForbiddenError.prototype.constructor = JsonqlForbiddenError; + + var staticAccessors = { statusCode: { configurable: true },name: { configurable: true } }; + + staticAccessors.statusCode.get = function () { + return 403; + }; + + staticAccessors.name.get = function () { + return 'JsonqlForbiddenError'; + }; + + Object.defineProperties( JsonqlForbiddenError, staticAccessors ); + + return JsonqlForbiddenError; +}(Error)); + +/** + * This is a custom error to throw when pass credential but fail + * This help us to capture the right error, due to the call happens in sequence + * @param {string} message to tell what happen + * @param {mixed} extra things we want to add, 500? + */ +var JsonqlAuthorisationError = /*@__PURE__*/(function (Error) { + function JsonqlAuthorisationError() { + var args = [], len = arguments.length; + while ( len-- ) args[ len ] = arguments[ len ]; + + Error.apply(this, args); + this.message = args[0]; + this.detail = args[1]; + + this.className = JsonqlAuthorisationError.name; + + if (Error.captureStackTrace) { + Error.captureStackTrace(this, JsonqlAuthorisationError); + } + } + + if ( Error ) JsonqlAuthorisationError.__proto__ = Error; + JsonqlAuthorisationError.prototype = Object.create( Error && Error.prototype ); + JsonqlAuthorisationError.prototype.constructor = JsonqlAuthorisationError; + + var staticAccessors = { statusCode: { configurable: true },name: { configurable: true } }; + + staticAccessors.statusCode.get = function () { + return 401; + }; + + staticAccessors.name.get = function () { + return 'JsonqlAuthorisationError'; + }; + + Object.defineProperties( JsonqlAuthorisationError, staticAccessors ); + + return JsonqlAuthorisationError; +}(Error)); + +/** + * This is a custom error when not supply the credential and try to get contract + * This help us to capture the right error, due to the call happens in sequence + * @param {string} message to tell what happen + * @param {mixed} extra things we want to add, 500? + */ +var JsonqlContractAuthError = /*@__PURE__*/(function (Error) { + function JsonqlContractAuthError() { + var args = [], len = arguments.length; + while ( len-- ) args[ len ] = arguments[ len ]; + + Error.apply(this, args); + this.message = args[0]; + this.detail = args[1]; + + this.className = JsonqlContractAuthError.name; + + if (Error.captureStackTrace) { + Error.captureStackTrace(this, JsonqlContractAuthError); + } + } + + if ( Error ) JsonqlContractAuthError.__proto__ = Error; + JsonqlContractAuthError.prototype = Object.create( Error && Error.prototype ); + JsonqlContractAuthError.prototype.constructor = JsonqlContractAuthError; + + var staticAccessors = { statusCode: { configurable: true },name: { configurable: true } }; + + staticAccessors.statusCode.get = function () { + return 401; + }; + + staticAccessors.name.get = function () { + return 'JsonqlContractAuthError'; + }; + + Object.defineProperties( JsonqlContractAuthError, staticAccessors ); + + return JsonqlContractAuthError; +}(Error)); + +/** + * This is a custom error to throw when the resolver throw error and capture inside the middleware + * This help us to capture the right error, due to the call happens in sequence + * @param {string} message to tell what happen + * @param {mixed} extra things we want to add, 500? + */ +var JsonqlResolverAppError = /*@__PURE__*/(function (Error) { + function JsonqlResolverAppError() { + var args = [], len = arguments.length; + while ( len-- ) args[ len ] = arguments[ len ]; + + Error.apply(this, args); + + this.message = args[0]; + this.detail = args[1]; + + this.className = JsonqlResolverAppError.name; + + if (Error.captureStackTrace) { + Error.captureStackTrace(this, JsonqlResolverAppError); + } + } + + if ( Error ) JsonqlResolverAppError.__proto__ = Error; + JsonqlResolverAppError.prototype = Object.create( Error && Error.prototype ); + JsonqlResolverAppError.prototype.constructor = JsonqlResolverAppError; + + var staticAccessors = { statusCode: { configurable: true },name: { configurable: true } }; + + staticAccessors.statusCode.get = function () { + return 500; + }; + + staticAccessors.name.get = function () { + return 'JsonqlResolverAppError'; + }; + + Object.defineProperties( JsonqlResolverAppError, staticAccessors ); + + return JsonqlResolverAppError; +}(Error)); + +/** + * This is a custom error to throw when could not find the resolver + * This help us to capture the right error, due to the call happens in sequence + * @param {string} message to tell what happen + * @param {mixed} extra things we want to add, 500? + */ +var JsonqlResolverNotFoundError = /*@__PURE__*/(function (Error) { + function JsonqlResolverNotFoundError() { + var args = [], len = arguments.length; + while ( len-- ) args[ len ] = arguments[ len ]; + + Error.apply(this, args); + + this.message = args[0]; + this.detail = args[1]; + + this.className = JsonqlResolverNotFoundError.name; + + if (Error.captureStackTrace) { + Error.captureStackTrace(this, JsonqlResolverNotFoundError); + } + } + + if ( Error ) JsonqlResolverNotFoundError.__proto__ = Error; + JsonqlResolverNotFoundError.prototype = Object.create( Error && Error.prototype ); + JsonqlResolverNotFoundError.prototype.constructor = JsonqlResolverNotFoundError; + + var staticAccessors = { statusCode: { configurable: true },name: { configurable: true } }; + + staticAccessors.statusCode.get = function () { + return 404; + }; + + staticAccessors.name.get = function () { + return 'JsonqlResolverNotFoundError'; + }; + + Object.defineProperties( JsonqlResolverNotFoundError, staticAccessors ); + + return JsonqlResolverNotFoundError; +}(Error)); + +// this is from an example from Koa team to use for internal middleware ctx.throw +// but after the test the res.body part is unable to extract the required data +// I keep this one here for future reference + +var JsonqlServerError = /*@__PURE__*/(function (Error) { + function JsonqlServerError(statusCode, message) { + Error.call(this, message); + this.statusCode = statusCode; + this.className = JsonqlServerError.name; + } + + if ( Error ) JsonqlServerError.__proto__ = Error; + JsonqlServerError.prototype = Object.create( Error && Error.prototype ); + JsonqlServerError.prototype.constructor = JsonqlServerError; + + var staticAccessors = { name: { configurable: true } }; + + staticAccessors.name.get = function () { + return 'JsonqlServerError'; + }; + + Object.defineProperties( JsonqlServerError, staticAccessors ); + + return JsonqlServerError; +}(Error)); + +/** + * this will put into generator call at the very end and catch + * the error throw from inside then throw again + * this is necessary because we split calls inside and the throw + * will not reach the actual client unless we do it this way + * @param {object} e Error + * @return {void} just throw + */ +function finalCatch(e) { + // this is a hack to get around the validateAsync not actually throw error + // instead it just rejected it with the array of failed parameters + if (Array.isArray(e)) { + // if we want the message then I will have to create yet another function + // to wrap this function to provide the name prop + throw new JsonqlValidationError('', e) + } + var msg = e.message || NO_ERROR_MSG; + var detail = e.detail || e; + // @BUG the instance of not always work for some reason! + // need to figure out a better way to find out the type of the error + switch (true) { + case e instanceof Jsonql406Error: + throw new Jsonql406Error(msg, detail) + case e instanceof Jsonql500Error: + throw new Jsonql500Error(msg, detail) + case e instanceof JsonqlForbiddenError: + throw new JsonqlForbiddenError(msg, detail) + case e instanceof JsonqlAuthorisationError: + throw new JsonqlAuthorisationError(msg, detail) + case e instanceof JsonqlContractAuthError: + throw new JsonqlContractAuthError(msg, detail) + case e instanceof JsonqlResolverAppError: + throw new JsonqlResolverAppError(msg, detail) + case e instanceof JsonqlResolverNotFoundError: + throw new JsonqlResolverNotFoundError(msg, detail) + case e instanceof JsonqlEnumError: + throw new JsonqlEnumError(msg, detail) + case e instanceof JsonqlTypeError: + throw new JsonqlTypeError(msg, detail) + case e instanceof JsonqlCheckerError: + throw new JsonqlCheckerError(msg, detail) + case e instanceof JsonqlValidationError: + throw new JsonqlValidationError(msg, detail) + case e instanceof JsonqlServerError: + throw new JsonqlServerError(msg, detail) + default: + throw new JsonqlError$1(msg, detail) + } +} + +// split the contract into the node side and the generic side +/** + * Check if the json is a contract file or not + * @param {object} contract json object + * @return {boolean} true + */ +function checkIsContract(contract) { + return isPlainObject(contract) + && ( + isObjectHasKey$1(contract, QUERY_NAME) + || isObjectHasKey$1(contract, MUTATION_NAME) + || isObjectHasKey$1(contract, SOCKET_NAME) + ) +} + +/** + * Wrapper method that check if it's contract then return the contract or false + * @param {object} contract the object to check + * @return {boolean | object} false when it's not + */ +function isContract(contract) { + return checkIsContract(contract) ? contract : false +} + +/** + * Ported from jsonql-params-validator but different + * if we don't find the socket part then return false + * @param {object} contract the contract object + * @return {object|boolean} false on failed + */ +function extractSocketPart(contract) { + if (isObjectHasKey$1(contract, SOCKET_NAME)) { + return contract[SOCKET_NAME] + } + return false +} + +// take out all the namespace related methods in one place for easy to find +var SOCKET_NOT_FOUND_ERR = "socket not found in contract!"; +var SIZE = 'size'; + +/** + * create the group using publicNamespace when there is only public + * @param {object} socket from contract + * @param {string} publicNamespace + */ +function groupPublicNamespace(socket, publicNamespace) { + var obj; + + var g = {}; + for (var resolverName in socket) { + var params = socket[resolverName]; + g[resolverName] = params; + } + return { size: 1, nspGroup: ( obj = {}, obj[publicNamespace] = g, obj ), publicNamespace: publicNamespace} +} + + +/** + * @BUG we should check the socket part instead of expect the downstream to read the menu! + * We only need this when the enableAuth is true otherwise there is only one namespace + * @param {object} contract the socket part of the contract file + * @return {object} 1. remap the contract using the namespace --> resolvers + * 2. the size of the object (1 all private, 2 mixed public with private) + * 3. which namespace is public + */ +function groupByNamespace(contract) { + var socket = extractSocketPart(contract); + if (socket === false) { + throw new JsonqlError('groupByNamespace', SOCKET_NOT_FOUND_ERR) + } + var prop = {}; + prop[NSP_GROUP] = {}; + prop[PUBLIC_NAMESPACE] = null; + prop[SIZE] = 0; + + for (var resolverName in socket) { + var params = socket[resolverName]; + var namespace = params.namespace; + if (namespace) { + if (!prop[NSP_GROUP][namespace]) { + ++prop[SIZE]; + prop[NSP_GROUP][namespace] = {}; + } + prop[NSP_GROUP][namespace][resolverName] = params; + // get the public namespace + if (!prop[PUBLIC_NAMESPACE] && params[PUBLIC_KEY]) { + prop[PUBLIC_NAMESPACE] = namespace; + } + } + } + + return prop +} + +/** + * @TODO this might change, what if we want to do room with ws + * 1. there will only be max two namespace + * 2. when it's normal we will have the stock path as namespace + * 3. when enableAuth then we will have two, one is jsonql/public + private + * @param {object} config options + * @return {array} of namespace(s) + */ +function getNamespace(config) { + var base = JSONQL_PATH; + if (config.enableAuth) { + // the public come first @1.0.1 we use the constants instead of the user supplied value + // @1.0.4 we use the config value again, because we could control this via the post init + return [ + [ base , config.publicNamespace ].join('/'), + [ base , config.privateNamespace ].join('/') + ] + } + return [ base ] +} + +/** + * Got a problem with a contract that is public only the groupByNamespace is wrong + * which is actually not a problem when using a fallback, but to be sure things in order + * we could combine with the config to group it + * @param {object} config configuration + * @return {object} nspInfo object + */ +function getNspInfoByConfig(config) { + var contract = config.contract; + var enableAuth = config.enableAuth; + var namespaces = getNamespace(config); + var nspInfo = enableAuth ? groupByNamespace(contract) + : groupPublicNamespace(contract.socket, namespaces[0]); + // add the namespaces into it as well + return Object.assign(nspInfo, { namespaces: namespaces }) +} + +// group all the small functions here + + +/** + * WebSocket is strict about the path, therefore we need to make sure before it goes in + * @param {string} url input url + * @return {string} url with correct path name + */ +var fixWss = function (url) { + var uri = url.toLowerCase(); + if (uri.indexOf('http') > -1) { + if (uri.indexOf('https') > -1) { + return uri.replace('https', 'wss') + } + return uri.replace('http', 'ws') + } + return uri +}; + + +/** + * get a stock host name from browser + */ +var getHostName = function () { + try { + return [window.location.protocol, window.location.host].join('//') + } catch(e) { + throw new JsonqlValidationError(e) + } +}; + +/** + * Unbind the event + * @param {object} ee EventEmitter + * @param {string} namespace + * @return {void} + */ +var clearMainEmitEvt = function (ee, namespace) { + var nsps = toArray$1(namespace); + nsps.forEach(function (n) { + ee.$off(createEvt(n, EMIT_REPLY_TYPE)); + }); +}; + +// 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 SOCKET_IO = JS_WS_SOCKET_IO_NAME; + +var EMIT_EVT = EMIT_REPLY_TYPE; + +var UNKNOWN_RESULT = 'UKNNOWN RESULT!'; + +var MY_NAMESPACE = 'myNamespace'; +// this is a socket only (for now) feature so we just put it here +var DISCONNECTED_ERROR_MSG = "You have disconnected from the socket server, please reconnect."; + +// breaking it up further to share between methods + +/** + * break out to use in different places to handle the return from server + * @param {object} data from server + * @param {function} resolver NOT from promise + * @param {function} rejecter NOT from promise + * @return {void} nothing + */ +function respondHandler(data, resolver, rejecter) { + if (isObjectHasKey$1(data, ERROR_KEY)) { + // debugFn('-- rejecter called --', data[ERROR_KEY]) + rejecter(data[ERROR_KEY]); + } else if (isObjectHasKey$1(data, DATA_KEY)) { + // debugFn('-- resolver called --', data[DATA_KEY]) + resolver(data[DATA_KEY]); + } else { + // debugFn('-- UNKNOWN_RESULT --', data) + rejecter({message: UNKNOWN_RESULT, error: data}); + } +} + +// the actual trigger call method + +/** + * just wrapper + * @param {object} ee EventEmitter + * @param {string} namespace where this belongs + * @param {string} resolverName resolver + * @param {array} args arguments + * @param {function} log function + * @return {void} nothing + */ +function actionCall(ee, namespace, resolverName, args, log) { + if ( args === void 0 ) args = []; + + // reply event + var outEventName = createEvt(namespace, EMIT_REPLY_TYPE); + + log(("actionCall: " + outEventName + " --> " + resolverName), args); + // This is the out going call + ee.$trigger(outEventName, [resolverName, toArray$1(args)]); + + // then we need to listen to the event callback here as well + return new Promise(function (resolver, rejecter) { + var inEventName = createEvt(namespace, resolverName, ON_RESULT_FN_NAME); + // this cause the onResult got the result back first + // and it should be the promise resolve first + // @TODO we need to rewrote the respondHandler to change the problem stated above + ee.$on( + inEventName, + function actionCallResultHandler(result) { + log("got the first result", result); + respondHandler(result, resolver, rejecter); + } + ); + }) +} + +// setting up the send method + +/** + * pairing with the server vesrion SEND_MSG_FN_NAME + * last of the chain so only return the resolver (fn) + * This is now change to a getter / setter method + * and call like this: resolver.send(...args) + * @param {function} fn the resolver function + * @param {object} ee event emitter instance + * @param {string} namespace the namespace it belongs to + * @param {string} resolverName name of the resolver + * @param {object} params from contract + * @param {function} log a logger function + * @return {function} return the resolver itself + */ +var setupSendMethod = function (fn, ee, namespace, resolverName, params, log) { return ( + objDefineProps( + fn, + SEND_MSG_FN_NAME, + nil, + function sendHandler() { + // let _log = (...args) => Reflect.apply(console.info, console, ['[SEND]'].concat(args)) + /** + * This will follow the same pattern like the resolver + * @param {array} args list of unknown argument follow the resolver + * @return {promise} resolve the result + */ + return function sendCallback() { + var args = [], len = arguments.length; + while ( len-- ) args[ len ] = arguments[ len ]; + + return validateAsync$1(args, params.params, true) + .then(function (_args) { + // @TODO check the result + // because the validation could failed with the list of fail properties + log(namespace, resolverName, _args); + return actionCall(ee, namespace, resolverName, _args, _log) + }) + .catch(function (err) { + // @TODO it shouldn't be just a validation error + // it could be server return error, so we need to check + // what error we got back here first + log('send error', err); + // @TODO it might not an validation error need the finalCatch here + ee.$call( + createEvt(namespace, resolverName, ON_ERROR_FN_NAME), + [new JsonqlValidationError(resolverName, err)] + ); + }) + } + }) +); }; + +// break up the original setup resolver method here + +/** + * The first one in the chain, just setup a namespace prop + * the rest are passing through + * @param {function} fn the resolver function + * @param {object} ee the event emitter + * @param {string} resolverName what it said + * @param {object} params for resolver from contract + * @param {function} log the logger function + * @return {array} + */ +var setupNamespace = function (fn, ee, namespace, resolverName, params, log) { return [ + injectToFn(fn, MY_NAMESPACE, namespace), + ee, + namespace, + resolverName, + params, + log +]; }; + +/** + * onResult handler + */ +var setupOnResult = function (fn, ee, namespace, resolverName, params, log) { return [ + objDefineProps(fn, ON_RESULT_FN_NAME, function(resultCallback) { + if (isFunc(resultCallback)) { + ee.$on( + createEvt(namespace, resolverName, ON_RESULT_FN_NAME), + function resultHandler(result) { + respondHandler(result, resultCallback, function (error) { + log(("Catch error: \"" + resolverName + "\""), error); + ee.$trigger( + createEvt(namespace, resolverName, ON_ERROR_FN_NAME), + error + ); + }); + } + ); + } + }), + ee, + namespace, + resolverName, + params, + log +]; }; + +/** + * we do need to add the send prop back because it's the only way to deal with + * bi-directional data stream + */ +var setupOnMessage = function (fn, ee, namespace, resolverName, params, log) { return [ + objDefineProps(fn, ON_MESSAGE_FN_NAME, function(messageCallback) { + // we expect this to be a function + if (isFunc(messageCallback)) { + // did that add to the callback + var onMessageCallback = function (args) { + respondHandler(args, messageCallback, function (error) { + log(("Catch error: \"" + resolverName + "\""), error); + ee.$trigger( + createEvt(namespace, resolverName, ON_ERROR_FN_NAME), + error + ); + }); + }; + // register the handler for this message event + ee.$only( + createEvt(namespace, resolverName, ON_MESSAGE_FN_NAME), + onMessageCallback + ); + } + }), + ee, + namespace, + resolverName, + params, + log +]; }; + +/** + * ON_ERROR_FN_NAME handler + */ +var setupOnError = function (fn, ee, namespace, resolverName, params, log) { return [ + objDefineProps(fn, ON_ERROR_FN_NAME, function(resolverErrorHandler) { + if (isFunc(resolverErrorHandler)) { + // please note ON_ERROR_FN_NAME can add multiple listners + ee.$only( + createEvt(namespace, resolverName, ON_ERROR_FN_NAME), + resolverErrorHandler + ); + } + }), + ee, + namespace, + resolverName, + params, + log +]; }; + +/** + * Add extra property / listeners to the resolver + * @param {string} namespace where this belongs + * @param {string} resolverName name as event name + * @param {object} params from contract + * @param {function} fn resolver function + * @param {object} ee EventEmitter + * @param {function} log function + * @return {function} resolver + */ +function setupResolver(namespace, resolverName, params, fn, ee, log) { + var fns = [ + setupNamespace, + setupOnResult, + setupOnMessage, + setupOnError, + setupSendMethod + ]; + + // get the executor + var executor = Reflect.apply(chainFns, null, fns); + var args = [fn, ee, namespace, resolverName, params, log]; + + return Reflect.apply(executor, null, args) +} + +// put all the resolver related methods here to make it more clear + +/** + * create the actual function to send message to server + * @param {object} ee EventEmitter instance + * @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 + * @return {function} resolver + */ +function createResolver(ee, namespace, resolverName, params, log) { + // note we pass the new withResult=true option + return function resolver() { + var args = [], len = arguments.length; + while ( len-- ) args[ len ] = arguments[ len ]; + + return validateAsync$1(args, params.params, true) + .then(function (_args) { return actionCall(ee, namespace, resolverName, _args, log); }) + .catch(finalCatch) + } +} + +/** + * step one get the clientmap with the namespace + * @param {object} opts configuration + * @param {object} ee EventEmitter + * @param {object} nspGroup resolvers index by their namespace + * @return {promise} resolve the clientmapped, and start the chain + */ +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) { + // resolverNames.push(resolverName) + var params = list[resolverName]; + var fn = createResolver(ee, namespace, resolverName, params, log); + // 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, setupResolver(namespace, resolverName, params, fn, ee, log)); + } + } + // resolve the clientto start the chain + // chain the result to allow the chain processing + return [ client, opts, ee, nspGroup ] +} + +/** + * The problem is the namespace can have more than one + * and we only have on onError message + * @param {object} clientthe client itself + * @param {object} opts configuration + * @param {object} ee Event Emitter + * @param {object} nspGroup namespace keys + * @return {array} [obj, opts, ee] + */ +function createNamespaceErrorHandler(client, opts, ee, nspGroup) { + return [ + // using the onError as name + // @TODO we should follow the convention earlier + // make this a setter for the clientitself + objDefineProps(client, ON_ERROR_FN_NAME, function namespaceErrorCallbackHandler(namespaceErrorHandler) { + if (isFunc(namespaceErrorHandler)) { + // please note ON_ERROR_FN_NAME can add multiple listners + for (var namespace in nspGroup) { + // this one is very tricky, we need to make sure the trigger is calling + // with the namespace as well as the error + ee.$on(createEvt(namespace, ON_ERROR_FN_NAME), namespaceErrorHandler); + } + } + }), + opts, + ee + ] +} + +/** + * This event will fire when the socket.io.on('connection') and ws.onopen + * @param {object} client client itself + * @param {object} opts configuration + * @param {object} ee Event Emitter + * @return {array} [ obj, opts, ee ] + */ +function createOnReadyHandler(client, opts, ee) { + return [ + objDefineProps(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); + } + }), + opts, + ee + ] +} + +// 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 + * output the client + * @param {object} client the client + * @param {object} opts configuration + * @param {object} ee the event emitter + * @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); + }) +} + +/** + * 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 + */ +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 + 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 + client.eventEmitter = opts.eventEmitter; + client.log = opts.log; + 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 generator(opts, nspMap, ee) { + + var args = [ + generateResolvers, + createNamespaceErrorHandler, + createOnReadyHandler + ]; + if (opts.enableAuth) { + args.push( + createAuthMethods + ); + } + // we will always get back the [ obj, opts, ee ] + // then we only return the obj (wsClient) + args.push(setupFinalStep); + // run it + var fn = Reflect.apply(chainFns, null, args); + + return fn(opts, ee, nspMap[NSP_GROUP]) +} + +var obj, obj$1, obj$2; +// import { AVAILABLE_SERVERS } from './constants' +var AVAILABLE_METHODS = [IO_ROUNDTRIP_LOGIN, IO_HANDSHAKE_LOGIN]; + +var configCheckMap = { + standalone: createConfig$1(false, [BOOLEAN_TYPE]), // to turn on or off some of the features + debugOn: createConfig$1(false, [BOOLEAN_TYPE]), + // useCallbackStyle: createConfig(false, [BOOLEAN_TYPE]), abandoned in 0.6.0 + // Please note the login method will be a public available always + // what if the developer wants to have a socket only setup to do a CORS SPA site + loginHandlerName: createConfig$1(LOGIN_NAME, [STRING_TYPE]), + logoutHandlerName: createConfig$1(LOGOUT_NAME, [STRING_TYPE]), + // just matching the server side + disconnectHandlerName: createConfig$1(DISCONNECT_FN_NAME, [STRING_TYPE]), + switchUserHandlerName: createConfig$1(SWITCH_USER_FN_NAME, [STRING_TYPE]), + // this is for socket.io + loginMethod: createConfig$1(IO_HANDSHAKE_LOGIN, [STRING_TYPE], ( obj = {}, obj[ENUM_KEY] = AVAILABLE_METHODS, obj )), + // we will use this for determine the socket.io client type as well - @TODO remove or rename + useJwt: createConfig$1(true, [BOOLEAN_TYPE, STRING_TYPE]), + // this is going to replace the use of useJwt === string next + authStrKey: createConfig$1(null, [STRING_TYPE]), + hostname: createConfig$1(false, [STRING_TYPE]), + namespace: createConfig$1(JSONQL_PATH, [STRING_TYPE]), + wsOptions: createConfig$1({}, [OBJECT_TYPE]), + // make this null as default don't set this here, only set in the down stream + // serverType: createConfig(null, [STRING_TYPE], {[ENUM_KEY]: AVAILABLE_SERVERS}), + // we require the contract already generated and pass here + contract: createConfig$1({}, [OBJECT_TYPE], ( obj$1 = {}, obj$1[CHECKER_KEY] = isContract, obj$1 )), + enableAuth: createConfig$1(false, [BOOLEAN_TYPE]), + token: createConfig$1(false, [STRING_TYPE]) +}; + +// socket client +var socketCheckMap = {}; +socketCheckMap[SOCKET_TYPE_KEY] = createConfig$1(null, [STRING_TYPE], ( obj$2 = {}, obj$2[ALIAS_KEY] = SOCKET_TYPE_CLIENT_ALIAS, obj$2 )); + +var wsCoreCheckMap = Object.assign(configCheckMap, socketCheckMap); + +// constant props +var wsCoreConstProps = { + log: null, + // contract: null, + eventEmitter: null, + // we unify the two different client into one now + // only expect different parameter + nspClient: null, + nspAuthClient: null, + // contructed path + wssPath: '' +}; + +// create options + + +/** + * wrapper method to check this already did the pre check + * @param {object} config user supply config + * @param {object} defaultOptions for checking + * @param {object} constProps user supply const props + * @return {promise} resolve to the checked opitons + */ +function checkConfiguration(config, defaultOptions, constProps) { + var defaultCheckMap= Object.assign(wsCoreCheckMap, defaultOptions); + var wsConstProps = Object.assign(wsCoreConstProps, constProps); + + return checkConfigAsync(config, defaultCheckMap, wsConstProps) +} + +/** + * Taking the `then` part from the method below + * @param {object} opts + * @return {promise} opts all done + */ +function postCheckInjectOpts(opts) { + return Promise.resolve(opts) + .then(function (opts) { + if (!opts.hostname) { + opts.hostname = getHostName(); + } + // @TODO the contract now will supply the namespace information + // and we need to use that to group the namespace call + opts.wssPath = fixWss([opts.hostname, opts.namespace].join('/'), opts.serverType); + // get the log function here + opts.log = getLogFn(opts); + + opts.eventEmitter = getEventEmitter(opts); + + return 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} + */ +function createRequiredParams(opts) { + return { + opts: opts, + nspMap: getNspInfoByConfig(opts), + ee: opts.eventEmitter + } +} + +// the top level API + + +/** + * 0.5.0 we break up the wsClientCore in two parts one without the config check + * @param {function} frameworkSocketEngine + * @param {object} config the already checked config + */ +function wsClientCoreAction(frameworkSocketEngine, config) { + return postCheckInjectOpts(config) + // the following two moved to wsPostConfig + .then(createRequiredParams) + .then( + function (ref) { + var opts = ref.opts; + var nspMap = ref.nspMap; + var ee = ref.ee; + + return frameworkSocketEngine(opts, nspMap, ee); + } + ) + .then( + function (ref) { + var opts = ref.opts; + var nspMap = ref.nspMap; + var ee = ref.ee; + + return generator(opts, nspMap, ee); + } + ) + .catch(function (err) { + console.error("jsonql-ws-core-client init error", err); + }) +} + +/** + * The main interface which will generate the socket clients and map all events + * @param {object} frameworkSocketEngine this is the one method export by various clients + * @param {object} [configCheckMap={}] we should do all the checking in the core instead of the client + * @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(frameworkSocketEngine, configCheckMap, constProps) { + if ( configCheckMap === void 0 ) configCheckMap = {}; + if ( constProps === void 0 ) constProps = {}; + + // we need to inject property to this client later + return function (config) { + if ( config === void 0 ) config = {}; + + return checkConfiguration(config, configCheckMap, constProps) + .then(function (opts) { return wsClientCoreAction(frameworkSocketEngine, opts); }); + } +} + +// since both the ws and io version are +// pre-defined in the client-generator +// and this one will have the same parameters +// and the callback is identical + +/** + * wrapper method to create a nsp without login + * @param {string|boolean} namespace namespace url could be false + * @param {object} opts configuration + * @return {object} ws client instance + */ +function createNspClient(namespace, opts) { + var hostname = opts.hostname; + var wssPath = opts.wssPath; + var wsOptions = opts.wsOptions; + var nspClient = opts.nspClient; + var url = namespace ? [hostname, namespace].join('/') : wssPath; + return nspClient(url, wsOptions) +} + +/** + * wrapper method to create a nsp with token auth + * @param {string} namespace namespace url + * @param {object} opts configuration + * @return {object} ws client instance + */ +function createNspAuthClient(namespace, opts) { + var hostname = opts.hostname; + var wssPath = opts.wssPath; + var token = opts.token; + var wsOptions = opts.wsOptions; + var nspAuthClient = opts.nspAuthClient; + var url = namespace ? [hostname, namespace].join('/') : wssPath; + if (token && typeof token !== 'string') { + throw new Error(("Expect token to be string, but got " + token)) + } + return nspAuthClient(url, token, wsOptions) +} + +// this use by client-event-handler + +/** + * trigger errors on all the namespace onError handler + * @param {object} ee Event Emitter + * @param {array} namespaces nsps string + * @param {string} message optional + * @return {void} + */ +function triggerNamespacesOnError(ee, namespaces, message) { + namespaces.forEach( function (namespace) { + ee.$trigger( + createEvt(namespace, ON_ERROR_FN_NAME), + [{ message: message, namespace: namespace }] + ); + }); +} + +/** + * Handle the onerror callback + * @param {object} ee event emitter + * @param {string} namespace which namespace has error + * @param {*} err error object + * @return {void} + */ +var handleNamespaceOnError = function (ee, namespace, err) { + ee.$trigger(createEvt(namespace, ON_ERROR_FN_NAME), [err]); +}; + +// This is share between different clients so we export it + +/** + * A Event handler placeholder when it's not connect to the private nsp + * @param {string} namespace nsp + * @param {object} ee EventEmitter + * @param {object} opts configuration + * @return {void} + */ +var notLoginWsHandler = function (namespace, ee, opts) { + var log = opts.log; + ee.$only( + createEvt(namespace, EMIT_EVT), + function notLoginHandlerCallback(resolverName, args) { + log('[notLoginHandler] hijack the ws call', namespace, resolverName, args); + var error = { + message: NOT_LOGIN_ERR_MSG + }; + // It should just throw error here and should not call the result + // because that's channel for handling normal event not the fake one + ee.$call(createEvt(namespace, resolverName, ON_ERROR_FN_NAME), [ error ]); + // also trigger the result handler, but wrap inside the error key + ee.$call(createEvt(namespace, resolverName, ON_RESULT_FN_NAME), [{ error: error }]); + } + ); +}; + +/** + * A Event handler placeholder when it's not connect to any nsp + * @param {string} namespace nsp + * @param {object} ee EventEmitter + * @param {object} opts configuration + * @return {void} + */ +var disconnectedHandler = function (namespace, ee, opts) { + var log = opts.log; + ee.$only( + createEvt(namespace, EMIT_EVT), + function disconnectedHandlerCallback(resolverName, args) { + log("[disconnectedHandler] hijack the ws call", namespace, resolverName, args); + var error = { + message: DISCONNECTED_ERROR_MSG + }; + ee.$call(createEvt(namespace, resolverName, ON_ERROR_FN_NAME), [ error ]); + // also trigger the result handler, but wrap inside the error key + ee.$call(createEvt(namespace, resolverName, ON_RESULT_FN_NAME), [{ error: error }]); + } + ); +}; + +/** + * get the private namespace + * @param {array} namespaces array + * @return {*} string on success + */ +var getPrivateNamespace = function (namespaces) { return ( + namespaces.length > 1 ? namespaces[0] : false +); }; + +/** + * Only when there is a private namespace then we bind to this event + * @param {object} nsps the available nsp(s) + * @param {array} namespaces available namespace + * @param {object} ee eventEmitter + * @param {object} opts configuration + * @return {void} + */ +var logoutEvtHandler = function (nsps, namespaces, ee, opts) { + var log = opts.log; + // this will be available regardless enableAuth + // because the server can log the client out + ee.$on(LOGOUT_EVENT_NAME, function logoutEvtHandlerAction() { + var privateNamespace = getPrivateNamespace(namespaces); + log((LOGOUT_EVENT_NAME + " event triggered")); + // disconnect(nsps, opts.serverType) + // we need to issue error to all the namespace onError handler + triggerNamespacesOnError(ee, [privateNamespace], LOGOUT_EVENT_NAME); + // rebind all of the handler to the fake one + log(("logout from " + privateNamespace)); + + clearMainEmitEvt(ee, privateNamespace); + // we need to issue one more call to the server before we disconnect + // now this is a catch 22, here we are not suppose to do anything platform specific + // so that should fire before trigger this event + // clear out the nsp + nsps[privateNamespace] = null; + // add a NOT LOGIN error if call + notLoginWsHandler(privateNamespace, ee, opts); + }); +}; + +/** + * The disconnect event handler, now we log the client out from everything + * @TODO now we are another problem they disconnect, how to reconnect + * @param {object} nsps the available nsp(s) + * @param {array} namespaces available namespace + * @param {object} ee eventEmitter + * @param {object} opts configuration + * @return {void} + */ +var disconnectHandler = function (nsps, namespaces, ee, opts) { + var log = opts.log; + ee.$on(DISCONNECT_EVENT_NAME, function disconnectEvtHandler() { + triggerNamespacesOnError(ee, namespaces, DISCONNECT_EVENT_NAME); + namespaces.forEach( function (namespace) { + log(("disconnect from " + namespace)); + + clearMainEmitEvt(ee, namespace); + nsps[namespace] = null; + disconnectedHandler(namespace, ee, opts); + }); + }); +}; + +/** + * centralize all the comm in one place + * @param {object} opts configuration + * @param {object} ee Event Emitter instance + * @param {function} bindWsHandler binding the ee to ws --> this is the core bit + * @param {object} nsps namespaced nsp + * @return {void} nothing + */ +function clientEventHandler$1(opts, ee, bindSocketEventHandler, nsps) { + // since all these params already in the opts + var nspMap = opts.nspMap; + var log = opts.log; + var namespaces = nspMap.namespaces; + // @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 + var privateNamespace = getPrivateNamespace(namespaces); + var isPrivate = false; + var hasPrivate = false; + // loop + // @BUG for io this has to be in order the one with auth need to get call first + // The order of login is very import we need to run in order here to make sure + // one is execute then the other + namespaces.forEach(function (namespace) { + isPrivate = privateNamespace === namespace; + if (!hasPrivate) { + hasPrivate = isPrivate; + } + if (nsps[namespace]) { + + log('[call bindWsHandler]', isPrivate, namespace); + var args = [namespace, nsps[namespace], ee, isPrivate, opts]; + + if (opts.serverType === SOCKET_IO) { + var nspGroup = nspMap.nspGroup; + args.push(nspGroup[namespace]); + } + Reflect.apply(bindSocketEventHandler, null, args); + } else { + // a dummy placeholder + // @TODO but it should be a not connect handler + // when it's not login (or fail) this should be handle differently + notLoginWsHandler(namespace, ee, opts); + } + }); + // logout event handler + if (hasPrivate) { + log("Has private and add logoutEvtHandler"); + + logoutEvtHandler(nsps, namespaces, ee, opts); + } + // finally the disconnect event handlers + disconnectHandler(nsps, namespaces, ee, opts); +} + +var ERROR_KEY$1 = 'error'; +var TIMESTAMP_PARAM_NAME = 'TS'; +var NO_STATUS_CODE$1 = -1; +var LOGIN_EVENT_NAME$1 = '__login__'; +var LOGOUT_EVENT_NAME$1 = '__logout__'; +// for ws servers +var WS_REPLY_TYPE = '__reply__'; +var WS_EVT_NAME = '__event__'; +var WS_DATA_NAME = '__data__'; +// this is somewhat vague about what is suppose to do +var EMIT_REPLY_TYPE$1 = 'emit_reply'; +var ACKNOWLEDGE_REPLY_TYPE = 'acknowledge_reply'; +var ERROR_TYPE = ERROR_KEY$1; // Should replace with ERROR_KEY +var JS_WS_NAME = 'ws'; + +// for ws client, 1.9.3 breaking change to name them as FN instead of PROP +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 TOKEN_PARAM_NAME = 'token'; + +// jsonql-ws-core takes over the check configuration +// constant props +var wsClientConstProps = { + version: 'version: 1.2.0 module: cjs', // will get replace + serverType: JS_WS_NAME +}; + +// pass the different type of ws to generate the client + +/** + * The bug was in the wsOptions where ws don't need it but socket.io do + * therefore the object was pass as second parameter! + * @param {object} WebSocket the client or node version of ws + * @param {boolean} auth if it's auth then 3 param or just one + */ +function initWebSocketClient(WebSocket, auth) { + if ( auth === void 0 ) auth = false; + + if (auth === false) { + return function createWsClientHandler(url) { + return new WebSocket(fixWss(url)) + } + } + + /** + * Create a client with auth token + * @param {string} url start with ws:// @TODO check this? + * @param {string} token the jwt token + * @return {object} ws instance + */ + return function createWsAuthClientHandler(url, token) { + var ws_url = fixWss(url); + // console.log('what happen here?', url, ws_url, token) + var uri = token && typeof token === 'string' ? (ws_url + "?" + TOKEN_PARAM_NAME + "=" + token) : ws_url; + try { + return new WebSocket(uri) + } catch(e) { + console.error('WebSocket Connection Error', e); + return false + } + } +} + +/** + * Because the nsps can be throw away so it doesn't matter the scope + * this will get reuse again + * @param {object} opts configuration + * @param {object} nspMap from contract + * @param {string|null} token whether we have the token at run time + * @return {object} nsps namespace with namespace as key + */ +var createNspAction$1 = function(opts, nspMap, token) { + var log = opts.log; + var publicNamespace = nspMap.publicNamespace; + var namespaces = nspMap.namespaces; + + return { + nsps: (function () { + var obj; + + // first we need to binding all the events handler + if (opts.enableAuth) { // && opts.useJwt + + return namespaces.map(function (namespace, i) { + var obj, obj$1, obj$2; + + if (i === 0) { + if (token) { + opts.token = token; + log('create createNspAuthClient at run time'); + return ( obj = {}, obj[namespace] = createNspAuthClient(namespace, opts), obj ) + } + return ( obj$1 = {}, obj$1[namespace] = false, obj$1 ) + } + return ( obj$2 = {}, obj$2[namespace] = createNspClient(namespace, opts), obj$2 ) + }).reduce(function (first, next) { return Object.assign(first, next); }, {}) + } + + // standard without login + return ( obj = {}, obj[publicNamespace] = createNspClient(false, opts), obj ) + })() + } +}; + +// @BUG when call disconnected + +/** + * create a login event handler + * @param {object} opts configurations + * @param {object} nspMap contain all the required info + * @param {object} ee event emitter + * @return {void} + */ +function loginEventHandler(opts, nspMap, ee) { + var log = opts.log; + var namespaces = nspMap.namespaces; + + ee.$only(LOGIN_EVENT_NAME$1, function loginEventHandlerCallback(tokenFromLoginAction) { + + log('createClient LOGIN_EVENT_NAME $only handler'); + + clearMainEmitEvt(ee, namespaces); + // console.log('LOGIN_EVENT_NAME', token) + var newNsps = createNspAction(opts, nspMap, tokenFromLoginAction); + // rebind it + Reflect.apply( + clientEventHandler, // @NOTE is this the problem that cause the hang up? + null, + args.concat([newNsps.namespaces, newNsps.nsps]) + ); + }); +} + +/** + * Checks if `value` is classified as an `Array` object. + * + * @static + * @memberOf _ + * @since 0.1.0 + * @category Lang + * @param {*} value The value to check. + * @returns {boolean} Returns `true` if `value` is an array, else `false`. + * @example + * + * _.isArray([1, 2, 3]); + * // => true + * + * _.isArray(document.body.children); + * // => false + * + * _.isArray('abc'); + * // => false + * + * _.isArray(_.noop); + * // => false + */ +var isArray$1 = Array.isArray; + +/** Detect free variable `global` from Node.js. */ +var freeGlobal$1 = typeof global$1 == 'object' && global$1 && global$1.Object === Object && global$1; + +/** Detect free variable `self`. */ +var freeSelf$1 = typeof self == 'object' && self && self.Object === Object && self; + +/** Used as a reference to the global object. */ +var root$1 = freeGlobal$1 || freeSelf$1 || Function('return this')(); + +/** Built-in value references. */ +var Symbol$1 = root$1.Symbol; + +/** Used for built-in method references. */ +var objectProto$f = Object.prototype; + +/** Used to check objects for own properties. */ +var hasOwnProperty$c = objectProto$f.hasOwnProperty; + +/** + * Used to resolve the + * [`toStringTag`](http://ecma-international.org/ecma-262/7.0/#sec-object.prototype.tostring) + * of values. + */ +var nativeObjectToString$2 = objectProto$f.toString; + +/** Built-in value references. */ +var symToStringTag$2 = Symbol$1 ? Symbol$1.toStringTag : undefined; + +/** + * A specialized version of `baseGetTag` which ignores `Symbol.toStringTag` values. + * + * @private + * @param {*} value The value to query. + * @returns {string} Returns the raw `toStringTag`. + */ +function getRawTag$1(value) { + var isOwn = hasOwnProperty$c.call(value, symToStringTag$2), + tag = value[symToStringTag$2]; + + try { + value[symToStringTag$2] = undefined; + var unmasked = true; + } catch (e) {} + + var result = nativeObjectToString$2.call(value); + if (unmasked) { + if (isOwn) { + value[symToStringTag$2] = tag; + } else { + delete value[symToStringTag$2]; + } + } + return result; +} + +/** Used for built-in method references. */ +var objectProto$g = Object.prototype; + +/** + * Used to resolve the + * [`toStringTag`](http://ecma-international.org/ecma-262/7.0/#sec-object.prototype.tostring) + * of values. + */ +var nativeObjectToString$3 = objectProto$g.toString; + +/** + * Converts `value` to a string using `Object.prototype.toString`. + * + * @private + * @param {*} value The value to convert. + * @returns {string} Returns the converted string. + */ +function objectToString$1(value) { + return nativeObjectToString$3.call(value); +} + +/** `Object#toString` result references. */ +var nullTag$1 = '[object Null]', + undefinedTag$1 = '[object Undefined]'; + +/** Built-in value references. */ +var symToStringTag$3 = Symbol$1 ? Symbol$1.toStringTag : undefined; + +/** + * The base implementation of `getTag` without fallbacks for buggy environments. + * + * @private + * @param {*} value The value to query. + * @returns {string} Returns the `toStringTag`. + */ +function baseGetTag$1(value) { + if (value == null) { + return value === undefined ? undefinedTag$1 : nullTag$1; + } + return (symToStringTag$3 && symToStringTag$3 in Object(value)) + ? getRawTag$1(value) + : objectToString$1(value); +} + +/** + * Checks if `value` is object-like. A value is object-like if it's not `null` + * and has a `typeof` result of "object". + * + * @static + * @memberOf _ + * @since 4.0.0 + * @category Lang + * @param {*} value The value to check. + * @returns {boolean} Returns `true` if `value` is object-like, else `false`. + * @example + * + * _.isObjectLike({}); + * // => true + * + * _.isObjectLike([1, 2, 3]); + * // => true + * + * _.isObjectLike(_.noop); + * // => false + * + * _.isObjectLike(null); + * // => false + */ +function isObjectLike$1(value) { + return value != null && typeof value == 'object'; +} + +// bunch of generic helpers + +/** + * DIY in Array + * @param {array} arr to check from + * @param {*} value to check against + * @return {boolean} true on found + */ +var inArray$2 = function (arr, value) { return !!arr.filter(function (a) { return a === value; }).length; }; + +/** + * parse string to json or just return the original value if error happened + * @param {*} n input + * @param {boolean} [t=true] or throw + * @return {*} json object on success + */ +var parseJson = function(n, t) { + if ( t === void 0 ) t=true; + + try { + return JSON.parse(n) + } catch(e) { + if (t) { + return n + } + throw new Error(e) + } +}; + +/** + * @param {object} obj for search + * @param {string} key target + * @return {boolean} true on success + */ +var isObjectHasKey$2 = function(obj, key) { + try { + var keys = Object.keys(obj); + return inArray$2(keys, key) + } catch(e) { + // @BUG when the obj is not an OBJECT we got some weird output + return false + } +}; + +/** + * create a event name + * @param {string[]} args + * @return {string} event name for use + */ +var createEvt$1 = function () { + var args = [], len = arguments.length; + while ( len-- ) args[ len ] = arguments[ len ]; + + return args.join('_'); +}; + +/** + * small util to make sure the return value is valid JSON object + * @param {*} n input + * @return {object} correct JSON object + */ +var toJson = function (n) { + if (typeof n === 'string') { + return parseJson(n) + } + return parseJson(JSON.stringify(n)) +}; + +// generic placeholder function +var nil$1 = function () { return false; }; + +/** + * This is a custom error to throw whenever a error happen inside the jsonql + * This help us to capture the right error, due to the call happens in sequence + * @param {string} message to tell what happen + * @param {mixed} extra things we want to add, 500? + */ +var JsonqlError$2 = /*@__PURE__*/(function (Error) { + function JsonqlError() { + var args = [], len = arguments.length; + while ( len-- ) args[ len ] = arguments[ len ]; + + Error.apply(this, args); + + this.message = args[0]; + this.detail = args[1]; + + this.className = JsonqlError.name; + + if (Error.captureStackTrace) { + Error.captureStackTrace(this, JsonqlError); + // this.detail = this.stack; + } + } + + if ( Error ) JsonqlError.__proto__ = Error; + JsonqlError.prototype = Object.create( Error && Error.prototype ); + JsonqlError.prototype.constructor = JsonqlError; + + var staticAccessors = { name: { configurable: true },statusCode: { configurable: true } }; + + staticAccessors.name.get = function () { + return 'JsonqlError'; + }; + + staticAccessors.statusCode.get = function () { + return NO_STATUS_CODE$1; + }; + + Object.defineProperties( JsonqlError, staticAccessors ); + + return JsonqlError; +}(Error)); + +/** + * @param {boolean} sec return in second or not + * @return {number} timestamp + */ +var timestamp = function (sec) { + if ( sec === void 0 ) sec = false; + + var time = Date.now(); + return sec ? Math.floor( time / 1000 ) : time +}; + +/** `Object#toString` result references. */ +var stringTag$3 = '[object String]'; + +/** + * Checks if `value` is classified as a `String` primitive or object. + * + * @static + * @since 0.1.0 + * @memberOf _ + * @category Lang + * @param {*} value The value to check. + * @returns {boolean} Returns `true` if `value` is a string, else `false`. + * @example + * + * _.isString('abc'); + * // => true + * + * _.isString(1); + * // => false + */ +function isString$3(value) { + return typeof value == 'string' || + (!isArray$1(value) && isObjectLike$1(value) && baseGetTag$1(value) == stringTag$3); +} + +// There are the socket related methods ported back from + +var WS_KEYS = [ + WS_REPLY_TYPE, + WS_EVT_NAME, + WS_DATA_NAME +]; + +/** + * The ws doesn't have a acknowledge callback like socket.io + * so we have to DIY one for ws and other that doesn't have it + * @param {string} type of reply + * @param {string} resolverName which is replying + * @param {*} data payload + * @param {array} [ts= []] the last received ts, if any + * @return {string} stringify json + */ +var createWsReply = function (type, resolverName, data, ts) { + var obj, obj$1; + + if ( ts === void 0 ) ts = []; + ts.push(timestamp()); + return JSON.stringify(( obj$1 = { + data: ( obj = {}, obj[WS_REPLY_TYPE] = type, obj[WS_EVT_NAME] = resolverName, obj[WS_DATA_NAME] = toJson(data), obj ) + }, obj$1[TIMESTAMP_PARAM_NAME] = ts, obj$1 )) +}; + +// extended function +var createReplyMsg = function (resolverName, data, ts) { + if ( ts === void 0 ) ts = []; + + return ( + createWsReply(EMIT_REPLY_TYPE$1, resolverName, data, ts) +); +}; + +/** + * @param {string|object} payload should be string when reply but could be transformed + * @return {boolean} true is OK + */ +var isWsReply = function (payload) { + var json = isString$3(payload) ? toJson(payload) : payload; + var data = json.data; + if (data) { + var result = WS_KEYS.filter(function (key) { return isObjectHasKey$2(data, key); }); + return (result.length === WS_KEYS.length) ? data : false + } + return false +}; + +/** + * @param {string|object} data received data + * @param {function} [cb=nil] this is for extracting the TS field or when it's error + * @return {object} false on failed + */ +var extractWsPayload = function (payload, cb) { + if ( cb === void 0 ) cb = nil$1; + + try { + var json = toJson(payload); + // now handle the data + var _data; + if ((_data = isWsReply(json)) !== false) { + // note the ts property is on its own + cb(TIMESTAMP_PARAM_NAME, json[TIMESTAMP_PARAM_NAME]); + + return { + data: toJson(_data[WS_DATA_NAME]), + resolverName: _data[WS_EVT_NAME], + type: _data[WS_REPLY_TYPE] + } + } + throw new JsonqlError$2('payload can not decoded', payload) + } catch(e) { + return cb(ERROR_KEY$1, e) + } +}; + +// the WebSocket main handler + +/** + * in some edge case we might not even have a resolverName, then + * we issue a global error for the developer to catch it + * @param {object} ee event emitter + * @param {string} namespace nsp + * @param {string} resolverName resolver + * @param {object} json decoded payload or error object + * @return {undefined} nothing return + */ +var errorTypeHandler = function (ee, namespace, resolverName, json) { + var evt = [namespace]; + if (resolverName) { + evt.push(resolverName); + } + evt.push(ON_ERROR_FN_NAME$1); + var evtName = Reflect.apply(createEvt$1, null, evt); + // test if there is a data field + var payload = json.data || json; + ee.$trigger(evtName, [payload]); +}; + +/** + * Handle the logout event when it's enableAuth + * @param {object} ee eventEmitter + * @return {void} + */ +var logoutEventHandler = function (ee) { + // listen to the LOGOUT_EVENT_NAME when this is a private nsp + ee.$on(LOGOUT_EVENT_NAME$1, function closeEvtHandler() { + try { + log('terminate ws connection'); + ws.terminate(); + } catch(e) { + console.error('ws.terminate error', e); + } + }); +}; + +/** + * Binding the event to socket normally + * @param {string} namespace + * @param {object} ws the nsp + * @param {object} ee EventEmitter + * @param {boolean} isPrivate to id if this namespace is private or not + * @param {object} opts configuration + * @return {object} promise resolve after the onopen event + */ +function socketEventHandler(namespace, ws, ee, isPrivate, opts) { + var log = opts.log; + + log("log test, isPrivate:", isPrivate); + // connection open + ws.onopen = function onOpenCallback() { + + log('ws.onopen listened'); + // we just call the onReady + 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); + } + // 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! + */ + function wsMainOnEvtHandler(resolverName, args) { + + var payload = createReplyMsg(resolverName, args); + log('ws.onopen.send', resolverName, args, payload); + + ws.send(payload); + } + ); + }; + + // reply + // If we change it to the event callback style + // then the payload will just be the payload and fucks up the extractWsPayload call @TODO + ws.onmessage = function onMessageCallback(payload) { + // console.log(`on.message`, typeof payload, payload) + try { + var json = extractWsPayload(payload); + var resolverName = json.resolverName; + var type = json.type; + + log('Hear from server', type, json); + + switch (type) { + case EMIT_REPLY_TYPE$1: + var e1 = createEvt$1(namespace, resolverName, ON_MESSAGE_FN_NAME$1); + var r = ee.$trigger(e1, [json]); + log("EMIT_REPLY_TYPE", e1, r); + break + case ACKNOWLEDGE_REPLY_TYPE: + var e2 = createEvt$1(namespace, resolverName, ON_RESULT_FN_NAME$1); + var x2 = ee.$trigger(e2, [json]); + log("ACKNOWLEDGE_REPLY_TYPE", e2, x2); + break + case ERROR_TYPE: + // this is handled error and we won't throw it + // we need to extract the error from json + log("ERROR_TYPE"); + errorTypeHandler(ee, namespace, resolverName, json); + 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 + log('Unhandled event!', json); + errorTypeHandler(ee, namespace, resolverName, json); + // let error = {error: {'message': 'Unhandled event!', type}}; + // ee.$trigger(createEvt(namespace, resolverName, ON_RESULT_FN_NAME), [error]) + } + } catch(e) { + console.error("ws.onmessage error", e); + errorTypeHandler(ee, namespace, false, e); + } + }; + // when the server close the connection + ws.onclose = function onCloseCallback() { + log('ws.onclose callback'); + // @TODO what to do with this + // ee.$trigger(LOGOUT_EVENT_NAME, [namespace]) + }; + // add a onerror event handler here + ws.onerror = function onErrorCallback(err) { + // trigger a global error event + log("ws.onerror", err); + handleNamespaceOnError(ee, namespace, err); + }; + + if (isPrivate) { + logoutEventHandler(ee); + } +} + +// actually binding the event client to the socket client + +/** + * 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 + * @return {object} what comes in what goes out + */ +function createNsp(opts, nspMap, ee) { + // arguments for clientEventHandler + var args = [opts, ee, socketEventHandler]; + + // now create the nsps + var namespaces = nspMap.namespaces; + var token = opts.token; + var ref = createNspAction$1(opts, nspMap, token); + var nsps = ref.nsps; + // binding the listeners - and it will listen to LOGOUT event + // to unbind itself, and the above call will bind it again + Reflect.apply(clientEventHandler$1, null, args.concat([namespaces, nsps])); + // setup listener for the login event + if (opts.enableAuth) { + loginEventHandler(ee, namespaces, nspMap); + } + // return what input + return { opts: opts, nspMap: nspMap, ee: ee } +} + +// breaking up the create-nsp.js file + +// share method to create the wsClientResolver + +/** + * Create the framework <---> jsonql client binding + * @param {object} frameworkModule the different WebSocket module + * @return {function} the wsClientResolver + */ +function bindFrameworkToJsonql(frameworkModule) { + + var publicClient = initWebSocketClient(frameworkModule); + var privateClient = initWebSocketClient(frameworkModule, true); + + /** + * wsClientResolver + * @param {object} opts configuration + * @param {object} nspMap from the contract + * @param {object} ee instance of the eventEmitter + * @return {object} passing the same 3 input out with additional in the opts + */ + return function createClientBindingAction(opts, nspMap, ee) { + opts.nspClient = publicClient; + opts.nspAuthClient = privateClient; + // @1.0.7 remove later once everything fixed + var log = opts.log; + if (log && typeof log === 'function') { + log('@jsonql/ws ee', ee.name); + log('@jsonql/ws createClientResolver', opts); + } + // console.log(`contract`, opts.contract) + return createNsp(opts, nspMap, ee) + } +} + +// this will be the news style interface that will pass to the jsonql-ws-client + +/** + * @param {object} opts configuration + * @param {object} nspMap from the contract + * @param {object} ee instance of the eventEmitter + * @return {object} passing the same 3 input out with additional in the opts + */ +var nodeFrameworkSocketEngine = bindFrameworkToJsonql(WebSocket); + +// this is the module entry point for node client + +// export back the function and that's it +function wsNodeClient(config, constProps) { + if ( config === void 0 ) config = {}; + if ( constProps === void 0 ) constProps = {}; + + var initClientMethod = wsClientCore( + nodeFrameworkSocketEngine, + {}, + Object.assign({}, wsClientConstProps, constProps) + ); + return initClientMethod(config) +} + +module.exports = wsNodeClient; //# sourceMappingURL=main.js.map diff --git a/packages/@jsonql/ws/main.js.map b/packages/@jsonql/ws/main.js.map index aee0a927..262847c2 100644 --- a/packages/@jsonql/ws/main.js.map +++ b/packages/@jsonql/ws/main.js.map @@ -1 +1 @@ -{"version":3,"file":"main.js","sources":[],"sourcesContent":[],"names":[],"mappings":""} \ No newline at end of file +{"version":3,"file":"main.js","sources":["node_modules/_rollup-plugin-node-globals@1.4.0@rollup-plugin-node-globals/src/global.js","../../ws-client-core/node_modules/lodash-es/_arrayMap.js","../../ws-client-core/node_modules/lodash-es/isArray.js","../../ws-client-core/node_modules/lodash-es/_objectToString.js","../../ws-client-core/node_modules/lodash-es/isObjectLike.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-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/lodash-es/_overArg.js","../../ws-client-core/node_modules/lodash-es/_arrayFilter.js","../../ws-client-core/node_modules/lodash-es/_createBaseFor.js","../../ws-client-core/node_modules/lodash-es/_baseTimes.js","../../ws-client-core/node_modules/lodash-es/stubFalse.js","../../ws-client-core/node_modules/lodash-es/_isIndex.js","../../ws-client-core/node_modules/lodash-es/isLength.js","../../ws-client-core/node_modules/lodash-es/_baseUnary.js","../../ws-client-core/node_modules/lodash-es/_isPrototype.js","../../ws-client-core/node_modules/lodash-es/isObject.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/_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/_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/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/identity.js","../../ws-client-core/node_modules/lodash-es/_baseProperty.js","../../ws-client-core/node_modules/jsonql-params-validator/src/object.js","../../ws-client-core/node_modules/jsonql-errors/src/validation-error.js","../../ws-client-core/node_modules/jsonql-params-validator/src/validator.js","../../ws-client-core/node_modules/lodash-es/_copyArray.js","../../ws-client-core/node_modules/lodash-es/_safeGet.js","../../ws-client-core/node_modules/lodash-es/_nativeKeysIn.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/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-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-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/node_modules/jsonql-utils/src/generic.js","../../ws-client-core/node_modules/jsonql-errors/src/500-error.js","../../ws-client-core/node_modules/jsonql-errors/src/resolver-not-found-error.js","../../ws-client-core/node_modules/jsonql-errors/src/server-error.js","../../ws-client-core/node_modules/jsonql-utils/src/contract.js","../../ws-client-core/node_modules/jsonql-utils/src/namespace.js","../../ws-client-core/src/utils/helpers.js","../../ws-client-core/src/core/setup-auth-methods.js","../../ws-client-core/src/options/constants.js","../../ws-client-core/src/core/respond-handler.js","../../ws-client-core/src/core/action-call.js","../../ws-client-core/src/core/setup-send-method.js","../../ws-client-core/src/core/setup-resolver.js","../../ws-client-core/src/core/resolver-methods.js","../../ws-client-core/src/core/setup-intercom.js","../../ws-client-core/src/core/generator.js","../../ws-client-core/src/options/index.js","../../ws-client-core/src/api.js","../../ws-client-core/src/share/create-nsp-client.js","../../ws-client-core/src/share/trigger-namespaces-on-error.js","../../ws-client-core/src/share/client-event-handler.js","src/options/index.js","src/core/create-websocket-binding/init-websocket-client.js","src/core/create-nsp/login-event-handler.js","node_modules/_lodash-es@4.17.15@lodash-es/isArray.js","node_modules/_lodash-es@4.17.15@lodash-es/_objectToString.js","node_modules/_lodash-es@4.17.15@lodash-es/isObjectLike.js","node_modules/_jsonql-utils@1.1.3@jsonql-utils/src/generic.js","node_modules/_jsonql-utils@1.1.3@jsonql-utils/src/timestamp.js","node_modules/_jsonql-utils@1.1.3@jsonql-utils/src/socket.js","src/core/create-nsp/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":["export default (typeof global !== \"undefined\" ? global :\n typeof self !== \"undefined\" ? self :\n typeof window !== \"undefined\" ? window : {});\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 * 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 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 * 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 * 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","// 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\nexport const 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)`\nexport const PARAMS_NOT_ARRAY_ERR = `params is not an array! Did something gone wrong when you generate the contract.json?`\nexport const EXCEPTION_CASE_ERR = 'Could not understand your arguments and parameter structure!'\nexport const UNUSUAL_CASE_ERR = 'This is an unusual situation where the arguments are more than the params, but not mark as spread'\n\n// re-export\nimport * as JSONQL_CONSTANTS from 'jsonql-constants'\n// @TODO the jsdoc return array. and we should also allow array syntax\nexport const DEFAULT_TYPE = JSONQL_CONSTANTS.DEFAULT_TYPE\nexport const ARRAY_TYPE_LFT = JSONQL_CONSTANTS.ARRAY_TYPE_LFT\nexport const ARRAY_TYPE_RGT = JSONQL_CONSTANTS.ARRAY_TYPE_RGT\n\nexport const TYPE_KEY = JSONQL_CONSTANTS.TYPE_KEY\nexport const OPTIONAL_KEY = JSONQL_CONSTANTS.OPTIONAL_KEY\nexport const ENUM_KEY = JSONQL_CONSTANTS.ENUM_KEY\nexport const ARGS_KEY = JSONQL_CONSTANTS.ARGS_KEY\nexport const CHECKER_KEY = JSONQL_CONSTANTS.CHECKER_KEY\nexport const ALIAS_KEY = JSONQL_CONSTANTS.ALIAS_KEY\n\nexport const ARRAY_TYPE = JSONQL_CONSTANTS.ARRAY_TYPE\nexport const OBJECT_TYPE = JSONQL_CONSTANTS.OBJECT_TYPE\nexport const STRING_TYPE = JSONQL_CONSTANTS.STRING_TYPE\nexport const BOOLEAN_TYPE = JSONQL_CONSTANTS.BOOLEAN_TYPE\nexport const NUMBER_TYPE = JSONQL_CONSTANTS.NUMBER_TYPE\nexport const KEY_WORD = JSONQL_CONSTANTS.KEY_WORD\nexport const OR_SEPERATOR = JSONQL_CONSTANTS.OR_SEPERATOR\n\n// not actually in use\n// export const NUMBER_TYPES = JSONQL_CONSTANTS.NUMBER_TYPES;\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","/**\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 * 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 * 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 * 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","/**\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","/** 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","/** 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 * 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","/** 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 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","/**\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","/** 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","/** 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 * 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 * 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 * 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","// validate object type\n\nimport isPlainObject from 'lodash-es/isPlainObject'\nimport filter from 'lodash-es/filter'\n\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","// 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","// 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 // checkIsObject,\n combineFn,\n notEmpty\n} from './index'\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 // UNUSUAL_CASE_ERR\n} from './constants'\nimport { DATA_KEY, ERROR_KEY } from 'jsonql-constants'\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","/**\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","/**\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 * 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 * 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","/** 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","// 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","// 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'\n// PIA syntax\nexport const isObject = checkIsObject\nexport const isAny = checkIsAny\nexport const isString = checkIsString\nexport const isBoolean = checkIsBoolean\nexport const isNumber = checkIsNumber\nexport const isArray = checkIsArray\nexport const isNotEmpty = notEmpty\n\nimport * as validator from './src/validator'\n\nexport const normalizeArgs = validator.normalizeArgs\nexport const validateSync = validator.validateSync\nexport const validateAsync = validator.validateAsync\n\n// configuration checking\n\nimport * as jsonqlOptions from './src/options'\n\nexport const JSONQL_PARAMS_VALIDATOR_INFO = jsonqlOptions.JSONQL_PARAMS_VALIDATOR_INFO\n\nexport const createConfig = jsonqlOptions.createConfig\nexport const constructConfig = jsonqlOptions.constructConfigFn\n// construct the final output 1.5.2\nexport const checkConfigAsync = jsonqlOptions.getCheckConfigAsync(validator.validateSync)\nexport const checkConfig = jsonqlOptions.getCheckConfig(validator.validateSync)\n\n// export the two extra functions\nimport isInArray from './src/is-in-array'\nimport isObjectHasKeyFn from './src/is-key-in-object'\n\nexport const inArray = isInArray\nexport const isObjectHasKey = isObjectHasKeyFn\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","// 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","/**\n * This is a custom error to throw when server throw a 500\n * This help us to capture the right error, due to the call happens in sequence\n * @param {string} message to tell what happen\n * @param {mixed} extra things we want to add, 500?\n */\nexport default class Jsonql500Error extends Error {\n constructor(...args) {\n super(...args)\n\n this.message = args[0]\n this.detail = args[1]\n\n this.className = Jsonql500Error.name;\n\n if (Error.captureStackTrace) {\n Error.captureStackTrace(this, Jsonql500Error)\n }\n }\n\n static get statusCode() {\n return 500;\n }\n\n static get name() {\n return 'Jsonql500Error';\n }\n\n}\n","/**\n * This is a custom error to throw when could not find the resolver\n * This help us to capture the right error, due to the call happens in sequence\n * @param {string} message to tell what happen\n * @param {mixed} extra things we want to add, 500?\n */\nexport default class JsonqlResolverNotFoundError extends Error {\n constructor(...args) {\n super(...args)\n\n this.message = args[0]\n this.detail = args[1]\n\n this.className = JsonqlResolverNotFoundError.name;\n\n if (Error.captureStackTrace) {\n Error.captureStackTrace(this, JsonqlResolverNotFoundError);\n }\n }\n\n static get statusCode() {\n return 404;\n }\n\n static get name() {\n return 'JsonqlResolverNotFoundError';\n }\n}\n","// this is from an example from Koa team to use for internal middleware ctx.throw\n// but after the test the res.body part is unable to extract the required data\n// I keep this one here for future reference\n\nexport default class JsonqlServerError extends Error {\n\n constructor(statusCode, message) {\n super(message)\n this.statusCode = statusCode;\n this.className = JsonqlServerError.name;\n }\n\n static get name() {\n return 'JsonqlServerError';\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","// 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.publicNamespace ].join('/'),\n [ base , config.privateNamespace ].join('/')\n ]\n }\n return [ base ]\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","// 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(client, resolverName, setupResolver(namespace, resolverName, params, fn, ee, log))\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 createNamespaceErrorHandler(client, opts, ee, nspGroup) {\n return [\n // using the onError as name\n // @TODO we should follow the convention earlier\n // make this a setter for the clientitself\n objDefineProps(client, ON_ERROR_FN_NAME, 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 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 createOnReadyHandler(client, opts, ee) {\n return [\n objDefineProps(client, ON_READY_FN_NAME, 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 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} ","// 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 createNamespaceErrorHandler,\n createOnReadyHandler\n} from './resolver-methods'\nimport {\n setupFinalStep \n} from './setup-final-step'\nimport {\n NSP_GROUP\n} from 'jsonql-constants'\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 generator(opts, nspMap, ee) {\n\n let args = [\n generateResolvers,\n createNamespaceErrorHandler,\n createOnReadyHandler\n ]\n if (opts.enableAuth) {\n args.push(\n createAuthMethods\n )\n } \n // we will always get back the [ obj, opts, ee ]\n // then we only return the obj (wsClient)\n args.push(setupFinalStep)\n // run it\n const fn = Reflect.apply(chainFns, null, args)\n\n return fn(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 { generator } from './core'\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} frameworkSocketEngine \n * @param {object} config the already checked config \n */\nexport function wsClientCoreAction(frameworkSocketEngine, config) {\n return postCheckInjectOpts(config)\n // the following two moved to wsPostConfig\n .then(createRequiredParams)\n .then(\n ({opts, nspMap, ee}) => frameworkSocketEngine(opts, nspMap, ee)\n )\n .then(\n ({opts, nspMap, ee}) => generator(opts, nspMap, ee)\n )\n .catch(err => {\n console.error(`jsonql-ws-core-client init error`, err)\n })\n}\n\n/**\n * The main interface which will generate the socket clients and map all events\n * @param {object} frameworkSocketEngine 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(frameworkSocketEngine, configCheckMap = {}, constProps = {}) {\n // we need to inject property to this client later\n return (config = {}) => checkConfiguration(config, configCheckMap, constProps)\n .then(opts => wsClientCoreAction(frameworkSocketEngine, opts))\n}\n","// since both the ws and io version are\n// pre-defined in the client-generator\n// and this one will have the same parameters\n// and the callback is identical\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 } = opts\n const url = namespace ? [hostname, namespace].join('/') : wssPath\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 } = opts\n const url = namespace ? [hostname, namespace].join('/') : wssPath\n if (token && typeof token !== 'string') {\n throw new Error(`Expect token to be string, but got ${token}`)\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}","// 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\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, SOCKET_IO, DISCONNECTED_ERROR_MSG } from '../options/constants'\nimport { createEvt, clearMainEmitEvt } from '../utils'\nimport { triggerNamespacesOnError } from './trigger-namespaces-on-error'\n\n/**\n * A Event handler 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 */\nconst notLoginWsHandler = (namespace, ee, opts) => {\n const { log } = opts \n ee.$only(\n createEvt(namespace, EMIT_EVT),\n function notLoginHandlerCallback(resolverName, args) {\n log('[notLoginHandler] hijack the ws call', namespace, resolverName, args)\n const error = {\n message: NOT_LOGIN_ERR_MSG\n }\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 handler, but wrap inside the error key\n ee.$call(createEvt(namespace, resolverName, ON_RESULT_FN_NAME), [{ error }])\n }\n )\n}\n\n/**\n * A Event handler 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 */\nconst disconnectedHandler = (namespace, ee, opts) => {\n const { log } = opts \n ee.$only(\n createEvt(namespace, EMIT_EVT),\n function disconnectedHandlerCallback(resolverName, args) {\n log(`[disconnectedHandler] 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 handler, but wrap inside the error key\n ee.$call(createEvt(namespace, resolverName, ON_RESULT_FN_NAME), [{ error }])\n }\n )\n}\n\n/**\n * get the private namespace\n * @param {array} namespaces array\n * @return {*} string on success\n */\nconst getPrivateNamespace = (namespaces) => (\n namespaces.length > 1 ? namespaces[0] : false\n)\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 */\nconst logoutEvtHandler = (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(LOGOUT_EVENT_NAME, function logoutEvtHandlerAction() {\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 handler\n triggerNamespacesOnError(ee, [privateNamespace], LOGOUT_EVENT_NAME)\n // rebind all of the handler 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 notLoginWsHandler(privateNamespace, ee, opts)\n })\n}\n\n/**\n * The disconnect event handler, 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 */\nconst disconnectHandler = (nsps, namespaces, ee, opts) => {\n const { log } = opts \n ee.$on(DISCONNECT_EVENT_NAME, function disconnectEvtHandler() {\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 disconnectedHandler(namespace, ee, opts)\n })\n })\n}\n\n/**\n * centralize all the comm in one place\n * @param {object} opts configuration\n * @param {object} ee Event Emitter instance\n * @param {function} bindWsHandler binding the ee to ws --> this is the core bit\n * @param {object} nsps namespaced nsp\n * @return {void} nothing\n */\nexport function clientEventHandler(opts, ee, bindSocketEventHandler, nsps) {\n // since all these params already in the opts\n const { nspMap, 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 let isPrivate = false\n let hasPrivate = false\n // loop\n // @BUG for io this has to be in order the one with auth need to get call first\n // The order of login is very import we need to run in order here to make sure\n // one is execute then the other\n namespaces.forEach(namespace => {\n isPrivate = privateNamespace === namespace\n if (!hasPrivate) {\n hasPrivate = isPrivate\n }\n if (nsps[namespace]) {\n\n log('[call bindWsHandler]', isPrivate, namespace)\n let args = [namespace, nsps[namespace], ee, isPrivate, opts]\n \n if (opts.serverType === SOCKET_IO) {\n let { nspGroup } = nspMap\n args.push(nspGroup[namespace])\n }\n Reflect.apply(bindSocketEventHandler, null, args)\n } else {\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 notLoginWsHandler(namespace, ee, opts)\n }\n })\n // logout event handler \n if (hasPrivate) {\n log(`Has private and add logoutEvtHandler`)\n\n logoutEvtHandler(nsps, namespaces, ee, opts)\n }\n // finally the disconnect event handlers\n disconnectHandler(nsps, namespaces, ee, opts) \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'\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 * @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 */\nfunction initWebSocketClient(WebSocket, auth = false) {\n if (auth === false) {\n return function createWsClientHandler(url) {\n return new WebSocket(fixWss(url))\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 * @return {object} ws instance\n */\n return function createWsAuthClientHandler(url, token) {\n const ws_url = fixWss(url)\n // console.log('what happen here?', url, ws_url, token)\n const uri = token && typeof token === 'string' ? `${ws_url}?${TOKEN_PARAM_NAME}=${token}` : ws_url\n try {\n return new WebSocket(uri)\n } catch(e) {\n console.error('WebSocket Connection Error', e)\n return false\n }\n }\n}\n\nexport { initWebSocketClient }","// @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}","/**\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 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 * 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","// 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","/**\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","// 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' \n\nconst WS_KEYS = [\n WS_REPLY_TYPE,\n WS_EVT_NAME,\n WS_DATA_NAME\n]\nimport isString from 'lodash-es/isString'\nimport { toJson, isFunc, isObjectHasKey, nil } from './generic'\nimport { timestamp } from './timestamp'\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 can not decoded', 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_TYPE,\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 createReplyMsg, \n createEvt, \n extractWsPayload \n} from 'jsonql-utils/module'\nimport {\n handleNamespaceOnError\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 * @return {void}\n */\nconst logoutEventHandler = (ee) => {\n // listen to the LOGOUT_EVENT_NAME when this is a private nsp\n ee.$on(LOGOUT_EVENT_NAME, function closeEvtHandler() {\n try {\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 socketEventHandler(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 = createReplyMsg(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 const json = extractWsPayload(payload)\n const { resolverName, type } = json\n \n log('Hear 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_TYPE:\n // this is handled error and we won't throw it\n // we need to extract the error from json\n log(`ERROR_TYPE`)\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 logoutEventHandler(ee)\n }\n}\n","// actually binding the event client to the socket client\n\n// from the jsonql-ws-client-core\nimport { clientEventHandler } from '../modules'\n// local \nimport { createNspAction } from './create-nsp-action'\nimport { loginEventHandler } from './login-event-handler'\nimport { socketEventHandler } from './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 // arguments for clientEventHandler\n const args = [opts, ee, socketEventHandler]\n\n // now create the nsps\n const { namespaces } = nspMap\n const { token } = opts\n const { nsps } = createNspAction(opts, nspMap, token)\n // binding the listeners - and it will listen to LOGOUT event\n // to unbind itself, and the above call will bind it again\n Reflect.apply(clientEventHandler, null, args.concat([namespaces, nsps]))\n // setup listener for the login event\n if (opts.enableAuth) {\n loginEventHandler(ee, namespaces, nspMap, opts)\n }\n // return what input\n return { opts, nspMap, ee }\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\n\nimport { initWebSocketClient } from './init-websocket-client'\nimport createNsp from '../create-nsp'\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 const publicClient = initWebSocketClient(frameworkModule)\n const privateClient = initWebSocketClient(frameworkModule, true)\n\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 opts.nspClient = publicClient\n opts.nspAuthClient = privateClient \n // @1.0.7 remove later once everything fixed \n const { log } = opts\n if (log && typeof log === 'function') {\n log('@jsonql/ws ee', ee.name)\n log('@jsonql/ws createClientResolver', opts)\n }\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;;;;;;;;;;;;;;;;;"} \ No newline at end of file diff --git a/packages/@jsonql/ws/node.js b/packages/@jsonql/ws/node.js index 2bbf1c5f..357f108e 100644 --- a/packages/@jsonql/ws/node.js +++ b/packages/@jsonql/ws/node.js @@ -1,2 +1,8620 @@ -"use strict";Object.defineProperty(exports,"__esModule",{value:!0});var t,e=(t=require("ws"))&&"object"==typeof t&&"default"in t?t.default:t,r="undefined"!=typeof global?global:"undefined"!=typeof self?self:"undefined"!=typeof window?window:{},n="object"==typeof r&&r&&r.Object===Object&&r,o="object"==typeof self&&self&&self.Object===Object&&self,i=n||o||Function("return this")(),a=i.Symbol;function u(t,e){for(var r=-1,n=null==t?0:t.length,o=Array(n);++r=n?t:function(t,e,r){var n=-1,o=t.length;e<0&&(e=-e>o?0:o+e),(r=r>o?o:r)<0&&(r+=o),o=e>r?0:r-e>>>0,e>>>=0;for(var i=Array(o);++n-1;);return r}(n,o),function(t,e){for(var r=t.length;r--&&O(e,t[r],0)>-1;);return r}(n,o)+1).join("")}var M=function(t){return!!c(t)||null!=t&&""!==L(t)};function J(t){return function(t){return"number"==typeof t||d(t)&&"[object Number]"==g(t)}(t)&&t!=+t}function U(t){return"string"==typeof t||!c(t)&&d(t)&&"[object String]"==g(t)}var D=function(t){return!U(t)&&!J(parseFloat(t))},H=function(t){return""!==L(t)&&U(t)},I=function(t){return null!=t&&"boolean"==typeof t},W=function(t,e){return void 0===e&&(e=!0),void 0!==t&&""!==t&&""!==L(t)&&(!1===e||!0===e&&null!==t)},G=function(t){switch(t){case"number":return D;case"string":return H;case"boolean":return I;default:return W}},B=function(t,e){return void 0===e&&(e=""),!!c(t)&&(""===e||""===L(e)||!(t.filter((function(t){return!G(e)(t)})).length>0))},V=function(t){if(t.indexOf("array.<")>-1&&t.indexOf(">")>-1){var e=t.replace("array.<","").replace(">","");return e.indexOf("|")?e.split("|"):[e]}return!1},Y=function(t,e){var r=t.arg;return e.length>1?!r.filter((function(t){return!(e.length>e.filter((function(e){return!G(e)(t)})).length)})).length:e.length>e.filter((function(t){return!B(r,t)})).length};function K(t,e){return function(r){return t(e(r))}}var Q=K(Object.getPrototypeOf,Object),X=Function.prototype,Z=Object.prototype,tt=X.toString,et=Z.hasOwnProperty,rt=tt.call(Object);function nt(t){if(!d(t)||"[object Object]"!=g(t))return!1;var e=Q(t);if(null===e)return!0;var r=et.call(e,"constructor")&&e.constructor;return"function"==typeof r&&r instanceof r&&tt.call(r)==rt}var ot,it=function(t,e,r){for(var n=-1,o=Object(t),i=r(t),a=i.length;a--;){var u=i[ot?a:++n];if(!1===e(o[u],u,o))break}return t};function at(t){return d(t)&&"[object Arguments]"==g(t)}var ut=Object.prototype,ct=ut.hasOwnProperty,st=ut.propertyIsEnumerable,ft=at(function(){return arguments}())?at:function(t){return d(t)&&ct.call(t,"callee")&&!st.call(t,"callee")};var lt="object"==typeof exports&&exports&&!exports.nodeType&&exports,pt=lt&&"object"==typeof module&&module&&!module.nodeType&&module,ht=pt&&pt.exports===lt?i.Buffer:void 0,vt=(ht?ht.isBuffer:void 0)||function(){return!1},gt=/^(?:0|[1-9]\d*)$/;function dt(t,e){var r=typeof t;return!!(e=null==e?9007199254740991:e)&&("number"==r||"symbol"!=r&>.test(t))&&t>-1&&t%1==0&&t-1&&t%1==0&&t<=9007199254740991}var _t={};_t["[object Float32Array]"]=_t["[object Float64Array]"]=_t["[object Int8Array]"]=_t["[object Int16Array]"]=_t["[object Int32Array]"]=_t["[object Uint8Array]"]=_t["[object Uint8ClampedArray]"]=_t["[object Uint16Array]"]=_t["[object Uint32Array]"]=!0,_t["[object Arguments]"]=_t["[object Array]"]=_t["[object ArrayBuffer]"]=_t["[object Boolean]"]=_t["[object DataView]"]=_t["[object Date]"]=_t["[object Error]"]=_t["[object Function]"]=_t["[object Map]"]=_t["[object Number]"]=_t["[object Object]"]=_t["[object RegExp]"]=_t["[object Set]"]=_t["[object String]"]=_t["[object WeakMap]"]=!1;var bt,mt="object"==typeof exports&&exports&&!exports.nodeType&&exports,jt=mt&&"object"==typeof module&&module&&!module.nodeType&&module,wt=jt&&jt.exports===mt&&n.process,Ot=function(){try{var t=jt&&jt.require&&jt.require("util").types;return t||wt&&wt.binding&&wt.binding("util")}catch(t){}}(),St=Ot&&Ot.isTypedArray,Et=St?(bt=St,function(t){return bt(t)}):function(t){return d(t)&&yt(t.length)&&!!_t[g(t)]},kt=Object.prototype.hasOwnProperty;function $t(t,e){var r=c(t),n=!r&&ft(t),o=!r&&!n&&vt(t),i=!r&&!n&&!o&&Et(t),a=r||n||o||i,u=a?function(t,e){for(var r=-1,n=Array(t);++r-1},Jt.prototype.set=function(t,e){var r=this.__data__,n=Lt(r,t);return n<0?(++this.size,r.push([t,e])):r[n][1]=e,this};var Ut,Dt=i["__core-js_shared__"],Ht=(Ut=/[^.]+$/.exec(Dt&&Dt.keys&&Dt.keys.IE_PROTO||""))?"Symbol(src)_1."+Ut:"";var It=Function.prototype.toString;function Wt(t){if(null!=t){try{return It.call(t)}catch(t){}try{return t+""}catch(t){}}return""}var Gt=/^\[object .+?Constructor\]$/,Bt=Function.prototype,Vt=Object.prototype,Yt=Bt.toString,Kt=Vt.hasOwnProperty,Qt=RegExp("^"+Yt.call(Kt).replace(/[\\^$.*+?()[\]{}|]/g,"\\$&").replace(/hasOwnProperty|(function).*?(?=\\\()| for .+?(?=\\\])/g,"$1.*?")+"$");function Xt(t){return!(!Nt(t)||function(t){return!!Ht&&Ht in t}(t))&&(zt(t)?Qt:Gt).test(Wt(t))}function Zt(t,e){var r=function(t,e){return null==t?void 0:t[e]}(t,e);return Xt(r)?r:void 0}var te=Zt(i,"Map"),ee=Zt(Object,"create");var re=Object.prototype.hasOwnProperty;var ne=Object.prototype.hasOwnProperty;function oe(t){var e=-1,r=null==t?0:t.length;for(this.clear();++eu))return!1;var s=i.get(t);if(s&&i.get(e))return s==e;var f=-1,l=!0,p=2&r?new ce:void 0;for(i.set(t,e),i.set(e,t);++fe.type.filter((function(t){var e;return void 0===r||(!1!==(e=V(t))?!Y({arg:r},e):!G(t)(r))})).length)})).length}return!1},or=function(t){function e(){for(var r=[],n=arguments.length;n--;)r[n]=arguments[n];t.apply(this,r),this.message=r[0],this.detail=r[1],this.className=e.name,t.captureStackTrace&&t.captureStackTrace(this,e)}t&&(e.__proto__=t),e.prototype=Object.create(t&&t.prototype),e.prototype.constructor=e;var r={name:{configurable:!0}};return r.name.get=function(){return"JsonqlValidationError"},Object.defineProperties(e,r),e}(Error),ir=function(t){function e(){for(var r=[],n=arguments.length;n--;)r[n]=arguments[n];t.apply(this,r),this.message=r[0],this.detail=r[1],this.className=e.name,t.captureStackTrace&&t.captureStackTrace(this,e)}t&&(e.__proto__=t),e.prototype=Object.create(t&&t.prototype),e.prototype.constructor=e;var r={name:{configurable:!0},statusCode:{configurable:!0}};return r.name.get=function(){return"JsonqlError"},r.statusCode.get=function(){return-1},Object.defineProperties(e,r),e}(Error),ar=function(t,e){var r,n,o,i,a;switch(!0){case"object"===t:return o=(n=e).arg,i=n.param,a=[o],Array.isArray(i.keys)&&i.keys.length&&a.push(i.keys),!Reflect.apply(nr,null,a);case"array"===t:return!B(e.arg);case!1!==(r=V(t)):return!Y(e,r);default:return!G(t)(e.arg)}},ur=function(t,e){return void 0!==t?t:!0===e.optional&&void 0!==e.defaultvalue?e.defaultvalue:null},cr=function(t,e,r){var n;void 0===r&&(r=!1);var o=function(t,e){if(!B(e))throw new or("params is not an array! Did something gone wrong when you generate the contract.json?");if(0===e.length)return[];if(!B(t))throw new or("args is not an array! You might want to do: ES6 Array.from(arguments) or ES5 Array.prototype.slice.call(arguments)");switch(!0){case t.length==e.length:return t.map((function(t,r){return{arg:t,index:r,param:e[r]}}));case!0===e[0].variable:var r=e[0].type;return t.map((function(t,n){return{arg:t,index:n,param:e[n]||{type:r,name:"_"}}}));case t.lengthe.length:var n=e.length,o=["any"];return t.map((function(t,r){var i=r>=n||!!e[r].optional,a=e[r]||{type:o,name:"_"+r};return{arg:i?ur(t,a):t,index:r,param:a,optional:i}}));default:throw new ir("Could not understand your arguments and parameter structure!",{args:t,params:e})}}(t,e),i=o.filter((function(t){return!0===t.optional||!0===t.param.optional?function(t){var e=t.arg,r=t.param;return!!M(e)&&!(r.type.length>r.type.filter((function(e){return ar(e,t)})).length)}(t):!(t.param.type.length>t.param.type.filter((function(e){return ar(e,t)})).length)}));return r?((n={}).error=i,n.data=o.map((function(t){return t.arg})),n):i},sr=function(){try{var t=Zt(Object,"defineProperty");return t({},"",{}),t}catch(t){}}();function fr(t,e,r){"__proto__"==e&&sr?sr(t,e,{configurable:!0,enumerable:!0,value:r,writable:!0}):t[e]=r}function lr(t,e,r){(void 0===r||Ft(t[e],r))&&(void 0!==r||e in t)||fr(t,e,r)}var pr="object"==typeof exports&&exports&&!exports.nodeType&&exports,hr=pr&&"object"==typeof module&&module&&!module.nodeType&&module,vr=hr&&hr.exports===pr?i.Buffer:void 0,gr=vr?vr.allocUnsafe:void 0;function dr(t,e){var r,n,o=e?(r=t.buffer,n=new r.constructor(r.byteLength),new le(n).set(new le(r)),n):t.buffer;return new t.constructor(o,t.byteOffset,t.length)}var yr=Object.create,_r=function(){function t(){}return function(e){if(!Nt(e))return{};if(yr)return yr(e);t.prototype=e;var r=new t;return t.prototype=void 0,r}}();function br(t,e){if(("constructor"!==e||"function"!=typeof t[e])&&"__proto__"!=e)return t[e]}var mr=Object.prototype.hasOwnProperty;function jr(t,e,r){var n=t[e];mr.call(t,e)&&Ft(n,r)&&(void 0!==r||e in t)||fr(t,e,r)}var wr=Object.prototype.hasOwnProperty;function Or(t){if(!Nt(t))return function(t){var e=[];if(null!=t)for(var r in Object(t))e.push(r);return e}(t);var e=At(t),r=[];for(var n in t)("constructor"!=n||!e&&wr.call(t,n))&&r.push(n);return r}function Sr(t){return Ct(t)?$t(t,!0):Or(t)}function Er(t){return function(t,e,r,n){var o=!r;r||(r={});for(var i=-1,a=e.length;++i0){if(++e>=800)return arguments[0]}else e=0;return t.apply(void 0,arguments)}}(Pr);function zr(t,e){return Nr(function(t,e,r){return e=Ar(void 0===e?t.length-1:e,0),function(){for(var n=arguments,o=-1,i=Ar(n.length-e,0),a=Array(i);++o1?e[n-1]:void 0,i=n>2?e[2]:void 0;for(o=Cr.length>3&&"function"==typeof o?(n--,o):void 0,i&&function(t,e,r){if(!Nt(r))return!1;var n=typeof e;return!!("number"==n?Ct(r)&&dt(e,r.length):"string"==n&&e in r)&&Ft(r[e],t)}(e[0],e[1],i)&&(o=n<3?void 0:o,n=1),t=Object(t);++r0;)e[r]=arguments[r+1];if(this.logger("($queue) get called"),!0===this.__suspend_state__){if(un(this.__pattern__)){var n=this.__pattern__.test(t);if(!n)return!1}this.logger("($queue) added to $queue",e),this.queueStore.add([t].concat(e))}return!!this.__suspend_state__},fn.$queues.get=function(){var t=this.queueStore.size;return this.logger("($queues)","size: "+t),t>0?Array.from(this.queueStore):[]},sn.prototype.__suspend__=function(t){if("boolean"!=typeof t)throw new Error("$suspend only accept Boolean value! we got "+typeof t);var e=this.__suspend_state__;this.__suspend_state__=t,this.logger('($suspend) Change from "'+e+'" --\x3e "'+t+'"'),!0===e&&!1===t&&this.__release__()},sn.prototype.__release__=function(){var t=this,e=this.queueStore.size,r=this.__pattern__;if(this.__pattern__=null,this.logger("(release) was called with "+e+(r?' for "'+r+'"':"")+" item"+(e>1?"s":"")),e>0){var n=Array.from(this.queueStore);this.queueStore.clear(),this.logger("(release queue)",n),n.forEach((function(e){t.logger(e),Reflect.apply(t.$trigger,t,e)})),this.logger("Release size "+this.queueStore.size)}return e},Object.defineProperties(sn.prototype,fn);var ln=function(t){function e(e){if("function"!=typeof e)throw new Error("Just die here the logger is not a function!");e("---\x3e Create a new EventEmitter <---"),t.call(this,{logger:e})}t&&(e.__proto__=t),e.prototype=Object.create(t&&t.prototype),e.prototype.constructor=e;var r={name:{configurable:!0}};return r.name.get=function(){return"jsonql-ws-client-core"},Object.defineProperties(e.prototype,r),e}(function(t){function e(e){void 0===e&&(e={}),t.call(this,e)}t&&(e.__proto__=t),e.prototype=Object.create(t&&t.prototype),e.prototype.constructor=e;var r={$name:{configurable:!0},is:{configurable:!0},$done:{configurable:!0}};return e.prototype.logger=function(){},r.$name.get=function(){return"to1source-event"},r.is.get=function(){return this.$name},e.prototype.$on=function(t,e,r){var n=this;void 0===r&&(r=null);this.validate(t,e);var o=this.takeFromStore(t);if(!1===o)return this.logger('($on) "'+t+'" is not in lazy store'),this.addToNormalStore(t,"on",e,r);this.logger("($on) "+t+" found in lazy store");var i=0;return o.forEach((function(o){var a=o[0],u=o[1],c=o[2];if(c&&"on"!==c)throw new Error(nn+" "+c);n.logger("($on)",'call run "'+t+'"'),n.run(e,a,r||u),i+=n.addToNormalStore(t,"on",e,r||u)})),this.logger("($on) return size "+i),i},e.prototype.$once=function(t,e,r){void 0===r&&(r=null),this.validate(t,e);var n=this.takeFromStore(t);this.normalStore;if(!1===n)return this.logger('($once) "'+t+'" is not in the lazy store'),this.addToNormalStore(t,"once",e,r);this.logger("($once)",n);var o=Array.from(n)[0],i=o[0],a=o[1],u=o[2];if(u&&"once"!==u)throw new Error(nn+" "+u);this.logger("($once)",'call run "'+t+'"'),this.run(e,i,r||a),this.$off(t)},e.prototype.$only=function(t,e,r){var n=this;void 0===r&&(r=null),this.validate(t,e);var o=!1,i=this.takeFromStore(t);(this.normalStore.has(t)||(this.logger('($only) "'+t+'" add to normalStore'),o=this.addToNormalStore(t,"only",e,r)),!1!==i)&&(this.logger('($only) "'+t+'" found data in lazy store to execute'),Array.from(i).forEach((function(o){var i=o[0],a=o[1],u=o[2];if(u&&"only"!==u)throw new Error(nn+" "+u);n.logger('($only) call run "'+t+'"'),n.run(e,i,r||a)})));return o},e.prototype.$onlyOnce=function(t,e,r){void 0===r&&(r=null),this.validate(t,e);var n=!1,o=this.takeFromStore(t);if(this.normalStore.has(t)||(this.logger('($onlyOnce) "'+t+'" add to normalStore'),n=this.addToNormalStore(t,"onlyOnce",e,r)),!1!==o){this.logger("($onlyOnce)",o);var i=Array.from(o)[0],a=i[0],u=i[1],c=i[2];if(c&&"onlyOnce"!==c)throw new Error(nn+" "+c);this.logger('($onlyOnce) call run "'+t+'"'),this.run(e,a,r||u),this.$off(t)}return n},e.prototype.$replace=function(t,e,r,n){if(void 0===r&&(r=null),void 0===n&&(n="on"),this.validateType(n)){this.$off(t);var o=this["$"+n];return this.logger("($replace)",t,e),Reflect.apply(o,this,[t,e,r])}throw new Error(n+" is not supported!")},e.prototype.$trigger=function(t,e,r,n){void 0===e&&(e=[]),void 0===r&&(r=null),void 0===n&&(n=!1),this.validateEvt(t);var o=0,i=this.normalStore;if(this.logger("($trigger) normalStore",i),i.has(t)){if(this.logger('($trigger) "'+t+'" found'),this.$queue(t,e,r,n))return this.logger('($trigger) Currently suspended "'+t+'" added to queue, nothing executed. Exit now.'),!1;for(var a=Array.from(i.get(t)),u=a.length,c=!1,s=0;s0;)n[o]=arguments[o+2];if(t.has(e)?(this.logger('(addToStore) "'+e+'" existed'),r=t.get(e)):(this.logger('(addToStore) create new Set for "'+e+'"'),r=new Set),n.length>2)if(Array.isArray(n[0])){var i=n[2];this.checkTypeInLazyStore(e,i)||r.add(n)}else this.checkContentExist(n,r)||(this.logger("(addToStore) insert new",n),r.add(n));else r.add(n);return t.set(e,r),[t,r.size]},e.prototype.checkContentExist=function(t,e){return!!Array.from(e).filter((function(e){return e[0]===t[0]})).length},e.prototype.checkTypeInStore=function(t,e){this.validateEvt(t,e);var r=this.$get(t,!0);return!1===r||!r.filter((function(t){var r=t[3];return e!==r})).length},e.prototype.checkTypeInLazyStore=function(t,e){this.validateEvt(t,e);var r=this.lazyStore.get(t);return this.logger("(checkTypeInLazyStore)",r),!!r&&!!Array.from(r).filter((function(t){return t[2]!==e})).length},e.prototype.addToNormalStore=function(t,e,r,n){if(void 0===n&&(n=null),this.logger('(addToNormalStore) try to add "'+e+'" --\x3e "'+t+'" to normal store'),this.checkTypeInStore(t,e)){this.logger("(addToNormalStore)",'"'+e+'" --\x3e "'+t+'" can add to normal store');var o=this.hashFnToKey(r),i=[this.normalStore,t,o,r,n,e],a=Reflect.apply(this.addToStore,this,i),u=a[0],c=a[1];return this.normalStore=u,c}return!1},e.prototype.addToLazyStore=function(t,e,r,n){void 0===e&&(e=[]),void 0===r&&(r=null),void 0===n&&(n=!1);var o=[this.lazyStore,t,this.toArray(e),r];n&&o.push(n);var i=Reflect.apply(this.addToStore,this,o),a=i[0],u=i[1];return this.lazyStore=a,this.logger("(addToLazyStore) size: "+u),u},e.prototype.toArray=function(t){return Array.isArray(t)?t:[t]},r.normalStore.set=function(t){on.set(this,t)},r.normalStore.get=function(){return on.get(this)},r.lazyStore.set=function(t){an.set(this,t)},r.lazyStore.get=function(){return an.get(this)},e.prototype.hashFnToKey=function(t){return function(t){return t.split("").reduce((function(t,e){return(t=(t<<5)-t+e.charCodeAt(0))&t}),0)}(t.toString())+""},Object.defineProperties(e.prototype,r),e}(sn))),pn=function(t){return c(t)?t:[t]},hn=function(t,e){try{var r=Object.keys(t);return n=e,!!r.filter((function(t){return t===n})).length}catch(t){return!1}var n},vn=function(){for(var t=[],e=arguments.length;e--;)t[e]=arguments[e];return t.join("_")},gn=function(t){if("function"==typeof t)return!0;console.error("Expect to be Function type! Got "+typeof t)},dn=function(){return!1},yn=function(t){for(var e=[],r=arguments.length-1;r-- >0;)e[r]=arguments[r+1];return function(){for(var r=[],n=arguments.length;n--;)r[n]=arguments[n];return e.reduce((function(t,e){return Reflect.apply(e,null,pn(t))}),Reflect.apply(t,null,r))}};function _n(t,e,r,n){return void 0===n&&(n=null),void 0===Object.getOwnPropertyDescriptor(t,e)&&Object.defineProperty(t,e,{set:r,get:null===n?function(){return null}:n}),t}function bn(t,e,r,n){void 0===n&&(n=!1);var o=function(t,e){var r=Object.getOwnPropertyDescriptor(t,e);return void 0!==r&&r.value?r.value:r}(t,e);return!1===n&&void 0!==o||Object.defineProperty(t,e,{value:r,writable:n}),t}var mn=function(t){function e(){for(var r=[],n=arguments.length;n--;)r[n]=arguments[n];t.apply(this,r),this.message=r[0],this.detail=r[1],this.className=e.name,t.captureStackTrace&&t.captureStackTrace(this,e)}t&&(e.__proto__=t),e.prototype=Object.create(t&&t.prototype),e.prototype.constructor=e;var r={statusCode:{configurable:!0},name:{configurable:!0}};return r.statusCode.get=function(){return 406},r.name.get=function(){return"Jsonql406Error"},Object.defineProperties(e,r),e}(Error),jn=function(t){function e(){for(var r=[],n=arguments.length;n--;)r[n]=arguments[n];t.apply(this,r),this.message=r[0],this.detail=r[1],this.className=e.name,t.captureStackTrace&&t.captureStackTrace(this,e)}t&&(e.__proto__=t),e.prototype=Object.create(t&&t.prototype),e.prototype.constructor=e;var r={statusCode:{configurable:!0},name:{configurable:!0}};return r.statusCode.get=function(){return 500},r.name.get=function(){return"Jsonql500Error"},Object.defineProperties(e,r),e}(Error),wn=function(t){function e(){for(var r=[],n=arguments.length;n--;)r[n]=arguments[n];t.apply(this,r),this.message=r[0],this.detail=r[1],this.className=e.name,t.captureStackTrace&&t.captureStackTrace(this,e)}t&&(e.__proto__=t),e.prototype=Object.create(t&&t.prototype),e.prototype.constructor=e;var r={statusCode:{configurable:!0},name:{configurable:!0}};return r.statusCode.get=function(){return 403},r.name.get=function(){return"JsonqlForbiddenError"},Object.defineProperties(e,r),e}(Error),On=function(t){function e(){for(var r=[],n=arguments.length;n--;)r[n]=arguments[n];t.apply(this,r),this.message=r[0],this.detail=r[1],this.className=e.name,t.captureStackTrace&&t.captureStackTrace(this,e)}t&&(e.__proto__=t),e.prototype=Object.create(t&&t.prototype),e.prototype.constructor=e;var r={statusCode:{configurable:!0},name:{configurable:!0}};return r.statusCode.get=function(){return 401},r.name.get=function(){return"JsonqlAuthorisationError"},Object.defineProperties(e,r),e}(Error),Sn=function(t){function e(){for(var r=[],n=arguments.length;n--;)r[n]=arguments[n];t.apply(this,r),this.message=r[0],this.detail=r[1],this.className=e.name,t.captureStackTrace&&t.captureStackTrace(this,e)}t&&(e.__proto__=t),e.prototype=Object.create(t&&t.prototype),e.prototype.constructor=e;var r={statusCode:{configurable:!0},name:{configurable:!0}};return r.statusCode.get=function(){return 401},r.name.get=function(){return"JsonqlContractAuthError"},Object.defineProperties(e,r),e}(Error),En=function(t){function e(){for(var r=[],n=arguments.length;n--;)r[n]=arguments[n];t.apply(this,r),this.message=r[0],this.detail=r[1],this.className=e.name,t.captureStackTrace&&t.captureStackTrace(this,e)}t&&(e.__proto__=t),e.prototype=Object.create(t&&t.prototype),e.prototype.constructor=e;var r={statusCode:{configurable:!0},name:{configurable:!0}};return r.statusCode.get=function(){return 500},r.name.get=function(){return"JsonqlResolverAppError"},Object.defineProperties(e,r),e}(Error),kn=function(t){function e(){for(var r=[],n=arguments.length;n--;)r[n]=arguments[n];t.apply(this,r),this.message=r[0],this.detail=r[1],this.className=e.name,t.captureStackTrace&&t.captureStackTrace(this,e)}t&&(e.__proto__=t),e.prototype=Object.create(t&&t.prototype),e.prototype.constructor=e;var r={statusCode:{configurable:!0},name:{configurable:!0}};return r.statusCode.get=function(){return 404},r.name.get=function(){return"JsonqlResolverNotFoundError"},Object.defineProperties(e,r),e}(Error),$n=function(t){function e(r,n){t.call(this,n),this.statusCode=r,this.className=e.name}t&&(e.__proto__=t),e.prototype=Object.create(t&&t.prototype),e.prototype.constructor=e;var r={name:{configurable:!0}};return r.name.get=function(){return"JsonqlServerError"},Object.defineProperties(e,r),e}(Error);function Tn(t){if(Array.isArray(t))throw new or("",t);var e=t.message||"No message",r=t.detail||t;switch(!0){case t instanceof mn:throw new mn(e,r);case t instanceof jn:throw new jn(e,r);case t instanceof wn:throw new wn(e,r);case t instanceof On:throw new On(e,r);case t instanceof Sn:throw new Sn(e,r);case t instanceof En:throw new En(e,r);case t instanceof kn:throw new kn(e,r);case t instanceof Wr:throw new Wr(e,r);case t instanceof Gr:throw new Gr(e,r);case t instanceof Br:throw new Br(e,r);case t instanceof or:throw new or(e,r);case t instanceof $n:throw new $n(e,r);default:throw new ir(e,r)}}function An(t){var e=function(t){return!!hn(t,"socket")&&t.socket}(t);if(!1===e)throw new JsonqlError("groupByNamespace","socket not found in contract!");var r={nspGroup:{},publicNamespace:null,size:0};for(var n in e){var o=e[n],i=o.namespace;i&&(r.nspGroup[i]||(++r.size,r.nspGroup[i]={}),r.nspGroup[i][n]=o,!r.publicNamespace&&o.public&&(r.publicNamespace=i))}return r}var Pn=function(t){var e=t.toLowerCase();return e.indexOf("http")>-1?e.indexOf("https")>-1?e.replace("https","wss"):e.replace("http","ws"):e},xn=function(t,e){pn(e).forEach((function(e){t.$off(vn(e,"emit_reply"))}))},Nn=function(t,e,r){return[bn(t,e.loginHandlerName,(function(t){if(t&&Qr(t))return e.log("Received __login__ with "+t),r.$trigger("__login__",[t]);throw new or(e.loginHandlerName,"Unexpected token "+t)})),e,r]},zn=function(t,e,r){return[bn(t,e.logoutHandlerName,(function(){for(var t=[],e=arguments.length;e--;)t[e]=arguments[e];r.$trigger("__logout__",t)})),e,r]},Cn=function(t,e,r){return[_n(t,"onLogin",(function(t){gn(t)&&r.$only("onLogin",t)})),e,r]};function Rn(t,e,r){return yn(Nn,zn,Cn)(t,e,r)}function qn(t,e,r){hn(t,"error")?r(t.error):hn(t,"data")?e(t.data):r({message:"UKNNOWN RESULT!",error:t})}function Fn(t,e,r,n,o){void 0===n&&(n=[]);var i=vn(e,"emit_reply");return o("actionCall: "+i+" --\x3e "+r,n),t.$trigger(i,[r,pn(n)]),new Promise((function(n,i){var a=vn(e,r,"onResult");t.$on(a,(function(t){o("got the first result",t),qn(t,n,i)}))}))}var Ln,Mn,Jn,Un=function(t,e,r,n,o,i){return _n(t,"send",dn,(function(){return function(){for(var t=[],a=arguments.length;a--;)t[a]=arguments[a];return Xr(t,o.params,!0).then((function(t){return i(r,n,t),Fn(e,r,n,t,_log)})).catch((function(t){i("send error",t),e.$call(vn(r,n,"onError"),[new or(n,t)])}))}}))},Dn=function(t,e,r,n,o,i){return[bn(t,"myNamespace",r),e,r,n,o,i]},Hn=function(t,e,r,n,o,i){return[_n(t,"onResult",(function(t){gn(t)&&e.$on(vn(r,n,"onResult"),(function(o){qn(o,t,(function(t){i('Catch error: "'+n+'"',t),e.$trigger(vn(r,n,"onError"),t)}))}))})),e,r,n,o,i]},In=function(t,e,r,n,o,i){return[_n(t,"onMessage",(function(t){if(gn(t)){e.$only(vn(r,n,"onMessage"),(function(o){qn(o,t,(function(t){i('Catch error: "'+n+'"',t),e.$trigger(vn(r,n,"onError"),t)}))}))}})),e,r,n,o,i]},Wn=function(t,e,r,n,o,i){return[_n(t,"onError",(function(t){gn(t)&&e.$only(vn(r,n,"onError"),t)})),e,r,n,o,i]};function Gn(t,e,r,n,o,i){var a=[Dn,Hn,In,Wn,Un],u=Reflect.apply(yn,null,a),c=[n,o,t,e,r,i];return Reflect.apply(u,null,c)}function Bn(t,e,r,n,o){return function(){for(var i=[],a=arguments.length;a--;)i[a]=arguments[a];return Xr(i,n.params,!0).then((function(n){return Fn(t,e,r,n,o)})).catch(Tn)}}function Vn(t,e,r){var n={},o=t.log;for(var i in r){var a=r[i];for(var u in a){var c=a[u];n=bn(n,u,Gn(i,u,c,Bn(e,i,u,c,o),e,o))}}return[n,t,e,r]}function Yn(t,e,r,n){return[_n(t,"onError",(function(t){if(gn(t))for(var e in n)r.$on(vn(e,"onError"),t)})),e,r]}function Kn(t,e,r){return[_n(t,"onReady",(function(t){gn(t)&&r.$on("onReady",t)})),e,r]}function Qn(t,e,r){var n=function(t,e,r){return bn(t,e.disconnectHandlerName,(function(){for(var t=[],e=arguments.length;e--;)t[e]=arguments[e];r.$trigger("__disconnect__",t)}))}(t,e,r);return e.log("---\x3e The final step to return the ws-client <---"),n.verifyEventEmitter=function(){return r.is},n.eventEmitter=e.eventEmitter,n.log=e.log,n}var Xn=["roundtip","handshake"],Zn={standalone:Zr(!1,["boolean"]),debugOn:Zr(!1,["boolean"]),loginHandlerName:Zr("login",["string"]),logoutHandlerName:Zr("logout",["string"]),disconnectHandlerName:Zr("disconnect",["string"]),switchUserHandlerName:Zr("switch-user",["string"]),loginMethod:Zr("handshake",["string"],(Ln={},Ln.enumv=Xn,Ln)),useJwt:Zr(!0,["boolean","string"]),authStrKey:Zr(null,["string"]),hostname:Zr(!1,["string"]),namespace:Zr("jsonql",["string"]),wsOptions:Zr({},["object"]),contract:Zr({},["object"],(Mn={},Mn.checker=function(t){return!!function(t){return nt(t)&&(hn(t,"query")||hn(t,"mutation")||hn(t,"socket"))}(t)&&t},Mn)),enableAuth:Zr(!1,["boolean"]),token:Zr(!1,["string"])},to={};to.serverType=Zr(null,["string"],((Jn={}).alias="socketClientType",Jn));var eo=Object.assign(Zn,to);function ro(t){return Promise.resolve(t).then((function(t){return t.hostname||(t.hostname=function(){try{return[window.location.protocol,window.location.host].join("//")}catch(t){throw new or(t)}}()),t.wssPath=Pn([t.hostname,t.namespace].join("/"),t.serverType),t.log=rn(t),t.eventEmitter=function(t){var e=t.log,r=t.eventEmitter;return r?(e("eventEmitter is:",r.name),r):new ln(t.log)}(t),t}))}function no(t){return{opts:t,nspMap:(e=t,r=e.contract,n=e.enableAuth,o=function(t){var e="jsonql";return t.enableAuth?[[e,t.publicNamespace].join("/"),[e,t.privateNamespace].join("/")]:[e]}(e),i=n?An(r):function(t,e){var r,n={};for(var o in t){var i=t[o];n[o]=i}return{size:1,nspGroup:(r={},r[e]=n,r),publicNamespace:e}}(r.socket,o[0]),Object.assign(i,{namespaces:o})),ee:t.eventEmitter};var e,r,n,o,i}function oo(t,e){return ro(e).then(no).then((function(e){var r=e.opts,n=e.nspMap,o=e.ee;return t(r,n,o)})).then((function(t){return function(t,e,r){var n=[Vn,Yn,Kn];return t.enableAuth&&n.push(Rn),n.push(Qn),Reflect.apply(yn,null,n)(t,r,e.nspGroup)}(t.opts,t.nspMap,t.ee)})).catch((function(t){console.error("jsonql-ws-core-client init error",t)}))}function io(t,e){var r=e.hostname,n=e.wssPath,o=e.wsOptions;return(0,e.nspClient)(t?[r,t].join("/"):n,o)}function ao(t,e,r){e.forEach((function(e){t.$trigger(vn(e,"onError"),[{message:r,namespace:e}])}))}var uo=function(t,e,r){var n=r.log;e.$only(vn(t,"emit_reply"),(function(r,o){n("[notLoginHandler] hijack the ws call",t,r,o);var i={message:"NOT LOGIN"};e.$call(vn(t,r,"onError"),[i]),e.$call(vn(t,r,"onResult"),[{error:i}])}))},co=function(t){return t.length>1&&t[0]},so=function(t,e,r,n){var o=n.log;r.$on("__disconnect__",(function(){ao(r,e,"__disconnect__"),e.forEach((function(e){o("disconnect from "+e),xn(r,e),t[e]=null,function(t,e,r){var n=r.log;e.$only(vn(t,"emit_reply"),(function(r,o){n("[disconnectedHandler] hijack the ws call",t,r,o);var i={message:"You have disconnected from the socket server, please reconnect."};e.$call(vn(t,r,"onError"),[i]),e.$call(vn(t,r,"onResult"),[{error:i}])}))}(e,r,n)}))}))};function fo(t,e,r,n,o,i){var a=co(o),u=!1,c=!1,s=t.log;o.forEach((function(o){if(u=a===o,c||(c=u),i[o]){s("[call bindWsHandler]",u,o);var f=[o,i[o],r,u,t];if("socket.io"===t.serverType){var l=e.nspSet;f.push(l[o])}Reflect.apply(n,null,f)}else uo(o,r,t)})),c&&(s("Has private and add logoutEvtHandler"),function(t,e,r,n){var o=n.log;r.$on("__logout__",(function(){var i=co(e);o("__logout__ event triggered"),ao(r,[i],"__logout__"),o("logout from "+i),xn(r,i),t[i]=null,uo(i,r,n)}))}(i,o,r,t)),so(i,o,r,t)}var lo={version:"version: 1.1.1 module: cjs-module",serverType:"ws"},po=Object.assign({},eo,{}),ho=Object.assign({},{log:null,eventEmitter:null,nspClient:null,nspAuthClient:null,wssPath:""},lo);function vo(t,e){return void 0===e&&(e=!1),!1===e?function(e){return new t(Pn(e))}:function(e,r){var n=Pn(e),o=r&&"string"==typeof r?n+"?token="+r:n;try{return new t(o)}catch(t){return console.error("WebSocket Connection Error",t),!1}}}var go=Array.isArray,yo="object"==typeof r&&r&&r.Object===Object&&r,_o="object"==typeof self&&self&&self.Object===Object&&self,bo=(yo||_o||Function("return this")()).Symbol,mo=Object.prototype,jo=mo.hasOwnProperty,wo=mo.toString,Oo=bo?bo.toStringTag:void 0;var So=Object.prototype.toString;var Eo=bo?bo.toStringTag:void 0;function ko(t){return null==t?void 0===t?"[object Undefined]":"[object Null]":Eo&&Eo in Object(t)?function(t){var e=jo.call(t,Oo),r=t[Oo];try{t[Oo]=void 0;var n=!0}catch(t){}var o=wo.call(t);return n&&(e?t[Oo]=r:delete t[Oo]),o}(t):function(t){return So.call(t)}(t)}function $o(t){return null!=t&&"object"==typeof t}var To=bo?bo.prototype:void 0,Ao=To?To.toString:void 0;function Po(t){if("string"==typeof t)return t;if(go(t))return function(t,e){for(var r=-1,n=null==t?0:t.length,o=Array(n);++r=n?t:function(t,e,r){var n=-1,o=t.length;e<0&&(e=-e>o?0:o+e),(r=r>o?o:r)<0&&(r+=o),o=e>r?0:r-e>>>0,e>>>=0;for(var i=Array(o);++n-1;);return r}(o,i),function(t,e){for(var r=t.length;r--&&zo(e,t[r],0)>-1;);return r}(o,i)+1).join("")}var Vo=function(){for(var t=[],e=arguments.length;e--;)t[e]=arguments[e];return t.join("_")},Yo=function(t){function e(){for(var r=[],n=arguments.length;n--;)r[n]=arguments[n];t.apply(this,r),this.message=r[0],this.detail=r[1],this.className=e.name,t.captureStackTrace&&t.captureStackTrace(this,e)}t&&(e.__proto__=t),e.prototype=Object.create(t&&t.prototype),e.prototype.constructor=e;var r={name:{configurable:!0}};return r.name.get=function(){return"JsonqlValidationError"},Object.defineProperties(e,r),e}(Error),Ko=function(t){function e(){for(var r=[],n=arguments.length;n--;)r[n]=arguments[n];t.apply(this,r),this.message=r[0],this.detail=r[1],this.className=e.name,t.captureStackTrace&&t.captureStackTrace(this,e)}t&&(e.__proto__=t),e.prototype=Object.create(t&&t.prototype),e.prototype.constructor=e;var r={name:{configurable:!0},statusCode:{configurable:!0}};return r.name.get=function(){return"JsonqlError"},r.statusCode.get=function(){return-1},Object.defineProperties(e,r),e}(Error),Qo=function(t){void 0===t&&(t=!1);var e=Date.now();return t?Math.floor(e/1e3):e};function Xo(t){return"string"==typeof t||!go(t)&&$o(t)&&"[object String]"==ko(t)}function Zo(t,e,r){if(void 0===e&&(e=[]),void 0===r&&(r=!1),Xo(t)&&go(e)){var n=function(t){var e;return(e={}).args=t,e}(e);return!0===r?n:function(t,e){var r;return(r={})[t]=e,r.TS=[Qo()],r}(t,n)}throw new Yo("[createQuery] expect resolverName to be string and args to be array!",{resolverName:t,args:e})}var ti=function(t){return""!==Bo(t)&&Xo(t)},ei=["__reply__","__event__","__data__"],ri=function(t){var e=t.data;return!!e&&(ei.filter((function(t){return function(t,e){try{var r=Object.keys(t);return n=e,!!r.filter((function(t){return t===n})).length}catch(t){return!1}var n}(e,t)})).length===ei.length&&e)},ni=function(t,e,r,n,o){var i=[e];r&&i.push(r),i.push(o);var a=Reflect.apply(Vo,null,i),u=n.data||n;t.$trigger(a,[u])};function oi(t,e,r,n,o){var i=o.log;i("log test, isPrivate:",n),e.onopen=function(){i("ws.onopen listened"),r.$call("onReady",t),n&&(i("isPrivate and fire the onLogin"),r.$call("onLogin",t)),r.$only(Vo(t,"emit_reply"),(function(t,r){var n=function(t,e,r){return void 0===e&&(e=[]),void 0===r&&(r=!1),JSON.stringify(Zo(t,e,r))}(t,r);i("calling server",t,r,n),e.send(n)}))},e.onmessage=function(e){try{var n=function(t){var e,r=t.data,n=ti(r)?JSON.parse(r):r;if(!1!==(e=ri(n)))return{resolverName:e.__event__,data:e.__data__,type:e.__reply__};throw new Ko("payload can not be decoded",t)}(e),o=n.resolverName,a=n.type;switch(i("Hear from server",a,n),a){case"emit_reply":var u=Vo(t,o,"onMessage"),c=r.$trigger(u,[n]);i("EMIT_REPLY_TYPE",u,c);break;case"acknowledge_reply":var s=Vo(t,o,"onResult"),f=r.$trigger(s,[n]);i("ACKNOWLEDGE_REPLY_TYPE",s,f);break;case"error":i("ERROR_TYPE"),ni(r,t,o,n,"onError");break;default:i("Unhandled event!",n),ni(r,t,o,n,"onError")}}catch(e){console.error("ws.onmessage error",e),ni(r,t,!1,e,"onError")}},e.onclose=function(){i("ws.onclose callback")},e.onerror=function(e){i("ws.onerror",e),r.$trigger(Vo(t,"onError"),[e])},n&&r.$on("__logout__",(function(){try{i("terminate ws connection"),e.terminate()}catch(t){console.error("ws.terminate error",t)}}))}var ii=function(t,e,r){var n,o=t.log,i=e.nspGroup,a=e.publicNamespace,u=!1,c=[],s={};if(t.enableAuth)u=!0,s=(c=function(t,e){var r=[];for(var n in t)n===e?r[1]=n:r[0]=n;return r}(i,a)).map((function(e,n){var i,a,u;return 0===n?r?(t.token=r,o("create createNspAuthClient at run time"),(i={})[e]=function(t,e){var r=e.hostname,n=e.wssPath,o=e.token,i=e.wsOptions,a=e.nspAuthClient,u=t?[r,t].join("/"):n;if(o&&"string"!=typeof o)throw new Error("Expect token to be string, but got "+o);return a(u,o,i)}(e,t),i):((a={})[e]=!1,a):((u={})[e]=io(e,t),u)})).reduce((function(t,e){return Object.assign(t,e)}),{});else{var f=(n=i,console.error("This method is going to be deprectead in the next release, please use getResolverFromPayload instead"),Object.keys(n)[0]);c.push(f),s[f]=io(!1,t)}return{nsps:s,namespaces:c,loginRequired:u}};function ai(t,e,r,n){var o=n.log;t.$only("__login__",(function(i){o("createClient LOGIN_EVENT_NAME $only handler"),xn(t,e);var a=ii(n,r,i);Reflect.apply(fo,null,args.concat([a.namespaces,a.nsps]))}))}var ui,ci,si,fi,li=(ci=vo(ui=e),si=vo(ui,!0),function(t,e,r){t.nspClient=ci,t.nspAuthClient=si;var n=t.log;return n&&"function"==typeof n&&(n("@jsonql/ws ee",r.name),n("@jsonql/ws createClientResolver",t)),function(t,e,r){var n=[t,e,r,oi],o=t.token,i=(t.log,ii(t,e,o)),a=i.nsps,u=i.namespaces,c=i.loginRequired;return Reflect.apply(fo,null,n.concat([u,a])),c&&ai(r,u,e,t),{opts:t,nspMap:e,ee:r}}(t,e,r)}),pi=(fi=li,function(t){return Promise.resolve(t).then((function(t){return oo(fi,t)}))});exports.checkSocketClientType=function(t){return tn(t,to)},exports.createWsClient=pi,exports.jsonqlWsClientAppProps=po,exports.jsonqlWsConstProps=ho; +'use strict'; + +Object.defineProperty(exports, '__esModule', { value: true }); + +function _interopDefault (ex) { return (ex && (typeof ex === 'object') && 'default' in ex) ? ex['default'] : ex; } + +var WebSocket = _interopDefault(require('ws')); + +var ERROR_KEY = 'error'; +var TIMESTAMP_PARAM_NAME = 'TS'; +var NO_STATUS_CODE = -1; +var LOGIN_EVENT_NAME = '__login__'; +var LOGOUT_EVENT_NAME = '__logout__'; +// for ws servers +var WS_REPLY_TYPE = '__reply__'; +var WS_EVT_NAME = '__event__'; +var WS_DATA_NAME = '__data__'; +// this is somewhat vague about what is suppose to do +var EMIT_REPLY_TYPE = 'emit_reply'; +var ACKNOWLEDGE_REPLY_TYPE = 'acknowledge_reply'; +var ERROR_TYPE = ERROR_KEY; // Should replace with ERROR_KEY +var JS_WS_NAME = 'ws'; + +// for ws client, 1.9.3 breaking change to name them as FN instead of PROP +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 +var TOKEN_PARAM_NAME = 'token'; + +// jsonql-ws-core takes over the check configuration +// constant props +var wsClientConstProps = { + version: 'version: 1.2.0 module: cjs-module', // will get replace + serverType: JS_WS_NAME +}; + +var global$1 = (typeof global !== "undefined" ? global : + typeof self !== "undefined" ? self : + typeof window !== "undefined" ? window : {}); + +/** Detect free variable `global` from Node.js. */ +var freeGlobal = typeof global$1 == 'object' && global$1 && global$1.Object === Object && global$1; + +/** Detect free variable `self`. */ +var freeSelf = typeof self == 'object' && self && self.Object === Object && self; + +/** Used as a reference to the global object. */ +var root = freeGlobal || freeSelf || Function('return this')(); + +/** Built-in value references. */ +var Symbol = root.Symbol; + +/** + * A specialized version of `_.map` for arrays without support for iteratee + * shorthands. + * + * @private + * @param {Array} [array] The array to iterate over. + * @param {Function} iteratee The function invoked per iteration. + * @returns {Array} Returns the new mapped array. + */ +function arrayMap(array, iteratee) { + var index = -1, + length = array == null ? 0 : array.length, + result = Array(length); + + while (++index < length) { + result[index] = iteratee(array[index], index, array); + } + return result; +} + +/** + * Checks if `value` is classified as an `Array` object. + * + * @static + * @memberOf _ + * @since 0.1.0 + * @category Lang + * @param {*} value The value to check. + * @returns {boolean} Returns `true` if `value` is an array, else `false`. + * @example + * + * _.isArray([1, 2, 3]); + * // => true + * + * _.isArray(document.body.children); + * // => false + * + * _.isArray('abc'); + * // => false + * + * _.isArray(_.noop); + * // => false + */ +var isArray = Array.isArray; + +/** Used for built-in method references. */ +var objectProto = Object.prototype; + +/** Used to check objects for own properties. */ +var hasOwnProperty = objectProto.hasOwnProperty; + +/** + * Used to resolve the + * [`toStringTag`](http://ecma-international.org/ecma-262/7.0/#sec-object.prototype.tostring) + * of values. + */ +var nativeObjectToString = objectProto.toString; + +/** Built-in value references. */ +var symToStringTag = Symbol ? Symbol.toStringTag : undefined; + +/** + * A specialized version of `baseGetTag` which ignores `Symbol.toStringTag` values. + * + * @private + * @param {*} value The value to query. + * @returns {string} Returns the raw `toStringTag`. + */ +function getRawTag(value) { + var isOwn = hasOwnProperty.call(value, symToStringTag), + tag = value[symToStringTag]; + + try { + value[symToStringTag] = undefined; + var unmasked = true; + } catch (e) {} + + var result = nativeObjectToString.call(value); + if (unmasked) { + if (isOwn) { + value[symToStringTag] = tag; + } else { + delete value[symToStringTag]; + } + } + return result; +} + +/** Used for built-in method references. */ +var objectProto$1 = Object.prototype; + +/** + * Used to resolve the + * [`toStringTag`](http://ecma-international.org/ecma-262/7.0/#sec-object.prototype.tostring) + * of values. + */ +var nativeObjectToString$1 = objectProto$1.toString; + +/** + * Converts `value` to a string using `Object.prototype.toString`. + * + * @private + * @param {*} value The value to convert. + * @returns {string} Returns the converted string. + */ +function objectToString(value) { + return nativeObjectToString$1.call(value); +} + +/** `Object#toString` result references. */ +var nullTag = '[object Null]', + undefinedTag = '[object Undefined]'; + +/** Built-in value references. */ +var symToStringTag$1 = Symbol ? Symbol.toStringTag : undefined; + +/** + * The base implementation of `getTag` without fallbacks for buggy environments. + * + * @private + * @param {*} value The value to query. + * @returns {string} Returns the `toStringTag`. + */ +function baseGetTag(value) { + if (value == null) { + return value === undefined ? undefinedTag : nullTag; + } + return (symToStringTag$1 && symToStringTag$1 in Object(value)) + ? getRawTag(value) + : objectToString(value); +} + +/** + * Checks if `value` is object-like. A value is object-like if it's not `null` + * and has a `typeof` result of "object". + * + * @static + * @memberOf _ + * @since 4.0.0 + * @category Lang + * @param {*} value The value to check. + * @returns {boolean} Returns `true` if `value` is object-like, else `false`. + * @example + * + * _.isObjectLike({}); + * // => true + * + * _.isObjectLike([1, 2, 3]); + * // => true + * + * _.isObjectLike(_.noop); + * // => false + * + * _.isObjectLike(null); + * // => false + */ +function isObjectLike(value) { + return value != null && typeof value == 'object'; +} + +/** `Object#toString` result references. */ +var symbolTag = '[object Symbol]'; + +/** + * Checks if `value` is classified as a `Symbol` primitive or object. + * + * @static + * @memberOf _ + * @since 4.0.0 + * @category Lang + * @param {*} value The value to check. + * @returns {boolean} Returns `true` if `value` is a symbol, else `false`. + * @example + * + * _.isSymbol(Symbol.iterator); + * // => true + * + * _.isSymbol('abc'); + * // => false + */ +function isSymbol(value) { + return typeof value == 'symbol' || + (isObjectLike(value) && baseGetTag(value) == symbolTag); +} + +/** Used as references for various `Number` constants. */ +var INFINITY = 1 / 0; + +/** Used to convert symbols to primitives and strings. */ +var symbolProto = Symbol ? Symbol.prototype : undefined, + symbolToString = symbolProto ? symbolProto.toString : undefined; + +/** + * The base implementation of `_.toString` which doesn't convert nullish + * values to empty strings. + * + * @private + * @param {*} value The value to process. + * @returns {string} Returns the string. + */ +function baseToString(value) { + // Exit early for strings to avoid a performance hit in some environments. + if (typeof value == 'string') { + return value; + } + if (isArray(value)) { + // Recursively convert values (susceptible to call stack limits). + return arrayMap(value, baseToString) + ''; + } + if (isSymbol(value)) { + return symbolToString ? symbolToString.call(value) : ''; + } + var result = (value + ''); + return (result == '0' && (1 / value) == -INFINITY) ? '-0' : result; +} + +/** + * The base implementation of `_.slice` without an iteratee call guard. + * + * @private + * @param {Array} array The array to slice. + * @param {number} [start=0] The start position. + * @param {number} [end=array.length] The end position. + * @returns {Array} Returns the slice of `array`. + */ +function baseSlice(array, start, end) { + var index = -1, + length = array.length; + + if (start < 0) { + start = -start > length ? 0 : (length + start); + } + end = end > length ? length : end; + if (end < 0) { + end += length; + } + length = start > end ? 0 : ((end - start) >>> 0); + start >>>= 0; + + var result = Array(length); + while (++index < length) { + result[index] = array[index + start]; + } + return result; +} + +/** + * Casts `array` to a slice if it's needed. + * + * @private + * @param {Array} array The array to inspect. + * @param {number} start The start position. + * @param {number} [end=array.length] The end position. + * @returns {Array} Returns the cast slice. + */ +function castSlice(array, start, end) { + var length = array.length; + end = end === undefined ? length : end; + return (!start && end >= length) ? array : baseSlice(array, start, end); +} + +/** + * The base implementation of `_.findIndex` and `_.findLastIndex` without + * support for iteratee shorthands. + * + * @private + * @param {Array} array The array to inspect. + * @param {Function} predicate The function invoked per iteration. + * @param {number} fromIndex The index to search from. + * @param {boolean} [fromRight] Specify iterating from right to left. + * @returns {number} Returns the index of the matched value, else `-1`. + */ +function baseFindIndex(array, predicate, fromIndex, fromRight) { + var length = array.length, + index = fromIndex + (fromRight ? 1 : -1); + + while ((fromRight ? index-- : ++index < length)) { + if (predicate(array[index], index, array)) { + return index; + } + } + return -1; +} + +/** + * The base implementation of `_.isNaN` without support for number objects. + * + * @private + * @param {*} value The value to check. + * @returns {boolean} Returns `true` if `value` is `NaN`, else `false`. + */ +function baseIsNaN(value) { + return value !== value; +} + +/** + * A specialized version of `_.indexOf` which performs strict equality + * comparisons of values, i.e. `===`. + * + * @private + * @param {Array} array The array to inspect. + * @param {*} value The value to search for. + * @param {number} fromIndex The index to search from. + * @returns {number} Returns the index of the matched value, else `-1`. + */ +function strictIndexOf(array, value, fromIndex) { + var index = fromIndex - 1, + length = array.length; + + while (++index < length) { + if (array[index] === value) { + return index; + } + } + return -1; +} + +/** + * The base implementation of `_.indexOf` without `fromIndex` bounds checks. + * + * @private + * @param {Array} array The array to inspect. + * @param {*} value The value to search for. + * @param {number} fromIndex The index to search from. + * @returns {number} Returns the index of the matched value, else `-1`. + */ +function baseIndexOf(array, value, fromIndex) { + return value === value + ? strictIndexOf(array, value, fromIndex) + : baseFindIndex(array, baseIsNaN, fromIndex); +} + +/** + * Used by `_.trim` and `_.trimEnd` to get the index of the last string symbol + * that is not found in the character symbols. + * + * @private + * @param {Array} strSymbols The string symbols to inspect. + * @param {Array} chrSymbols The character symbols to find. + * @returns {number} Returns the index of the last unmatched string symbol. + */ +function charsEndIndex(strSymbols, chrSymbols) { + var index = strSymbols.length; + + while (index-- && baseIndexOf(chrSymbols, strSymbols[index], 0) > -1) {} + return index; +} + +/** + * Used by `_.trim` and `_.trimStart` to get the index of the first string symbol + * that is not found in the character symbols. + * + * @private + * @param {Array} strSymbols The string symbols to inspect. + * @param {Array} chrSymbols The character symbols to find. + * @returns {number} Returns the index of the first unmatched string symbol. + */ +function charsStartIndex(strSymbols, chrSymbols) { + var index = -1, + length = strSymbols.length; + + while (++index < length && baseIndexOf(chrSymbols, strSymbols[index], 0) > -1) {} + return index; +} + +/** + * Converts an ASCII `string` to an array. + * + * @private + * @param {string} string The string to convert. + * @returns {Array} Returns the converted array. + */ +function asciiToArray(string) { + return string.split(''); +} + +/** Used to compose unicode character classes. */ +var rsAstralRange = '\\ud800-\\udfff', + rsComboMarksRange = '\\u0300-\\u036f', + reComboHalfMarksRange = '\\ufe20-\\ufe2f', + rsComboSymbolsRange = '\\u20d0-\\u20ff', + rsComboRange = rsComboMarksRange + reComboHalfMarksRange + rsComboSymbolsRange, + rsVarRange = '\\ufe0e\\ufe0f'; + +/** Used to compose unicode capture groups. */ +var rsZWJ = '\\u200d'; + +/** 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/). */ +var reHasUnicode = RegExp('[' + rsZWJ + rsAstralRange + rsComboRange + rsVarRange + ']'); + +/** + * Checks if `string` contains Unicode symbols. + * + * @private + * @param {string} string The string to inspect. + * @returns {boolean} Returns `true` if a symbol is found, else `false`. + */ +function hasUnicode(string) { + return reHasUnicode.test(string); +} + +/** Used to compose unicode character classes. */ +var rsAstralRange$1 = '\\ud800-\\udfff', + rsComboMarksRange$1 = '\\u0300-\\u036f', + reComboHalfMarksRange$1 = '\\ufe20-\\ufe2f', + rsComboSymbolsRange$1 = '\\u20d0-\\u20ff', + rsComboRange$1 = rsComboMarksRange$1 + reComboHalfMarksRange$1 + rsComboSymbolsRange$1, + rsVarRange$1 = '\\ufe0e\\ufe0f'; + +/** Used to compose unicode capture groups. */ +var rsAstral = '[' + rsAstralRange$1 + ']', + rsCombo = '[' + rsComboRange$1 + ']', + rsFitz = '\\ud83c[\\udffb-\\udfff]', + rsModifier = '(?:' + rsCombo + '|' + rsFitz + ')', + rsNonAstral = '[^' + rsAstralRange$1 + ']', + rsRegional = '(?:\\ud83c[\\udde6-\\uddff]){2}', + rsSurrPair = '[\\ud800-\\udbff][\\udc00-\\udfff]', + rsZWJ$1 = '\\u200d'; + +/** Used to compose unicode regexes. */ +var reOptMod = rsModifier + '?', + rsOptVar = '[' + rsVarRange$1 + ']?', + rsOptJoin = '(?:' + rsZWJ$1 + '(?:' + [rsNonAstral, rsRegional, rsSurrPair].join('|') + ')' + rsOptVar + reOptMod + ')*', + rsSeq = rsOptVar + reOptMod + rsOptJoin, + rsSymbol = '(?:' + [rsNonAstral + rsCombo + '?', rsCombo, rsRegional, rsSurrPair, rsAstral].join('|') + ')'; + +/** Used to match [string symbols](https://mathiasbynens.be/notes/javascript-unicode). */ +var reUnicode = RegExp(rsFitz + '(?=' + rsFitz + ')|' + rsSymbol + rsSeq, 'g'); + +/** + * Converts a Unicode `string` to an array. + * + * @private + * @param {string} string The string to convert. + * @returns {Array} Returns the converted array. + */ +function unicodeToArray(string) { + return string.match(reUnicode) || []; +} + +/** + * Converts `string` to an array. + * + * @private + * @param {string} string The string to convert. + * @returns {Array} Returns the converted array. + */ +function stringToArray(string) { + return hasUnicode(string) + ? unicodeToArray(string) + : asciiToArray(string); +} + +/** + * Converts `value` to a string. An empty string is returned for `null` + * and `undefined` values. The sign of `-0` is preserved. + * + * @static + * @memberOf _ + * @since 4.0.0 + * @category Lang + * @param {*} value The value to convert. + * @returns {string} Returns the converted string. + * @example + * + * _.toString(null); + * // => '' + * + * _.toString(-0); + * // => '-0' + * + * _.toString([1, 2, 3]); + * // => '1,2,3' + */ +function toString(value) { + return value == null ? '' : baseToString(value); +} + +/** Used to match leading and trailing whitespace. */ +var reTrim = /^\s+|\s+$/g; + +/** + * Removes leading and trailing whitespace or specified characters from `string`. + * + * @static + * @memberOf _ + * @since 3.0.0 + * @category String + * @param {string} [string=''] The string to trim. + * @param {string} [chars=whitespace] The characters to trim. + * @param- {Object} [guard] Enables use as an iteratee for methods like `_.map`. + * @returns {string} Returns the trimmed string. + * @example + * + * _.trim(' abc '); + * // => 'abc' + * + * _.trim('-_-abc-_-', '_-'); + * // => 'abc' + * + * _.map([' foo ', ' bar '], _.trim); + * // => ['foo', 'bar'] + */ +function trim(string, chars, guard) { + string = toString(string); + if (string && (guard || chars === undefined)) { + return string.replace(reTrim, ''); + } + if (!string || !(chars = baseToString(chars))) { + return string; + } + var strSymbols = stringToArray(string), + chrSymbols = stringToArray(chars), + start = charsStartIndex(strSymbols, chrSymbols), + end = charsEndIndex(strSymbols, chrSymbols) + 1; + + return castSlice(strSymbols, start, end).join(''); +} + +/** + * Check several parameter that there is something in the param + * @param {*} param input + * @return {boolean} + */ + var isNotEmpty = function (a) { + if (isArray(a)) { + return true; + } + return a !== undefined && a !== null && trim(a) !== '' +}; + +/** `Object#toString` result references. */ +var numberTag = '[object Number]'; + +/** + * Checks if `value` is classified as a `Number` primitive or object. + * + * **Note:** To exclude `Infinity`, `-Infinity`, and `NaN`, which are + * classified as numbers, use the `_.isFinite` method. + * + * @static + * @memberOf _ + * @since 0.1.0 + * @category Lang + * @param {*} value The value to check. + * @returns {boolean} Returns `true` if `value` is a number, else `false`. + * @example + * + * _.isNumber(3); + * // => true + * + * _.isNumber(Number.MIN_VALUE); + * // => true + * + * _.isNumber(Infinity); + * // => true + * + * _.isNumber('3'); + * // => false + */ +function isNumber(value) { + return typeof value == 'number' || + (isObjectLike(value) && baseGetTag(value) == numberTag); +} + +/** + * Checks if `value` is `NaN`. + * + * **Note:** This method is based on + * [`Number.isNaN`](https://mdn.io/Number/isNaN) and is not the same as + * global [`isNaN`](https://mdn.io/isNaN) which returns `true` for + * `undefined` and other non-number values. + * + * @static + * @memberOf _ + * @since 0.1.0 + * @category Lang + * @param {*} value The value to check. + * @returns {boolean} Returns `true` if `value` is `NaN`, else `false`. + * @example + * + * _.isNaN(NaN); + * // => true + * + * _.isNaN(new Number(NaN)); + * // => true + * + * isNaN(undefined); + * // => true + * + * _.isNaN(undefined); + * // => false + */ +function isNaN(value) { + // An `NaN` primitive is the only value that is not equal to itself. + // Perform the `toStringTag` check first to avoid errors with some + // ActiveX objects in IE. + return isNumber(value) && value != +value; +} + +/** `Object#toString` result references. */ +var stringTag = '[object String]'; + +/** + * Checks if `value` is classified as a `String` primitive or object. + * + * @static + * @since 0.1.0 + * @memberOf _ + * @category Lang + * @param {*} value The value to check. + * @returns {boolean} Returns `true` if `value` is a string, else `false`. + * @example + * + * _.isString('abc'); + * // => true + * + * _.isString(1); + * // => false + */ +function isString(value) { + return typeof value == 'string' || + (!isArray(value) && isObjectLike(value) && baseGetTag(value) == stringTag); +} + +// validator numbers +/** + * @2015-05-04 found a problem if the value is a number like string + * it will pass, so add a chck if it's string before we pass to next + * @param {number} value expected value + * @return {boolean} true if OK + */ +var checkIsNumber = function(value) { + return isString(value) ? false : !isNaN( parseFloat(value) ) +}; + +// validate string type +/** + * @param {string} value expected value + * @return {boolean} true if OK + */ +var checkIsString = function(value) { + return (trim(value) !== '') ? isString(value) : false +}; + +// check for boolean + +/** + * @param {boolean} value expected + * @return {boolean} true if OK + */ +var checkIsBoolean = function(value) { + return value !== null && value !== undefined && typeof value === 'boolean' +}; + +// validate any thing only check if there is something + +/** + * @param {*} value the value + * @param {boolean} [checkNull=true] strict check if there is null value + * @return {boolean} true is OK + */ +var checkIsAny = function(value, checkNull) { + if ( checkNull === void 0 ) checkNull = true; + + if (value !== undefined && value !== '' && trim(value) !== '') { + if (checkNull === false || (checkNull === true && value !== null)) { + return true; + } + } + return false; +}; + +// the core stuff to id if it's calling with jsonql +var DATA_KEY = 'data'; +var ERROR_KEY$1 = 'error'; + +var JSONQL_PATH = 'jsonql'; + +// export const INDEX = 'index' use INDEX_KEY instead +var DEFAULT_TYPE = 'any'; + +// @TODO remove this is not in use +// export const CLIENT_CONFIG_FILE = '.clients.json' +// export const CONTRACT_CONFIG_FILE = 'jsonql-contract-config.js' +// type of resolvers +var QUERY_NAME = 'query'; +var MUTATION_NAME = 'mutation'; +var SOCKET_NAME = 'socket'; +// for contract-cli +var KEY_WORD = 'continue'; +var PUBLIC_KEY = 'public'; + +var TYPE_KEY = 'type'; +var OPTIONAL_KEY = 'optional'; +var ENUM_KEY = 'enumv'; // need to change this because enum is a reserved word +var ARGS_KEY = 'args'; +var CHECKER_KEY = 'checker'; +var ALIAS_KEY = 'alias'; +var LOGIN_NAME = 'login'; +// export const ISSUER_NAME = LOGIN_NAME // legacy issue need to replace them later +var LOGOUT_NAME = 'logout'; +var DISCONNECT_FN_NAME = 'disconnect'; +var SWITCH_USER_FN_NAME = 'switch-user'; + +var OR_SEPERATOR = '|'; +var STRING_TYPE = 'string'; +var BOOLEAN_TYPE = 'boolean'; +var ARRAY_TYPE = 'array'; +var OBJECT_TYPE = 'object'; + +var NUMBER_TYPE = 'number'; +var ARRAY_TYPE_LFT = 'array.<'; +var ARRAY_TYPE_RGT = '>'; + +var NO_ERROR_MSG = 'No message'; +var NO_STATUS_CODE$1 = -1; +var LOGIN_EVENT_NAME$1 = '__login__'; +var LOGOUT_EVENT_NAME$1 = '__logout__'; +var DISCONNECT_EVENT_NAME = '__disconnect__'; +// this is somewhat vague about what is suppose to do +var EMIT_REPLY_TYPE$1 = 'emit_reply'; + +var NSP_GROUP = 'nspGroup'; +var PUBLIC_NAMESPACE = 'publicNamespace'; + +var JS_WS_SOCKET_IO_NAME = 'socket.io'; +// type name and Alias +var SOCKET_TYPE_KEY = 'serverType'; //1.9.1 +var SOCKET_TYPE_CLIENT_ALIAS = 'socketClientType'; // 1.9.0 + +// for ws client, 1.9.3 breaking change to name them as FN instead of PROP +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 +// the actual method name client.resolverName.send +var SEND_MSG_FN_NAME = 'send'; +var NOT_LOGIN_ERR_MSG = 'NOT LOGIN'; +var IO_ROUNDTRIP_LOGIN = 'roundtip'; +var IO_HANDSHAKE_LOGIN = 'handshake'; + +// Good practice rule - No magic number + +var 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)"; +var PARAMS_NOT_ARRAY_ERR = "params is not an array! Did something gone wrong when you generate the contract.json?"; +var EXCEPTION_CASE_ERR = 'Could not understand your arguments and parameter structure!'; +// @TODO the jsdoc return array. and we should also allow array syntax +var DEFAULT_TYPE$1 = DEFAULT_TYPE; +var ARRAY_TYPE_LFT$1 = ARRAY_TYPE_LFT; +var ARRAY_TYPE_RGT$1 = ARRAY_TYPE_RGT; + +var TYPE_KEY$1 = TYPE_KEY; +var OPTIONAL_KEY$1 = OPTIONAL_KEY; +var ENUM_KEY$1 = ENUM_KEY; +var ARGS_KEY$1 = ARGS_KEY; +var CHECKER_KEY$1 = CHECKER_KEY; +var ALIAS_KEY$1 = ALIAS_KEY; + +var ARRAY_TYPE$1 = ARRAY_TYPE; +var OBJECT_TYPE$1 = OBJECT_TYPE; +var STRING_TYPE$1 = STRING_TYPE; +var BOOLEAN_TYPE$1 = BOOLEAN_TYPE; +var NUMBER_TYPE$1 = NUMBER_TYPE; +var KEY_WORD$1 = KEY_WORD; +var OR_SEPERATOR$1 = OR_SEPERATOR; + +// not actually in use +// export const NUMBER_TYPES = JSONQL_CONSTANTS.NUMBER_TYPES; + +// primitive types + +/** + * this is a wrapper method to call different one based on their type + * @param {string} type to check + * @return {function} a function to handle the type + */ +var combineFn = function(type) { + switch (type) { + case NUMBER_TYPE$1: + return checkIsNumber + case STRING_TYPE$1: + return checkIsString + case BOOLEAN_TYPE$1: + return checkIsBoolean + default: + return checkIsAny + } +}; + +// validate array type + +/** + * @param {array} value expected + * @param {string} [type=''] pass the type if we encounter array. then we need to check the value as well + * @return {boolean} true if OK + */ +var checkIsArray = function(value, type) { + if ( type === void 0 ) type=''; + + if (isArray(value)) { + if (type === '' || trim(type)==='') { + return true; + } + // we test it in reverse + // @TODO if the type is an array (OR) then what? + // we need to take into account this could be an array + var c = value.filter(function (v) { return !combineFn(type)(v); }); + return !(c.length > 0) + } + return false +}; + +/** + * check if it matches the array. pattern + * @param {string} type + * @return {boolean|array} false means NO, always return array + */ +var isArrayLike = function(type) { + // @TODO could that have something like array<> instead of array.<>? missing the dot? + // because type script is Array without the dot + if (type.indexOf(ARRAY_TYPE_LFT$1) > -1 && type.indexOf(ARRAY_TYPE_RGT$1) > -1) { + var _type = type.replace(ARRAY_TYPE_LFT$1, '').replace(ARRAY_TYPE_RGT$1, ''); + if (_type.indexOf(OR_SEPERATOR$1)) { + return _type.split(OR_SEPERATOR$1) + } + return [_type] + } + return false +}; + +/** + * we might encounter something like array. then we need to take it apart + * @param {object} p the prepared object for processing + * @param {string|array} type the type came from + * @return {boolean} for the filter to operate on + */ +var arrayTypeHandler = function(p, type) { + var arg = p.arg; + // need a special case to handle the OR type + // we need to test the args instead of the type(s) + if (type.length > 1) { + return !arg.filter(function (v) { return ( + !(type.length > type.filter(function (t) { return !combineFn(t)(v); }).length) + ); }).length + } + // type is array so this will be or! + return type.length > type.filter(function (t) { return !checkIsArray(arg, t); }).length +}; + +/** + * Creates a unary function that invokes `func` with its argument transformed. + * + * @private + * @param {Function} func The function to wrap. + * @param {Function} transform The argument transform. + * @returns {Function} Returns the new function. + */ +function overArg(func, transform) { + return function(arg) { + return func(transform(arg)); + }; +} + +/** Built-in value references. */ +var getPrototype = overArg(Object.getPrototypeOf, Object); + +/** `Object#toString` result references. */ +var objectTag = '[object Object]'; + +/** Used for built-in method references. */ +var funcProto = Function.prototype, + objectProto$2 = Object.prototype; + +/** Used to resolve the decompiled source of functions. */ +var funcToString = funcProto.toString; + +/** Used to check objects for own properties. */ +var hasOwnProperty$1 = objectProto$2.hasOwnProperty; + +/** Used to infer the `Object` constructor. */ +var objectCtorString = funcToString.call(Object); + +/** + * Checks if `value` is a plain object, that is, an object created by the + * `Object` constructor or one with a `[[Prototype]]` of `null`. + * + * @static + * @memberOf _ + * @since 0.8.0 + * @category Lang + * @param {*} value The value to check. + * @returns {boolean} Returns `true` if `value` is a plain object, else `false`. + * @example + * + * function Foo() { + * this.a = 1; + * } + * + * _.isPlainObject(new Foo); + * // => false + * + * _.isPlainObject([1, 2, 3]); + * // => false + * + * _.isPlainObject({ 'x': 0, 'y': 0 }); + * // => true + * + * _.isPlainObject(Object.create(null)); + * // => true + */ +function isPlainObject(value) { + if (!isObjectLike(value) || baseGetTag(value) != objectTag) { + return false; + } + var proto = getPrototype(value); + if (proto === null) { + return true; + } + var Ctor = hasOwnProperty$1.call(proto, 'constructor') && proto.constructor; + return typeof Ctor == 'function' && Ctor instanceof Ctor && + funcToString.call(Ctor) == objectCtorString; +} + +/** + * A specialized version of `_.filter` for arrays without support for + * iteratee shorthands. + * + * @private + * @param {Array} [array] The array to iterate over. + * @param {Function} predicate The function invoked per iteration. + * @returns {Array} Returns the new filtered array. + */ +function arrayFilter(array, predicate) { + var index = -1, + length = array == null ? 0 : array.length, + resIndex = 0, + result = []; + + while (++index < length) { + var value = array[index]; + if (predicate(value, index, array)) { + result[resIndex++] = value; + } + } + return result; +} + +/** + * Creates a base function for methods like `_.forIn` and `_.forOwn`. + * + * @private + * @param {boolean} [fromRight] Specify iterating from right to left. + * @returns {Function} Returns the new base function. + */ +function createBaseFor(fromRight) { + return function(object, iteratee, keysFunc) { + var index = -1, + iterable = Object(object), + props = keysFunc(object), + length = props.length; + + while (length--) { + var key = props[fromRight ? length : ++index]; + if (iteratee(iterable[key], key, iterable) === false) { + break; + } + } + return object; + }; +} + +/** + * The base implementation of `baseForOwn` which iterates over `object` + * properties returned by `keysFunc` and invokes `iteratee` for each property. + * Iteratee functions may exit iteration early by explicitly returning `false`. + * + * @private + * @param {Object} object The object to iterate over. + * @param {Function} iteratee The function invoked per iteration. + * @param {Function} keysFunc The function to get the keys of `object`. + * @returns {Object} Returns `object`. + */ +var baseFor = createBaseFor(); + +/** + * The base implementation of `_.times` without support for iteratee shorthands + * or max array length checks. + * + * @private + * @param {number} n The number of times to invoke `iteratee`. + * @param {Function} iteratee The function invoked per iteration. + * @returns {Array} Returns the array of results. + */ +function baseTimes(n, iteratee) { + var index = -1, + result = Array(n); + + while (++index < n) { + result[index] = iteratee(index); + } + return result; +} + +/** `Object#toString` result references. */ +var argsTag = '[object Arguments]'; + +/** + * The base implementation of `_.isArguments`. + * + * @private + * @param {*} value The value to check. + * @returns {boolean} Returns `true` if `value` is an `arguments` object, + */ +function baseIsArguments(value) { + return isObjectLike(value) && baseGetTag(value) == argsTag; +} + +/** Used for built-in method references. */ +var objectProto$3 = Object.prototype; + +/** Used to check objects for own properties. */ +var hasOwnProperty$2 = objectProto$3.hasOwnProperty; + +/** Built-in value references. */ +var propertyIsEnumerable = objectProto$3.propertyIsEnumerable; + +/** + * Checks if `value` is likely an `arguments` object. + * + * @static + * @memberOf _ + * @since 0.1.0 + * @category Lang + * @param {*} value The value to check. + * @returns {boolean} Returns `true` if `value` is an `arguments` object, + * else `false`. + * @example + * + * _.isArguments(function() { return arguments; }()); + * // => true + * + * _.isArguments([1, 2, 3]); + * // => false + */ +var isArguments = baseIsArguments(function() { return arguments; }()) ? baseIsArguments : function(value) { + return isObjectLike(value) && hasOwnProperty$2.call(value, 'callee') && + !propertyIsEnumerable.call(value, 'callee'); +}; + +/** + * This method returns `false`. + * + * @static + * @memberOf _ + * @since 4.13.0 + * @category Util + * @returns {boolean} Returns `false`. + * @example + * + * _.times(2, _.stubFalse); + * // => [false, false] + */ +function stubFalse() { + return false; +} + +/** Detect free variable `exports`. */ +var freeExports = typeof exports == 'object' && exports && !exports.nodeType && exports; + +/** Detect free variable `module`. */ +var freeModule = freeExports && typeof module == 'object' && module && !module.nodeType && module; + +/** Detect the popular CommonJS extension `module.exports`. */ +var moduleExports = freeModule && freeModule.exports === freeExports; + +/** Built-in value references. */ +var Buffer = moduleExports ? root.Buffer : undefined; + +/* Built-in method references for those with the same name as other `lodash` methods. */ +var nativeIsBuffer = Buffer ? Buffer.isBuffer : undefined; + +/** + * Checks if `value` is a buffer. + * + * @static + * @memberOf _ + * @since 4.3.0 + * @category Lang + * @param {*} value The value to check. + * @returns {boolean} Returns `true` if `value` is a buffer, else `false`. + * @example + * + * _.isBuffer(new Buffer(2)); + * // => true + * + * _.isBuffer(new Uint8Array(2)); + * // => false + */ +var isBuffer = nativeIsBuffer || stubFalse; + +/** Used as references for various `Number` constants. */ +var MAX_SAFE_INTEGER = 9007199254740991; + +/** Used to detect unsigned integer values. */ +var reIsUint = /^(?:0|[1-9]\d*)$/; + +/** + * Checks if `value` is a valid array-like index. + * + * @private + * @param {*} value The value to check. + * @param {number} [length=MAX_SAFE_INTEGER] The upper bounds of a valid index. + * @returns {boolean} Returns `true` if `value` is a valid index, else `false`. + */ +function isIndex(value, length) { + var type = typeof value; + length = length == null ? MAX_SAFE_INTEGER : length; + + return !!length && + (type == 'number' || + (type != 'symbol' && reIsUint.test(value))) && + (value > -1 && value % 1 == 0 && value < length); +} + +/** Used as references for various `Number` constants. */ +var MAX_SAFE_INTEGER$1 = 9007199254740991; + +/** + * Checks if `value` is a valid array-like length. + * + * **Note:** This method is loosely based on + * [`ToLength`](http://ecma-international.org/ecma-262/7.0/#sec-tolength). + * + * @static + * @memberOf _ + * @since 4.0.0 + * @category Lang + * @param {*} value The value to check. + * @returns {boolean} Returns `true` if `value` is a valid length, else `false`. + * @example + * + * _.isLength(3); + * // => true + * + * _.isLength(Number.MIN_VALUE); + * // => false + * + * _.isLength(Infinity); + * // => false + * + * _.isLength('3'); + * // => false + */ +function isLength(value) { + return typeof value == 'number' && + value > -1 && value % 1 == 0 && value <= MAX_SAFE_INTEGER$1; +} + +/** `Object#toString` result references. */ +var argsTag$1 = '[object Arguments]', + arrayTag = '[object Array]', + boolTag = '[object Boolean]', + dateTag = '[object Date]', + errorTag = '[object Error]', + funcTag = '[object Function]', + mapTag = '[object Map]', + numberTag$1 = '[object Number]', + objectTag$1 = '[object Object]', + regexpTag = '[object RegExp]', + setTag = '[object Set]', + stringTag$1 = '[object String]', + weakMapTag = '[object WeakMap]'; + +var arrayBufferTag = '[object ArrayBuffer]', + dataViewTag = '[object DataView]', + float32Tag = '[object Float32Array]', + float64Tag = '[object Float64Array]', + int8Tag = '[object Int8Array]', + int16Tag = '[object Int16Array]', + int32Tag = '[object Int32Array]', + uint8Tag = '[object Uint8Array]', + uint8ClampedTag = '[object Uint8ClampedArray]', + uint16Tag = '[object Uint16Array]', + uint32Tag = '[object Uint32Array]'; + +/** Used to identify `toStringTag` values of typed arrays. */ +var typedArrayTags = {}; +typedArrayTags[float32Tag] = typedArrayTags[float64Tag] = +typedArrayTags[int8Tag] = typedArrayTags[int16Tag] = +typedArrayTags[int32Tag] = typedArrayTags[uint8Tag] = +typedArrayTags[uint8ClampedTag] = typedArrayTags[uint16Tag] = +typedArrayTags[uint32Tag] = true; +typedArrayTags[argsTag$1] = typedArrayTags[arrayTag] = +typedArrayTags[arrayBufferTag] = typedArrayTags[boolTag] = +typedArrayTags[dataViewTag] = typedArrayTags[dateTag] = +typedArrayTags[errorTag] = typedArrayTags[funcTag] = +typedArrayTags[mapTag] = typedArrayTags[numberTag$1] = +typedArrayTags[objectTag$1] = typedArrayTags[regexpTag] = +typedArrayTags[setTag] = typedArrayTags[stringTag$1] = +typedArrayTags[weakMapTag] = false; + +/** + * The base implementation of `_.isTypedArray` without Node.js optimizations. + * + * @private + * @param {*} value The value to check. + * @returns {boolean} Returns `true` if `value` is a typed array, else `false`. + */ +function baseIsTypedArray(value) { + return isObjectLike(value) && + isLength(value.length) && !!typedArrayTags[baseGetTag(value)]; +} + +/** + * The base implementation of `_.unary` without support for storing metadata. + * + * @private + * @param {Function} func The function to cap arguments for. + * @returns {Function} Returns the new capped function. + */ +function baseUnary(func) { + return function(value) { + return func(value); + }; +} + +/** Detect free variable `exports`. */ +var freeExports$1 = typeof exports == 'object' && exports && !exports.nodeType && exports; + +/** Detect free variable `module`. */ +var freeModule$1 = freeExports$1 && typeof module == 'object' && module && !module.nodeType && module; + +/** Detect the popular CommonJS extension `module.exports`. */ +var moduleExports$1 = freeModule$1 && freeModule$1.exports === freeExports$1; + +/** Detect free variable `process` from Node.js. */ +var freeProcess = moduleExports$1 && freeGlobal.process; + +/** Used to access faster Node.js helpers. */ +var nodeUtil = (function() { + try { + // Use `util.types` for Node.js 10+. + var types = freeModule$1 && freeModule$1.require && freeModule$1.require('util').types; + + if (types) { + return types; + } + + // Legacy `process.binding('util')` for Node.js < 10. + return freeProcess && freeProcess.binding && freeProcess.binding('util'); + } catch (e) {} +}()); + +/* Node.js helper references. */ +var nodeIsTypedArray = nodeUtil && nodeUtil.isTypedArray; + +/** + * Checks if `value` is classified as a typed array. + * + * @static + * @memberOf _ + * @since 3.0.0 + * @category Lang + * @param {*} value The value to check. + * @returns {boolean} Returns `true` if `value` is a typed array, else `false`. + * @example + * + * _.isTypedArray(new Uint8Array); + * // => true + * + * _.isTypedArray([]); + * // => false + */ +var isTypedArray = nodeIsTypedArray ? baseUnary(nodeIsTypedArray) : baseIsTypedArray; + +/** Used for built-in method references. */ +var objectProto$4 = Object.prototype; + +/** Used to check objects for own properties. */ +var hasOwnProperty$3 = objectProto$4.hasOwnProperty; + +/** + * Creates an array of the enumerable property names of the array-like `value`. + * + * @private + * @param {*} value The value to query. + * @param {boolean} inherited Specify returning inherited property names. + * @returns {Array} Returns the array of property names. + */ +function arrayLikeKeys(value, inherited) { + var isArr = isArray(value), + isArg = !isArr && isArguments(value), + isBuff = !isArr && !isArg && isBuffer(value), + isType = !isArr && !isArg && !isBuff && isTypedArray(value), + skipIndexes = isArr || isArg || isBuff || isType, + result = skipIndexes ? baseTimes(value.length, String) : [], + length = result.length; + + for (var key in value) { + if ((inherited || hasOwnProperty$3.call(value, key)) && + !(skipIndexes && ( + // Safari 9 has enumerable `arguments.length` in strict mode. + key == 'length' || + // Node.js 0.10 has enumerable non-index properties on buffers. + (isBuff && (key == 'offset' || key == 'parent')) || + // PhantomJS 2 has enumerable non-index properties on typed arrays. + (isType && (key == 'buffer' || key == 'byteLength' || key == 'byteOffset')) || + // Skip index properties. + isIndex(key, length) + ))) { + result.push(key); + } + } + return result; +} + +/** Used for built-in method references. */ +var objectProto$5 = Object.prototype; + +/** + * Checks if `value` is likely a prototype object. + * + * @private + * @param {*} value The value to check. + * @returns {boolean} Returns `true` if `value` is a prototype, else `false`. + */ +function isPrototype(value) { + var Ctor = value && value.constructor, + proto = (typeof Ctor == 'function' && Ctor.prototype) || objectProto$5; + + return value === proto; +} + +/* Built-in method references for those with the same name as other `lodash` methods. */ +var nativeKeys = overArg(Object.keys, Object); + +/** Used for built-in method references. */ +var objectProto$6 = Object.prototype; + +/** Used to check objects for own properties. */ +var hasOwnProperty$4 = objectProto$6.hasOwnProperty; + +/** + * The base implementation of `_.keys` which doesn't treat sparse arrays as dense. + * + * @private + * @param {Object} object The object to query. + * @returns {Array} Returns the array of property names. + */ +function baseKeys(object) { + if (!isPrototype(object)) { + return nativeKeys(object); + } + var result = []; + for (var key in Object(object)) { + if (hasOwnProperty$4.call(object, key) && key != 'constructor') { + result.push(key); + } + } + return result; +} + +/** + * Checks if `value` is the + * [language type](http://www.ecma-international.org/ecma-262/7.0/#sec-ecmascript-language-types) + * of `Object`. (e.g. arrays, functions, objects, regexes, `new Number(0)`, and `new String('')`) + * + * @static + * @memberOf _ + * @since 0.1.0 + * @category Lang + * @param {*} value The value to check. + * @returns {boolean} Returns `true` if `value` is an object, else `false`. + * @example + * + * _.isObject({}); + * // => true + * + * _.isObject([1, 2, 3]); + * // => true + * + * _.isObject(_.noop); + * // => true + * + * _.isObject(null); + * // => false + */ +function isObject(value) { + var type = typeof value; + return value != null && (type == 'object' || type == 'function'); +} + +/** `Object#toString` result references. */ +var asyncTag = '[object AsyncFunction]', + funcTag$1 = '[object Function]', + genTag = '[object GeneratorFunction]', + proxyTag = '[object Proxy]'; + +/** + * Checks if `value` is classified as a `Function` object. + * + * @static + * @memberOf _ + * @since 0.1.0 + * @category Lang + * @param {*} value The value to check. + * @returns {boolean} Returns `true` if `value` is a function, else `false`. + * @example + * + * _.isFunction(_); + * // => true + * + * _.isFunction(/abc/); + * // => false + */ +function isFunction(value) { + if (!isObject(value)) { + return false; + } + // The use of `Object#toString` avoids issues with the `typeof` operator + // in Safari 9 which returns 'object' for typed arrays and other constructors. + var tag = baseGetTag(value); + return tag == funcTag$1 || tag == genTag || tag == asyncTag || tag == proxyTag; +} + +/** + * Checks if `value` is array-like. A value is considered array-like if it's + * not a function and has a `value.length` that's an integer greater than or + * equal to `0` and less than or equal to `Number.MAX_SAFE_INTEGER`. + * + * @static + * @memberOf _ + * @since 4.0.0 + * @category Lang + * @param {*} value The value to check. + * @returns {boolean} Returns `true` if `value` is array-like, else `false`. + * @example + * + * _.isArrayLike([1, 2, 3]); + * // => true + * + * _.isArrayLike(document.body.children); + * // => true + * + * _.isArrayLike('abc'); + * // => true + * + * _.isArrayLike(_.noop); + * // => false + */ +function isArrayLike$1(value) { + return value != null && isLength(value.length) && !isFunction(value); +} + +/** + * Creates an array of the own enumerable property names of `object`. + * + * **Note:** Non-object values are coerced to objects. See the + * [ES spec](http://ecma-international.org/ecma-262/7.0/#sec-object.keys) + * for more details. + * + * @static + * @since 0.1.0 + * @memberOf _ + * @category Object + * @param {Object} object The object to query. + * @returns {Array} Returns the array of property names. + * @example + * + * function Foo() { + * this.a = 1; + * this.b = 2; + * } + * + * Foo.prototype.c = 3; + * + * _.keys(new Foo); + * // => ['a', 'b'] (iteration order is not guaranteed) + * + * _.keys('hi'); + * // => ['0', '1'] + */ +function keys(object) { + return isArrayLike$1(object) ? arrayLikeKeys(object) : baseKeys(object); +} + +/** + * The base implementation of `_.forOwn` without support for iteratee shorthands. + * + * @private + * @param {Object} object The object to iterate over. + * @param {Function} iteratee The function invoked per iteration. + * @returns {Object} Returns `object`. + */ +function baseForOwn(object, iteratee) { + return object && baseFor(object, iteratee, keys); +} + +/** + * Removes all key-value entries from the list cache. + * + * @private + * @name clear + * @memberOf ListCache + */ +function listCacheClear() { + this.__data__ = []; + this.size = 0; +} + +/** + * Performs a + * [`SameValueZero`](http://ecma-international.org/ecma-262/7.0/#sec-samevaluezero) + * comparison between two values to determine if they are equivalent. + * + * @static + * @memberOf _ + * @since 4.0.0 + * @category Lang + * @param {*} value The value to compare. + * @param {*} other The other value to compare. + * @returns {boolean} Returns `true` if the values are equivalent, else `false`. + * @example + * + * var object = { 'a': 1 }; + * var other = { 'a': 1 }; + * + * _.eq(object, object); + * // => true + * + * _.eq(object, other); + * // => false + * + * _.eq('a', 'a'); + * // => true + * + * _.eq('a', Object('a')); + * // => false + * + * _.eq(NaN, NaN); + * // => true + */ +function eq(value, other) { + return value === other || (value !== value && other !== other); +} + +/** + * Gets the index at which the `key` is found in `array` of key-value pairs. + * + * @private + * @param {Array} array The array to inspect. + * @param {*} key The key to search for. + * @returns {number} Returns the index of the matched value, else `-1`. + */ +function assocIndexOf(array, key) { + var length = array.length; + while (length--) { + if (eq(array[length][0], key)) { + return length; + } + } + return -1; +} + +/** Used for built-in method references. */ +var arrayProto = Array.prototype; + +/** Built-in value references. */ +var splice = arrayProto.splice; + +/** + * Removes `key` and its value from the list cache. + * + * @private + * @name delete + * @memberOf ListCache + * @param {string} key The key of the value to remove. + * @returns {boolean} Returns `true` if the entry was removed, else `false`. + */ +function listCacheDelete(key) { + var data = this.__data__, + index = assocIndexOf(data, key); + + if (index < 0) { + return false; + } + var lastIndex = data.length - 1; + if (index == lastIndex) { + data.pop(); + } else { + splice.call(data, index, 1); + } + --this.size; + return true; +} + +/** + * Gets the list cache value for `key`. + * + * @private + * @name get + * @memberOf ListCache + * @param {string} key The key of the value to get. + * @returns {*} Returns the entry value. + */ +function listCacheGet(key) { + var data = this.__data__, + index = assocIndexOf(data, key); + + return index < 0 ? undefined : data[index][1]; +} + +/** + * Checks if a list cache value for `key` exists. + * + * @private + * @name has + * @memberOf ListCache + * @param {string} key The key of the entry to check. + * @returns {boolean} Returns `true` if an entry for `key` exists, else `false`. + */ +function listCacheHas(key) { + return assocIndexOf(this.__data__, key) > -1; +} + +/** + * Sets the list cache `key` to `value`. + * + * @private + * @name set + * @memberOf ListCache + * @param {string} key The key of the value to set. + * @param {*} value The value to set. + * @returns {Object} Returns the list cache instance. + */ +function listCacheSet(key, value) { + var data = this.__data__, + index = assocIndexOf(data, key); + + if (index < 0) { + ++this.size; + data.push([key, value]); + } else { + data[index][1] = value; + } + return this; +} + +/** + * Creates an list cache object. + * + * @private + * @constructor + * @param {Array} [entries] The key-value pairs to cache. + */ +function ListCache(entries) { + var index = -1, + length = entries == null ? 0 : entries.length; + + this.clear(); + while (++index < length) { + var entry = entries[index]; + this.set(entry[0], entry[1]); + } +} + +// Add methods to `ListCache`. +ListCache.prototype.clear = listCacheClear; +ListCache.prototype['delete'] = listCacheDelete; +ListCache.prototype.get = listCacheGet; +ListCache.prototype.has = listCacheHas; +ListCache.prototype.set = listCacheSet; + +/** + * Removes all key-value entries from the stack. + * + * @private + * @name clear + * @memberOf Stack + */ +function stackClear() { + this.__data__ = new ListCache; + this.size = 0; +} + +/** + * Removes `key` and its value from the stack. + * + * @private + * @name delete + * @memberOf Stack + * @param {string} key The key of the value to remove. + * @returns {boolean} Returns `true` if the entry was removed, else `false`. + */ +function stackDelete(key) { + var data = this.__data__, + result = data['delete'](key); + + this.size = data.size; + return result; +} + +/** + * Gets the stack value for `key`. + * + * @private + * @name get + * @memberOf Stack + * @param {string} key The key of the value to get. + * @returns {*} Returns the entry value. + */ +function stackGet(key) { + return this.__data__.get(key); +} + +/** + * Checks if a stack value for `key` exists. + * + * @private + * @name has + * @memberOf Stack + * @param {string} key The key of the entry to check. + * @returns {boolean} Returns `true` if an entry for `key` exists, else `false`. + */ +function stackHas(key) { + return this.__data__.has(key); +} + +/** Used to detect overreaching core-js shims. */ +var coreJsData = root['__core-js_shared__']; + +/** Used to detect methods masquerading as native. */ +var maskSrcKey = (function() { + var uid = /[^.]+$/.exec(coreJsData && coreJsData.keys && coreJsData.keys.IE_PROTO || ''); + return uid ? ('Symbol(src)_1.' + uid) : ''; +}()); + +/** + * Checks if `func` has its source masked. + * + * @private + * @param {Function} func The function to check. + * @returns {boolean} Returns `true` if `func` is masked, else `false`. + */ +function isMasked(func) { + return !!maskSrcKey && (maskSrcKey in func); +} + +/** Used for built-in method references. */ +var funcProto$1 = Function.prototype; + +/** Used to resolve the decompiled source of functions. */ +var funcToString$1 = funcProto$1.toString; + +/** + * Converts `func` to its source code. + * + * @private + * @param {Function} func The function to convert. + * @returns {string} Returns the source code. + */ +function toSource(func) { + if (func != null) { + try { + return funcToString$1.call(func); + } catch (e) {} + try { + return (func + ''); + } catch (e) {} + } + return ''; +} + +/** + * Used to match `RegExp` + * [syntax characters](http://ecma-international.org/ecma-262/7.0/#sec-patterns). + */ +var reRegExpChar = /[\\^$.*+?()[\]{}|]/g; + +/** Used to detect host constructors (Safari). */ +var reIsHostCtor = /^\[object .+?Constructor\]$/; + +/** Used for built-in method references. */ +var funcProto$2 = Function.prototype, + objectProto$7 = Object.prototype; + +/** Used to resolve the decompiled source of functions. */ +var funcToString$2 = funcProto$2.toString; + +/** Used to check objects for own properties. */ +var hasOwnProperty$5 = objectProto$7.hasOwnProperty; + +/** Used to detect if a method is native. */ +var reIsNative = RegExp('^' + + funcToString$2.call(hasOwnProperty$5).replace(reRegExpChar, '\\$&') + .replace(/hasOwnProperty|(function).*?(?=\\\()| for .+?(?=\\\])/g, '$1.*?') + '$' +); + +/** + * The base implementation of `_.isNative` without bad shim checks. + * + * @private + * @param {*} value The value to check. + * @returns {boolean} Returns `true` if `value` is a native function, + * else `false`. + */ +function baseIsNative(value) { + if (!isObject(value) || isMasked(value)) { + return false; + } + var pattern = isFunction(value) ? reIsNative : reIsHostCtor; + return pattern.test(toSource(value)); +} + +/** + * Gets the value at `key` of `object`. + * + * @private + * @param {Object} [object] The object to query. + * @param {string} key The key of the property to get. + * @returns {*} Returns the property value. + */ +function getValue(object, key) { + return object == null ? undefined : object[key]; +} + +/** + * Gets the native function at `key` of `object`. + * + * @private + * @param {Object} object The object to query. + * @param {string} key The key of the method to get. + * @returns {*} Returns the function if it's native, else `undefined`. + */ +function getNative(object, key) { + var value = getValue(object, key); + return baseIsNative(value) ? value : undefined; +} + +/* Built-in method references that are verified to be native. */ +var Map$1 = getNative(root, 'Map'); + +/* Built-in method references that are verified to be native. */ +var nativeCreate = getNative(Object, 'create'); + +/** + * Removes all key-value entries from the hash. + * + * @private + * @name clear + * @memberOf Hash + */ +function hashClear() { + this.__data__ = nativeCreate ? nativeCreate(null) : {}; + this.size = 0; +} + +/** + * Removes `key` and its value from the hash. + * + * @private + * @name delete + * @memberOf Hash + * @param {Object} hash The hash to modify. + * @param {string} key The key of the value to remove. + * @returns {boolean} Returns `true` if the entry was removed, else `false`. + */ +function hashDelete(key) { + var result = this.has(key) && delete this.__data__[key]; + this.size -= result ? 1 : 0; + return result; +} + +/** Used to stand-in for `undefined` hash values. */ +var HASH_UNDEFINED = '__lodash_hash_undefined__'; + +/** Used for built-in method references. */ +var objectProto$8 = Object.prototype; + +/** Used to check objects for own properties. */ +var hasOwnProperty$6 = objectProto$8.hasOwnProperty; + +/** + * Gets the hash value for `key`. + * + * @private + * @name get + * @memberOf Hash + * @param {string} key The key of the value to get. + * @returns {*} Returns the entry value. + */ +function hashGet(key) { + var data = this.__data__; + if (nativeCreate) { + var result = data[key]; + return result === HASH_UNDEFINED ? undefined : result; + } + return hasOwnProperty$6.call(data, key) ? data[key] : undefined; +} + +/** Used for built-in method references. */ +var objectProto$9 = Object.prototype; + +/** Used to check objects for own properties. */ +var hasOwnProperty$7 = objectProto$9.hasOwnProperty; + +/** + * Checks if a hash value for `key` exists. + * + * @private + * @name has + * @memberOf Hash + * @param {string} key The key of the entry to check. + * @returns {boolean} Returns `true` if an entry for `key` exists, else `false`. + */ +function hashHas(key) { + var data = this.__data__; + return nativeCreate ? (data[key] !== undefined) : hasOwnProperty$7.call(data, key); +} + +/** Used to stand-in for `undefined` hash values. */ +var HASH_UNDEFINED$1 = '__lodash_hash_undefined__'; + +/** + * Sets the hash `key` to `value`. + * + * @private + * @name set + * @memberOf Hash + * @param {string} key The key of the value to set. + * @param {*} value The value to set. + * @returns {Object} Returns the hash instance. + */ +function hashSet(key, value) { + var data = this.__data__; + this.size += this.has(key) ? 0 : 1; + data[key] = (nativeCreate && value === undefined) ? HASH_UNDEFINED$1 : value; + return this; +} + +/** + * Creates a hash object. + * + * @private + * @constructor + * @param {Array} [entries] The key-value pairs to cache. + */ +function Hash(entries) { + var index = -1, + length = entries == null ? 0 : entries.length; + + this.clear(); + while (++index < length) { + var entry = entries[index]; + this.set(entry[0], entry[1]); + } +} + +// Add methods to `Hash`. +Hash.prototype.clear = hashClear; +Hash.prototype['delete'] = hashDelete; +Hash.prototype.get = hashGet; +Hash.prototype.has = hashHas; +Hash.prototype.set = hashSet; + +/** + * Removes all key-value entries from the map. + * + * @private + * @name clear + * @memberOf MapCache + */ +function mapCacheClear() { + this.size = 0; + this.__data__ = { + 'hash': new Hash, + 'map': new (Map$1 || ListCache), + 'string': new Hash + }; +} + +/** + * Checks if `value` is suitable for use as unique object key. + * + * @private + * @param {*} value The value to check. + * @returns {boolean} Returns `true` if `value` is suitable, else `false`. + */ +function isKeyable(value) { + var type = typeof value; + return (type == 'string' || type == 'number' || type == 'symbol' || type == 'boolean') + ? (value !== '__proto__') + : (value === null); +} + +/** + * Gets the data for `map`. + * + * @private + * @param {Object} map The map to query. + * @param {string} key The reference key. + * @returns {*} Returns the map data. + */ +function getMapData(map, key) { + var data = map.__data__; + return isKeyable(key) + ? data[typeof key == 'string' ? 'string' : 'hash'] + : data.map; +} + +/** + * Removes `key` and its value from the map. + * + * @private + * @name delete + * @memberOf MapCache + * @param {string} key The key of the value to remove. + * @returns {boolean} Returns `true` if the entry was removed, else `false`. + */ +function mapCacheDelete(key) { + var result = getMapData(this, key)['delete'](key); + this.size -= result ? 1 : 0; + return result; +} + +/** + * Gets the map value for `key`. + * + * @private + * @name get + * @memberOf MapCache + * @param {string} key The key of the value to get. + * @returns {*} Returns the entry value. + */ +function mapCacheGet(key) { + return getMapData(this, key).get(key); +} + +/** + * Checks if a map value for `key` exists. + * + * @private + * @name has + * @memberOf MapCache + * @param {string} key The key of the entry to check. + * @returns {boolean} Returns `true` if an entry for `key` exists, else `false`. + */ +function mapCacheHas(key) { + return getMapData(this, key).has(key); +} + +/** + * Sets the map `key` to `value`. + * + * @private + * @name set + * @memberOf MapCache + * @param {string} key The key of the value to set. + * @param {*} value The value to set. + * @returns {Object} Returns the map cache instance. + */ +function mapCacheSet(key, value) { + var data = getMapData(this, key), + size = data.size; + + data.set(key, value); + this.size += data.size == size ? 0 : 1; + return this; +} + +/** + * Creates a map cache object to store key-value pairs. + * + * @private + * @constructor + * @param {Array} [entries] The key-value pairs to cache. + */ +function MapCache(entries) { + var index = -1, + length = entries == null ? 0 : entries.length; + + this.clear(); + while (++index < length) { + var entry = entries[index]; + this.set(entry[0], entry[1]); + } +} + +// Add methods to `MapCache`. +MapCache.prototype.clear = mapCacheClear; +MapCache.prototype['delete'] = mapCacheDelete; +MapCache.prototype.get = mapCacheGet; +MapCache.prototype.has = mapCacheHas; +MapCache.prototype.set = mapCacheSet; + +/** Used as the size to enable large array optimizations. */ +var LARGE_ARRAY_SIZE = 200; + +/** + * Sets the stack `key` to `value`. + * + * @private + * @name set + * @memberOf Stack + * @param {string} key The key of the value to set. + * @param {*} value The value to set. + * @returns {Object} Returns the stack cache instance. + */ +function stackSet(key, value) { + var data = this.__data__; + if (data instanceof ListCache) { + var pairs = data.__data__; + if (!Map$1 || (pairs.length < LARGE_ARRAY_SIZE - 1)) { + pairs.push([key, value]); + this.size = ++data.size; + return this; + } + data = this.__data__ = new MapCache(pairs); + } + data.set(key, value); + this.size = data.size; + return this; +} + +/** + * Creates a stack cache object to store key-value pairs. + * + * @private + * @constructor + * @param {Array} [entries] The key-value pairs to cache. + */ +function Stack(entries) { + var data = this.__data__ = new ListCache(entries); + this.size = data.size; +} + +// Add methods to `Stack`. +Stack.prototype.clear = stackClear; +Stack.prototype['delete'] = stackDelete; +Stack.prototype.get = stackGet; +Stack.prototype.has = stackHas; +Stack.prototype.set = stackSet; + +/** Used to stand-in for `undefined` hash values. */ +var HASH_UNDEFINED$2 = '__lodash_hash_undefined__'; + +/** + * Adds `value` to the array cache. + * + * @private + * @name add + * @memberOf SetCache + * @alias push + * @param {*} value The value to cache. + * @returns {Object} Returns the cache instance. + */ +function setCacheAdd(value) { + this.__data__.set(value, HASH_UNDEFINED$2); + return this; +} + +/** + * Checks if `value` is in the array cache. + * + * @private + * @name has + * @memberOf SetCache + * @param {*} value The value to search for. + * @returns {number} Returns `true` if `value` is found, else `false`. + */ +function setCacheHas(value) { + return this.__data__.has(value); +} + +/** + * + * Creates an array cache object to store unique values. + * + * @private + * @constructor + * @param {Array} [values] The values to cache. + */ +function SetCache(values) { + var index = -1, + length = values == null ? 0 : values.length; + + this.__data__ = new MapCache; + while (++index < length) { + this.add(values[index]); + } +} + +// Add methods to `SetCache`. +SetCache.prototype.add = SetCache.prototype.push = setCacheAdd; +SetCache.prototype.has = setCacheHas; + +/** + * A specialized version of `_.some` for arrays without support for iteratee + * shorthands. + * + * @private + * @param {Array} [array] The array to iterate over. + * @param {Function} predicate The function invoked per iteration. + * @returns {boolean} Returns `true` if any element passes the predicate check, + * else `false`. + */ +function arraySome(array, predicate) { + var index = -1, + length = array == null ? 0 : array.length; + + while (++index < length) { + if (predicate(array[index], index, array)) { + return true; + } + } + return false; +} + +/** + * Checks if a `cache` value for `key` exists. + * + * @private + * @param {Object} cache The cache to query. + * @param {string} key The key of the entry to check. + * @returns {boolean} Returns `true` if an entry for `key` exists, else `false`. + */ +function cacheHas(cache, key) { + return cache.has(key); +} + +/** Used to compose bitmasks for value comparisons. */ +var COMPARE_PARTIAL_FLAG = 1, + COMPARE_UNORDERED_FLAG = 2; + +/** + * A specialized version of `baseIsEqualDeep` for arrays with support for + * partial deep comparisons. + * + * @private + * @param {Array} array The array to compare. + * @param {Array} other The other array to compare. + * @param {number} bitmask The bitmask flags. See `baseIsEqual` for more details. + * @param {Function} customizer The function to customize comparisons. + * @param {Function} equalFunc The function to determine equivalents of values. + * @param {Object} stack Tracks traversed `array` and `other` objects. + * @returns {boolean} Returns `true` if the arrays are equivalent, else `false`. + */ +function equalArrays(array, other, bitmask, customizer, equalFunc, stack) { + var isPartial = bitmask & COMPARE_PARTIAL_FLAG, + arrLength = array.length, + othLength = other.length; + + if (arrLength != othLength && !(isPartial && othLength > arrLength)) { + return false; + } + // Assume cyclic values are equal. + var stacked = stack.get(array); + if (stacked && stack.get(other)) { + return stacked == other; + } + var index = -1, + result = true, + seen = (bitmask & COMPARE_UNORDERED_FLAG) ? new SetCache : undefined; + + stack.set(array, other); + stack.set(other, array); + + // Ignore non-index properties. + while (++index < arrLength) { + var arrValue = array[index], + othValue = other[index]; + + if (customizer) { + var compared = isPartial + ? customizer(othValue, arrValue, index, other, array, stack) + : customizer(arrValue, othValue, index, array, other, stack); + } + if (compared !== undefined) { + if (compared) { + continue; + } + result = false; + break; + } + // Recursively compare arrays (susceptible to call stack limits). + if (seen) { + if (!arraySome(other, function(othValue, othIndex) { + if (!cacheHas(seen, othIndex) && + (arrValue === othValue || equalFunc(arrValue, othValue, bitmask, customizer, stack))) { + return seen.push(othIndex); + } + })) { + result = false; + break; + } + } else if (!( + arrValue === othValue || + equalFunc(arrValue, othValue, bitmask, customizer, stack) + )) { + result = false; + break; + } + } + stack['delete'](array); + stack['delete'](other); + return result; +} + +/** Built-in value references. */ +var Uint8Array = root.Uint8Array; + +/** + * Converts `map` to its key-value pairs. + * + * @private + * @param {Object} map The map to convert. + * @returns {Array} Returns the key-value pairs. + */ +function mapToArray(map) { + var index = -1, + result = Array(map.size); + + map.forEach(function(value, key) { + result[++index] = [key, value]; + }); + return result; +} + +/** + * Converts `set` to an array of its values. + * + * @private + * @param {Object} set The set to convert. + * @returns {Array} Returns the values. + */ +function setToArray(set) { + var index = -1, + result = Array(set.size); + + set.forEach(function(value) { + result[++index] = value; + }); + return result; +} + +/** Used to compose bitmasks for value comparisons. */ +var COMPARE_PARTIAL_FLAG$1 = 1, + COMPARE_UNORDERED_FLAG$1 = 2; + +/** `Object#toString` result references. */ +var boolTag$1 = '[object Boolean]', + dateTag$1 = '[object Date]', + errorTag$1 = '[object Error]', + mapTag$1 = '[object Map]', + numberTag$2 = '[object Number]', + regexpTag$1 = '[object RegExp]', + setTag$1 = '[object Set]', + stringTag$2 = '[object String]', + symbolTag$1 = '[object Symbol]'; + +var arrayBufferTag$1 = '[object ArrayBuffer]', + dataViewTag$1 = '[object DataView]'; + +/** Used to convert symbols to primitives and strings. */ +var symbolProto$1 = Symbol ? Symbol.prototype : undefined, + symbolValueOf = symbolProto$1 ? symbolProto$1.valueOf : undefined; + +/** + * A specialized version of `baseIsEqualDeep` for comparing objects of + * the same `toStringTag`. + * + * **Note:** This function only supports comparing values with tags of + * `Boolean`, `Date`, `Error`, `Number`, `RegExp`, or `String`. + * + * @private + * @param {Object} object The object to compare. + * @param {Object} other The other object to compare. + * @param {string} tag The `toStringTag` of the objects to compare. + * @param {number} bitmask The bitmask flags. See `baseIsEqual` for more details. + * @param {Function} customizer The function to customize comparisons. + * @param {Function} equalFunc The function to determine equivalents of values. + * @param {Object} stack Tracks traversed `object` and `other` objects. + * @returns {boolean} Returns `true` if the objects are equivalent, else `false`. + */ +function equalByTag(object, other, tag, bitmask, customizer, equalFunc, stack) { + switch (tag) { + case dataViewTag$1: + if ((object.byteLength != other.byteLength) || + (object.byteOffset != other.byteOffset)) { + return false; + } + object = object.buffer; + other = other.buffer; + + case arrayBufferTag$1: + if ((object.byteLength != other.byteLength) || + !equalFunc(new Uint8Array(object), new Uint8Array(other))) { + return false; + } + return true; + + case boolTag$1: + case dateTag$1: + case numberTag$2: + // Coerce booleans to `1` or `0` and dates to milliseconds. + // Invalid dates are coerced to `NaN`. + return eq(+object, +other); + + case errorTag$1: + return object.name == other.name && object.message == other.message; + + case regexpTag$1: + case stringTag$2: + // Coerce regexes to strings and treat strings, primitives and objects, + // as equal. See http://www.ecma-international.org/ecma-262/7.0/#sec-regexp.prototype.tostring + // for more details. + return object == (other + ''); + + case mapTag$1: + var convert = mapToArray; + + case setTag$1: + var isPartial = bitmask & COMPARE_PARTIAL_FLAG$1; + convert || (convert = setToArray); + + if (object.size != other.size && !isPartial) { + return false; + } + // Assume cyclic values are equal. + var stacked = stack.get(object); + if (stacked) { + return stacked == other; + } + bitmask |= COMPARE_UNORDERED_FLAG$1; + + // Recursively compare objects (susceptible to call stack limits). + stack.set(object, other); + var result = equalArrays(convert(object), convert(other), bitmask, customizer, equalFunc, stack); + stack['delete'](object); + return result; + + case symbolTag$1: + if (symbolValueOf) { + return symbolValueOf.call(object) == symbolValueOf.call(other); + } + } + return false; +} + +/** + * Appends the elements of `values` to `array`. + * + * @private + * @param {Array} array The array to modify. + * @param {Array} values The values to append. + * @returns {Array} Returns `array`. + */ +function arrayPush(array, values) { + var index = -1, + length = values.length, + offset = array.length; + + while (++index < length) { + array[offset + index] = values[index]; + } + return array; +} + +/** + * The base implementation of `getAllKeys` and `getAllKeysIn` which uses + * `keysFunc` and `symbolsFunc` to get the enumerable property names and + * symbols of `object`. + * + * @private + * @param {Object} object The object to query. + * @param {Function} keysFunc The function to get the keys of `object`. + * @param {Function} symbolsFunc The function to get the symbols of `object`. + * @returns {Array} Returns the array of property names and symbols. + */ +function baseGetAllKeys(object, keysFunc, symbolsFunc) { + var result = keysFunc(object); + return isArray(object) ? result : arrayPush(result, symbolsFunc(object)); +} + +/** + * This method returns a new empty array. + * + * @static + * @memberOf _ + * @since 4.13.0 + * @category Util + * @returns {Array} Returns the new empty array. + * @example + * + * var arrays = _.times(2, _.stubArray); + * + * console.log(arrays); + * // => [[], []] + * + * console.log(arrays[0] === arrays[1]); + * // => false + */ +function stubArray() { + return []; +} + +/** Used for built-in method references. */ +var objectProto$a = Object.prototype; + +/** Built-in value references. */ +var propertyIsEnumerable$1 = objectProto$a.propertyIsEnumerable; + +/* Built-in method references for those with the same name as other `lodash` methods. */ +var nativeGetSymbols = Object.getOwnPropertySymbols; + +/** + * Creates an array of the own enumerable symbols of `object`. + * + * @private + * @param {Object} object The object to query. + * @returns {Array} Returns the array of symbols. + */ +var getSymbols = !nativeGetSymbols ? stubArray : function(object) { + if (object == null) { + return []; + } + object = Object(object); + return arrayFilter(nativeGetSymbols(object), function(symbol) { + return propertyIsEnumerable$1.call(object, symbol); + }); +}; + +/** + * Creates an array of own enumerable property names and symbols of `object`. + * + * @private + * @param {Object} object The object to query. + * @returns {Array} Returns the array of property names and symbols. + */ +function getAllKeys(object) { + return baseGetAllKeys(object, keys, getSymbols); +} + +/** Used to compose bitmasks for value comparisons. */ +var COMPARE_PARTIAL_FLAG$2 = 1; + +/** Used for built-in method references. */ +var objectProto$b = Object.prototype; + +/** Used to check objects for own properties. */ +var hasOwnProperty$8 = objectProto$b.hasOwnProperty; + +/** + * A specialized version of `baseIsEqualDeep` for objects with support for + * partial deep comparisons. + * + * @private + * @param {Object} object The object to compare. + * @param {Object} other The other object to compare. + * @param {number} bitmask The bitmask flags. See `baseIsEqual` for more details. + * @param {Function} customizer The function to customize comparisons. + * @param {Function} equalFunc The function to determine equivalents of values. + * @param {Object} stack Tracks traversed `object` and `other` objects. + * @returns {boolean} Returns `true` if the objects are equivalent, else `false`. + */ +function equalObjects(object, other, bitmask, customizer, equalFunc, stack) { + var isPartial = bitmask & COMPARE_PARTIAL_FLAG$2, + objProps = getAllKeys(object), + objLength = objProps.length, + othProps = getAllKeys(other), + othLength = othProps.length; + + if (objLength != othLength && !isPartial) { + return false; + } + var index = objLength; + while (index--) { + var key = objProps[index]; + if (!(isPartial ? key in other : hasOwnProperty$8.call(other, key))) { + return false; + } + } + // Assume cyclic values are equal. + var stacked = stack.get(object); + if (stacked && stack.get(other)) { + return stacked == other; + } + var result = true; + stack.set(object, other); + stack.set(other, object); + + var skipCtor = isPartial; + while (++index < objLength) { + key = objProps[index]; + var objValue = object[key], + othValue = other[key]; + + if (customizer) { + var compared = isPartial + ? customizer(othValue, objValue, key, other, object, stack) + : customizer(objValue, othValue, key, object, other, stack); + } + // Recursively compare objects (susceptible to call stack limits). + if (!(compared === undefined + ? (objValue === othValue || equalFunc(objValue, othValue, bitmask, customizer, stack)) + : compared + )) { + result = false; + break; + } + skipCtor || (skipCtor = key == 'constructor'); + } + if (result && !skipCtor) { + var objCtor = object.constructor, + othCtor = other.constructor; + + // Non `Object` object instances with different constructors are not equal. + if (objCtor != othCtor && + ('constructor' in object && 'constructor' in other) && + !(typeof objCtor == 'function' && objCtor instanceof objCtor && + typeof othCtor == 'function' && othCtor instanceof othCtor)) { + result = false; + } + } + stack['delete'](object); + stack['delete'](other); + return result; +} + +/* Built-in method references that are verified to be native. */ +var DataView = getNative(root, 'DataView'); + +/* Built-in method references that are verified to be native. */ +var Promise$1 = getNative(root, 'Promise'); + +/* Built-in method references that are verified to be native. */ +var Set$1 = getNative(root, 'Set'); + +/* Built-in method references that are verified to be native. */ +var WeakMap$1 = getNative(root, 'WeakMap'); + +/** `Object#toString` result references. */ +var mapTag$2 = '[object Map]', + objectTag$2 = '[object Object]', + promiseTag = '[object Promise]', + setTag$2 = '[object Set]', + weakMapTag$1 = '[object WeakMap]'; + +var dataViewTag$2 = '[object DataView]'; + +/** Used to detect maps, sets, and weakmaps. */ +var dataViewCtorString = toSource(DataView), + mapCtorString = toSource(Map$1), + promiseCtorString = toSource(Promise$1), + setCtorString = toSource(Set$1), + weakMapCtorString = toSource(WeakMap$1); + +/** + * Gets the `toStringTag` of `value`. + * + * @private + * @param {*} value The value to query. + * @returns {string} Returns the `toStringTag`. + */ +var getTag = baseGetTag; + +// Fallback for data views, maps, sets, and weak maps in IE 11 and promises in Node.js < 6. +if ((DataView && getTag(new DataView(new ArrayBuffer(1))) != dataViewTag$2) || + (Map$1 && getTag(new Map$1) != mapTag$2) || + (Promise$1 && getTag(Promise$1.resolve()) != promiseTag) || + (Set$1 && getTag(new Set$1) != setTag$2) || + (WeakMap$1 && getTag(new WeakMap$1) != weakMapTag$1)) { + getTag = function(value) { + var result = baseGetTag(value), + Ctor = result == objectTag$2 ? value.constructor : undefined, + ctorString = Ctor ? toSource(Ctor) : ''; + + if (ctorString) { + switch (ctorString) { + case dataViewCtorString: return dataViewTag$2; + case mapCtorString: return mapTag$2; + case promiseCtorString: return promiseTag; + case setCtorString: return setTag$2; + case weakMapCtorString: return weakMapTag$1; + } + } + return result; + }; +} + +var getTag$1 = getTag; + +/** Used to compose bitmasks for value comparisons. */ +var COMPARE_PARTIAL_FLAG$3 = 1; + +/** `Object#toString` result references. */ +var argsTag$2 = '[object Arguments]', + arrayTag$1 = '[object Array]', + objectTag$3 = '[object Object]'; + +/** Used for built-in method references. */ +var objectProto$c = Object.prototype; + +/** Used to check objects for own properties. */ +var hasOwnProperty$9 = objectProto$c.hasOwnProperty; + +/** + * A specialized version of `baseIsEqual` for arrays and objects which performs + * deep comparisons and tracks traversed objects enabling objects with circular + * references to be compared. + * + * @private + * @param {Object} object The object to compare. + * @param {Object} other The other object to compare. + * @param {number} bitmask The bitmask flags. See `baseIsEqual` for more details. + * @param {Function} customizer The function to customize comparisons. + * @param {Function} equalFunc The function to determine equivalents of values. + * @param {Object} [stack] Tracks traversed `object` and `other` objects. + * @returns {boolean} Returns `true` if the objects are equivalent, else `false`. + */ +function baseIsEqualDeep(object, other, bitmask, customizer, equalFunc, stack) { + var objIsArr = isArray(object), + othIsArr = isArray(other), + objTag = objIsArr ? arrayTag$1 : getTag$1(object), + othTag = othIsArr ? arrayTag$1 : getTag$1(other); + + objTag = objTag == argsTag$2 ? objectTag$3 : objTag; + othTag = othTag == argsTag$2 ? objectTag$3 : othTag; + + var objIsObj = objTag == objectTag$3, + othIsObj = othTag == objectTag$3, + isSameTag = objTag == othTag; + + if (isSameTag && isBuffer(object)) { + if (!isBuffer(other)) { + return false; + } + objIsArr = true; + objIsObj = false; + } + if (isSameTag && !objIsObj) { + stack || (stack = new Stack); + return (objIsArr || isTypedArray(object)) + ? equalArrays(object, other, bitmask, customizer, equalFunc, stack) + : equalByTag(object, other, objTag, bitmask, customizer, equalFunc, stack); + } + if (!(bitmask & COMPARE_PARTIAL_FLAG$3)) { + var objIsWrapped = objIsObj && hasOwnProperty$9.call(object, '__wrapped__'), + othIsWrapped = othIsObj && hasOwnProperty$9.call(other, '__wrapped__'); + + if (objIsWrapped || othIsWrapped) { + var objUnwrapped = objIsWrapped ? object.value() : object, + othUnwrapped = othIsWrapped ? other.value() : other; + + stack || (stack = new Stack); + return equalFunc(objUnwrapped, othUnwrapped, bitmask, customizer, stack); + } + } + if (!isSameTag) { + return false; + } + stack || (stack = new Stack); + return equalObjects(object, other, bitmask, customizer, equalFunc, stack); +} + +/** + * The base implementation of `_.isEqual` which supports partial comparisons + * and tracks traversed objects. + * + * @private + * @param {*} value The value to compare. + * @param {*} other The other value to compare. + * @param {boolean} bitmask The bitmask flags. + * 1 - Unordered comparison + * 2 - Partial comparison + * @param {Function} [customizer] The function to customize comparisons. + * @param {Object} [stack] Tracks traversed `value` and `other` objects. + * @returns {boolean} Returns `true` if the values are equivalent, else `false`. + */ +function baseIsEqual(value, other, bitmask, customizer, stack) { + if (value === other) { + return true; + } + if (value == null || other == null || (!isObjectLike(value) && !isObjectLike(other))) { + return value !== value && other !== other; + } + return baseIsEqualDeep(value, other, bitmask, customizer, baseIsEqual, stack); +} + +/** Used to compose bitmasks for value comparisons. */ +var COMPARE_PARTIAL_FLAG$4 = 1, + COMPARE_UNORDERED_FLAG$2 = 2; + +/** + * The base implementation of `_.isMatch` without support for iteratee shorthands. + * + * @private + * @param {Object} object The object to inspect. + * @param {Object} source The object of property values to match. + * @param {Array} matchData The property names, values, and compare flags to match. + * @param {Function} [customizer] The function to customize comparisons. + * @returns {boolean} Returns `true` if `object` is a match, else `false`. + */ +function baseIsMatch(object, source, matchData, customizer) { + var index = matchData.length, + length = index, + noCustomizer = !customizer; + + if (object == null) { + return !length; + } + object = Object(object); + while (index--) { + var data = matchData[index]; + if ((noCustomizer && data[2]) + ? data[1] !== object[data[0]] + : !(data[0] in object) + ) { + return false; + } + } + while (++index < length) { + data = matchData[index]; + var key = data[0], + objValue = object[key], + srcValue = data[1]; + + if (noCustomizer && data[2]) { + if (objValue === undefined && !(key in object)) { + return false; + } + } else { + var stack = new Stack; + if (customizer) { + var result = customizer(objValue, srcValue, key, object, source, stack); + } + if (!(result === undefined + ? baseIsEqual(srcValue, objValue, COMPARE_PARTIAL_FLAG$4 | COMPARE_UNORDERED_FLAG$2, customizer, stack) + : result + )) { + return false; + } + } + } + return true; +} + +/** + * Checks if `value` is suitable for strict equality comparisons, i.e. `===`. + * + * @private + * @param {*} value The value to check. + * @returns {boolean} Returns `true` if `value` if suitable for strict + * equality comparisons, else `false`. + */ +function isStrictComparable(value) { + return value === value && !isObject(value); +} + +/** + * Gets the property names, values, and compare flags of `object`. + * + * @private + * @param {Object} object The object to query. + * @returns {Array} Returns the match data of `object`. + */ +function getMatchData(object) { + var result = keys(object), + length = result.length; + + while (length--) { + var key = result[length], + value = object[key]; + + result[length] = [key, value, isStrictComparable(value)]; + } + return result; +} + +/** + * A specialized version of `matchesProperty` for source values suitable + * for strict equality comparisons, i.e. `===`. + * + * @private + * @param {string} key The key of the property to get. + * @param {*} srcValue The value to match. + * @returns {Function} Returns the new spec function. + */ +function matchesStrictComparable(key, srcValue) { + return function(object) { + if (object == null) { + return false; + } + return object[key] === srcValue && + (srcValue !== undefined || (key in Object(object))); + }; +} + +/** + * The base implementation of `_.matches` which doesn't clone `source`. + * + * @private + * @param {Object} source The object of property values to match. + * @returns {Function} Returns the new spec function. + */ +function baseMatches(source) { + var matchData = getMatchData(source); + if (matchData.length == 1 && matchData[0][2]) { + return matchesStrictComparable(matchData[0][0], matchData[0][1]); + } + return function(object) { + return object === source || baseIsMatch(object, source, matchData); + }; +} + +/** Used to match property names within property paths. */ +var reIsDeepProp = /\.|\[(?:[^[\]]*|(["'])(?:(?!\1)[^\\]|\\.)*?\1)\]/, + reIsPlainProp = /^\w*$/; + +/** + * Checks if `value` is a property name and not a property path. + * + * @private + * @param {*} value The value to check. + * @param {Object} [object] The object to query keys on. + * @returns {boolean} Returns `true` if `value` is a property name, else `false`. + */ +function isKey(value, object) { + if (isArray(value)) { + return false; + } + var type = typeof value; + if (type == 'number' || type == 'symbol' || type == 'boolean' || + value == null || isSymbol(value)) { + return true; + } + return reIsPlainProp.test(value) || !reIsDeepProp.test(value) || + (object != null && value in Object(object)); +} + +/** Error message constants. */ +var FUNC_ERROR_TEXT = 'Expected a function'; + +/** + * Creates a function that memoizes the result of `func`. If `resolver` is + * provided, it determines the cache key for storing the result based on the + * arguments provided to the memoized function. By default, the first argument + * provided to the memoized function is used as the map cache key. The `func` + * is invoked with the `this` binding of the memoized function. + * + * **Note:** The cache is exposed as the `cache` property on the memoized + * function. Its creation may be customized by replacing the `_.memoize.Cache` + * constructor with one whose instances implement the + * [`Map`](http://ecma-international.org/ecma-262/7.0/#sec-properties-of-the-map-prototype-object) + * method interface of `clear`, `delete`, `get`, `has`, and `set`. + * + * @static + * @memberOf _ + * @since 0.1.0 + * @category Function + * @param {Function} func The function to have its output memoized. + * @param {Function} [resolver] The function to resolve the cache key. + * @returns {Function} Returns the new memoized function. + * @example + * + * var object = { 'a': 1, 'b': 2 }; + * var other = { 'c': 3, 'd': 4 }; + * + * var values = _.memoize(_.values); + * values(object); + * // => [1, 2] + * + * values(other); + * // => [3, 4] + * + * object.a = 2; + * values(object); + * // => [1, 2] + * + * // Modify the result cache. + * values.cache.set(object, ['a', 'b']); + * values(object); + * // => ['a', 'b'] + * + * // Replace `_.memoize.Cache`. + * _.memoize.Cache = WeakMap; + */ +function memoize(func, resolver) { + if (typeof func != 'function' || (resolver != null && typeof resolver != 'function')) { + throw new TypeError(FUNC_ERROR_TEXT); + } + var memoized = function() { + var args = arguments, + key = resolver ? resolver.apply(this, args) : args[0], + cache = memoized.cache; + + if (cache.has(key)) { + return cache.get(key); + } + var result = func.apply(this, args); + memoized.cache = cache.set(key, result) || cache; + return result; + }; + memoized.cache = new (memoize.Cache || MapCache); + return memoized; +} + +// Expose `MapCache`. +memoize.Cache = MapCache; + +/** Used as the maximum memoize cache size. */ +var MAX_MEMOIZE_SIZE = 500; + +/** + * A specialized version of `_.memoize` which clears the memoized function's + * cache when it exceeds `MAX_MEMOIZE_SIZE`. + * + * @private + * @param {Function} func The function to have its output memoized. + * @returns {Function} Returns the new memoized function. + */ +function memoizeCapped(func) { + var result = memoize(func, function(key) { + if (cache.size === MAX_MEMOIZE_SIZE) { + cache.clear(); + } + return key; + }); + + var cache = result.cache; + return result; +} + +/** Used to match property names within property paths. */ +var rePropName = /[^.[\]]+|\[(?:(-?\d+(?:\.\d+)?)|(["'])((?:(?!\2)[^\\]|\\.)*?)\2)\]|(?=(?:\.|\[\])(?:\.|\[\]|$))/g; + +/** Used to match backslashes in property paths. */ +var reEscapeChar = /\\(\\)?/g; + +/** + * Converts `string` to a property path array. + * + * @private + * @param {string} string The string to convert. + * @returns {Array} Returns the property path array. + */ +var stringToPath = memoizeCapped(function(string) { + var result = []; + if (string.charCodeAt(0) === 46 /* . */) { + result.push(''); + } + string.replace(rePropName, function(match, number, quote, subString) { + result.push(quote ? subString.replace(reEscapeChar, '$1') : (number || match)); + }); + return result; +}); + +/** + * Casts `value` to a path array if it's not one. + * + * @private + * @param {*} value The value to inspect. + * @param {Object} [object] The object to query keys on. + * @returns {Array} Returns the cast property path array. + */ +function castPath(value, object) { + if (isArray(value)) { + return value; + } + return isKey(value, object) ? [value] : stringToPath(toString(value)); +} + +/** Used as references for various `Number` constants. */ +var INFINITY$1 = 1 / 0; + +/** + * Converts `value` to a string key if it's not a string or symbol. + * + * @private + * @param {*} value The value to inspect. + * @returns {string|symbol} Returns the key. + */ +function toKey(value) { + if (typeof value == 'string' || isSymbol(value)) { + return value; + } + var result = (value + ''); + return (result == '0' && (1 / value) == -INFINITY$1) ? '-0' : result; +} + +/** + * The base implementation of `_.get` without support for default values. + * + * @private + * @param {Object} object The object to query. + * @param {Array|string} path The path of the property to get. + * @returns {*} Returns the resolved value. + */ +function baseGet(object, path) { + path = castPath(path, object); + + var index = 0, + length = path.length; + + while (object != null && index < length) { + object = object[toKey(path[index++])]; + } + return (index && index == length) ? object : undefined; +} + +/** + * Gets the value at `path` of `object`. If the resolved value is + * `undefined`, the `defaultValue` is returned in its place. + * + * @static + * @memberOf _ + * @since 3.7.0 + * @category Object + * @param {Object} object The object to query. + * @param {Array|string} path The path of the property to get. + * @param {*} [defaultValue] The value returned for `undefined` resolved values. + * @returns {*} Returns the resolved value. + * @example + * + * var object = { 'a': [{ 'b': { 'c': 3 } }] }; + * + * _.get(object, 'a[0].b.c'); + * // => 3 + * + * _.get(object, ['a', '0', 'b', 'c']); + * // => 3 + * + * _.get(object, 'a.b.c', 'default'); + * // => 'default' + */ +function get(object, path, defaultValue) { + var result = object == null ? undefined : baseGet(object, path); + return result === undefined ? defaultValue : result; +} + +/** + * The base implementation of `_.hasIn` without support for deep paths. + * + * @private + * @param {Object} [object] The object to query. + * @param {Array|string} key The key to check. + * @returns {boolean} Returns `true` if `key` exists, else `false`. + */ +function baseHasIn(object, key) { + return object != null && key in Object(object); +} + +/** + * Checks if `path` exists on `object`. + * + * @private + * @param {Object} object The object to query. + * @param {Array|string} path The path to check. + * @param {Function} hasFunc The function to check properties. + * @returns {boolean} Returns `true` if `path` exists, else `false`. + */ +function hasPath(object, path, hasFunc) { + path = castPath(path, object); + + var index = -1, + length = path.length, + result = false; + + while (++index < length) { + var key = toKey(path[index]); + if (!(result = object != null && hasFunc(object, key))) { + break; + } + object = object[key]; + } + if (result || ++index != length) { + return result; + } + length = object == null ? 0 : object.length; + return !!length && isLength(length) && isIndex(key, length) && + (isArray(object) || isArguments(object)); +} + +/** + * Checks if `path` is a direct or inherited property of `object`. + * + * @static + * @memberOf _ + * @since 4.0.0 + * @category Object + * @param {Object} object The object to query. + * @param {Array|string} path The path to check. + * @returns {boolean} Returns `true` if `path` exists, else `false`. + * @example + * + * var object = _.create({ 'a': _.create({ 'b': 2 }) }); + * + * _.hasIn(object, 'a'); + * // => true + * + * _.hasIn(object, 'a.b'); + * // => true + * + * _.hasIn(object, ['a', 'b']); + * // => true + * + * _.hasIn(object, 'b'); + * // => false + */ +function hasIn(object, path) { + return object != null && hasPath(object, path, baseHasIn); +} + +/** Used to compose bitmasks for value comparisons. */ +var COMPARE_PARTIAL_FLAG$5 = 1, + COMPARE_UNORDERED_FLAG$3 = 2; + +/** + * The base implementation of `_.matchesProperty` which doesn't clone `srcValue`. + * + * @private + * @param {string} path The path of the property to get. + * @param {*} srcValue The value to match. + * @returns {Function} Returns the new spec function. + */ +function baseMatchesProperty(path, srcValue) { + if (isKey(path) && isStrictComparable(srcValue)) { + return matchesStrictComparable(toKey(path), srcValue); + } + return function(object) { + var objValue = get(object, path); + return (objValue === undefined && objValue === srcValue) + ? hasIn(object, path) + : baseIsEqual(srcValue, objValue, COMPARE_PARTIAL_FLAG$5 | COMPARE_UNORDERED_FLAG$3); + }; +} + +/** + * This method returns the first argument it receives. + * + * @static + * @since 0.1.0 + * @memberOf _ + * @category Util + * @param {*} value Any value. + * @returns {*} Returns `value`. + * @example + * + * var object = { 'a': 1 }; + * + * console.log(_.identity(object) === object); + * // => true + */ +function identity(value) { + return value; +} + +/** + * The base implementation of `_.property` without support for deep paths. + * + * @private + * @param {string} key The key of the property to get. + * @returns {Function} Returns the new accessor function. + */ +function baseProperty(key) { + return function(object) { + return object == null ? undefined : object[key]; + }; +} + +/** + * A specialized version of `baseProperty` which supports deep paths. + * + * @private + * @param {Array|string} path The path of the property to get. + * @returns {Function} Returns the new accessor function. + */ +function basePropertyDeep(path) { + return function(object) { + return baseGet(object, path); + }; +} + +/** + * Creates a function that returns the value at `path` of a given object. + * + * @static + * @memberOf _ + * @since 2.4.0 + * @category Util + * @param {Array|string} path The path of the property to get. + * @returns {Function} Returns the new accessor function. + * @example + * + * var objects = [ + * { 'a': { 'b': 2 } }, + * { 'a': { 'b': 1 } } + * ]; + * + * _.map(objects, _.property('a.b')); + * // => [2, 1] + * + * _.map(_.sortBy(objects, _.property(['a', 'b'])), 'a.b'); + * // => [1, 2] + */ +function property(path) { + return isKey(path) ? baseProperty(toKey(path)) : basePropertyDeep(path); +} + +/** + * The base implementation of `_.iteratee`. + * + * @private + * @param {*} [value=_.identity] The value to convert to an iteratee. + * @returns {Function} Returns the iteratee. + */ +function baseIteratee(value) { + // Don't store the `typeof` result in a variable to avoid a JIT bug in Safari 9. + // See https://bugs.webkit.org/show_bug.cgi?id=156034 for more details. + if (typeof value == 'function') { + return value; + } + if (value == null) { + return identity; + } + if (typeof value == 'object') { + return isArray(value) + ? baseMatchesProperty(value[0], value[1]) + : baseMatches(value); + } + return property(value); +} + +// validate object type +/** + * @TODO if provide with the keys then we need to check if the key:value type as well + * @param {object} value expected + * @param {array} [keys=null] if it has the keys array to compare as well + * @return {boolean} true if OK + */ +var checkIsObject = function(value, keys) { + if ( keys === void 0 ) keys=null; + + if (isPlainObject(value)) { + if (!keys) { + return true + } + if (checkIsArray(keys)) { + // please note we DON'T care if some is optional + // plese refer to the contract.json for the keys + return !keys.filter(function (key) { + var _value = value[key.name]; + return !(key.type.length > key.type.filter(function (type) { + var tmp; + if (_value !== undefined) { + if ((tmp = isArrayLike(type)) !== false) { + return !arrayTypeHandler({arg: _value}, tmp) + // return tmp.filter(t => !checkIsArray(_value, t)).length; + // @TODO there might be an object within an object with keys as well :S + } + return !combineFn(type)(_value) + } + return true + }).length) + }).length; + } + } + return false +}; + +/** + * fold this into it's own function to handler different object type + * @param {object} p the prepared object for process + * @return {boolean} + */ +var objectTypeHandler = function(p) { + var arg = p.arg; + var param = p.param; + var _args = [arg]; + if (Array.isArray(param.keys) && param.keys.length) { + _args.push(param.keys); + } + // just simple check + return Reflect.apply(checkIsObject, null, _args) +}; + +// custom validation error class +// when validaton failed +var JsonqlValidationError = /*@__PURE__*/(function (Error) { + function JsonqlValidationError() { + var args = [], len = arguments.length; + while ( len-- ) args[ len ] = arguments[ len ]; + + Error.apply(this, args); + + this.message = args[0]; + this.detail = args[1]; + + this.className = JsonqlValidationError.name; + + if (Error.captureStackTrace) { + Error.captureStackTrace(this, JsonqlValidationError); + } + } + + if ( Error ) JsonqlValidationError.__proto__ = Error; + JsonqlValidationError.prototype = Object.create( Error && Error.prototype ); + JsonqlValidationError.prototype.constructor = JsonqlValidationError; + + var staticAccessors = { name: { configurable: true } }; + + staticAccessors.name.get = function () { + return 'JsonqlValidationError'; + }; + + Object.defineProperties( JsonqlValidationError, staticAccessors ); + + return JsonqlValidationError; +}(Error)); + +/** + * This is a custom error to throw whenever a error happen inside the jsonql + * This help us to capture the right error, due to the call happens in sequence + * @param {string} message to tell what happen + * @param {mixed} extra things we want to add, 500? + */ +var JsonqlError$1 = /*@__PURE__*/(function (Error) { + function JsonqlError() { + var args = [], len = arguments.length; + while ( len-- ) args[ len ] = arguments[ len ]; + + Error.apply(this, args); + + this.message = args[0]; + this.detail = args[1]; + + this.className = JsonqlError.name; + + if (Error.captureStackTrace) { + Error.captureStackTrace(this, JsonqlError); + // this.detail = this.stack; + } + } + + if ( Error ) JsonqlError.__proto__ = Error; + JsonqlError.prototype = Object.create( Error && Error.prototype ); + JsonqlError.prototype.constructor = JsonqlError; + + var staticAccessors = { name: { configurable: true },statusCode: { configurable: true } }; + + staticAccessors.name.get = function () { + return 'JsonqlError'; + }; + + staticAccessors.statusCode.get = function () { + return NO_STATUS_CODE$1; + }; + + Object.defineProperties( JsonqlError, staticAccessors ); + + return JsonqlError; +}(Error)); + +// move the index.js code here that make more sense to find where things are +// import debug from 'debug' +// const debugFn = debug('jsonql-params-validator:validator') +// also export this for use in other places + +/** + * We need to handle those optional parameter without a default value + * @param {object} params from contract.json + * @return {boolean} for filter operation false is actually OK + */ +var optionalHandler = function( params ) { + var arg = params.arg; + var param = params.param; + if (isNotEmpty(arg)) { + // debug('call optional handler', arg, params); + // loop through the type in param + return !(param.type.length > param.type.filter(function (type) { return validateHandler(type, params); } + ).length) + } + return false +}; + +/** + * actually picking the validator + * @param {*} type for checking + * @param {*} value for checking + * @return {boolean} true on OK + */ +var validateHandler = function(type, value) { + var tmp; + switch (true) { + case type === OBJECT_TYPE$1: + // debugFn('call OBJECT_TYPE') + return !objectTypeHandler(value) + case type === ARRAY_TYPE$1: + // debugFn('call ARRAY_TYPE') + return !checkIsArray(value.arg) + // @TODO when the type is not present, it always fall through here + // so we need to find a way to actually pre-check the type first + // AKA check the contract.json map before running here + case (tmp = isArrayLike(type)) !== false: + // debugFn('call ARRAY_LIKE: %O', value) + return !arrayTypeHandler(value, tmp) + default: + return !combineFn(type)(value.arg) + } +}; + +/** + * it get too longer to fit in one line so break it out from the fn below + * @param {*} arg value + * @param {object} param config + * @return {*} value or apply default value + */ +var getOptionalValue = function(arg, param) { + if (arg !== undefined) { + return arg + } + return (param.optional === true && param.defaultvalue !== undefined ? param.defaultvalue : null) +}; + +/** + * padding the arguments with defaultValue if the arguments did not provide the value + * this will be the name export + * @param {array} args normalized arguments + * @param {array} params from contract.json + * @return {array} merge the two together + */ +var normalizeArgs = function(args, params) { + // first we should check if this call require a validation at all + // there will be situation where the function doesn't need args and params + if (!checkIsArray(params)) { + // debugFn('params value', params) + throw new JsonqlValidationError(PARAMS_NOT_ARRAY_ERR) + } + if (params.length === 0) { + return [] + } + if (!checkIsArray(args)) { + throw new JsonqlValidationError(ARGS_NOT_ARRAY_ERR) + } + // debugFn(args, params); + // fall through switch + switch(true) { + case args.length == params.length: // standard + return args.map(function (arg, i) { return ( + { + arg: arg, + index: i, + param: params[i] + } + ); }) + case params[0].variable === true: // using spread syntax + var type = params[0].type; + return args.map(function (arg, i) { return ( + { + arg: arg, + index: i, // keep the index for reference + param: params[i] || { type: type, name: '_' } + } + ); }) + // with optional defaultValue parameters + case args.length < params.length: + return params.map(function (param, i) { return ( + { + param: param, + index: i, + arg: getOptionalValue(args[i], param), + optional: param.optional || false + } + ); }) + // this one pass more than it should have anything after the args.length will be cast as any type + case args.length > params.length: + var ctn = params.length; + // this happens when we have those array. type + var _type = [ DEFAULT_TYPE$1 ]; + // we only looking at the first one, this might be a @BUG + /* + if ((tmp = isArrayLike(params[0].type[0])) !== false) { + _type = tmp; + } */ + // if we use the params as guide then the rest will get throw out + // which is not what we want, instead, anything without the param + // will get a any type and optional flag + return args.map(function (arg, i) { + var optional = i >= ctn ? true : !!params[i].optional; + var param = params[i] || { type: _type, name: ("_" + i) }; + return { + arg: optional ? getOptionalValue(arg, param) : arg, + index: i, + param: param, + optional: optional + } + }) + // @TODO find out if there is more cases not cover + default: // this should never happen + // debugFn('args', args) + // debugFn('params', params) + // this is unknown therefore we just throw it! + throw new JsonqlError$1(EXCEPTION_CASE_ERR, { args: args, params: params }) + } +}; + +// what we want is after the validaton we also get the normalized result +// which is with the optional property if the argument didn't provide it +/** + * process the array of params back to their arguments + * @param {array} result the params result + * @return {array} arguments + */ +var processReturn = function (result) { return result.map(function (r) { return r.arg; }); }; + +/** + * validator main interface + * @param {array} args the arguments pass to the method call + * @param {array} params from the contract for that method + * @param {boolean} [withResul=false] if true then this will return the normalize result as well + * @return {array} empty array on success, or failed parameter and reasons + */ +var validateSync = function(args, params, withResult) { + var obj; + + if ( withResult === void 0 ) withResult = false; + var cleanArgs = normalizeArgs(args, params); + var checkResult = cleanArgs.filter(function (p) { + // v1.4.4 this fixed the problem, the root level optional is from the last fn + if (p.optional === true || p.param.optional === true) { + return optionalHandler(p) + } + // because array of types means OR so if one pass means pass + return !(p.param.type.length > p.param.type.filter( + function (type) { return validateHandler(type, p); } + ).length) + }); + // using the same convention we been using all this time + return !withResult ? checkResult : ( obj = {}, obj[ERROR_KEY$1] = checkResult, obj[DATA_KEY] = processReturn(cleanArgs), obj ) +}; + +/** + * A wrapper method that return promise + * @param {array} args arguments + * @param {array} params from contract.json + * @param {boolean} [withResul=false] if true then this will return the normalize result as well + * @return {object} promise.then or catch + */ +var validateAsync = function(args, params, withResult) { + if ( withResult === void 0 ) withResult = false; + + return new Promise(function (resolver, rejecter) { + var result = validateSync(args, params, withResult); + if (withResult) { + return result[ERROR_KEY$1].length ? rejecter(result[ERROR_KEY$1]) + : resolver(result[DATA_KEY]) + } + // the different is just in the then or catch phrase + return result.length ? rejecter(result) : resolver([]) + }) +}; + +var defineProperty = (function() { + try { + var func = getNative(Object, 'defineProperty'); + func({}, '', {}); + return func; + } catch (e) {} +}()); + +/** + * The base implementation of `assignValue` and `assignMergeValue` without + * value checks. + * + * @private + * @param {Object} object The object to modify. + * @param {string} key The key of the property to assign. + * @param {*} value The value to assign. + */ +function baseAssignValue(object, key, value) { + if (key == '__proto__' && defineProperty) { + defineProperty(object, key, { + 'configurable': true, + 'enumerable': true, + 'value': value, + 'writable': true + }); + } else { + object[key] = value; + } +} + +/** + * This function is like `assignValue` except that it doesn't assign + * `undefined` values. + * + * @private + * @param {Object} object The object to modify. + * @param {string} key The key of the property to assign. + * @param {*} value The value to assign. + */ +function assignMergeValue(object, key, value) { + if ((value !== undefined && !eq(object[key], value)) || + (value === undefined && !(key in object))) { + baseAssignValue(object, key, value); + } +} + +/** Detect free variable `exports`. */ +var freeExports$2 = typeof exports == 'object' && exports && !exports.nodeType && exports; + +/** Detect free variable `module`. */ +var freeModule$2 = freeExports$2 && typeof module == 'object' && module && !module.nodeType && module; + +/** Detect the popular CommonJS extension `module.exports`. */ +var moduleExports$2 = freeModule$2 && freeModule$2.exports === freeExports$2; + +/** Built-in value references. */ +var Buffer$1 = moduleExports$2 ? root.Buffer : undefined, + allocUnsafe = Buffer$1 ? Buffer$1.allocUnsafe : undefined; + +/** + * Creates a clone of `buffer`. + * + * @private + * @param {Buffer} buffer The buffer to clone. + * @param {boolean} [isDeep] Specify a deep clone. + * @returns {Buffer} Returns the cloned buffer. + */ +function cloneBuffer(buffer, isDeep) { + if (isDeep) { + return buffer.slice(); + } + var length = buffer.length, + result = allocUnsafe ? allocUnsafe(length) : new buffer.constructor(length); + + buffer.copy(result); + return result; +} + +/** + * Creates a clone of `arrayBuffer`. + * + * @private + * @param {ArrayBuffer} arrayBuffer The array buffer to clone. + * @returns {ArrayBuffer} Returns the cloned array buffer. + */ +function cloneArrayBuffer(arrayBuffer) { + var result = new arrayBuffer.constructor(arrayBuffer.byteLength); + new Uint8Array(result).set(new Uint8Array(arrayBuffer)); + return result; +} + +/** + * Creates a clone of `typedArray`. + * + * @private + * @param {Object} typedArray The typed array to clone. + * @param {boolean} [isDeep] Specify a deep clone. + * @returns {Object} Returns the cloned typed array. + */ +function cloneTypedArray(typedArray, isDeep) { + var buffer = isDeep ? cloneArrayBuffer(typedArray.buffer) : typedArray.buffer; + return new typedArray.constructor(buffer, typedArray.byteOffset, typedArray.length); +} + +/** + * Copies the values of `source` to `array`. + * + * @private + * @param {Array} source The array to copy values from. + * @param {Array} [array=[]] The array to copy values to. + * @returns {Array} Returns `array`. + */ +function copyArray(source, array) { + var index = -1, + length = source.length; + + array || (array = Array(length)); + while (++index < length) { + array[index] = source[index]; + } + return array; +} + +/** Built-in value references. */ +var objectCreate = Object.create; + +/** + * The base implementation of `_.create` without support for assigning + * properties to the created object. + * + * @private + * @param {Object} proto The object to inherit from. + * @returns {Object} Returns the new object. + */ +var baseCreate = (function() { + function object() {} + return function(proto) { + if (!isObject(proto)) { + return {}; + } + if (objectCreate) { + return objectCreate(proto); + } + object.prototype = proto; + var result = new object; + object.prototype = undefined; + return result; + }; +}()); + +/** + * Initializes an object clone. + * + * @private + * @param {Object} object The object to clone. + * @returns {Object} Returns the initialized clone. + */ +function initCloneObject(object) { + return (typeof object.constructor == 'function' && !isPrototype(object)) + ? baseCreate(getPrototype(object)) + : {}; +} + +/** + * This method is like `_.isArrayLike` except that it also checks if `value` + * is an object. + * + * @static + * @memberOf _ + * @since 4.0.0 + * @category Lang + * @param {*} value The value to check. + * @returns {boolean} Returns `true` if `value` is an array-like object, + * else `false`. + * @example + * + * _.isArrayLikeObject([1, 2, 3]); + * // => true + * + * _.isArrayLikeObject(document.body.children); + * // => true + * + * _.isArrayLikeObject('abc'); + * // => false + * + * _.isArrayLikeObject(_.noop); + * // => false + */ +function isArrayLikeObject(value) { + return isObjectLike(value) && isArrayLike$1(value); +} + +/** + * Gets the value at `key`, unless `key` is "__proto__" or "constructor". + * + * @private + * @param {Object} object The object to query. + * @param {string} key The key of the property to get. + * @returns {*} Returns the property value. + */ +function safeGet(object, key) { + if (key === 'constructor' && typeof object[key] === 'function') { + return; + } + + if (key == '__proto__') { + return; + } + + return object[key]; +} + +/** Used for built-in method references. */ +var objectProto$d = Object.prototype; + +/** Used to check objects for own properties. */ +var hasOwnProperty$a = objectProto$d.hasOwnProperty; + +/** + * Assigns `value` to `key` of `object` if the existing value is not equivalent + * using [`SameValueZero`](http://ecma-international.org/ecma-262/7.0/#sec-samevaluezero) + * for equality comparisons. + * + * @private + * @param {Object} object The object to modify. + * @param {string} key The key of the property to assign. + * @param {*} value The value to assign. + */ +function assignValue(object, key, value) { + var objValue = object[key]; + if (!(hasOwnProperty$a.call(object, key) && eq(objValue, value)) || + (value === undefined && !(key in object))) { + baseAssignValue(object, key, value); + } +} + +/** + * Copies properties of `source` to `object`. + * + * @private + * @param {Object} source The object to copy properties from. + * @param {Array} props The property identifiers to copy. + * @param {Object} [object={}] The object to copy properties to. + * @param {Function} [customizer] The function to customize copied values. + * @returns {Object} Returns `object`. + */ +function copyObject(source, props, object, customizer) { + var isNew = !object; + object || (object = {}); + + var index = -1, + length = props.length; + + while (++index < length) { + var key = props[index]; + + var newValue = customizer + ? customizer(object[key], source[key], key, object, source) + : undefined; + + if (newValue === undefined) { + newValue = source[key]; + } + if (isNew) { + baseAssignValue(object, key, newValue); + } else { + assignValue(object, key, newValue); + } + } + return object; +} + +/** + * This function is like + * [`Object.keys`](http://ecma-international.org/ecma-262/7.0/#sec-object.keys) + * except that it includes inherited enumerable properties. + * + * @private + * @param {Object} object The object to query. + * @returns {Array} Returns the array of property names. + */ +function nativeKeysIn(object) { + var result = []; + if (object != null) { + for (var key in Object(object)) { + result.push(key); + } + } + return result; +} + +/** Used for built-in method references. */ +var objectProto$e = Object.prototype; + +/** Used to check objects for own properties. */ +var hasOwnProperty$b = objectProto$e.hasOwnProperty; + +/** + * The base implementation of `_.keysIn` which doesn't treat sparse arrays as dense. + * + * @private + * @param {Object} object The object to query. + * @returns {Array} Returns the array of property names. + */ +function baseKeysIn(object) { + if (!isObject(object)) { + return nativeKeysIn(object); + } + var isProto = isPrototype(object), + result = []; + + for (var key in object) { + if (!(key == 'constructor' && (isProto || !hasOwnProperty$b.call(object, key)))) { + result.push(key); + } + } + return result; +} + +/** + * Creates an array of the own and inherited enumerable property names of `object`. + * + * **Note:** Non-object values are coerced to objects. + * + * @static + * @memberOf _ + * @since 3.0.0 + * @category Object + * @param {Object} object The object to query. + * @returns {Array} Returns the array of property names. + * @example + * + * function Foo() { + * this.a = 1; + * this.b = 2; + * } + * + * Foo.prototype.c = 3; + * + * _.keysIn(new Foo); + * // => ['a', 'b', 'c'] (iteration order is not guaranteed) + */ +function keysIn(object) { + return isArrayLike$1(object) ? arrayLikeKeys(object, true) : baseKeysIn(object); +} + +/** + * Converts `value` to a plain object flattening inherited enumerable string + * keyed properties of `value` to own properties of the plain object. + * + * @static + * @memberOf _ + * @since 3.0.0 + * @category Lang + * @param {*} value The value to convert. + * @returns {Object} Returns the converted plain object. + * @example + * + * function Foo() { + * this.b = 2; + * } + * + * Foo.prototype.c = 3; + * + * _.assign({ 'a': 1 }, new Foo); + * // => { 'a': 1, 'b': 2 } + * + * _.assign({ 'a': 1 }, _.toPlainObject(new Foo)); + * // => { 'a': 1, 'b': 2, 'c': 3 } + */ +function toPlainObject(value) { + return copyObject(value, keysIn(value)); +} + +/** + * A specialized version of `baseMerge` for arrays and objects which performs + * deep merges and tracks traversed objects enabling objects with circular + * references to be merged. + * + * @private + * @param {Object} object The destination object. + * @param {Object} source The source object. + * @param {string} key The key of the value to merge. + * @param {number} srcIndex The index of `source`. + * @param {Function} mergeFunc The function to merge values. + * @param {Function} [customizer] The function to customize assigned values. + * @param {Object} [stack] Tracks traversed source values and their merged + * counterparts. + */ +function baseMergeDeep(object, source, key, srcIndex, mergeFunc, customizer, stack) { + var objValue = safeGet(object, key), + srcValue = safeGet(source, key), + stacked = stack.get(srcValue); + + if (stacked) { + assignMergeValue(object, key, stacked); + return; + } + var newValue = customizer + ? customizer(objValue, srcValue, (key + ''), object, source, stack) + : undefined; + + var isCommon = newValue === undefined; + + if (isCommon) { + var isArr = isArray(srcValue), + isBuff = !isArr && isBuffer(srcValue), + isTyped = !isArr && !isBuff && isTypedArray(srcValue); + + newValue = srcValue; + if (isArr || isBuff || isTyped) { + if (isArray(objValue)) { + newValue = objValue; + } + else if (isArrayLikeObject(objValue)) { + newValue = copyArray(objValue); + } + else if (isBuff) { + isCommon = false; + newValue = cloneBuffer(srcValue, true); + } + else if (isTyped) { + isCommon = false; + newValue = cloneTypedArray(srcValue, true); + } + else { + newValue = []; + } + } + else if (isPlainObject(srcValue) || isArguments(srcValue)) { + newValue = objValue; + if (isArguments(objValue)) { + newValue = toPlainObject(objValue); + } + else if (!isObject(objValue) || isFunction(objValue)) { + newValue = initCloneObject(srcValue); + } + } + else { + isCommon = false; + } + } + if (isCommon) { + // Recursively merge objects and arrays (susceptible to call stack limits). + stack.set(srcValue, newValue); + mergeFunc(newValue, srcValue, srcIndex, customizer, stack); + stack['delete'](srcValue); + } + assignMergeValue(object, key, newValue); +} + +/** + * The base implementation of `_.merge` without support for multiple sources. + * + * @private + * @param {Object} object The destination object. + * @param {Object} source The source object. + * @param {number} srcIndex The index of `source`. + * @param {Function} [customizer] The function to customize merged values. + * @param {Object} [stack] Tracks traversed source values and their merged + * counterparts. + */ +function baseMerge(object, source, srcIndex, customizer, stack) { + if (object === source) { + return; + } + baseFor(source, function(srcValue, key) { + stack || (stack = new Stack); + if (isObject(srcValue)) { + baseMergeDeep(object, source, key, srcIndex, baseMerge, customizer, stack); + } + else { + var newValue = customizer + ? customizer(safeGet(object, key), srcValue, (key + ''), object, source, stack) + : undefined; + + if (newValue === undefined) { + newValue = srcValue; + } + assignMergeValue(object, key, newValue); + } + }, keysIn); +} + +/** + * A faster alternative to `Function#apply`, this function invokes `func` + * with the `this` binding of `thisArg` and the arguments of `args`. + * + * @private + * @param {Function} func The function to invoke. + * @param {*} thisArg The `this` binding of `func`. + * @param {Array} args The arguments to invoke `func` with. + * @returns {*} Returns the result of `func`. + */ +function apply(func, thisArg, args) { + switch (args.length) { + case 0: return func.call(thisArg); + case 1: return func.call(thisArg, args[0]); + case 2: return func.call(thisArg, args[0], args[1]); + case 3: return func.call(thisArg, args[0], args[1], args[2]); + } + return func.apply(thisArg, args); +} + +/* Built-in method references for those with the same name as other `lodash` methods. */ +var nativeMax = Math.max; + +/** + * A specialized version of `baseRest` which transforms the rest array. + * + * @private + * @param {Function} func The function to apply a rest parameter to. + * @param {number} [start=func.length-1] The start position of the rest parameter. + * @param {Function} transform The rest array transform. + * @returns {Function} Returns the new function. + */ +function overRest(func, start, transform) { + start = nativeMax(start === undefined ? (func.length - 1) : start, 0); + return function() { + var args = arguments, + index = -1, + length = nativeMax(args.length - start, 0), + array = Array(length); + + while (++index < length) { + array[index] = args[start + index]; + } + index = -1; + var otherArgs = Array(start + 1); + while (++index < start) { + otherArgs[index] = args[index]; + } + otherArgs[start] = transform(array); + return apply(func, this, otherArgs); + }; +} + +/** + * Creates a function that returns `value`. + * + * @static + * @memberOf _ + * @since 2.4.0 + * @category Util + * @param {*} value The value to return from the new function. + * @returns {Function} Returns the new constant function. + * @example + * + * var objects = _.times(2, _.constant({ 'a': 1 })); + * + * console.log(objects); + * // => [{ 'a': 1 }, { 'a': 1 }] + * + * console.log(objects[0] === objects[1]); + * // => true + */ +function constant(value) { + return function() { + return value; + }; +} + +/** + * The base implementation of `setToString` without support for hot loop shorting. + * + * @private + * @param {Function} func The function to modify. + * @param {Function} string The `toString` result. + * @returns {Function} Returns `func`. + */ +var baseSetToString = !defineProperty ? identity : function(func, string) { + return defineProperty(func, 'toString', { + 'configurable': true, + 'enumerable': false, + 'value': constant(string), + 'writable': true + }); +}; + +/** Used to detect hot functions by number of calls within a span of milliseconds. */ +var HOT_COUNT = 800, + HOT_SPAN = 16; + +/* Built-in method references for those with the same name as other `lodash` methods. */ +var nativeNow = Date.now; + +/** + * Creates a function that'll short out and invoke `identity` instead + * of `func` when it's called `HOT_COUNT` or more times in `HOT_SPAN` + * milliseconds. + * + * @private + * @param {Function} func The function to restrict. + * @returns {Function} Returns the new shortable function. + */ +function shortOut(func) { + var count = 0, + lastCalled = 0; + + return function() { + var stamp = nativeNow(), + remaining = HOT_SPAN - (stamp - lastCalled); + + lastCalled = stamp; + if (remaining > 0) { + if (++count >= HOT_COUNT) { + return arguments[0]; + } + } else { + count = 0; + } + return func.apply(undefined, arguments); + }; +} + +/** + * Sets the `toString` method of `func` to return `string`. + * + * @private + * @param {Function} func The function to modify. + * @param {Function} string The `toString` result. + * @returns {Function} Returns `func`. + */ +var setToString = shortOut(baseSetToString); + +/** + * The base implementation of `_.rest` which doesn't validate or coerce arguments. + * + * @private + * @param {Function} func The function to apply a rest parameter to. + * @param {number} [start=func.length-1] The start position of the rest parameter. + * @returns {Function} Returns the new function. + */ +function baseRest(func, start) { + return setToString(overRest(func, start, identity), func + ''); +} + +/** + * Checks if the given arguments are from an iteratee call. + * + * @private + * @param {*} value The potential iteratee value argument. + * @param {*} index The potential iteratee index or key argument. + * @param {*} object The potential iteratee object argument. + * @returns {boolean} Returns `true` if the arguments are from an iteratee call, + * else `false`. + */ +function isIterateeCall(value, index, object) { + if (!isObject(object)) { + return false; + } + var type = typeof index; + if (type == 'number' + ? (isArrayLike$1(object) && isIndex(index, object.length)) + : (type == 'string' && index in object) + ) { + return eq(object[index], value); + } + return false; +} + +/** + * Creates a function like `_.assign`. + * + * @private + * @param {Function} assigner The function to assign values. + * @returns {Function} Returns the new assigner function. + */ +function createAssigner(assigner) { + return baseRest(function(object, sources) { + var index = -1, + length = sources.length, + customizer = length > 1 ? sources[length - 1] : undefined, + guard = length > 2 ? sources[2] : undefined; + + customizer = (assigner.length > 3 && typeof customizer == 'function') + ? (length--, customizer) + : undefined; + + if (guard && isIterateeCall(sources[0], sources[1], guard)) { + customizer = length < 3 ? undefined : customizer; + length = 1; + } + object = Object(object); + while (++index < length) { + var source = sources[index]; + if (source) { + assigner(object, source, index, customizer); + } + } + return object; + }); +} + +/** + * This method is like `_.assign` except that it recursively merges own and + * inherited enumerable string keyed properties of source objects into the + * destination object. Source properties that resolve to `undefined` are + * skipped if a destination value exists. Array and plain object properties + * are merged recursively. Other objects and value types are overridden by + * assignment. Source objects are applied from left to right. Subsequent + * sources overwrite property assignments of previous sources. + * + * **Note:** This method mutates `object`. + * + * @static + * @memberOf _ + * @since 0.5.0 + * @category Object + * @param {Object} object The destination object. + * @param {...Object} [sources] The source objects. + * @returns {Object} Returns `object`. + * @example + * + * var object = { + * 'a': [{ 'b': 2 }, { 'd': 4 }] + * }; + * + * var other = { + * 'a': [{ 'c': 3 }, { 'e': 5 }] + * }; + * + * _.merge(object, other); + * // => { 'a': [{ 'b': 2, 'c': 3 }, { 'd': 4, 'e': 5 }] } + */ +var merge = createAssigner(function(object, source, srcIndex) { + baseMerge(object, source, srcIndex); +}); + +/** + * Creates an object with the same keys as `object` and values generated + * by running each own enumerable string keyed property of `object` thru + * `iteratee`. The iteratee is invoked with three arguments: + * (value, key, object). + * + * @static + * @memberOf _ + * @since 2.4.0 + * @category Object + * @param {Object} object The object to iterate over. + * @param {Function} [iteratee=_.identity] The function invoked per iteration. + * @returns {Object} Returns the new mapped object. + * @see _.mapKeys + * @example + * + * var users = { + * 'fred': { 'user': 'fred', 'age': 40 }, + * 'pebbles': { 'user': 'pebbles', 'age': 1 } + * }; + * + * _.mapValues(users, function(o) { return o.age; }); + * // => { 'fred': 40, 'pebbles': 1 } (iteration order is not guaranteed) + * + * // The `_.property` iteratee shorthand. + * _.mapValues(users, 'age'); + * // => { 'fred': 40, 'pebbles': 1 } (iteration order is not guaranteed) + */ +function mapValues(object, iteratee) { + var result = {}; + iteratee = baseIteratee(iteratee); + + baseForOwn(object, function(value, key, object) { + baseAssignValue(result, key, iteratee(value, key, object)); + }); + return result; +} + +/** + * The opposite of `_.mapValues`; this method creates an object with the + * same values as `object` and keys generated by running each own enumerable + * string keyed property of `object` thru `iteratee`. The iteratee is invoked + * with three arguments: (value, key, object). + * + * @static + * @memberOf _ + * @since 3.8.0 + * @category Object + * @param {Object} object The object to iterate over. + * @param {Function} [iteratee=_.identity] The function invoked per iteration. + * @returns {Object} Returns the new mapped object. + * @see _.mapValues + * @example + * + * _.mapKeys({ 'a': 1, 'b': 2 }, function(value, key) { + * return key + value; + * }); + * // => { 'a1': 1, 'b2': 2 } + */ +function mapKeys(object, iteratee) { + var result = {}; + iteratee = baseIteratee(iteratee); + + baseForOwn(object, function(value, key, object) { + baseAssignValue(result, iteratee(value, key, object), value); + }); + return result; +} + +/** Error message constants. */ +var FUNC_ERROR_TEXT$1 = 'Expected a function'; + +/** + * Creates a function that negates the result of the predicate `func`. The + * `func` predicate is invoked with the `this` binding and arguments of the + * created function. + * + * @static + * @memberOf _ + * @since 3.0.0 + * @category Function + * @param {Function} predicate The predicate to negate. + * @returns {Function} Returns the new negated function. + * @example + * + * function isEven(n) { + * return n % 2 == 0; + * } + * + * _.filter([1, 2, 3, 4, 5, 6], _.negate(isEven)); + * // => [1, 3, 5] + */ +function negate(predicate) { + if (typeof predicate != 'function') { + throw new TypeError(FUNC_ERROR_TEXT$1); + } + return function() { + var args = arguments; + switch (args.length) { + case 0: return !predicate.call(this); + case 1: return !predicate.call(this, args[0]); + case 2: return !predicate.call(this, args[0], args[1]); + case 3: return !predicate.call(this, args[0], args[1], args[2]); + } + return !predicate.apply(this, args); + }; +} + +/** + * The base implementation of `_.set`. + * + * @private + * @param {Object} object The object to modify. + * @param {Array|string} path The path of the property to set. + * @param {*} value The value to set. + * @param {Function} [customizer] The function to customize path creation. + * @returns {Object} Returns `object`. + */ +function baseSet(object, path, value, customizer) { + if (!isObject(object)) { + return object; + } + path = castPath(path, object); + + var index = -1, + length = path.length, + lastIndex = length - 1, + nested = object; + + while (nested != null && ++index < length) { + var key = toKey(path[index]), + newValue = value; + + if (index != lastIndex) { + var objValue = nested[key]; + newValue = customizer ? customizer(objValue, key, nested) : undefined; + if (newValue === undefined) { + newValue = isObject(objValue) + ? objValue + : (isIndex(path[index + 1]) ? [] : {}); + } + } + assignValue(nested, key, newValue); + nested = nested[key]; + } + return object; +} + +/** + * The base implementation of `_.pickBy` without support for iteratee shorthands. + * + * @private + * @param {Object} object The source object. + * @param {string[]} paths The property paths to pick. + * @param {Function} predicate The function invoked per property. + * @returns {Object} Returns the new object. + */ +function basePickBy(object, paths, predicate) { + var index = -1, + length = paths.length, + result = {}; + + while (++index < length) { + var path = paths[index], + value = baseGet(object, path); + + if (predicate(value, path)) { + baseSet(result, castPath(path, object), value); + } + } + return result; +} + +/* Built-in method references for those with the same name as other `lodash` methods. */ +var nativeGetSymbols$1 = Object.getOwnPropertySymbols; + +/** + * Creates an array of the own and inherited enumerable symbols of `object`. + * + * @private + * @param {Object} object The object to query. + * @returns {Array} Returns the array of symbols. + */ +var getSymbolsIn = !nativeGetSymbols$1 ? stubArray : function(object) { + var result = []; + while (object) { + arrayPush(result, getSymbols(object)); + object = getPrototype(object); + } + return result; +}; + +/** + * Creates an array of own and inherited enumerable property names and + * symbols of `object`. + * + * @private + * @param {Object} object The object to query. + * @returns {Array} Returns the array of property names and symbols. + */ +function getAllKeysIn(object) { + return baseGetAllKeys(object, keysIn, getSymbolsIn); +} + +/** + * Creates an object composed of the `object` properties `predicate` returns + * truthy for. The predicate is invoked with two arguments: (value, key). + * + * @static + * @memberOf _ + * @since 4.0.0 + * @category Object + * @param {Object} object The source object. + * @param {Function} [predicate=_.identity] The function invoked per property. + * @returns {Object} Returns the new object. + * @example + * + * var object = { 'a': 1, 'b': '2', 'c': 3 }; + * + * _.pickBy(object, _.isNumber); + * // => { 'a': 1, 'c': 3 } + */ +function pickBy(object, predicate) { + if (object == null) { + return {}; + } + var props = arrayMap(getAllKeysIn(object), function(prop) { + return [prop]; + }); + predicate = baseIteratee(predicate); + return basePickBy(object, props, function(value, path) { + return predicate(value, path[0]); + }); +} + +/** + * The opposite of `_.pickBy`; this method creates an object composed of + * the own and inherited enumerable string keyed properties of `object` that + * `predicate` doesn't return truthy for. The predicate is invoked with two + * arguments: (value, key). + * + * @static + * @memberOf _ + * @since 4.0.0 + * @category Object + * @param {Object} object The source object. + * @param {Function} [predicate=_.identity] The function invoked per property. + * @returns {Object} Returns the new object. + * @example + * + * var object = { 'a': 1, 'b': '2', 'c': 3 }; + * + * _.omitBy(object, _.isNumber); + * // => { 'b': '2' } + */ +function omitBy(object, predicate) { + return pickBy(object, negate(baseIteratee(predicate))); +} + +/** + * Performs a deep comparison between two values to determine if they are + * equivalent. + * + * **Note:** This method supports comparing arrays, array buffers, booleans, + * date objects, error objects, maps, numbers, `Object` objects, regexes, + * sets, strings, symbols, and typed arrays. `Object` objects are compared + * by their own, not inherited, enumerable properties. Functions and DOM + * nodes are compared by strict equality, i.e. `===`. + * + * @static + * @memberOf _ + * @since 0.1.0 + * @category Lang + * @param {*} value The value to compare. + * @param {*} other The other value to compare. + * @returns {boolean} Returns `true` if the values are equivalent, else `false`. + * @example + * + * var object = { 'a': 1 }; + * var other = { 'a': 1 }; + * + * _.isEqual(object, other); + * // => true + * + * object === other; + * // => false + */ +function isEqual(value, other) { + return baseIsEqual(value, other); +} + +/** + * The base implementation of methods like `_.findKey` and `_.findLastKey`, + * without support for iteratee shorthands, which iterates over `collection` + * using `eachFunc`. + * + * @private + * @param {Array|Object} collection The collection to inspect. + * @param {Function} predicate The function invoked per iteration. + * @param {Function} eachFunc The function to iterate over `collection`. + * @returns {*} Returns the found element or its key, else `undefined`. + */ +function baseFindKey(collection, predicate, eachFunc) { + var result; + eachFunc(collection, function(value, key, collection) { + if (predicate(value, key, collection)) { + result = key; + return false; + } + }); + return result; +} + +/** + * This method is like `_.find` except that it returns the key of the first + * element `predicate` returns truthy for instead of the element itself. + * + * @static + * @memberOf _ + * @since 1.1.0 + * @category Object + * @param {Object} object The object to inspect. + * @param {Function} [predicate=_.identity] The function invoked per iteration. + * @returns {string|undefined} Returns the key of the matched element, + * else `undefined`. + * @example + * + * var users = { + * 'barney': { 'age': 36, 'active': true }, + * 'fred': { 'age': 40, 'active': false }, + * 'pebbles': { 'age': 1, 'active': true } + * }; + * + * _.findKey(users, function(o) { return o.age < 40; }); + * // => 'barney' (iteration order is not guaranteed) + * + * // The `_.matches` iteratee shorthand. + * _.findKey(users, { 'age': 1, 'active': true }); + * // => 'pebbles' + * + * // The `_.matchesProperty` iteratee shorthand. + * _.findKey(users, ['active', false]); + * // => 'fred' + * + * // The `_.property` iteratee shorthand. + * _.findKey(users, 'active'); + * // => 'barney' + */ +function findKey(object, predicate) { + return baseFindKey(object, baseIteratee(predicate), baseForOwn); +} + +/** + * @param {array} arr Array for check + * @param {*} value target + * @return {boolean} true on successs + */ +var isInArray = function(arr, value) { + return !!arr.filter(function (a) { return a === value; }).length +}; + +var isObjectHasKey = function(obj, key) { + var keys = Object.keys(obj); + return isInArray(keys, key) +}; + +// just not to make my head hurt +var isEmpty = function (value) { return !isNotEmpty(value); }; + +/** + * Map the alias to their key then grab their value over + * @param {object} config the user supplied config + * @param {object} appProps the default option map + * @return {object} the config keys replaced with the appProps key by the ALIAS + */ +function mapAliasConfigKeys(config, appProps) { + // need to do two steps + // 1. take key with alias key + var aliasMap = omitBy(appProps, function (value, k) { return !value[ALIAS_KEY$1]; } ); + if (isEqual(aliasMap, {})) { + return config; + } + return mapKeys(config, function (v, key) { return findKey(aliasMap, function (o) { return o.alias === key; }) || key; }) +} + +/** + * We only want to run the valdiation against the config (user supplied) value + * but keep the defaultOptions untouch + * @param {object} config configuraton supplied by user + * @param {object} appProps the default options map + * @return {object} the pristine values that will add back to the final output + */ +function preservePristineValues(config, appProps) { + // @BUG this will filter out those that is alias key + // we need to first map the alias keys back to their full key + var _config = mapAliasConfigKeys(config, appProps); + // take the default value out + var pristineValues = mapValues( + omitBy(appProps, function (value, key) { return isObjectHasKey(_config, key); }), + function (value) { return value.args; } + ); + // for testing the value + var checkAgainstAppProps = omitBy(appProps, function (value, key) { return !isObjectHasKey(_config, key); }); + // output + return { + pristineValues: pristineValues, + checkAgainstAppProps: checkAgainstAppProps, + config: _config // passing this correct values back + } +} + +/** + * This will take the value that is ONLY need to check + * @param {object} config that one + * @param {object} props map for creating checking + * @return {object} put that arg into the args + */ +function processConfigAction(config, props) { + // debugFn('processConfigAction', props) + // v.1.2.0 add checking if its mark optional and the value is empty then pass + return mapValues(props, function (value, key) { + var obj, obj$1; + + return ( + config[key] === undefined || (value[OPTIONAL_KEY$1] === true && isEmpty(config[key])) + ? merge({}, value, ( obj = {}, obj[KEY_WORD$1] = true, obj )) + : ( obj$1 = {}, obj$1[ARGS_KEY$1] = config[key], obj$1[TYPE_KEY$1] = value[TYPE_KEY$1], obj$1[OPTIONAL_KEY$1] = value[OPTIONAL_KEY$1] || false, obj$1[ENUM_KEY$1] = value[ENUM_KEY$1] || false, obj$1[CHECKER_KEY$1] = value[CHECKER_KEY$1] || false, obj$1 ) + ); + } + ) +} + +/** + * Quick transform + * @TODO we should only validate those that is pass from the config + * and pass through those values that is from the defaultOptions + * @param {object} opts that one + * @param {object} appProps mutation configuration options + * @return {object} put that arg into the args + */ +function prepareArgsForValidation(opts, appProps) { + var ref = preservePristineValues(opts, appProps); + var config = ref.config; + var pristineValues = ref.pristineValues; + var checkAgainstAppProps = ref.checkAgainstAppProps; + // output + return [ + processConfigAction(config, checkAgainstAppProps), + pristineValues + ] +} + +// this get throw from within the checkOptions when run through the enum failed +var JsonqlEnumError = /*@__PURE__*/(function (Error) { + function JsonqlEnumError() { + var args = [], len = arguments.length; + while ( len-- ) args[ len ] = arguments[ len ]; + + Error.apply(this, args); + + this.message = args[0]; + this.detail = args[1]; + + this.className = JsonqlEnumError.name; + + if (Error.captureStackTrace) { + Error.captureStackTrace(this, JsonqlEnumError); + } + } + + if ( Error ) JsonqlEnumError.__proto__ = Error; + JsonqlEnumError.prototype = Object.create( Error && Error.prototype ); + JsonqlEnumError.prototype.constructor = JsonqlEnumError; + + var staticAccessors = { name: { configurable: true } }; + + staticAccessors.name.get = function () { + return 'JsonqlEnumError'; + }; + + Object.defineProperties( JsonqlEnumError, staticAccessors ); + + return JsonqlEnumError; +}(Error)); + +// this will throw from inside the checkOptions +var JsonqlTypeError = /*@__PURE__*/(function (Error) { + function JsonqlTypeError() { + var args = [], len = arguments.length; + while ( len-- ) args[ len ] = arguments[ len ]; + + Error.apply(this, args); + + this.message = args[0]; + this.detail = args[1]; + + this.className = JsonqlTypeError.name; + + if (Error.captureStackTrace) { + Error.captureStackTrace(this, JsonqlTypeError); + } + } + + if ( Error ) JsonqlTypeError.__proto__ = Error; + JsonqlTypeError.prototype = Object.create( Error && Error.prototype ); + JsonqlTypeError.prototype.constructor = JsonqlTypeError; + + var staticAccessors = { name: { configurable: true } }; + + staticAccessors.name.get = function () { + return 'JsonqlTypeError'; + }; + + Object.defineProperties( JsonqlTypeError, staticAccessors ); + + return JsonqlTypeError; +}(Error)); + +// allow supply a custom checker function +// if that failed then we throw this error +var JsonqlCheckerError = /*@__PURE__*/(function (Error) { + function JsonqlCheckerError() { + var args = [], len = arguments.length; + while ( len-- ) args[ len ] = arguments[ len ]; + + Error.apply(this, args); + this.message = args[0]; + this.detail = args[1]; + + this.className = JsonqlCheckerError.name; + + if (Error.captureStackTrace) { + Error.captureStackTrace(this, JsonqlCheckerError); + } + } + + if ( Error ) JsonqlCheckerError.__proto__ = Error; + JsonqlCheckerError.prototype = Object.create( Error && Error.prototype ); + JsonqlCheckerError.prototype.constructor = JsonqlCheckerError; + + var staticAccessors = { name: { configurable: true } }; + + staticAccessors.name.get = function () { + return 'JsonqlCheckerError'; + }; + + Object.defineProperties( JsonqlCheckerError, staticAccessors ); + + return JsonqlCheckerError; +}(Error)); + +// breaking the whole thing up to see what cause the multiple calls issue + +// import debug from 'debug'; +// const debugFn = debug('jsonql-params-validator:options:validation') + +/** + * just make sure it returns an array to use + * @param {*} arg input + * @return {array} output + */ +var toArray = function (arg) { return checkIsArray(arg) ? arg : [arg]; }; + +/** + * DIY in array + * @param {array} arr to check against + * @param {*} value to check + * @return {boolean} true on OK + */ +var inArray = function (arr, value) { return ( + !!arr.filter(function (v) { return v === value; }).length +); }; + +/** + * break out to make the code easier to read + * @param {object} value to process + * @param {function} cb the validateSync + * @return {array} empty on success + */ +function validateHandler$1(value, cb) { + var obj; + + // cb is the validateSync methods + var args = [ + [ value[ARGS_KEY$1] ], + [( obj = {}, obj[TYPE_KEY$1] = toArray(value[TYPE_KEY$1]), obj[OPTIONAL_KEY$1] = value[OPTIONAL_KEY$1], obj )] + ]; + // debugFn('validateHandler', args) + return Reflect.apply(cb, null, args) +} + +/** + * Check against the enum value if it's provided + * @param {*} value to check + * @param {*} enumv to check against if it's not false + * @return {boolean} true on OK + */ +var enumHandler = function (value, enumv) { + if (checkIsArray(enumv)) { + return inArray(enumv, value) + } + return true +}; + +/** + * Allow passing a function to check the value + * There might be a problem here if the function is incorrect + * and that will makes it hard to debug what is going on inside + * @TODO there could be a few feature add to this one under different circumstance + * @param {*} value to check + * @param {function} checker for checking + */ +var checkerHandler = function (value, checker) { + try { + return isFunction(checker) ? checker.apply(null, [value]) : false + } catch (e) { + return false + } +}; + +/** + * Taken out from the runValidaton this only validate the required values + * @param {array} args from the config2argsAction + * @param {function} cb validateSync + * @return {array} of configuration values + */ +function runValidationAction(cb) { + return function (value, key) { + // debugFn('runValidationAction', key, value) + if (value[KEY_WORD$1]) { + return value[ARGS_KEY$1] + } + var check = validateHandler$1(value, cb); + if (check.length) { + // log('runValidationAction', key, value) + throw new JsonqlTypeError(key, check) + } + if (value[ENUM_KEY$1] !== false && !enumHandler(value[ARGS_KEY$1], value[ENUM_KEY$1])) { + // log(ENUM_KEY, value[ENUM_KEY]) + throw new JsonqlEnumError(key) + } + if (value[CHECKER_KEY$1] !== false && !checkerHandler(value[ARGS_KEY$1], value[CHECKER_KEY$1])) { + // log(CHECKER_KEY, value[CHECKER_KEY]) + throw new JsonqlCheckerError(key) + } + return value[ARGS_KEY$1] + } +} + +/** + * @param {object} args from the config2argsAction + * @param {function} cb validateSync + * @return {object} of configuration values + */ +function runValidation(args, cb) { + var argsForValidate = args[0]; + var pristineValues = args[1]; + // turn the thing into an array and see what happen here + // debugFn('_args', argsForValidate) + var result = mapValues(argsForValidate, runValidationAction(cb)); + return merge(result, pristineValues) +} + +/// this is port back from the client to share across all projects + +// import debug from 'debug' +// const debugFn = debug('jsonql-params-validator:check-options-async') + +/** + * Quick transform + * @param {object} config that one + * @param {object} appProps mutation configuration options + * @return {object} put that arg into the args + */ +var configToArgs = function (config, appProps) { + return Promise.resolve( + prepareArgsForValidation(config, appProps) + ) +}; + +/** + * @param {object} config user provide configuration option + * @param {object} appProps mutation configuration options + * @param {object} constProps the immutable configuration options + * @param {function} cb the validateSync method + * @return {object} Promise resolve merge config object + */ +function checkOptionsAsync(config, appProps, constProps, cb) { + if ( config === void 0 ) config = {}; + + return configToArgs(config, appProps) + .then(function (args1) { return runValidation(args1, cb); }) + // next if every thing good then pass to final merging + .then(function (args2) { return merge({}, args2, constProps); }) +} + +// this is port back from the client to share across all projects + +/** + * @param {object} config user provide configuration option + * @param {object} appProps mutation configuration options + * @param {object} constProps the immutable configuration options + * @param {function} cb the validateSync method + * @return {object} Promise resolve merge config object + */ +function checkOptionsSync(config, appProps, constProps, cb) { + if ( config === void 0 ) config = {}; + + return merge( + runValidation( + prepareArgsForValidation(config, appProps), + cb + ), + constProps + ) +} + +// create function to construct the config entry so we don't need to keep building object +// import checkIsBoolean from '../boolean' +// import debug from 'debug'; +// const debugFn = debug('jsonql-params-validator:construct-config'); +/** + * @param {*} args value + * @param {string} type for value + * @param {boolean} [optional=false] + * @param {boolean|array} [enumv=false] + * @param {boolean|function} [checker=false] + * @return {object} config entry + */ +function constructConfig(args, type, optional, enumv, checker, alias) { + if ( optional === void 0 ) optional=false; + if ( enumv === void 0 ) enumv=false; + if ( checker === void 0 ) checker=false; + if ( alias === void 0 ) alias=false; + + var base = {}; + base[ARGS_KEY] = args; + base[TYPE_KEY] = type; + if (optional === true) { + base[OPTIONAL_KEY] = true; + } + if (checkIsArray(enumv)) { + base[ENUM_KEY] = enumv; + } + if (isFunction(checker)) { + base[CHECKER_KEY] = checker; + } + if (isString(alias)) { + base[ALIAS_KEY] = alias; + } + return base +} + +// export also create wrapper methods + +/** + * This has a different interface + * @param {*} value to supply + * @param {string|array} type for checking + * @param {object} params to map against the config check + * @param {array} params.enumv NOT enum + * @param {boolean} params.optional false then nothing + * @param {function} params.checker need more work on this one later + * @param {string} params.alias mostly for cmd + */ +var createConfig = function (value, type, params) { + if ( params === void 0 ) params = {}; + + // Note the enumv not ENUM + // const { enumv, optional, checker, alias } = params; + // let args = [value, type, optional, enumv, checker, alias]; + var o = params[OPTIONAL_KEY]; + var e = params[ENUM_KEY]; + var c = params[CHECKER_KEY]; + var a = params[ALIAS_KEY]; + return constructConfig.apply(null, [value, type, o, e, c, a]) +}; + +/** + * construct the actual end user method, rename with prefix get since 1.5.2 + * @param {function} validateSync validation method + * @return {function} for performaning the actual valdiation + */ +var getCheckConfigAsync = function(validateSync) { + /** + * We recreate the method here to avoid the circlar import + * @param {object} config user supply configuration + * @param {object} appProps mutation options + * @param {object} [constantProps={}] optional: immutation options + * @return {object} all checked configuration + */ + return function(config, appProps, constantProps) { + if ( constantProps === void 0 ) constantProps= {}; + + return checkOptionsAsync(config, appProps, constantProps, validateSync) + } +}; + +/** + * copy of above but it's sync, rename with prefix get since 1.5.2 + * @param {function} validateSync validation method + * @return {function} for performaning the actual valdiation + */ +var getCheckConfig = function(validateSync) { + return function(config, appProps, constantProps) { + if ( constantProps === void 0 ) constantProps = {}; + + return checkOptionsSync(config, appProps, constantProps, validateSync) + } +}; + +// export +var isString$1 = checkIsString; +var validateAsync$1 = validateAsync; + +var createConfig$1 = createConfig; +// construct the final output 1.5.2 +var checkConfigAsync = getCheckConfigAsync(validateSync); +var checkConfig = getCheckConfig(validateSync); + +// move the get logger stuff here + +// it does nothing +var dummyLogger = function () {}; + +/** + * re-use the debugOn prop to control this log method + * @param {object} opts configuration + * @return {function} the log function + */ +var getLogger = function (opts) { + var debugOn = opts.debugOn; + if (debugOn) { + return function () { + var args = [], len = arguments.length; + while ( len-- ) args[ len ] = arguments[ len ]; + + Reflect.apply(console.info, console, ['[jsonql-ws-client-core]' ].concat( args)); + } + } + return dummyLogger +}; + +/** + * Make sure there is a log method + * @param {object} opts configuration + * @return {object} opts + */ +var getLogFn = function (opts) { + var log = opts.log; // 1.3.9 if we pass a log method here then we use this + if (!log || typeof log !== 'function') { + return getLogger(opts) + } + opts.log('---> getLogFn user supplied log function <---', opts); + return log +}; + +// group all the repetitive message here + +var TAKEN_BY_OTHER_TYPE_ERR = 'You are trying to register an event already been taken by other type:'; + +// Create two WeakMap store as a private keys +var NB_EVENT_SERVICE_PRIVATE_STORE = new WeakMap(); +var NB_EVENT_SERVICE_PRIVATE_LAZY = new WeakMap(); + +/** + * generate a 32bit hash based on the function.toString() + * _from http://stackoverflow.com/questions/7616461/generate-a-hash-_from-string-in-javascript-jquery + * @param {string} s the converted to string function + * @return {string} the hashed function string + */ +function hashCode(s) { + return s.split("").reduce(function(a,b){a=((a<<5)-a)+b.charCodeAt(0);return a&a},0) +} + +/** + * wrapper to make sure it string + * @param {*} input whatever + * @return {string} output + */ +function hashCode2Str(s) { + return hashCode(s) + '' +} + +/** + * Just check if a pattern is an RegExp object + * @param {*} pat whatever + * @return {boolean} false when its not + */ +function isRegExp(pat) { + return pat instanceof RegExp +} + +/** + * check if its string + * @param {*} arg whatever + * @return {boolean} false when it's not + */ +function isString$2(arg) { + return typeof arg === 'string' +} + +/** + * Find from the array by matching the pattern + * @param {*} pattern a string or RegExp object + * @return {object} regex object or false when we can not id the input + */ +function getRegex(pattern) { + switch (true) { + case isRegExp(pattern) === true: + return pattern + case isString$2(pattern) === true: + return new RegExp(pattern) + default: + return false + } +} + +// making all the functionality on it's own + +var SuspendClass = function SuspendClass() { + // suspend, release and queue + this.__suspend_state__ = null; + // to do this proper we don't use a new prop to hold the event name pattern + this.__pattern__ = null; + this.queueStore = new Set(); +}; + +var prototypeAccessors = { $queues: { configurable: true } }; + +/** + * start suspend + * @return {void} + */ +SuspendClass.prototype.$suspend = function $suspend () { + this.logger("---> SUSPEND ALL OPS <---"); + this.__suspend__(true); +}; + +/** + * release the queue + * @return {void} + */ +SuspendClass.prototype.$release = function $release () { + this.logger("---> RELEASE SUSPENDED QUEUE <---"); + this.__suspend__(false); +}; + +/** + * suspend event by pattern + * @param {string} pattern the pattern search matches the event name + * @return {void} + */ +SuspendClass.prototype.$suspendEvent = function $suspendEvent (pattern) { + var regex = getRegex(pattern); + if (isRegExp(regex)) { + this.__pattern__ = regex; + return this.$suspend() + } + throw new Error(("We expect a pattern variable to be string or RegExp, but we got \"" + (typeof regex) + "\" instead")) +}; + +/** + * queuing call up when it's in suspend mode + * @param {string} evt the event name + * @param {*} args unknown number of arguments + * @return {boolean} true when added or false when it's not + */ +SuspendClass.prototype.$queue = function $queue (evt) { + var args = [], len = arguments.length - 1; + while ( len-- > 0 ) args[ len ] = arguments[ len + 1 ]; + + this.logger('($queue) get called'); + if (this.__suspend_state__ === true) { + if (isRegExp(this.__pattern__)) { // it's better then check if its not null + // check the pattern and decide if we want to suspend it or not + var found = this.__pattern__.test(evt); + if (!found) { + return false + } + } + this.logger('($queue) added to $queue', args); + // @TODO there shouldn't be any duplicate, but how to make sure? + this.queueStore.add([evt].concat(args)); + // return this.queueStore.size + } + return !!this.__suspend_state__ +}; + +/** + * a getter to get all the store queue + * @return {array} Set turn into Array before return + */ +prototypeAccessors.$queues.get = function () { + var size = this.queueStore.size; + this.logger('($queues)', ("size: " + size)); + if (size > 0) { + return Array.from(this.queueStore) + } + return [] +}; + +/** + * to set the suspend and check if it's boolean value + * @param {boolean} value to trigger + */ +SuspendClass.prototype.__suspend__ = function __suspend__ (value) { + if (typeof value === 'boolean') { + var lastValue = this.__suspend_state__; + this.__suspend_state__ = value; + this.logger(("($suspend) Change from \"" + lastValue + "\" --> \"" + value + "\"")); + if (lastValue === true && value === false) { + this.__release__(); + } + } else { + throw new Error(("$suspend only accept Boolean value! we got " + (typeof value))) + } +}; + +/** + * Release the queue + * @return {int} size if any + */ +SuspendClass.prototype.__release__ = function __release__ () { + var this$1 = this; + + var size = this.queueStore.size; + var pattern = this.__pattern__; + this.__pattern__ = null; + this.logger(("(release) was called with " + size + (pattern ? ' for "' + pattern + '"': '') + " item" + (size > 1 ? 's' : ''))); + if (size > 0) { + var queue = Array.from(this.queueStore); + this.queueStore.clear(); + this.logger('(release queue)', queue); + queue.forEach(function (args) { + this$1.logger(args); + Reflect.apply(this$1.$trigger, this$1, args); + }); + this.logger(("Release size " + (this.queueStore.size))); + } + + return size +}; + +Object.defineProperties( SuspendClass.prototype, prototypeAccessors ); + +// break up the main file because its getting way too long + +var StoreService = /*@__PURE__*/(function (SuspendClass) { + function StoreService(config) { + if ( config === void 0 ) config = {}; + + SuspendClass.call(this); + if (config.logger && typeof config.logger === 'function') { + this.logger = config.logger; + } + this.keep = config.keep; + // for the $done setter + this.result = config.keep ? [] : null; + // we need to init the store first otherwise it could be a lot of checking later + this.normalStore = new Map(); + this.lazyStore = new Map(); + } + + if ( SuspendClass ) StoreService.__proto__ = SuspendClass; + StoreService.prototype = Object.create( SuspendClass && SuspendClass.prototype ); + StoreService.prototype.constructor = StoreService; + + var prototypeAccessors = { normalStore: { configurable: true },lazyStore: { configurable: true } }; + + /** + * validate the event name(s) + * @param {string[]} evt event name + * @return {boolean} true when OK + */ + StoreService.prototype.validateEvt = function validateEvt () { + var this$1 = this; + var evt = [], len = arguments.length; + while ( len-- ) evt[ len ] = arguments[ len ]; + + evt.forEach(function (e) { + if (!isString$2(e)) { + this$1.logger('(validateEvt)', e); + throw new Error(("Event name must be string type! we got " + (typeof e))) + } + }); + return true + }; + + /** + * Simple quick check on the two main parameters + * @param {string} evt event name + * @param {function} callback function to call + * @return {boolean} true when OK + */ + StoreService.prototype.validate = function validate (evt, callback) { + if (this.validateEvt(evt)) { + if (typeof callback === 'function') { + return true + } + } + throw new Error(("callback required to be function type! we got " + (typeof callback))) + }; + + /** + * Check if this type is correct or not added in V1.5.0 + * @param {string} type for checking + * @return {boolean} true on OK + */ + StoreService.prototype.validateType = function validateType (type) { + this.validateEvt(type); + var types = ['on', 'only', 'once', 'onlyOnce']; + return !!types.filter(function (t) { return type === t; }).length + }; + + /** + * Run the callback + * @param {function} callback function to execute + * @param {array} payload for callback + * @param {object} ctx context or null + * @return {void} the result store in $done + */ + StoreService.prototype.run = function run (callback, payload, ctx) { + this.logger('(run) callback:', callback, 'payload:', payload, 'context:', ctx); + this.$done = Reflect.apply(callback, ctx, this.toArray(payload)); + }; + + /** + * Take the content out and remove it from store id by the name + * @param {string} evt event name + * @param {string} [storeName = lazyStore] name of store + * @return {object|boolean} content or false on not found + */ + StoreService.prototype.takeFromStore = function takeFromStore (evt, storeName) { + if ( storeName === void 0 ) storeName = 'lazyStore'; + + var store = this[storeName]; // it could be empty at this point + if (store) { + this.logger('(takeFromStore)', storeName, store); + if (store.has(evt)) { + var content = store.get(evt); + this.logger(("(takeFromStore) has \"" + evt + "\""), content); + store.delete(evt); + return content + } + return false + } + throw new Error(("\"" + storeName + "\" is not supported!")) + }; + + /** + * This was part of the $get. We take it out + * so we could use a regex to remove more than one event + * @param {object} store the store to return from + * @param {string} evt event name + * @param {boolean} full return just the callback or everything + * @return {array|boolean} false when not found + */ + StoreService.prototype.findFromStore = function findFromStore (evt, store, full) { + if ( full === void 0 ) full = false; + + if (store.has(evt)) { + return Array + .from(store.get(evt)) + .map( function (l) { + if (full) { + return l + } + var key = l[0]; + var callback = l[1]; + return callback + }) + } + return false + }; + + /** + * Similar to the findFromStore, but remove + * @param {string} evt event name + * @param {object} store the store to remove from + * @return {boolean} false when not found + */ + StoreService.prototype.removeFromStore = function removeFromStore (evt, store) { + if (store.has(evt)) { + this.logger('($off)', evt); + store.delete(evt); + return true + } + return false + }; + + /** + * The add to store step is similar so make it generic for resuse + * @param {object} store which store to use + * @param {string} evt event name + * @param {spread} args because the lazy store and normal store store different things + * @return {array} store and the size of the store + */ + StoreService.prototype.addToStore = function addToStore (store, evt) { + var args = [], len = arguments.length - 2; + while ( len-- > 0 ) args[ len ] = arguments[ len + 2 ]; + + var fnSet; + if (store.has(evt)) { + this.logger(("(addToStore) \"" + evt + "\" existed")); + fnSet = store.get(evt); + } else { + this.logger(("(addToStore) create new Set for \"" + evt + "\"")); + // this is new + fnSet = new Set(); + } + // lazy only store 2 items - this is not the case in V1.6.0 anymore + // we need to check the first parameter is string or not + if (args.length > 2) { + if (Array.isArray(args[0])) { // lazy store + // check if this type of this event already register in the lazy store + var t = args[2]; + if (!this.checkTypeInLazyStore(evt, t)) { + fnSet.add(args); + } + } else { + if (!this.checkContentExist(args, fnSet)) { + this.logger("(addToStore) insert new", args); + fnSet.add(args); + } + } + } else { // add straight to lazy store + fnSet.add(args); + } + store.set(evt, fnSet); + return [store, fnSet.size] + }; + + /** + * @param {array} args for compare + * @param {object} fnSet A Set to search from + * @return {boolean} true on exist + */ + StoreService.prototype.checkContentExist = function checkContentExist (args, fnSet) { + var list = Array.from(fnSet); + return !!list.filter(function (li) { + var hash = li[0]; + return hash === args[0] + }).length + }; + + /** + * get the existing type to make sure no mix type add to the same store + * @param {string} evtName event name + * @param {string} type the type to check + * @return {boolean} true you can add, false then you can't add this type + */ + StoreService.prototype.checkTypeInStore = function checkTypeInStore (evtName, type) { + this.validateEvt(evtName, type); + var all = this.$get(evtName, true); + if (all === false) { + // pristine it means you can add + return true + } + // it should only have ONE type in ONE event store + return !all.filter(function (list) { + var t = list[3]; + return type !== t + }).length + }; + + /** + * This is checking just the lazy store because the structure is different + * therefore we need to use a new method to check it + */ + StoreService.prototype.checkTypeInLazyStore = function checkTypeInLazyStore (evtName, type) { + this.validateEvt(evtName, type); + var store = this.lazyStore.get(evtName); + this.logger('(checkTypeInLazyStore)', store); + if (store) { + return !!Array + .from(store) + .filter(function (li) { + var t = li[2]; + return t !== type + }).length + } + return false + }; + + /** + * wrapper to re-use the addToStore, + * V1.3.0 add extra check to see if this type can add to this evt + * @param {string} evt event name + * @param {string} type on or once + * @param {function} callback function + * @param {object} context the context the function execute in or null + * @return {number} size of the store + */ + StoreService.prototype.addToNormalStore = function addToNormalStore (evt, type, callback, context) { + if ( context === void 0 ) context = null; + + this.logger(("(addToNormalStore) try to add \"" + type + "\" --> \"" + evt + "\" to normal store")); + // @TODO we need to check the existing store for the type first! + if (this.checkTypeInStore(evt, type)) { + this.logger('(addToNormalStore)', ("\"" + type + "\" --> \"" + evt + "\" can add to normal store")); + var key = this.hashFnToKey(callback); + var args = [this.normalStore, evt, key, callback, context, type]; + var ref = Reflect.apply(this.addToStore, this, args); + var _store = ref[0]; + var size = ref[1]; + this.normalStore = _store; + return size + } + return false + }; + + /** + * Add to lazy store this get calls when the callback is not register yet + * so we only get a payload object or even nothing + * @param {string} evt event name + * @param {array} payload of arguments or empty if there is none + * @param {object} [context=null] the context the callback execute in + * @param {string} [type=false] register a type so no other type can add to this evt + * @return {number} size of the store + */ + StoreService.prototype.addToLazyStore = function addToLazyStore (evt, payload, context, type) { + if ( payload === void 0 ) payload = []; + if ( context === void 0 ) context = null; + if ( type === void 0 ) type = false; + + // this is add in V1.6.0 + // when there is type then we will need to check if this already added in lazy store + // and no other type can add to this lazy store + var args = [this.lazyStore, evt, this.toArray(payload), context]; + if (type) { + args.push(type); + } + var ref = Reflect.apply(this.addToStore, this, args); + var _store = ref[0]; + var size = ref[1]; + this.lazyStore = _store; + this.logger(("(addToLazyStore) size: " + size)); + return size + }; + + /** + * make sure we store the argument correctly + * @param {*} arg could be array + * @return {array} make sured + */ + StoreService.prototype.toArray = function toArray (arg) { + return Array.isArray(arg) ? arg : [arg] + }; + + /** + * setter to store the Set in private + * @param {object} obj a Set + */ + prototypeAccessors.normalStore.set = function (obj) { + NB_EVENT_SERVICE_PRIVATE_STORE.set(this, obj); + }; + + /** + * @return {object} Set object + */ + prototypeAccessors.normalStore.get = function () { + return NB_EVENT_SERVICE_PRIVATE_STORE.get(this) + }; + + /** + * setter to store the Set in lazy store + * @param {object} obj a Set + */ + prototypeAccessors.lazyStore.set = function (obj) { + NB_EVENT_SERVICE_PRIVATE_LAZY.set(this , obj); + }; + + /** + * @return {object} the lazy store Set + */ + prototypeAccessors.lazyStore.get = function () { + return NB_EVENT_SERVICE_PRIVATE_LAZY.get(this) + }; + + /** + * generate a hashKey to identify the function call + * The build-in store some how could store the same values! + * @param {function} fn the converted to string function + * @return {string} hashKey + */ + StoreService.prototype.hashFnToKey = function hashFnToKey (fn) { + return hashCode2Str(fn.toString()) + }; + + Object.defineProperties( StoreService.prototype, prototypeAccessors ); + + return StoreService; +}(SuspendClass)); + +// The top level +// export +var EventService = /*@__PURE__*/(function (StoreService) { + function EventService(config) { + if ( config === void 0 ) config = {}; + + StoreService.call(this, config); + } + + if ( StoreService ) EventService.__proto__ = StoreService; + EventService.prototype = Object.create( StoreService && StoreService.prototype ); + EventService.prototype.constructor = EventService; + + var prototypeAccessors = { $name: { configurable: true },is: { configurable: true },$done: { configurable: true } }; + + /** + * logger function for overwrite + */ + EventService.prototype.logger = function logger () {}; + + // for id if the instance is this class + prototypeAccessors.$name.get = function () { + return 'to1source-event' + }; + + // take this down in the next release + prototypeAccessors.is.get = function () { + return this.$name + }; + + ////////////////////////// + // PUBLIC METHODS // + ////////////////////////// + + /** + * Register your evt handler, note we don't check the type here, + * we expect you to be sensible and know what you are doing. + * @param {string} evt name of event + * @param {function} callback bind method --> if it's array or not + * @param {object} [context=null] to execute this call in + * @return {number} the size of the store + */ + EventService.prototype.$on = function $on (evt , callback , context) { + var this$1 = this; + if ( context === void 0 ) context = null; + + var type = 'on'; + this.validate(evt, callback); + // first need to check if this evt is in lazy store + var lazyStoreContent = this.takeFromStore(evt); + // this is normal register first then call later + if (lazyStoreContent === false) { + this.logger(("($on) \"" + evt + "\" is not in lazy store")); + // @TODO we need to check if there was other listener to this + // event and are they the same type then we could solve that + // register the different type to the same event name + return this.addToNormalStore(evt, type, callback, context) + } + this.logger(("($on) " + evt + " found in lazy store")); + // this is when they call $trigger before register this callback + var size = 0; + lazyStoreContent.forEach(function (content) { + var payload = content[0]; + var ctx = content[1]; + var t = content[2]; + if (t && t !== type) { + throw new Error((TAKEN_BY_OTHER_TYPE_ERR + " " + t)) + } + this$1.logger("($on)", ("call run \"" + evt + "\"")); + this$1.run(callback, payload, context || ctx); + size += this$1.addToNormalStore(evt, type, callback, context || ctx); + }); + + this.logger(("($on) return size " + size)); + return size + }; + + /** + * once only registered it once, there is no overwrite option here + * @NOTE change in v1.3.0 $once can add multiple listeners + * but once the event fired, it will remove this event (see $only) + * @param {string} evt name + * @param {function} callback to execute + * @param {object} [context=null] the handler execute in + * @return {boolean} result + */ + EventService.prototype.$once = function $once (evt , callback , context) { + if ( context === void 0 ) context = null; + + this.validate(evt, callback); + var type = 'once'; + var lazyStoreContent = this.takeFromStore(evt); + // this is normal register before call $trigger + var nStore = this.normalStore; + if (lazyStoreContent === false) { + this.logger(("($once) \"" + evt + "\" is not in the lazy store")); + // v1.3.0 $once now allow to add multiple listeners + return this.addToNormalStore(evt, type, callback, context) + } else { + // now this is the tricky bit + // there is a potential bug here that cause by the developer + // if they call $trigger first, the lazy won't know it's a once call + // so if in the middle they register any call with the same evt name + // then this $once call will be fucked - add this to the documentation + this.logger('($once)', lazyStoreContent); + var list = Array.from(lazyStoreContent); + // should never have more than 1 + var ref = list[0]; + var payload = ref[0]; + var ctx = ref[1]; + var t = ref[2]; + if (t && t !== type) { + throw new Error((TAKEN_BY_OTHER_TYPE_ERR + " " + t)) + } + this.logger('($once)', ("call run \"" + evt + "\"")); + this.run(callback, payload, context || ctx); + // remove this evt from store + this.$off(evt); + } + }; + + /** + * This one event can only bind one callbackback + * @param {string} evt event name + * @param {function} callback event handler + * @param {object} [context=null] the context the event handler execute in + * @return {boolean} true bind for first time, false already existed + */ + EventService.prototype.$only = function $only (evt, callback, context) { + var this$1 = this; + if ( context === void 0 ) context = null; + + this.validate(evt, callback); + var type = 'only'; + var added = false; + var lazyStoreContent = this.takeFromStore(evt); + // this is normal register before call $trigger + var nStore = this.normalStore; + if (!nStore.has(evt)) { + this.logger(("($only) \"" + evt + "\" add to normalStore")); + added = this.addToNormalStore(evt, type, callback, context); + } + if (lazyStoreContent !== false) { + // there are data store in lazy store + this.logger(("($only) \"" + evt + "\" found data in lazy store to execute")); + var list = Array.from(lazyStoreContent); + // $only allow to trigger this multiple time on the single handler + list.forEach( function (li) { + var payload = li[0]; + var ctx = li[1]; + var t = li[2]; + if (t && t !== type) { + throw new Error((TAKEN_BY_OTHER_TYPE_ERR + " " + t)) + } + this$1.logger(("($only) call run \"" + evt + "\"")); + this$1.run(callback, payload, context || ctx); + }); + } + return added + }; + + /** + * $only + $once this is because I found a very subtile bug when we pass a + * resolver, rejecter - and it never fire because that's OLD added in v1.4.0 + * @param {string} evt event name + * @param {function} callback to call later + * @param {object} [context=null] exeucte context + * @return {void} + */ + EventService.prototype.$onlyOnce = function $onlyOnce (evt, callback, context) { + if ( context === void 0 ) context = null; + + this.validate(evt, callback); + var type = 'onlyOnce'; + var added = false; + var lazyStoreContent = this.takeFromStore(evt); + // this is normal register before call $trigger + var nStore = this.normalStore; + if (!nStore.has(evt)) { + this.logger(("($onlyOnce) \"" + evt + "\" add to normalStore")); + added = this.addToNormalStore(evt, type, callback, context); + } + if (lazyStoreContent !== false) { + // there are data store in lazy store + this.logger('($onlyOnce)', lazyStoreContent); + var list = Array.from(lazyStoreContent); + // should never have more than 1 + var ref = list[0]; + var payload = ref[0]; + var ctx = ref[1]; + var t = ref[2]; + if (t && t !== 'onlyOnce') { + throw new Error((TAKEN_BY_OTHER_TYPE_ERR + " " + t)) + } + this.logger(("($onlyOnce) call run \"" + evt + "\"")); + this.run(callback, payload, context || ctx); + // remove this evt from store + this.$off(evt); + } + return added + }; + + /** + * This is a shorthand of $off + $on added in V1.5.0 + * @param {string} evt event name + * @param {function} callback to exeucte + * @param {object} [context = null] or pass a string as type + * @param {string} [type=on] what type of method to replace + * @return {*} + */ + EventService.prototype.$replace = function $replace (evt, callback, context, type) { + if ( context === void 0 ) context = null; + if ( type === void 0 ) type = 'on'; + + if (this.validateType(type)) { + this.$off(evt); + var method = this['$' + type]; + this.logger("($replace)", evt, callback); + return Reflect.apply(method, this, [evt, callback, context]) + } + throw new Error((type + " is not supported!")) + }; + + /** + * trigger the event + * @param {string} evt name NOT allow array anymore! + * @param {mixed} [payload = []] pass to fn + * @param {object|string} [context = null] overwrite what stored + * @param {string} [type=false] if pass this then we need to add type to store too + * @return {number} if it has been execute how many times + */ + EventService.prototype.$trigger = function $trigger (evt , payload , context, type) { + if ( payload === void 0 ) payload = []; + if ( context === void 0 ) context = null; + if ( type === void 0 ) type = false; + + this.validateEvt(evt); + var found = 0; + // first check the normal store + var nStore = this.normalStore; + this.logger('($trigger) normalStore', nStore); + if (nStore.has(evt)) { + this.logger(("($trigger) \"" + evt + "\" found")); + // @1.8.0 to add the suspend queue + var added = this.$queue(evt, payload, context, type); + if (added) { + this.logger(("($trigger) Currently suspended \"" + evt + "\" added to queue, nothing executed. Exit now.")); + return false // not executed + } + var nSet = Array.from(nStore.get(evt)); + var ctn = nSet.length; + var hasOnce = false; + for (var i=0; i < ctn; ++i) { + ++found; + // this.logger('found', found) + var ref = nSet[i]; + var _ = ref[0]; + var callback = ref[1]; + var ctx = ref[2]; + var type$1 = ref[3]; + this.logger(("($trigger) call run for " + evt)); + this.run(callback, payload, context || ctx); + if (type$1 === 'once' || type$1 === 'onlyOnce') { + hasOnce = true; + } + } + if (hasOnce) { + nStore.delete(evt); + } + return found + } + // now this is not register yet + this.addToLazyStore(evt, payload, context, type); + return found + }; + + /** + * this is an alias to the $trigger + * @NOTE breaking change in V1.6.0 we swap the parameter aroun + * @NOTE breaking change: v1.9.1 it return an function to accept the params as spread + * @param {string} evt event name + * @param {string} type of call + * @param {object} context what context callback execute in + * @return {*} from $trigger + */ + EventService.prototype.$call = function $call (evt, type, context) { + if ( type === void 0 ) type = false; + if ( context === void 0 ) context = null; + + var ctx = this; + + return function () { + var args = [], len = arguments.length; + while ( len-- ) args[ len ] = arguments[ len ]; + + var _args = [evt, args, context, type]; + return Reflect.apply(ctx.$trigger, ctx, _args) + } + }; + + /** + * remove the evt from all the stores + * @param {string} evt name + * @return {boolean} true actually delete something + */ + EventService.prototype.$off = function $off (evt) { + var this$1 = this; + + // @TODO we will allow a regex pattern to mass remove event + this.validateEvt(evt); + var stores = [ this.lazyStore, this.normalStore ]; + + return !!stores + .filter(function (store) { return store.has(evt); }) + .map(function (store) { return this$1.removeFromStore(evt, store); }) + .length + }; + + /** + * return all the listener bind to that event name + * @param {string} evtName event name + * @param {boolean} [full=false] if true then return the entire content + * @return {array|boolean} listerner(s) or false when not found + */ + EventService.prototype.$get = function $get (evt, full) { + if ( full === void 0 ) full = false; + + // @TODO should we allow the same Regex to search for all? + this.validateEvt(evt); + var store = this.normalStore; + return this.findFromStore(evt, store, full) + }; + + /** + * store the return result from the run + * @param {*} value whatever return from callback + */ + prototypeAccessors.$done.set = function (value) { + this.logger('($done) set value: ', value); + if (this.keep) { + this.result.push(value); + } else { + this.result = value; + } + }; + + /** + * @TODO is there any real use with the keep prop? + * getter for $done + * @return {*} whatever last store result + */ + prototypeAccessors.$done.get = function () { + this.logger('($done) get result:', this.result); + if (this.keep) { + return this.result[this.result.length - 1] + } + return this.result + }; + + /** + * Take a look inside the stores + * @param {number|null} idx of the store, null means all + * @return {void} + */ + EventService.prototype.$debug = function $debug (idx) { + var this$1 = this; + if ( idx === void 0 ) idx = null; + + var names = ['lazyStore', 'normalStore']; + var stores = [this.lazyStore, this.normalStore]; + if (stores[idx]) { + this.logger(names[idx], stores[idx]); + } else { + stores.map(function (store, i) { + this$1.logger(names[i], store); + }); + } + }; + + Object.defineProperties( EventService.prototype, prototypeAccessors ); + + return EventService; +}(StoreService)); + +// default + +// this will generate a event emitter and will be use everywhere +// create a clone version so we know which one we actually is using +var JsonqlWsEvt = /*@__PURE__*/(function (EventEmitterClass) { + function JsonqlWsEvt(logger) { + if (typeof logger !== 'function') { + throw new Error("Just die here the logger is not a function!") + } + logger("---> Create a new EventEmitter <---"); + // this ee will always come with the logger + // because we should take the ee from the configuration + EventEmitterClass.call(this, { logger: logger }); + } + + if ( EventEmitterClass ) JsonqlWsEvt.__proto__ = EventEmitterClass; + JsonqlWsEvt.prototype = Object.create( EventEmitterClass && EventEmitterClass.prototype ); + JsonqlWsEvt.prototype.constructor = JsonqlWsEvt; + + var prototypeAccessors = { name: { configurable: true } }; + + prototypeAccessors.name.get = function () { + return 'jsonql-ws-client-core' + }; + + Object.defineProperties( JsonqlWsEvt.prototype, prototypeAccessors ); + + return JsonqlWsEvt; +}(EventService)); + +/** + * getting the event emitter + * @param {object} opts configuration + * @return {object} the event emitter instance + */ +var getEventEmitter = function (opts) { + var log = opts.log; + var eventEmitter = opts.eventEmitter; + + if (eventEmitter) { + log("eventEmitter is:", eventEmitter.name); + return eventEmitter + } + + return new JsonqlWsEvt( opts.log ) +}; + +// bunch of generic helpers + +/** + * DIY in Array + * @param {array} arr to check from + * @param {*} value to check against + * @return {boolean} true on found + */ +var inArray$1 = function (arr, value) { return !!arr.filter(function (a) { return a === value; }).length; }; + +// quick and dirty to turn non array to array +var toArray$1 = function (arg) { return isArray(arg) ? arg : [arg]; }; + +/** + * @param {object} obj for search + * @param {string} key target + * @return {boolean} true on success + */ +var isObjectHasKey$1 = function(obj, key) { + try { + var keys = Object.keys(obj); + return inArray$1(keys, key) + } catch(e) { + // @BUG when the obj is not an OBJECT we got some weird output + return false + } +}; + +/** + * create a event name + * @param {string[]} args + * @return {string} event name for use + */ +var createEvt = function () { + var args = [], len = arguments.length; + while ( len-- ) args[ len ] = arguments[ len ]; + + return args.join('_'); +}; + +/** + * Simple check if the prop is function + * @param {*} prop input + * @return {boolean} true on success + */ +var isFunc = function (prop) { + if (typeof prop === 'function') { + return true; + } + console.error(("Expect to be Function type! Got " + (typeof prop))); +}; + +// generic placeholder function +var nil = function () { return false; }; + +/** + * using just the map reduce to chain multiple functions together + * @param {function} mainFn the init function + * @param {array} moreFns as many as you want to take the last value and return a new one + * @return {function} accept value for the mainFn + */ +var chainFns = function (mainFn) { + var moreFns = [], len = arguments.length - 1; + while ( len-- > 0 ) moreFns[ len ] = arguments[ len + 1 ]; + + return ( + function () { + var args = [], len = arguments.length; + while ( len-- ) args[ len ] = arguments[ len ]; + + return ( + moreFns.reduce(function (value, nextFn) { return ( + // change here to check if the return value is array then we spread it + Reflect.apply(nextFn, null, toArray$1(value)) + ); }, Reflect.apply(mainFn, null, args)) + ); + } +); +}; + +/** + * this is essentially the same as the injectToFn + * but this will not allow overwrite and set the setter and getter + * @param {object} obj to get injected + * @param {string} name of the property + * @param {function} setter for set + * @param {function} [getter=null] for get default return null fn + * @return {object} the injected obj + */ +function objDefineProps(obj, name, setter, getter) { + if ( getter === void 0 ) getter = null; + + if (Object.getOwnPropertyDescriptor(obj, name) === undefined) { + Object.defineProperty(obj, name, { + set: setter, + get: getter === null ? function() { return null; } : getter + }); + } + return obj +} + +/** + * check if the object has name property + * @param {object} obj the object to check + * @param {string} name the prop name + * @return {*} the value or undefined + */ +function objHasProp(obj, name) { + var prop = Object.getOwnPropertyDescriptor(obj, name); + return prop !== undefined && prop.value ? prop.value : prop +} + +/** + * After the user login we will use this Object.define add a new property + * to the resolver with the decoded user data + * @param {function} resolver target resolver + * @param {string} name the name of the object to get inject also for checking + * @param {object} data to inject into the function static interface + * @param {boolean} [overwrite=false] if we want to overwrite the existing data + * @return {function} added property resolver + */ +function injectToFn(resolver, name, data, overwrite) { + if ( overwrite === void 0 ) overwrite = false; + + var check = objHasProp(resolver, name); + if (overwrite === false && check !== undefined) { + // console.info(`NOT INJECTED`) + return resolver + } + /* this will throw error! @TODO how to remove props? + if (overwrite === true && check !== undefined) { + delete resolver[name] // delete this property + } + */ + // console.info(`INJECTED`) + Object.defineProperty(resolver, name, { + value: data, + writable: overwrite // if its set to true then we should able to overwrite it + }); + + return resolver +} + +/** + * This is a custom error to throw when server throw a 406 + * This help us to capture the right error, due to the call happens in sequence + * @param {string} message to tell what happen + * @param {mixed} extra things we want to add, 500? + */ +var Jsonql406Error = /*@__PURE__*/(function (Error) { + function Jsonql406Error() { + var args = [], len = arguments.length; + while ( len-- ) args[ len ] = arguments[ len ]; + + Error.apply(this, args); + this.message = args[0]; + this.detail = args[1]; + // We can't access the static name from an instance + // but we can do it like this + this.className = Jsonql406Error.name; + + if (Error.captureStackTrace) { + Error.captureStackTrace(this, Jsonql406Error); + } + } + + if ( Error ) Jsonql406Error.__proto__ = Error; + Jsonql406Error.prototype = Object.create( Error && Error.prototype ); + Jsonql406Error.prototype.constructor = Jsonql406Error; + + var staticAccessors = { statusCode: { configurable: true },name: { configurable: true } }; + + staticAccessors.statusCode.get = function () { + return 406; + }; + + staticAccessors.name.get = function () { + return 'Jsonql406Error'; + }; + + Object.defineProperties( Jsonql406Error, staticAccessors ); + + return Jsonql406Error; +}(Error)); + +/** + * This is a custom error to throw when server throw a 500 + * This help us to capture the right error, due to the call happens in sequence + * @param {string} message to tell what happen + * @param {mixed} extra things we want to add, 500? + */ +var Jsonql500Error = /*@__PURE__*/(function (Error) { + function Jsonql500Error() { + var args = [], len = arguments.length; + while ( len-- ) args[ len ] = arguments[ len ]; + + Error.apply(this, args); + + this.message = args[0]; + this.detail = args[1]; + + this.className = Jsonql500Error.name; + + if (Error.captureStackTrace) { + Error.captureStackTrace(this, Jsonql500Error); + } + } + + if ( Error ) Jsonql500Error.__proto__ = Error; + Jsonql500Error.prototype = Object.create( Error && Error.prototype ); + Jsonql500Error.prototype.constructor = Jsonql500Error; + + var staticAccessors = { statusCode: { configurable: true },name: { configurable: true } }; + + staticAccessors.statusCode.get = function () { + return 500; + }; + + staticAccessors.name.get = function () { + return 'Jsonql500Error'; + }; + + Object.defineProperties( Jsonql500Error, staticAccessors ); + + return Jsonql500Error; +}(Error)); + +/** + * this is the 403 Forbidden error + * that means this user is not login + * use the 401 for try to login and failed + * @param {string} message to tell what happen + * @param {mixed} extra things we want to add, 500? + */ +var JsonqlForbiddenError = /*@__PURE__*/(function (Error) { + function JsonqlForbiddenError() { + var args = [], len = arguments.length; + while ( len-- ) args[ len ] = arguments[ len ]; + + Error.apply(this, args); + this.message = args[0]; + this.detail = args[1]; + + this.className = JsonqlForbiddenError.name; + + if (Error.captureStackTrace) { + Error.captureStackTrace(this, JsonqlForbiddenError); + } + } + + if ( Error ) JsonqlForbiddenError.__proto__ = Error; + JsonqlForbiddenError.prototype = Object.create( Error && Error.prototype ); + JsonqlForbiddenError.prototype.constructor = JsonqlForbiddenError; + + var staticAccessors = { statusCode: { configurable: true },name: { configurable: true } }; + + staticAccessors.statusCode.get = function () { + return 403; + }; + + staticAccessors.name.get = function () { + return 'JsonqlForbiddenError'; + }; + + Object.defineProperties( JsonqlForbiddenError, staticAccessors ); + + return JsonqlForbiddenError; +}(Error)); + +/** + * This is a custom error to throw when pass credential but fail + * This help us to capture the right error, due to the call happens in sequence + * @param {string} message to tell what happen + * @param {mixed} extra things we want to add, 500? + */ +var JsonqlAuthorisationError = /*@__PURE__*/(function (Error) { + function JsonqlAuthorisationError() { + var args = [], len = arguments.length; + while ( len-- ) args[ len ] = arguments[ len ]; + + Error.apply(this, args); + this.message = args[0]; + this.detail = args[1]; + + this.className = JsonqlAuthorisationError.name; + + if (Error.captureStackTrace) { + Error.captureStackTrace(this, JsonqlAuthorisationError); + } + } + + if ( Error ) JsonqlAuthorisationError.__proto__ = Error; + JsonqlAuthorisationError.prototype = Object.create( Error && Error.prototype ); + JsonqlAuthorisationError.prototype.constructor = JsonqlAuthorisationError; + + var staticAccessors = { statusCode: { configurable: true },name: { configurable: true } }; + + staticAccessors.statusCode.get = function () { + return 401; + }; + + staticAccessors.name.get = function () { + return 'JsonqlAuthorisationError'; + }; + + Object.defineProperties( JsonqlAuthorisationError, staticAccessors ); + + return JsonqlAuthorisationError; +}(Error)); + +/** + * This is a custom error when not supply the credential and try to get contract + * This help us to capture the right error, due to the call happens in sequence + * @param {string} message to tell what happen + * @param {mixed} extra things we want to add, 500? + */ +var JsonqlContractAuthError = /*@__PURE__*/(function (Error) { + function JsonqlContractAuthError() { + var args = [], len = arguments.length; + while ( len-- ) args[ len ] = arguments[ len ]; + + Error.apply(this, args); + this.message = args[0]; + this.detail = args[1]; + + this.className = JsonqlContractAuthError.name; + + if (Error.captureStackTrace) { + Error.captureStackTrace(this, JsonqlContractAuthError); + } + } + + if ( Error ) JsonqlContractAuthError.__proto__ = Error; + JsonqlContractAuthError.prototype = Object.create( Error && Error.prototype ); + JsonqlContractAuthError.prototype.constructor = JsonqlContractAuthError; + + var staticAccessors = { statusCode: { configurable: true },name: { configurable: true } }; + + staticAccessors.statusCode.get = function () { + return 401; + }; + + staticAccessors.name.get = function () { + return 'JsonqlContractAuthError'; + }; + + Object.defineProperties( JsonqlContractAuthError, staticAccessors ); + + return JsonqlContractAuthError; +}(Error)); + +/** + * This is a custom error to throw when the resolver throw error and capture inside the middleware + * This help us to capture the right error, due to the call happens in sequence + * @param {string} message to tell what happen + * @param {mixed} extra things we want to add, 500? + */ +var JsonqlResolverAppError = /*@__PURE__*/(function (Error) { + function JsonqlResolverAppError() { + var args = [], len = arguments.length; + while ( len-- ) args[ len ] = arguments[ len ]; + + Error.apply(this, args); + + this.message = args[0]; + this.detail = args[1]; + + this.className = JsonqlResolverAppError.name; + + if (Error.captureStackTrace) { + Error.captureStackTrace(this, JsonqlResolverAppError); + } + } + + if ( Error ) JsonqlResolverAppError.__proto__ = Error; + JsonqlResolverAppError.prototype = Object.create( Error && Error.prototype ); + JsonqlResolverAppError.prototype.constructor = JsonqlResolverAppError; + + var staticAccessors = { statusCode: { configurable: true },name: { configurable: true } }; + + staticAccessors.statusCode.get = function () { + return 500; + }; + + staticAccessors.name.get = function () { + return 'JsonqlResolverAppError'; + }; + + Object.defineProperties( JsonqlResolverAppError, staticAccessors ); + + return JsonqlResolverAppError; +}(Error)); + +/** + * This is a custom error to throw when could not find the resolver + * This help us to capture the right error, due to the call happens in sequence + * @param {string} message to tell what happen + * @param {mixed} extra things we want to add, 500? + */ +var JsonqlResolverNotFoundError = /*@__PURE__*/(function (Error) { + function JsonqlResolverNotFoundError() { + var args = [], len = arguments.length; + while ( len-- ) args[ len ] = arguments[ len ]; + + Error.apply(this, args); + + this.message = args[0]; + this.detail = args[1]; + + this.className = JsonqlResolverNotFoundError.name; + + if (Error.captureStackTrace) { + Error.captureStackTrace(this, JsonqlResolverNotFoundError); + } + } + + if ( Error ) JsonqlResolverNotFoundError.__proto__ = Error; + JsonqlResolverNotFoundError.prototype = Object.create( Error && Error.prototype ); + JsonqlResolverNotFoundError.prototype.constructor = JsonqlResolverNotFoundError; + + var staticAccessors = { statusCode: { configurable: true },name: { configurable: true } }; + + staticAccessors.statusCode.get = function () { + return 404; + }; + + staticAccessors.name.get = function () { + return 'JsonqlResolverNotFoundError'; + }; + + Object.defineProperties( JsonqlResolverNotFoundError, staticAccessors ); + + return JsonqlResolverNotFoundError; +}(Error)); + +// this is from an example from Koa team to use for internal middleware ctx.throw +// but after the test the res.body part is unable to extract the required data +// I keep this one here for future reference + +var JsonqlServerError = /*@__PURE__*/(function (Error) { + function JsonqlServerError(statusCode, message) { + Error.call(this, message); + this.statusCode = statusCode; + this.className = JsonqlServerError.name; + } + + if ( Error ) JsonqlServerError.__proto__ = Error; + JsonqlServerError.prototype = Object.create( Error && Error.prototype ); + JsonqlServerError.prototype.constructor = JsonqlServerError; + + var staticAccessors = { name: { configurable: true } }; + + staticAccessors.name.get = function () { + return 'JsonqlServerError'; + }; + + Object.defineProperties( JsonqlServerError, staticAccessors ); + + return JsonqlServerError; +}(Error)); + +/** + * this will put into generator call at the very end and catch + * the error throw from inside then throw again + * this is necessary because we split calls inside and the throw + * will not reach the actual client unless we do it this way + * @param {object} e Error + * @return {void} just throw + */ +function finalCatch(e) { + // this is a hack to get around the validateAsync not actually throw error + // instead it just rejected it with the array of failed parameters + if (Array.isArray(e)) { + // if we want the message then I will have to create yet another function + // to wrap this function to provide the name prop + throw new JsonqlValidationError('', e) + } + var msg = e.message || NO_ERROR_MSG; + var detail = e.detail || e; + // @BUG the instance of not always work for some reason! + // need to figure out a better way to find out the type of the error + switch (true) { + case e instanceof Jsonql406Error: + throw new Jsonql406Error(msg, detail) + case e instanceof Jsonql500Error: + throw new Jsonql500Error(msg, detail) + case e instanceof JsonqlForbiddenError: + throw new JsonqlForbiddenError(msg, detail) + case e instanceof JsonqlAuthorisationError: + throw new JsonqlAuthorisationError(msg, detail) + case e instanceof JsonqlContractAuthError: + throw new JsonqlContractAuthError(msg, detail) + case e instanceof JsonqlResolverAppError: + throw new JsonqlResolverAppError(msg, detail) + case e instanceof JsonqlResolverNotFoundError: + throw new JsonqlResolverNotFoundError(msg, detail) + case e instanceof JsonqlEnumError: + throw new JsonqlEnumError(msg, detail) + case e instanceof JsonqlTypeError: + throw new JsonqlTypeError(msg, detail) + case e instanceof JsonqlCheckerError: + throw new JsonqlCheckerError(msg, detail) + case e instanceof JsonqlValidationError: + throw new JsonqlValidationError(msg, detail) + case e instanceof JsonqlServerError: + throw new JsonqlServerError(msg, detail) + default: + throw new JsonqlError$1(msg, detail) + } +} + +// split the contract into the node side and the generic side +/** + * Check if the json is a contract file or not + * @param {object} contract json object + * @return {boolean} true + */ +function checkIsContract(contract) { + return isPlainObject(contract) + && ( + isObjectHasKey$1(contract, QUERY_NAME) + || isObjectHasKey$1(contract, MUTATION_NAME) + || isObjectHasKey$1(contract, SOCKET_NAME) + ) +} + +/** + * Wrapper method that check if it's contract then return the contract or false + * @param {object} contract the object to check + * @return {boolean | object} false when it's not + */ +function isContract(contract) { + return checkIsContract(contract) ? contract : false +} + +/** + * Ported from jsonql-params-validator but different + * if we don't find the socket part then return false + * @param {object} contract the contract object + * @return {object|boolean} false on failed + */ +function extractSocketPart(contract) { + if (isObjectHasKey$1(contract, SOCKET_NAME)) { + return contract[SOCKET_NAME] + } + return false +} + +// take out all the namespace related methods in one place for easy to find +var SOCKET_NOT_FOUND_ERR = "socket not found in contract!"; +var SIZE = 'size'; + +/** + * create the group using publicNamespace when there is only public + * @param {object} socket from contract + * @param {string} publicNamespace + */ +function groupPublicNamespace(socket, publicNamespace) { + var obj; + + var g = {}; + for (var resolverName in socket) { + var params = socket[resolverName]; + g[resolverName] = params; + } + return { size: 1, nspGroup: ( obj = {}, obj[publicNamespace] = g, obj ), publicNamespace: publicNamespace} +} + + +/** + * @BUG we should check the socket part instead of expect the downstream to read the menu! + * We only need this when the enableAuth is true otherwise there is only one namespace + * @param {object} contract the socket part of the contract file + * @return {object} 1. remap the contract using the namespace --> resolvers + * 2. the size of the object (1 all private, 2 mixed public with private) + * 3. which namespace is public + */ +function groupByNamespace(contract) { + var socket = extractSocketPart(contract); + if (socket === false) { + throw new JsonqlError('groupByNamespace', SOCKET_NOT_FOUND_ERR) + } + var prop = {}; + prop[NSP_GROUP] = {}; + prop[PUBLIC_NAMESPACE] = null; + prop[SIZE] = 0; + + for (var resolverName in socket) { + var params = socket[resolverName]; + var namespace = params.namespace; + if (namespace) { + if (!prop[NSP_GROUP][namespace]) { + ++prop[SIZE]; + prop[NSP_GROUP][namespace] = {}; + } + prop[NSP_GROUP][namespace][resolverName] = params; + // get the public namespace + if (!prop[PUBLIC_NAMESPACE] && params[PUBLIC_KEY]) { + prop[PUBLIC_NAMESPACE] = namespace; + } + } + } + + return prop +} + +/** + * @TODO this might change, what if we want to do room with ws + * 1. there will only be max two namespace + * 2. when it's normal we will have the stock path as namespace + * 3. when enableAuth then we will have two, one is jsonql/public + private + * @param {object} config options + * @return {array} of namespace(s) + */ +function getNamespace(config) { + var base = JSONQL_PATH; + if (config.enableAuth) { + // the public come first @1.0.1 we use the constants instead of the user supplied value + // @1.0.4 we use the config value again, because we could control this via the post init + return [ + [ base , config.publicNamespace ].join('/'), + [ base , config.privateNamespace ].join('/') + ] + } + return [ base ] +} + +/** + * Got a problem with a contract that is public only the groupByNamespace is wrong + * which is actually not a problem when using a fallback, but to be sure things in order + * we could combine with the config to group it + * @param {object} config configuration + * @return {object} nspInfo object + */ +function getNspInfoByConfig(config) { + var contract = config.contract; + var enableAuth = config.enableAuth; + var namespaces = getNamespace(config); + var nspInfo = enableAuth ? groupByNamespace(contract) + : groupPublicNamespace(contract.socket, namespaces[0]); + // add the namespaces into it as well + return Object.assign(nspInfo, { namespaces: namespaces }) +} + +// group all the small functions here + + +/** + * WebSocket is strict about the path, therefore we need to make sure before it goes in + * @param {string} url input url + * @return {string} url with correct path name + */ +var fixWss = function (url) { + var uri = url.toLowerCase(); + if (uri.indexOf('http') > -1) { + if (uri.indexOf('https') > -1) { + return uri.replace('https', 'wss') + } + return uri.replace('http', 'ws') + } + return uri +}; + + +/** + * get a stock host name from browser + */ +var getHostName = function () { + try { + return [window.location.protocol, window.location.host].join('//') + } catch(e) { + throw new JsonqlValidationError(e) + } +}; + +/** + * Unbind the event + * @param {object} ee EventEmitter + * @param {string} namespace + * @return {void} + */ +var clearMainEmitEvt = function (ee, namespace) { + var nsps = toArray$1(namespace); + nsps.forEach(function (n) { + ee.$off(createEvt(n, EMIT_REPLY_TYPE$1)); + }); +}; + +// 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$1 + " with " + token)); + // @TODO add the interceptor hook + return ee.$trigger(LOGIN_EVENT_NAME$1, [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$1, 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$1, function onLoginCallbackHandler(onLoginCallback) { + if (isFunc(onLoginCallback)) { + // only one callback can registered with it, TBC + ee.$only(ON_LOGIN_FN_NAME$1, 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 SOCKET_IO = JS_WS_SOCKET_IO_NAME; + +var EMIT_EVT = EMIT_REPLY_TYPE$1; + +var UNKNOWN_RESULT = 'UKNNOWN RESULT!'; + +var MY_NAMESPACE = 'myNamespace'; +// this is a socket only (for now) feature so we just put it here +var DISCONNECTED_ERROR_MSG = "You have disconnected from the socket server, please reconnect."; + +// breaking it up further to share between methods + +/** + * break out to use in different places to handle the return from server + * @param {object} data from server + * @param {function} resolver NOT from promise + * @param {function} rejecter NOT from promise + * @return {void} nothing + */ +function respondHandler(data, resolver, rejecter) { + if (isObjectHasKey$1(data, ERROR_KEY$1)) { + // debugFn('-- rejecter called --', data[ERROR_KEY]) + rejecter(data[ERROR_KEY$1]); + } else if (isObjectHasKey$1(data, DATA_KEY)) { + // debugFn('-- resolver called --', data[DATA_KEY]) + resolver(data[DATA_KEY]); + } else { + // debugFn('-- UNKNOWN_RESULT --', data) + rejecter({message: UNKNOWN_RESULT, error: data}); + } +} + +// the actual trigger call method + +/** + * just wrapper + * @param {object} ee EventEmitter + * @param {string} namespace where this belongs + * @param {string} resolverName resolver + * @param {array} args arguments + * @param {function} log function + * @return {void} nothing + */ +function actionCall(ee, namespace, resolverName, args, log) { + if ( args === void 0 ) args = []; + + // reply event + var outEventName = createEvt(namespace, EMIT_REPLY_TYPE$1); + + log(("actionCall: " + outEventName + " --> " + resolverName), args); + // This is the out going call + ee.$trigger(outEventName, [resolverName, toArray$1(args)]); + + // then we need to listen to the event callback here as well + return new Promise(function (resolver, rejecter) { + var inEventName = createEvt(namespace, resolverName, ON_RESULT_FN_NAME$1); + // this cause the onResult got the result back first + // and it should be the promise resolve first + // @TODO we need to rewrote the respondHandler to change the problem stated above + ee.$on( + inEventName, + function actionCallResultHandler(result) { + log("got the first result", result); + respondHandler(result, resolver, rejecter); + } + ); + }) +} + +// setting up the send method + +/** + * pairing with the server vesrion SEND_MSG_FN_NAME + * last of the chain so only return the resolver (fn) + * This is now change to a getter / setter method + * and call like this: resolver.send(...args) + * @param {function} fn the resolver function + * @param {object} ee event emitter instance + * @param {string} namespace the namespace it belongs to + * @param {string} resolverName name of the resolver + * @param {object} params from contract + * @param {function} log a logger function + * @return {function} return the resolver itself + */ +var setupSendMethod = function (fn, ee, namespace, resolverName, params, log) { return ( + objDefineProps( + fn, + SEND_MSG_FN_NAME, + nil, + function sendHandler() { + // let _log = (...args) => Reflect.apply(console.info, console, ['[SEND]'].concat(args)) + /** + * This will follow the same pattern like the resolver + * @param {array} args list of unknown argument follow the resolver + * @return {promise} resolve the result + */ + return function sendCallback() { + var args = [], len = arguments.length; + while ( len-- ) args[ len ] = arguments[ len ]; + + return validateAsync$1(args, params.params, true) + .then(function (_args) { + // @TODO check the result + // because the validation could failed with the list of fail properties + log(namespace, resolverName, _args); + return actionCall(ee, namespace, resolverName, _args, _log) + }) + .catch(function (err) { + // @TODO it shouldn't be just a validation error + // it could be server return error, so we need to check + // what error we got back here first + log('send error', err); + // @TODO it might not an validation error need the finalCatch here + ee.$call( + createEvt(namespace, resolverName, ON_ERROR_FN_NAME$1), + [new JsonqlValidationError(resolverName, err)] + ); + }) + } + }) +); }; + +// break up the original setup resolver method here + +/** + * The first one in the chain, just setup a namespace prop + * the rest are passing through + * @param {function} fn the resolver function + * @param {object} ee the event emitter + * @param {string} resolverName what it said + * @param {object} params for resolver from contract + * @param {function} log the logger function + * @return {array} + */ +var setupNamespace = function (fn, ee, namespace, resolverName, params, log) { return [ + injectToFn(fn, MY_NAMESPACE, namespace), + ee, + namespace, + resolverName, + params, + log +]; }; + +/** + * onResult handler + */ +var setupOnResult = function (fn, ee, namespace, resolverName, params, log) { return [ + objDefineProps(fn, ON_RESULT_FN_NAME$1, function(resultCallback) { + if (isFunc(resultCallback)) { + ee.$on( + createEvt(namespace, resolverName, ON_RESULT_FN_NAME$1), + function resultHandler(result) { + respondHandler(result, resultCallback, function (error) { + log(("Catch error: \"" + resolverName + "\""), error); + ee.$trigger( + createEvt(namespace, resolverName, ON_ERROR_FN_NAME$1), + error + ); + }); + } + ); + } + }), + ee, + namespace, + resolverName, + params, + log +]; }; + +/** + * we do need to add the send prop back because it's the only way to deal with + * bi-directional data stream + */ +var setupOnMessage = function (fn, ee, namespace, resolverName, params, log) { return [ + objDefineProps(fn, ON_MESSAGE_FN_NAME$1, function(messageCallback) { + // we expect this to be a function + if (isFunc(messageCallback)) { + // did that add to the callback + var onMessageCallback = function (args) { + respondHandler(args, messageCallback, function (error) { + log(("Catch error: \"" + resolverName + "\""), error); + ee.$trigger( + createEvt(namespace, resolverName, ON_ERROR_FN_NAME$1), + error + ); + }); + }; + // register the handler for this message event + ee.$only( + createEvt(namespace, resolverName, ON_MESSAGE_FN_NAME$1), + onMessageCallback + ); + } + }), + ee, + namespace, + resolverName, + params, + log +]; }; + +/** + * ON_ERROR_FN_NAME handler + */ +var setupOnError = function (fn, ee, namespace, resolverName, params, log) { return [ + objDefineProps(fn, ON_ERROR_FN_NAME$1, function(resolverErrorHandler) { + if (isFunc(resolverErrorHandler)) { + // please note ON_ERROR_FN_NAME can add multiple listners + ee.$only( + createEvt(namespace, resolverName, ON_ERROR_FN_NAME$1), + resolverErrorHandler + ); + } + }), + ee, + namespace, + resolverName, + params, + log +]; }; + +/** + * Add extra property / listeners to the resolver + * @param {string} namespace where this belongs + * @param {string} resolverName name as event name + * @param {object} params from contract + * @param {function} fn resolver function + * @param {object} ee EventEmitter + * @param {function} log function + * @return {function} resolver + */ +function setupResolver(namespace, resolverName, params, fn, ee, log) { + var fns = [ + setupNamespace, + setupOnResult, + setupOnMessage, + setupOnError, + setupSendMethod + ]; + + // get the executor + var executor = Reflect.apply(chainFns, null, fns); + var args = [fn, ee, namespace, resolverName, params, log]; + + return Reflect.apply(executor, null, args) +} + +// put all the resolver related methods here to make it more clear + +/** + * create the actual function to send message to server + * @param {object} ee EventEmitter instance + * @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 + * @return {function} resolver + */ +function createResolver(ee, namespace, resolverName, params, log) { + // note we pass the new withResult=true option + return function resolver() { + var args = [], len = arguments.length; + while ( len-- ) args[ len ] = arguments[ len ]; + + return validateAsync$1(args, params.params, true) + .then(function (_args) { return actionCall(ee, namespace, resolverName, _args, log); }) + .catch(finalCatch) + } +} + +/** + * step one get the clientmap with the namespace + * @param {object} opts configuration + * @param {object} ee EventEmitter + * @param {object} nspGroup resolvers index by their namespace + * @return {promise} resolve the clientmapped, and start the chain + */ +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) { + // resolverNames.push(resolverName) + var params = list[resolverName]; + var fn = createResolver(ee, namespace, resolverName, params, log); + // 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, setupResolver(namespace, resolverName, params, fn, ee, log)); + } + } + // resolve the clientto start the chain + // chain the result to allow the chain processing + return [ client, opts, ee, nspGroup ] +} + +/** + * The problem is the namespace can have more than one + * and we only have on onError message + * @param {object} clientthe client itself + * @param {object} opts configuration + * @param {object} ee Event Emitter + * @param {object} nspGroup namespace keys + * @return {array} [obj, opts, ee] + */ +function createNamespaceErrorHandler(client, opts, ee, nspGroup) { + return [ + // using the onError as name + // @TODO we should follow the convention earlier + // make this a setter for the clientitself + objDefineProps(client, ON_ERROR_FN_NAME$1, function namespaceErrorCallbackHandler(namespaceErrorHandler) { + if (isFunc(namespaceErrorHandler)) { + // please note ON_ERROR_FN_NAME can add multiple listners + for (var namespace in nspGroup) { + // this one is very tricky, we need to make sure the trigger is calling + // with the namespace as well as the error + ee.$on(createEvt(namespace, ON_ERROR_FN_NAME$1), namespaceErrorHandler); + } + } + }), + opts, + ee + ] +} + +/** + * This event will fire when the socket.io.on('connection') and ws.onopen + * @param {object} client client itself + * @param {object} opts configuration + * @param {object} ee Event Emitter + * @return {array} [ obj, opts, ee ] + */ +function createOnReadyHandler(client, opts, ee) { + return [ + objDefineProps(client, ON_READY_FN_NAME$1, function onReadyCallbackHandler(onReadyCallback) { + if (isFunc(onReadyCallback)) { + // reduce it down to just one flat level + ee.$on(ON_READY_FN_NAME$1, onReadyCallback); + } + }), + opts, + ee + ] +} + +// 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 + * output the client + * @param {object} client the client + * @param {object} opts configuration + * @param {object} ee the event emitter + * @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); + }) +} + +/** + * 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 + */ +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 + 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 + client.eventEmitter = opts.eventEmitter; + client.log = opts.log; + 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 generator(opts, nspMap, ee) { + + var args = [ + generateResolvers, + createNamespaceErrorHandler, + createOnReadyHandler + ]; + if (opts.enableAuth) { + args.push( + createAuthMethods + ); + } + // we will always get back the [ obj, opts, ee ] + // then we only return the obj (wsClient) + args.push(setupFinalStep); + // run it + var fn = Reflect.apply(chainFns, null, args); + + return fn(opts, ee, nspMap[NSP_GROUP]) +} + +var obj, obj$1, obj$2; +// import { AVAILABLE_SERVERS } from './constants' +var AVAILABLE_METHODS = [IO_ROUNDTRIP_LOGIN, IO_HANDSHAKE_LOGIN]; + +var configCheckMap = { + standalone: createConfig$1(false, [BOOLEAN_TYPE]), // to turn on or off some of the features + debugOn: createConfig$1(false, [BOOLEAN_TYPE]), + // useCallbackStyle: createConfig(false, [BOOLEAN_TYPE]), abandoned in 0.6.0 + // Please note the login method will be a public available always + // what if the developer wants to have a socket only setup to do a CORS SPA site + loginHandlerName: createConfig$1(LOGIN_NAME, [STRING_TYPE]), + logoutHandlerName: createConfig$1(LOGOUT_NAME, [STRING_TYPE]), + // just matching the server side + disconnectHandlerName: createConfig$1(DISCONNECT_FN_NAME, [STRING_TYPE]), + switchUserHandlerName: createConfig$1(SWITCH_USER_FN_NAME, [STRING_TYPE]), + // this is for socket.io + loginMethod: createConfig$1(IO_HANDSHAKE_LOGIN, [STRING_TYPE], ( obj = {}, obj[ENUM_KEY] = AVAILABLE_METHODS, obj )), + // we will use this for determine the socket.io client type as well - @TODO remove or rename + useJwt: createConfig$1(true, [BOOLEAN_TYPE, STRING_TYPE]), + // this is going to replace the use of useJwt === string next + authStrKey: createConfig$1(null, [STRING_TYPE]), + hostname: createConfig$1(false, [STRING_TYPE]), + namespace: createConfig$1(JSONQL_PATH, [STRING_TYPE]), + wsOptions: createConfig$1({}, [OBJECT_TYPE]), + // make this null as default don't set this here, only set in the down stream + // serverType: createConfig(null, [STRING_TYPE], {[ENUM_KEY]: AVAILABLE_SERVERS}), + // we require the contract already generated and pass here + contract: createConfig$1({}, [OBJECT_TYPE], ( obj$1 = {}, obj$1[CHECKER_KEY] = isContract, obj$1 )), + enableAuth: createConfig$1(false, [BOOLEAN_TYPE]), + token: createConfig$1(false, [STRING_TYPE]) +}; + +// socket client +var socketCheckMap = {}; +socketCheckMap[SOCKET_TYPE_KEY] = createConfig$1(null, [STRING_TYPE], ( obj$2 = {}, obj$2[ALIAS_KEY] = SOCKET_TYPE_CLIENT_ALIAS, obj$2 )); + +var wsCoreCheckMap = Object.assign(configCheckMap, socketCheckMap); + +// constant props +var wsCoreConstProps = { + log: null, + // contract: null, + eventEmitter: null, + // we unify the two different client into one now + // only expect different parameter + nspClient: null, + nspAuthClient: null, + // contructed path + wssPath: '' +}; + +// create options + +/** + * We need this to find the socket server type + * @param {*} config + * @return {string} the name of the socket server if any + */ +function checkSocketClientType(config) { + return checkConfig(config, socketCheckMap) +} + +/** + * 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 + */ +function createCombineConfigCheck(configCheckMap, constProps) { + var combineCheckMap = Object.assign({}, configCheckMap, wsCoreCheckMap); + var combineConstProps = Object.assign({}, constProps, wsCoreConstProps); + return function (config) { return checkConfigAsync(config, combineCheckMap, combineConstProps); } +} + +/** + * Taking the `then` part from the method below + * @param {object} opts + * @return {promise} opts all done + */ +function postCheckInjectOpts(opts) { + return Promise.resolve(opts) + .then(function (opts) { + if (!opts.hostname) { + opts.hostname = getHostName(); + } + // @TODO the contract now will supply the namespace information + // and we need to use that to group the namespace call + opts.wssPath = fixWss([opts.hostname, opts.namespace].join('/'), opts.serverType); + // get the log function here + opts.log = getLogFn(opts); + + opts.eventEmitter = getEventEmitter(opts); + + return 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} + */ +function createRequiredParams(opts) { + return { + opts: opts, + nspMap: getNspInfoByConfig(opts), + ee: opts.eventEmitter + } +} + +// the top level API + + +/** + * 0.5.0 we break up the wsClientCore in two parts one without the config check + * @param {function} frameworkSocketEngine + * @param {object} config the already checked config + */ +function wsClientCoreAction(frameworkSocketEngine, config) { + return postCheckInjectOpts(config) + // the following two moved to wsPostConfig + .then(createRequiredParams) + .then( + function (ref) { + var opts = ref.opts; + var nspMap = ref.nspMap; + var ee = ref.ee; + + return frameworkSocketEngine(opts, nspMap, ee); + } + ) + .then( + function (ref) { + var opts = ref.opts; + var nspMap = ref.nspMap; + var ee = ref.ee; + + return generator(opts, nspMap, ee); + } + ) + .catch(function (err) { + console.error("jsonql-ws-core-client init error", err); + }) +} + +// since both the ws and io version are +// pre-defined in the client-generator +// and this one will have the same parameters +// and the callback is identical + +/** + * wrapper method to create a nsp without login + * @param {string|boolean} namespace namespace url could be false + * @param {object} opts configuration + * @return {object} ws client instance + */ +function createNspClient(namespace, opts) { + var hostname = opts.hostname; + var wssPath = opts.wssPath; + var wsOptions = opts.wsOptions; + var nspClient = opts.nspClient; + var url = namespace ? [hostname, namespace].join('/') : wssPath; + return nspClient(url, wsOptions) +} + +/** + * wrapper method to create a nsp with token auth + * @param {string} namespace namespace url + * @param {object} opts configuration + * @return {object} ws client instance + */ +function createNspAuthClient(namespace, opts) { + var hostname = opts.hostname; + var wssPath = opts.wssPath; + var token = opts.token; + var wsOptions = opts.wsOptions; + var nspAuthClient = opts.nspAuthClient; + var url = namespace ? [hostname, namespace].join('/') : wssPath; + if (token && typeof token !== 'string') { + throw new Error(("Expect token to be string, but got " + token)) + } + return nspAuthClient(url, token, wsOptions) +} + +// this use by client-event-handler + +/** + * trigger errors on all the namespace onError handler + * @param {object} ee Event Emitter + * @param {array} namespaces nsps string + * @param {string} message optional + * @return {void} + */ +function triggerNamespacesOnError(ee, namespaces, message) { + namespaces.forEach( function (namespace) { + ee.$trigger( + createEvt(namespace, ON_ERROR_FN_NAME$1), + [{ message: message, namespace: namespace }] + ); + }); +} + +/** + * Handle the onerror callback + * @param {object} ee event emitter + * @param {string} namespace which namespace has error + * @param {*} err error object + * @return {void} + */ +var handleNamespaceOnError = function (ee, namespace, err) { + ee.$trigger(createEvt(namespace, ON_ERROR_FN_NAME$1), [err]); +}; + +// This is share between different clients so we export it + +/** + * A Event handler placeholder when it's not connect to the private nsp + * @param {string} namespace nsp + * @param {object} ee EventEmitter + * @param {object} opts configuration + * @return {void} + */ +var notLoginWsHandler = function (namespace, ee, opts) { + var log = opts.log; + ee.$only( + createEvt(namespace, EMIT_EVT), + function notLoginHandlerCallback(resolverName, args) { + log('[notLoginHandler] hijack the ws call', namespace, resolverName, args); + var error = { + message: NOT_LOGIN_ERR_MSG + }; + // It should just throw error here and should not call the result + // because that's channel for handling normal event not the fake one + ee.$call(createEvt(namespace, resolverName, ON_ERROR_FN_NAME$1), [ error ]); + // also trigger the result handler, but wrap inside the error key + ee.$call(createEvt(namespace, resolverName, ON_RESULT_FN_NAME$1), [{ error: error }]); + } + ); +}; + +/** + * A Event handler placeholder when it's not connect to any nsp + * @param {string} namespace nsp + * @param {object} ee EventEmitter + * @param {object} opts configuration + * @return {void} + */ +var disconnectedHandler = function (namespace, ee, opts) { + var log = opts.log; + ee.$only( + createEvt(namespace, EMIT_EVT), + function disconnectedHandlerCallback(resolverName, args) { + log("[disconnectedHandler] hijack the ws call", namespace, resolverName, args); + var error = { + message: DISCONNECTED_ERROR_MSG + }; + ee.$call(createEvt(namespace, resolverName, ON_ERROR_FN_NAME$1), [ error ]); + // also trigger the result handler, but wrap inside the error key + ee.$call(createEvt(namespace, resolverName, ON_RESULT_FN_NAME$1), [{ error: error }]); + } + ); +}; + +/** + * get the private namespace + * @param {array} namespaces array + * @return {*} string on success + */ +var getPrivateNamespace = function (namespaces) { return ( + namespaces.length > 1 ? namespaces[0] : false +); }; + +/** + * Only when there is a private namespace then we bind to this event + * @param {object} nsps the available nsp(s) + * @param {array} namespaces available namespace + * @param {object} ee eventEmitter + * @param {object} opts configuration + * @return {void} + */ +var logoutEvtHandler = function (nsps, namespaces, ee, opts) { + var log = opts.log; + // this will be available regardless enableAuth + // because the server can log the client out + ee.$on(LOGOUT_EVENT_NAME$1, function logoutEvtHandlerAction() { + var privateNamespace = getPrivateNamespace(namespaces); + log((LOGOUT_EVENT_NAME$1 + " event triggered")); + // disconnect(nsps, opts.serverType) + // we need to issue error to all the namespace onError handler + triggerNamespacesOnError(ee, [privateNamespace], LOGOUT_EVENT_NAME$1); + // rebind all of the handler to the fake one + log(("logout from " + privateNamespace)); + + clearMainEmitEvt(ee, privateNamespace); + // we need to issue one more call to the server before we disconnect + // now this is a catch 22, here we are not suppose to do anything platform specific + // so that should fire before trigger this event + // clear out the nsp + nsps[privateNamespace] = null; + // add a NOT LOGIN error if call + notLoginWsHandler(privateNamespace, ee, opts); + }); +}; + +/** + * The disconnect event handler, now we log the client out from everything + * @TODO now we are another problem they disconnect, how to reconnect + * @param {object} nsps the available nsp(s) + * @param {array} namespaces available namespace + * @param {object} ee eventEmitter + * @param {object} opts configuration + * @return {void} + */ +var disconnectHandler = function (nsps, namespaces, ee, opts) { + var log = opts.log; + ee.$on(DISCONNECT_EVENT_NAME, function disconnectEvtHandler() { + triggerNamespacesOnError(ee, namespaces, DISCONNECT_EVENT_NAME); + namespaces.forEach( function (namespace) { + log(("disconnect from " + namespace)); + + clearMainEmitEvt(ee, namespace); + nsps[namespace] = null; + disconnectedHandler(namespace, ee, opts); + }); + }); +}; + +/** + * centralize all the comm in one place + * @param {object} opts configuration + * @param {object} ee Event Emitter instance + * @param {function} bindWsHandler binding the ee to ws --> this is the core bit + * @param {object} nsps namespaced nsp + * @return {void} nothing + */ +function clientEventHandler$1(opts, ee, bindSocketEventHandler, nsps) { + // since all these params already in the opts + var nspMap = opts.nspMap; + var log = opts.log; + var namespaces = nspMap.namespaces; + // @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 + var privateNamespace = getPrivateNamespace(namespaces); + var isPrivate = false; + var hasPrivate = false; + // loop + // @BUG for io this has to be in order the one with auth need to get call first + // The order of login is very import we need to run in order here to make sure + // one is execute then the other + namespaces.forEach(function (namespace) { + isPrivate = privateNamespace === namespace; + if (!hasPrivate) { + hasPrivate = isPrivate; + } + if (nsps[namespace]) { + + log('[call bindWsHandler]', isPrivate, namespace); + var args = [namespace, nsps[namespace], ee, isPrivate, opts]; + + if (opts.serverType === SOCKET_IO) { + var nspGroup = nspMap.nspGroup; + args.push(nspGroup[namespace]); + } + Reflect.apply(bindSocketEventHandler, null, args); + } else { + // a dummy placeholder + // @TODO but it should be a not connect handler + // when it's not login (or fail) this should be handle differently + notLoginWsHandler(namespace, ee, opts); + } + }); + // logout event handler + if (hasPrivate) { + log("Has private and add logoutEvtHandler"); + + logoutEvtHandler(nsps, namespaces, ee, opts); + } + // finally the disconnect event handlers + disconnectHandler(nsps, namespaces, ee, opts); +} + +/** + * After a long period of struggle with the architect problem. Comes to a conclusion - it was shit. + * + * Instead of think of it from a host / slave structure. Should take a higher approach to look at it like + * onion skins. + * + * At the moment, the ws client module export back the `configCheckMap` and `constProps` then back in here + * which is very messy. + */ + +/** + * Create a combine client + * @param {function} httpClientConstructor the method generate the http client + * @param {function} wsClientEngine the core socket engine + * @param {object} configCheckMap the configuration check map + * @param {object} constProps props that add to the config post check + * @return {function} (config) => combine client + */ +function createCombineClient(httpClientConstructor, wsClientEngine, configCheckMap, constProps) { + var checkConfigFn = createCombineConfigCheck(configCheckMap, constProps); + /** + * This will become the final interace facing the app to use + */ + return function (config) { + if ( config === void 0 ) config = {}; + + return checkConfigFn(config) + .then(function (opts) { + // this constructor should not need to check the config again + return httpClientConstructor(opts) + }) + .then(function (httpClient) { + var socketClient = wsClientCoreAction(wsClientEngine, opts); + httpClient[SOCKET_NAME] = socketClient; + return httpClient + }); + } +} + +// this is a wrapper + +/** + * Overload the createCombineCreate to create a combine http / ws client + * @param {object} configCheckMap + * @param {object} constProps + * @return {function} to accept config then generate the client + */ +function createCombineWsClientConstructor(frameworkSocketEngine) { + + return function createCombineWsClient(httpClientConstructor, configCheckMap, constProps) { + var localConstProps = Object.assign({}, constProps, wsClientConstProps); + + return createCombineClient( + httpClientConstructor, + frameworkSocketEngine, + configCheckMap, + localConstProps + ) + } +} + +// pass the different type of ws to generate the client + +/** + * The bug was in the wsOptions where ws don't need it but socket.io do + * therefore the object was pass as second parameter! + * @param {object} WebSocket the client or node version of ws + * @param {boolean} auth if it's auth then 3 param or just one + */ +function initWebSocketClient(WebSocket, auth) { + if ( auth === void 0 ) auth = false; + + if (auth === false) { + return function createWsClientHandler(url) { + return new WebSocket(fixWss(url)) + } + } + + /** + * Create a client with auth token + * @param {string} url start with ws:// @TODO check this? + * @param {string} token the jwt token + * @return {object} ws instance + */ + return function createWsAuthClientHandler(url, token) { + var ws_url = fixWss(url); + // console.log('what happen here?', url, ws_url, token) + var uri = token && typeof token === 'string' ? (ws_url + "?" + TOKEN_PARAM_NAME + "=" + token) : ws_url; + try { + return new WebSocket(uri) + } catch(e) { + console.error('WebSocket Connection Error', e); + return false + } + } +} + +/** + * Because the nsps can be throw away so it doesn't matter the scope + * this will get reuse again + * @param {object} opts configuration + * @param {object} nspMap from contract + * @param {string|null} token whether we have the token at run time + * @return {object} nsps namespace with namespace as key + */ +var createNspAction$1 = function(opts, nspMap, token) { + var log = opts.log; + var publicNamespace = nspMap.publicNamespace; + var namespaces = nspMap.namespaces; + + return { + nsps: (function () { + var obj; + + // first we need to binding all the events handler + if (opts.enableAuth) { // && opts.useJwt + + return namespaces.map(function (namespace, i) { + var obj, obj$1, obj$2; + + if (i === 0) { + if (token) { + opts.token = token; + log('create createNspAuthClient at run time'); + return ( obj = {}, obj[namespace] = createNspAuthClient(namespace, opts), obj ) + } + return ( obj$1 = {}, obj$1[namespace] = false, obj$1 ) + } + return ( obj$2 = {}, obj$2[namespace] = createNspClient(namespace, opts), obj$2 ) + }).reduce(function (first, next) { return Object.assign(first, next); }, {}) + } + + // standard without login + return ( obj = {}, obj[publicNamespace] = createNspClient(false, opts), obj ) + })() + } +}; + +// @BUG when call disconnected + +/** + * create a login event handler + * @param {object} opts configurations + * @param {object} nspMap contain all the required info + * @param {object} ee event emitter + * @return {void} + */ +function loginEventHandler(opts, nspMap, ee) { + var log = opts.log; + var namespaces = nspMap.namespaces; + + ee.$only(LOGIN_EVENT_NAME, function loginEventHandlerCallback(tokenFromLoginAction) { + + log('createClient LOGIN_EVENT_NAME $only handler'); + + clearMainEmitEvt(ee, namespaces); + // console.log('LOGIN_EVENT_NAME', token) + var newNsps = createNspAction(opts, nspMap, tokenFromLoginAction); + // rebind it + Reflect.apply( + clientEventHandler, // @NOTE is this the problem that cause the hang up? + null, + args.concat([newNsps.namespaces, newNsps.nsps]) + ); + }); +} + +/** + * Checks if `value` is classified as an `Array` object. + * + * @static + * @memberOf _ + * @since 0.1.0 + * @category Lang + * @param {*} value The value to check. + * @returns {boolean} Returns `true` if `value` is an array, else `false`. + * @example + * + * _.isArray([1, 2, 3]); + * // => true + * + * _.isArray(document.body.children); + * // => false + * + * _.isArray('abc'); + * // => false + * + * _.isArray(_.noop); + * // => false + */ +var isArray$1 = Array.isArray; + +/** Detect free variable `global` from Node.js. */ +var freeGlobal$1 = typeof global$1 == 'object' && global$1 && global$1.Object === Object && global$1; + +/** Detect free variable `self`. */ +var freeSelf$1 = typeof self == 'object' && self && self.Object === Object && self; + +/** Used as a reference to the global object. */ +var root$1 = freeGlobal$1 || freeSelf$1 || Function('return this')(); + +/** Built-in value references. */ +var Symbol$1 = root$1.Symbol; + +/** Used for built-in method references. */ +var objectProto$f = Object.prototype; + +/** Used to check objects for own properties. */ +var hasOwnProperty$c = objectProto$f.hasOwnProperty; + +/** + * Used to resolve the + * [`toStringTag`](http://ecma-international.org/ecma-262/7.0/#sec-object.prototype.tostring) + * of values. + */ +var nativeObjectToString$2 = objectProto$f.toString; + +/** Built-in value references. */ +var symToStringTag$2 = Symbol$1 ? Symbol$1.toStringTag : undefined; + +/** + * A specialized version of `baseGetTag` which ignores `Symbol.toStringTag` values. + * + * @private + * @param {*} value The value to query. + * @returns {string} Returns the raw `toStringTag`. + */ +function getRawTag$1(value) { + var isOwn = hasOwnProperty$c.call(value, symToStringTag$2), + tag = value[symToStringTag$2]; + + try { + value[symToStringTag$2] = undefined; + var unmasked = true; + } catch (e) {} + + var result = nativeObjectToString$2.call(value); + if (unmasked) { + if (isOwn) { + value[symToStringTag$2] = tag; + } else { + delete value[symToStringTag$2]; + } + } + return result; +} + +/** Used for built-in method references. */ +var objectProto$g = Object.prototype; + +/** + * Used to resolve the + * [`toStringTag`](http://ecma-international.org/ecma-262/7.0/#sec-object.prototype.tostring) + * of values. + */ +var nativeObjectToString$3 = objectProto$g.toString; + +/** + * Converts `value` to a string using `Object.prototype.toString`. + * + * @private + * @param {*} value The value to convert. + * @returns {string} Returns the converted string. + */ +function objectToString$1(value) { + return nativeObjectToString$3.call(value); +} + +/** `Object#toString` result references. */ +var nullTag$1 = '[object Null]', + undefinedTag$1 = '[object Undefined]'; + +/** Built-in value references. */ +var symToStringTag$3 = Symbol$1 ? Symbol$1.toStringTag : undefined; + +/** + * The base implementation of `getTag` without fallbacks for buggy environments. + * + * @private + * @param {*} value The value to query. + * @returns {string} Returns the `toStringTag`. + */ +function baseGetTag$1(value) { + if (value == null) { + return value === undefined ? undefinedTag$1 : nullTag$1; + } + return (symToStringTag$3 && symToStringTag$3 in Object(value)) + ? getRawTag$1(value) + : objectToString$1(value); +} + +/** + * Checks if `value` is object-like. A value is object-like if it's not `null` + * and has a `typeof` result of "object". + * + * @static + * @memberOf _ + * @since 4.0.0 + * @category Lang + * @param {*} value The value to check. + * @returns {boolean} Returns `true` if `value` is object-like, else `false`. + * @example + * + * _.isObjectLike({}); + * // => true + * + * _.isObjectLike([1, 2, 3]); + * // => true + * + * _.isObjectLike(_.noop); + * // => false + * + * _.isObjectLike(null); + * // => false + */ +function isObjectLike$1(value) { + return value != null && typeof value == 'object'; +} + +// bunch of generic helpers + +/** + * DIY in Array + * @param {array} arr to check from + * @param {*} value to check against + * @return {boolean} true on found + */ +var inArray$2 = function (arr, value) { return !!arr.filter(function (a) { return a === value; }).length; }; + +/** + * parse string to json or just return the original value if error happened + * @param {*} n input + * @param {boolean} [t=true] or throw + * @return {*} json object on success + */ +var parseJson = function(n, t) { + if ( t === void 0 ) t=true; + + try { + return JSON.parse(n) + } catch(e) { + if (t) { + return n + } + throw new Error(e) + } +}; + +/** + * @param {object} obj for search + * @param {string} key target + * @return {boolean} true on success + */ +var isObjectHasKey$2 = function(obj, key) { + try { + var keys = Object.keys(obj); + return inArray$2(keys, key) + } catch(e) { + // @BUG when the obj is not an OBJECT we got some weird output + return false + } +}; + +/** + * create a event name + * @param {string[]} args + * @return {string} event name for use + */ +var createEvt$1 = function () { + var args = [], len = arguments.length; + while ( len-- ) args[ len ] = arguments[ len ]; + + return args.join('_'); +}; + +/** + * small util to make sure the return value is valid JSON object + * @param {*} n input + * @return {object} correct JSON object + */ +var toJson = function (n) { + if (typeof n === 'string') { + return parseJson(n) + } + return parseJson(JSON.stringify(n)) +}; + +// generic placeholder function +var nil$1 = function () { return false; }; + +/** + * This is a custom error to throw whenever a error happen inside the jsonql + * This help us to capture the right error, due to the call happens in sequence + * @param {string} message to tell what happen + * @param {mixed} extra things we want to add, 500? + */ +var JsonqlError$2 = /*@__PURE__*/(function (Error) { + function JsonqlError() { + var args = [], len = arguments.length; + while ( len-- ) args[ len ] = arguments[ len ]; + + Error.apply(this, args); + + this.message = args[0]; + this.detail = args[1]; + + this.className = JsonqlError.name; + + if (Error.captureStackTrace) { + Error.captureStackTrace(this, JsonqlError); + // this.detail = this.stack; + } + } + + if ( Error ) JsonqlError.__proto__ = Error; + JsonqlError.prototype = Object.create( Error && Error.prototype ); + JsonqlError.prototype.constructor = JsonqlError; + + var staticAccessors = { name: { configurable: true },statusCode: { configurable: true } }; + + staticAccessors.name.get = function () { + return 'JsonqlError'; + }; + + staticAccessors.statusCode.get = function () { + return NO_STATUS_CODE; + }; + + Object.defineProperties( JsonqlError, staticAccessors ); + + return JsonqlError; +}(Error)); + +/** + * @param {boolean} sec return in second or not + * @return {number} timestamp + */ +var timestamp = function (sec) { + if ( sec === void 0 ) sec = false; + + var time = Date.now(); + return sec ? Math.floor( time / 1000 ) : time +}; + +/** `Object#toString` result references. */ +var stringTag$3 = '[object String]'; + +/** + * Checks if `value` is classified as a `String` primitive or object. + * + * @static + * @since 0.1.0 + * @memberOf _ + * @category Lang + * @param {*} value The value to check. + * @returns {boolean} Returns `true` if `value` is a string, else `false`. + * @example + * + * _.isString('abc'); + * // => true + * + * _.isString(1); + * // => false + */ +function isString$3(value) { + return typeof value == 'string' || + (!isArray$1(value) && isObjectLike$1(value) && baseGetTag$1(value) == stringTag$3); +} + +// There are the socket related methods ported back from + +var WS_KEYS = [ + WS_REPLY_TYPE, + WS_EVT_NAME, + WS_DATA_NAME +]; + +/** + * The ws doesn't have a acknowledge callback like socket.io + * so we have to DIY one for ws and other that doesn't have it + * @param {string} type of reply + * @param {string} resolverName which is replying + * @param {*} data payload + * @param {array} [ts= []] the last received ts, if any + * @return {string} stringify json + */ +var createWsReply = function (type, resolverName, data, ts) { + var obj, obj$1; + + if ( ts === void 0 ) ts = []; + ts.push(timestamp()); + return JSON.stringify(( obj$1 = { + data: ( obj = {}, obj[WS_REPLY_TYPE] = type, obj[WS_EVT_NAME] = resolverName, obj[WS_DATA_NAME] = toJson(data), obj ) + }, obj$1[TIMESTAMP_PARAM_NAME] = ts, obj$1 )) +}; + +// extended function +var createReplyMsg = function (resolverName, data, ts) { + if ( ts === void 0 ) ts = []; + + return ( + createWsReply(EMIT_REPLY_TYPE, resolverName, data, ts) +); +}; + +/** + * @param {string|object} payload should be string when reply but could be transformed + * @return {boolean} true is OK + */ +var isWsReply = function (payload) { + var json = isString$3(payload) ? toJson(payload) : payload; + var data = json.data; + if (data) { + var result = WS_KEYS.filter(function (key) { return isObjectHasKey$2(data, key); }); + return (result.length === WS_KEYS.length) ? data : false + } + return false +}; + +/** + * @param {string|object} data received data + * @param {function} [cb=nil] this is for extracting the TS field or when it's error + * @return {object} false on failed + */ +var extractWsPayload = function (payload, cb) { + if ( cb === void 0 ) cb = nil$1; + + try { + var json = toJson(payload); + // now handle the data + var _data; + if ((_data = isWsReply(json)) !== false) { + // note the ts property is on its own + cb(TIMESTAMP_PARAM_NAME, json[TIMESTAMP_PARAM_NAME]); + + return { + data: toJson(_data[WS_DATA_NAME]), + resolverName: _data[WS_EVT_NAME], + type: _data[WS_REPLY_TYPE] + } + } + throw new JsonqlError$2('payload can not decoded', payload) + } catch(e) { + return cb(ERROR_KEY, e) + } +}; + +// the WebSocket main handler + +/** + * in some edge case we might not even have a resolverName, then + * we issue a global error for the developer to catch it + * @param {object} ee event emitter + * @param {string} namespace nsp + * @param {string} resolverName resolver + * @param {object} json decoded payload or error object + * @return {undefined} nothing return + */ +var errorTypeHandler = function (ee, namespace, resolverName, json) { + var evt = [namespace]; + if (resolverName) { + evt.push(resolverName); + } + evt.push(ON_ERROR_FN_NAME); + var evtName = Reflect.apply(createEvt$1, null, evt); + // test if there is a data field + var payload = json.data || json; + ee.$trigger(evtName, [payload]); +}; + +/** + * Handle the logout event when it's enableAuth + * @param {object} ee eventEmitter + * @return {void} + */ +var logoutEventHandler = function (ee) { + // listen to the LOGOUT_EVENT_NAME when this is a private nsp + ee.$on(LOGOUT_EVENT_NAME, function closeEvtHandler() { + try { + log('terminate ws connection'); + ws.terminate(); + } catch(e) { + console.error('ws.terminate error', e); + } + }); +}; + +/** + * Binding the event to socket normally + * @param {string} namespace + * @param {object} ws the nsp + * @param {object} ee EventEmitter + * @param {boolean} isPrivate to id if this namespace is private or not + * @param {object} opts configuration + * @return {object} promise resolve after the onopen event + */ +function socketEventHandler(namespace, ws, ee, isPrivate, opts) { + var log = opts.log; + + log("log test, isPrivate:", isPrivate); + // connection open + ws.onopen = function onOpenCallback() { + + log('ws.onopen listened'); + // we just call the onReady + 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); + } + // add listener only after the open is called + ee.$only( + createEvt$1(namespace, EMIT_REPLY_TYPE), + /** + * actually send the payload to server + * @param {string} resolverName + * @param {array} args NEED TO CHECK HOW WE PASS THIS! + */ + function wsMainOnEvtHandler(resolverName, args) { + + var payload = createReplyMsg(resolverName, args); + log('ws.onopen.send', resolverName, args, payload); + + ws.send(payload); + } + ); + }; + + // reply + // If we change it to the event callback style + // then the payload will just be the payload and fucks up the extractWsPayload call @TODO + ws.onmessage = function onMessageCallback(payload) { + // console.log(`on.message`, typeof payload, payload) + try { + var json = extractWsPayload(payload); + var resolverName = json.resolverName; + var type = json.type; + + log('Hear from server', type, json); + + switch (type) { + case EMIT_REPLY_TYPE: + var e1 = createEvt$1(namespace, resolverName, ON_MESSAGE_FN_NAME); + var r = ee.$trigger(e1, [json]); + log("EMIT_REPLY_TYPE", e1, r); + break + case ACKNOWLEDGE_REPLY_TYPE: + var e2 = createEvt$1(namespace, resolverName, ON_RESULT_FN_NAME); + var x2 = ee.$trigger(e2, [json]); + log("ACKNOWLEDGE_REPLY_TYPE", e2, x2); + break + case ERROR_TYPE: + // this is handled error and we won't throw it + // we need to extract the error from json + log("ERROR_TYPE"); + errorTypeHandler(ee, namespace, resolverName, json); + 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 + log('Unhandled event!', json); + errorTypeHandler(ee, namespace, resolverName, json); + // let error = {error: {'message': 'Unhandled event!', type}}; + // ee.$trigger(createEvt(namespace, resolverName, ON_RESULT_FN_NAME), [error]) + } + } catch(e) { + console.error("ws.onmessage error", e); + errorTypeHandler(ee, namespace, false, e); + } + }; + // when the server close the connection + ws.onclose = function onCloseCallback() { + log('ws.onclose callback'); + // @TODO what to do with this + // ee.$trigger(LOGOUT_EVENT_NAME, [namespace]) + }; + // add a onerror event handler here + ws.onerror = function onErrorCallback(err) { + // trigger a global error event + log("ws.onerror", err); + handleNamespaceOnError(ee, namespace, err); + }; + + if (isPrivate) { + logoutEventHandler(ee); + } +} + +// actually binding the event client to the socket client + +/** + * 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 + * @return {object} what comes in what goes out + */ +function createNsp(opts, nspMap, ee) { + // arguments for clientEventHandler + var args = [opts, ee, socketEventHandler]; + + // now create the nsps + var namespaces = nspMap.namespaces; + var token = opts.token; + var ref = createNspAction$1(opts, nspMap, token); + var nsps = ref.nsps; + // binding the listeners - and it will listen to LOGOUT event + // to unbind itself, and the above call will bind it again + Reflect.apply(clientEventHandler$1, null, args.concat([namespaces, nsps])); + // setup listener for the login event + if (opts.enableAuth) { + loginEventHandler(ee, namespaces, nspMap); + } + // return what input + return { opts: opts, nspMap: nspMap, ee: ee } +} + +// breaking up the create-nsp.js file + +// share method to create the wsClientResolver + +/** + * Create the framework <---> jsonql client binding + * @param {object} frameworkModule the different WebSocket module + * @return {function} the wsClientResolver + */ +function bindFrameworkToJsonql(frameworkModule) { + + var publicClient = initWebSocketClient(frameworkModule); + var privateClient = initWebSocketClient(frameworkModule, true); + + /** + * wsClientResolver + * @param {object} opts configuration + * @param {object} nspMap from the contract + * @param {object} ee instance of the eventEmitter + * @return {object} passing the same 3 input out with additional in the opts + */ + return function createClientBindingAction(opts, nspMap, ee) { + opts.nspClient = publicClient; + opts.nspAuthClient = privateClient; + // @1.0.7 remove later once everything fixed + var log = opts.log; + if (log && typeof log === 'function') { + log('@jsonql/ws ee', ee.name); + log('@jsonql/ws createClientResolver', opts); + } + // console.log(`contract`, opts.contract) + return createNsp(opts, nspMap, ee) + } +} + +// this will be the news style interface that will pass to the jsonql-ws-client + +/** + * @param {object} opts configuration + * @param {object} nspMap from the contract + * @param {object} ee instance of the eventEmitter + * @return {object} passing the same 3 input out with additional in the opts + */ +var nodeFrameworkSocketEngine = bindFrameworkToJsonql(WebSocket); + +// this is for node upstream client to include and construct their own client + +var createCombineWsClient = createCombineWsClientConstructor(nodeFrameworkSocketEngine); + +exports.EventEmitterClass = EventService; +exports.checkSocketClientType = checkSocketClientType; +exports.createCombineWsClient = createCombineWsClient; +exports.getEventEmitter = getEventEmitter; //# sourceMappingURL=node.js.map diff --git a/packages/@jsonql/ws/node.js.map b/packages/@jsonql/ws/node.js.map index dec3b7b6..457220e3 100644 --- a/packages/@jsonql/ws/node.js.map +++ b/packages/@jsonql/ws/node.js.map @@ -1 +1 @@ -{"version":3,"file":"node.js","sources":[],"sourcesContent":[],"names":[],"mappings":""} \ No newline at end of file +{"version":3,"file":"node.js","sources":["src/options/index.js","node_modules/_rollup-plugin-node-globals@1.4.0@rollup-plugin-node-globals/src/global.js","../../ws-client-core/node_modules/lodash-es/_arrayMap.js","../../ws-client-core/node_modules/lodash-es/isArray.js","../../ws-client-core/node_modules/lodash-es/_objectToString.js","../../ws-client-core/node_modules/lodash-es/isObjectLike.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-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/lodash-es/_overArg.js","../../ws-client-core/node_modules/lodash-es/_arrayFilter.js","../../ws-client-core/node_modules/lodash-es/_createBaseFor.js","../../ws-client-core/node_modules/lodash-es/_baseTimes.js","../../ws-client-core/node_modules/lodash-es/stubFalse.js","../../ws-client-core/node_modules/lodash-es/_isIndex.js","../../ws-client-core/node_modules/lodash-es/isLength.js","../../ws-client-core/node_modules/lodash-es/_baseUnary.js","../../ws-client-core/node_modules/lodash-es/_isPrototype.js","../../ws-client-core/node_modules/lodash-es/isObject.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/_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/_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/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/identity.js","../../ws-client-core/node_modules/lodash-es/_baseProperty.js","../../ws-client-core/node_modules/jsonql-params-validator/src/object.js","../../ws-client-core/node_modules/jsonql-errors/src/validation-error.js","../../ws-client-core/node_modules/jsonql-params-validator/src/validator.js","../../ws-client-core/node_modules/lodash-es/_copyArray.js","../../ws-client-core/node_modules/lodash-es/_safeGet.js","../../ws-client-core/node_modules/lodash-es/_nativeKeysIn.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/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-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-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/check-options-sync.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/node_modules/jsonql-utils/src/generic.js","../../ws-client-core/node_modules/jsonql-errors/src/500-error.js","../../ws-client-core/node_modules/jsonql-errors/src/resolver-not-found-error.js","../../ws-client-core/node_modules/jsonql-errors/src/server-error.js","../../ws-client-core/node_modules/jsonql-utils/src/contract.js","../../ws-client-core/node_modules/jsonql-utils/src/namespace.js","../../ws-client-core/src/utils/helpers.js","../../ws-client-core/src/core/setup-auth-methods.js","../../ws-client-core/src/options/constants.js","../../ws-client-core/src/core/respond-handler.js","../../ws-client-core/src/core/action-call.js","../../ws-client-core/src/core/setup-send-method.js","../../ws-client-core/src/core/setup-resolver.js","../../ws-client-core/src/core/resolver-methods.js","../../ws-client-core/src/core/setup-intercom.js","../../ws-client-core/src/core/generator.js","../../ws-client-core/src/options/index.js","../../ws-client-core/src/api.js","../../ws-client-core/src/share/create-nsp-client.js","../../ws-client-core/src/share/trigger-namespaces-on-error.js","../../ws-client-core/src/share/client-event-handler.js","../../ws-client-core/src/create-combine-client.js","src/create-combine-client.js","src/core/create-websocket-binding/init-websocket-client.js","src/core/create-nsp/login-event-handler.js","node_modules/_lodash-es@4.17.15@lodash-es/isArray.js","node_modules/_lodash-es@4.17.15@lodash-es/_objectToString.js","node_modules/_lodash-es@4.17.15@lodash-es/isObjectLike.js","node_modules/_jsonql-utils@1.1.3@jsonql-utils/src/generic.js","node_modules/_jsonql-utils@1.1.3@jsonql-utils/src/timestamp.js","node_modules/_jsonql-utils@1.1.3@jsonql-utils/src/socket.js","src/core/create-nsp/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/module.js"],"sourcesContent":["// 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","export default (typeof global !== \"undefined\" ? global :\n typeof self !== \"undefined\" ? self :\n typeof window !== \"undefined\" ? window : {});\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 * 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 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 * 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 * 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","// 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\nexport const 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)`\nexport const PARAMS_NOT_ARRAY_ERR = `params is not an array! Did something gone wrong when you generate the contract.json?`\nexport const EXCEPTION_CASE_ERR = 'Could not understand your arguments and parameter structure!'\nexport const UNUSUAL_CASE_ERR = 'This is an unusual situation where the arguments are more than the params, but not mark as spread'\n\n// re-export\nimport * as JSONQL_CONSTANTS from 'jsonql-constants'\n// @TODO the jsdoc return array. and we should also allow array syntax\nexport const DEFAULT_TYPE = JSONQL_CONSTANTS.DEFAULT_TYPE\nexport const ARRAY_TYPE_LFT = JSONQL_CONSTANTS.ARRAY_TYPE_LFT\nexport const ARRAY_TYPE_RGT = JSONQL_CONSTANTS.ARRAY_TYPE_RGT\n\nexport const TYPE_KEY = JSONQL_CONSTANTS.TYPE_KEY\nexport const OPTIONAL_KEY = JSONQL_CONSTANTS.OPTIONAL_KEY\nexport const ENUM_KEY = JSONQL_CONSTANTS.ENUM_KEY\nexport const ARGS_KEY = JSONQL_CONSTANTS.ARGS_KEY\nexport const CHECKER_KEY = JSONQL_CONSTANTS.CHECKER_KEY\nexport const ALIAS_KEY = JSONQL_CONSTANTS.ALIAS_KEY\n\nexport const ARRAY_TYPE = JSONQL_CONSTANTS.ARRAY_TYPE\nexport const OBJECT_TYPE = JSONQL_CONSTANTS.OBJECT_TYPE\nexport const STRING_TYPE = JSONQL_CONSTANTS.STRING_TYPE\nexport const BOOLEAN_TYPE = JSONQL_CONSTANTS.BOOLEAN_TYPE\nexport const NUMBER_TYPE = JSONQL_CONSTANTS.NUMBER_TYPE\nexport const KEY_WORD = JSONQL_CONSTANTS.KEY_WORD\nexport const OR_SEPERATOR = JSONQL_CONSTANTS.OR_SEPERATOR\n\n// not actually in use\n// export const NUMBER_TYPES = JSONQL_CONSTANTS.NUMBER_TYPES;\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","/**\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 * 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 * 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 * 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","/**\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","/** 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","/** 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 * 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","/** 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 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","/**\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","/** 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","/** 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 * 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 * 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 * 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","// validate object type\n\nimport isPlainObject from 'lodash-es/isPlainObject'\nimport filter from 'lodash-es/filter'\n\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","// 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","// 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 // checkIsObject,\n combineFn,\n notEmpty\n} from './index'\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 // UNUSUAL_CASE_ERR\n} from './constants'\nimport { DATA_KEY, ERROR_KEY } from 'jsonql-constants'\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","/**\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","/**\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 * 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 * 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","/** 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","// 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","// 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","// this is port back from the client to share across all projects\nimport merge from 'lodash-es/merge'\nimport { prepareArgsForValidation } from './prepare-args-for-validation'\nimport runValidation from './run-validation'\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 merge(\n runValidation(\n prepareArgsForValidation(config, appProps),\n cb\n ),\n constProps\n )\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'\n// PIA syntax\nexport const isObject = checkIsObject\nexport const isAny = checkIsAny\nexport const isString = checkIsString\nexport const isBoolean = checkIsBoolean\nexport const isNumber = checkIsNumber\nexport const isArray = checkIsArray\nexport const isNotEmpty = notEmpty\n\nimport * as validator from './src/validator'\n\nexport const normalizeArgs = validator.normalizeArgs\nexport const validateSync = validator.validateSync\nexport const validateAsync = validator.validateAsync\n\n// configuration checking\n\nimport * as jsonqlOptions from './src/options'\n\nexport const JSONQL_PARAMS_VALIDATOR_INFO = jsonqlOptions.JSONQL_PARAMS_VALIDATOR_INFO\n\nexport const createConfig = jsonqlOptions.createConfig\nexport const constructConfig = jsonqlOptions.constructConfigFn\n// construct the final output 1.5.2\nexport const checkConfigAsync = jsonqlOptions.getCheckConfigAsync(validator.validateSync)\nexport const checkConfig = jsonqlOptions.getCheckConfig(validator.validateSync)\n\n// export the two extra functions\nimport isInArray from './src/is-in-array'\nimport isObjectHasKeyFn from './src/is-key-in-object'\n\nexport const inArray = isInArray\nexport const isObjectHasKey = isObjectHasKeyFn\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","// 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","/**\n * This is a custom error to throw when server throw a 500\n * This help us to capture the right error, due to the call happens in sequence\n * @param {string} message to tell what happen\n * @param {mixed} extra things we want to add, 500?\n */\nexport default class Jsonql500Error extends Error {\n constructor(...args) {\n super(...args)\n\n this.message = args[0]\n this.detail = args[1]\n\n this.className = Jsonql500Error.name;\n\n if (Error.captureStackTrace) {\n Error.captureStackTrace(this, Jsonql500Error)\n }\n }\n\n static get statusCode() {\n return 500;\n }\n\n static get name() {\n return 'Jsonql500Error';\n }\n\n}\n","/**\n * This is a custom error to throw when could not find the resolver\n * This help us to capture the right error, due to the call happens in sequence\n * @param {string} message to tell what happen\n * @param {mixed} extra things we want to add, 500?\n */\nexport default class JsonqlResolverNotFoundError extends Error {\n constructor(...args) {\n super(...args)\n\n this.message = args[0]\n this.detail = args[1]\n\n this.className = JsonqlResolverNotFoundError.name;\n\n if (Error.captureStackTrace) {\n Error.captureStackTrace(this, JsonqlResolverNotFoundError);\n }\n }\n\n static get statusCode() {\n return 404;\n }\n\n static get name() {\n return 'JsonqlResolverNotFoundError';\n }\n}\n","// this is from an example from Koa team to use for internal middleware ctx.throw\n// but after the test the res.body part is unable to extract the required data\n// I keep this one here for future reference\n\nexport default class JsonqlServerError extends Error {\n\n constructor(statusCode, message) {\n super(message)\n this.statusCode = statusCode;\n this.className = JsonqlServerError.name;\n }\n\n static get name() {\n return 'JsonqlServerError';\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","// 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.publicNamespace ].join('/'),\n [ base , config.privateNamespace ].join('/')\n ]\n }\n return [ base ]\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","// 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(client, resolverName, setupResolver(namespace, resolverName, params, fn, ee, log))\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 createNamespaceErrorHandler(client, opts, ee, nspGroup) {\n return [\n // using the onError as name\n // @TODO we should follow the convention earlier\n // make this a setter for the clientitself\n objDefineProps(client, ON_ERROR_FN_NAME, 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 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 createOnReadyHandler(client, opts, ee) {\n return [\n objDefineProps(client, ON_READY_FN_NAME, 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 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} ","// 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 createNamespaceErrorHandler,\n createOnReadyHandler\n} from './resolver-methods'\nimport {\n setupFinalStep \n} from './setup-final-step'\nimport {\n NSP_GROUP\n} from 'jsonql-constants'\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 generator(opts, nspMap, ee) {\n\n let args = [\n generateResolvers,\n createNamespaceErrorHandler,\n createOnReadyHandler\n ]\n if (opts.enableAuth) {\n args.push(\n createAuthMethods\n )\n } \n // we will always get back the [ obj, opts, ee ]\n // then we only return the obj (wsClient)\n args.push(setupFinalStep)\n // run it\n const fn = Reflect.apply(chainFns, null, args)\n\n return fn(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 { generator } from './core'\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} frameworkSocketEngine \n * @param {object} config the already checked config \n */\nexport function wsClientCoreAction(frameworkSocketEngine, config) {\n return postCheckInjectOpts(config)\n // the following two moved to wsPostConfig\n .then(createRequiredParams)\n .then(\n ({opts, nspMap, ee}) => frameworkSocketEngine(opts, nspMap, ee)\n )\n .then(\n ({opts, nspMap, ee}) => generator(opts, nspMap, ee)\n )\n .catch(err => {\n console.error(`jsonql-ws-core-client init error`, err)\n })\n}\n\n/**\n * The main interface which will generate the socket clients and map all events\n * @param {object} frameworkSocketEngine 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(frameworkSocketEngine, configCheckMap = {}, constProps = {}) {\n // we need to inject property to this client later\n return (config = {}) => checkConfiguration(config, configCheckMap, constProps)\n .then(opts => wsClientCoreAction(frameworkSocketEngine, opts))\n}\n","// since both the ws and io version are\n// pre-defined in the client-generator\n// and this one will have the same parameters\n// and the callback is identical\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 } = opts\n const url = namespace ? [hostname, namespace].join('/') : wssPath\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 } = opts\n const url = namespace ? [hostname, namespace].join('/') : wssPath\n if (token && typeof token !== 'string') {\n throw new Error(`Expect token to be string, but got ${token}`)\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}","// 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\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, SOCKET_IO, DISCONNECTED_ERROR_MSG } from '../options/constants'\nimport { createEvt, clearMainEmitEvt } from '../utils'\nimport { triggerNamespacesOnError } from './trigger-namespaces-on-error'\n\n/**\n * A Event handler 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 */\nconst notLoginWsHandler = (namespace, ee, opts) => {\n const { log } = opts \n ee.$only(\n createEvt(namespace, EMIT_EVT),\n function notLoginHandlerCallback(resolverName, args) {\n log('[notLoginHandler] hijack the ws call', namespace, resolverName, args)\n const error = {\n message: NOT_LOGIN_ERR_MSG\n }\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 handler, but wrap inside the error key\n ee.$call(createEvt(namespace, resolverName, ON_RESULT_FN_NAME), [{ error }])\n }\n )\n}\n\n/**\n * A Event handler 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 */\nconst disconnectedHandler = (namespace, ee, opts) => {\n const { log } = opts \n ee.$only(\n createEvt(namespace, EMIT_EVT),\n function disconnectedHandlerCallback(resolverName, args) {\n log(`[disconnectedHandler] 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 handler, but wrap inside the error key\n ee.$call(createEvt(namespace, resolverName, ON_RESULT_FN_NAME), [{ error }])\n }\n )\n}\n\n/**\n * get the private namespace\n * @param {array} namespaces array\n * @return {*} string on success\n */\nconst getPrivateNamespace = (namespaces) => (\n namespaces.length > 1 ? namespaces[0] : false\n)\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 */\nconst logoutEvtHandler = (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(LOGOUT_EVENT_NAME, function logoutEvtHandlerAction() {\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 handler\n triggerNamespacesOnError(ee, [privateNamespace], LOGOUT_EVENT_NAME)\n // rebind all of the handler 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 notLoginWsHandler(privateNamespace, ee, opts)\n })\n}\n\n/**\n * The disconnect event handler, 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 */\nconst disconnectHandler = (nsps, namespaces, ee, opts) => {\n const { log } = opts \n ee.$on(DISCONNECT_EVENT_NAME, function disconnectEvtHandler() {\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 disconnectedHandler(namespace, ee, opts)\n })\n })\n}\n\n/**\n * centralize all the comm in one place\n * @param {object} opts configuration\n * @param {object} ee Event Emitter instance\n * @param {function} bindWsHandler binding the ee to ws --> this is the core bit\n * @param {object} nsps namespaced nsp\n * @return {void} nothing\n */\nexport function clientEventHandler(opts, ee, bindSocketEventHandler, nsps) {\n // since all these params already in the opts\n const { nspMap, 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 let isPrivate = false\n let hasPrivate = false\n // loop\n // @BUG for io this has to be in order the one with auth need to get call first\n // The order of login is very import we need to run in order here to make sure\n // one is execute then the other\n namespaces.forEach(namespace => {\n isPrivate = privateNamespace === namespace\n if (!hasPrivate) {\n hasPrivate = isPrivate\n }\n if (nsps[namespace]) {\n\n log('[call bindWsHandler]', isPrivate, namespace)\n let args = [namespace, nsps[namespace], ee, isPrivate, opts]\n \n if (opts.serverType === SOCKET_IO) {\n let { nspGroup } = nspMap\n args.push(nspGroup[namespace])\n }\n Reflect.apply(bindSocketEventHandler, null, args)\n } else {\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 notLoginWsHandler(namespace, ee, opts)\n }\n })\n // logout event handler \n if (hasPrivate) {\n log(`Has private and add logoutEvtHandler`)\n\n logoutEvtHandler(nsps, namespaces, ee, opts)\n }\n // finally the disconnect event handlers\n disconnectHandler(nsps, namespaces, ee, opts) \n}\n","/** \n * After a long period of struggle with the architect problem. Comes to a conclusion - it was shit.\n *\n * Instead of think of it from a host / slave structure. Should take a higher approach to look at it like \n * onion skins. \n *\n * At the moment, the ws client module export back the `configCheckMap` and `constProps` then back in here\n * which is very messy.\n */\nimport { createCombineConfigCheck } from './options'\nimport { wsClientCoreAction } from './api'\nimport { SOCKET_NAME } from 'jsonql-constants'\n\n/**\n * Create a combine client\n * @param {function} httpClientConstructor the method generate the http client \n * @param {function} wsClientEngine the core socket engine \n * @param {object} configCheckMap the configuration check map \n * @param {object} constProps props that add to the config post check\n * @return {function} (config) => combine client \n */\nfunction createCombineClient(httpClientConstructor, wsClientEngine, configCheckMap, constProps) {\n const checkConfigFn = createCombineConfigCheck(configCheckMap, constProps)\n /**\n * This will become the final interace facing the app to use\n */\n return (config = {}) => checkConfigFn(config)\n .then(opts => {\n // this constructor should not need to check the config again\n return httpClientConstructor(opts)\n })\n .then(httpClient => {\n const socketClient = wsClientCoreAction(wsClientEngine, opts)\n httpClient[SOCKET_NAME] = socketClient \n return httpClient\n })\n}\n\nexport { createCombineClient }\n","// this is a wrapper \n// then different version (e.g. node or browser)\n// just pass the engine here to create the client\n\nimport { \n wsClientConstProps\n} from './options'\nimport {\n checkSocketClientType,\n createCombineClient,\n getEventEmitter, \n EventEmitterClass\n} from './core/modules'\n\n/**\n * Overload the createCombineCreate to create a combine http / ws client\n * @param {object} configCheckMap \n * @param {object} constProps \n * @return {function} to accept config then generate the client\n */\nfunction createCombineWsClientConstructor(frameworkSocketEngine) {\n\n return function createCombineWsClient(httpClientConstructor, configCheckMap, constProps) {\n const localConstProps = Object.assign({}, constProps, wsClientConstProps)\n \n return createCombineClient(\n httpClientConstructor,\n frameworkSocketEngine,\n configCheckMap, \n localConstProps\n )\n }\n}\n\nexport {\n createCombineWsClientConstructor,\n // straight export\n checkSocketClientType,\n getEventEmitter, \n EventEmitterClass\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'\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 * @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 */\nfunction initWebSocketClient(WebSocket, auth = false) {\n if (auth === false) {\n return function createWsClientHandler(url) {\n return new WebSocket(fixWss(url))\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 * @return {object} ws instance\n */\n return function createWsAuthClientHandler(url, token) {\n const ws_url = fixWss(url)\n // console.log('what happen here?', url, ws_url, token)\n const uri = token && typeof token === 'string' ? `${ws_url}?${TOKEN_PARAM_NAME}=${token}` : ws_url\n try {\n return new WebSocket(uri)\n } catch(e) {\n console.error('WebSocket Connection Error', e)\n return false\n }\n }\n}\n\nexport { initWebSocketClient }","// @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}","/**\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 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 * 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","// 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","/**\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","// 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' \n\nconst WS_KEYS = [\n WS_REPLY_TYPE,\n WS_EVT_NAME,\n WS_DATA_NAME\n]\nimport isString from 'lodash-es/isString'\nimport { toJson, isFunc, isObjectHasKey, nil } from './generic'\nimport { timestamp } from './timestamp'\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 can not decoded', 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_TYPE,\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 createReplyMsg, \n createEvt, \n extractWsPayload \n} from 'jsonql-utils/module'\nimport {\n handleNamespaceOnError\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 * @return {void}\n */\nconst logoutEventHandler = (ee) => {\n // listen to the LOGOUT_EVENT_NAME when this is a private nsp\n ee.$on(LOGOUT_EVENT_NAME, function closeEvtHandler() {\n try {\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 socketEventHandler(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 = createReplyMsg(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 const json = extractWsPayload(payload)\n const { resolverName, type } = json\n \n log('Hear 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_TYPE:\n // this is handled error and we won't throw it\n // we need to extract the error from json\n log(`ERROR_TYPE`)\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 logoutEventHandler(ee)\n }\n}\n","// actually binding the event client to the socket client\n\n// from the jsonql-ws-client-core\nimport { clientEventHandler } from '../modules'\n// local \nimport { createNspAction } from './create-nsp-action'\nimport { loginEventHandler } from './login-event-handler'\nimport { socketEventHandler } from './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 // arguments for clientEventHandler\n const args = [opts, ee, socketEventHandler]\n\n // now create the nsps\n const { namespaces } = nspMap\n const { token } = opts\n const { nsps } = createNspAction(opts, nspMap, token)\n // binding the listeners - and it will listen to LOGOUT event\n // to unbind itself, and the above call will bind it again\n Reflect.apply(clientEventHandler, null, args.concat([namespaces, nsps]))\n // setup listener for the login event\n if (opts.enableAuth) {\n loginEventHandler(ee, namespaces, nspMap, opts)\n }\n // return what input\n return { opts, nspMap, ee }\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\n\nimport { initWebSocketClient } from './init-websocket-client'\nimport createNsp from '../create-nsp'\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 const publicClient = initWebSocketClient(frameworkModule)\n const privateClient = initWebSocketClient(frameworkModule, true)\n\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 opts.nspClient = publicClient\n opts.nspAuthClient = privateClient \n // @1.0.7 remove later once everything fixed \n const { log } = opts\n if (log && typeof log === 'function') {\n log('@jsonql/ws ee', ee.name)\n log('@jsonql/ws createClientResolver', opts)\n }\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 for node upstream client to include and construct their own client \nimport {\n createCombineWsClientConstructor,\n // straight export\n checkSocketClientType,\n getEventEmitter, \n EventEmitterClass\n} from '../create-combine-client'\nimport nodeFrameworkSocketEngine from './node-framework-socket-engine'\n\nconst createCombineWsClient = createCombineWsClientConstructor(nodeFrameworkSocketEngine)\n\nexport {\n createCombineWsClient,\n checkSocketClientType,\n getEventEmitter, \n EventEmitterClass\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;;;;;;;;;"} \ No newline at end of file diff --git a/packages/@jsonql/ws/package.json b/packages/@jsonql/ws/package.json index dececd9a..e8f73ff8 100644 --- a/packages/@jsonql/ws/package.json +++ b/packages/@jsonql/ws/package.json @@ -24,7 +24,7 @@ "build:cjs:prod": "NODE_ENV=production TARGET=cjs rollup -c", "build:umd:prod": "NODE_ENV=production TARGET=umd rollup -c", "build:cjs:module:prod": "NODE_ENV=production npm run build:cjs:module", - "build:test": "npm run build:cjs && npm run build:umd && build:cjs:module", + "build:test": "npm run build:cjs && npm run build:umd && npm run build:cjs:module", "test:browser:basic": "npm run build:umd && DEBUG=jsonql-ws-client*,server-io-core* node ./tests/browser/run-qunit.js", "test:browser:auth": "npm run build:umd && DEBUG=jsonql-ws-* NODE_ENV=ws-auth node ./tests/browser/run-qunit.js", "test:opt": "ava ./tests/opt.test.js", diff --git a/packages/@jsonql/ws/src/core/framework-socket-engine.js b/packages/@jsonql/ws/src/core/framework-socket-engine.js index f3020868..63e551f1 100644 --- a/packages/@jsonql/ws/src/core/framework-socket-engine.js +++ b/packages/@jsonql/ws/src/core/framework-socket-engine.js @@ -4,7 +4,7 @@ // then return a function for accepting an opts to generate the final // client api import WebSocket from './ws' -import createWebSocketBinding from '../create-websocket-binding' +import createWebSocketBinding from './create-websocket-binding' /** * @param {object} opts configuration diff --git a/packages/@jsonql/ws/src/node/module.js b/packages/@jsonql/ws/src/node/module.js index db9a2f7c..aa894398 100644 --- a/packages/@jsonql/ws/src/node/module.js +++ b/packages/@jsonql/ws/src/node/module.js @@ -5,7 +5,7 @@ import { checkSocketClientType, getEventEmitter, EventEmitterClass -} from './src/create-combine-client' +} from '../create-combine-client' import nodeFrameworkSocketEngine from './node-framework-socket-engine' const createCombineWsClient = createCombineWsClientConstructor(nodeFrameworkSocketEngine) -- Gitee From 96fb306688af2c3d59b3b5e33c4ee2f663b4a88a Mon Sep 17 00:00:00 2001 From: joelchu Date: Fri, 13 Mar 2020 21:34:42 +0800 Subject: [PATCH 34/45] Fix all the basic but its still hanging up --- packages/@jsonql/ws/main.js | 10 +++++----- packages/@jsonql/ws/main.js.map | 2 +- packages/@jsonql/ws/src/core/create-nsp/create-nsp.js | 2 +- .../create-websocket-binding/init-websocket-client.js | 4 ++-- .../ws-client-core/src/share/client-event-handler.js | 5 +++-- 5 files changed, 12 insertions(+), 11 deletions(-) diff --git a/packages/@jsonql/ws/main.js b/packages/@jsonql/ws/main.js index 8e532770..699a61c5 100644 --- a/packages/@jsonql/ws/main.js +++ b/packages/@jsonql/ws/main.js @@ -7742,14 +7742,14 @@ var disconnectHandler = function (nsps, namespaces, ee, opts) { /** * centralize all the comm in one place * @param {object} opts configuration + * @param {object} nspMap this is not in the opts * @param {object} ee Event Emitter instance * @param {function} bindWsHandler binding the ee to ws --> this is the core bit * @param {object} nsps namespaced nsp * @return {void} nothing */ -function clientEventHandler$1(opts, ee, bindSocketEventHandler, nsps) { +function clientEventHandler$1(opts, nspMap, ee, bindSocketEventHandler, nsps) { // since all these params already in the opts - var nspMap = opts.nspMap; var log = opts.log; var namespaces = nspMap.namespaces; // @1.1.3 add isPrivate prop to id which namespace is the private nsp @@ -7835,7 +7835,7 @@ function initWebSocketClient(WebSocket, auth) { if ( auth === void 0 ) auth = false; if (auth === false) { - return function createWsClientHandler(url) { + return function createWsClient(url) { return new WebSocket(fixWss(url)) } } @@ -7846,7 +7846,7 @@ function initWebSocketClient(WebSocket, auth) { * @param {string} token the jwt token * @return {object} ws instance */ - return function createWsAuthClientHandler(url, token) { + return function createWsAuthClient(url, token) { var ws_url = fixWss(url); // console.log('what happen here?', url, ws_url, token) var uri = token && typeof token === 'string' ? (ws_url + "?" + TOKEN_PARAM_NAME + "=" + token) : ws_url; @@ -8462,7 +8462,7 @@ function socketEventHandler(namespace, ws, ee, isPrivate, opts) { */ function createNsp(opts, nspMap, ee) { // arguments for clientEventHandler - var args = [opts, ee, socketEventHandler]; + var args = [opts, nspMap, ee, socketEventHandler]; // now create the nsps var namespaces = nspMap.namespaces; diff --git a/packages/@jsonql/ws/main.js.map b/packages/@jsonql/ws/main.js.map index 262847c2..48133a74 100644 --- a/packages/@jsonql/ws/main.js.map +++ b/packages/@jsonql/ws/main.js.map @@ -1 +1 @@ -{"version":3,"file":"main.js","sources":["node_modules/_rollup-plugin-node-globals@1.4.0@rollup-plugin-node-globals/src/global.js","../../ws-client-core/node_modules/lodash-es/_arrayMap.js","../../ws-client-core/node_modules/lodash-es/isArray.js","../../ws-client-core/node_modules/lodash-es/_objectToString.js","../../ws-client-core/node_modules/lodash-es/isObjectLike.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-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/lodash-es/_overArg.js","../../ws-client-core/node_modules/lodash-es/_arrayFilter.js","../../ws-client-core/node_modules/lodash-es/_createBaseFor.js","../../ws-client-core/node_modules/lodash-es/_baseTimes.js","../../ws-client-core/node_modules/lodash-es/stubFalse.js","../../ws-client-core/node_modules/lodash-es/_isIndex.js","../../ws-client-core/node_modules/lodash-es/isLength.js","../../ws-client-core/node_modules/lodash-es/_baseUnary.js","../../ws-client-core/node_modules/lodash-es/_isPrototype.js","../../ws-client-core/node_modules/lodash-es/isObject.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/_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/_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/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/identity.js","../../ws-client-core/node_modules/lodash-es/_baseProperty.js","../../ws-client-core/node_modules/jsonql-params-validator/src/object.js","../../ws-client-core/node_modules/jsonql-errors/src/validation-error.js","../../ws-client-core/node_modules/jsonql-params-validator/src/validator.js","../../ws-client-core/node_modules/lodash-es/_copyArray.js","../../ws-client-core/node_modules/lodash-es/_safeGet.js","../../ws-client-core/node_modules/lodash-es/_nativeKeysIn.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/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-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-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/node_modules/jsonql-utils/src/generic.js","../../ws-client-core/node_modules/jsonql-errors/src/500-error.js","../../ws-client-core/node_modules/jsonql-errors/src/resolver-not-found-error.js","../../ws-client-core/node_modules/jsonql-errors/src/server-error.js","../../ws-client-core/node_modules/jsonql-utils/src/contract.js","../../ws-client-core/node_modules/jsonql-utils/src/namespace.js","../../ws-client-core/src/utils/helpers.js","../../ws-client-core/src/core/setup-auth-methods.js","../../ws-client-core/src/options/constants.js","../../ws-client-core/src/core/respond-handler.js","../../ws-client-core/src/core/action-call.js","../../ws-client-core/src/core/setup-send-method.js","../../ws-client-core/src/core/setup-resolver.js","../../ws-client-core/src/core/resolver-methods.js","../../ws-client-core/src/core/setup-intercom.js","../../ws-client-core/src/core/generator.js","../../ws-client-core/src/options/index.js","../../ws-client-core/src/api.js","../../ws-client-core/src/share/create-nsp-client.js","../../ws-client-core/src/share/trigger-namespaces-on-error.js","../../ws-client-core/src/share/client-event-handler.js","src/options/index.js","src/core/create-websocket-binding/init-websocket-client.js","src/core/create-nsp/login-event-handler.js","node_modules/_lodash-es@4.17.15@lodash-es/isArray.js","node_modules/_lodash-es@4.17.15@lodash-es/_objectToString.js","node_modules/_lodash-es@4.17.15@lodash-es/isObjectLike.js","node_modules/_jsonql-utils@1.1.3@jsonql-utils/src/generic.js","node_modules/_jsonql-utils@1.1.3@jsonql-utils/src/timestamp.js","node_modules/_jsonql-utils@1.1.3@jsonql-utils/src/socket.js","src/core/create-nsp/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":["export default (typeof global !== \"undefined\" ? global :\n typeof self !== \"undefined\" ? self :\n typeof window !== \"undefined\" ? window : {});\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 * 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 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 * 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 * 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","// 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\nexport const 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)`\nexport const PARAMS_NOT_ARRAY_ERR = `params is not an array! Did something gone wrong when you generate the contract.json?`\nexport const EXCEPTION_CASE_ERR = 'Could not understand your arguments and parameter structure!'\nexport const UNUSUAL_CASE_ERR = 'This is an unusual situation where the arguments are more than the params, but not mark as spread'\n\n// re-export\nimport * as JSONQL_CONSTANTS from 'jsonql-constants'\n// @TODO the jsdoc return array. and we should also allow array syntax\nexport const DEFAULT_TYPE = JSONQL_CONSTANTS.DEFAULT_TYPE\nexport const ARRAY_TYPE_LFT = JSONQL_CONSTANTS.ARRAY_TYPE_LFT\nexport const ARRAY_TYPE_RGT = JSONQL_CONSTANTS.ARRAY_TYPE_RGT\n\nexport const TYPE_KEY = JSONQL_CONSTANTS.TYPE_KEY\nexport const OPTIONAL_KEY = JSONQL_CONSTANTS.OPTIONAL_KEY\nexport const ENUM_KEY = JSONQL_CONSTANTS.ENUM_KEY\nexport const ARGS_KEY = JSONQL_CONSTANTS.ARGS_KEY\nexport const CHECKER_KEY = JSONQL_CONSTANTS.CHECKER_KEY\nexport const ALIAS_KEY = JSONQL_CONSTANTS.ALIAS_KEY\n\nexport const ARRAY_TYPE = JSONQL_CONSTANTS.ARRAY_TYPE\nexport const OBJECT_TYPE = JSONQL_CONSTANTS.OBJECT_TYPE\nexport const STRING_TYPE = JSONQL_CONSTANTS.STRING_TYPE\nexport const BOOLEAN_TYPE = JSONQL_CONSTANTS.BOOLEAN_TYPE\nexport const NUMBER_TYPE = JSONQL_CONSTANTS.NUMBER_TYPE\nexport const KEY_WORD = JSONQL_CONSTANTS.KEY_WORD\nexport const OR_SEPERATOR = JSONQL_CONSTANTS.OR_SEPERATOR\n\n// not actually in use\n// export const NUMBER_TYPES = JSONQL_CONSTANTS.NUMBER_TYPES;\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","/**\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 * 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 * 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 * 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","/**\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","/** 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","/** 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 * 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","/** 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 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","/**\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","/** 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","/** 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 * 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 * 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 * 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","// validate object type\n\nimport isPlainObject from 'lodash-es/isPlainObject'\nimport filter from 'lodash-es/filter'\n\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","// 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","// 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 // checkIsObject,\n combineFn,\n notEmpty\n} from './index'\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 // UNUSUAL_CASE_ERR\n} from './constants'\nimport { DATA_KEY, ERROR_KEY } from 'jsonql-constants'\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","/**\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","/**\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 * 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 * 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","/** 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","// 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","// 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'\n// PIA syntax\nexport const isObject = checkIsObject\nexport const isAny = checkIsAny\nexport const isString = checkIsString\nexport const isBoolean = checkIsBoolean\nexport const isNumber = checkIsNumber\nexport const isArray = checkIsArray\nexport const isNotEmpty = notEmpty\n\nimport * as validator from './src/validator'\n\nexport const normalizeArgs = validator.normalizeArgs\nexport const validateSync = validator.validateSync\nexport const validateAsync = validator.validateAsync\n\n// configuration checking\n\nimport * as jsonqlOptions from './src/options'\n\nexport const JSONQL_PARAMS_VALIDATOR_INFO = jsonqlOptions.JSONQL_PARAMS_VALIDATOR_INFO\n\nexport const createConfig = jsonqlOptions.createConfig\nexport const constructConfig = jsonqlOptions.constructConfigFn\n// construct the final output 1.5.2\nexport const checkConfigAsync = jsonqlOptions.getCheckConfigAsync(validator.validateSync)\nexport const checkConfig = jsonqlOptions.getCheckConfig(validator.validateSync)\n\n// export the two extra functions\nimport isInArray from './src/is-in-array'\nimport isObjectHasKeyFn from './src/is-key-in-object'\n\nexport const inArray = isInArray\nexport const isObjectHasKey = isObjectHasKeyFn\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","// 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","/**\n * This is a custom error to throw when server throw a 500\n * This help us to capture the right error, due to the call happens in sequence\n * @param {string} message to tell what happen\n * @param {mixed} extra things we want to add, 500?\n */\nexport default class Jsonql500Error extends Error {\n constructor(...args) {\n super(...args)\n\n this.message = args[0]\n this.detail = args[1]\n\n this.className = Jsonql500Error.name;\n\n if (Error.captureStackTrace) {\n Error.captureStackTrace(this, Jsonql500Error)\n }\n }\n\n static get statusCode() {\n return 500;\n }\n\n static get name() {\n return 'Jsonql500Error';\n }\n\n}\n","/**\n * This is a custom error to throw when could not find the resolver\n * This help us to capture the right error, due to the call happens in sequence\n * @param {string} message to tell what happen\n * @param {mixed} extra things we want to add, 500?\n */\nexport default class JsonqlResolverNotFoundError extends Error {\n constructor(...args) {\n super(...args)\n\n this.message = args[0]\n this.detail = args[1]\n\n this.className = JsonqlResolverNotFoundError.name;\n\n if (Error.captureStackTrace) {\n Error.captureStackTrace(this, JsonqlResolverNotFoundError);\n }\n }\n\n static get statusCode() {\n return 404;\n }\n\n static get name() {\n return 'JsonqlResolverNotFoundError';\n }\n}\n","// this is from an example from Koa team to use for internal middleware ctx.throw\n// but after the test the res.body part is unable to extract the required data\n// I keep this one here for future reference\n\nexport default class JsonqlServerError extends Error {\n\n constructor(statusCode, message) {\n super(message)\n this.statusCode = statusCode;\n this.className = JsonqlServerError.name;\n }\n\n static get name() {\n return 'JsonqlServerError';\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","// 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.publicNamespace ].join('/'),\n [ base , config.privateNamespace ].join('/')\n ]\n }\n return [ base ]\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","// 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(client, resolverName, setupResolver(namespace, resolverName, params, fn, ee, log))\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 createNamespaceErrorHandler(client, opts, ee, nspGroup) {\n return [\n // using the onError as name\n // @TODO we should follow the convention earlier\n // make this a setter for the clientitself\n objDefineProps(client, ON_ERROR_FN_NAME, 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 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 createOnReadyHandler(client, opts, ee) {\n return [\n objDefineProps(client, ON_READY_FN_NAME, 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 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} ","// 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 createNamespaceErrorHandler,\n createOnReadyHandler\n} from './resolver-methods'\nimport {\n setupFinalStep \n} from './setup-final-step'\nimport {\n NSP_GROUP\n} from 'jsonql-constants'\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 generator(opts, nspMap, ee) {\n\n let args = [\n generateResolvers,\n createNamespaceErrorHandler,\n createOnReadyHandler\n ]\n if (opts.enableAuth) {\n args.push(\n createAuthMethods\n )\n } \n // we will always get back the [ obj, opts, ee ]\n // then we only return the obj (wsClient)\n args.push(setupFinalStep)\n // run it\n const fn = Reflect.apply(chainFns, null, args)\n\n return fn(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 { generator } from './core'\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} frameworkSocketEngine \n * @param {object} config the already checked config \n */\nexport function wsClientCoreAction(frameworkSocketEngine, config) {\n return postCheckInjectOpts(config)\n // the following two moved to wsPostConfig\n .then(createRequiredParams)\n .then(\n ({opts, nspMap, ee}) => frameworkSocketEngine(opts, nspMap, ee)\n )\n .then(\n ({opts, nspMap, ee}) => generator(opts, nspMap, ee)\n )\n .catch(err => {\n console.error(`jsonql-ws-core-client init error`, err)\n })\n}\n\n/**\n * The main interface which will generate the socket clients and map all events\n * @param {object} frameworkSocketEngine 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(frameworkSocketEngine, configCheckMap = {}, constProps = {}) {\n // we need to inject property to this client later\n return (config = {}) => checkConfiguration(config, configCheckMap, constProps)\n .then(opts => wsClientCoreAction(frameworkSocketEngine, opts))\n}\n","// since both the ws and io version are\n// pre-defined in the client-generator\n// and this one will have the same parameters\n// and the callback is identical\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 } = opts\n const url = namespace ? [hostname, namespace].join('/') : wssPath\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 } = opts\n const url = namespace ? [hostname, namespace].join('/') : wssPath\n if (token && typeof token !== 'string') {\n throw new Error(`Expect token to be string, but got ${token}`)\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}","// 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\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, SOCKET_IO, DISCONNECTED_ERROR_MSG } from '../options/constants'\nimport { createEvt, clearMainEmitEvt } from '../utils'\nimport { triggerNamespacesOnError } from './trigger-namespaces-on-error'\n\n/**\n * A Event handler 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 */\nconst notLoginWsHandler = (namespace, ee, opts) => {\n const { log } = opts \n ee.$only(\n createEvt(namespace, EMIT_EVT),\n function notLoginHandlerCallback(resolverName, args) {\n log('[notLoginHandler] hijack the ws call', namespace, resolverName, args)\n const error = {\n message: NOT_LOGIN_ERR_MSG\n }\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 handler, but wrap inside the error key\n ee.$call(createEvt(namespace, resolverName, ON_RESULT_FN_NAME), [{ error }])\n }\n )\n}\n\n/**\n * A Event handler 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 */\nconst disconnectedHandler = (namespace, ee, opts) => {\n const { log } = opts \n ee.$only(\n createEvt(namespace, EMIT_EVT),\n function disconnectedHandlerCallback(resolverName, args) {\n log(`[disconnectedHandler] 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 handler, but wrap inside the error key\n ee.$call(createEvt(namespace, resolverName, ON_RESULT_FN_NAME), [{ error }])\n }\n )\n}\n\n/**\n * get the private namespace\n * @param {array} namespaces array\n * @return {*} string on success\n */\nconst getPrivateNamespace = (namespaces) => (\n namespaces.length > 1 ? namespaces[0] : false\n)\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 */\nconst logoutEvtHandler = (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(LOGOUT_EVENT_NAME, function logoutEvtHandlerAction() {\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 handler\n triggerNamespacesOnError(ee, [privateNamespace], LOGOUT_EVENT_NAME)\n // rebind all of the handler 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 notLoginWsHandler(privateNamespace, ee, opts)\n })\n}\n\n/**\n * The disconnect event handler, 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 */\nconst disconnectHandler = (nsps, namespaces, ee, opts) => {\n const { log } = opts \n ee.$on(DISCONNECT_EVENT_NAME, function disconnectEvtHandler() {\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 disconnectedHandler(namespace, ee, opts)\n })\n })\n}\n\n/**\n * centralize all the comm in one place\n * @param {object} opts configuration\n * @param {object} ee Event Emitter instance\n * @param {function} bindWsHandler binding the ee to ws --> this is the core bit\n * @param {object} nsps namespaced nsp\n * @return {void} nothing\n */\nexport function clientEventHandler(opts, ee, bindSocketEventHandler, nsps) {\n // since all these params already in the opts\n const { nspMap, 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 let isPrivate = false\n let hasPrivate = false\n // loop\n // @BUG for io this has to be in order the one with auth need to get call first\n // The order of login is very import we need to run in order here to make sure\n // one is execute then the other\n namespaces.forEach(namespace => {\n isPrivate = privateNamespace === namespace\n if (!hasPrivate) {\n hasPrivate = isPrivate\n }\n if (nsps[namespace]) {\n\n log('[call bindWsHandler]', isPrivate, namespace)\n let args = [namespace, nsps[namespace], ee, isPrivate, opts]\n \n if (opts.serverType === SOCKET_IO) {\n let { nspGroup } = nspMap\n args.push(nspGroup[namespace])\n }\n Reflect.apply(bindSocketEventHandler, null, args)\n } else {\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 notLoginWsHandler(namespace, ee, opts)\n }\n })\n // logout event handler \n if (hasPrivate) {\n log(`Has private and add logoutEvtHandler`)\n\n logoutEvtHandler(nsps, namespaces, ee, opts)\n }\n // finally the disconnect event handlers\n disconnectHandler(nsps, namespaces, ee, opts) \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'\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 * @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 */\nfunction initWebSocketClient(WebSocket, auth = false) {\n if (auth === false) {\n return function createWsClientHandler(url) {\n return new WebSocket(fixWss(url))\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 * @return {object} ws instance\n */\n return function createWsAuthClientHandler(url, token) {\n const ws_url = fixWss(url)\n // console.log('what happen here?', url, ws_url, token)\n const uri = token && typeof token === 'string' ? `${ws_url}?${TOKEN_PARAM_NAME}=${token}` : ws_url\n try {\n return new WebSocket(uri)\n } catch(e) {\n console.error('WebSocket Connection Error', e)\n return false\n }\n }\n}\n\nexport { initWebSocketClient }","// @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}","/**\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 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 * 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","// 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","/**\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","// 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' \n\nconst WS_KEYS = [\n WS_REPLY_TYPE,\n WS_EVT_NAME,\n WS_DATA_NAME\n]\nimport isString from 'lodash-es/isString'\nimport { toJson, isFunc, isObjectHasKey, nil } from './generic'\nimport { timestamp } from './timestamp'\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 can not decoded', 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_TYPE,\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 createReplyMsg, \n createEvt, \n extractWsPayload \n} from 'jsonql-utils/module'\nimport {\n handleNamespaceOnError\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 * @return {void}\n */\nconst logoutEventHandler = (ee) => {\n // listen to the LOGOUT_EVENT_NAME when this is a private nsp\n ee.$on(LOGOUT_EVENT_NAME, function closeEvtHandler() {\n try {\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 socketEventHandler(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 = createReplyMsg(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 const json = extractWsPayload(payload)\n const { resolverName, type } = json\n \n log('Hear 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_TYPE:\n // this is handled error and we won't throw it\n // we need to extract the error from json\n log(`ERROR_TYPE`)\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 logoutEventHandler(ee)\n }\n}\n","// actually binding the event client to the socket client\n\n// from the jsonql-ws-client-core\nimport { clientEventHandler } from '../modules'\n// local \nimport { createNspAction } from './create-nsp-action'\nimport { loginEventHandler } from './login-event-handler'\nimport { socketEventHandler } from './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 // arguments for clientEventHandler\n const args = [opts, ee, socketEventHandler]\n\n // now create the nsps\n const { namespaces } = nspMap\n const { token } = opts\n const { nsps } = createNspAction(opts, nspMap, token)\n // binding the listeners - and it will listen to LOGOUT event\n // to unbind itself, and the above call will bind it again\n Reflect.apply(clientEventHandler, null, args.concat([namespaces, nsps]))\n // setup listener for the login event\n if (opts.enableAuth) {\n loginEventHandler(ee, namespaces, nspMap, opts)\n }\n // return what input\n return { opts, nspMap, ee }\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\n\nimport { initWebSocketClient } from './init-websocket-client'\nimport createNsp from '../create-nsp'\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 const publicClient = initWebSocketClient(frameworkModule)\n const privateClient = initWebSocketClient(frameworkModule, true)\n\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 opts.nspClient = publicClient\n opts.nspAuthClient = privateClient \n // @1.0.7 remove later once everything fixed \n const { log } = opts\n if (log && typeof log === 'function') {\n log('@jsonql/ws ee', ee.name)\n log('@jsonql/ws createClientResolver', opts)\n }\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;;;;;;;;;;;;;;;;;"} \ No newline at end of file +{"version":3,"file":"main.js","sources":["node_modules/_rollup-plugin-node-globals@1.4.0@rollup-plugin-node-globals/src/global.js","../../ws-client-core/node_modules/lodash-es/_arrayMap.js","../../ws-client-core/node_modules/lodash-es/isArray.js","../../ws-client-core/node_modules/lodash-es/_objectToString.js","../../ws-client-core/node_modules/lodash-es/isObjectLike.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-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/lodash-es/_overArg.js","../../ws-client-core/node_modules/lodash-es/_arrayFilter.js","../../ws-client-core/node_modules/lodash-es/_createBaseFor.js","../../ws-client-core/node_modules/lodash-es/_baseTimes.js","../../ws-client-core/node_modules/lodash-es/stubFalse.js","../../ws-client-core/node_modules/lodash-es/_isIndex.js","../../ws-client-core/node_modules/lodash-es/isLength.js","../../ws-client-core/node_modules/lodash-es/_baseUnary.js","../../ws-client-core/node_modules/lodash-es/_isPrototype.js","../../ws-client-core/node_modules/lodash-es/isObject.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/_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/_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/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/identity.js","../../ws-client-core/node_modules/lodash-es/_baseProperty.js","../../ws-client-core/node_modules/jsonql-params-validator/src/object.js","../../ws-client-core/node_modules/jsonql-errors/src/validation-error.js","../../ws-client-core/node_modules/jsonql-params-validator/src/validator.js","../../ws-client-core/node_modules/lodash-es/_copyArray.js","../../ws-client-core/node_modules/lodash-es/_safeGet.js","../../ws-client-core/node_modules/lodash-es/_nativeKeysIn.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/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-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-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/node_modules/jsonql-utils/src/generic.js","../../ws-client-core/node_modules/jsonql-errors/src/500-error.js","../../ws-client-core/node_modules/jsonql-errors/src/resolver-not-found-error.js","../../ws-client-core/node_modules/jsonql-errors/src/server-error.js","../../ws-client-core/node_modules/jsonql-utils/src/contract.js","../../ws-client-core/node_modules/jsonql-utils/src/namespace.js","../../ws-client-core/src/utils/helpers.js","../../ws-client-core/src/core/setup-auth-methods.js","../../ws-client-core/src/options/constants.js","../../ws-client-core/src/core/respond-handler.js","../../ws-client-core/src/core/action-call.js","../../ws-client-core/src/core/setup-send-method.js","../../ws-client-core/src/core/setup-resolver.js","../../ws-client-core/src/core/resolver-methods.js","../../ws-client-core/src/core/setup-intercom.js","../../ws-client-core/src/core/generator.js","../../ws-client-core/src/options/index.js","../../ws-client-core/src/api.js","../../ws-client-core/src/share/create-nsp-client.js","../../ws-client-core/src/share/trigger-namespaces-on-error.js","../../ws-client-core/src/share/client-event-handler.js","src/options/index.js","src/core/create-websocket-binding/init-websocket-client.js","src/core/create-nsp/login-event-handler.js","node_modules/_lodash-es@4.17.15@lodash-es/isArray.js","node_modules/_lodash-es@4.17.15@lodash-es/_objectToString.js","node_modules/_lodash-es@4.17.15@lodash-es/isObjectLike.js","node_modules/_jsonql-utils@1.1.3@jsonql-utils/src/generic.js","node_modules/_jsonql-utils@1.1.3@jsonql-utils/src/timestamp.js","node_modules/_jsonql-utils@1.1.3@jsonql-utils/src/socket.js","src/core/create-nsp/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":["export default (typeof global !== \"undefined\" ? global :\n typeof self !== \"undefined\" ? self :\n typeof window !== \"undefined\" ? window : {});\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 * 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 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 * 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 * 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","// 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\nexport const 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)`\nexport const PARAMS_NOT_ARRAY_ERR = `params is not an array! Did something gone wrong when you generate the contract.json?`\nexport const EXCEPTION_CASE_ERR = 'Could not understand your arguments and parameter structure!'\nexport const UNUSUAL_CASE_ERR = 'This is an unusual situation where the arguments are more than the params, but not mark as spread'\n\n// re-export\nimport * as JSONQL_CONSTANTS from 'jsonql-constants'\n// @TODO the jsdoc return array. and we should also allow array syntax\nexport const DEFAULT_TYPE = JSONQL_CONSTANTS.DEFAULT_TYPE\nexport const ARRAY_TYPE_LFT = JSONQL_CONSTANTS.ARRAY_TYPE_LFT\nexport const ARRAY_TYPE_RGT = JSONQL_CONSTANTS.ARRAY_TYPE_RGT\n\nexport const TYPE_KEY = JSONQL_CONSTANTS.TYPE_KEY\nexport const OPTIONAL_KEY = JSONQL_CONSTANTS.OPTIONAL_KEY\nexport const ENUM_KEY = JSONQL_CONSTANTS.ENUM_KEY\nexport const ARGS_KEY = JSONQL_CONSTANTS.ARGS_KEY\nexport const CHECKER_KEY = JSONQL_CONSTANTS.CHECKER_KEY\nexport const ALIAS_KEY = JSONQL_CONSTANTS.ALIAS_KEY\n\nexport const ARRAY_TYPE = JSONQL_CONSTANTS.ARRAY_TYPE\nexport const OBJECT_TYPE = JSONQL_CONSTANTS.OBJECT_TYPE\nexport const STRING_TYPE = JSONQL_CONSTANTS.STRING_TYPE\nexport const BOOLEAN_TYPE = JSONQL_CONSTANTS.BOOLEAN_TYPE\nexport const NUMBER_TYPE = JSONQL_CONSTANTS.NUMBER_TYPE\nexport const KEY_WORD = JSONQL_CONSTANTS.KEY_WORD\nexport const OR_SEPERATOR = JSONQL_CONSTANTS.OR_SEPERATOR\n\n// not actually in use\n// export const NUMBER_TYPES = JSONQL_CONSTANTS.NUMBER_TYPES;\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","/**\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 * 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 * 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 * 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","/**\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","/** 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","/** 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 * 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","/** 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 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","/**\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","/** 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","/** 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 * 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 * 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 * 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","// validate object type\n\nimport isPlainObject from 'lodash-es/isPlainObject'\nimport filter from 'lodash-es/filter'\n\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","// 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","// 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 // checkIsObject,\n combineFn,\n notEmpty\n} from './index'\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 // UNUSUAL_CASE_ERR\n} from './constants'\nimport { DATA_KEY, ERROR_KEY } from 'jsonql-constants'\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","/**\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","/**\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 * 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 * 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","/** 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","// 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","// 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'\n// PIA syntax\nexport const isObject = checkIsObject\nexport const isAny = checkIsAny\nexport const isString = checkIsString\nexport const isBoolean = checkIsBoolean\nexport const isNumber = checkIsNumber\nexport const isArray = checkIsArray\nexport const isNotEmpty = notEmpty\n\nimport * as validator from './src/validator'\n\nexport const normalizeArgs = validator.normalizeArgs\nexport const validateSync = validator.validateSync\nexport const validateAsync = validator.validateAsync\n\n// configuration checking\n\nimport * as jsonqlOptions from './src/options'\n\nexport const JSONQL_PARAMS_VALIDATOR_INFO = jsonqlOptions.JSONQL_PARAMS_VALIDATOR_INFO\n\nexport const createConfig = jsonqlOptions.createConfig\nexport const constructConfig = jsonqlOptions.constructConfigFn\n// construct the final output 1.5.2\nexport const checkConfigAsync = jsonqlOptions.getCheckConfigAsync(validator.validateSync)\nexport const checkConfig = jsonqlOptions.getCheckConfig(validator.validateSync)\n\n// export the two extra functions\nimport isInArray from './src/is-in-array'\nimport isObjectHasKeyFn from './src/is-key-in-object'\n\nexport const inArray = isInArray\nexport const isObjectHasKey = isObjectHasKeyFn\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","// 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","/**\n * This is a custom error to throw when server throw a 500\n * This help us to capture the right error, due to the call happens in sequence\n * @param {string} message to tell what happen\n * @param {mixed} extra things we want to add, 500?\n */\nexport default class Jsonql500Error extends Error {\n constructor(...args) {\n super(...args)\n\n this.message = args[0]\n this.detail = args[1]\n\n this.className = Jsonql500Error.name;\n\n if (Error.captureStackTrace) {\n Error.captureStackTrace(this, Jsonql500Error)\n }\n }\n\n static get statusCode() {\n return 500;\n }\n\n static get name() {\n return 'Jsonql500Error';\n }\n\n}\n","/**\n * This is a custom error to throw when could not find the resolver\n * This help us to capture the right error, due to the call happens in sequence\n * @param {string} message to tell what happen\n * @param {mixed} extra things we want to add, 500?\n */\nexport default class JsonqlResolverNotFoundError extends Error {\n constructor(...args) {\n super(...args)\n\n this.message = args[0]\n this.detail = args[1]\n\n this.className = JsonqlResolverNotFoundError.name;\n\n if (Error.captureStackTrace) {\n Error.captureStackTrace(this, JsonqlResolverNotFoundError);\n }\n }\n\n static get statusCode() {\n return 404;\n }\n\n static get name() {\n return 'JsonqlResolverNotFoundError';\n }\n}\n","// this is from an example from Koa team to use for internal middleware ctx.throw\n// but after the test the res.body part is unable to extract the required data\n// I keep this one here for future reference\n\nexport default class JsonqlServerError extends Error {\n\n constructor(statusCode, message) {\n super(message)\n this.statusCode = statusCode;\n this.className = JsonqlServerError.name;\n }\n\n static get name() {\n return 'JsonqlServerError';\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","// 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.publicNamespace ].join('/'),\n [ base , config.privateNamespace ].join('/')\n ]\n }\n return [ base ]\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","// 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(client, resolverName, setupResolver(namespace, resolverName, params, fn, ee, log))\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 createNamespaceErrorHandler(client, opts, ee, nspGroup) {\n return [\n // using the onError as name\n // @TODO we should follow the convention earlier\n // make this a setter for the clientitself\n objDefineProps(client, ON_ERROR_FN_NAME, 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 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 createOnReadyHandler(client, opts, ee) {\n return [\n objDefineProps(client, ON_READY_FN_NAME, 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 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} ","// 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 createNamespaceErrorHandler,\n createOnReadyHandler\n} from './resolver-methods'\nimport {\n setupFinalStep \n} from './setup-final-step'\nimport {\n NSP_GROUP\n} from 'jsonql-constants'\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 generator(opts, nspMap, ee) {\n\n let args = [\n generateResolvers,\n createNamespaceErrorHandler,\n createOnReadyHandler\n ]\n if (opts.enableAuth) {\n args.push(\n createAuthMethods\n )\n } \n // we will always get back the [ obj, opts, ee ]\n // then we only return the obj (wsClient)\n args.push(setupFinalStep)\n // run it\n const fn = Reflect.apply(chainFns, null, args)\n\n return fn(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 { generator } from './core'\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} frameworkSocketEngine \n * @param {object} config the already checked config \n */\nexport function wsClientCoreAction(frameworkSocketEngine, config) {\n return postCheckInjectOpts(config)\n // the following two moved to wsPostConfig\n .then(createRequiredParams)\n .then(\n ({opts, nspMap, ee}) => frameworkSocketEngine(opts, nspMap, ee)\n )\n .then(\n ({opts, nspMap, ee}) => generator(opts, nspMap, ee)\n )\n .catch(err => {\n console.error(`jsonql-ws-core-client init error`, err)\n })\n}\n\n/**\n * The main interface which will generate the socket clients and map all events\n * @param {object} frameworkSocketEngine 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(frameworkSocketEngine, configCheckMap = {}, constProps = {}) {\n // we need to inject property to this client later\n return (config = {}) => checkConfiguration(config, configCheckMap, constProps)\n .then(opts => wsClientCoreAction(frameworkSocketEngine, opts))\n}\n","// since both the ws and io version are\n// pre-defined in the client-generator\n// and this one will have the same parameters\n// and the callback is identical\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 } = opts\n const url = namespace ? [hostname, namespace].join('/') : wssPath\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 } = opts\n const url = namespace ? [hostname, namespace].join('/') : wssPath\n if (token && typeof token !== 'string') {\n throw new Error(`Expect token to be string, but got ${token}`)\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}","// 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\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, SOCKET_IO, DISCONNECTED_ERROR_MSG } from '../options/constants'\nimport { createEvt, clearMainEmitEvt } from '../utils'\nimport { triggerNamespacesOnError } from './trigger-namespaces-on-error'\n\n/**\n * A Event handler 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 */\nconst notLoginWsHandler = (namespace, ee, opts) => {\n const { log } = opts \n ee.$only(\n createEvt(namespace, EMIT_EVT),\n function notLoginHandlerCallback(resolverName, args) {\n log('[notLoginHandler] hijack the ws call', namespace, resolverName, args)\n const error = {\n message: NOT_LOGIN_ERR_MSG\n }\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 handler, but wrap inside the error key\n ee.$call(createEvt(namespace, resolverName, ON_RESULT_FN_NAME), [{ error }])\n }\n )\n}\n\n/**\n * A Event handler 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 */\nconst disconnectedHandler = (namespace, ee, opts) => {\n const { log } = opts \n ee.$only(\n createEvt(namespace, EMIT_EVT),\n function disconnectedHandlerCallback(resolverName, args) {\n log(`[disconnectedHandler] 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 handler, but wrap inside the error key\n ee.$call(createEvt(namespace, resolverName, ON_RESULT_FN_NAME), [{ error }])\n }\n )\n}\n\n/**\n * get the private namespace\n * @param {array} namespaces array\n * @return {*} string on success\n */\nconst getPrivateNamespace = (namespaces) => (\n namespaces.length > 1 ? namespaces[0] : false\n)\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 */\nconst logoutEvtHandler = (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(LOGOUT_EVENT_NAME, function logoutEvtHandlerAction() {\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 handler\n triggerNamespacesOnError(ee, [privateNamespace], LOGOUT_EVENT_NAME)\n // rebind all of the handler 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 notLoginWsHandler(privateNamespace, ee, opts)\n })\n}\n\n/**\n * The disconnect event handler, 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 */\nconst disconnectHandler = (nsps, namespaces, ee, opts) => {\n const { log } = opts \n ee.$on(DISCONNECT_EVENT_NAME, function disconnectEvtHandler() {\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 disconnectedHandler(namespace, ee, opts)\n })\n })\n}\n\n/**\n * centralize all the comm in one place\n * @param {object} opts configuration\n * @param {object} nspMap this is not in the opts \n * @param {object} ee Event Emitter instance\n * @param {function} bindWsHandler binding the ee to ws --> this is the core bit\n * @param {object} nsps namespaced nsp\n * @return {void} nothing\n */\nexport function clientEventHandler(opts, nspMap, ee, bindSocketEventHandler, nsps) {\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 let isPrivate = false\n let hasPrivate = false\n // loop\n // @BUG for io this has to be in order the one with auth need to get call first\n // The order of login is very import we need to run in order here to make sure\n // one is execute then the other\n namespaces.forEach(namespace => {\n isPrivate = privateNamespace === namespace\n if (!hasPrivate) {\n hasPrivate = isPrivate\n }\n if (nsps[namespace]) {\n\n log('[call bindWsHandler]', isPrivate, namespace)\n let args = [namespace, nsps[namespace], ee, isPrivate, opts]\n \n if (opts.serverType === SOCKET_IO) {\n let { nspGroup } = nspMap\n args.push(nspGroup[namespace])\n }\n Reflect.apply(bindSocketEventHandler, null, args)\n } else {\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 notLoginWsHandler(namespace, ee, opts)\n }\n })\n // logout event handler \n if (hasPrivate) {\n log(`Has private and add logoutEvtHandler`)\n\n logoutEvtHandler(nsps, namespaces, ee, opts)\n }\n // finally the disconnect event handlers\n disconnectHandler(nsps, namespaces, ee, opts) \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'\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 * @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 */\nfunction initWebSocketClient(WebSocket, auth = false) {\n if (auth === false) {\n return function createWsClient(url) {\n return new WebSocket(fixWss(url))\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 * @return {object} ws instance\n */\n return function createWsAuthClient(url, token) {\n const ws_url = fixWss(url)\n // console.log('what happen here?', url, ws_url, token)\n const uri = token && typeof token === 'string' ? `${ws_url}?${TOKEN_PARAM_NAME}=${token}` : ws_url\n try {\n return new WebSocket(uri)\n } catch(e) {\n console.error('WebSocket Connection Error', e)\n return false\n }\n }\n}\n\nexport { initWebSocketClient }","// @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}","/**\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 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 * 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","// 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","/**\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","// 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' \n\nconst WS_KEYS = [\n WS_REPLY_TYPE,\n WS_EVT_NAME,\n WS_DATA_NAME\n]\nimport isString from 'lodash-es/isString'\nimport { toJson, isFunc, isObjectHasKey, nil } from './generic'\nimport { timestamp } from './timestamp'\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 can not decoded', 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_TYPE,\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 createReplyMsg, \n createEvt, \n extractWsPayload \n} from 'jsonql-utils/module'\nimport {\n handleNamespaceOnError\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 * @return {void}\n */\nconst logoutEventHandler = (ee) => {\n // listen to the LOGOUT_EVENT_NAME when this is a private nsp\n ee.$on(LOGOUT_EVENT_NAME, function closeEvtHandler() {\n try {\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 socketEventHandler(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 = createReplyMsg(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 const json = extractWsPayload(payload)\n const { resolverName, type } = json\n \n log('Hear 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_TYPE:\n // this is handled error and we won't throw it\n // we need to extract the error from json\n log(`ERROR_TYPE`)\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 logoutEventHandler(ee)\n }\n}\n","// actually binding the event client to the socket client\n\n// from the jsonql-ws-client-core\nimport { clientEventHandler } from '../modules'\n// local \nimport { createNspAction } from './create-nsp-action'\nimport { loginEventHandler } from './login-event-handler'\nimport { socketEventHandler } from './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 // arguments for clientEventHandler\n const args = [opts, nspMap, ee, socketEventHandler]\n\n // now create the nsps\n const { namespaces } = nspMap\n const { token } = opts\n const { nsps } = createNspAction(opts, nspMap, token)\n // binding the listeners - and it will listen to LOGOUT event\n // to unbind itself, and the above call will bind it again\n Reflect.apply(clientEventHandler, null, args.concat([namespaces, nsps]))\n // setup listener for the login event\n if (opts.enableAuth) {\n loginEventHandler(ee, namespaces, nspMap, opts)\n }\n // return what input\n return { opts, nspMap, ee }\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\n\nimport { initWebSocketClient } from './init-websocket-client'\nimport createNsp from '../create-nsp'\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 const publicClient = initWebSocketClient(frameworkModule)\n const privateClient = initWebSocketClient(frameworkModule, true)\n\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 opts.nspClient = publicClient\n opts.nspAuthClient = privateClient \n // @1.0.7 remove later once everything fixed \n const { log } = opts\n if (log && typeof log === 'function') {\n log('@jsonql/ws ee', ee.name)\n log('@jsonql/ws createClientResolver', opts)\n }\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;;;;;;;;;;;;;;;;;"} \ 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 79e1fe5a..626256b4 100644 --- a/packages/@jsonql/ws/src/core/create-nsp/create-nsp.js +++ b/packages/@jsonql/ws/src/core/create-nsp/create-nsp.js @@ -16,7 +16,7 @@ import { socketEventHandler } from './socket-event-handler' */ function createNsp(opts, nspMap, ee) { // arguments for clientEventHandler - const args = [opts, ee, socketEventHandler] + const args = [opts, nspMap, ee, socketEventHandler] // now create the nsps const { namespaces } = nspMap diff --git a/packages/@jsonql/ws/src/core/create-websocket-binding/init-websocket-client.js b/packages/@jsonql/ws/src/core/create-websocket-binding/init-websocket-client.js index 16ced255..7527a433 100644 --- a/packages/@jsonql/ws/src/core/create-websocket-binding/init-websocket-client.js +++ b/packages/@jsonql/ws/src/core/create-websocket-binding/init-websocket-client.js @@ -11,7 +11,7 @@ import { fixWss } from '../modules' */ function initWebSocketClient(WebSocket, auth = false) { if (auth === false) { - return function createWsClientHandler(url) { + return function createWsClient(url) { return new WebSocket(fixWss(url)) } } @@ -22,7 +22,7 @@ function initWebSocketClient(WebSocket, auth = false) { * @param {string} token the jwt token * @return {object} ws instance */ - return function createWsAuthClientHandler(url, token) { + return function createWsAuthClient(url, token) { const ws_url = fixWss(url) // console.log('what happen here?', url, ws_url, token) const uri = token && typeof token === 'string' ? `${ws_url}?${TOKEN_PARAM_NAME}=${token}` : ws_url diff --git a/packages/ws-client-core/src/share/client-event-handler.js b/packages/ws-client-core/src/share/client-event-handler.js index 2a93e38c..f04bc48a 100644 --- a/packages/ws-client-core/src/share/client-event-handler.js +++ b/packages/ws-client-core/src/share/client-event-handler.js @@ -128,14 +128,15 @@ const disconnectHandler = (nsps, namespaces, ee, opts) => { /** * centralize all the comm in one place * @param {object} opts configuration + * @param {object} nspMap this is not in the opts * @param {object} ee Event Emitter instance * @param {function} bindWsHandler binding the ee to ws --> this is the core bit * @param {object} nsps namespaced nsp * @return {void} nothing */ -export function clientEventHandler(opts, ee, bindSocketEventHandler, nsps) { +export function clientEventHandler(opts, nspMap, ee, bindSocketEventHandler, nsps) { // since all these params already in the opts - const { nspMap, log } = opts + const { log } = opts const { namespaces } = nspMap // @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 -- Gitee From dc0428e35bccb17b5a23e7dd6f1b87774df9d29b Mon Sep 17 00:00:00 2001 From: joelchu Date: Fri, 13 Mar 2020 23:22:54 +0800 Subject: [PATCH 35/45] move the create nsp client back because its getting too confusing, just a bit duplicated code --- packages/@jsonql/ws/main.js | 8 +++----- packages/@jsonql/ws/main.js.map | 2 +- .../ws/src/core/create-nsp/create-nsp-action.js | 10 +++++++--- .../bind-framework-to-jsonql.js | 5 +---- .../create-websocket-binding}/create-nsp-client.js | 6 ++---- packages/@jsonql/ws/tests/ws-client-basic.test.js | 7 +++---- packages/ws-client-core/index.js | 10 +--------- .../ws-client-core/src/share/client-event-handler.js | 3 ++- 8 files changed, 20 insertions(+), 31 deletions(-) rename packages/{ws-client-core/src/share => @jsonql/ws/src/core/create-websocket-binding}/create-nsp-client.js (86%) diff --git a/packages/@jsonql/ws/main.js b/packages/@jsonql/ws/main.js index 699a61c5..d985c499 100644 --- a/packages/@jsonql/ws/main.js +++ b/packages/@jsonql/ws/main.js @@ -7766,6 +7766,7 @@ function clientEventHandler$1(opts, nspMap, ee, bindSocketEventHandler, nsps) { if (!hasPrivate) { hasPrivate = isPrivate; } + log(namespace, ' --> nsps --> ', nsps[namespace]); if (nsps[namespace]) { log('[call bindWsHandler]', isPrivate, namespace); @@ -7777,6 +7778,7 @@ function clientEventHandler$1(opts, nspMap, ee, bindSocketEventHandler, nsps) { } Reflect.apply(bindSocketEventHandler, null, args); } 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 @@ -7786,7 +7788,6 @@ function clientEventHandler$1(opts, nspMap, ee, bindSocketEventHandler, nsps) { // logout event handler if (hasPrivate) { log("Has private and add logoutEvtHandler"); - logoutEvtHandler(nsps, namespaces, ee, opts); } // finally the disconnect event handlers @@ -8506,10 +8507,7 @@ function bindFrameworkToJsonql(frameworkModule) { opts.nspAuthClient = privateClient; // @1.0.7 remove later once everything fixed var log = opts.log; - if (log && typeof log === 'function') { - log('@jsonql/ws ee', ee.name); - log('@jsonql/ws createClientResolver', opts); - } + log("bindFrameworkToJsonql", ee.name, nspMap); // console.log(`contract`, opts.contract) return createNsp(opts, nspMap, ee) } diff --git a/packages/@jsonql/ws/main.js.map b/packages/@jsonql/ws/main.js.map index 48133a74..a8a17883 100644 --- a/packages/@jsonql/ws/main.js.map +++ b/packages/@jsonql/ws/main.js.map @@ -1 +1 @@ -{"version":3,"file":"main.js","sources":["node_modules/_rollup-plugin-node-globals@1.4.0@rollup-plugin-node-globals/src/global.js","../../ws-client-core/node_modules/lodash-es/_arrayMap.js","../../ws-client-core/node_modules/lodash-es/isArray.js","../../ws-client-core/node_modules/lodash-es/_objectToString.js","../../ws-client-core/node_modules/lodash-es/isObjectLike.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-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/lodash-es/_overArg.js","../../ws-client-core/node_modules/lodash-es/_arrayFilter.js","../../ws-client-core/node_modules/lodash-es/_createBaseFor.js","../../ws-client-core/node_modules/lodash-es/_baseTimes.js","../../ws-client-core/node_modules/lodash-es/stubFalse.js","../../ws-client-core/node_modules/lodash-es/_isIndex.js","../../ws-client-core/node_modules/lodash-es/isLength.js","../../ws-client-core/node_modules/lodash-es/_baseUnary.js","../../ws-client-core/node_modules/lodash-es/_isPrototype.js","../../ws-client-core/node_modules/lodash-es/isObject.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/_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/_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/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/identity.js","../../ws-client-core/node_modules/lodash-es/_baseProperty.js","../../ws-client-core/node_modules/jsonql-params-validator/src/object.js","../../ws-client-core/node_modules/jsonql-errors/src/validation-error.js","../../ws-client-core/node_modules/jsonql-params-validator/src/validator.js","../../ws-client-core/node_modules/lodash-es/_copyArray.js","../../ws-client-core/node_modules/lodash-es/_safeGet.js","../../ws-client-core/node_modules/lodash-es/_nativeKeysIn.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/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-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-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/node_modules/jsonql-utils/src/generic.js","../../ws-client-core/node_modules/jsonql-errors/src/500-error.js","../../ws-client-core/node_modules/jsonql-errors/src/resolver-not-found-error.js","../../ws-client-core/node_modules/jsonql-errors/src/server-error.js","../../ws-client-core/node_modules/jsonql-utils/src/contract.js","../../ws-client-core/node_modules/jsonql-utils/src/namespace.js","../../ws-client-core/src/utils/helpers.js","../../ws-client-core/src/core/setup-auth-methods.js","../../ws-client-core/src/options/constants.js","../../ws-client-core/src/core/respond-handler.js","../../ws-client-core/src/core/action-call.js","../../ws-client-core/src/core/setup-send-method.js","../../ws-client-core/src/core/setup-resolver.js","../../ws-client-core/src/core/resolver-methods.js","../../ws-client-core/src/core/setup-intercom.js","../../ws-client-core/src/core/generator.js","../../ws-client-core/src/options/index.js","../../ws-client-core/src/api.js","../../ws-client-core/src/share/create-nsp-client.js","../../ws-client-core/src/share/trigger-namespaces-on-error.js","../../ws-client-core/src/share/client-event-handler.js","src/options/index.js","src/core/create-websocket-binding/init-websocket-client.js","src/core/create-nsp/login-event-handler.js","node_modules/_lodash-es@4.17.15@lodash-es/isArray.js","node_modules/_lodash-es@4.17.15@lodash-es/_objectToString.js","node_modules/_lodash-es@4.17.15@lodash-es/isObjectLike.js","node_modules/_jsonql-utils@1.1.3@jsonql-utils/src/generic.js","node_modules/_jsonql-utils@1.1.3@jsonql-utils/src/timestamp.js","node_modules/_jsonql-utils@1.1.3@jsonql-utils/src/socket.js","src/core/create-nsp/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":["export default (typeof global !== \"undefined\" ? global :\n typeof self !== \"undefined\" ? self :\n typeof window !== \"undefined\" ? window : {});\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 * 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 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 * 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 * 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","// 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\nexport const 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)`\nexport const PARAMS_NOT_ARRAY_ERR = `params is not an array! Did something gone wrong when you generate the contract.json?`\nexport const EXCEPTION_CASE_ERR = 'Could not understand your arguments and parameter structure!'\nexport const UNUSUAL_CASE_ERR = 'This is an unusual situation where the arguments are more than the params, but not mark as spread'\n\n// re-export\nimport * as JSONQL_CONSTANTS from 'jsonql-constants'\n// @TODO the jsdoc return array. and we should also allow array syntax\nexport const DEFAULT_TYPE = JSONQL_CONSTANTS.DEFAULT_TYPE\nexport const ARRAY_TYPE_LFT = JSONQL_CONSTANTS.ARRAY_TYPE_LFT\nexport const ARRAY_TYPE_RGT = JSONQL_CONSTANTS.ARRAY_TYPE_RGT\n\nexport const TYPE_KEY = JSONQL_CONSTANTS.TYPE_KEY\nexport const OPTIONAL_KEY = JSONQL_CONSTANTS.OPTIONAL_KEY\nexport const ENUM_KEY = JSONQL_CONSTANTS.ENUM_KEY\nexport const ARGS_KEY = JSONQL_CONSTANTS.ARGS_KEY\nexport const CHECKER_KEY = JSONQL_CONSTANTS.CHECKER_KEY\nexport const ALIAS_KEY = JSONQL_CONSTANTS.ALIAS_KEY\n\nexport const ARRAY_TYPE = JSONQL_CONSTANTS.ARRAY_TYPE\nexport const OBJECT_TYPE = JSONQL_CONSTANTS.OBJECT_TYPE\nexport const STRING_TYPE = JSONQL_CONSTANTS.STRING_TYPE\nexport const BOOLEAN_TYPE = JSONQL_CONSTANTS.BOOLEAN_TYPE\nexport const NUMBER_TYPE = JSONQL_CONSTANTS.NUMBER_TYPE\nexport const KEY_WORD = JSONQL_CONSTANTS.KEY_WORD\nexport const OR_SEPERATOR = JSONQL_CONSTANTS.OR_SEPERATOR\n\n// not actually in use\n// export const NUMBER_TYPES = JSONQL_CONSTANTS.NUMBER_TYPES;\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","/**\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 * 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 * 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 * 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","/**\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","/** 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","/** 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 * 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","/** 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 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","/**\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","/** 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","/** 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 * 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 * 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 * 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","// validate object type\n\nimport isPlainObject from 'lodash-es/isPlainObject'\nimport filter from 'lodash-es/filter'\n\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","// 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","// 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 // checkIsObject,\n combineFn,\n notEmpty\n} from './index'\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 // UNUSUAL_CASE_ERR\n} from './constants'\nimport { DATA_KEY, ERROR_KEY } from 'jsonql-constants'\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","/**\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","/**\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 * 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 * 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","/** 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","// 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","// 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'\n// PIA syntax\nexport const isObject = checkIsObject\nexport const isAny = checkIsAny\nexport const isString = checkIsString\nexport const isBoolean = checkIsBoolean\nexport const isNumber = checkIsNumber\nexport const isArray = checkIsArray\nexport const isNotEmpty = notEmpty\n\nimport * as validator from './src/validator'\n\nexport const normalizeArgs = validator.normalizeArgs\nexport const validateSync = validator.validateSync\nexport const validateAsync = validator.validateAsync\n\n// configuration checking\n\nimport * as jsonqlOptions from './src/options'\n\nexport const JSONQL_PARAMS_VALIDATOR_INFO = jsonqlOptions.JSONQL_PARAMS_VALIDATOR_INFO\n\nexport const createConfig = jsonqlOptions.createConfig\nexport const constructConfig = jsonqlOptions.constructConfigFn\n// construct the final output 1.5.2\nexport const checkConfigAsync = jsonqlOptions.getCheckConfigAsync(validator.validateSync)\nexport const checkConfig = jsonqlOptions.getCheckConfig(validator.validateSync)\n\n// export the two extra functions\nimport isInArray from './src/is-in-array'\nimport isObjectHasKeyFn from './src/is-key-in-object'\n\nexport const inArray = isInArray\nexport const isObjectHasKey = isObjectHasKeyFn\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","// 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","/**\n * This is a custom error to throw when server throw a 500\n * This help us to capture the right error, due to the call happens in sequence\n * @param {string} message to tell what happen\n * @param {mixed} extra things we want to add, 500?\n */\nexport default class Jsonql500Error extends Error {\n constructor(...args) {\n super(...args)\n\n this.message = args[0]\n this.detail = args[1]\n\n this.className = Jsonql500Error.name;\n\n if (Error.captureStackTrace) {\n Error.captureStackTrace(this, Jsonql500Error)\n }\n }\n\n static get statusCode() {\n return 500;\n }\n\n static get name() {\n return 'Jsonql500Error';\n }\n\n}\n","/**\n * This is a custom error to throw when could not find the resolver\n * This help us to capture the right error, due to the call happens in sequence\n * @param {string} message to tell what happen\n * @param {mixed} extra things we want to add, 500?\n */\nexport default class JsonqlResolverNotFoundError extends Error {\n constructor(...args) {\n super(...args)\n\n this.message = args[0]\n this.detail = args[1]\n\n this.className = JsonqlResolverNotFoundError.name;\n\n if (Error.captureStackTrace) {\n Error.captureStackTrace(this, JsonqlResolverNotFoundError);\n }\n }\n\n static get statusCode() {\n return 404;\n }\n\n static get name() {\n return 'JsonqlResolverNotFoundError';\n }\n}\n","// this is from an example from Koa team to use for internal middleware ctx.throw\n// but after the test the res.body part is unable to extract the required data\n// I keep this one here for future reference\n\nexport default class JsonqlServerError extends Error {\n\n constructor(statusCode, message) {\n super(message)\n this.statusCode = statusCode;\n this.className = JsonqlServerError.name;\n }\n\n static get name() {\n return 'JsonqlServerError';\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","// 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.publicNamespace ].join('/'),\n [ base , config.privateNamespace ].join('/')\n ]\n }\n return [ base ]\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","// 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(client, resolverName, setupResolver(namespace, resolverName, params, fn, ee, log))\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 createNamespaceErrorHandler(client, opts, ee, nspGroup) {\n return [\n // using the onError as name\n // @TODO we should follow the convention earlier\n // make this a setter for the clientitself\n objDefineProps(client, ON_ERROR_FN_NAME, 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 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 createOnReadyHandler(client, opts, ee) {\n return [\n objDefineProps(client, ON_READY_FN_NAME, 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 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} ","// 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 createNamespaceErrorHandler,\n createOnReadyHandler\n} from './resolver-methods'\nimport {\n setupFinalStep \n} from './setup-final-step'\nimport {\n NSP_GROUP\n} from 'jsonql-constants'\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 generator(opts, nspMap, ee) {\n\n let args = [\n generateResolvers,\n createNamespaceErrorHandler,\n createOnReadyHandler\n ]\n if (opts.enableAuth) {\n args.push(\n createAuthMethods\n )\n } \n // we will always get back the [ obj, opts, ee ]\n // then we only return the obj (wsClient)\n args.push(setupFinalStep)\n // run it\n const fn = Reflect.apply(chainFns, null, args)\n\n return fn(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 { generator } from './core'\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} frameworkSocketEngine \n * @param {object} config the already checked config \n */\nexport function wsClientCoreAction(frameworkSocketEngine, config) {\n return postCheckInjectOpts(config)\n // the following two moved to wsPostConfig\n .then(createRequiredParams)\n .then(\n ({opts, nspMap, ee}) => frameworkSocketEngine(opts, nspMap, ee)\n )\n .then(\n ({opts, nspMap, ee}) => generator(opts, nspMap, ee)\n )\n .catch(err => {\n console.error(`jsonql-ws-core-client init error`, err)\n })\n}\n\n/**\n * The main interface which will generate the socket clients and map all events\n * @param {object} frameworkSocketEngine 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(frameworkSocketEngine, configCheckMap = {}, constProps = {}) {\n // we need to inject property to this client later\n return (config = {}) => checkConfiguration(config, configCheckMap, constProps)\n .then(opts => wsClientCoreAction(frameworkSocketEngine, opts))\n}\n","// since both the ws and io version are\n// pre-defined in the client-generator\n// and this one will have the same parameters\n// and the callback is identical\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 } = opts\n const url = namespace ? [hostname, namespace].join('/') : wssPath\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 } = opts\n const url = namespace ? [hostname, namespace].join('/') : wssPath\n if (token && typeof token !== 'string') {\n throw new Error(`Expect token to be string, but got ${token}`)\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}","// 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\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, SOCKET_IO, DISCONNECTED_ERROR_MSG } from '../options/constants'\nimport { createEvt, clearMainEmitEvt } from '../utils'\nimport { triggerNamespacesOnError } from './trigger-namespaces-on-error'\n\n/**\n * A Event handler 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 */\nconst notLoginWsHandler = (namespace, ee, opts) => {\n const { log } = opts \n ee.$only(\n createEvt(namespace, EMIT_EVT),\n function notLoginHandlerCallback(resolverName, args) {\n log('[notLoginHandler] hijack the ws call', namespace, resolverName, args)\n const error = {\n message: NOT_LOGIN_ERR_MSG\n }\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 handler, but wrap inside the error key\n ee.$call(createEvt(namespace, resolverName, ON_RESULT_FN_NAME), [{ error }])\n }\n )\n}\n\n/**\n * A Event handler 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 */\nconst disconnectedHandler = (namespace, ee, opts) => {\n const { log } = opts \n ee.$only(\n createEvt(namespace, EMIT_EVT),\n function disconnectedHandlerCallback(resolverName, args) {\n log(`[disconnectedHandler] 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 handler, but wrap inside the error key\n ee.$call(createEvt(namespace, resolverName, ON_RESULT_FN_NAME), [{ error }])\n }\n )\n}\n\n/**\n * get the private namespace\n * @param {array} namespaces array\n * @return {*} string on success\n */\nconst getPrivateNamespace = (namespaces) => (\n namespaces.length > 1 ? namespaces[0] : false\n)\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 */\nconst logoutEvtHandler = (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(LOGOUT_EVENT_NAME, function logoutEvtHandlerAction() {\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 handler\n triggerNamespacesOnError(ee, [privateNamespace], LOGOUT_EVENT_NAME)\n // rebind all of the handler 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 notLoginWsHandler(privateNamespace, ee, opts)\n })\n}\n\n/**\n * The disconnect event handler, 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 */\nconst disconnectHandler = (nsps, namespaces, ee, opts) => {\n const { log } = opts \n ee.$on(DISCONNECT_EVENT_NAME, function disconnectEvtHandler() {\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 disconnectedHandler(namespace, ee, opts)\n })\n })\n}\n\n/**\n * centralize all the comm in one place\n * @param {object} opts configuration\n * @param {object} nspMap this is not in the opts \n * @param {object} ee Event Emitter instance\n * @param {function} bindWsHandler binding the ee to ws --> this is the core bit\n * @param {object} nsps namespaced nsp\n * @return {void} nothing\n */\nexport function clientEventHandler(opts, nspMap, ee, bindSocketEventHandler, nsps) {\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 let isPrivate = false\n let hasPrivate = false\n // loop\n // @BUG for io this has to be in order the one with auth need to get call first\n // The order of login is very import we need to run in order here to make sure\n // one is execute then the other\n namespaces.forEach(namespace => {\n isPrivate = privateNamespace === namespace\n if (!hasPrivate) {\n hasPrivate = isPrivate\n }\n if (nsps[namespace]) {\n\n log('[call bindWsHandler]', isPrivate, namespace)\n let args = [namespace, nsps[namespace], ee, isPrivate, opts]\n \n if (opts.serverType === SOCKET_IO) {\n let { nspGroup } = nspMap\n args.push(nspGroup[namespace])\n }\n Reflect.apply(bindSocketEventHandler, null, args)\n } else {\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 notLoginWsHandler(namespace, ee, opts)\n }\n })\n // logout event handler \n if (hasPrivate) {\n log(`Has private and add logoutEvtHandler`)\n\n logoutEvtHandler(nsps, namespaces, ee, opts)\n }\n // finally the disconnect event handlers\n disconnectHandler(nsps, namespaces, ee, opts) \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'\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 * @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 */\nfunction initWebSocketClient(WebSocket, auth = false) {\n if (auth === false) {\n return function createWsClient(url) {\n return new WebSocket(fixWss(url))\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 * @return {object} ws instance\n */\n return function createWsAuthClient(url, token) {\n const ws_url = fixWss(url)\n // console.log('what happen here?', url, ws_url, token)\n const uri = token && typeof token === 'string' ? `${ws_url}?${TOKEN_PARAM_NAME}=${token}` : ws_url\n try {\n return new WebSocket(uri)\n } catch(e) {\n console.error('WebSocket Connection Error', e)\n return false\n }\n }\n}\n\nexport { initWebSocketClient }","// @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}","/**\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 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 * 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","// 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","/**\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","// 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' \n\nconst WS_KEYS = [\n WS_REPLY_TYPE,\n WS_EVT_NAME,\n WS_DATA_NAME\n]\nimport isString from 'lodash-es/isString'\nimport { toJson, isFunc, isObjectHasKey, nil } from './generic'\nimport { timestamp } from './timestamp'\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 can not decoded', 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_TYPE,\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 createReplyMsg, \n createEvt, \n extractWsPayload \n} from 'jsonql-utils/module'\nimport {\n handleNamespaceOnError\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 * @return {void}\n */\nconst logoutEventHandler = (ee) => {\n // listen to the LOGOUT_EVENT_NAME when this is a private nsp\n ee.$on(LOGOUT_EVENT_NAME, function closeEvtHandler() {\n try {\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 socketEventHandler(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 = createReplyMsg(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 const json = extractWsPayload(payload)\n const { resolverName, type } = json\n \n log('Hear 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_TYPE:\n // this is handled error and we won't throw it\n // we need to extract the error from json\n log(`ERROR_TYPE`)\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 logoutEventHandler(ee)\n }\n}\n","// actually binding the event client to the socket client\n\n// from the jsonql-ws-client-core\nimport { clientEventHandler } from '../modules'\n// local \nimport { createNspAction } from './create-nsp-action'\nimport { loginEventHandler } from './login-event-handler'\nimport { socketEventHandler } from './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 // arguments for clientEventHandler\n const args = [opts, nspMap, ee, socketEventHandler]\n\n // now create the nsps\n const { namespaces } = nspMap\n const { token } = opts\n const { nsps } = createNspAction(opts, nspMap, token)\n // binding the listeners - and it will listen to LOGOUT event\n // to unbind itself, and the above call will bind it again\n Reflect.apply(clientEventHandler, null, args.concat([namespaces, nsps]))\n // setup listener for the login event\n if (opts.enableAuth) {\n loginEventHandler(ee, namespaces, nspMap, opts)\n }\n // return what input\n return { opts, nspMap, ee }\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\n\nimport { initWebSocketClient } from './init-websocket-client'\nimport createNsp from '../create-nsp'\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 const publicClient = initWebSocketClient(frameworkModule)\n const privateClient = initWebSocketClient(frameworkModule, true)\n\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 opts.nspClient = publicClient\n opts.nspAuthClient = privateClient \n // @1.0.7 remove later once everything fixed \n const { log } = opts\n if (log && typeof log === 'function') {\n log('@jsonql/ws ee', ee.name)\n log('@jsonql/ws createClientResolver', opts)\n }\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;;;;;;;;;;;;;;;;;"} \ No newline at end of file +{"version":3,"file":"main.js","sources":["node_modules/_rollup-plugin-node-globals@1.4.0@rollup-plugin-node-globals/src/global.js","../../ws-client-core/node_modules/lodash-es/_arrayMap.js","../../ws-client-core/node_modules/lodash-es/isArray.js","../../ws-client-core/node_modules/lodash-es/_objectToString.js","../../ws-client-core/node_modules/lodash-es/isObjectLike.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-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/lodash-es/_overArg.js","../../ws-client-core/node_modules/lodash-es/_arrayFilter.js","../../ws-client-core/node_modules/lodash-es/_createBaseFor.js","../../ws-client-core/node_modules/lodash-es/_baseTimes.js","../../ws-client-core/node_modules/lodash-es/stubFalse.js","../../ws-client-core/node_modules/lodash-es/_isIndex.js","../../ws-client-core/node_modules/lodash-es/isLength.js","../../ws-client-core/node_modules/lodash-es/_baseUnary.js","../../ws-client-core/node_modules/lodash-es/_isPrototype.js","../../ws-client-core/node_modules/lodash-es/isObject.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/_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/_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/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/identity.js","../../ws-client-core/node_modules/lodash-es/_baseProperty.js","../../ws-client-core/node_modules/jsonql-params-validator/src/object.js","../../ws-client-core/node_modules/jsonql-errors/src/validation-error.js","../../ws-client-core/node_modules/jsonql-params-validator/src/validator.js","../../ws-client-core/node_modules/lodash-es/_copyArray.js","../../ws-client-core/node_modules/lodash-es/_safeGet.js","../../ws-client-core/node_modules/lodash-es/_nativeKeysIn.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/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-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-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/node_modules/jsonql-utils/src/generic.js","../../ws-client-core/node_modules/jsonql-errors/src/500-error.js","../../ws-client-core/node_modules/jsonql-errors/src/resolver-not-found-error.js","../../ws-client-core/node_modules/jsonql-errors/src/server-error.js","../../ws-client-core/node_modules/jsonql-utils/src/contract.js","../../ws-client-core/node_modules/jsonql-utils/src/namespace.js","../../ws-client-core/src/utils/helpers.js","../../ws-client-core/src/core/setup-auth-methods.js","../../ws-client-core/src/options/constants.js","../../ws-client-core/src/core/respond-handler.js","../../ws-client-core/src/core/action-call.js","../../ws-client-core/src/core/setup-send-method.js","../../ws-client-core/src/core/setup-resolver.js","../../ws-client-core/src/core/resolver-methods.js","../../ws-client-core/src/core/setup-intercom.js","../../ws-client-core/src/core/generator.js","../../ws-client-core/src/options/index.js","../../ws-client-core/src/api.js","../../ws-client-core/src/share/create-nsp-client.js","../../ws-client-core/src/share/trigger-namespaces-on-error.js","../../ws-client-core/src/share/client-event-handler.js","src/options/index.js","src/core/create-websocket-binding/init-websocket-client.js","src/core/create-nsp/login-event-handler.js","node_modules/_lodash-es@4.17.15@lodash-es/isArray.js","node_modules/_lodash-es@4.17.15@lodash-es/_objectToString.js","node_modules/_lodash-es@4.17.15@lodash-es/isObjectLike.js","node_modules/_jsonql-utils@1.1.3@jsonql-utils/src/generic.js","node_modules/_jsonql-utils@1.1.3@jsonql-utils/src/timestamp.js","node_modules/_jsonql-utils@1.1.3@jsonql-utils/src/socket.js","src/core/create-nsp/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":["export default (typeof global !== \"undefined\" ? global :\n typeof self !== \"undefined\" ? self :\n typeof window !== \"undefined\" ? window : {});\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 * 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 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 * 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 * 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","// 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\nexport const 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)`\nexport const PARAMS_NOT_ARRAY_ERR = `params is not an array! Did something gone wrong when you generate the contract.json?`\nexport const EXCEPTION_CASE_ERR = 'Could not understand your arguments and parameter structure!'\nexport const UNUSUAL_CASE_ERR = 'This is an unusual situation where the arguments are more than the params, but not mark as spread'\n\n// re-export\nimport * as JSONQL_CONSTANTS from 'jsonql-constants'\n// @TODO the jsdoc return array. and we should also allow array syntax\nexport const DEFAULT_TYPE = JSONQL_CONSTANTS.DEFAULT_TYPE\nexport const ARRAY_TYPE_LFT = JSONQL_CONSTANTS.ARRAY_TYPE_LFT\nexport const ARRAY_TYPE_RGT = JSONQL_CONSTANTS.ARRAY_TYPE_RGT\n\nexport const TYPE_KEY = JSONQL_CONSTANTS.TYPE_KEY\nexport const OPTIONAL_KEY = JSONQL_CONSTANTS.OPTIONAL_KEY\nexport const ENUM_KEY = JSONQL_CONSTANTS.ENUM_KEY\nexport const ARGS_KEY = JSONQL_CONSTANTS.ARGS_KEY\nexport const CHECKER_KEY = JSONQL_CONSTANTS.CHECKER_KEY\nexport const ALIAS_KEY = JSONQL_CONSTANTS.ALIAS_KEY\n\nexport const ARRAY_TYPE = JSONQL_CONSTANTS.ARRAY_TYPE\nexport const OBJECT_TYPE = JSONQL_CONSTANTS.OBJECT_TYPE\nexport const STRING_TYPE = JSONQL_CONSTANTS.STRING_TYPE\nexport const BOOLEAN_TYPE = JSONQL_CONSTANTS.BOOLEAN_TYPE\nexport const NUMBER_TYPE = JSONQL_CONSTANTS.NUMBER_TYPE\nexport const KEY_WORD = JSONQL_CONSTANTS.KEY_WORD\nexport const OR_SEPERATOR = JSONQL_CONSTANTS.OR_SEPERATOR\n\n// not actually in use\n// export const NUMBER_TYPES = JSONQL_CONSTANTS.NUMBER_TYPES;\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","/**\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 * 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 * 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 * 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","/**\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","/** 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","/** 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 * 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","/** 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 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","/**\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","/** 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","/** 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 * 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 * 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 * 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","// validate object type\n\nimport isPlainObject from 'lodash-es/isPlainObject'\nimport filter from 'lodash-es/filter'\n\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","// 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","// 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 // checkIsObject,\n combineFn,\n notEmpty\n} from './index'\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 // UNUSUAL_CASE_ERR\n} from './constants'\nimport { DATA_KEY, ERROR_KEY } from 'jsonql-constants'\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","/**\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","/**\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 * 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 * 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","/** 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","// 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","// 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'\n// PIA syntax\nexport const isObject = checkIsObject\nexport const isAny = checkIsAny\nexport const isString = checkIsString\nexport const isBoolean = checkIsBoolean\nexport const isNumber = checkIsNumber\nexport const isArray = checkIsArray\nexport const isNotEmpty = notEmpty\n\nimport * as validator from './src/validator'\n\nexport const normalizeArgs = validator.normalizeArgs\nexport const validateSync = validator.validateSync\nexport const validateAsync = validator.validateAsync\n\n// configuration checking\n\nimport * as jsonqlOptions from './src/options'\n\nexport const JSONQL_PARAMS_VALIDATOR_INFO = jsonqlOptions.JSONQL_PARAMS_VALIDATOR_INFO\n\nexport const createConfig = jsonqlOptions.createConfig\nexport const constructConfig = jsonqlOptions.constructConfigFn\n// construct the final output 1.5.2\nexport const checkConfigAsync = jsonqlOptions.getCheckConfigAsync(validator.validateSync)\nexport const checkConfig = jsonqlOptions.getCheckConfig(validator.validateSync)\n\n// export the two extra functions\nimport isInArray from './src/is-in-array'\nimport isObjectHasKeyFn from './src/is-key-in-object'\n\nexport const inArray = isInArray\nexport const isObjectHasKey = isObjectHasKeyFn\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","// 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","/**\n * This is a custom error to throw when server throw a 500\n * This help us to capture the right error, due to the call happens in sequence\n * @param {string} message to tell what happen\n * @param {mixed} extra things we want to add, 500?\n */\nexport default class Jsonql500Error extends Error {\n constructor(...args) {\n super(...args)\n\n this.message = args[0]\n this.detail = args[1]\n\n this.className = Jsonql500Error.name;\n\n if (Error.captureStackTrace) {\n Error.captureStackTrace(this, Jsonql500Error)\n }\n }\n\n static get statusCode() {\n return 500;\n }\n\n static get name() {\n return 'Jsonql500Error';\n }\n\n}\n","/**\n * This is a custom error to throw when could not find the resolver\n * This help us to capture the right error, due to the call happens in sequence\n * @param {string} message to tell what happen\n * @param {mixed} extra things we want to add, 500?\n */\nexport default class JsonqlResolverNotFoundError extends Error {\n constructor(...args) {\n super(...args)\n\n this.message = args[0]\n this.detail = args[1]\n\n this.className = JsonqlResolverNotFoundError.name;\n\n if (Error.captureStackTrace) {\n Error.captureStackTrace(this, JsonqlResolverNotFoundError);\n }\n }\n\n static get statusCode() {\n return 404;\n }\n\n static get name() {\n return 'JsonqlResolverNotFoundError';\n }\n}\n","// this is from an example from Koa team to use for internal middleware ctx.throw\n// but after the test the res.body part is unable to extract the required data\n// I keep this one here for future reference\n\nexport default class JsonqlServerError extends Error {\n\n constructor(statusCode, message) {\n super(message)\n this.statusCode = statusCode;\n this.className = JsonqlServerError.name;\n }\n\n static get name() {\n return 'JsonqlServerError';\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","// 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.publicNamespace ].join('/'),\n [ base , config.privateNamespace ].join('/')\n ]\n }\n return [ base ]\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","// 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(client, resolverName, setupResolver(namespace, resolverName, params, fn, ee, log))\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 createNamespaceErrorHandler(client, opts, ee, nspGroup) {\n return [\n // using the onError as name\n // @TODO we should follow the convention earlier\n // make this a setter for the clientitself\n objDefineProps(client, ON_ERROR_FN_NAME, 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 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 createOnReadyHandler(client, opts, ee) {\n return [\n objDefineProps(client, ON_READY_FN_NAME, 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 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} ","// 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 createNamespaceErrorHandler,\n createOnReadyHandler\n} from './resolver-methods'\nimport {\n setupFinalStep \n} from './setup-final-step'\nimport {\n NSP_GROUP\n} from 'jsonql-constants'\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 generator(opts, nspMap, ee) {\n\n let args = [\n generateResolvers,\n createNamespaceErrorHandler,\n createOnReadyHandler\n ]\n if (opts.enableAuth) {\n args.push(\n createAuthMethods\n )\n } \n // we will always get back the [ obj, opts, ee ]\n // then we only return the obj (wsClient)\n args.push(setupFinalStep)\n // run it\n const fn = Reflect.apply(chainFns, null, args)\n\n return fn(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 { generator } from './core'\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} frameworkSocketEngine \n * @param {object} config the already checked config \n */\nexport function wsClientCoreAction(frameworkSocketEngine, config) {\n return postCheckInjectOpts(config)\n // the following two moved to wsPostConfig\n .then(createRequiredParams)\n .then(\n ({opts, nspMap, ee}) => frameworkSocketEngine(opts, nspMap, ee)\n )\n .then(\n ({opts, nspMap, ee}) => generator(opts, nspMap, ee)\n )\n .catch(err => {\n console.error(`jsonql-ws-core-client init error`, err)\n })\n}\n\n/**\n * The main interface which will generate the socket clients and map all events\n * @param {object} frameworkSocketEngine 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(frameworkSocketEngine, configCheckMap = {}, constProps = {}) {\n // we need to inject property to this client later\n return (config = {}) => checkConfiguration(config, configCheckMap, constProps)\n .then(opts => wsClientCoreAction(frameworkSocketEngine, opts))\n}\n","// since both the ws and io version are\n// pre-defined in the client-generator\n// and this one will have the same parameters\n// and the callback is identical\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 } = opts\n const url = namespace ? [hostname, namespace].join('/') : wssPath\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 } = opts\n const url = namespace ? [hostname, namespace].join('/') : wssPath\n if (token && typeof token !== 'string') {\n throw new Error(`Expect token to be string, but got ${token}`)\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}","// 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\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, SOCKET_IO, DISCONNECTED_ERROR_MSG } from '../options/constants'\nimport { createEvt, clearMainEmitEvt } from '../utils'\nimport { triggerNamespacesOnError } from './trigger-namespaces-on-error'\n\n/**\n * A Event handler 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 */\nconst notLoginWsHandler = (namespace, ee, opts) => {\n const { log } = opts \n ee.$only(\n createEvt(namespace, EMIT_EVT),\n function notLoginHandlerCallback(resolverName, args) {\n log('[notLoginHandler] hijack the ws call', namespace, resolverName, args)\n const error = {\n message: NOT_LOGIN_ERR_MSG\n }\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 handler, but wrap inside the error key\n ee.$call(createEvt(namespace, resolverName, ON_RESULT_FN_NAME), [{ error }])\n }\n )\n}\n\n/**\n * A Event handler 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 */\nconst disconnectedHandler = (namespace, ee, opts) => {\n const { log } = opts \n ee.$only(\n createEvt(namespace, EMIT_EVT),\n function disconnectedHandlerCallback(resolverName, args) {\n log(`[disconnectedHandler] 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 handler, but wrap inside the error key\n ee.$call(createEvt(namespace, resolverName, ON_RESULT_FN_NAME), [{ error }])\n }\n )\n}\n\n/**\n * get the private namespace\n * @param {array} namespaces array\n * @return {*} string on success\n */\nconst getPrivateNamespace = (namespaces) => (\n namespaces.length > 1 ? namespaces[0] : false\n)\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 */\nconst logoutEvtHandler = (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(LOGOUT_EVENT_NAME, function logoutEvtHandlerAction() {\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 handler\n triggerNamespacesOnError(ee, [privateNamespace], LOGOUT_EVENT_NAME)\n // rebind all of the handler 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 notLoginWsHandler(privateNamespace, ee, opts)\n })\n}\n\n/**\n * The disconnect event handler, 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 */\nconst disconnectHandler = (nsps, namespaces, ee, opts) => {\n const { log } = opts \n ee.$on(DISCONNECT_EVENT_NAME, function disconnectEvtHandler() {\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 disconnectedHandler(namespace, ee, opts)\n })\n })\n}\n\n/**\n * centralize all the comm in one place\n * @param {object} opts configuration\n * @param {object} nspMap this is not in the opts \n * @param {object} ee Event Emitter instance\n * @param {function} bindWsHandler binding the ee to ws --> this is the core bit\n * @param {object} nsps namespaced nsp\n * @return {void} nothing\n */\nexport function clientEventHandler(opts, nspMap, ee, bindSocketEventHandler, nsps) {\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 let isPrivate = false\n let hasPrivate = false\n // loop\n // @BUG for io this has to be in order the one with auth need to get call first\n // The order of login is very import we need to run in order here to make sure\n // one is execute then the other\n namespaces.forEach(namespace => {\n isPrivate = privateNamespace === namespace\n if (!hasPrivate) {\n hasPrivate = isPrivate\n }\n log(namespace, ' --> nsps --> ', nsps[namespace])\n if (nsps[namespace]) {\n\n log('[call bindWsHandler]', isPrivate, namespace)\n let args = [namespace, nsps[namespace], ee, isPrivate, opts]\n \n if (opts.serverType === SOCKET_IO) {\n let { nspGroup } = nspMap\n args.push(nspGroup[namespace])\n }\n Reflect.apply(bindSocketEventHandler, null, args)\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 notLoginWsHandler(namespace, ee, opts)\n }\n })\n // logout event handler \n if (hasPrivate) {\n log(`Has private and add logoutEvtHandler`)\n logoutEvtHandler(nsps, namespaces, ee, opts)\n }\n // finally the disconnect event handlers\n disconnectHandler(nsps, namespaces, ee, opts) \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'\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 * @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 */\nfunction initWebSocketClient(WebSocket, auth = false) {\n if (auth === false) {\n return function createWsClient(url) {\n return new WebSocket(fixWss(url))\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 * @return {object} ws instance\n */\n return function createWsAuthClient(url, token) {\n const ws_url = fixWss(url)\n // console.log('what happen here?', url, ws_url, token)\n const uri = token && typeof token === 'string' ? `${ws_url}?${TOKEN_PARAM_NAME}=${token}` : ws_url\n try {\n return new WebSocket(uri)\n } catch(e) {\n console.error('WebSocket Connection Error', e)\n return false\n }\n }\n}\n\nexport { initWebSocketClient }","// @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}","/**\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 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 * 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","// 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","/**\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","// 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' \n\nconst WS_KEYS = [\n WS_REPLY_TYPE,\n WS_EVT_NAME,\n WS_DATA_NAME\n]\nimport isString from 'lodash-es/isString'\nimport { toJson, isFunc, isObjectHasKey, nil } from './generic'\nimport { timestamp } from './timestamp'\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 can not decoded', 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_TYPE,\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 createReplyMsg, \n createEvt, \n extractWsPayload \n} from 'jsonql-utils/module'\nimport {\n handleNamespaceOnError\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 * @return {void}\n */\nconst logoutEventHandler = (ee) => {\n // listen to the LOGOUT_EVENT_NAME when this is a private nsp\n ee.$on(LOGOUT_EVENT_NAME, function closeEvtHandler() {\n try {\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 socketEventHandler(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 = createReplyMsg(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 const json = extractWsPayload(payload)\n const { resolverName, type } = json\n \n log('Hear 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_TYPE:\n // this is handled error and we won't throw it\n // we need to extract the error from json\n log(`ERROR_TYPE`)\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 logoutEventHandler(ee)\n }\n}\n","// actually binding the event client to the socket client\n\n// from the jsonql-ws-client-core\nimport { clientEventHandler } from '../modules'\n// local \nimport { createNspAction } from './create-nsp-action'\nimport { loginEventHandler } from './login-event-handler'\nimport { socketEventHandler } from './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 // arguments for clientEventHandler\n const args = [opts, nspMap, ee, socketEventHandler]\n\n // now create the nsps\n const { namespaces } = nspMap\n const { token } = opts\n const { nsps } = createNspAction(opts, nspMap, token)\n // binding the listeners - and it will listen to LOGOUT event\n // to unbind itself, and the above call will bind it again\n Reflect.apply(clientEventHandler, null, args.concat([namespaces, nsps]))\n // setup listener for the login event\n if (opts.enableAuth) {\n loginEventHandler(ee, namespaces, nspMap, opts)\n }\n // return what input\n return { opts, nspMap, ee }\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\n\nimport { initWebSocketClient } from './init-websocket-client'\nimport createNsp from '../create-nsp'\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 const publicClient = initWebSocketClient(frameworkModule)\n const privateClient = initWebSocketClient(frameworkModule, true)\n\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 opts.nspClient = publicClient\n opts.nspAuthClient = privateClient \n // @1.0.7 remove later once everything fixed \n const { log } = opts\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;;;;;;;;;;;;;;;;;"} \ No newline at end of file diff --git a/packages/@jsonql/ws/src/core/create-nsp/create-nsp-action.js b/packages/@jsonql/ws/src/core/create-nsp/create-nsp-action.js index c3b50b39..92f26982 100644 --- a/packages/@jsonql/ws/src/core/create-nsp/create-nsp-action.js +++ b/packages/@jsonql/ws/src/core/create-nsp/create-nsp-action.js @@ -17,16 +17,19 @@ const createNspAction = function(opts, nspMap, token) { return { nsps: (() => { + const { nspClient, nspAuthClient } = opts + // first we need to binding all the events handler if (opts.enableAuth) { // && opts.useJwt - + return namespaces.map((namespace, i) => { if (i === 0) { if (token) { opts.token = token log('create createNspAuthClient at run time') return { - [namespace]: createNspAuthClient(namespace, opts) + [namespace]: nspAuthClient() + // createNspAuthClient(namespace, opts) } } return { @@ -41,7 +44,8 @@ const createNspAction = function(opts, nspMap, token) { // standard without login return { - [publicNamespace]: createNspClient(false, opts) + [publicNamespace]: + // createNspClient(false, opts) } })() } diff --git a/packages/@jsonql/ws/src/core/create-websocket-binding/bind-framework-to-jsonql.js b/packages/@jsonql/ws/src/core/create-websocket-binding/bind-framework-to-jsonql.js index bcd4e36c..b10d0783 100644 --- a/packages/@jsonql/ws/src/core/create-websocket-binding/bind-framework-to-jsonql.js +++ b/packages/@jsonql/ws/src/core/create-websocket-binding/bind-framework-to-jsonql.js @@ -25,10 +25,7 @@ function bindFrameworkToJsonql(frameworkModule) { opts.nspAuthClient = privateClient // @1.0.7 remove later once everything fixed const { log } = opts - if (log && typeof log === 'function') { - log('@jsonql/ws ee', ee.name) - log('@jsonql/ws createClientResolver', opts) - } + log(`bindFrameworkToJsonql`, ee.name, nspMap) // console.log(`contract`, opts.contract) return createNsp(opts, nspMap, ee) } diff --git a/packages/ws-client-core/src/share/create-nsp-client.js b/packages/@jsonql/ws/src/core/create-websocket-binding/create-nsp-client.js similarity index 86% rename from packages/ws-client-core/src/share/create-nsp-client.js rename to packages/@jsonql/ws/src/core/create-websocket-binding/create-nsp-client.js index ab4c41ed..faaadb49 100644 --- a/packages/ws-client-core/src/share/create-nsp-client.js +++ b/packages/@jsonql/ws/src/core/create-websocket-binding/create-nsp-client.js @@ -1,7 +1,5 @@ -// since both the ws and io version are -// pre-defined in the client-generator -// and this one will have the same parameters -// and the callback is identical +// this is getting too confusing +// therefore we move it back to the framework specific /** * wrapper method to create a nsp without login diff --git a/packages/@jsonql/ws/tests/ws-client-basic.test.js b/packages/@jsonql/ws/tests/ws-client-basic.test.js index d6ea0c1f..e6c2d5fd 100644 --- a/packages/@jsonql/ws/tests/ws-client-basic.test.js +++ b/packages/@jsonql/ws/tests/ws-client-basic.test.js @@ -28,14 +28,14 @@ test.before(async t => { t.context.client = await wsClient({ hostname: `ws://localhost:${port}`, contract: publicContract - }, {log: () => {}}) // set a dummy because too much output + }, {log: debug}) // set a dummy because too much output }) // finish test.after(t => { t.context.server.close() }) // start test -test.cb('It should able to connect to the ws server', t => { +test.cb.only('It should able to connect to the ws server', t => { t.plan(2) let client = t.context.client // this will get respond last @@ -49,7 +49,6 @@ test.cb('It should able to connect to the ws server', t => { client.simple.onResult = (result) => { debug(`Catch the onResult event`.rainbow, result) t.is(101, result) - } }) @@ -66,7 +65,7 @@ test.cb('It should able to handle error', t => { } }) -test.cb.only('It should able to send message back while its talking to the server', t => { +test.cb('It should able to send message back while its talking to the server', t => { t.plan(1) let c = 0; let client = t.context.client diff --git a/packages/ws-client-core/index.js b/packages/ws-client-core/index.js index fadc99e2..f30c8060 100644 --- a/packages/ws-client-core/index.js +++ b/packages/ws-client-core/index.js @@ -12,12 +12,7 @@ import { } from './src/options' // these were in the share.js and now we combine into one import * as jsonqlWsConstants from './src/options/constants' -// import the share methods -import { - createNspClient, - createNspAuthClient -} from './src/share/create-nsp-client' -import { +import { triggerNamespacesOnError, handleNamespaceOnError } from './src/share/trigger-namespaces-on-error' @@ -54,9 +49,6 @@ export { checkSocketClientType, // from share.js - - createNspClient, - createNspAuthClient, triggerNamespacesOnError, handleNamespaceOnError, diff --git a/packages/ws-client-core/src/share/client-event-handler.js b/packages/ws-client-core/src/share/client-event-handler.js index f04bc48a..8191ca1e 100644 --- a/packages/ws-client-core/src/share/client-event-handler.js +++ b/packages/ws-client-core/src/share/client-event-handler.js @@ -152,6 +152,7 @@ export function clientEventHandler(opts, nspMap, ee, bindSocketEventHandler, nsp if (!hasPrivate) { hasPrivate = isPrivate } + log(namespace, ' --> nsps --> ', nsps[namespace]) if (nsps[namespace]) { log('[call bindWsHandler]', isPrivate, namespace) @@ -163,6 +164,7 @@ export function clientEventHandler(opts, nspMap, ee, bindSocketEventHandler, nsp } Reflect.apply(bindSocketEventHandler, null, args) } 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 @@ -172,7 +174,6 @@ export function clientEventHandler(opts, nspMap, ee, bindSocketEventHandler, nsp // logout event handler if (hasPrivate) { log(`Has private and add logoutEvtHandler`) - logoutEvtHandler(nsps, namespaces, ee, opts) } // finally the disconnect event handlers -- Gitee From 92462092d498e60689933b1c3475057b8b120a4b Mon Sep 17 00:00:00 2001 From: joelchu Date: Fri, 13 Mar 2020 23:58:49 +0800 Subject: [PATCH 36/45] moving things back to where they because finally figure out how it suppose to work --- .../ws/src/core/create-nsp/create-nsp-action.js | 11 ++++------- .../bind-framework-to-jsonql.js | 8 ++++---- packages/@jsonql/ws/src/core/modules.js | 10 ++++------ packages/ws-client-core/index.js | 10 +++++++++- .../src/share/create-nsp-clients.js} | 9 +++++++-- 5 files changed, 28 insertions(+), 20 deletions(-) rename packages/{@jsonql/ws/src/core/create-websocket-binding/create-nsp-client.js => ws-client-core/src/share/create-nsp-clients.js} (81%) diff --git a/packages/@jsonql/ws/src/core/create-nsp/create-nsp-action.js b/packages/@jsonql/ws/src/core/create-nsp/create-nsp-action.js index 92f26982..6b968dc0 100644 --- a/packages/@jsonql/ws/src/core/create-nsp/create-nsp-action.js +++ b/packages/@jsonql/ws/src/core/create-nsp/create-nsp-action.js @@ -1,6 +1,6 @@ import { createNspClient, - createNspAuthClient, + createNspAuthClient } from '../modules' /** @@ -14,11 +14,10 @@ import { const createNspAction = function(opts, nspMap, token) { const { log } = opts let { publicNamespace, namespaces } = nspMap + log(`createNspAction`, 'publicNamespace', publicNamespace, 'namespaces', namespaces) return { nsps: (() => { - const { nspClient, nspAuthClient } = opts - // first we need to binding all the events handler if (opts.enableAuth) { // && opts.useJwt @@ -28,8 +27,7 @@ const createNspAction = function(opts, nspMap, token) { opts.token = token log('create createNspAuthClient at run time') return { - [namespace]: nspAuthClient() - // createNspAuthClient(namespace, opts) + [namespace]: createNspAuthClient(namespace, opts) } } return { @@ -44,8 +42,7 @@ const createNspAction = function(opts, nspMap, token) { // standard without login return { - [publicNamespace]: - // createNspClient(false, opts) + [publicNamespace]: createNspClient(false, opts) } })() } diff --git a/packages/@jsonql/ws/src/core/create-websocket-binding/bind-framework-to-jsonql.js b/packages/@jsonql/ws/src/core/create-websocket-binding/bind-framework-to-jsonql.js index b10d0783..08ebee44 100644 --- a/packages/@jsonql/ws/src/core/create-websocket-binding/bind-framework-to-jsonql.js +++ b/packages/@jsonql/ws/src/core/create-websocket-binding/bind-framework-to-jsonql.js @@ -10,8 +10,8 @@ import createNsp from '../create-nsp' */ function bindFrameworkToJsonql(frameworkModule) { - const publicClient = initWebSocketClient(frameworkModule) - const privateClient = initWebSocketClient(frameworkModule, true) + const nspClient = initWebSocketClient(frameworkModule) + const nspAuthClient = initWebSocketClient(frameworkModule, true) /** * wsClientResolver @@ -21,8 +21,8 @@ function bindFrameworkToJsonql(frameworkModule) { * @return {object} passing the same 3 input out with additional in the opts */ return function createClientBindingAction(opts, nspMap, ee) { - opts.nspClient = publicClient - opts.nspAuthClient = privateClient + opts.nspClient = nspClient + opts.nspAuthClient = nspAuthClient // @1.0.7 remove later once everything fixed const { log } = opts log(`bindFrameworkToJsonql`, ee.name, nspMap) diff --git a/packages/@jsonql/ws/src/core/modules.js b/packages/@jsonql/ws/src/core/modules.js index bb9a2abf..bd36ddc2 100644 --- a/packages/@jsonql/ws/src/core/modules.js +++ b/packages/@jsonql/ws/src/core/modules.js @@ -3,14 +3,13 @@ import { wsCoreCheckMap, wsCoreConstProps, + jsonqlWsConstants, // generator methods wsClientCore, wsClientCoreAction, // helper methods checkSocketClientType, - // from share.js - jsonqlWsConstants, - + // construct url and call the nspClient createNspClient, createNspAuthClient, @@ -30,14 +29,13 @@ import { export { wsCoreCheckMap, wsCoreConstProps, + jsonqlWsConstants, // generator methods wsClientCore, wsClientCoreAction, // helper methods checkSocketClientType, - // from share.js - jsonqlWsConstants, - + createNspClient, createNspAuthClient, diff --git a/packages/ws-client-core/index.js b/packages/ws-client-core/index.js index f30c8060..2398a68f 100644 --- a/packages/ws-client-core/index.js +++ b/packages/ws-client-core/index.js @@ -12,6 +12,13 @@ import { } from './src/options' // these were in the share.js and now we combine into one import * as jsonqlWsConstants from './src/options/constants' +// moving it back because it's the same for two different framework +import { + createNspClient, + createNspAuthClient +} from './src/share/create-nsp-clients' + + import { triggerNamespacesOnError, handleNamespaceOnError @@ -48,7 +55,8 @@ export { checkSocketClientType, // from share.js - + createNspClient, + createNspAuthClient, triggerNamespacesOnError, handleNamespaceOnError, diff --git a/packages/@jsonql/ws/src/core/create-websocket-binding/create-nsp-client.js b/packages/ws-client-core/src/share/create-nsp-clients.js similarity index 81% rename from packages/@jsonql/ws/src/core/create-websocket-binding/create-nsp-client.js rename to packages/ws-client-core/src/share/create-nsp-clients.js index faaadb49..330ab258 100644 --- a/packages/@jsonql/ws/src/core/create-websocket-binding/create-nsp-client.js +++ b/packages/ws-client-core/src/share/create-nsp-clients.js @@ -8,8 +8,10 @@ * @return {object} ws client instance */ function createNspClient(namespace, opts) { - const { hostname, wssPath, wsOptions, nspClient } = opts + const { hostname, wssPath, wsOptions, nspClient, log } = opts const url = namespace ? [hostname, namespace].join('/') : wssPath + log(`createNspClient --> `, url) + return nspClient(url, wsOptions) } @@ -20,11 +22,14 @@ function createNspClient(namespace, opts) { * @return {object} ws client instance */ function createNspAuthClient(namespace, opts) { - const { hostname, wssPath, token, wsOptions, nspAuthClient } = opts + const { hostname, wssPath, token, wsOptions, nspAuthClient, log } = opts const url = namespace ? [hostname, namespace].join('/') : wssPath + log(`createNspAuthClient -->`, url) + if (token && typeof token !== 'string') { throw new Error(`Expect token to be string, but got ${token}`) } + return nspAuthClient(url, token, wsOptions) } -- Gitee From ff34e5aa9300af7e38633515e2ad9fc686ce6a7f Mon Sep 17 00:00:00 2001 From: joelchu Date: Sat, 14 Mar 2020 00:37:29 +0800 Subject: [PATCH 37/45] Fix the init nsps problem --- packages/@jsonql/ws/main.js | 31 ++++++++++++------- packages/@jsonql/ws/main.js.map | 2 +- .../src/core/create-nsp/create-nsp-action.js | 1 - .../ws/src/core/create-nsp/create-nsp.js | 7 +++-- .../src/share/client-event-handler.js | 2 +- 5 files changed, 27 insertions(+), 16 deletions(-) diff --git a/packages/@jsonql/ws/main.js b/packages/@jsonql/ws/main.js index d985c499..69f565df 100644 --- a/packages/@jsonql/ws/main.js +++ b/packages/@jsonql/ws/main.js @@ -7557,10 +7557,8 @@ function wsClientCore(frameworkSocketEngine, configCheckMap, constProps) { } } -// since both the ws and io version are -// pre-defined in the client-generator -// and this one will have the same parameters -// and the callback is identical +// this is getting too confusing +// therefore we move it back to the framework specific /** * wrapper method to create a nsp without login @@ -7573,7 +7571,10 @@ function createNspClient(namespace, opts) { var wssPath = opts.wssPath; var wsOptions = opts.wsOptions; var nspClient = opts.nspClient; + var log = opts.log; var url = namespace ? [hostname, namespace].join('/') : wssPath; + log("createNspClient --> ", url); + return nspClient(url, wsOptions) } @@ -7589,10 +7590,14 @@ function createNspAuthClient(namespace, opts) { var token = opts.token; var wsOptions = opts.wsOptions; var nspAuthClient = opts.nspAuthClient; + var log = opts.log; var url = namespace ? [hostname, namespace].join('/') : wssPath; + log("createNspAuthClient -->", url); + if (token && typeof token !== 'string') { throw new Error(("Expect token to be string, but got " + token)) } + return nspAuthClient(url, token, wsOptions) } @@ -7872,6 +7877,7 @@ var createNspAction$1 = function(opts, nspMap, token) { var log = opts.log; var publicNamespace = nspMap.publicNamespace; var namespaces = nspMap.namespaces; + log("createNspAction", 'publicNamespace', publicNamespace, 'namespaces', namespaces); return { nsps: (function () { @@ -7879,7 +7885,7 @@ var createNspAction$1 = function(opts, nspMap, token) { // first we need to binding all the events handler if (opts.enableAuth) { // && opts.useJwt - + return namespaces.map(function (namespace, i) { var obj, obj$1, obj$2; @@ -7894,7 +7900,6 @@ var createNspAction$1 = function(opts, nspMap, token) { return ( obj$2 = {}, obj$2[namespace] = createNspClient(namespace, opts), obj$2 ) }).reduce(function (first, next) { return Object.assign(first, next); }, {}) } - // standard without login return ( obj = {}, obj[publicNamespace] = createNspClient(false, opts), obj ) })() @@ -8468,11 +8473,15 @@ function createNsp(opts, nspMap, ee) { // now create the nsps var namespaces = nspMap.namespaces; var token = opts.token; + var log = opts.log; var ref = createNspAction$1(opts, nspMap, token); var nsps = ref.nsps; + args.push(nsps); + // log(`argument length`, args.length, args) + // binding the listeners - and it will listen to LOGOUT event // to unbind itself, and the above call will bind it again - Reflect.apply(clientEventHandler$1, null, args.concat([namespaces, nsps])); + Reflect.apply(clientEventHandler$1, null, args); // setup listener for the login event if (opts.enableAuth) { loginEventHandler(ee, namespaces, nspMap); @@ -8492,8 +8501,8 @@ function createNsp(opts, nspMap, ee) { */ function bindFrameworkToJsonql(frameworkModule) { - var publicClient = initWebSocketClient(frameworkModule); - var privateClient = initWebSocketClient(frameworkModule, true); + var nspClient = initWebSocketClient(frameworkModule); + var nspAuthClient = initWebSocketClient(frameworkModule, true); /** * wsClientResolver @@ -8503,8 +8512,8 @@ function bindFrameworkToJsonql(frameworkModule) { * @return {object} passing the same 3 input out with additional in the opts */ return function createClientBindingAction(opts, nspMap, ee) { - opts.nspClient = publicClient; - opts.nspAuthClient = privateClient; + opts.nspClient = nspClient; + opts.nspAuthClient = nspAuthClient; // @1.0.7 remove later once everything fixed var log = opts.log; log("bindFrameworkToJsonql", ee.name, nspMap); diff --git a/packages/@jsonql/ws/main.js.map b/packages/@jsonql/ws/main.js.map index a8a17883..cf64ff4c 100644 --- a/packages/@jsonql/ws/main.js.map +++ b/packages/@jsonql/ws/main.js.map @@ -1 +1 @@ -{"version":3,"file":"main.js","sources":["node_modules/_rollup-plugin-node-globals@1.4.0@rollup-plugin-node-globals/src/global.js","../../ws-client-core/node_modules/lodash-es/_arrayMap.js","../../ws-client-core/node_modules/lodash-es/isArray.js","../../ws-client-core/node_modules/lodash-es/_objectToString.js","../../ws-client-core/node_modules/lodash-es/isObjectLike.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-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/lodash-es/_overArg.js","../../ws-client-core/node_modules/lodash-es/_arrayFilter.js","../../ws-client-core/node_modules/lodash-es/_createBaseFor.js","../../ws-client-core/node_modules/lodash-es/_baseTimes.js","../../ws-client-core/node_modules/lodash-es/stubFalse.js","../../ws-client-core/node_modules/lodash-es/_isIndex.js","../../ws-client-core/node_modules/lodash-es/isLength.js","../../ws-client-core/node_modules/lodash-es/_baseUnary.js","../../ws-client-core/node_modules/lodash-es/_isPrototype.js","../../ws-client-core/node_modules/lodash-es/isObject.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/_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/_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/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/identity.js","../../ws-client-core/node_modules/lodash-es/_baseProperty.js","../../ws-client-core/node_modules/jsonql-params-validator/src/object.js","../../ws-client-core/node_modules/jsonql-errors/src/validation-error.js","../../ws-client-core/node_modules/jsonql-params-validator/src/validator.js","../../ws-client-core/node_modules/lodash-es/_copyArray.js","../../ws-client-core/node_modules/lodash-es/_safeGet.js","../../ws-client-core/node_modules/lodash-es/_nativeKeysIn.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/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-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-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/node_modules/jsonql-utils/src/generic.js","../../ws-client-core/node_modules/jsonql-errors/src/500-error.js","../../ws-client-core/node_modules/jsonql-errors/src/resolver-not-found-error.js","../../ws-client-core/node_modules/jsonql-errors/src/server-error.js","../../ws-client-core/node_modules/jsonql-utils/src/contract.js","../../ws-client-core/node_modules/jsonql-utils/src/namespace.js","../../ws-client-core/src/utils/helpers.js","../../ws-client-core/src/core/setup-auth-methods.js","../../ws-client-core/src/options/constants.js","../../ws-client-core/src/core/respond-handler.js","../../ws-client-core/src/core/action-call.js","../../ws-client-core/src/core/setup-send-method.js","../../ws-client-core/src/core/setup-resolver.js","../../ws-client-core/src/core/resolver-methods.js","../../ws-client-core/src/core/setup-intercom.js","../../ws-client-core/src/core/generator.js","../../ws-client-core/src/options/index.js","../../ws-client-core/src/api.js","../../ws-client-core/src/share/create-nsp-client.js","../../ws-client-core/src/share/trigger-namespaces-on-error.js","../../ws-client-core/src/share/client-event-handler.js","src/options/index.js","src/core/create-websocket-binding/init-websocket-client.js","src/core/create-nsp/login-event-handler.js","node_modules/_lodash-es@4.17.15@lodash-es/isArray.js","node_modules/_lodash-es@4.17.15@lodash-es/_objectToString.js","node_modules/_lodash-es@4.17.15@lodash-es/isObjectLike.js","node_modules/_jsonql-utils@1.1.3@jsonql-utils/src/generic.js","node_modules/_jsonql-utils@1.1.3@jsonql-utils/src/timestamp.js","node_modules/_jsonql-utils@1.1.3@jsonql-utils/src/socket.js","src/core/create-nsp/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":["export default (typeof global !== \"undefined\" ? global :\n typeof self !== \"undefined\" ? self :\n typeof window !== \"undefined\" ? window : {});\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 * 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 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 * 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 * 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","// 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\nexport const 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)`\nexport const PARAMS_NOT_ARRAY_ERR = `params is not an array! Did something gone wrong when you generate the contract.json?`\nexport const EXCEPTION_CASE_ERR = 'Could not understand your arguments and parameter structure!'\nexport const UNUSUAL_CASE_ERR = 'This is an unusual situation where the arguments are more than the params, but not mark as spread'\n\n// re-export\nimport * as JSONQL_CONSTANTS from 'jsonql-constants'\n// @TODO the jsdoc return array. and we should also allow array syntax\nexport const DEFAULT_TYPE = JSONQL_CONSTANTS.DEFAULT_TYPE\nexport const ARRAY_TYPE_LFT = JSONQL_CONSTANTS.ARRAY_TYPE_LFT\nexport const ARRAY_TYPE_RGT = JSONQL_CONSTANTS.ARRAY_TYPE_RGT\n\nexport const TYPE_KEY = JSONQL_CONSTANTS.TYPE_KEY\nexport const OPTIONAL_KEY = JSONQL_CONSTANTS.OPTIONAL_KEY\nexport const ENUM_KEY = JSONQL_CONSTANTS.ENUM_KEY\nexport const ARGS_KEY = JSONQL_CONSTANTS.ARGS_KEY\nexport const CHECKER_KEY = JSONQL_CONSTANTS.CHECKER_KEY\nexport const ALIAS_KEY = JSONQL_CONSTANTS.ALIAS_KEY\n\nexport const ARRAY_TYPE = JSONQL_CONSTANTS.ARRAY_TYPE\nexport const OBJECT_TYPE = JSONQL_CONSTANTS.OBJECT_TYPE\nexport const STRING_TYPE = JSONQL_CONSTANTS.STRING_TYPE\nexport const BOOLEAN_TYPE = JSONQL_CONSTANTS.BOOLEAN_TYPE\nexport const NUMBER_TYPE = JSONQL_CONSTANTS.NUMBER_TYPE\nexport const KEY_WORD = JSONQL_CONSTANTS.KEY_WORD\nexport const OR_SEPERATOR = JSONQL_CONSTANTS.OR_SEPERATOR\n\n// not actually in use\n// export const NUMBER_TYPES = JSONQL_CONSTANTS.NUMBER_TYPES;\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","/**\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 * 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 * 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 * 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","/**\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","/** 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","/** 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 * 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","/** 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 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","/**\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","/** 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","/** 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 * 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 * 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 * 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","// validate object type\n\nimport isPlainObject from 'lodash-es/isPlainObject'\nimport filter from 'lodash-es/filter'\n\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","// 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","// 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 // checkIsObject,\n combineFn,\n notEmpty\n} from './index'\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 // UNUSUAL_CASE_ERR\n} from './constants'\nimport { DATA_KEY, ERROR_KEY } from 'jsonql-constants'\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","/**\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","/**\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 * 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 * 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","/** 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","// 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","// 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'\n// PIA syntax\nexport const isObject = checkIsObject\nexport const isAny = checkIsAny\nexport const isString = checkIsString\nexport const isBoolean = checkIsBoolean\nexport const isNumber = checkIsNumber\nexport const isArray = checkIsArray\nexport const isNotEmpty = notEmpty\n\nimport * as validator from './src/validator'\n\nexport const normalizeArgs = validator.normalizeArgs\nexport const validateSync = validator.validateSync\nexport const validateAsync = validator.validateAsync\n\n// configuration checking\n\nimport * as jsonqlOptions from './src/options'\n\nexport const JSONQL_PARAMS_VALIDATOR_INFO = jsonqlOptions.JSONQL_PARAMS_VALIDATOR_INFO\n\nexport const createConfig = jsonqlOptions.createConfig\nexport const constructConfig = jsonqlOptions.constructConfigFn\n// construct the final output 1.5.2\nexport const checkConfigAsync = jsonqlOptions.getCheckConfigAsync(validator.validateSync)\nexport const checkConfig = jsonqlOptions.getCheckConfig(validator.validateSync)\n\n// export the two extra functions\nimport isInArray from './src/is-in-array'\nimport isObjectHasKeyFn from './src/is-key-in-object'\n\nexport const inArray = isInArray\nexport const isObjectHasKey = isObjectHasKeyFn\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","// 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","/**\n * This is a custom error to throw when server throw a 500\n * This help us to capture the right error, due to the call happens in sequence\n * @param {string} message to tell what happen\n * @param {mixed} extra things we want to add, 500?\n */\nexport default class Jsonql500Error extends Error {\n constructor(...args) {\n super(...args)\n\n this.message = args[0]\n this.detail = args[1]\n\n this.className = Jsonql500Error.name;\n\n if (Error.captureStackTrace) {\n Error.captureStackTrace(this, Jsonql500Error)\n }\n }\n\n static get statusCode() {\n return 500;\n }\n\n static get name() {\n return 'Jsonql500Error';\n }\n\n}\n","/**\n * This is a custom error to throw when could not find the resolver\n * This help us to capture the right error, due to the call happens in sequence\n * @param {string} message to tell what happen\n * @param {mixed} extra things we want to add, 500?\n */\nexport default class JsonqlResolverNotFoundError extends Error {\n constructor(...args) {\n super(...args)\n\n this.message = args[0]\n this.detail = args[1]\n\n this.className = JsonqlResolverNotFoundError.name;\n\n if (Error.captureStackTrace) {\n Error.captureStackTrace(this, JsonqlResolverNotFoundError);\n }\n }\n\n static get statusCode() {\n return 404;\n }\n\n static get name() {\n return 'JsonqlResolverNotFoundError';\n }\n}\n","// this is from an example from Koa team to use for internal middleware ctx.throw\n// but after the test the res.body part is unable to extract the required data\n// I keep this one here for future reference\n\nexport default class JsonqlServerError extends Error {\n\n constructor(statusCode, message) {\n super(message)\n this.statusCode = statusCode;\n this.className = JsonqlServerError.name;\n }\n\n static get name() {\n return 'JsonqlServerError';\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","// 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.publicNamespace ].join('/'),\n [ base , config.privateNamespace ].join('/')\n ]\n }\n return [ base ]\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","// 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(client, resolverName, setupResolver(namespace, resolverName, params, fn, ee, log))\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 createNamespaceErrorHandler(client, opts, ee, nspGroup) {\n return [\n // using the onError as name\n // @TODO we should follow the convention earlier\n // make this a setter for the clientitself\n objDefineProps(client, ON_ERROR_FN_NAME, 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 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 createOnReadyHandler(client, opts, ee) {\n return [\n objDefineProps(client, ON_READY_FN_NAME, 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 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} ","// 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 createNamespaceErrorHandler,\n createOnReadyHandler\n} from './resolver-methods'\nimport {\n setupFinalStep \n} from './setup-final-step'\nimport {\n NSP_GROUP\n} from 'jsonql-constants'\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 generator(opts, nspMap, ee) {\n\n let args = [\n generateResolvers,\n createNamespaceErrorHandler,\n createOnReadyHandler\n ]\n if (opts.enableAuth) {\n args.push(\n createAuthMethods\n )\n } \n // we will always get back the [ obj, opts, ee ]\n // then we only return the obj (wsClient)\n args.push(setupFinalStep)\n // run it\n const fn = Reflect.apply(chainFns, null, args)\n\n return fn(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 { generator } from './core'\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} frameworkSocketEngine \n * @param {object} config the already checked config \n */\nexport function wsClientCoreAction(frameworkSocketEngine, config) {\n return postCheckInjectOpts(config)\n // the following two moved to wsPostConfig\n .then(createRequiredParams)\n .then(\n ({opts, nspMap, ee}) => frameworkSocketEngine(opts, nspMap, ee)\n )\n .then(\n ({opts, nspMap, ee}) => generator(opts, nspMap, ee)\n )\n .catch(err => {\n console.error(`jsonql-ws-core-client init error`, err)\n })\n}\n\n/**\n * The main interface which will generate the socket clients and map all events\n * @param {object} frameworkSocketEngine 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(frameworkSocketEngine, configCheckMap = {}, constProps = {}) {\n // we need to inject property to this client later\n return (config = {}) => checkConfiguration(config, configCheckMap, constProps)\n .then(opts => wsClientCoreAction(frameworkSocketEngine, opts))\n}\n","// since both the ws and io version are\n// pre-defined in the client-generator\n// and this one will have the same parameters\n// and the callback is identical\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 } = opts\n const url = namespace ? [hostname, namespace].join('/') : wssPath\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 } = opts\n const url = namespace ? [hostname, namespace].join('/') : wssPath\n if (token && typeof token !== 'string') {\n throw new Error(`Expect token to be string, but got ${token}`)\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}","// 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\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, SOCKET_IO, DISCONNECTED_ERROR_MSG } from '../options/constants'\nimport { createEvt, clearMainEmitEvt } from '../utils'\nimport { triggerNamespacesOnError } from './trigger-namespaces-on-error'\n\n/**\n * A Event handler 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 */\nconst notLoginWsHandler = (namespace, ee, opts) => {\n const { log } = opts \n ee.$only(\n createEvt(namespace, EMIT_EVT),\n function notLoginHandlerCallback(resolverName, args) {\n log('[notLoginHandler] hijack the ws call', namespace, resolverName, args)\n const error = {\n message: NOT_LOGIN_ERR_MSG\n }\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 handler, but wrap inside the error key\n ee.$call(createEvt(namespace, resolverName, ON_RESULT_FN_NAME), [{ error }])\n }\n )\n}\n\n/**\n * A Event handler 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 */\nconst disconnectedHandler = (namespace, ee, opts) => {\n const { log } = opts \n ee.$only(\n createEvt(namespace, EMIT_EVT),\n function disconnectedHandlerCallback(resolverName, args) {\n log(`[disconnectedHandler] 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 handler, but wrap inside the error key\n ee.$call(createEvt(namespace, resolverName, ON_RESULT_FN_NAME), [{ error }])\n }\n )\n}\n\n/**\n * get the private namespace\n * @param {array} namespaces array\n * @return {*} string on success\n */\nconst getPrivateNamespace = (namespaces) => (\n namespaces.length > 1 ? namespaces[0] : false\n)\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 */\nconst logoutEvtHandler = (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(LOGOUT_EVENT_NAME, function logoutEvtHandlerAction() {\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 handler\n triggerNamespacesOnError(ee, [privateNamespace], LOGOUT_EVENT_NAME)\n // rebind all of the handler 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 notLoginWsHandler(privateNamespace, ee, opts)\n })\n}\n\n/**\n * The disconnect event handler, 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 */\nconst disconnectHandler = (nsps, namespaces, ee, opts) => {\n const { log } = opts \n ee.$on(DISCONNECT_EVENT_NAME, function disconnectEvtHandler() {\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 disconnectedHandler(namespace, ee, opts)\n })\n })\n}\n\n/**\n * centralize all the comm in one place\n * @param {object} opts configuration\n * @param {object} nspMap this is not in the opts \n * @param {object} ee Event Emitter instance\n * @param {function} bindWsHandler binding the ee to ws --> this is the core bit\n * @param {object} nsps namespaced nsp\n * @return {void} nothing\n */\nexport function clientEventHandler(opts, nspMap, ee, bindSocketEventHandler, nsps) {\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 let isPrivate = false\n let hasPrivate = false\n // loop\n // @BUG for io this has to be in order the one with auth need to get call first\n // The order of login is very import we need to run in order here to make sure\n // one is execute then the other\n namespaces.forEach(namespace => {\n isPrivate = privateNamespace === namespace\n if (!hasPrivate) {\n hasPrivate = isPrivate\n }\n log(namespace, ' --> nsps --> ', nsps[namespace])\n if (nsps[namespace]) {\n\n log('[call bindWsHandler]', isPrivate, namespace)\n let args = [namespace, nsps[namespace], ee, isPrivate, opts]\n \n if (opts.serverType === SOCKET_IO) {\n let { nspGroup } = nspMap\n args.push(nspGroup[namespace])\n }\n Reflect.apply(bindSocketEventHandler, null, args)\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 notLoginWsHandler(namespace, ee, opts)\n }\n })\n // logout event handler \n if (hasPrivate) {\n log(`Has private and add logoutEvtHandler`)\n logoutEvtHandler(nsps, namespaces, ee, opts)\n }\n // finally the disconnect event handlers\n disconnectHandler(nsps, namespaces, ee, opts) \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'\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 * @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 */\nfunction initWebSocketClient(WebSocket, auth = false) {\n if (auth === false) {\n return function createWsClient(url) {\n return new WebSocket(fixWss(url))\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 * @return {object} ws instance\n */\n return function createWsAuthClient(url, token) {\n const ws_url = fixWss(url)\n // console.log('what happen here?', url, ws_url, token)\n const uri = token && typeof token === 'string' ? `${ws_url}?${TOKEN_PARAM_NAME}=${token}` : ws_url\n try {\n return new WebSocket(uri)\n } catch(e) {\n console.error('WebSocket Connection Error', e)\n return false\n }\n }\n}\n\nexport { initWebSocketClient }","// @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}","/**\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 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 * 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","// 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","/**\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","// 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' \n\nconst WS_KEYS = [\n WS_REPLY_TYPE,\n WS_EVT_NAME,\n WS_DATA_NAME\n]\nimport isString from 'lodash-es/isString'\nimport { toJson, isFunc, isObjectHasKey, nil } from './generic'\nimport { timestamp } from './timestamp'\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 can not decoded', 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_TYPE,\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 createReplyMsg, \n createEvt, \n extractWsPayload \n} from 'jsonql-utils/module'\nimport {\n handleNamespaceOnError\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 * @return {void}\n */\nconst logoutEventHandler = (ee) => {\n // listen to the LOGOUT_EVENT_NAME when this is a private nsp\n ee.$on(LOGOUT_EVENT_NAME, function closeEvtHandler() {\n try {\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 socketEventHandler(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 = createReplyMsg(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 const json = extractWsPayload(payload)\n const { resolverName, type } = json\n \n log('Hear 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_TYPE:\n // this is handled error and we won't throw it\n // we need to extract the error from json\n log(`ERROR_TYPE`)\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 logoutEventHandler(ee)\n }\n}\n","// actually binding the event client to the socket client\n\n// from the jsonql-ws-client-core\nimport { clientEventHandler } from '../modules'\n// local \nimport { createNspAction } from './create-nsp-action'\nimport { loginEventHandler } from './login-event-handler'\nimport { socketEventHandler } from './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 // arguments for clientEventHandler\n const args = [opts, nspMap, ee, socketEventHandler]\n\n // now create the nsps\n const { namespaces } = nspMap\n const { token } = opts\n const { nsps } = createNspAction(opts, nspMap, token)\n // binding the listeners - and it will listen to LOGOUT event\n // to unbind itself, and the above call will bind it again\n Reflect.apply(clientEventHandler, null, args.concat([namespaces, nsps]))\n // setup listener for the login event\n if (opts.enableAuth) {\n loginEventHandler(ee, namespaces, nspMap, opts)\n }\n // return what input\n return { opts, nspMap, ee }\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\n\nimport { initWebSocketClient } from './init-websocket-client'\nimport createNsp from '../create-nsp'\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 const publicClient = initWebSocketClient(frameworkModule)\n const privateClient = initWebSocketClient(frameworkModule, true)\n\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 opts.nspClient = publicClient\n opts.nspAuthClient = privateClient \n // @1.0.7 remove later once everything fixed \n const { log } = opts\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;;;;;;;;;;;;;;;;;"} \ No newline at end of file +{"version":3,"file":"main.js","sources":["node_modules/_rollup-plugin-node-globals@1.4.0@rollup-plugin-node-globals/src/global.js","../../ws-client-core/node_modules/lodash-es/_arrayMap.js","../../ws-client-core/node_modules/lodash-es/isArray.js","../../ws-client-core/node_modules/lodash-es/_objectToString.js","../../ws-client-core/node_modules/lodash-es/isObjectLike.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-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/lodash-es/_overArg.js","../../ws-client-core/node_modules/lodash-es/_arrayFilter.js","../../ws-client-core/node_modules/lodash-es/_createBaseFor.js","../../ws-client-core/node_modules/lodash-es/_baseTimes.js","../../ws-client-core/node_modules/lodash-es/stubFalse.js","../../ws-client-core/node_modules/lodash-es/_isIndex.js","../../ws-client-core/node_modules/lodash-es/isLength.js","../../ws-client-core/node_modules/lodash-es/_baseUnary.js","../../ws-client-core/node_modules/lodash-es/_isPrototype.js","../../ws-client-core/node_modules/lodash-es/isObject.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/_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/_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/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/identity.js","../../ws-client-core/node_modules/lodash-es/_baseProperty.js","../../ws-client-core/node_modules/jsonql-params-validator/src/object.js","../../ws-client-core/node_modules/jsonql-errors/src/validation-error.js","../../ws-client-core/node_modules/jsonql-params-validator/src/validator.js","../../ws-client-core/node_modules/lodash-es/_copyArray.js","../../ws-client-core/node_modules/lodash-es/_safeGet.js","../../ws-client-core/node_modules/lodash-es/_nativeKeysIn.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/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-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-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/node_modules/jsonql-utils/src/generic.js","../../ws-client-core/node_modules/jsonql-errors/src/500-error.js","../../ws-client-core/node_modules/jsonql-errors/src/resolver-not-found-error.js","../../ws-client-core/node_modules/jsonql-errors/src/server-error.js","../../ws-client-core/node_modules/jsonql-utils/src/contract.js","../../ws-client-core/node_modules/jsonql-utils/src/namespace.js","../../ws-client-core/src/utils/helpers.js","../../ws-client-core/src/core/setup-auth-methods.js","../../ws-client-core/src/options/constants.js","../../ws-client-core/src/core/respond-handler.js","../../ws-client-core/src/core/action-call.js","../../ws-client-core/src/core/setup-send-method.js","../../ws-client-core/src/core/setup-resolver.js","../../ws-client-core/src/core/resolver-methods.js","../../ws-client-core/src/core/setup-intercom.js","../../ws-client-core/src/core/generator.js","../../ws-client-core/src/options/index.js","../../ws-client-core/src/api.js","../../ws-client-core/src/share/create-nsp-clients.js","../../ws-client-core/src/share/trigger-namespaces-on-error.js","../../ws-client-core/src/share/client-event-handler.js","src/options/index.js","src/core/create-websocket-binding/init-websocket-client.js","src/core/create-nsp/login-event-handler.js","node_modules/_lodash-es@4.17.15@lodash-es/isArray.js","node_modules/_lodash-es@4.17.15@lodash-es/_objectToString.js","node_modules/_lodash-es@4.17.15@lodash-es/isObjectLike.js","node_modules/_jsonql-utils@1.1.3@jsonql-utils/src/generic.js","node_modules/_jsonql-utils@1.1.3@jsonql-utils/src/timestamp.js","node_modules/_jsonql-utils@1.1.3@jsonql-utils/src/socket.js","src/core/create-nsp/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":["export default (typeof global !== \"undefined\" ? global :\n typeof self !== \"undefined\" ? self :\n typeof window !== \"undefined\" ? window : {});\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 * 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 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 * 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 * 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","// 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\nexport const 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)`\nexport const PARAMS_NOT_ARRAY_ERR = `params is not an array! Did something gone wrong when you generate the contract.json?`\nexport const EXCEPTION_CASE_ERR = 'Could not understand your arguments and parameter structure!'\nexport const UNUSUAL_CASE_ERR = 'This is an unusual situation where the arguments are more than the params, but not mark as spread'\n\n// re-export\nimport * as JSONQL_CONSTANTS from 'jsonql-constants'\n// @TODO the jsdoc return array. and we should also allow array syntax\nexport const DEFAULT_TYPE = JSONQL_CONSTANTS.DEFAULT_TYPE\nexport const ARRAY_TYPE_LFT = JSONQL_CONSTANTS.ARRAY_TYPE_LFT\nexport const ARRAY_TYPE_RGT = JSONQL_CONSTANTS.ARRAY_TYPE_RGT\n\nexport const TYPE_KEY = JSONQL_CONSTANTS.TYPE_KEY\nexport const OPTIONAL_KEY = JSONQL_CONSTANTS.OPTIONAL_KEY\nexport const ENUM_KEY = JSONQL_CONSTANTS.ENUM_KEY\nexport const ARGS_KEY = JSONQL_CONSTANTS.ARGS_KEY\nexport const CHECKER_KEY = JSONQL_CONSTANTS.CHECKER_KEY\nexport const ALIAS_KEY = JSONQL_CONSTANTS.ALIAS_KEY\n\nexport const ARRAY_TYPE = JSONQL_CONSTANTS.ARRAY_TYPE\nexport const OBJECT_TYPE = JSONQL_CONSTANTS.OBJECT_TYPE\nexport const STRING_TYPE = JSONQL_CONSTANTS.STRING_TYPE\nexport const BOOLEAN_TYPE = JSONQL_CONSTANTS.BOOLEAN_TYPE\nexport const NUMBER_TYPE = JSONQL_CONSTANTS.NUMBER_TYPE\nexport const KEY_WORD = JSONQL_CONSTANTS.KEY_WORD\nexport const OR_SEPERATOR = JSONQL_CONSTANTS.OR_SEPERATOR\n\n// not actually in use\n// export const NUMBER_TYPES = JSONQL_CONSTANTS.NUMBER_TYPES;\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","/**\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 * 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 * 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 * 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","/**\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","/** 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","/** 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 * 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","/** 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 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","/**\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","/** 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","/** 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 * 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 * 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 * 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","// validate object type\n\nimport isPlainObject from 'lodash-es/isPlainObject'\nimport filter from 'lodash-es/filter'\n\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","// 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","// 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 // checkIsObject,\n combineFn,\n notEmpty\n} from './index'\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 // UNUSUAL_CASE_ERR\n} from './constants'\nimport { DATA_KEY, ERROR_KEY } from 'jsonql-constants'\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","/**\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","/**\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 * 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 * 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","/** 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","// 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","// 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'\n// PIA syntax\nexport const isObject = checkIsObject\nexport const isAny = checkIsAny\nexport const isString = checkIsString\nexport const isBoolean = checkIsBoolean\nexport const isNumber = checkIsNumber\nexport const isArray = checkIsArray\nexport const isNotEmpty = notEmpty\n\nimport * as validator from './src/validator'\n\nexport const normalizeArgs = validator.normalizeArgs\nexport const validateSync = validator.validateSync\nexport const validateAsync = validator.validateAsync\n\n// configuration checking\n\nimport * as jsonqlOptions from './src/options'\n\nexport const JSONQL_PARAMS_VALIDATOR_INFO = jsonqlOptions.JSONQL_PARAMS_VALIDATOR_INFO\n\nexport const createConfig = jsonqlOptions.createConfig\nexport const constructConfig = jsonqlOptions.constructConfigFn\n// construct the final output 1.5.2\nexport const checkConfigAsync = jsonqlOptions.getCheckConfigAsync(validator.validateSync)\nexport const checkConfig = jsonqlOptions.getCheckConfig(validator.validateSync)\n\n// export the two extra functions\nimport isInArray from './src/is-in-array'\nimport isObjectHasKeyFn from './src/is-key-in-object'\n\nexport const inArray = isInArray\nexport const isObjectHasKey = isObjectHasKeyFn\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","// 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","/**\n * This is a custom error to throw when server throw a 500\n * This help us to capture the right error, due to the call happens in sequence\n * @param {string} message to tell what happen\n * @param {mixed} extra things we want to add, 500?\n */\nexport default class Jsonql500Error extends Error {\n constructor(...args) {\n super(...args)\n\n this.message = args[0]\n this.detail = args[1]\n\n this.className = Jsonql500Error.name;\n\n if (Error.captureStackTrace) {\n Error.captureStackTrace(this, Jsonql500Error)\n }\n }\n\n static get statusCode() {\n return 500;\n }\n\n static get name() {\n return 'Jsonql500Error';\n }\n\n}\n","/**\n * This is a custom error to throw when could not find the resolver\n * This help us to capture the right error, due to the call happens in sequence\n * @param {string} message to tell what happen\n * @param {mixed} extra things we want to add, 500?\n */\nexport default class JsonqlResolverNotFoundError extends Error {\n constructor(...args) {\n super(...args)\n\n this.message = args[0]\n this.detail = args[1]\n\n this.className = JsonqlResolverNotFoundError.name;\n\n if (Error.captureStackTrace) {\n Error.captureStackTrace(this, JsonqlResolverNotFoundError);\n }\n }\n\n static get statusCode() {\n return 404;\n }\n\n static get name() {\n return 'JsonqlResolverNotFoundError';\n }\n}\n","// this is from an example from Koa team to use for internal middleware ctx.throw\n// but after the test the res.body part is unable to extract the required data\n// I keep this one here for future reference\n\nexport default class JsonqlServerError extends Error {\n\n constructor(statusCode, message) {\n super(message)\n this.statusCode = statusCode;\n this.className = JsonqlServerError.name;\n }\n\n static get name() {\n return 'JsonqlServerError';\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","// 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.publicNamespace ].join('/'),\n [ base , config.privateNamespace ].join('/')\n ]\n }\n return [ base ]\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","// 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(client, resolverName, setupResolver(namespace, resolverName, params, fn, ee, log))\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 createNamespaceErrorHandler(client, opts, ee, nspGroup) {\n return [\n // using the onError as name\n // @TODO we should follow the convention earlier\n // make this a setter for the clientitself\n objDefineProps(client, ON_ERROR_FN_NAME, 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 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 createOnReadyHandler(client, opts, ee) {\n return [\n objDefineProps(client, ON_READY_FN_NAME, 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 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} ","// 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 createNamespaceErrorHandler,\n createOnReadyHandler\n} from './resolver-methods'\nimport {\n setupFinalStep \n} from './setup-final-step'\nimport {\n NSP_GROUP\n} from 'jsonql-constants'\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 generator(opts, nspMap, ee) {\n\n let args = [\n generateResolvers,\n createNamespaceErrorHandler,\n createOnReadyHandler\n ]\n if (opts.enableAuth) {\n args.push(\n createAuthMethods\n )\n } \n // we will always get back the [ obj, opts, ee ]\n // then we only return the obj (wsClient)\n args.push(setupFinalStep)\n // run it\n const fn = Reflect.apply(chainFns, null, args)\n\n return fn(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 { generator } from './core'\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} frameworkSocketEngine \n * @param {object} config the already checked config \n */\nexport function wsClientCoreAction(frameworkSocketEngine, config) {\n return postCheckInjectOpts(config)\n // the following two moved to wsPostConfig\n .then(createRequiredParams)\n .then(\n ({opts, nspMap, ee}) => frameworkSocketEngine(opts, nspMap, ee)\n )\n .then(\n ({opts, nspMap, ee}) => generator(opts, nspMap, ee)\n )\n .catch(err => {\n console.error(`jsonql-ws-core-client init error`, err)\n })\n}\n\n/**\n * The main interface which will generate the socket clients and map all events\n * @param {object} frameworkSocketEngine 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(frameworkSocketEngine, configCheckMap = {}, constProps = {}) {\n // we need to inject property to this client later\n return (config = {}) => checkConfiguration(config, configCheckMap, constProps)\n .then(opts => wsClientCoreAction(frameworkSocketEngine, opts))\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 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}","// 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\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, SOCKET_IO, DISCONNECTED_ERROR_MSG } from '../options/constants'\nimport { createEvt, clearMainEmitEvt } from '../utils'\nimport { triggerNamespacesOnError } from './trigger-namespaces-on-error'\n\n/**\n * A Event handler 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 */\nconst notLoginWsHandler = (namespace, ee, opts) => {\n const { log } = opts \n ee.$only(\n createEvt(namespace, EMIT_EVT),\n function notLoginHandlerCallback(resolverName, args) {\n log('[notLoginHandler] hijack the ws call', namespace, resolverName, args)\n const error = {\n message: NOT_LOGIN_ERR_MSG\n }\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 handler, but wrap inside the error key\n ee.$call(createEvt(namespace, resolverName, ON_RESULT_FN_NAME), [{ error }])\n }\n )\n}\n\n/**\n * A Event handler 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 */\nconst disconnectedHandler = (namespace, ee, opts) => {\n const { log } = opts \n ee.$only(\n createEvt(namespace, EMIT_EVT),\n function disconnectedHandlerCallback(resolverName, args) {\n log(`[disconnectedHandler] 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 handler, but wrap inside the error key\n ee.$call(createEvt(namespace, resolverName, ON_RESULT_FN_NAME), [{ error }])\n }\n )\n}\n\n/**\n * get the private namespace\n * @param {array} namespaces array\n * @return {*} string on success\n */\nconst getPrivateNamespace = (namespaces) => (\n namespaces.length > 1 ? namespaces[0] : false\n)\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 */\nconst logoutEvtHandler = (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(LOGOUT_EVENT_NAME, function logoutEvtHandlerAction() {\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 handler\n triggerNamespacesOnError(ee, [privateNamespace], LOGOUT_EVENT_NAME)\n // rebind all of the handler 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 notLoginWsHandler(privateNamespace, ee, opts)\n })\n}\n\n/**\n * The disconnect event handler, 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 */\nconst disconnectHandler = (nsps, namespaces, ee, opts) => {\n const { log } = opts \n ee.$on(DISCONNECT_EVENT_NAME, function disconnectEvtHandler() {\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 disconnectedHandler(namespace, ee, opts)\n })\n })\n}\n\n/**\n * centralize all the comm in one place\n * @param {object} opts configuration\n * @param {object} nspMap this is not in the opts \n * @param {object} ee Event Emitter instance\n * @param {function} bindWsHandler binding the ee to ws --> this is the core bit\n * @param {object} nsps namespaced nsp\n * @return {void} nothing\n */\nexport function clientEventHandler(opts, nspMap, ee, bindSocketEventHandler, nsps) {\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 let isPrivate = false\n let hasPrivate = false\n // loop\n // @BUG for io this has to be in order the one with auth need to get call first\n // The order of login is very import we need to run in order here to make sure\n // one is execute then the other\n namespaces.forEach(namespace => {\n isPrivate = privateNamespace === namespace\n if (!hasPrivate) {\n hasPrivate = isPrivate\n }\n log(namespace, ' --> nsps --> ', nsps[namespace])\n if (nsps[namespace]) {\n\n log('[call bindWsHandler]', isPrivate, namespace)\n let args = [namespace, nsps[namespace], ee, isPrivate, opts]\n \n if (opts.serverType === SOCKET_IO) {\n let { nspGroup } = nspMap\n args.push(nspGroup[namespace])\n }\n Reflect.apply(bindSocketEventHandler, null, args)\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 notLoginWsHandler(namespace, ee, opts)\n }\n })\n // logout event handler \n if (hasPrivate) {\n log(`Has private and add logoutEvtHandler`)\n logoutEvtHandler(nsps, namespaces, ee, opts)\n }\n // finally the disconnect event handlers\n disconnectHandler(nsps, namespaces, ee, opts) \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'\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 * @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 */\nfunction initWebSocketClient(WebSocket, auth = false) {\n if (auth === false) {\n return function createWsClient(url) {\n return new WebSocket(fixWss(url))\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 * @return {object} ws instance\n */\n return function createWsAuthClient(url, token) {\n const ws_url = fixWss(url)\n // console.log('what happen here?', url, ws_url, token)\n const uri = token && typeof token === 'string' ? `${ws_url}?${TOKEN_PARAM_NAME}=${token}` : ws_url\n try {\n return new WebSocket(uri)\n } catch(e) {\n console.error('WebSocket Connection Error', e)\n return false\n }\n }\n}\n\nexport { initWebSocketClient }","// @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}","/**\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 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 * 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","// 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","/**\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","// 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' \n\nconst WS_KEYS = [\n WS_REPLY_TYPE,\n WS_EVT_NAME,\n WS_DATA_NAME\n]\nimport isString from 'lodash-es/isString'\nimport { toJson, isFunc, isObjectHasKey, nil } from './generic'\nimport { timestamp } from './timestamp'\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 can not decoded', 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_TYPE,\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 createReplyMsg, \n createEvt, \n extractWsPayload \n} from 'jsonql-utils/module'\nimport {\n handleNamespaceOnError\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 * @return {void}\n */\nconst logoutEventHandler = (ee) => {\n // listen to the LOGOUT_EVENT_NAME when this is a private nsp\n ee.$on(LOGOUT_EVENT_NAME, function closeEvtHandler() {\n try {\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 socketEventHandler(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 = createReplyMsg(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 const json = extractWsPayload(payload)\n const { resolverName, type } = json\n \n log('Hear 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_TYPE:\n // this is handled error and we won't throw it\n // we need to extract the error from json\n log(`ERROR_TYPE`)\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 logoutEventHandler(ee)\n }\n}\n","// actually binding the event client to the socket client\n\n// from the jsonql-ws-client-core\nimport { clientEventHandler } from '../modules'\n// local \nimport { createNspAction } from './create-nsp-action'\nimport { loginEventHandler } from './login-event-handler'\nimport { socketEventHandler } from './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 // arguments for clientEventHandler\n const args = [opts, nspMap, ee, socketEventHandler]\n\n // now create the nsps\n const { namespaces } = nspMap\n const { token, log } = opts\n const { nsps } = createNspAction(opts, nspMap, token)\n args.push(nsps)\n // log(`argument length`, args.length, args)\n\n // binding the listeners - and it will listen to LOGOUT event\n // to unbind itself, and the above call will bind it again\n Reflect.apply(clientEventHandler, null, args)\n // setup listener for the login event\n if (opts.enableAuth) {\n loginEventHandler(ee, namespaces, nspMap, opts)\n }\n // return what input\n return { opts, nspMap, ee }\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\n\nimport { initWebSocketClient } from './init-websocket-client'\nimport createNsp from '../create-nsp'\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 const nspClient = initWebSocketClient(frameworkModule)\n const nspAuthClient = initWebSocketClient(frameworkModule, true)\n\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 opts.nspClient = nspClient\n opts.nspAuthClient = nspAuthClient \n // @1.0.7 remove later once everything fixed \n const { log } = opts\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;;;;;;;;;;;;;;;;;"} \ No newline at end of file diff --git a/packages/@jsonql/ws/src/core/create-nsp/create-nsp-action.js b/packages/@jsonql/ws/src/core/create-nsp/create-nsp-action.js index 6b968dc0..ca9727e5 100644 --- a/packages/@jsonql/ws/src/core/create-nsp/create-nsp-action.js +++ b/packages/@jsonql/ws/src/core/create-nsp/create-nsp-action.js @@ -39,7 +39,6 @@ const createNspAction = function(opts, nspMap, token) { } }).reduce((first, next) => Object.assign(first, next), {}) } - // standard without login return { [publicNamespace]: createNspClient(false, opts) 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 626256b4..636c7dc8 100644 --- a/packages/@jsonql/ws/src/core/create-nsp/create-nsp.js +++ b/packages/@jsonql/ws/src/core/create-nsp/create-nsp.js @@ -20,11 +20,14 @@ function createNsp(opts, nspMap, ee) { // now create the nsps const { namespaces } = nspMap - const { token } = opts + const { token, log } = opts const { nsps } = createNspAction(opts, nspMap, token) + args.push(nsps) + // log(`argument length`, args.length, args) + // binding the listeners - and it will listen to LOGOUT event // to unbind itself, and the above call will bind it again - Reflect.apply(clientEventHandler, null, args.concat([namespaces, nsps])) + Reflect.apply(clientEventHandler, null, args) // setup listener for the login event if (opts.enableAuth) { loginEventHandler(ee, namespaces, nspMap, opts) diff --git a/packages/ws-client-core/src/share/client-event-handler.js b/packages/ws-client-core/src/share/client-event-handler.js index 8191ca1e..e284d821 100644 --- a/packages/ws-client-core/src/share/client-event-handler.js +++ b/packages/ws-client-core/src/share/client-event-handler.js @@ -152,7 +152,7 @@ export function clientEventHandler(opts, nspMap, ee, bindSocketEventHandler, nsp if (!hasPrivate) { hasPrivate = isPrivate } - log(namespace, ' --> nsps --> ', nsps[namespace]) + // log(namespace, ' --> nsps --> ', nsps[namespace]) if (nsps[namespace]) { log('[call bindWsHandler]', isPrivate, namespace) -- Gitee From af35a69b79b134d9a4e7082ca2a10e092aed599e Mon Sep 17 00:00:00 2001 From: joelchu Date: Sat, 14 Mar 2020 00:53:44 +0800 Subject: [PATCH 38/45] resolve the simple test --- packages/@jsonql/ws/main.js | 129 +++++++++++++----- packages/@jsonql/ws/main.js.map | 2 +- .../core/create-nsp/socket-event-handler.js | 9 +- 3 files changed, 105 insertions(+), 35 deletions(-) diff --git a/packages/@jsonql/ws/main.js b/packages/@jsonql/ws/main.js index 69f565df..e04e354e 100644 --- a/packages/@jsonql/ws/main.js +++ b/packages/@jsonql/ws/main.js @@ -7771,7 +7771,7 @@ function clientEventHandler$1(opts, nspMap, ee, bindSocketEventHandler, nsps) { if (!hasPrivate) { hasPrivate = isPrivate; } - log(namespace, ' --> nsps --> ', nsps[namespace]); + // log(namespace, ' --> nsps --> ', nsps[namespace]) if (nsps[namespace]) { log('[call bindWsHandler]', isPrivate, namespace); @@ -7800,6 +7800,7 @@ function clientEventHandler$1(opts, nspMap, ee, bindSocketEventHandler, nsps) { } var ERROR_KEY$1 = 'error'; +var QUERY_ARG_NAME = 'args'; var TIMESTAMP_PARAM_NAME = 'TS'; var NO_STATUS_CODE$1 = -1; var LOGIN_EVENT_NAME$1 = '__login__'; @@ -8158,6 +8159,40 @@ var toJson = function (n) { // generic placeholder function var nil$1 = function () { return false; }; +// custom validation error class +// when validaton failed +var JsonqlValidationError$1 = /*@__PURE__*/(function (Error) { + function JsonqlValidationError() { + var args = [], len = arguments.length; + while ( len-- ) args[ len ] = arguments[ len ]; + + Error.apply(this, args); + + this.message = args[0]; + this.detail = args[1]; + + this.className = JsonqlValidationError.name; + + if (Error.captureStackTrace) { + Error.captureStackTrace(this, JsonqlValidationError); + } + } + + if ( Error ) JsonqlValidationError.__proto__ = Error; + JsonqlValidationError.prototype = Object.create( Error && Error.prototype ); + JsonqlValidationError.prototype.constructor = JsonqlValidationError; + + var staticAccessors = { name: { configurable: true } }; + + staticAccessors.name.get = function () { + return 'JsonqlValidationError'; + }; + + Object.defineProperties( JsonqlValidationError, staticAccessors ); + + return JsonqlValidationError; +}(Error)); + /** * This is a custom error to throw whenever a error happen inside the jsonql * This help us to capture the right error, due to the call happens in sequence @@ -8237,42 +8272,71 @@ function isString$3(value) { (!isArray$1(value) && isObjectLike$1(value) && baseGetTag$1(value) == stringTag$3); } -// There are the socket related methods ported back from - -var WS_KEYS = [ - WS_REPLY_TYPE, - WS_EVT_NAME, - WS_DATA_NAME -]; +// ported from jsonql-params-validator /** - * The ws doesn't have a acknowledge callback like socket.io - * so we have to DIY one for ws and other that doesn't have it - * @param {string} type of reply - * @param {string} resolverName which is replying - * @param {*} data payload - * @param {array} [ts= []] the last received ts, if any - * @return {string} stringify json + * @param {*} args arguments to send + *@return {object} formatted payload */ -var createWsReply = function (type, resolverName, data, ts) { - var obj, obj$1; - - if ( ts === void 0 ) ts = []; - ts.push(timestamp()); - return JSON.stringify(( obj$1 = { - data: ( obj = {}, obj[WS_REPLY_TYPE] = type, obj[WS_EVT_NAME] = resolverName, obj[WS_DATA_NAME] = toJson(data), obj ) - }, obj$1[TIMESTAMP_PARAM_NAME] = ts, obj$1 )) -}; - -// extended function -var createReplyMsg = function (resolverName, data, ts) { - if ( ts === void 0 ) ts = []; +var formatPayload = function (args) { + var obj; return ( - createWsReply(EMIT_REPLY_TYPE$1, resolverName, data, ts) + ( obj = {}, obj[QUERY_ARG_NAME] = args, obj ) ); }; +/** + * wrapper method to add the timestamp as well + * @param {string} resolverName + * @param {*} payload + * @return {object} delierable + */ +function createDeliverable(resolverName, payload) { + var obj; + + return ( obj = {}, obj[resolverName] = payload, obj[TIMESTAMP_PARAM_NAME] = [ timestamp() ], obj ) +} + +/** + * @param {string} resolverName name of function + * @param {array} [args=[]] from the ...args + * @param {boolean} [jsonp = false] add v1.3.0 to koa + * @return {object} formatted argument + */ +function createQuery(resolverName, args, jsonp) { + if ( args === void 0 ) args = []; + if ( jsonp === void 0 ) jsonp = false; + + if (isString$3(resolverName) && isArray$1(args)) { + var payload = formatPayload(args); + if (jsonp === true) { + return payload; + } + return createDeliverable(resolverName, payload) + } + throw new JsonqlValidationError$1("[createQuery] expect resolverName to be string and args to be array!", { resolverName: resolverName, args: args }) +} + +/** + * string version of the createQuery + * @return {string} + */ +function createQueryStr(resolverName, args, jsonp) { + if ( args === void 0 ) args = []; + if ( jsonp === void 0 ) jsonp = false; + + return JSON.stringify(createQuery(resolverName, args, jsonp)) +} + +// There are the socket related methods ported back from + +var WS_KEYS = [ + WS_REPLY_TYPE, + WS_EVT_NAME, + WS_DATA_NAME +]; + /** * @param {string|object} payload should be string when reply but could be transformed * @return {boolean} true is OK @@ -8389,7 +8453,7 @@ function socketEventHandler(namespace, ws, ee, isPrivate, opts) { */ function wsMainOnEvtHandler(resolverName, args) { - var payload = createReplyMsg(resolverName, args); + var payload = createQueryStr(resolverName, args); log('ws.onopen.send', resolverName, args, payload); ws.send(payload); @@ -8403,7 +8467,10 @@ function socketEventHandler(namespace, ws, ee, isPrivate, opts) { ws.onmessage = function onMessageCallback(payload) { // console.log(`on.message`, typeof payload, payload) try { - var json = extractWsPayload(payload); + log("ws.onmessage raw payload", payload); + // the payload actually contain quite a few things - is that changed? + // type: message, data: data_send_from_server + var json = extractWsPayload(payload.data); var resolverName = json.resolverName; var type = json.type; diff --git a/packages/@jsonql/ws/main.js.map b/packages/@jsonql/ws/main.js.map index cf64ff4c..7f4db12b 100644 --- a/packages/@jsonql/ws/main.js.map +++ b/packages/@jsonql/ws/main.js.map @@ -1 +1 @@ -{"version":3,"file":"main.js","sources":["node_modules/_rollup-plugin-node-globals@1.4.0@rollup-plugin-node-globals/src/global.js","../../ws-client-core/node_modules/lodash-es/_arrayMap.js","../../ws-client-core/node_modules/lodash-es/isArray.js","../../ws-client-core/node_modules/lodash-es/_objectToString.js","../../ws-client-core/node_modules/lodash-es/isObjectLike.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-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/lodash-es/_overArg.js","../../ws-client-core/node_modules/lodash-es/_arrayFilter.js","../../ws-client-core/node_modules/lodash-es/_createBaseFor.js","../../ws-client-core/node_modules/lodash-es/_baseTimes.js","../../ws-client-core/node_modules/lodash-es/stubFalse.js","../../ws-client-core/node_modules/lodash-es/_isIndex.js","../../ws-client-core/node_modules/lodash-es/isLength.js","../../ws-client-core/node_modules/lodash-es/_baseUnary.js","../../ws-client-core/node_modules/lodash-es/_isPrototype.js","../../ws-client-core/node_modules/lodash-es/isObject.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/_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/_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/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/identity.js","../../ws-client-core/node_modules/lodash-es/_baseProperty.js","../../ws-client-core/node_modules/jsonql-params-validator/src/object.js","../../ws-client-core/node_modules/jsonql-errors/src/validation-error.js","../../ws-client-core/node_modules/jsonql-params-validator/src/validator.js","../../ws-client-core/node_modules/lodash-es/_copyArray.js","../../ws-client-core/node_modules/lodash-es/_safeGet.js","../../ws-client-core/node_modules/lodash-es/_nativeKeysIn.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/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-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-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/node_modules/jsonql-utils/src/generic.js","../../ws-client-core/node_modules/jsonql-errors/src/500-error.js","../../ws-client-core/node_modules/jsonql-errors/src/resolver-not-found-error.js","../../ws-client-core/node_modules/jsonql-errors/src/server-error.js","../../ws-client-core/node_modules/jsonql-utils/src/contract.js","../../ws-client-core/node_modules/jsonql-utils/src/namespace.js","../../ws-client-core/src/utils/helpers.js","../../ws-client-core/src/core/setup-auth-methods.js","../../ws-client-core/src/options/constants.js","../../ws-client-core/src/core/respond-handler.js","../../ws-client-core/src/core/action-call.js","../../ws-client-core/src/core/setup-send-method.js","../../ws-client-core/src/core/setup-resolver.js","../../ws-client-core/src/core/resolver-methods.js","../../ws-client-core/src/core/setup-intercom.js","../../ws-client-core/src/core/generator.js","../../ws-client-core/src/options/index.js","../../ws-client-core/src/api.js","../../ws-client-core/src/share/create-nsp-clients.js","../../ws-client-core/src/share/trigger-namespaces-on-error.js","../../ws-client-core/src/share/client-event-handler.js","src/options/index.js","src/core/create-websocket-binding/init-websocket-client.js","src/core/create-nsp/login-event-handler.js","node_modules/_lodash-es@4.17.15@lodash-es/isArray.js","node_modules/_lodash-es@4.17.15@lodash-es/_objectToString.js","node_modules/_lodash-es@4.17.15@lodash-es/isObjectLike.js","node_modules/_jsonql-utils@1.1.3@jsonql-utils/src/generic.js","node_modules/_jsonql-utils@1.1.3@jsonql-utils/src/timestamp.js","node_modules/_jsonql-utils@1.1.3@jsonql-utils/src/socket.js","src/core/create-nsp/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":["export default (typeof global !== \"undefined\" ? global :\n typeof self !== \"undefined\" ? self :\n typeof window !== \"undefined\" ? window : {});\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 * 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 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 * 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 * 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","// 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\nexport const 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)`\nexport const PARAMS_NOT_ARRAY_ERR = `params is not an array! Did something gone wrong when you generate the contract.json?`\nexport const EXCEPTION_CASE_ERR = 'Could not understand your arguments and parameter structure!'\nexport const UNUSUAL_CASE_ERR = 'This is an unusual situation where the arguments are more than the params, but not mark as spread'\n\n// re-export\nimport * as JSONQL_CONSTANTS from 'jsonql-constants'\n// @TODO the jsdoc return array. and we should also allow array syntax\nexport const DEFAULT_TYPE = JSONQL_CONSTANTS.DEFAULT_TYPE\nexport const ARRAY_TYPE_LFT = JSONQL_CONSTANTS.ARRAY_TYPE_LFT\nexport const ARRAY_TYPE_RGT = JSONQL_CONSTANTS.ARRAY_TYPE_RGT\n\nexport const TYPE_KEY = JSONQL_CONSTANTS.TYPE_KEY\nexport const OPTIONAL_KEY = JSONQL_CONSTANTS.OPTIONAL_KEY\nexport const ENUM_KEY = JSONQL_CONSTANTS.ENUM_KEY\nexport const ARGS_KEY = JSONQL_CONSTANTS.ARGS_KEY\nexport const CHECKER_KEY = JSONQL_CONSTANTS.CHECKER_KEY\nexport const ALIAS_KEY = JSONQL_CONSTANTS.ALIAS_KEY\n\nexport const ARRAY_TYPE = JSONQL_CONSTANTS.ARRAY_TYPE\nexport const OBJECT_TYPE = JSONQL_CONSTANTS.OBJECT_TYPE\nexport const STRING_TYPE = JSONQL_CONSTANTS.STRING_TYPE\nexport const BOOLEAN_TYPE = JSONQL_CONSTANTS.BOOLEAN_TYPE\nexport const NUMBER_TYPE = JSONQL_CONSTANTS.NUMBER_TYPE\nexport const KEY_WORD = JSONQL_CONSTANTS.KEY_WORD\nexport const OR_SEPERATOR = JSONQL_CONSTANTS.OR_SEPERATOR\n\n// not actually in use\n// export const NUMBER_TYPES = JSONQL_CONSTANTS.NUMBER_TYPES;\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","/**\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 * 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 * 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 * 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","/**\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","/** 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","/** 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 * 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","/** 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 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","/**\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","/** 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","/** 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 * 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 * 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 * 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","// validate object type\n\nimport isPlainObject from 'lodash-es/isPlainObject'\nimport filter from 'lodash-es/filter'\n\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","// 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","// 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 // checkIsObject,\n combineFn,\n notEmpty\n} from './index'\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 // UNUSUAL_CASE_ERR\n} from './constants'\nimport { DATA_KEY, ERROR_KEY } from 'jsonql-constants'\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","/**\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","/**\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 * 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 * 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","/** 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","// 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","// 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'\n// PIA syntax\nexport const isObject = checkIsObject\nexport const isAny = checkIsAny\nexport const isString = checkIsString\nexport const isBoolean = checkIsBoolean\nexport const isNumber = checkIsNumber\nexport const isArray = checkIsArray\nexport const isNotEmpty = notEmpty\n\nimport * as validator from './src/validator'\n\nexport const normalizeArgs = validator.normalizeArgs\nexport const validateSync = validator.validateSync\nexport const validateAsync = validator.validateAsync\n\n// configuration checking\n\nimport * as jsonqlOptions from './src/options'\n\nexport const JSONQL_PARAMS_VALIDATOR_INFO = jsonqlOptions.JSONQL_PARAMS_VALIDATOR_INFO\n\nexport const createConfig = jsonqlOptions.createConfig\nexport const constructConfig = jsonqlOptions.constructConfigFn\n// construct the final output 1.5.2\nexport const checkConfigAsync = jsonqlOptions.getCheckConfigAsync(validator.validateSync)\nexport const checkConfig = jsonqlOptions.getCheckConfig(validator.validateSync)\n\n// export the two extra functions\nimport isInArray from './src/is-in-array'\nimport isObjectHasKeyFn from './src/is-key-in-object'\n\nexport const inArray = isInArray\nexport const isObjectHasKey = isObjectHasKeyFn\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","// 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","/**\n * This is a custom error to throw when server throw a 500\n * This help us to capture the right error, due to the call happens in sequence\n * @param {string} message to tell what happen\n * @param {mixed} extra things we want to add, 500?\n */\nexport default class Jsonql500Error extends Error {\n constructor(...args) {\n super(...args)\n\n this.message = args[0]\n this.detail = args[1]\n\n this.className = Jsonql500Error.name;\n\n if (Error.captureStackTrace) {\n Error.captureStackTrace(this, Jsonql500Error)\n }\n }\n\n static get statusCode() {\n return 500;\n }\n\n static get name() {\n return 'Jsonql500Error';\n }\n\n}\n","/**\n * This is a custom error to throw when could not find the resolver\n * This help us to capture the right error, due to the call happens in sequence\n * @param {string} message to tell what happen\n * @param {mixed} extra things we want to add, 500?\n */\nexport default class JsonqlResolverNotFoundError extends Error {\n constructor(...args) {\n super(...args)\n\n this.message = args[0]\n this.detail = args[1]\n\n this.className = JsonqlResolverNotFoundError.name;\n\n if (Error.captureStackTrace) {\n Error.captureStackTrace(this, JsonqlResolverNotFoundError);\n }\n }\n\n static get statusCode() {\n return 404;\n }\n\n static get name() {\n return 'JsonqlResolverNotFoundError';\n }\n}\n","// this is from an example from Koa team to use for internal middleware ctx.throw\n// but after the test the res.body part is unable to extract the required data\n// I keep this one here for future reference\n\nexport default class JsonqlServerError extends Error {\n\n constructor(statusCode, message) {\n super(message)\n this.statusCode = statusCode;\n this.className = JsonqlServerError.name;\n }\n\n static get name() {\n return 'JsonqlServerError';\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","// 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.publicNamespace ].join('/'),\n [ base , config.privateNamespace ].join('/')\n ]\n }\n return [ base ]\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","// 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(client, resolverName, setupResolver(namespace, resolverName, params, fn, ee, log))\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 createNamespaceErrorHandler(client, opts, ee, nspGroup) {\n return [\n // using the onError as name\n // @TODO we should follow the convention earlier\n // make this a setter for the clientitself\n objDefineProps(client, ON_ERROR_FN_NAME, 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 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 createOnReadyHandler(client, opts, ee) {\n return [\n objDefineProps(client, ON_READY_FN_NAME, 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 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} ","// 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 createNamespaceErrorHandler,\n createOnReadyHandler\n} from './resolver-methods'\nimport {\n setupFinalStep \n} from './setup-final-step'\nimport {\n NSP_GROUP\n} from 'jsonql-constants'\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 generator(opts, nspMap, ee) {\n\n let args = [\n generateResolvers,\n createNamespaceErrorHandler,\n createOnReadyHandler\n ]\n if (opts.enableAuth) {\n args.push(\n createAuthMethods\n )\n } \n // we will always get back the [ obj, opts, ee ]\n // then we only return the obj (wsClient)\n args.push(setupFinalStep)\n // run it\n const fn = Reflect.apply(chainFns, null, args)\n\n return fn(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 { generator } from './core'\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} frameworkSocketEngine \n * @param {object} config the already checked config \n */\nexport function wsClientCoreAction(frameworkSocketEngine, config) {\n return postCheckInjectOpts(config)\n // the following two moved to wsPostConfig\n .then(createRequiredParams)\n .then(\n ({opts, nspMap, ee}) => frameworkSocketEngine(opts, nspMap, ee)\n )\n .then(\n ({opts, nspMap, ee}) => generator(opts, nspMap, ee)\n )\n .catch(err => {\n console.error(`jsonql-ws-core-client init error`, err)\n })\n}\n\n/**\n * The main interface which will generate the socket clients and map all events\n * @param {object} frameworkSocketEngine 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(frameworkSocketEngine, configCheckMap = {}, constProps = {}) {\n // we need to inject property to this client later\n return (config = {}) => checkConfiguration(config, configCheckMap, constProps)\n .then(opts => wsClientCoreAction(frameworkSocketEngine, opts))\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 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}","// 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\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, SOCKET_IO, DISCONNECTED_ERROR_MSG } from '../options/constants'\nimport { createEvt, clearMainEmitEvt } from '../utils'\nimport { triggerNamespacesOnError } from './trigger-namespaces-on-error'\n\n/**\n * A Event handler 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 */\nconst notLoginWsHandler = (namespace, ee, opts) => {\n const { log } = opts \n ee.$only(\n createEvt(namespace, EMIT_EVT),\n function notLoginHandlerCallback(resolverName, args) {\n log('[notLoginHandler] hijack the ws call', namespace, resolverName, args)\n const error = {\n message: NOT_LOGIN_ERR_MSG\n }\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 handler, but wrap inside the error key\n ee.$call(createEvt(namespace, resolverName, ON_RESULT_FN_NAME), [{ error }])\n }\n )\n}\n\n/**\n * A Event handler 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 */\nconst disconnectedHandler = (namespace, ee, opts) => {\n const { log } = opts \n ee.$only(\n createEvt(namespace, EMIT_EVT),\n function disconnectedHandlerCallback(resolverName, args) {\n log(`[disconnectedHandler] 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 handler, but wrap inside the error key\n ee.$call(createEvt(namespace, resolverName, ON_RESULT_FN_NAME), [{ error }])\n }\n )\n}\n\n/**\n * get the private namespace\n * @param {array} namespaces array\n * @return {*} string on success\n */\nconst getPrivateNamespace = (namespaces) => (\n namespaces.length > 1 ? namespaces[0] : false\n)\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 */\nconst logoutEvtHandler = (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(LOGOUT_EVENT_NAME, function logoutEvtHandlerAction() {\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 handler\n triggerNamespacesOnError(ee, [privateNamespace], LOGOUT_EVENT_NAME)\n // rebind all of the handler 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 notLoginWsHandler(privateNamespace, ee, opts)\n })\n}\n\n/**\n * The disconnect event handler, 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 */\nconst disconnectHandler = (nsps, namespaces, ee, opts) => {\n const { log } = opts \n ee.$on(DISCONNECT_EVENT_NAME, function disconnectEvtHandler() {\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 disconnectedHandler(namespace, ee, opts)\n })\n })\n}\n\n/**\n * centralize all the comm in one place\n * @param {object} opts configuration\n * @param {object} nspMap this is not in the opts \n * @param {object} ee Event Emitter instance\n * @param {function} bindWsHandler binding the ee to ws --> this is the core bit\n * @param {object} nsps namespaced nsp\n * @return {void} nothing\n */\nexport function clientEventHandler(opts, nspMap, ee, bindSocketEventHandler, nsps) {\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 let isPrivate = false\n let hasPrivate = false\n // loop\n // @BUG for io this has to be in order the one with auth need to get call first\n // The order of login is very import we need to run in order here to make sure\n // one is execute then the other\n namespaces.forEach(namespace => {\n isPrivate = privateNamespace === namespace\n if (!hasPrivate) {\n hasPrivate = isPrivate\n }\n log(namespace, ' --> nsps --> ', nsps[namespace])\n if (nsps[namespace]) {\n\n log('[call bindWsHandler]', isPrivate, namespace)\n let args = [namespace, nsps[namespace], ee, isPrivate, opts]\n \n if (opts.serverType === SOCKET_IO) {\n let { nspGroup } = nspMap\n args.push(nspGroup[namespace])\n }\n Reflect.apply(bindSocketEventHandler, null, args)\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 notLoginWsHandler(namespace, ee, opts)\n }\n })\n // logout event handler \n if (hasPrivate) {\n log(`Has private and add logoutEvtHandler`)\n logoutEvtHandler(nsps, namespaces, ee, opts)\n }\n // finally the disconnect event handlers\n disconnectHandler(nsps, namespaces, ee, opts) \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'\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 * @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 */\nfunction initWebSocketClient(WebSocket, auth = false) {\n if (auth === false) {\n return function createWsClient(url) {\n return new WebSocket(fixWss(url))\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 * @return {object} ws instance\n */\n return function createWsAuthClient(url, token) {\n const ws_url = fixWss(url)\n // console.log('what happen here?', url, ws_url, token)\n const uri = token && typeof token === 'string' ? `${ws_url}?${TOKEN_PARAM_NAME}=${token}` : ws_url\n try {\n return new WebSocket(uri)\n } catch(e) {\n console.error('WebSocket Connection Error', e)\n return false\n }\n }\n}\n\nexport { initWebSocketClient }","// @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}","/**\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 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 * 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","// 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","/**\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","// 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' \n\nconst WS_KEYS = [\n WS_REPLY_TYPE,\n WS_EVT_NAME,\n WS_DATA_NAME\n]\nimport isString from 'lodash-es/isString'\nimport { toJson, isFunc, isObjectHasKey, nil } from './generic'\nimport { timestamp } from './timestamp'\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 can not decoded', 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_TYPE,\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 createReplyMsg, \n createEvt, \n extractWsPayload \n} from 'jsonql-utils/module'\nimport {\n handleNamespaceOnError\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 * @return {void}\n */\nconst logoutEventHandler = (ee) => {\n // listen to the LOGOUT_EVENT_NAME when this is a private nsp\n ee.$on(LOGOUT_EVENT_NAME, function closeEvtHandler() {\n try {\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 socketEventHandler(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 = createReplyMsg(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 const json = extractWsPayload(payload)\n const { resolverName, type } = json\n \n log('Hear 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_TYPE:\n // this is handled error and we won't throw it\n // we need to extract the error from json\n log(`ERROR_TYPE`)\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 logoutEventHandler(ee)\n }\n}\n","// actually binding the event client to the socket client\n\n// from the jsonql-ws-client-core\nimport { clientEventHandler } from '../modules'\n// local \nimport { createNspAction } from './create-nsp-action'\nimport { loginEventHandler } from './login-event-handler'\nimport { socketEventHandler } from './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 // arguments for clientEventHandler\n const args = [opts, nspMap, ee, socketEventHandler]\n\n // now create the nsps\n const { namespaces } = nspMap\n const { token, log } = opts\n const { nsps } = createNspAction(opts, nspMap, token)\n args.push(nsps)\n // log(`argument length`, args.length, args)\n\n // binding the listeners - and it will listen to LOGOUT event\n // to unbind itself, and the above call will bind it again\n Reflect.apply(clientEventHandler, null, args)\n // setup listener for the login event\n if (opts.enableAuth) {\n loginEventHandler(ee, namespaces, nspMap, opts)\n }\n // return what input\n return { opts, nspMap, ee }\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\n\nimport { initWebSocketClient } from './init-websocket-client'\nimport createNsp from '../create-nsp'\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 const nspClient = initWebSocketClient(frameworkModule)\n const nspAuthClient = initWebSocketClient(frameworkModule, true)\n\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 opts.nspClient = nspClient\n opts.nspAuthClient = nspAuthClient \n // @1.0.7 remove later once everything fixed \n const { log } = opts\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;;;;;;;;;;;;;;;;;"} \ No newline at end of file +{"version":3,"file":"main.js","sources":["node_modules/_rollup-plugin-node-globals@1.4.0@rollup-plugin-node-globals/src/global.js","../../ws-client-core/node_modules/lodash-es/_arrayMap.js","../../ws-client-core/node_modules/lodash-es/isArray.js","../../ws-client-core/node_modules/lodash-es/_objectToString.js","../../ws-client-core/node_modules/lodash-es/isObjectLike.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-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/lodash-es/_overArg.js","../../ws-client-core/node_modules/lodash-es/_arrayFilter.js","../../ws-client-core/node_modules/lodash-es/_createBaseFor.js","../../ws-client-core/node_modules/lodash-es/_baseTimes.js","../../ws-client-core/node_modules/lodash-es/stubFalse.js","../../ws-client-core/node_modules/lodash-es/_isIndex.js","../../ws-client-core/node_modules/lodash-es/isLength.js","../../ws-client-core/node_modules/lodash-es/_baseUnary.js","../../ws-client-core/node_modules/lodash-es/_isPrototype.js","../../ws-client-core/node_modules/lodash-es/isObject.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/_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/_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/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/identity.js","../../ws-client-core/node_modules/lodash-es/_baseProperty.js","../../ws-client-core/node_modules/jsonql-params-validator/src/object.js","../../ws-client-core/node_modules/jsonql-errors/src/validation-error.js","../../ws-client-core/node_modules/jsonql-params-validator/src/validator.js","../../ws-client-core/node_modules/lodash-es/_copyArray.js","../../ws-client-core/node_modules/lodash-es/_safeGet.js","../../ws-client-core/node_modules/lodash-es/_nativeKeysIn.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/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-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-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/node_modules/jsonql-utils/src/generic.js","../../ws-client-core/node_modules/jsonql-errors/src/500-error.js","../../ws-client-core/node_modules/jsonql-errors/src/resolver-not-found-error.js","../../ws-client-core/node_modules/jsonql-errors/src/server-error.js","../../ws-client-core/node_modules/jsonql-utils/src/contract.js","../../ws-client-core/node_modules/jsonql-utils/src/namespace.js","../../ws-client-core/src/utils/helpers.js","../../ws-client-core/src/core/setup-auth-methods.js","../../ws-client-core/src/options/constants.js","../../ws-client-core/src/core/respond-handler.js","../../ws-client-core/src/core/action-call.js","../../ws-client-core/src/core/setup-send-method.js","../../ws-client-core/src/core/setup-resolver.js","../../ws-client-core/src/core/resolver-methods.js","../../ws-client-core/src/core/setup-intercom.js","../../ws-client-core/src/core/generator.js","../../ws-client-core/src/options/index.js","../../ws-client-core/src/api.js","../../ws-client-core/src/share/create-nsp-clients.js","../../ws-client-core/src/share/trigger-namespaces-on-error.js","../../ws-client-core/src/share/client-event-handler.js","src/options/index.js","src/core/create-websocket-binding/init-websocket-client.js","src/core/create-nsp/login-event-handler.js","node_modules/_lodash-es@4.17.15@lodash-es/isArray.js","node_modules/_lodash-es@4.17.15@lodash-es/_objectToString.js","node_modules/_lodash-es@4.17.15@lodash-es/isObjectLike.js","node_modules/_jsonql-utils@1.1.3@jsonql-utils/src/generic.js","node_modules/_jsonql-errors@1.1.10@jsonql-errors/src/validation-error.js","node_modules/_jsonql-utils@1.1.3@jsonql-utils/src/timestamp.js","node_modules/_jsonql-utils@1.1.3@jsonql-utils/src/params-api.js","node_modules/_jsonql-utils@1.1.3@jsonql-utils/src/socket.js","src/core/create-nsp/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":["export default (typeof global !== \"undefined\" ? global :\n typeof self !== \"undefined\" ? self :\n typeof window !== \"undefined\" ? window : {});\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 * 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 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 * 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 * 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","// 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\nexport const 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)`\nexport const PARAMS_NOT_ARRAY_ERR = `params is not an array! Did something gone wrong when you generate the contract.json?`\nexport const EXCEPTION_CASE_ERR = 'Could not understand your arguments and parameter structure!'\nexport const UNUSUAL_CASE_ERR = 'This is an unusual situation where the arguments are more than the params, but not mark as spread'\n\n// re-export\nimport * as JSONQL_CONSTANTS from 'jsonql-constants'\n// @TODO the jsdoc return array. and we should also allow array syntax\nexport const DEFAULT_TYPE = JSONQL_CONSTANTS.DEFAULT_TYPE\nexport const ARRAY_TYPE_LFT = JSONQL_CONSTANTS.ARRAY_TYPE_LFT\nexport const ARRAY_TYPE_RGT = JSONQL_CONSTANTS.ARRAY_TYPE_RGT\n\nexport const TYPE_KEY = JSONQL_CONSTANTS.TYPE_KEY\nexport const OPTIONAL_KEY = JSONQL_CONSTANTS.OPTIONAL_KEY\nexport const ENUM_KEY = JSONQL_CONSTANTS.ENUM_KEY\nexport const ARGS_KEY = JSONQL_CONSTANTS.ARGS_KEY\nexport const CHECKER_KEY = JSONQL_CONSTANTS.CHECKER_KEY\nexport const ALIAS_KEY = JSONQL_CONSTANTS.ALIAS_KEY\n\nexport const ARRAY_TYPE = JSONQL_CONSTANTS.ARRAY_TYPE\nexport const OBJECT_TYPE = JSONQL_CONSTANTS.OBJECT_TYPE\nexport const STRING_TYPE = JSONQL_CONSTANTS.STRING_TYPE\nexport const BOOLEAN_TYPE = JSONQL_CONSTANTS.BOOLEAN_TYPE\nexport const NUMBER_TYPE = JSONQL_CONSTANTS.NUMBER_TYPE\nexport const KEY_WORD = JSONQL_CONSTANTS.KEY_WORD\nexport const OR_SEPERATOR = JSONQL_CONSTANTS.OR_SEPERATOR\n\n// not actually in use\n// export const NUMBER_TYPES = JSONQL_CONSTANTS.NUMBER_TYPES;\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","/**\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 * 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 * 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 * 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","/**\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","/** 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","/** 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 * 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","/** 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 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","/**\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","/** 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","/** 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 * 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 * 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 * 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","// validate object type\n\nimport isPlainObject from 'lodash-es/isPlainObject'\nimport filter from 'lodash-es/filter'\n\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","// 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","// 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 // checkIsObject,\n combineFn,\n notEmpty\n} from './index'\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 // UNUSUAL_CASE_ERR\n} from './constants'\nimport { DATA_KEY, ERROR_KEY } from 'jsonql-constants'\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","/**\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","/**\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 * 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 * 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","/** 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","// 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","// 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'\n// PIA syntax\nexport const isObject = checkIsObject\nexport const isAny = checkIsAny\nexport const isString = checkIsString\nexport const isBoolean = checkIsBoolean\nexport const isNumber = checkIsNumber\nexport const isArray = checkIsArray\nexport const isNotEmpty = notEmpty\n\nimport * as validator from './src/validator'\n\nexport const normalizeArgs = validator.normalizeArgs\nexport const validateSync = validator.validateSync\nexport const validateAsync = validator.validateAsync\n\n// configuration checking\n\nimport * as jsonqlOptions from './src/options'\n\nexport const JSONQL_PARAMS_VALIDATOR_INFO = jsonqlOptions.JSONQL_PARAMS_VALIDATOR_INFO\n\nexport const createConfig = jsonqlOptions.createConfig\nexport const constructConfig = jsonqlOptions.constructConfigFn\n// construct the final output 1.5.2\nexport const checkConfigAsync = jsonqlOptions.getCheckConfigAsync(validator.validateSync)\nexport const checkConfig = jsonqlOptions.getCheckConfig(validator.validateSync)\n\n// export the two extra functions\nimport isInArray from './src/is-in-array'\nimport isObjectHasKeyFn from './src/is-key-in-object'\n\nexport const inArray = isInArray\nexport const isObjectHasKey = isObjectHasKeyFn\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","// 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","/**\n * This is a custom error to throw when server throw a 500\n * This help us to capture the right error, due to the call happens in sequence\n * @param {string} message to tell what happen\n * @param {mixed} extra things we want to add, 500?\n */\nexport default class Jsonql500Error extends Error {\n constructor(...args) {\n super(...args)\n\n this.message = args[0]\n this.detail = args[1]\n\n this.className = Jsonql500Error.name;\n\n if (Error.captureStackTrace) {\n Error.captureStackTrace(this, Jsonql500Error)\n }\n }\n\n static get statusCode() {\n return 500;\n }\n\n static get name() {\n return 'Jsonql500Error';\n }\n\n}\n","/**\n * This is a custom error to throw when could not find the resolver\n * This help us to capture the right error, due to the call happens in sequence\n * @param {string} message to tell what happen\n * @param {mixed} extra things we want to add, 500?\n */\nexport default class JsonqlResolverNotFoundError extends Error {\n constructor(...args) {\n super(...args)\n\n this.message = args[0]\n this.detail = args[1]\n\n this.className = JsonqlResolverNotFoundError.name;\n\n if (Error.captureStackTrace) {\n Error.captureStackTrace(this, JsonqlResolverNotFoundError);\n }\n }\n\n static get statusCode() {\n return 404;\n }\n\n static get name() {\n return 'JsonqlResolverNotFoundError';\n }\n}\n","// this is from an example from Koa team to use for internal middleware ctx.throw\n// but after the test the res.body part is unable to extract the required data\n// I keep this one here for future reference\n\nexport default class JsonqlServerError extends Error {\n\n constructor(statusCode, message) {\n super(message)\n this.statusCode = statusCode;\n this.className = JsonqlServerError.name;\n }\n\n static get name() {\n return 'JsonqlServerError';\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","// 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.publicNamespace ].join('/'),\n [ base , config.privateNamespace ].join('/')\n ]\n }\n return [ base ]\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","// 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(client, resolverName, setupResolver(namespace, resolverName, params, fn, ee, log))\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 createNamespaceErrorHandler(client, opts, ee, nspGroup) {\n return [\n // using the onError as name\n // @TODO we should follow the convention earlier\n // make this a setter for the clientitself\n objDefineProps(client, ON_ERROR_FN_NAME, 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 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 createOnReadyHandler(client, opts, ee) {\n return [\n objDefineProps(client, ON_READY_FN_NAME, 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 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} ","// 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 createNamespaceErrorHandler,\n createOnReadyHandler\n} from './resolver-methods'\nimport {\n setupFinalStep \n} from './setup-final-step'\nimport {\n NSP_GROUP\n} from 'jsonql-constants'\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 generator(opts, nspMap, ee) {\n\n let args = [\n generateResolvers,\n createNamespaceErrorHandler,\n createOnReadyHandler\n ]\n if (opts.enableAuth) {\n args.push(\n createAuthMethods\n )\n } \n // we will always get back the [ obj, opts, ee ]\n // then we only return the obj (wsClient)\n args.push(setupFinalStep)\n // run it\n const fn = Reflect.apply(chainFns, null, args)\n\n return fn(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 { generator } from './core'\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} frameworkSocketEngine \n * @param {object} config the already checked config \n */\nexport function wsClientCoreAction(frameworkSocketEngine, config) {\n return postCheckInjectOpts(config)\n // the following two moved to wsPostConfig\n .then(createRequiredParams)\n .then(\n ({opts, nspMap, ee}) => frameworkSocketEngine(opts, nspMap, ee)\n )\n .then(\n ({opts, nspMap, ee}) => generator(opts, nspMap, ee)\n )\n .catch(err => {\n console.error(`jsonql-ws-core-client init error`, err)\n })\n}\n\n/**\n * The main interface which will generate the socket clients and map all events\n * @param {object} frameworkSocketEngine 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(frameworkSocketEngine, configCheckMap = {}, constProps = {}) {\n // we need to inject property to this client later\n return (config = {}) => checkConfiguration(config, configCheckMap, constProps)\n .then(opts => wsClientCoreAction(frameworkSocketEngine, opts))\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 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}","// 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\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, SOCKET_IO, DISCONNECTED_ERROR_MSG } from '../options/constants'\nimport { createEvt, clearMainEmitEvt } from '../utils'\nimport { triggerNamespacesOnError } from './trigger-namespaces-on-error'\n\n/**\n * A Event handler 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 */\nconst notLoginWsHandler = (namespace, ee, opts) => {\n const { log } = opts \n ee.$only(\n createEvt(namespace, EMIT_EVT),\n function notLoginHandlerCallback(resolverName, args) {\n log('[notLoginHandler] hijack the ws call', namespace, resolverName, args)\n const error = {\n message: NOT_LOGIN_ERR_MSG\n }\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 handler, but wrap inside the error key\n ee.$call(createEvt(namespace, resolverName, ON_RESULT_FN_NAME), [{ error }])\n }\n )\n}\n\n/**\n * A Event handler 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 */\nconst disconnectedHandler = (namespace, ee, opts) => {\n const { log } = opts \n ee.$only(\n createEvt(namespace, EMIT_EVT),\n function disconnectedHandlerCallback(resolverName, args) {\n log(`[disconnectedHandler] 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 handler, but wrap inside the error key\n ee.$call(createEvt(namespace, resolverName, ON_RESULT_FN_NAME), [{ error }])\n }\n )\n}\n\n/**\n * get the private namespace\n * @param {array} namespaces array\n * @return {*} string on success\n */\nconst getPrivateNamespace = (namespaces) => (\n namespaces.length > 1 ? namespaces[0] : false\n)\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 */\nconst logoutEvtHandler = (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(LOGOUT_EVENT_NAME, function logoutEvtHandlerAction() {\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 handler\n triggerNamespacesOnError(ee, [privateNamespace], LOGOUT_EVENT_NAME)\n // rebind all of the handler 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 notLoginWsHandler(privateNamespace, ee, opts)\n })\n}\n\n/**\n * The disconnect event handler, 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 */\nconst disconnectHandler = (nsps, namespaces, ee, opts) => {\n const { log } = opts \n ee.$on(DISCONNECT_EVENT_NAME, function disconnectEvtHandler() {\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 disconnectedHandler(namespace, ee, opts)\n })\n })\n}\n\n/**\n * centralize all the comm in one place\n * @param {object} opts configuration\n * @param {object} nspMap this is not in the opts \n * @param {object} ee Event Emitter instance\n * @param {function} bindWsHandler binding the ee to ws --> this is the core bit\n * @param {object} nsps namespaced nsp\n * @return {void} nothing\n */\nexport function clientEventHandler(opts, nspMap, ee, bindSocketEventHandler, nsps) {\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 let isPrivate = false\n let hasPrivate = false\n // loop\n // @BUG for io this has to be in order the one with auth need to get call first\n // The order of login is very import we need to run in order here to make sure\n // one is execute then the other\n namespaces.forEach(namespace => {\n isPrivate = privateNamespace === namespace\n if (!hasPrivate) {\n hasPrivate = isPrivate\n }\n // log(namespace, ' --> nsps --> ', nsps[namespace])\n if (nsps[namespace]) {\n\n log('[call bindWsHandler]', isPrivate, namespace)\n let args = [namespace, nsps[namespace], ee, isPrivate, opts]\n \n if (opts.serverType === SOCKET_IO) {\n let { nspGroup } = nspMap\n args.push(nspGroup[namespace])\n }\n Reflect.apply(bindSocketEventHandler, null, args)\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 notLoginWsHandler(namespace, ee, opts)\n }\n })\n // logout event handler \n if (hasPrivate) {\n log(`Has private and add logoutEvtHandler`)\n logoutEvtHandler(nsps, namespaces, ee, opts)\n }\n // finally the disconnect event handlers\n disconnectHandler(nsps, namespaces, ee, opts) \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'\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 * @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 */\nfunction initWebSocketClient(WebSocket, auth = false) {\n if (auth === false) {\n return function createWsClient(url) {\n return new WebSocket(fixWss(url))\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 * @return {object} ws instance\n */\n return function createWsAuthClient(url, token) {\n const ws_url = fixWss(url)\n // console.log('what happen here?', url, ws_url, token)\n const uri = token && typeof token === 'string' ? `${ws_url}?${TOKEN_PARAM_NAME}=${token}` : ws_url\n try {\n return new WebSocket(uri)\n } catch(e) {\n console.error('WebSocket Connection Error', e)\n return false\n }\n }\n}\n\nexport { initWebSocketClient }","// @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}","/**\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 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 * 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","// 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'\nimport JsonqlValidationError from 'jsonql-errors/src/validation-error'\n\nimport isArray from 'lodash-es/isArray'\nimport isPlainObject from 'lodash-es/isPlainObject'\nimport isString from 'lodash-es/isString'\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 * Get name from the payload (ported back from jsonql-koa)\n * @param {*} payload to extract from\n * @return {string} name\n */\nexport function getNameFromPayload(payload) {\n console.error(`This method is going to be deprectead in the next release, please use getResolverFromPayload instead`)\n return Object.keys(payload)[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' \n\nconst WS_KEYS = [\n WS_REPLY_TYPE,\n WS_EVT_NAME,\n WS_DATA_NAME\n]\nimport isString from 'lodash-es/isString'\nimport { toJson, isFunc, isObjectHasKey, nil } from './generic'\nimport { timestamp } from './timestamp'\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 can not decoded', 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_TYPE,\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} 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 * @return {void}\n */\nconst logoutEventHandler = (ee) => {\n // listen to the LOGOUT_EVENT_NAME when this is a private nsp\n ee.$on(LOGOUT_EVENT_NAME, function closeEvtHandler() {\n try {\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 socketEventHandler(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 // 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('Hear 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_TYPE:\n // this is handled error and we won't throw it\n // we need to extract the error from json\n log(`ERROR_TYPE`)\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 logoutEventHandler(ee)\n }\n}\n","// actually binding the event client to the socket client\n\n// from the jsonql-ws-client-core\nimport { clientEventHandler } from '../modules'\n// local \nimport { createNspAction } from './create-nsp-action'\nimport { loginEventHandler } from './login-event-handler'\nimport { socketEventHandler } from './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 // arguments for clientEventHandler\n const args = [opts, nspMap, ee, socketEventHandler]\n\n // now create the nsps\n const { namespaces } = nspMap\n const { token, log } = opts\n const { nsps } = createNspAction(opts, nspMap, token)\n args.push(nsps)\n // log(`argument length`, args.length, args)\n\n // binding the listeners - and it will listen to LOGOUT event\n // to unbind itself, and the above call will bind it again\n Reflect.apply(clientEventHandler, null, args)\n // setup listener for the login event\n if (opts.enableAuth) {\n loginEventHandler(ee, namespaces, nspMap, opts)\n }\n // return what input\n return { opts, nspMap, ee }\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\n\nimport { initWebSocketClient } from './init-websocket-client'\nimport createNsp from '../create-nsp'\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 const nspClient = initWebSocketClient(frameworkModule)\n const nspAuthClient = initWebSocketClient(frameworkModule, true)\n\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 opts.nspClient = nspClient\n opts.nspAuthClient = nspAuthClient \n // @1.0.7 remove later once everything fixed \n const { log } = opts\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;;;;;;;;;;;;;;;;;"} \ No newline at end of file diff --git a/packages/@jsonql/ws/src/core/create-nsp/socket-event-handler.js b/packages/@jsonql/ws/src/core/create-nsp/socket-event-handler.js index 59ef2933..f5b9297b 100644 --- a/packages/@jsonql/ws/src/core/create-nsp/socket-event-handler.js +++ b/packages/@jsonql/ws/src/core/create-nsp/socket-event-handler.js @@ -12,7 +12,7 @@ import { ON_LOGIN_FN_NAME } from 'jsonql-constants' import { - createReplyMsg, + createQueryStr, createEvt, extractWsPayload } from 'jsonql-utils/module' @@ -92,7 +92,7 @@ export function socketEventHandler(namespace, ws, ee, isPrivate, opts) { */ function wsMainOnEvtHandler(resolverName, args) { - const payload = createReplyMsg(resolverName, args) + const payload = createQueryStr(resolverName, args) log('ws.onopen.send', resolverName, args, payload) ws.send(payload) @@ -106,7 +106,10 @@ export function socketEventHandler(namespace, ws, ee, isPrivate, opts) { ws.onmessage = function onMessageCallback(payload) { // console.log(`on.message`, typeof payload, payload) try { - const json = extractWsPayload(payload) + log(`ws.onmessage raw payload`, payload) + // 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('Hear from server', type, json) -- Gitee From 25427a93eebe713f06a8f12be17edc809d6eda74 Mon Sep 17 00:00:00 2001 From: joelchu Date: Sat, 14 Mar 2020 08:04:10 +0800 Subject: [PATCH 39/45] fix the basic test --- .../@jsonql/ws/src/core/create-nsp/socket-event-handler.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/@jsonql/ws/src/core/create-nsp/socket-event-handler.js b/packages/@jsonql/ws/src/core/create-nsp/socket-event-handler.js index f5b9297b..f21bec1c 100644 --- a/packages/@jsonql/ws/src/core/create-nsp/socket-event-handler.js +++ b/packages/@jsonql/ws/src/core/create-nsp/socket-event-handler.js @@ -106,13 +106,13 @@ export function socketEventHandler(namespace, ws, ee, isPrivate, opts) { ws.onmessage = function onMessageCallback(payload) { // console.log(`on.message`, typeof payload, payload) try { - log(`ws.onmessage raw payload`, payload) - // the payload actually contain quite a few things - is that changed? + // log(`ws.onmessage raw payload`, payload) + // @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('Hear from server', type, json) + log('Respond from server', type, json) switch (type) { case EMIT_REPLY_TYPE: -- Gitee From 658364e0e452588851acdb1509a49dc35093bed3 Mon Sep 17 00:00:00 2001 From: joelchu Date: Sat, 14 Mar 2020 08:15:04 +0800 Subject: [PATCH 40/45] fix test:chain --- packages/@jsonql/ws/main.js | 6 +++--- packages/@jsonql/ws/main.js.map | 2 +- packages/@jsonql/ws/tests/ws-client-chain.test.js | 6 +++--- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/packages/@jsonql/ws/main.js b/packages/@jsonql/ws/main.js index e04e354e..f06bfe14 100644 --- a/packages/@jsonql/ws/main.js +++ b/packages/@jsonql/ws/main.js @@ -8467,14 +8467,14 @@ function socketEventHandler(namespace, ws, ee, isPrivate, opts) { ws.onmessage = function onMessageCallback(payload) { // console.log(`on.message`, typeof payload, payload) try { - log("ws.onmessage raw payload", payload); - // the payload actually contain quite a few things - is that changed? + // log(`ws.onmessage raw payload`, payload) + // @TODO the payload actually contain quite a few things - is that changed? // type: message, data: data_send_from_server var json = extractWsPayload(payload.data); var resolverName = json.resolverName; var type = json.type; - log('Hear from server', type, json); + log('Respond from server', type, json); switch (type) { case EMIT_REPLY_TYPE$1: diff --git a/packages/@jsonql/ws/main.js.map b/packages/@jsonql/ws/main.js.map index 7f4db12b..360cdf46 100644 --- a/packages/@jsonql/ws/main.js.map +++ b/packages/@jsonql/ws/main.js.map @@ -1 +1 @@ -{"version":3,"file":"main.js","sources":["node_modules/_rollup-plugin-node-globals@1.4.0@rollup-plugin-node-globals/src/global.js","../../ws-client-core/node_modules/lodash-es/_arrayMap.js","../../ws-client-core/node_modules/lodash-es/isArray.js","../../ws-client-core/node_modules/lodash-es/_objectToString.js","../../ws-client-core/node_modules/lodash-es/isObjectLike.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-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/lodash-es/_overArg.js","../../ws-client-core/node_modules/lodash-es/_arrayFilter.js","../../ws-client-core/node_modules/lodash-es/_createBaseFor.js","../../ws-client-core/node_modules/lodash-es/_baseTimes.js","../../ws-client-core/node_modules/lodash-es/stubFalse.js","../../ws-client-core/node_modules/lodash-es/_isIndex.js","../../ws-client-core/node_modules/lodash-es/isLength.js","../../ws-client-core/node_modules/lodash-es/_baseUnary.js","../../ws-client-core/node_modules/lodash-es/_isPrototype.js","../../ws-client-core/node_modules/lodash-es/isObject.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/_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/_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/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/identity.js","../../ws-client-core/node_modules/lodash-es/_baseProperty.js","../../ws-client-core/node_modules/jsonql-params-validator/src/object.js","../../ws-client-core/node_modules/jsonql-errors/src/validation-error.js","../../ws-client-core/node_modules/jsonql-params-validator/src/validator.js","../../ws-client-core/node_modules/lodash-es/_copyArray.js","../../ws-client-core/node_modules/lodash-es/_safeGet.js","../../ws-client-core/node_modules/lodash-es/_nativeKeysIn.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/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-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-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/node_modules/jsonql-utils/src/generic.js","../../ws-client-core/node_modules/jsonql-errors/src/500-error.js","../../ws-client-core/node_modules/jsonql-errors/src/resolver-not-found-error.js","../../ws-client-core/node_modules/jsonql-errors/src/server-error.js","../../ws-client-core/node_modules/jsonql-utils/src/contract.js","../../ws-client-core/node_modules/jsonql-utils/src/namespace.js","../../ws-client-core/src/utils/helpers.js","../../ws-client-core/src/core/setup-auth-methods.js","../../ws-client-core/src/options/constants.js","../../ws-client-core/src/core/respond-handler.js","../../ws-client-core/src/core/action-call.js","../../ws-client-core/src/core/setup-send-method.js","../../ws-client-core/src/core/setup-resolver.js","../../ws-client-core/src/core/resolver-methods.js","../../ws-client-core/src/core/setup-intercom.js","../../ws-client-core/src/core/generator.js","../../ws-client-core/src/options/index.js","../../ws-client-core/src/api.js","../../ws-client-core/src/share/create-nsp-clients.js","../../ws-client-core/src/share/trigger-namespaces-on-error.js","../../ws-client-core/src/share/client-event-handler.js","src/options/index.js","src/core/create-websocket-binding/init-websocket-client.js","src/core/create-nsp/login-event-handler.js","node_modules/_lodash-es@4.17.15@lodash-es/isArray.js","node_modules/_lodash-es@4.17.15@lodash-es/_objectToString.js","node_modules/_lodash-es@4.17.15@lodash-es/isObjectLike.js","node_modules/_jsonql-utils@1.1.3@jsonql-utils/src/generic.js","node_modules/_jsonql-errors@1.1.10@jsonql-errors/src/validation-error.js","node_modules/_jsonql-utils@1.1.3@jsonql-utils/src/timestamp.js","node_modules/_jsonql-utils@1.1.3@jsonql-utils/src/params-api.js","node_modules/_jsonql-utils@1.1.3@jsonql-utils/src/socket.js","src/core/create-nsp/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":["export default (typeof global !== \"undefined\" ? global :\n typeof self !== \"undefined\" ? self :\n typeof window !== \"undefined\" ? window : {});\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 * 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 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 * 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 * 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","// 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\nexport const 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)`\nexport const PARAMS_NOT_ARRAY_ERR = `params is not an array! Did something gone wrong when you generate the contract.json?`\nexport const EXCEPTION_CASE_ERR = 'Could not understand your arguments and parameter structure!'\nexport const UNUSUAL_CASE_ERR = 'This is an unusual situation where the arguments are more than the params, but not mark as spread'\n\n// re-export\nimport * as JSONQL_CONSTANTS from 'jsonql-constants'\n// @TODO the jsdoc return array. and we should also allow array syntax\nexport const DEFAULT_TYPE = JSONQL_CONSTANTS.DEFAULT_TYPE\nexport const ARRAY_TYPE_LFT = JSONQL_CONSTANTS.ARRAY_TYPE_LFT\nexport const ARRAY_TYPE_RGT = JSONQL_CONSTANTS.ARRAY_TYPE_RGT\n\nexport const TYPE_KEY = JSONQL_CONSTANTS.TYPE_KEY\nexport const OPTIONAL_KEY = JSONQL_CONSTANTS.OPTIONAL_KEY\nexport const ENUM_KEY = JSONQL_CONSTANTS.ENUM_KEY\nexport const ARGS_KEY = JSONQL_CONSTANTS.ARGS_KEY\nexport const CHECKER_KEY = JSONQL_CONSTANTS.CHECKER_KEY\nexport const ALIAS_KEY = JSONQL_CONSTANTS.ALIAS_KEY\n\nexport const ARRAY_TYPE = JSONQL_CONSTANTS.ARRAY_TYPE\nexport const OBJECT_TYPE = JSONQL_CONSTANTS.OBJECT_TYPE\nexport const STRING_TYPE = JSONQL_CONSTANTS.STRING_TYPE\nexport const BOOLEAN_TYPE = JSONQL_CONSTANTS.BOOLEAN_TYPE\nexport const NUMBER_TYPE = JSONQL_CONSTANTS.NUMBER_TYPE\nexport const KEY_WORD = JSONQL_CONSTANTS.KEY_WORD\nexport const OR_SEPERATOR = JSONQL_CONSTANTS.OR_SEPERATOR\n\n// not actually in use\n// export const NUMBER_TYPES = JSONQL_CONSTANTS.NUMBER_TYPES;\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","/**\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 * 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 * 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 * 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","/**\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","/** 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","/** 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 * 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","/** 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 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","/**\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","/** 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","/** 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 * 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 * 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 * 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","// validate object type\n\nimport isPlainObject from 'lodash-es/isPlainObject'\nimport filter from 'lodash-es/filter'\n\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","// 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","// 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 // checkIsObject,\n combineFn,\n notEmpty\n} from './index'\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 // UNUSUAL_CASE_ERR\n} from './constants'\nimport { DATA_KEY, ERROR_KEY } from 'jsonql-constants'\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","/**\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","/**\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 * 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 * 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","/** 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","// 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","// 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'\n// PIA syntax\nexport const isObject = checkIsObject\nexport const isAny = checkIsAny\nexport const isString = checkIsString\nexport const isBoolean = checkIsBoolean\nexport const isNumber = checkIsNumber\nexport const isArray = checkIsArray\nexport const isNotEmpty = notEmpty\n\nimport * as validator from './src/validator'\n\nexport const normalizeArgs = validator.normalizeArgs\nexport const validateSync = validator.validateSync\nexport const validateAsync = validator.validateAsync\n\n// configuration checking\n\nimport * as jsonqlOptions from './src/options'\n\nexport const JSONQL_PARAMS_VALIDATOR_INFO = jsonqlOptions.JSONQL_PARAMS_VALIDATOR_INFO\n\nexport const createConfig = jsonqlOptions.createConfig\nexport const constructConfig = jsonqlOptions.constructConfigFn\n// construct the final output 1.5.2\nexport const checkConfigAsync = jsonqlOptions.getCheckConfigAsync(validator.validateSync)\nexport const checkConfig = jsonqlOptions.getCheckConfig(validator.validateSync)\n\n// export the two extra functions\nimport isInArray from './src/is-in-array'\nimport isObjectHasKeyFn from './src/is-key-in-object'\n\nexport const inArray = isInArray\nexport const isObjectHasKey = isObjectHasKeyFn\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","// 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","/**\n * This is a custom error to throw when server throw a 500\n * This help us to capture the right error, due to the call happens in sequence\n * @param {string} message to tell what happen\n * @param {mixed} extra things we want to add, 500?\n */\nexport default class Jsonql500Error extends Error {\n constructor(...args) {\n super(...args)\n\n this.message = args[0]\n this.detail = args[1]\n\n this.className = Jsonql500Error.name;\n\n if (Error.captureStackTrace) {\n Error.captureStackTrace(this, Jsonql500Error)\n }\n }\n\n static get statusCode() {\n return 500;\n }\n\n static get name() {\n return 'Jsonql500Error';\n }\n\n}\n","/**\n * This is a custom error to throw when could not find the resolver\n * This help us to capture the right error, due to the call happens in sequence\n * @param {string} message to tell what happen\n * @param {mixed} extra things we want to add, 500?\n */\nexport default class JsonqlResolverNotFoundError extends Error {\n constructor(...args) {\n super(...args)\n\n this.message = args[0]\n this.detail = args[1]\n\n this.className = JsonqlResolverNotFoundError.name;\n\n if (Error.captureStackTrace) {\n Error.captureStackTrace(this, JsonqlResolverNotFoundError);\n }\n }\n\n static get statusCode() {\n return 404;\n }\n\n static get name() {\n return 'JsonqlResolverNotFoundError';\n }\n}\n","// this is from an example from Koa team to use for internal middleware ctx.throw\n// but after the test the res.body part is unable to extract the required data\n// I keep this one here for future reference\n\nexport default class JsonqlServerError extends Error {\n\n constructor(statusCode, message) {\n super(message)\n this.statusCode = statusCode;\n this.className = JsonqlServerError.name;\n }\n\n static get name() {\n return 'JsonqlServerError';\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","// 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.publicNamespace ].join('/'),\n [ base , config.privateNamespace ].join('/')\n ]\n }\n return [ base ]\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","// 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(client, resolverName, setupResolver(namespace, resolverName, params, fn, ee, log))\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 createNamespaceErrorHandler(client, opts, ee, nspGroup) {\n return [\n // using the onError as name\n // @TODO we should follow the convention earlier\n // make this a setter for the clientitself\n objDefineProps(client, ON_ERROR_FN_NAME, 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 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 createOnReadyHandler(client, opts, ee) {\n return [\n objDefineProps(client, ON_READY_FN_NAME, 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 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} ","// 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 createNamespaceErrorHandler,\n createOnReadyHandler\n} from './resolver-methods'\nimport {\n setupFinalStep \n} from './setup-final-step'\nimport {\n NSP_GROUP\n} from 'jsonql-constants'\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 generator(opts, nspMap, ee) {\n\n let args = [\n generateResolvers,\n createNamespaceErrorHandler,\n createOnReadyHandler\n ]\n if (opts.enableAuth) {\n args.push(\n createAuthMethods\n )\n } \n // we will always get back the [ obj, opts, ee ]\n // then we only return the obj (wsClient)\n args.push(setupFinalStep)\n // run it\n const fn = Reflect.apply(chainFns, null, args)\n\n return fn(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 { generator } from './core'\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} frameworkSocketEngine \n * @param {object} config the already checked config \n */\nexport function wsClientCoreAction(frameworkSocketEngine, config) {\n return postCheckInjectOpts(config)\n // the following two moved to wsPostConfig\n .then(createRequiredParams)\n .then(\n ({opts, nspMap, ee}) => frameworkSocketEngine(opts, nspMap, ee)\n )\n .then(\n ({opts, nspMap, ee}) => generator(opts, nspMap, ee)\n )\n .catch(err => {\n console.error(`jsonql-ws-core-client init error`, err)\n })\n}\n\n/**\n * The main interface which will generate the socket clients and map all events\n * @param {object} frameworkSocketEngine 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(frameworkSocketEngine, configCheckMap = {}, constProps = {}) {\n // we need to inject property to this client later\n return (config = {}) => checkConfiguration(config, configCheckMap, constProps)\n .then(opts => wsClientCoreAction(frameworkSocketEngine, opts))\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 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}","// 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\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, SOCKET_IO, DISCONNECTED_ERROR_MSG } from '../options/constants'\nimport { createEvt, clearMainEmitEvt } from '../utils'\nimport { triggerNamespacesOnError } from './trigger-namespaces-on-error'\n\n/**\n * A Event handler 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 */\nconst notLoginWsHandler = (namespace, ee, opts) => {\n const { log } = opts \n ee.$only(\n createEvt(namespace, EMIT_EVT),\n function notLoginHandlerCallback(resolverName, args) {\n log('[notLoginHandler] hijack the ws call', namespace, resolverName, args)\n const error = {\n message: NOT_LOGIN_ERR_MSG\n }\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 handler, but wrap inside the error key\n ee.$call(createEvt(namespace, resolverName, ON_RESULT_FN_NAME), [{ error }])\n }\n )\n}\n\n/**\n * A Event handler 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 */\nconst disconnectedHandler = (namespace, ee, opts) => {\n const { log } = opts \n ee.$only(\n createEvt(namespace, EMIT_EVT),\n function disconnectedHandlerCallback(resolverName, args) {\n log(`[disconnectedHandler] 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 handler, but wrap inside the error key\n ee.$call(createEvt(namespace, resolverName, ON_RESULT_FN_NAME), [{ error }])\n }\n )\n}\n\n/**\n * get the private namespace\n * @param {array} namespaces array\n * @return {*} string on success\n */\nconst getPrivateNamespace = (namespaces) => (\n namespaces.length > 1 ? namespaces[0] : false\n)\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 */\nconst logoutEvtHandler = (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(LOGOUT_EVENT_NAME, function logoutEvtHandlerAction() {\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 handler\n triggerNamespacesOnError(ee, [privateNamespace], LOGOUT_EVENT_NAME)\n // rebind all of the handler 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 notLoginWsHandler(privateNamespace, ee, opts)\n })\n}\n\n/**\n * The disconnect event handler, 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 */\nconst disconnectHandler = (nsps, namespaces, ee, opts) => {\n const { log } = opts \n ee.$on(DISCONNECT_EVENT_NAME, function disconnectEvtHandler() {\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 disconnectedHandler(namespace, ee, opts)\n })\n })\n}\n\n/**\n * centralize all the comm in one place\n * @param {object} opts configuration\n * @param {object} nspMap this is not in the opts \n * @param {object} ee Event Emitter instance\n * @param {function} bindWsHandler binding the ee to ws --> this is the core bit\n * @param {object} nsps namespaced nsp\n * @return {void} nothing\n */\nexport function clientEventHandler(opts, nspMap, ee, bindSocketEventHandler, nsps) {\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 let isPrivate = false\n let hasPrivate = false\n // loop\n // @BUG for io this has to be in order the one with auth need to get call first\n // The order of login is very import we need to run in order here to make sure\n // one is execute then the other\n namespaces.forEach(namespace => {\n isPrivate = privateNamespace === namespace\n if (!hasPrivate) {\n hasPrivate = isPrivate\n }\n // log(namespace, ' --> nsps --> ', nsps[namespace])\n if (nsps[namespace]) {\n\n log('[call bindWsHandler]', isPrivate, namespace)\n let args = [namespace, nsps[namespace], ee, isPrivate, opts]\n \n if (opts.serverType === SOCKET_IO) {\n let { nspGroup } = nspMap\n args.push(nspGroup[namespace])\n }\n Reflect.apply(bindSocketEventHandler, null, args)\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 notLoginWsHandler(namespace, ee, opts)\n }\n })\n // logout event handler \n if (hasPrivate) {\n log(`Has private and add logoutEvtHandler`)\n logoutEvtHandler(nsps, namespaces, ee, opts)\n }\n // finally the disconnect event handlers\n disconnectHandler(nsps, namespaces, ee, opts) \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'\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 * @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 */\nfunction initWebSocketClient(WebSocket, auth = false) {\n if (auth === false) {\n return function createWsClient(url) {\n return new WebSocket(fixWss(url))\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 * @return {object} ws instance\n */\n return function createWsAuthClient(url, token) {\n const ws_url = fixWss(url)\n // console.log('what happen here?', url, ws_url, token)\n const uri = token && typeof token === 'string' ? `${ws_url}?${TOKEN_PARAM_NAME}=${token}` : ws_url\n try {\n return new WebSocket(uri)\n } catch(e) {\n console.error('WebSocket Connection Error', e)\n return false\n }\n }\n}\n\nexport { initWebSocketClient }","// @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}","/**\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 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 * 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","// 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'\nimport JsonqlValidationError from 'jsonql-errors/src/validation-error'\n\nimport isArray from 'lodash-es/isArray'\nimport isPlainObject from 'lodash-es/isPlainObject'\nimport isString from 'lodash-es/isString'\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 * Get name from the payload (ported back from jsonql-koa)\n * @param {*} payload to extract from\n * @return {string} name\n */\nexport function getNameFromPayload(payload) {\n console.error(`This method is going to be deprectead in the next release, please use getResolverFromPayload instead`)\n return Object.keys(payload)[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' \n\nconst WS_KEYS = [\n WS_REPLY_TYPE,\n WS_EVT_NAME,\n WS_DATA_NAME\n]\nimport isString from 'lodash-es/isString'\nimport { toJson, isFunc, isObjectHasKey, nil } from './generic'\nimport { timestamp } from './timestamp'\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 can not decoded', 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_TYPE,\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} 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 * @return {void}\n */\nconst logoutEventHandler = (ee) => {\n // listen to the LOGOUT_EVENT_NAME when this is a private nsp\n ee.$on(LOGOUT_EVENT_NAME, function closeEvtHandler() {\n try {\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 socketEventHandler(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 // 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('Hear 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_TYPE:\n // this is handled error and we won't throw it\n // we need to extract the error from json\n log(`ERROR_TYPE`)\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 logoutEventHandler(ee)\n }\n}\n","// actually binding the event client to the socket client\n\n// from the jsonql-ws-client-core\nimport { clientEventHandler } from '../modules'\n// local \nimport { createNspAction } from './create-nsp-action'\nimport { loginEventHandler } from './login-event-handler'\nimport { socketEventHandler } from './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 // arguments for clientEventHandler\n const args = [opts, nspMap, ee, socketEventHandler]\n\n // now create the nsps\n const { namespaces } = nspMap\n const { token, log } = opts\n const { nsps } = createNspAction(opts, nspMap, token)\n args.push(nsps)\n // log(`argument length`, args.length, args)\n\n // binding the listeners - and it will listen to LOGOUT event\n // to unbind itself, and the above call will bind it again\n Reflect.apply(clientEventHandler, null, args)\n // setup listener for the login event\n if (opts.enableAuth) {\n loginEventHandler(ee, namespaces, nspMap, opts)\n }\n // return what input\n return { opts, nspMap, ee }\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\n\nimport { initWebSocketClient } from './init-websocket-client'\nimport createNsp from '../create-nsp'\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 const nspClient = initWebSocketClient(frameworkModule)\n const nspAuthClient = initWebSocketClient(frameworkModule, true)\n\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 opts.nspClient = nspClient\n opts.nspAuthClient = nspAuthClient \n // @1.0.7 remove later once everything fixed \n const { log } = opts\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;;;;;;;;;;;;;;;;;"} \ No newline at end of file +{"version":3,"file":"main.js","sources":["node_modules/_rollup-plugin-node-globals@1.4.0@rollup-plugin-node-globals/src/global.js","../../ws-client-core/node_modules/lodash-es/_arrayMap.js","../../ws-client-core/node_modules/lodash-es/isArray.js","../../ws-client-core/node_modules/lodash-es/_objectToString.js","../../ws-client-core/node_modules/lodash-es/isObjectLike.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-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/lodash-es/_overArg.js","../../ws-client-core/node_modules/lodash-es/_arrayFilter.js","../../ws-client-core/node_modules/lodash-es/_createBaseFor.js","../../ws-client-core/node_modules/lodash-es/_baseTimes.js","../../ws-client-core/node_modules/lodash-es/stubFalse.js","../../ws-client-core/node_modules/lodash-es/_isIndex.js","../../ws-client-core/node_modules/lodash-es/isLength.js","../../ws-client-core/node_modules/lodash-es/_baseUnary.js","../../ws-client-core/node_modules/lodash-es/_isPrototype.js","../../ws-client-core/node_modules/lodash-es/isObject.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/_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/_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/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/identity.js","../../ws-client-core/node_modules/lodash-es/_baseProperty.js","../../ws-client-core/node_modules/jsonql-params-validator/src/object.js","../../ws-client-core/node_modules/jsonql-errors/src/validation-error.js","../../ws-client-core/node_modules/jsonql-params-validator/src/validator.js","../../ws-client-core/node_modules/lodash-es/_copyArray.js","../../ws-client-core/node_modules/lodash-es/_safeGet.js","../../ws-client-core/node_modules/lodash-es/_nativeKeysIn.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/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-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-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/node_modules/jsonql-utils/src/generic.js","../../ws-client-core/node_modules/jsonql-errors/src/500-error.js","../../ws-client-core/node_modules/jsonql-errors/src/resolver-not-found-error.js","../../ws-client-core/node_modules/jsonql-errors/src/server-error.js","../../ws-client-core/node_modules/jsonql-utils/src/contract.js","../../ws-client-core/node_modules/jsonql-utils/src/namespace.js","../../ws-client-core/src/utils/helpers.js","../../ws-client-core/src/core/setup-auth-methods.js","../../ws-client-core/src/options/constants.js","../../ws-client-core/src/core/respond-handler.js","../../ws-client-core/src/core/action-call.js","../../ws-client-core/src/core/setup-send-method.js","../../ws-client-core/src/core/setup-resolver.js","../../ws-client-core/src/core/resolver-methods.js","../../ws-client-core/src/core/setup-intercom.js","../../ws-client-core/src/core/generator.js","../../ws-client-core/src/options/index.js","../../ws-client-core/src/api.js","../../ws-client-core/src/share/create-nsp-clients.js","../../ws-client-core/src/share/trigger-namespaces-on-error.js","../../ws-client-core/src/share/client-event-handler.js","src/options/index.js","src/core/create-websocket-binding/init-websocket-client.js","src/core/create-nsp/login-event-handler.js","node_modules/_lodash-es@4.17.15@lodash-es/isArray.js","node_modules/_lodash-es@4.17.15@lodash-es/_objectToString.js","node_modules/_lodash-es@4.17.15@lodash-es/isObjectLike.js","node_modules/_jsonql-utils@1.1.3@jsonql-utils/src/generic.js","node_modules/_jsonql-errors@1.1.10@jsonql-errors/src/validation-error.js","node_modules/_jsonql-utils@1.1.3@jsonql-utils/src/timestamp.js","node_modules/_jsonql-utils@1.1.3@jsonql-utils/src/params-api.js","node_modules/_jsonql-utils@1.1.3@jsonql-utils/src/socket.js","src/core/create-nsp/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":["export default (typeof global !== \"undefined\" ? global :\n typeof self !== \"undefined\" ? self :\n typeof window !== \"undefined\" ? window : {});\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 * 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 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 * 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 * 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","// 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\nexport const 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)`\nexport const PARAMS_NOT_ARRAY_ERR = `params is not an array! Did something gone wrong when you generate the contract.json?`\nexport const EXCEPTION_CASE_ERR = 'Could not understand your arguments and parameter structure!'\nexport const UNUSUAL_CASE_ERR = 'This is an unusual situation where the arguments are more than the params, but not mark as spread'\n\n// re-export\nimport * as JSONQL_CONSTANTS from 'jsonql-constants'\n// @TODO the jsdoc return array. and we should also allow array syntax\nexport const DEFAULT_TYPE = JSONQL_CONSTANTS.DEFAULT_TYPE\nexport const ARRAY_TYPE_LFT = JSONQL_CONSTANTS.ARRAY_TYPE_LFT\nexport const ARRAY_TYPE_RGT = JSONQL_CONSTANTS.ARRAY_TYPE_RGT\n\nexport const TYPE_KEY = JSONQL_CONSTANTS.TYPE_KEY\nexport const OPTIONAL_KEY = JSONQL_CONSTANTS.OPTIONAL_KEY\nexport const ENUM_KEY = JSONQL_CONSTANTS.ENUM_KEY\nexport const ARGS_KEY = JSONQL_CONSTANTS.ARGS_KEY\nexport const CHECKER_KEY = JSONQL_CONSTANTS.CHECKER_KEY\nexport const ALIAS_KEY = JSONQL_CONSTANTS.ALIAS_KEY\n\nexport const ARRAY_TYPE = JSONQL_CONSTANTS.ARRAY_TYPE\nexport const OBJECT_TYPE = JSONQL_CONSTANTS.OBJECT_TYPE\nexport const STRING_TYPE = JSONQL_CONSTANTS.STRING_TYPE\nexport const BOOLEAN_TYPE = JSONQL_CONSTANTS.BOOLEAN_TYPE\nexport const NUMBER_TYPE = JSONQL_CONSTANTS.NUMBER_TYPE\nexport const KEY_WORD = JSONQL_CONSTANTS.KEY_WORD\nexport const OR_SEPERATOR = JSONQL_CONSTANTS.OR_SEPERATOR\n\n// not actually in use\n// export const NUMBER_TYPES = JSONQL_CONSTANTS.NUMBER_TYPES;\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","/**\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 * 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 * 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 * 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","/**\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","/** 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","/** 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 * 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","/** 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 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","/**\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","/** 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","/** 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 * 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 * 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 * 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","// validate object type\n\nimport isPlainObject from 'lodash-es/isPlainObject'\nimport filter from 'lodash-es/filter'\n\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","// 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","// 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 // checkIsObject,\n combineFn,\n notEmpty\n} from './index'\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 // UNUSUAL_CASE_ERR\n} from './constants'\nimport { DATA_KEY, ERROR_KEY } from 'jsonql-constants'\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","/**\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","/**\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 * 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 * 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","/** 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","// 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","// 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'\n// PIA syntax\nexport const isObject = checkIsObject\nexport const isAny = checkIsAny\nexport const isString = checkIsString\nexport const isBoolean = checkIsBoolean\nexport const isNumber = checkIsNumber\nexport const isArray = checkIsArray\nexport const isNotEmpty = notEmpty\n\nimport * as validator from './src/validator'\n\nexport const normalizeArgs = validator.normalizeArgs\nexport const validateSync = validator.validateSync\nexport const validateAsync = validator.validateAsync\n\n// configuration checking\n\nimport * as jsonqlOptions from './src/options'\n\nexport const JSONQL_PARAMS_VALIDATOR_INFO = jsonqlOptions.JSONQL_PARAMS_VALIDATOR_INFO\n\nexport const createConfig = jsonqlOptions.createConfig\nexport const constructConfig = jsonqlOptions.constructConfigFn\n// construct the final output 1.5.2\nexport const checkConfigAsync = jsonqlOptions.getCheckConfigAsync(validator.validateSync)\nexport const checkConfig = jsonqlOptions.getCheckConfig(validator.validateSync)\n\n// export the two extra functions\nimport isInArray from './src/is-in-array'\nimport isObjectHasKeyFn from './src/is-key-in-object'\n\nexport const inArray = isInArray\nexport const isObjectHasKey = isObjectHasKeyFn\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","// 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","/**\n * This is a custom error to throw when server throw a 500\n * This help us to capture the right error, due to the call happens in sequence\n * @param {string} message to tell what happen\n * @param {mixed} extra things we want to add, 500?\n */\nexport default class Jsonql500Error extends Error {\n constructor(...args) {\n super(...args)\n\n this.message = args[0]\n this.detail = args[1]\n\n this.className = Jsonql500Error.name;\n\n if (Error.captureStackTrace) {\n Error.captureStackTrace(this, Jsonql500Error)\n }\n }\n\n static get statusCode() {\n return 500;\n }\n\n static get name() {\n return 'Jsonql500Error';\n }\n\n}\n","/**\n * This is a custom error to throw when could not find the resolver\n * This help us to capture the right error, due to the call happens in sequence\n * @param {string} message to tell what happen\n * @param {mixed} extra things we want to add, 500?\n */\nexport default class JsonqlResolverNotFoundError extends Error {\n constructor(...args) {\n super(...args)\n\n this.message = args[0]\n this.detail = args[1]\n\n this.className = JsonqlResolverNotFoundError.name;\n\n if (Error.captureStackTrace) {\n Error.captureStackTrace(this, JsonqlResolverNotFoundError);\n }\n }\n\n static get statusCode() {\n return 404;\n }\n\n static get name() {\n return 'JsonqlResolverNotFoundError';\n }\n}\n","// this is from an example from Koa team to use for internal middleware ctx.throw\n// but after the test the res.body part is unable to extract the required data\n// I keep this one here for future reference\n\nexport default class JsonqlServerError extends Error {\n\n constructor(statusCode, message) {\n super(message)\n this.statusCode = statusCode;\n this.className = JsonqlServerError.name;\n }\n\n static get name() {\n return 'JsonqlServerError';\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","// 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.publicNamespace ].join('/'),\n [ base , config.privateNamespace ].join('/')\n ]\n }\n return [ base ]\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","// 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(client, resolverName, setupResolver(namespace, resolverName, params, fn, ee, log))\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 createNamespaceErrorHandler(client, opts, ee, nspGroup) {\n return [\n // using the onError as name\n // @TODO we should follow the convention earlier\n // make this a setter for the clientitself\n objDefineProps(client, ON_ERROR_FN_NAME, 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 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 createOnReadyHandler(client, opts, ee) {\n return [\n objDefineProps(client, ON_READY_FN_NAME, 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 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} ","// 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 createNamespaceErrorHandler,\n createOnReadyHandler\n} from './resolver-methods'\nimport {\n setupFinalStep \n} from './setup-final-step'\nimport {\n NSP_GROUP\n} from 'jsonql-constants'\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 generator(opts, nspMap, ee) {\n\n let args = [\n generateResolvers,\n createNamespaceErrorHandler,\n createOnReadyHandler\n ]\n if (opts.enableAuth) {\n args.push(\n createAuthMethods\n )\n } \n // we will always get back the [ obj, opts, ee ]\n // then we only return the obj (wsClient)\n args.push(setupFinalStep)\n // run it\n const fn = Reflect.apply(chainFns, null, args)\n\n return fn(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 { generator } from './core'\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} frameworkSocketEngine \n * @param {object} config the already checked config \n */\nexport function wsClientCoreAction(frameworkSocketEngine, config) {\n return postCheckInjectOpts(config)\n // the following two moved to wsPostConfig\n .then(createRequiredParams)\n .then(\n ({opts, nspMap, ee}) => frameworkSocketEngine(opts, nspMap, ee)\n )\n .then(\n ({opts, nspMap, ee}) => generator(opts, nspMap, ee)\n )\n .catch(err => {\n console.error(`jsonql-ws-core-client init error`, err)\n })\n}\n\n/**\n * The main interface which will generate the socket clients and map all events\n * @param {object} frameworkSocketEngine 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(frameworkSocketEngine, configCheckMap = {}, constProps = {}) {\n // we need to inject property to this client later\n return (config = {}) => checkConfiguration(config, configCheckMap, constProps)\n .then(opts => wsClientCoreAction(frameworkSocketEngine, opts))\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 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}","// 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\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, SOCKET_IO, DISCONNECTED_ERROR_MSG } from '../options/constants'\nimport { createEvt, clearMainEmitEvt } from '../utils'\nimport { triggerNamespacesOnError } from './trigger-namespaces-on-error'\n\n/**\n * A Event handler 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 */\nconst notLoginWsHandler = (namespace, ee, opts) => {\n const { log } = opts \n ee.$only(\n createEvt(namespace, EMIT_EVT),\n function notLoginHandlerCallback(resolverName, args) {\n log('[notLoginHandler] hijack the ws call', namespace, resolverName, args)\n const error = {\n message: NOT_LOGIN_ERR_MSG\n }\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 handler, but wrap inside the error key\n ee.$call(createEvt(namespace, resolverName, ON_RESULT_FN_NAME), [{ error }])\n }\n )\n}\n\n/**\n * A Event handler 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 */\nconst disconnectedHandler = (namespace, ee, opts) => {\n const { log } = opts \n ee.$only(\n createEvt(namespace, EMIT_EVT),\n function disconnectedHandlerCallback(resolverName, args) {\n log(`[disconnectedHandler] 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 handler, but wrap inside the error key\n ee.$call(createEvt(namespace, resolverName, ON_RESULT_FN_NAME), [{ error }])\n }\n )\n}\n\n/**\n * get the private namespace\n * @param {array} namespaces array\n * @return {*} string on success\n */\nconst getPrivateNamespace = (namespaces) => (\n namespaces.length > 1 ? namespaces[0] : false\n)\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 */\nconst logoutEvtHandler = (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(LOGOUT_EVENT_NAME, function logoutEvtHandlerAction() {\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 handler\n triggerNamespacesOnError(ee, [privateNamespace], LOGOUT_EVENT_NAME)\n // rebind all of the handler 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 notLoginWsHandler(privateNamespace, ee, opts)\n })\n}\n\n/**\n * The disconnect event handler, 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 */\nconst disconnectHandler = (nsps, namespaces, ee, opts) => {\n const { log } = opts \n ee.$on(DISCONNECT_EVENT_NAME, function disconnectEvtHandler() {\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 disconnectedHandler(namespace, ee, opts)\n })\n })\n}\n\n/**\n * centralize all the comm in one place\n * @param {object} opts configuration\n * @param {object} nspMap this is not in the opts \n * @param {object} ee Event Emitter instance\n * @param {function} bindWsHandler binding the ee to ws --> this is the core bit\n * @param {object} nsps namespaced nsp\n * @return {void} nothing\n */\nexport function clientEventHandler(opts, nspMap, ee, bindSocketEventHandler, nsps) {\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 let isPrivate = false\n let hasPrivate = false\n // loop\n // @BUG for io this has to be in order the one with auth need to get call first\n // The order of login is very import we need to run in order here to make sure\n // one is execute then the other\n namespaces.forEach(namespace => {\n isPrivate = privateNamespace === namespace\n if (!hasPrivate) {\n hasPrivate = isPrivate\n }\n // log(namespace, ' --> nsps --> ', nsps[namespace])\n if (nsps[namespace]) {\n\n log('[call bindWsHandler]', isPrivate, namespace)\n let args = [namespace, nsps[namespace], ee, isPrivate, opts]\n \n if (opts.serverType === SOCKET_IO) {\n let { nspGroup } = nspMap\n args.push(nspGroup[namespace])\n }\n Reflect.apply(bindSocketEventHandler, null, args)\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 notLoginWsHandler(namespace, ee, opts)\n }\n })\n // logout event handler \n if (hasPrivate) {\n log(`Has private and add logoutEvtHandler`)\n logoutEvtHandler(nsps, namespaces, ee, opts)\n }\n // finally the disconnect event handlers\n disconnectHandler(nsps, namespaces, ee, opts) \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'\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 * @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 */\nfunction initWebSocketClient(WebSocket, auth = false) {\n if (auth === false) {\n return function createWsClient(url) {\n return new WebSocket(fixWss(url))\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 * @return {object} ws instance\n */\n return function createWsAuthClient(url, token) {\n const ws_url = fixWss(url)\n // console.log('what happen here?', url, ws_url, token)\n const uri = token && typeof token === 'string' ? `${ws_url}?${TOKEN_PARAM_NAME}=${token}` : ws_url\n try {\n return new WebSocket(uri)\n } catch(e) {\n console.error('WebSocket Connection Error', e)\n return false\n }\n }\n}\n\nexport { initWebSocketClient }","// @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}","/**\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 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 * 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","// 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'\nimport JsonqlValidationError from 'jsonql-errors/src/validation-error'\n\nimport isArray from 'lodash-es/isArray'\nimport isPlainObject from 'lodash-es/isPlainObject'\nimport isString from 'lodash-es/isString'\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 * Get name from the payload (ported back from jsonql-koa)\n * @param {*} payload to extract from\n * @return {string} name\n */\nexport function getNameFromPayload(payload) {\n console.error(`This method is going to be deprectead in the next release, please use getResolverFromPayload instead`)\n return Object.keys(payload)[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' \n\nconst WS_KEYS = [\n WS_REPLY_TYPE,\n WS_EVT_NAME,\n WS_DATA_NAME\n]\nimport isString from 'lodash-es/isString'\nimport { toJson, isFunc, isObjectHasKey, nil } from './generic'\nimport { timestamp } from './timestamp'\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 can not decoded', 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_TYPE,\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} 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 * @return {void}\n */\nconst logoutEventHandler = (ee) => {\n // listen to the LOGOUT_EVENT_NAME when this is a private nsp\n ee.$on(LOGOUT_EVENT_NAME, function closeEvtHandler() {\n try {\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 socketEventHandler(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_TYPE:\n // this is handled error and we won't throw it\n // we need to extract the error from json\n log(`ERROR_TYPE`)\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 logoutEventHandler(ee)\n }\n}\n","// actually binding the event client to the socket client\n\n// from the jsonql-ws-client-core\nimport { clientEventHandler } from '../modules'\n// local \nimport { createNspAction } from './create-nsp-action'\nimport { loginEventHandler } from './login-event-handler'\nimport { socketEventHandler } from './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 // arguments for clientEventHandler\n const args = [opts, nspMap, ee, socketEventHandler]\n\n // now create the nsps\n const { namespaces } = nspMap\n const { token, log } = opts\n const { nsps } = createNspAction(opts, nspMap, token)\n args.push(nsps)\n // log(`argument length`, args.length, args)\n\n // binding the listeners - and it will listen to LOGOUT event\n // to unbind itself, and the above call will bind it again\n Reflect.apply(clientEventHandler, null, args)\n // setup listener for the login event\n if (opts.enableAuth) {\n loginEventHandler(ee, namespaces, nspMap, opts)\n }\n // return what input\n return { opts, nspMap, ee }\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\n\nimport { initWebSocketClient } from './init-websocket-client'\nimport createNsp from '../create-nsp'\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 const nspClient = initWebSocketClient(frameworkModule)\n const nspAuthClient = initWebSocketClient(frameworkModule, true)\n\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 opts.nspClient = nspClient\n opts.nspAuthClient = nspAuthClient \n // @1.0.7 remove later once everything fixed \n const { log } = opts\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;;;;;;;;;;;;;;;;;"} \ No newline at end of file diff --git a/packages/@jsonql/ws/tests/ws-client-chain.test.js b/packages/@jsonql/ws/tests/ws-client-chain.test.js index 91371f18..c2f7a850 100644 --- a/packages/@jsonql/ws/tests/ws-client-chain.test.js +++ b/packages/@jsonql/ws/tests/ws-client-chain.test.js @@ -3,12 +3,12 @@ const test = require('ava') const { join } = require('path') const fsx = require('fs-extra') const { chainPromises } = require('jsonql-utils') -const { createFrameworkDepClient } = require('../src/core/create-framework-dep-client') +const { initWebSocketClient } = require('../src/core/create-websocket-binding/init-websocket-client') const WebSocket = require('ws') -const wsNodeAuthClient = createFrameworkDepClient(WebSocket, true) -const wsNodeClient = createFrameworkDepClient(WebSocket) +const wsNodeAuthClient = initWebSocketClient(WebSocket, true) +const wsNodeClient = initWebSocketClient(WebSocket) const serverSetup = require('./fixtures/server-setup') const genToken = require('./fixtures/token') -- Gitee From dde9cc5c9221a8b5e1feb407ce7c358da5c8c75f Mon Sep 17 00:00:00 2001 From: joelchu Date: Sat, 14 Mar 2020 08:46:06 +0800 Subject: [PATCH 41/45] update the login handler call params inside the create-nsp --- packages/@jsonql/ws/package.json | 1 - packages/@jsonql/ws/src/core/create-nsp/create-nsp.js | 2 +- packages/@jsonql/ws/tests/ws-client-auth.test.js | 5 ++++- 3 files changed, 5 insertions(+), 3 deletions(-) diff --git a/packages/@jsonql/ws/package.json b/packages/@jsonql/ws/package.json index e8f73ff8..ae117b25 100644 --- a/packages/@jsonql/ws/package.json +++ b/packages/@jsonql/ws/package.json @@ -30,7 +30,6 @@ "test:opt": "ava ./tests/opt.test.js", "test:basic": "npm run build:cjs && DEBUG=jsonql-ws-* ava ./tests/ws-client-basic.test.js", "test:auth": "npm run build:cjs && DEBUG=jsonql-ws-client* ava ./tests/ws-client-auth.test.js", - "test:auth:debug": "JSONQL_DEBUG=0 DEBUG=jsonql-ws-client* ava ./tests/ws-client-auth.test.js", "test:login": "npm run build:cjs && DEBUG=jsonql-ws* ava ./tests/ws-client-auth-login.test.js", "test:chain": "npm run build:cjs && DEBUG=jsonql-ws-client* ava ./tests/ws-client-chain.test.js", "test:int": "npm run build:cjs && DEBUG=jsonql-ws-client* ava ./tests/integration.test.js", 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 636c7dc8..90c01c49 100644 --- a/packages/@jsonql/ws/src/core/create-nsp/create-nsp.js +++ b/packages/@jsonql/ws/src/core/create-nsp/create-nsp.js @@ -30,7 +30,7 @@ function createNsp(opts, nspMap, ee) { Reflect.apply(clientEventHandler, null, args) // setup listener for the login event if (opts.enableAuth) { - loginEventHandler(ee, namespaces, nspMap, opts) + loginEventHandler(opts, nspMap, ee) } // return what input return { opts, nspMap, ee } diff --git a/packages/@jsonql/ws/tests/ws-client-auth.test.js b/packages/@jsonql/ws/tests/ws-client-auth.test.js index 74da2ce3..0a6f15ac 100644 --- a/packages/@jsonql/ws/tests/ws-client-auth.test.js +++ b/packages/@jsonql/ws/tests/ws-client-auth.test.js @@ -23,7 +23,7 @@ const port = 8002 test.before(async t => { - const { io, app } = await serverSetup({ + const { app } = await serverSetup({ contract, contractDir, resolverDir: join(__dirname, 'fixtures', 'resolvers'), @@ -68,6 +68,9 @@ test.serial.cb(`Should able to handle multiple onMessage and one onLogin callbac t.pass() t.end() } + + // we need to trigger the login + }) -- Gitee From f1e9061a883199732966fa5e4522f00f8896e787 Mon Sep 17 00:00:00 2001 From: joelchu Date: Sat, 14 Mar 2020 09:46:15 +0800 Subject: [PATCH 42/45] commit the changes first and go back to sort out the server side features become continue on the client --- packages/@jsonql/ws/main.js | 2 +- packages/@jsonql/ws/main.js.map | 2 +- .../@jsonql/ws/src/core/create-nsp/create-nsp.js | 3 +-- packages/@jsonql/ws/tests/ws-client-auth.test.js | 16 ++++++++++------ 4 files changed, 13 insertions(+), 10 deletions(-) diff --git a/packages/@jsonql/ws/main.js b/packages/@jsonql/ws/main.js index f06bfe14..4c85dd9e 100644 --- a/packages/@jsonql/ws/main.js +++ b/packages/@jsonql/ws/main.js @@ -8551,7 +8551,7 @@ function createNsp(opts, nspMap, ee) { Reflect.apply(clientEventHandler$1, null, args); // setup listener for the login event if (opts.enableAuth) { - loginEventHandler(ee, namespaces, nspMap); + loginEventHandler(opts, nspMap, ee); } // return what input return { opts: opts, nspMap: nspMap, ee: ee } diff --git a/packages/@jsonql/ws/main.js.map b/packages/@jsonql/ws/main.js.map index 360cdf46..05598d39 100644 --- a/packages/@jsonql/ws/main.js.map +++ b/packages/@jsonql/ws/main.js.map @@ -1 +1 @@ -{"version":3,"file":"main.js","sources":["node_modules/_rollup-plugin-node-globals@1.4.0@rollup-plugin-node-globals/src/global.js","../../ws-client-core/node_modules/lodash-es/_arrayMap.js","../../ws-client-core/node_modules/lodash-es/isArray.js","../../ws-client-core/node_modules/lodash-es/_objectToString.js","../../ws-client-core/node_modules/lodash-es/isObjectLike.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-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/lodash-es/_overArg.js","../../ws-client-core/node_modules/lodash-es/_arrayFilter.js","../../ws-client-core/node_modules/lodash-es/_createBaseFor.js","../../ws-client-core/node_modules/lodash-es/_baseTimes.js","../../ws-client-core/node_modules/lodash-es/stubFalse.js","../../ws-client-core/node_modules/lodash-es/_isIndex.js","../../ws-client-core/node_modules/lodash-es/isLength.js","../../ws-client-core/node_modules/lodash-es/_baseUnary.js","../../ws-client-core/node_modules/lodash-es/_isPrototype.js","../../ws-client-core/node_modules/lodash-es/isObject.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/_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/_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/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/identity.js","../../ws-client-core/node_modules/lodash-es/_baseProperty.js","../../ws-client-core/node_modules/jsonql-params-validator/src/object.js","../../ws-client-core/node_modules/jsonql-errors/src/validation-error.js","../../ws-client-core/node_modules/jsonql-params-validator/src/validator.js","../../ws-client-core/node_modules/lodash-es/_copyArray.js","../../ws-client-core/node_modules/lodash-es/_safeGet.js","../../ws-client-core/node_modules/lodash-es/_nativeKeysIn.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/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-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-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/node_modules/jsonql-utils/src/generic.js","../../ws-client-core/node_modules/jsonql-errors/src/500-error.js","../../ws-client-core/node_modules/jsonql-errors/src/resolver-not-found-error.js","../../ws-client-core/node_modules/jsonql-errors/src/server-error.js","../../ws-client-core/node_modules/jsonql-utils/src/contract.js","../../ws-client-core/node_modules/jsonql-utils/src/namespace.js","../../ws-client-core/src/utils/helpers.js","../../ws-client-core/src/core/setup-auth-methods.js","../../ws-client-core/src/options/constants.js","../../ws-client-core/src/core/respond-handler.js","../../ws-client-core/src/core/action-call.js","../../ws-client-core/src/core/setup-send-method.js","../../ws-client-core/src/core/setup-resolver.js","../../ws-client-core/src/core/resolver-methods.js","../../ws-client-core/src/core/setup-intercom.js","../../ws-client-core/src/core/generator.js","../../ws-client-core/src/options/index.js","../../ws-client-core/src/api.js","../../ws-client-core/src/share/create-nsp-clients.js","../../ws-client-core/src/share/trigger-namespaces-on-error.js","../../ws-client-core/src/share/client-event-handler.js","src/options/index.js","src/core/create-websocket-binding/init-websocket-client.js","src/core/create-nsp/login-event-handler.js","node_modules/_lodash-es@4.17.15@lodash-es/isArray.js","node_modules/_lodash-es@4.17.15@lodash-es/_objectToString.js","node_modules/_lodash-es@4.17.15@lodash-es/isObjectLike.js","node_modules/_jsonql-utils@1.1.3@jsonql-utils/src/generic.js","node_modules/_jsonql-errors@1.1.10@jsonql-errors/src/validation-error.js","node_modules/_jsonql-utils@1.1.3@jsonql-utils/src/timestamp.js","node_modules/_jsonql-utils@1.1.3@jsonql-utils/src/params-api.js","node_modules/_jsonql-utils@1.1.3@jsonql-utils/src/socket.js","src/core/create-nsp/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":["export default (typeof global !== \"undefined\" ? global :\n typeof self !== \"undefined\" ? self :\n typeof window !== \"undefined\" ? window : {});\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 * 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 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 * 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 * 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","// 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\nexport const 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)`\nexport const PARAMS_NOT_ARRAY_ERR = `params is not an array! Did something gone wrong when you generate the contract.json?`\nexport const EXCEPTION_CASE_ERR = 'Could not understand your arguments and parameter structure!'\nexport const UNUSUAL_CASE_ERR = 'This is an unusual situation where the arguments are more than the params, but not mark as spread'\n\n// re-export\nimport * as JSONQL_CONSTANTS from 'jsonql-constants'\n// @TODO the jsdoc return array. and we should also allow array syntax\nexport const DEFAULT_TYPE = JSONQL_CONSTANTS.DEFAULT_TYPE\nexport const ARRAY_TYPE_LFT = JSONQL_CONSTANTS.ARRAY_TYPE_LFT\nexport const ARRAY_TYPE_RGT = JSONQL_CONSTANTS.ARRAY_TYPE_RGT\n\nexport const TYPE_KEY = JSONQL_CONSTANTS.TYPE_KEY\nexport const OPTIONAL_KEY = JSONQL_CONSTANTS.OPTIONAL_KEY\nexport const ENUM_KEY = JSONQL_CONSTANTS.ENUM_KEY\nexport const ARGS_KEY = JSONQL_CONSTANTS.ARGS_KEY\nexport const CHECKER_KEY = JSONQL_CONSTANTS.CHECKER_KEY\nexport const ALIAS_KEY = JSONQL_CONSTANTS.ALIAS_KEY\n\nexport const ARRAY_TYPE = JSONQL_CONSTANTS.ARRAY_TYPE\nexport const OBJECT_TYPE = JSONQL_CONSTANTS.OBJECT_TYPE\nexport const STRING_TYPE = JSONQL_CONSTANTS.STRING_TYPE\nexport const BOOLEAN_TYPE = JSONQL_CONSTANTS.BOOLEAN_TYPE\nexport const NUMBER_TYPE = JSONQL_CONSTANTS.NUMBER_TYPE\nexport const KEY_WORD = JSONQL_CONSTANTS.KEY_WORD\nexport const OR_SEPERATOR = JSONQL_CONSTANTS.OR_SEPERATOR\n\n// not actually in use\n// export const NUMBER_TYPES = JSONQL_CONSTANTS.NUMBER_TYPES;\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","/**\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 * 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 * 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 * 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","/**\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","/** 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","/** 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 * 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","/** 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 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","/**\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","/** 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","/** 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 * 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 * 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 * 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","// validate object type\n\nimport isPlainObject from 'lodash-es/isPlainObject'\nimport filter from 'lodash-es/filter'\n\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","// 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","// 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 // checkIsObject,\n combineFn,\n notEmpty\n} from './index'\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 // UNUSUAL_CASE_ERR\n} from './constants'\nimport { DATA_KEY, ERROR_KEY } from 'jsonql-constants'\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","/**\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","/**\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 * 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 * 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","/** 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","// 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","// 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'\n// PIA syntax\nexport const isObject = checkIsObject\nexport const isAny = checkIsAny\nexport const isString = checkIsString\nexport const isBoolean = checkIsBoolean\nexport const isNumber = checkIsNumber\nexport const isArray = checkIsArray\nexport const isNotEmpty = notEmpty\n\nimport * as validator from './src/validator'\n\nexport const normalizeArgs = validator.normalizeArgs\nexport const validateSync = validator.validateSync\nexport const validateAsync = validator.validateAsync\n\n// configuration checking\n\nimport * as jsonqlOptions from './src/options'\n\nexport const JSONQL_PARAMS_VALIDATOR_INFO = jsonqlOptions.JSONQL_PARAMS_VALIDATOR_INFO\n\nexport const createConfig = jsonqlOptions.createConfig\nexport const constructConfig = jsonqlOptions.constructConfigFn\n// construct the final output 1.5.2\nexport const checkConfigAsync = jsonqlOptions.getCheckConfigAsync(validator.validateSync)\nexport const checkConfig = jsonqlOptions.getCheckConfig(validator.validateSync)\n\n// export the two extra functions\nimport isInArray from './src/is-in-array'\nimport isObjectHasKeyFn from './src/is-key-in-object'\n\nexport const inArray = isInArray\nexport const isObjectHasKey = isObjectHasKeyFn\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","// 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","/**\n * This is a custom error to throw when server throw a 500\n * This help us to capture the right error, due to the call happens in sequence\n * @param {string} message to tell what happen\n * @param {mixed} extra things we want to add, 500?\n */\nexport default class Jsonql500Error extends Error {\n constructor(...args) {\n super(...args)\n\n this.message = args[0]\n this.detail = args[1]\n\n this.className = Jsonql500Error.name;\n\n if (Error.captureStackTrace) {\n Error.captureStackTrace(this, Jsonql500Error)\n }\n }\n\n static get statusCode() {\n return 500;\n }\n\n static get name() {\n return 'Jsonql500Error';\n }\n\n}\n","/**\n * This is a custom error to throw when could not find the resolver\n * This help us to capture the right error, due to the call happens in sequence\n * @param {string} message to tell what happen\n * @param {mixed} extra things we want to add, 500?\n */\nexport default class JsonqlResolverNotFoundError extends Error {\n constructor(...args) {\n super(...args)\n\n this.message = args[0]\n this.detail = args[1]\n\n this.className = JsonqlResolverNotFoundError.name;\n\n if (Error.captureStackTrace) {\n Error.captureStackTrace(this, JsonqlResolverNotFoundError);\n }\n }\n\n static get statusCode() {\n return 404;\n }\n\n static get name() {\n return 'JsonqlResolverNotFoundError';\n }\n}\n","// this is from an example from Koa team to use for internal middleware ctx.throw\n// but after the test the res.body part is unable to extract the required data\n// I keep this one here for future reference\n\nexport default class JsonqlServerError extends Error {\n\n constructor(statusCode, message) {\n super(message)\n this.statusCode = statusCode;\n this.className = JsonqlServerError.name;\n }\n\n static get name() {\n return 'JsonqlServerError';\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","// 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.publicNamespace ].join('/'),\n [ base , config.privateNamespace ].join('/')\n ]\n }\n return [ base ]\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","// 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(client, resolverName, setupResolver(namespace, resolverName, params, fn, ee, log))\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 createNamespaceErrorHandler(client, opts, ee, nspGroup) {\n return [\n // using the onError as name\n // @TODO we should follow the convention earlier\n // make this a setter for the clientitself\n objDefineProps(client, ON_ERROR_FN_NAME, 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 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 createOnReadyHandler(client, opts, ee) {\n return [\n objDefineProps(client, ON_READY_FN_NAME, 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 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} ","// 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 createNamespaceErrorHandler,\n createOnReadyHandler\n} from './resolver-methods'\nimport {\n setupFinalStep \n} from './setup-final-step'\nimport {\n NSP_GROUP\n} from 'jsonql-constants'\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 generator(opts, nspMap, ee) {\n\n let args = [\n generateResolvers,\n createNamespaceErrorHandler,\n createOnReadyHandler\n ]\n if (opts.enableAuth) {\n args.push(\n createAuthMethods\n )\n } \n // we will always get back the [ obj, opts, ee ]\n // then we only return the obj (wsClient)\n args.push(setupFinalStep)\n // run it\n const fn = Reflect.apply(chainFns, null, args)\n\n return fn(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 { generator } from './core'\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} frameworkSocketEngine \n * @param {object} config the already checked config \n */\nexport function wsClientCoreAction(frameworkSocketEngine, config) {\n return postCheckInjectOpts(config)\n // the following two moved to wsPostConfig\n .then(createRequiredParams)\n .then(\n ({opts, nspMap, ee}) => frameworkSocketEngine(opts, nspMap, ee)\n )\n .then(\n ({opts, nspMap, ee}) => generator(opts, nspMap, ee)\n )\n .catch(err => {\n console.error(`jsonql-ws-core-client init error`, err)\n })\n}\n\n/**\n * The main interface which will generate the socket clients and map all events\n * @param {object} frameworkSocketEngine 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(frameworkSocketEngine, configCheckMap = {}, constProps = {}) {\n // we need to inject property to this client later\n return (config = {}) => checkConfiguration(config, configCheckMap, constProps)\n .then(opts => wsClientCoreAction(frameworkSocketEngine, opts))\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 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}","// 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\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, SOCKET_IO, DISCONNECTED_ERROR_MSG } from '../options/constants'\nimport { createEvt, clearMainEmitEvt } from '../utils'\nimport { triggerNamespacesOnError } from './trigger-namespaces-on-error'\n\n/**\n * A Event handler 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 */\nconst notLoginWsHandler = (namespace, ee, opts) => {\n const { log } = opts \n ee.$only(\n createEvt(namespace, EMIT_EVT),\n function notLoginHandlerCallback(resolverName, args) {\n log('[notLoginHandler] hijack the ws call', namespace, resolverName, args)\n const error = {\n message: NOT_LOGIN_ERR_MSG\n }\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 handler, but wrap inside the error key\n ee.$call(createEvt(namespace, resolverName, ON_RESULT_FN_NAME), [{ error }])\n }\n )\n}\n\n/**\n * A Event handler 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 */\nconst disconnectedHandler = (namespace, ee, opts) => {\n const { log } = opts \n ee.$only(\n createEvt(namespace, EMIT_EVT),\n function disconnectedHandlerCallback(resolverName, args) {\n log(`[disconnectedHandler] 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 handler, but wrap inside the error key\n ee.$call(createEvt(namespace, resolverName, ON_RESULT_FN_NAME), [{ error }])\n }\n )\n}\n\n/**\n * get the private namespace\n * @param {array} namespaces array\n * @return {*} string on success\n */\nconst getPrivateNamespace = (namespaces) => (\n namespaces.length > 1 ? namespaces[0] : false\n)\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 */\nconst logoutEvtHandler = (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(LOGOUT_EVENT_NAME, function logoutEvtHandlerAction() {\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 handler\n triggerNamespacesOnError(ee, [privateNamespace], LOGOUT_EVENT_NAME)\n // rebind all of the handler 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 notLoginWsHandler(privateNamespace, ee, opts)\n })\n}\n\n/**\n * The disconnect event handler, 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 */\nconst disconnectHandler = (nsps, namespaces, ee, opts) => {\n const { log } = opts \n ee.$on(DISCONNECT_EVENT_NAME, function disconnectEvtHandler() {\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 disconnectedHandler(namespace, ee, opts)\n })\n })\n}\n\n/**\n * centralize all the comm in one place\n * @param {object} opts configuration\n * @param {object} nspMap this is not in the opts \n * @param {object} ee Event Emitter instance\n * @param {function} bindWsHandler binding the ee to ws --> this is the core bit\n * @param {object} nsps namespaced nsp\n * @return {void} nothing\n */\nexport function clientEventHandler(opts, nspMap, ee, bindSocketEventHandler, nsps) {\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 let isPrivate = false\n let hasPrivate = false\n // loop\n // @BUG for io this has to be in order the one with auth need to get call first\n // The order of login is very import we need to run in order here to make sure\n // one is execute then the other\n namespaces.forEach(namespace => {\n isPrivate = privateNamespace === namespace\n if (!hasPrivate) {\n hasPrivate = isPrivate\n }\n // log(namespace, ' --> nsps --> ', nsps[namespace])\n if (nsps[namespace]) {\n\n log('[call bindWsHandler]', isPrivate, namespace)\n let args = [namespace, nsps[namespace], ee, isPrivate, opts]\n \n if (opts.serverType === SOCKET_IO) {\n let { nspGroup } = nspMap\n args.push(nspGroup[namespace])\n }\n Reflect.apply(bindSocketEventHandler, null, args)\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 notLoginWsHandler(namespace, ee, opts)\n }\n })\n // logout event handler \n if (hasPrivate) {\n log(`Has private and add logoutEvtHandler`)\n logoutEvtHandler(nsps, namespaces, ee, opts)\n }\n // finally the disconnect event handlers\n disconnectHandler(nsps, namespaces, ee, opts) \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'\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 * @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 */\nfunction initWebSocketClient(WebSocket, auth = false) {\n if (auth === false) {\n return function createWsClient(url) {\n return new WebSocket(fixWss(url))\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 * @return {object} ws instance\n */\n return function createWsAuthClient(url, token) {\n const ws_url = fixWss(url)\n // console.log('what happen here?', url, ws_url, token)\n const uri = token && typeof token === 'string' ? `${ws_url}?${TOKEN_PARAM_NAME}=${token}` : ws_url\n try {\n return new WebSocket(uri)\n } catch(e) {\n console.error('WebSocket Connection Error', e)\n return false\n }\n }\n}\n\nexport { initWebSocketClient }","// @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}","/**\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 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 * 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","// 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'\nimport JsonqlValidationError from 'jsonql-errors/src/validation-error'\n\nimport isArray from 'lodash-es/isArray'\nimport isPlainObject from 'lodash-es/isPlainObject'\nimport isString from 'lodash-es/isString'\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 * Get name from the payload (ported back from jsonql-koa)\n * @param {*} payload to extract from\n * @return {string} name\n */\nexport function getNameFromPayload(payload) {\n console.error(`This method is going to be deprectead in the next release, please use getResolverFromPayload instead`)\n return Object.keys(payload)[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' \n\nconst WS_KEYS = [\n WS_REPLY_TYPE,\n WS_EVT_NAME,\n WS_DATA_NAME\n]\nimport isString from 'lodash-es/isString'\nimport { toJson, isFunc, isObjectHasKey, nil } from './generic'\nimport { timestamp } from './timestamp'\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 can not decoded', 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_TYPE,\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} 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 * @return {void}\n */\nconst logoutEventHandler = (ee) => {\n // listen to the LOGOUT_EVENT_NAME when this is a private nsp\n ee.$on(LOGOUT_EVENT_NAME, function closeEvtHandler() {\n try {\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 socketEventHandler(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_TYPE:\n // this is handled error and we won't throw it\n // we need to extract the error from json\n log(`ERROR_TYPE`)\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 logoutEventHandler(ee)\n }\n}\n","// actually binding the event client to the socket client\n\n// from the jsonql-ws-client-core\nimport { clientEventHandler } from '../modules'\n// local \nimport { createNspAction } from './create-nsp-action'\nimport { loginEventHandler } from './login-event-handler'\nimport { socketEventHandler } from './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 // arguments for clientEventHandler\n const args = [opts, nspMap, ee, socketEventHandler]\n\n // now create the nsps\n const { namespaces } = nspMap\n const { token, log } = opts\n const { nsps } = createNspAction(opts, nspMap, token)\n args.push(nsps)\n // log(`argument length`, args.length, args)\n\n // binding the listeners - and it will listen to LOGOUT event\n // to unbind itself, and the above call will bind it again\n Reflect.apply(clientEventHandler, null, args)\n // setup listener for the login event\n if (opts.enableAuth) {\n loginEventHandler(ee, namespaces, nspMap, opts)\n }\n // return what input\n return { opts, nspMap, ee }\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\n\nimport { initWebSocketClient } from './init-websocket-client'\nimport createNsp from '../create-nsp'\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 const nspClient = initWebSocketClient(frameworkModule)\n const nspAuthClient = initWebSocketClient(frameworkModule, true)\n\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 opts.nspClient = nspClient\n opts.nspAuthClient = nspAuthClient \n // @1.0.7 remove later once everything fixed \n const { log } = opts\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;;;;;;;;;;;;;;;;;"} \ No newline at end of file +{"version":3,"file":"main.js","sources":["node_modules/_rollup-plugin-node-globals@1.4.0@rollup-plugin-node-globals/src/global.js","../../ws-client-core/node_modules/lodash-es/_arrayMap.js","../../ws-client-core/node_modules/lodash-es/isArray.js","../../ws-client-core/node_modules/lodash-es/_objectToString.js","../../ws-client-core/node_modules/lodash-es/isObjectLike.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-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/lodash-es/_overArg.js","../../ws-client-core/node_modules/lodash-es/_arrayFilter.js","../../ws-client-core/node_modules/lodash-es/_createBaseFor.js","../../ws-client-core/node_modules/lodash-es/_baseTimes.js","../../ws-client-core/node_modules/lodash-es/stubFalse.js","../../ws-client-core/node_modules/lodash-es/_isIndex.js","../../ws-client-core/node_modules/lodash-es/isLength.js","../../ws-client-core/node_modules/lodash-es/_baseUnary.js","../../ws-client-core/node_modules/lodash-es/_isPrototype.js","../../ws-client-core/node_modules/lodash-es/isObject.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/_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/_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/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/identity.js","../../ws-client-core/node_modules/lodash-es/_baseProperty.js","../../ws-client-core/node_modules/jsonql-params-validator/src/object.js","../../ws-client-core/node_modules/jsonql-errors/src/validation-error.js","../../ws-client-core/node_modules/jsonql-params-validator/src/validator.js","../../ws-client-core/node_modules/lodash-es/_copyArray.js","../../ws-client-core/node_modules/lodash-es/_safeGet.js","../../ws-client-core/node_modules/lodash-es/_nativeKeysIn.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/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-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-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/node_modules/jsonql-utils/src/generic.js","../../ws-client-core/node_modules/jsonql-errors/src/500-error.js","../../ws-client-core/node_modules/jsonql-errors/src/resolver-not-found-error.js","../../ws-client-core/node_modules/jsonql-errors/src/server-error.js","../../ws-client-core/node_modules/jsonql-utils/src/contract.js","../../ws-client-core/node_modules/jsonql-utils/src/namespace.js","../../ws-client-core/src/utils/helpers.js","../../ws-client-core/src/core/setup-auth-methods.js","../../ws-client-core/src/options/constants.js","../../ws-client-core/src/core/respond-handler.js","../../ws-client-core/src/core/action-call.js","../../ws-client-core/src/core/setup-send-method.js","../../ws-client-core/src/core/setup-resolver.js","../../ws-client-core/src/core/resolver-methods.js","../../ws-client-core/src/core/setup-intercom.js","../../ws-client-core/src/core/generator.js","../../ws-client-core/src/options/index.js","../../ws-client-core/src/api.js","../../ws-client-core/src/share/create-nsp-clients.js","../../ws-client-core/src/share/trigger-namespaces-on-error.js","../../ws-client-core/src/share/client-event-handler.js","src/options/index.js","src/core/create-websocket-binding/init-websocket-client.js","src/core/create-nsp/login-event-handler.js","node_modules/_lodash-es@4.17.15@lodash-es/isArray.js","node_modules/_lodash-es@4.17.15@lodash-es/_objectToString.js","node_modules/_lodash-es@4.17.15@lodash-es/isObjectLike.js","node_modules/_jsonql-utils@1.1.3@jsonql-utils/src/generic.js","node_modules/_jsonql-errors@1.1.10@jsonql-errors/src/validation-error.js","node_modules/_jsonql-utils@1.1.3@jsonql-utils/src/timestamp.js","node_modules/_jsonql-utils@1.1.3@jsonql-utils/src/params-api.js","node_modules/_jsonql-utils@1.1.3@jsonql-utils/src/socket.js","src/core/create-nsp/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":["export default (typeof global !== \"undefined\" ? global :\n typeof self !== \"undefined\" ? self :\n typeof window !== \"undefined\" ? window : {});\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 * 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 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 * 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 * 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","// 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\nexport const 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)`\nexport const PARAMS_NOT_ARRAY_ERR = `params is not an array! Did something gone wrong when you generate the contract.json?`\nexport const EXCEPTION_CASE_ERR = 'Could not understand your arguments and parameter structure!'\nexport const UNUSUAL_CASE_ERR = 'This is an unusual situation where the arguments are more than the params, but not mark as spread'\n\n// re-export\nimport * as JSONQL_CONSTANTS from 'jsonql-constants'\n// @TODO the jsdoc return array. and we should also allow array syntax\nexport const DEFAULT_TYPE = JSONQL_CONSTANTS.DEFAULT_TYPE\nexport const ARRAY_TYPE_LFT = JSONQL_CONSTANTS.ARRAY_TYPE_LFT\nexport const ARRAY_TYPE_RGT = JSONQL_CONSTANTS.ARRAY_TYPE_RGT\n\nexport const TYPE_KEY = JSONQL_CONSTANTS.TYPE_KEY\nexport const OPTIONAL_KEY = JSONQL_CONSTANTS.OPTIONAL_KEY\nexport const ENUM_KEY = JSONQL_CONSTANTS.ENUM_KEY\nexport const ARGS_KEY = JSONQL_CONSTANTS.ARGS_KEY\nexport const CHECKER_KEY = JSONQL_CONSTANTS.CHECKER_KEY\nexport const ALIAS_KEY = JSONQL_CONSTANTS.ALIAS_KEY\n\nexport const ARRAY_TYPE = JSONQL_CONSTANTS.ARRAY_TYPE\nexport const OBJECT_TYPE = JSONQL_CONSTANTS.OBJECT_TYPE\nexport const STRING_TYPE = JSONQL_CONSTANTS.STRING_TYPE\nexport const BOOLEAN_TYPE = JSONQL_CONSTANTS.BOOLEAN_TYPE\nexport const NUMBER_TYPE = JSONQL_CONSTANTS.NUMBER_TYPE\nexport const KEY_WORD = JSONQL_CONSTANTS.KEY_WORD\nexport const OR_SEPERATOR = JSONQL_CONSTANTS.OR_SEPERATOR\n\n// not actually in use\n// export const NUMBER_TYPES = JSONQL_CONSTANTS.NUMBER_TYPES;\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","/**\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 * 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 * 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 * 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","/**\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","/** 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","/** 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 * 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","/** 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 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","/**\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","/** 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","/** 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 * 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 * 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 * 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","// validate object type\n\nimport isPlainObject from 'lodash-es/isPlainObject'\nimport filter from 'lodash-es/filter'\n\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","// 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","// 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 // checkIsObject,\n combineFn,\n notEmpty\n} from './index'\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 // UNUSUAL_CASE_ERR\n} from './constants'\nimport { DATA_KEY, ERROR_KEY } from 'jsonql-constants'\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","/**\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","/**\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 * 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 * 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","/** 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","// 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","// 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'\n// PIA syntax\nexport const isObject = checkIsObject\nexport const isAny = checkIsAny\nexport const isString = checkIsString\nexport const isBoolean = checkIsBoolean\nexport const isNumber = checkIsNumber\nexport const isArray = checkIsArray\nexport const isNotEmpty = notEmpty\n\nimport * as validator from './src/validator'\n\nexport const normalizeArgs = validator.normalizeArgs\nexport const validateSync = validator.validateSync\nexport const validateAsync = validator.validateAsync\n\n// configuration checking\n\nimport * as jsonqlOptions from './src/options'\n\nexport const JSONQL_PARAMS_VALIDATOR_INFO = jsonqlOptions.JSONQL_PARAMS_VALIDATOR_INFO\n\nexport const createConfig = jsonqlOptions.createConfig\nexport const constructConfig = jsonqlOptions.constructConfigFn\n// construct the final output 1.5.2\nexport const checkConfigAsync = jsonqlOptions.getCheckConfigAsync(validator.validateSync)\nexport const checkConfig = jsonqlOptions.getCheckConfig(validator.validateSync)\n\n// export the two extra functions\nimport isInArray from './src/is-in-array'\nimport isObjectHasKeyFn from './src/is-key-in-object'\n\nexport const inArray = isInArray\nexport const isObjectHasKey = isObjectHasKeyFn\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","// 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","/**\n * This is a custom error to throw when server throw a 500\n * This help us to capture the right error, due to the call happens in sequence\n * @param {string} message to tell what happen\n * @param {mixed} extra things we want to add, 500?\n */\nexport default class Jsonql500Error extends Error {\n constructor(...args) {\n super(...args)\n\n this.message = args[0]\n this.detail = args[1]\n\n this.className = Jsonql500Error.name;\n\n if (Error.captureStackTrace) {\n Error.captureStackTrace(this, Jsonql500Error)\n }\n }\n\n static get statusCode() {\n return 500;\n }\n\n static get name() {\n return 'Jsonql500Error';\n }\n\n}\n","/**\n * This is a custom error to throw when could not find the resolver\n * This help us to capture the right error, due to the call happens in sequence\n * @param {string} message to tell what happen\n * @param {mixed} extra things we want to add, 500?\n */\nexport default class JsonqlResolverNotFoundError extends Error {\n constructor(...args) {\n super(...args)\n\n this.message = args[0]\n this.detail = args[1]\n\n this.className = JsonqlResolverNotFoundError.name;\n\n if (Error.captureStackTrace) {\n Error.captureStackTrace(this, JsonqlResolverNotFoundError);\n }\n }\n\n static get statusCode() {\n return 404;\n }\n\n static get name() {\n return 'JsonqlResolverNotFoundError';\n }\n}\n","// this is from an example from Koa team to use for internal middleware ctx.throw\n// but after the test the res.body part is unable to extract the required data\n// I keep this one here for future reference\n\nexport default class JsonqlServerError extends Error {\n\n constructor(statusCode, message) {\n super(message)\n this.statusCode = statusCode;\n this.className = JsonqlServerError.name;\n }\n\n static get name() {\n return 'JsonqlServerError';\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","// 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.publicNamespace ].join('/'),\n [ base , config.privateNamespace ].join('/')\n ]\n }\n return [ base ]\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","// 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(client, resolverName, setupResolver(namespace, resolverName, params, fn, ee, log))\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 createNamespaceErrorHandler(client, opts, ee, nspGroup) {\n return [\n // using the onError as name\n // @TODO we should follow the convention earlier\n // make this a setter for the clientitself\n objDefineProps(client, ON_ERROR_FN_NAME, 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 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 createOnReadyHandler(client, opts, ee) {\n return [\n objDefineProps(client, ON_READY_FN_NAME, 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 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} ","// 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 createNamespaceErrorHandler,\n createOnReadyHandler\n} from './resolver-methods'\nimport {\n setupFinalStep \n} from './setup-final-step'\nimport {\n NSP_GROUP\n} from 'jsonql-constants'\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 generator(opts, nspMap, ee) {\n\n let args = [\n generateResolvers,\n createNamespaceErrorHandler,\n createOnReadyHandler\n ]\n if (opts.enableAuth) {\n args.push(\n createAuthMethods\n )\n } \n // we will always get back the [ obj, opts, ee ]\n // then we only return the obj (wsClient)\n args.push(setupFinalStep)\n // run it\n const fn = Reflect.apply(chainFns, null, args)\n\n return fn(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 { generator } from './core'\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} frameworkSocketEngine \n * @param {object} config the already checked config \n */\nexport function wsClientCoreAction(frameworkSocketEngine, config) {\n return postCheckInjectOpts(config)\n // the following two moved to wsPostConfig\n .then(createRequiredParams)\n .then(\n ({opts, nspMap, ee}) => frameworkSocketEngine(opts, nspMap, ee)\n )\n .then(\n ({opts, nspMap, ee}) => generator(opts, nspMap, ee)\n )\n .catch(err => {\n console.error(`jsonql-ws-core-client init error`, err)\n })\n}\n\n/**\n * The main interface which will generate the socket clients and map all events\n * @param {object} frameworkSocketEngine 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(frameworkSocketEngine, configCheckMap = {}, constProps = {}) {\n // we need to inject property to this client later\n return (config = {}) => checkConfiguration(config, configCheckMap, constProps)\n .then(opts => wsClientCoreAction(frameworkSocketEngine, opts))\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 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}","// 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\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, SOCKET_IO, DISCONNECTED_ERROR_MSG } from '../options/constants'\nimport { createEvt, clearMainEmitEvt } from '../utils'\nimport { triggerNamespacesOnError } from './trigger-namespaces-on-error'\n\n/**\n * A Event handler 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 */\nconst notLoginWsHandler = (namespace, ee, opts) => {\n const { log } = opts \n ee.$only(\n createEvt(namespace, EMIT_EVT),\n function notLoginHandlerCallback(resolverName, args) {\n log('[notLoginHandler] hijack the ws call', namespace, resolverName, args)\n const error = {\n message: NOT_LOGIN_ERR_MSG\n }\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 handler, but wrap inside the error key\n ee.$call(createEvt(namespace, resolverName, ON_RESULT_FN_NAME), [{ error }])\n }\n )\n}\n\n/**\n * A Event handler 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 */\nconst disconnectedHandler = (namespace, ee, opts) => {\n const { log } = opts \n ee.$only(\n createEvt(namespace, EMIT_EVT),\n function disconnectedHandlerCallback(resolverName, args) {\n log(`[disconnectedHandler] 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 handler, but wrap inside the error key\n ee.$call(createEvt(namespace, resolverName, ON_RESULT_FN_NAME), [{ error }])\n }\n )\n}\n\n/**\n * get the private namespace\n * @param {array} namespaces array\n * @return {*} string on success\n */\nconst getPrivateNamespace = (namespaces) => (\n namespaces.length > 1 ? namespaces[0] : false\n)\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 */\nconst logoutEvtHandler = (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(LOGOUT_EVENT_NAME, function logoutEvtHandlerAction() {\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 handler\n triggerNamespacesOnError(ee, [privateNamespace], LOGOUT_EVENT_NAME)\n // rebind all of the handler 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 notLoginWsHandler(privateNamespace, ee, opts)\n })\n}\n\n/**\n * The disconnect event handler, 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 */\nconst disconnectHandler = (nsps, namespaces, ee, opts) => {\n const { log } = opts \n ee.$on(DISCONNECT_EVENT_NAME, function disconnectEvtHandler() {\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 disconnectedHandler(namespace, ee, opts)\n })\n })\n}\n\n/**\n * centralize all the comm in one place\n * @param {object} opts configuration\n * @param {object} nspMap this is not in the opts \n * @param {object} ee Event Emitter instance\n * @param {function} bindWsHandler binding the ee to ws --> this is the core bit\n * @param {object} nsps namespaced nsp\n * @return {void} nothing\n */\nexport function clientEventHandler(opts, nspMap, ee, bindSocketEventHandler, nsps) {\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 let isPrivate = false\n let hasPrivate = false\n // loop\n // @BUG for io this has to be in order the one with auth need to get call first\n // The order of login is very import we need to run in order here to make sure\n // one is execute then the other\n namespaces.forEach(namespace => {\n isPrivate = privateNamespace === namespace\n if (!hasPrivate) {\n hasPrivate = isPrivate\n }\n // log(namespace, ' --> nsps --> ', nsps[namespace])\n if (nsps[namespace]) {\n\n log('[call bindWsHandler]', isPrivate, namespace)\n let args = [namespace, nsps[namespace], ee, isPrivate, opts]\n \n if (opts.serverType === SOCKET_IO) {\n let { nspGroup } = nspMap\n args.push(nspGroup[namespace])\n }\n Reflect.apply(bindSocketEventHandler, null, args)\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 notLoginWsHandler(namespace, ee, opts)\n }\n })\n // logout event handler \n if (hasPrivate) {\n log(`Has private and add logoutEvtHandler`)\n logoutEvtHandler(nsps, namespaces, ee, opts)\n }\n // finally the disconnect event handlers\n disconnectHandler(nsps, namespaces, ee, opts) \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'\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 * @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 */\nfunction initWebSocketClient(WebSocket, auth = false) {\n if (auth === false) {\n return function createWsClient(url) {\n return new WebSocket(fixWss(url))\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 * @return {object} ws instance\n */\n return function createWsAuthClient(url, token) {\n const ws_url = fixWss(url)\n // console.log('what happen here?', url, ws_url, token)\n const uri = token && typeof token === 'string' ? `${ws_url}?${TOKEN_PARAM_NAME}=${token}` : ws_url\n try {\n return new WebSocket(uri)\n } catch(e) {\n console.error('WebSocket Connection Error', e)\n return false\n }\n }\n}\n\nexport { initWebSocketClient }","// @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}","/**\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 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 * 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","// 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'\nimport JsonqlValidationError from 'jsonql-errors/src/validation-error'\n\nimport isArray from 'lodash-es/isArray'\nimport isPlainObject from 'lodash-es/isPlainObject'\nimport isString from 'lodash-es/isString'\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 * Get name from the payload (ported back from jsonql-koa)\n * @param {*} payload to extract from\n * @return {string} name\n */\nexport function getNameFromPayload(payload) {\n console.error(`This method is going to be deprectead in the next release, please use getResolverFromPayload instead`)\n return Object.keys(payload)[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' \n\nconst WS_KEYS = [\n WS_REPLY_TYPE,\n WS_EVT_NAME,\n WS_DATA_NAME\n]\nimport isString from 'lodash-es/isString'\nimport { toJson, isFunc, isObjectHasKey, nil } from './generic'\nimport { timestamp } from './timestamp'\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 can not decoded', 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_TYPE,\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} 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 * @return {void}\n */\nconst logoutEventHandler = (ee) => {\n // listen to the LOGOUT_EVENT_NAME when this is a private nsp\n ee.$on(LOGOUT_EVENT_NAME, function closeEvtHandler() {\n try {\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 socketEventHandler(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_TYPE:\n // this is handled error and we won't throw it\n // we need to extract the error from json\n log(`ERROR_TYPE`)\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 logoutEventHandler(ee)\n }\n}\n","// actually binding the event client to the socket client\n\n// from the jsonql-ws-client-core\nimport { clientEventHandler } from '../modules'\n// local \nimport { createNspAction } from './create-nsp-action'\nimport { loginEventHandler } from './login-event-handler'\nimport { socketEventHandler } from './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 // arguments for clientEventHandler\n const args = [opts, nspMap, ee, socketEventHandler]\n\n // now create the nsps\n const { namespaces } = nspMap\n const { token, log } = opts\n const { nsps } = createNspAction(opts, nspMap, token)\n args.push(nsps)\n // log(`argument length`, args.length, args)\n\n // binding the listeners - and it will listen to LOGOUT event\n // to unbind itself, and the above call will bind it again\n Reflect.apply(clientEventHandler, null, args)\n // setup listener for the login event\n if (opts.enableAuth) {\n loginEventHandler(opts, nspMap, ee)\n }\n // return what input\n return { opts, nspMap, ee }\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\n\nimport { initWebSocketClient } from './init-websocket-client'\nimport createNsp from '../create-nsp'\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 const nspClient = initWebSocketClient(frameworkModule)\n const nspAuthClient = initWebSocketClient(frameworkModule, true)\n\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 opts.nspClient = nspClient\n opts.nspAuthClient = nspAuthClient \n // @1.0.7 remove later once everything fixed \n const { log } = opts\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;;;;;;;;;;;;;;;;;"} \ 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 90c01c49..8f2bfe58 100644 --- a/packages/@jsonql/ws/src/core/create-nsp/create-nsp.js +++ b/packages/@jsonql/ws/src/core/create-nsp/create-nsp.js @@ -17,9 +17,8 @@ import { socketEventHandler } from './socket-event-handler' function createNsp(opts, nspMap, ee) { // arguments for clientEventHandler const args = [opts, nspMap, ee, socketEventHandler] - // now create the nsps - const { namespaces } = nspMap + // const { namespaces } = nspMap const { token, log } = opts const { nsps } = createNspAction(opts, nspMap, token) args.push(nsps) diff --git a/packages/@jsonql/ws/tests/ws-client-auth.test.js b/packages/@jsonql/ws/tests/ws-client-auth.test.js index 0a6f15ac..ed9f7a99 100644 --- a/packages/@jsonql/ws/tests/ws-client-auth.test.js +++ b/packages/@jsonql/ws/tests/ws-client-auth.test.js @@ -16,6 +16,12 @@ const contract = fsx.readJsonSync(join(contractDir, 'contract.json')) const publicContract = fsx.readJsonSync(join(contractDir, 'public-contract.json')) const debug = require('debug')('jsonql-ws-client:test:ws-auth') +const colors = require('colors/safe') + +const localDebug = (str, ...args) => { + + Reflect.apply(debug, null, [ colors.black.brightGreenBg(str+'') ].concat(args) ) +} const payload = {name: 'Joel'} const token = genToken(payload) @@ -48,29 +54,27 @@ 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.only(`Should able to handle multiple onMessage and one onLogin callback`, t => { t.plan(3) let client = t.context.client client.onReady = function onReadyCallback(w) { - debug('onReady -->', w) + localDebug('onReady -->', w) t.pass() } client.onReady = function onReadyAgainCallback(w) { - debug('onReady again', w) + localDebug('onReady again', w) t.pass() } client.onLogin = function onLoginCallback(n) { - debug(`onLogin -->`, n) + localDebug(`onLogin -->`, n) t.pass() t.end() } - // we need to trigger the login - }) -- Gitee From 2034be2e688b76a5556f1406f21cc8c5af4a8e94 Mon Sep 17 00:00:00 2001 From: joelchu Date: Sat, 14 Mar 2020 09:57:16 +0800 Subject: [PATCH 43/45] clean up the dead code and styling first --- packages/contract-cli/package.json | 2 +- packages/contract-cli/src/ast/jsdoc.js | 4 ++-- .../src/generator/generate-output.js | 9 ++++----- .../src/generator/get-resolver.js | 12 +++++------ .../contract-cli/src/generator/helpers.js | 20 +++++++++---------- packages/contract-cli/src/generator/index.js | 8 +++----- .../src/generator/process-file.js | 12 ++++++----- .../src/generator/read-files-out-contract.js | 6 +++--- .../contract-cli/src/generator/split-task.js | 2 +- 9 files changed, 37 insertions(+), 38 deletions(-) diff --git a/packages/contract-cli/package.json b/packages/contract-cli/package.json index 3d644b4f..98b3bf1d 100755 --- a/packages/contract-cli/package.json +++ b/packages/contract-cli/package.json @@ -1,6 +1,6 @@ { "name": "jsonql-contract", - "version": "1.8.8", + "version": "1.8.9", "description": "JS API / command line tool to generate the contract.json for jsonql", "main": "index.js", "files": [ diff --git a/packages/contract-cli/src/ast/jsdoc.js b/packages/contract-cli/src/ast/jsdoc.js index 45240bd5..f50e539f 100644 --- a/packages/contract-cli/src/ast/jsdoc.js +++ b/packages/contract-cli/src/ast/jsdoc.js @@ -1,9 +1,9 @@ // using jsdoc-cli to read the file and get additional properties // @TODO we still need to handle the @callback tag for function parameter // http://usejsdoc.org/tags-param.html -const { join } = require('path') +// const fs = require('fs-extra') +// const { join } = require('path') const { inspect } = require('util') -const fs = require('fs-extra') const jsdoc = require('jsdoc-api') const debug = require('debug')('jsonql-contract:jsdoc-api') const { diff --git a/packages/contract-cli/src/generator/generate-output.js b/packages/contract-cli/src/generator/generate-output.js index c2d4e692..251f5de0 100644 --- a/packages/contract-cli/src/generator/generate-output.js +++ b/packages/contract-cli/src/generator/generate-output.js @@ -1,19 +1,18 @@ // the final step to generate output const { RETURN_AS_JSON } = require('jsonql-constants') -const { keepOrCleanContract, isContractExisted, writeFileOut } = require('./files-op') +const { keepOrCleanContract, writeFileOut } = require('./files-op') const { mutateContract } = require('./helpers') const { join } = require('path') + /** * Generate the final contract output to file - * @param {string} sourceType what type of file we are dealing with * @param {object} config output directory * @param {object} contract processed result - * @param {boolean|object} [rawData=false] the raw contract data for ES6 create files * @return {boolean} true on success */ -const generateOutput = function(sourceType, config, contract, rawData = false) { +const generateOutput = function(config, contract) { // this return a promise interface - const { outputFilename, contractDir, resolverDir } = config; + const { outputFilename, contractDir } = config; const dist = join(contractDir, outputFilename) // keep or remove the existing contract file return keepOrCleanContract(config, dist) diff --git a/packages/contract-cli/src/generator/get-resolver.js b/packages/contract-cli/src/generator/get-resolver.js index be7c5919..31cbf0d7 100644 --- a/packages/contract-cli/src/generator/get-resolver.js +++ b/packages/contract-cli/src/generator/get-resolver.js @@ -1,6 +1,6 @@ // this is the HEART of this module const fsx = require('fs-extra') -const { join, basename } = require('path') +const { basename } = require('path') const { compact, merge } = require('lodash') const { MODULE_TYPE, @@ -8,17 +8,17 @@ const { INDEX_KEY } = require('jsonql-constants') const { - logToFile, + // logToFile, inTypesArray, isAuthType, checkIfIsPublic, checkIfIsPrivate, - addPublicKey, + // addPublicKey, packOutput } = require('./helpers') const { astParser, - extractReturns, + // extractReturns, extractParams, isExpression, getJsdoc @@ -76,7 +76,7 @@ const checkResolver = (indexFile, inDir, fileType, config) => (baseFile) => { const type = fileParts[0] // we ignore all the fileParts on the root level if (fileParts.length === 1) { - return failed; + return failed } const ext = '.' + fileType; // process fileParts within the folder of query, mutation, auth @@ -96,7 +96,7 @@ const checkResolver = (indexFile, inDir, fileType, config) => (baseFile) => { } } // make sure it always terminate here - return failed; + return failed case 3: // this could be inside the public folder if (inTypesArray(type) || isAuthType(type, fileName, config)) { let isPublic = checkIfIsPublic(fileParts, config) diff --git a/packages/contract-cli/src/generator/helpers.js b/packages/contract-cli/src/generator/helpers.js index d503b2aa..339ca03e 100644 --- a/packages/contract-cli/src/generator/helpers.js +++ b/packages/contract-cli/src/generator/helpers.js @@ -2,22 +2,22 @@ const fsx = require('fs-extra') const { merge, extend, camelCase } = require('lodash') const { isObject } = require('jsonql-params-validator') -const { isObjectHasKey, isContract } = require('jsonql-utils') +const { isContract } = require('jsonql-utils') const { RESOLVER_TYPES, AUTH_TYPE, SOCKET_NAME, - PUBLIC_KEY, - QUERY_NAME, - MUTATION_NAME, + // PUBLIC_KEY, + // QUERY_NAME, + // MUTATION_NAME, JSONQL_PATH, PRIVATE_KEY } = require('jsonql-constants') -const { getJsdoc } = require('../ast') +// const { getJsdoc } = require('../ast') const { getDebug } = require('../utils') // Not using the stock one from jsonql-constants -let AUTH_TYPE_METHODS; +let AUTH_TYPE_METHODS const debug = getDebug('generator:helpers') @@ -43,11 +43,11 @@ const inTypesArray = (item) => ( const isAuthType = function(type, file, config) { let resolverName = camelCase(file) if (!AUTH_TYPE_METHODS) { - const { loginHandlerName, logoutHandlerName, validatorHandlerName } = config; - AUTH_TYPE_METHODS = [loginHandlerName, logoutHandlerName, validatorHandlerName]; + const { loginHandlerName, logoutHandlerName, validatorHandlerName } = config + AUTH_TYPE_METHODS = [loginHandlerName, logoutHandlerName, validatorHandlerName] } // debug('AUTH_TYPE_METHODS', resolverName, AUTH_TYPE_METHODS) - return type === AUTH_TYPE && !!AUTH_TYPE_METHODS.filter(method => resolverName === method).length; + return type === AUTH_TYPE && !!AUTH_TYPE_METHODS.filter(method => resolverName === method).length } /** @@ -105,7 +105,7 @@ const checkIfIsPrivate = (files, config) => ( * @return {object} flag up or not */ const addPublicKey = (baseObj, isPublic) => ( - extend( baseObj, (isPublic ? {public: isPublic} : {}) ) + extend( baseObj, (isPublic ? { public: isPublic } : {}) ) ) /** diff --git a/packages/contract-cli/src/generator/index.js b/packages/contract-cli/src/generator/index.js index d5a168c5..fa01d81a 100644 --- a/packages/contract-cli/src/generator/index.js +++ b/packages/contract-cli/src/generator/index.js @@ -8,7 +8,7 @@ const { merge } = require('lodash') const colors = require('colors/safe') -const debug = require('debug')('jsonql-contract:generator') +// const debug = require('debug')('jsonql-contract:generator') const { PUBLIC_CONTRACT_FILE_NAME } = require('jsonql-constants') @@ -46,10 +46,8 @@ const banner = config => { */ const callPublicGenerator = (config, contract) => ( generateOutput( - contract.sourceType, merge({}, config, { outputFilename: PUBLIC_CONTRACT_FILE_NAME }), - publicContractGenerator(config, contract), - contract // <-- this is when ES6 module require to generate import export files + publicContractGenerator(config, contract) ) ) @@ -66,7 +64,7 @@ const generateNewContract = (config) => { // we can get the sourceType from the contract return callPublicGenerator(config, contract) } - return generateOutput(sourceType, config, contract) + return generateOutput(config, contract) }) } diff --git a/packages/contract-cli/src/generator/process-file.js b/packages/contract-cli/src/generator/process-file.js index 60f4cd17..28f9b324 100644 --- a/packages/contract-cli/src/generator/process-file.js +++ b/packages/contract-cli/src/generator/process-file.js @@ -1,5 +1,5 @@ // this is the heart of the process that pass the resolver file into the AST to understand it -const { join, basename } = require('path') +// const { join, basename } = require('path') const { merge } = require('lodash') const { getResolver, @@ -9,7 +9,7 @@ const { } = require('./get-resolver') const { splitTask } = require('./split-task') const { NOT_ENOUGH_CPU } = require('nb-split-tasks/constants') -const { EXT } = require('jsonql-constants') +// const { EXT } = require('jsonql-constants') const { JsonqlError } = require('jsonql-errors') const { getDebug } = require('../utils') @@ -23,8 +23,10 @@ const debug = getDebug('process-file') */ function processFilesAction(files, fileType, config) { const preprocessor = getResolver(config, fileType) - return Promise.resolve( - files.map( preprocessor ) + return Promise + .resolve( + files + .map( preprocessor ) .filter( obj => obj.ok ) ) } @@ -119,7 +121,7 @@ function postProcessResolverFile(contract, config) { contract.auth = {} } - return contract; + return contract } // export diff --git a/packages/contract-cli/src/generator/read-files-out-contract.js b/packages/contract-cli/src/generator/read-files-out-contract.js index 3335c3f3..e27b438c 100644 --- a/packages/contract-cli/src/generator/read-files-out-contract.js +++ b/packages/contract-cli/src/generator/read-files-out-contract.js @@ -1,6 +1,6 @@ // Here is the point where we need to split to load to different CPU -const { join, basename } = require('path') -const os = require('os') +const { join } = require('path') +// const os = require('os') const glob = require('glob') const colors = require('colors/safe') const { EXT } = require('jsonql-constants') @@ -39,7 +39,7 @@ function getResolverFiles(resolverDir, fileType) { */ function readFilesOutContract(config) { const { resolverDir } = config; - let fileType = config.ext || EXT; + let fileType = config.ext || EXT let timestart = Date.now() return getResolverFiles(resolverDir, fileType) diff --git a/packages/contract-cli/src/generator/split-task.js b/packages/contract-cli/src/generator/split-task.js index 37383724..1072efe1 100644 --- a/packages/contract-cli/src/generator/split-task.js +++ b/packages/contract-cli/src/generator/split-task.js @@ -3,7 +3,7 @@ const { join } = require('path') const nbSplitTasks = require('nb-split-tasks') const { getDebug } = require('../utils') -const debug = getDebug('split-task') +// const debug = getDebug('split-task') const basePath = join(__dirname, 'sub') -- Gitee From 013c93cfbdd850a9203d17576ed7150f880250d9 Mon Sep 17 00:00:00 2001 From: joelchu Date: Sat, 14 Mar 2020 10:07:00 +0800 Subject: [PATCH 44/45] setting up socket test --- packages/contract-cli/extra.js | 2 +- packages/contract-cli/index.js | 4 ++-- packages/contract-cli/src/get-paths.js | 8 ++++---- packages/contract-cli/src/utils.js | 18 ++++++++++-------- packages/contract-cli/test.js | 10 +++++----- .../tests/fixtures/socket/config.js | 10 ++++++++++ packages/contract-cli/tests/socket.test.js | 16 ++++++++++++++++ .../tests/fixtures/jwt/contract.json | 2 +- 8 files changed, 49 insertions(+), 21 deletions(-) create mode 100644 packages/contract-cli/tests/fixtures/socket/config.js diff --git a/packages/contract-cli/extra.js b/packages/contract-cli/extra.js index 83d240dc..bf0ea852 100644 --- a/packages/contract-cli/extra.js +++ b/packages/contract-cli/extra.js @@ -20,7 +20,7 @@ const readContract = function(contractDir, pub) { debug('Serving up the existing one from ', file) return fsx.readJsonSync(file) } - return false; + return false } /** diff --git a/packages/contract-cli/index.js b/packages/contract-cli/index.js index b0550b71..4f749e9c 100755 --- a/packages/contract-cli/index.js +++ b/packages/contract-cli/index.js @@ -5,7 +5,7 @@ const { getPaths, watcher } = require('./src') -const { KEY_WORD } = require('jsonql-constants') +// const { KEY_WORD } = require('jsonql-constants') // const debug = require('debug')('jsonql-contract:api'); // main contract-cli @api public module.exports = function(config) { @@ -17,7 +17,7 @@ module.exports = function(config) { // let the watcher run watcher(opts) // always return the result for the next op - return result; + return result }) ) .catch(err => { diff --git a/packages/contract-cli/src/get-paths.js b/packages/contract-cli/src/get-paths.js index 62d60424..a3f3cabb 100755 --- a/packages/contract-cli/src/get-paths.js +++ b/packages/contract-cli/src/get-paths.js @@ -17,19 +17,19 @@ function getPaths(argv) { if (argv.contractDir) { argv.contractDir = resolve(argv.contractDir) } else { - argv.contractDir = baseDir; + argv.contractDir = baseDir } argv.resolverDir = resolve(argv.resolverDir) - return resolver(argv); // just return it + return resolver(argv) // just return it } else if (argv._) { - const args = argv._; + const args = argv._ if (args[0]) { return resolver({ resolverDir: resolve(args[0]), contractDir: args[1] ? resolve(args[1]) : baseDir, // raw: argv.raw, if they are using command line raw is not available as option public: argv.public - }); + }) } } rejecter('You need to provide the input path!') diff --git a/packages/contract-cli/src/utils.js b/packages/contract-cli/src/utils.js index 4155acb2..69618326 100644 --- a/packages/contract-cli/src/utils.js +++ b/packages/contract-cli/src/utils.js @@ -48,18 +48,17 @@ const getConfigFromArgs = (config, cmd) => ( if (key === '_') { switch (cmd) { case 'create': - let [inDir, outDir] = value; - result.inDir = inDir; - result.outDir = outDir; - break; + let [inDir, outDir] = value + result.inDir = inDir + result.outDir = outDir + break case 'remote': // @TODO throw new Error('Not support at the moment!') - break; case 'config': // we don't need to do anything here // console.log('config', key, value) - break; + break } } else { result[key] = value @@ -77,11 +76,14 @@ const getConfigFromArgs = (config, cmd) => ( const applyDefaultOptions = (config, cmd = false) => ( getConfigFromArgs(config, cmd) .then(config => { + getDebug('applyDefaultOptions')('show config', config) + if (config.public === 'true' || config.public === 1 || config.public === '1') { - config.public = true; // because it might be a string true + config.public = true // because it might be a string true } - return config; + + return config }) .then(checkForConfigFile) .then(checkOptions) diff --git a/packages/contract-cli/test.js b/packages/contract-cli/test.js index b5e03d08..304b2096 100644 --- a/packages/contract-cli/test.js +++ b/packages/contract-cli/test.js @@ -15,22 +15,22 @@ watcher({ }); */ console.time('test') -let startBase, fullYear; +let startBase, fullYear const increase = (base, percent, year, target) => { if (!startBase && !fullYear) { - startBase = base; - fullYear = year; + startBase = base + fullYear = year } base = (base * (100 + percent)) / 100; --year; if (target && base >= target) { - console.info(`In year ${fullYear - year} and you will get ${Math.round(base)}`); + console.info(`In year ${fullYear - year} and you will get ${Math.round(base)}`) return; } if (year > 0) { console.info(`(add ${startBase} each year) ${Math.round(base)} at ${percent}% interest for ${fullYear - year} comes to `, Math.round(base)); - increase(base + startBase, percent, year, target); + increase(base + startBase, percent, year, target) } else { console.info(`Finally ${startBase} at ${percent}% interest for ${fullYear} years comes to `, Math.round(base)); } diff --git a/packages/contract-cli/tests/fixtures/socket/config.js b/packages/contract-cli/tests/fixtures/socket/config.js new file mode 100644 index 00000000..efb9dbf7 --- /dev/null +++ b/packages/contract-cli/tests/fixtures/socket/config.js @@ -0,0 +1,10 @@ +// create a configuration files for the socket operation +const base = { + enableAuth: true, + loginHandlerName: 'login', + logoutHandlerName: 'logout' +} + +module.exports = function(extra = {}) { + return Object.assign({}, base, extra) +} \ No newline at end of file diff --git a/packages/contract-cli/tests/socket.test.js b/packages/contract-cli/tests/socket.test.js index ec7ac4ae..b6770bab 100644 --- a/packages/contract-cli/tests/socket.test.js +++ b/packages/contract-cli/tests/socket.test.js @@ -4,6 +4,22 @@ const { join } = require('path') const fsx = require('fs-extra') const resolverDir = join(__dirname, 'fixtures', 'resolvers') +const { + getResolver, + getSourceType, + getContractBase +} = require('../src/generator/get-resolver') +const socketConfig = require('./fixtures/socket/config') + +test.before(t => { + + +}) + + +test.todo(`It should able to return a list of socket auth files`) + + test.todo(`It should able to generate new entry when socket/auth has content`) diff --git a/packages/node-client/tests/fixtures/jwt/contract.json b/packages/node-client/tests/fixtures/jwt/contract.json index b59ec20a..c4d029a8 100644 --- a/packages/node-client/tests/fixtures/jwt/contract.json +++ b/packages/node-client/tests/fixtures/jwt/contract.json @@ -102,7 +102,7 @@ ] } }, - "timestamp": 1583829857, + "timestamp": 1584151039, "sourceType": "script", "socket": { "gateway": { -- Gitee From 9a85f306ab7eef90e4936ab8e9b0f17b3f1e53a8 Mon Sep 17 00:00:00 2001 From: joelchu Date: Sat, 14 Mar 2020 12:28:40 +0800 Subject: [PATCH 45/45] add new ping event name for socket server --- packages/constants/README.md | 2 + packages/constants/constants.json | 2 + packages/constants/main.js | 2 + packages/constants/module.js | 2 + packages/constants/package.json | 2 +- packages/contract-cli/package.json | 3 +- .../src/generator/generate-output.js | 2 +- .../src/generator/get-resolver.js | 6 +- .../src/generator/get-socket-auth-resolver.js | 58 +++++++++++++++++++ packages/contract-cli/src/generator/index.js | 1 + .../src/generator/read-files-out-contract.js | 7 ++- packages/contract-cli/tests/socket.test.js | 20 +++++-- packages/ws-server-core/src/options/props.js | 6 +- 13 files changed, 96 insertions(+), 17 deletions(-) create mode 100644 packages/contract-cli/src/generator/get-socket-auth-resolver.js diff --git a/packages/constants/README.md b/packages/constants/README.md index 3036badd..dfa4332c 100755 --- a/packages/constants/README.md +++ b/packages/constants/README.md @@ -52,6 +52,7 @@ non-javascript to develop your tool. You can also use the included `constants.js - ALIAS_KEY - CHECKED_KEY - AUTH_TYPE +- AUTH_NAME - LOGIN_NAME - LOGOUT_NAME - VALIDATOR_NAME @@ -91,6 +92,7 @@ non-javascript to develop your tool. You can also use the included `constants.js - RETURN_AS_ENUM - NO_ERROR_MSG - NO_STATUS_CODE +- SOCKET_PING_EVENT_NAME - SWITCH_USER_EVENT_NAME - LOGIN_EVENT_NAME - LOGOUT_EVENT_NAME diff --git a/packages/constants/constants.json b/packages/constants/constants.json index 2774b718..c0d9844f 100644 --- a/packages/constants/constants.json +++ b/packages/constants/constants.json @@ -58,6 +58,7 @@ "ALIAS_KEY": "alias", "CHECKED_KEY": "__checked__", "AUTH_TYPE": "auth", + "AUTH_NAME": "auth", "LOGIN_NAME": "login", "LOGOUT_NAME": "logout", "VALIDATOR_NAME": "validator", @@ -118,6 +119,7 @@ ], "NO_ERROR_MSG": "No message", "NO_STATUS_CODE": -1, + "SOCKET_PING_EVENT_NAME": "__ping__", "SWITCH_USER_EVENT_NAME": "__switch__", "LOGIN_EVENT_NAME": "__login__", "LOGOUT_EVENT_NAME": "__logout__", diff --git a/packages/constants/main.js b/packages/constants/main.js index 13299a4c..fc49c787 100644 --- a/packages/constants/main.js +++ b/packages/constants/main.js @@ -58,6 +58,7 @@ module.exports = { "ALIAS_KEY": "alias", "CHECKED_KEY": "__checked__", "AUTH_TYPE": "auth", + "AUTH_NAME": "auth", "LOGIN_NAME": "login", "LOGOUT_NAME": "logout", "VALIDATOR_NAME": "validator", @@ -118,6 +119,7 @@ module.exports = { ], "NO_ERROR_MSG": "No message", "NO_STATUS_CODE": -1, + "SOCKET_PING_EVENT_NAME": "__ping__", "SWITCH_USER_EVENT_NAME": "__switch__", "LOGIN_EVENT_NAME": "__login__", "LOGOUT_EVENT_NAME": "__logout__", diff --git a/packages/constants/module.js b/packages/constants/module.js index 33149d8c..044997d6 100644 --- a/packages/constants/module.js +++ b/packages/constants/module.js @@ -67,6 +67,7 @@ export const ALIAS_KEY = 'alias' export const CHECKED_KEY = '__checked__' // author export const AUTH_TYPE = 'auth' +export const AUTH_NAME = AUTH_TYPE // alias export const LOGIN_NAME = 'login' // export const ISSUER_NAME = LOGIN_NAME // legacy issue need to replace them later export const LOGOUT_NAME = 'logout' @@ -125,6 +126,7 @@ export const NO_ERROR_MSG = 'No message' export const NO_STATUS_CODE = -1 // use throughout the clients +export const SOCKET_PING_EVENT_NAME = '__ping__' // when init connection do a ping export const SWITCH_USER_EVENT_NAME = '__switch__' export const LOGIN_EVENT_NAME = '__login__' export const LOGOUT_EVENT_NAME = '__logout__' diff --git a/packages/constants/package.json b/packages/constants/package.json index 833cdcf3..fc3408f9 100755 --- a/packages/constants/package.json +++ b/packages/constants/package.json @@ -1,6 +1,6 @@ { "name": "jsonql-constants", - "version": "1.9.9", + "version": "1.9.10", "description": "All the share constants for jsonql tools", "main": "main.js", "module": "module.js", diff --git a/packages/contract-cli/package.json b/packages/contract-cli/package.json index 98b3bf1d..6fec3e75 100755 --- a/packages/contract-cli/package.json +++ b/packages/contract-cli/package.json @@ -13,10 +13,11 @@ "scripts": { "dev": "DEBUG=jsonql-contract:* node ./test.js", "coverage": "nyc ava", - "prepare": "ava", + "prepare": "npm test", "cli": "DEBUG=jsonql-contract* node ./cli.js", "cli:watch": "DEBUG=jsonql-contract* node ./watch.js", "test": "ava", + "test:socket": "DEBUG=jsonql-contract* ava ./tests/socket.test.js", "test:cli": "npm run cli configFile ./tests/fixtures/cmd-config-test.js", "test:doc": "DEBUG=jsonql-contract:* ava ./tests/contract-with-doc.test.js", "test:gen": "DEBUG=jsonql-contract:* ava ./tests/generator.test.js", diff --git a/packages/contract-cli/src/generator/generate-output.js b/packages/contract-cli/src/generator/generate-output.js index 251f5de0..2efcd39f 100644 --- a/packages/contract-cli/src/generator/generate-output.js +++ b/packages/contract-cli/src/generator/generate-output.js @@ -12,7 +12,7 @@ const { join } = require('path') */ const generateOutput = function(config, contract) { // this return a promise interface - const { outputFilename, contractDir } = config; + const { outputFilename, contractDir } = config const dist = join(contractDir, outputFilename) // keep or remove the existing contract file return keepOrCleanContract(config, dist) diff --git a/packages/contract-cli/src/generator/get-resolver.js b/packages/contract-cli/src/generator/get-resolver.js index 31cbf0d7..8422d1b0 100644 --- a/packages/contract-cli/src/generator/get-resolver.js +++ b/packages/contract-cli/src/generator/get-resolver.js @@ -48,8 +48,8 @@ const sourceFileType = src => { * @return {object} add the resourceType to the object */ function getSourceType(objs) { - let sourceType; - let ctn = objs.length; + let sourceType + let ctn = objs.lengths for (let i = 0; i < ctn; ++i) { if (!sourceType) { resourceType = sourceFileType(objs[i].file) @@ -78,7 +78,7 @@ const checkResolver = (indexFile, inDir, fileType, config) => (baseFile) => { if (fileParts.length === 1) { return failed } - const ext = '.' + fileType; + const ext = '.' + fileType // process fileParts within the folder of query, mutation, auth const fileName = basename(fileParts[1], ext) // const evt = basename(fileParts[1]); diff --git a/packages/contract-cli/src/generator/get-socket-auth-resolver.js b/packages/contract-cli/src/generator/get-socket-auth-resolver.js new file mode 100644 index 00000000..52b81226 --- /dev/null +++ b/packages/contract-cli/src/generator/get-socket-auth-resolver.js @@ -0,0 +1,58 @@ +// This will be add to the post generate main contract.json file process +// these functions should not appear in the public-contract.json +// its mainly for internal use +const fsx = require('fs-extra') +const debug = require('debug')('jsonql-contract:generator:get-socket-auth-resolver') +const { join } = require('path') +const { SOCKET_NAME, AUTH_TYPE } = require('jsonql-constants') +const { getResolverFiles } = require('./read-files-out-contract') + + +function getSocketAuthResolver(resolverDir, fileType) { + +} + +/** + * Take the list of files from the folder, then filter out those that are not + * registered socket auth files + * @param {array} authFiles the list of auth files + * @param {string} fileType the file extension + * @param {object} config configuration options + * @return {array} the list of registered socket auth files + */ +function filterAuthFiles(authFiles, fileType, config) { + // setup the targets + const { + loginHandlerName, + logoutHandlerName, + disconnectHandlerName + } = config + const targets = [ + loginHandlerName, + logoutHandlerName, + disconnectHandlerName + ] + return authFiles.filter(file => { + + + }) + +} + +/** + * Return the list of files from the folder first + * @param {string} resolverDir where the base resolver directory + * @param {string} fileType what type of files + * @return {promise} resolve the list of files + */ +function getSocketAuthResolverFiles(resolverDir, fileType) { + const dir = join(resolverDir, SOCKET_NAME, AUTH_TYPE) + if (fsx.existsSync(dir)) { + return getResolverFiles(dir, fileType) + } + debug(`${dir} not existed!`) + // we don't throw error here just return an empty result + return Promise.resolve([]) +} + + diff --git a/packages/contract-cli/src/generator/index.js b/packages/contract-cli/src/generator/index.js index fa01d81a..ebe0da58 100644 --- a/packages/contract-cli/src/generator/index.js +++ b/packages/contract-cli/src/generator/index.js @@ -53,6 +53,7 @@ const callPublicGenerator = (config, contract) => ( /** * This is taken out from the original generator main interface + * Create a new contract from scratch * @param {object} config options * @return {mixed} depends on the returnAs parameter */ diff --git a/packages/contract-cli/src/generator/read-files-out-contract.js b/packages/contract-cli/src/generator/read-files-out-contract.js index e27b438c..b2b54cde 100644 --- a/packages/contract-cli/src/generator/read-files-out-contract.js +++ b/packages/contract-cli/src/generator/read-files-out-contract.js @@ -19,7 +19,7 @@ const debug = getDebug('read-files-out-contract') * @param {string} [fileType=EXT] the file extension * @return {promise} resolve the files array on success or reject with error */ -function getResolverFiles(resolverDir, fileType) { +function getResolverFiles(resolverDir, fileType = EXT) { const pat = join(resolverDir, '**', ['*', fileType].join('.')) return new Promise((resolver, rejecter) => { glob(pat, (err, files) => { @@ -41,7 +41,8 @@ function readFilesOutContract(config) { const { resolverDir } = config; let fileType = config.ext || EXT let timestart = Date.now() - + const name = 'readFilesOutContract' + console.time(name) return getResolverFiles(resolverDir, fileType) .then(files => preprocessResolverFile(files, fileType, config) .then(result => { @@ -52,7 +53,7 @@ function readFilesOutContract(config) { ) .then(result => { let timeend = Date.now() - timestart - debug('Time it took:', colors.yellow(timeend)) + debug('Time it took:', colors.yellow(timeend), console.timeEnd(name)) return result }) } diff --git a/packages/contract-cli/tests/socket.test.js b/packages/contract-cli/tests/socket.test.js index b6770bab..f74cbd34 100644 --- a/packages/contract-cli/tests/socket.test.js +++ b/packages/contract-cli/tests/socket.test.js @@ -2,22 +2,32 @@ const test = require('ava') const { join } = require('path') const fsx = require('fs-extra') - +const { SOCKET_NAME, AUTH_TYPE } = require('jsonql-constants') const resolverDir = join(__dirname, 'fixtures', 'resolvers') const { getResolver, getSourceType, getContractBase } = require('../src/generator/get-resolver') +const { getResolverFiles } = require('../src/generator/read-files-out-contract') + const socketConfig = require('./fixtures/socket/config') +const debug = require('debug')('jsonql-contract:test:socket') -test.before(t => { - -}) +test.cb(`It should able to return a list of socket auth files`, t => { + t.plan(1) + getResolverFiles(join(resolverDir, SOCKET_NAME, AUTH_TYPE)) + .then(files => { -test.todo(`It should able to return a list of socket auth files`) + debug('files', files) + + t.pass() + t.end() + }) + +}) diff --git a/packages/ws-server-core/src/options/props.js b/packages/ws-server-core/src/options/props.js index 9d69b1e6..2ccd2179 100644 --- a/packages/ws-server-core/src/options/props.js +++ b/packages/ws-server-core/src/options/props.js @@ -2,7 +2,7 @@ // and methods in another const { join } = require('path') const { createConfig } = require('jsonql-params-validator') -const { isFunc } = require('../share/helpers') +// const { isFunc } = require('../share/helpers') const { HSA_ALGO, @@ -10,9 +10,9 @@ const { ALIAS_KEY, PUBLIC_KEY, PRIVATE_KEY, - CHECKER_KEY, + // CHECKER_KEY, - ANY_TYPE, + // ANY_TYPE, STRING_TYPE, BOOLEAN_TYPE, NUMBER_TYPE, -- Gitee