{"_id":"@io-maana/q-assistant-client","_rev":"59-27f953e43f0ab91a76639ad52de9e26f","name":"@io-maana/q-assistant-client","dist-tags":{"latest":"3.2.3","beta":"3.3.0-beta.20"},"versions":{"3.2.1-beta.1":{"name":"@io-maana/q-assistant-client","version":"3.2.1-beta.1","description":"JavaScript package to streamline communication between an assistant and the Maana Q Assistant API.","main":"AssistantAPIClient.js","scripts":{"test":"echo \"Error: no test specified\" && exit 1"},"repository":{"type":"git","url":"git+https://github.com/maana-io/q-assistant-client.git"},"keywords":["Maana","Q"],"author":{"name":"Logan Gore @ Maana.io"},"license":"MIT","bugs":{"url":"https://github.com/maana-io/q-assistant-client/issues"},"homepage":"https://github.com/maana-io/q-assistant-client#readme","dependencies":{"post-robot":"^10.0.18"},"gitHead":"ac51d941f60a556721708a8133f03ed6a0e4daf7","_id":"@io-maana/q-assistant-client@3.2.1-beta.1","_npmVersion":"6.4.1","_nodeVersion":"10.15.2","_npmUser":{"name":"bzvetey","email":"bzvestey@gmail.com"},"dist":{"integrity":"sha512-Q0ypFT2oDwV6JeUPb82qm2ah/cLsnqxteWEmhJ4vzlL+MZ6TJVSPKXTr+7Te3CQc+by4yQ0hdy/Wy6sJsXU1Nw==","shasum":"38940135ddcd8a8206c3a519aa63ebb1f2f6edd3","tarball":"https://registry.npmjs.org/@io-maana/q-assistant-client/-/q-assistant-client-3.2.1-beta.1.tgz","fileCount":3,"unpackedSize":4945,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJdVGZrCRA9TVsSAnZWagAAFL4P/0dqH7CGoOz1WlQSmdkm\nt3wW9R7zgZ1N5mZZWCIcmhKfbkOAuVzL8fQV7bCNHCnI60JpoeALEn/YH915\nrue1MPvWT8aT8+OW5UJaIxWTyzGbb+nQUyhJwfhhXzh9KYdM7keSLV84Ue2p\nU46CtYD137AOzMPrRRGvIDevk9PfgNTNSQqjbSXMz1tK+MYw68OFBx0aJ3UF\ncp1IOQVIGhGmGmKvwtH+u7E9fUkEPU7ZYl9d9jlUTBUUt+s3XERRCR+f+luc\nA9IWH2muDSBlG7MjSBGke+mFtYb6yzAcJOd0BQkMylMXZozDDJ0E5tR61U15\nEaDe4c8lPCOFLMDN+KFwyunGlQvrz6p2LjZcbxk4HNRL4m/LLfAuBgB5WuoA\nilDKX0J99E8Kvsn5fCKNaXDs/2EnFtW2E63f2flph9UoXqIRsOqOZioGdNTK\n1P8rIHUc5XdEtyaeZ5/EsUjJEiQBo8EZTFI/WRckVIQadW1l23kuM65xzqNL\nkLdW56LGkjFLtq/ruklqrq1QgHNLlbvmOO5vCGmHY2QOeKohPwRY6HIrmgRH\nu6dfcXLGnu35ZP5zBeBqeDx6TWLQQYckqoEPEFg0o8Yvu0El7newWGYrtTg2\ndW3jxUkDQXxJ+jM1Kr8UXP0iZ+9N/j4jygaktbqKIb7MRU6glhPFEA2mbl2n\nnRzY\r\n=YMHI\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIAE305dLBobTHOP9a/wCLZyEib6CpBB8c7rlSOPqoHo7AiEAwI848k3eRrY9tJWRg6Q512mHUwU0LUeZawri6FEmNH4="}]},"maintainers":[{"name":"witt3rd","email":"witt3rd@witt3rd.com"},{"name":"bzvetey","email":"bzvestey@gmail.com"},{"name":"abatyuk","email":"andrey@maana.io"},{"name":"rpovey","email":"rob@maana.io"},{"name":"teamcitymaana","email":"teamcity@maana.io"}],"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/q-assistant-client_3.2.1-beta.1_1565812330359_0.33132927714372684"},"_hasShrinkwrap":false},"3.2.1-beta.2":{"name":"@io-maana/q-assistant-client","version":"3.2.1-beta.2","description":"JavaScript package to streamline communication between an assistant and the Maana Q Assistant API.","main":"build/AssistantAPIClient.js","scripts":{"build":"babel src --out-dir build","prepack":"npm run build","test":"echo \"Error: no test specified\" && exit 1"},"repository":{"type":"git","url":"git+https://github.com/maana-io/q-assistant-client.git"},"keywords":["Maana","Q"],"author":{"name":"Logan Gore @ Maana.io"},"license":"MIT","bugs":{"url":"https://github.com/maana-io/q-assistant-client/issues"},"homepage":"https://github.com/maana-io/q-assistant-client#readme","dependencies":{"post-robot":"^10.0.18"},"devDependencies":{"@babel/cli":"^7.5.5","@babel/core":"^7.5.5","@babel/plugin-proposal-class-properties":"^7.5.5","@babel/preset-env":"^7.5.5"},"gitHead":"ac51d941f60a556721708a8133f03ed6a0e4daf7","_id":"@io-maana/q-assistant-client@3.2.1-beta.2","_npmVersion":"6.4.1","_nodeVersion":"10.15.2","_npmUser":{"name":"bzvetey","email":"bzvestey@gmail.com"},"dist":{"integrity":"sha512-+4uE6+Eblcy51TXuB+VXjPMmSxBX8wX8gIWhmyYEUmY4P3D+K/OO3wcGRMm6FDM2FO16dq8ervye/aK0nJPaXw==","shasum":"d2403e42a1e250cbb897cd8b2bef36295b9b0480","tarball":"https://registry.npmjs.org/@io-maana/q-assistant-client/-/q-assistant-client-3.2.1-beta.2.tgz","fileCount":5,"unpackedSize":8736,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJdVG5eCRA9TVsSAnZWagAAxWoQAJlzx7fhX7WIwHuAR3in\n9APftHxKoFYL9jbqHRJhEw07GVcWjcOQHzdvK03X2gFyG5N0bdcgsPbhtKDf\nzJWscS7TRmkmEUVwqg6ojzbX3eLC587dYGIpTC6j7yfOwdg0/Ys6Ty/5UMpH\niEXrNISGFewXCZlzUbjxqOIyYoWNo4swpehOMu42Sogjt5B5c+uiPNTv0gdj\nH1N8ovr0WuIuHq1m7H6HyriWfac8UB6UpuEiok7G1aqtP3aAUooTqh5oESip\nGWW1cufs5MXYL1zYWt/8ElYm0N77dz00QzjcGV6ULNT6HPeZ4pVP+5yjUP3n\nTyNPsJ79MQo9+Z5bcZboo43veY2qy25045wqF46b2thrIUSPbVTNxexnYZ8p\nx8FnCuwrEGcmAIBVgolzfg7m4izJKipaoXNgQHhP0sF98NIeRebUw7OyCvUe\nZEs/GFHtOwFLevUjmkbdq1HEsqmBUB9FKMceb9D3YJl+impeg2xXD3Gt4hBB\ndMa6bgQLMggwgm/TBuOSSsiUGE6Mbxh9+TUzTGQQsyDh0Kxcor16XNQbUwPp\n3H7OqKyeNkHt0RE/qzuJVBCjV4tqFcFPx6WUa/uTOqgWEZb+qlNhzh8+avCP\nH8+U3gZOTTpYavupXi+7ZD8Bd6aZ9tRg7VG7cQb6pkKvukLdTaSchs+apL+t\nKQpE\r\n=D4ZC\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIQD2/9G8C/nK76W8GwtRUFKzrao6/di3KAt2e9rgE8JPPwIgCr2hFTOhGaewv6rloQswTU7AFksJAxrgA4km7aJwb+E="}]},"maintainers":[{"name":"abatyuk","email":"andrey@maana.io"},{"name":"bzvetey","email":"bzvestey@gmail.com"},{"name":"rpovey","email":"rob@maana.io"},{"name":"teamcitymaana","email":"teamcity@maana.io"},{"name":"witt3rd","email":"witt3rd@witt3rd.com"}],"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/q-assistant-client_3.2.1-beta.2_1565814366280_0.5344715390239203"},"_hasShrinkwrap":false},"3.2.1-beta.3":{"name":"@io-maana/q-assistant-client","version":"3.2.1-beta.3","description":"JavaScript package to streamline communication between an assistant and the Maana Q Assistant API.","main":"build/AssistantAPIClient.js","scripts":{"build":"babel src --out-dir build","prepack":"npm run build","test":"echo \"Error: no test specified\" && exit 1"},"repository":{"type":"git","url":"git+https://github.com/maana-io/q-assistant-client.git"},"keywords":["Maana","Q"],"author":{"name":"Logan Gore @ Maana.io"},"license":"MIT","bugs":{"url":"https://github.com/maana-io/q-assistant-client/issues"},"homepage":"https://github.com/maana-io/q-assistant-client#readme","dependencies":{"post-robot":"^10.0.18"},"devDependencies":{"@babel/cli":"^7.5.5","@babel/core":"^7.5.5","@babel/plugin-proposal-class-properties":"^7.5.5","@babel/preset-env":"^7.5.5"},"gitHead":"ac51d941f60a556721708a8133f03ed6a0e4daf7","_id":"@io-maana/q-assistant-client@3.2.1-beta.3","_npmVersion":"6.4.1","_nodeVersion":"10.15.2","_npmUser":{"name":"bzvetey","email":"bzvestey@gmail.com"},"dist":{"integrity":"sha512-aEZa1k8Eom8gwN5m4PrIL2ZNd3G3L7AFiNcGg59+p17mh1Za4E5kXc3H2AZpjNnr/Ql90MCL4u9OUZWKYlGHqA==","shasum":"97913bcd3b45c89f28e53988c215b0b79064e898","tarball":"https://registry.npmjs.org/@io-maana/q-assistant-client/-/q-assistant-client-3.2.1-beta.3.tgz","fileCount":5,"unpackedSize":8969,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJdVHGNCRA9TVsSAnZWagAArVIP/2hyJlnesQ4Ui1b9ScUO\nISd9RpdRN03bzDhSbVQvDxInTLl6il1YNb4w9stk+L24k1nEGem+sdqXzKC+\nyUsaOLVsXHrRvw9PUrRPGSe3xp742y0/LSTdcGfI3mjZX13P8zejC2azAt8u\njkQDd4e7D/Z7/bidAUVyy2aIJpMrThhAM+y6cnIKTvjEBXiYvWVImVhugz20\n4O//IyFpeKx8sAEkvWksFGJaP66UCC5aTBnID7EX37EV3nKoRrzX/Zzwryt9\n6IH0CyfJZssF/m5iUZEegzjuUaYZFbj1C44nbZYjQQ1EL7XhyssB0EK+49Gq\nLUai3TCuxq0dVT4tvUKJohCcW9zG3qi/IKWvPq9PlDDtquXd289N2bU8lnWq\n4AaSms9kjiotKJGoa8FFKALSjtUhNLjPKFDgti/0HVBPE8It7n9cZ9PY/s/i\nrez38XvclMZKyTeYy05TBdEde800tBFvO/9cztV9I3VvDIlllZYxdMPH/NTJ\ntPVuZhue/RXYzXMUamCHQsXsBUGJq1wyzwxZF0Cb4X+9HUYPqUNoYZmotIYR\nEfZBT3vjdevpwG6GY+EVx16PjhJiICBCDo3ctJ5DKre/kQKA0+HUblFbLTdK\nH+WYBbakHc4ITfKhBEAYMtee9WRmmFxQSie74uL9DpRrwdanxUwPclZ/oSJk\nGgVA\r\n=WLiX\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIQCyGB4bbhEYymVHyFEGI2q7EMooUofEo1oORknaaSYtkgIgP2ruj39/yuvH0IiNH/CiCcps54CcVsUzZsAeZaXvm0Y="}]},"maintainers":[{"name":"abatyuk","email":"andrey@maana.io"},{"name":"bzvetey","email":"bzvestey@gmail.com"},{"name":"rpovey","email":"rob@maana.io"},{"name":"teamcitymaana","email":"teamcity@maana.io"},{"name":"witt3rd","email":"witt3rd@witt3rd.com"}],"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/q-assistant-client_3.2.1-beta.3_1565815181215_0.7615230521559908"},"_hasShrinkwrap":false},"3.2.1-beta.4":{"name":"@io-maana/q-assistant-client","version":"3.2.1-beta.4","description":"JavaScript package to streamline communication between an assistant and the Maana Q Assistant API.","main":"build/AssistantAPIClient.js","scripts":{"build":"babel src --out-dir build","prepack":"npm run build","test":"echo \"Error: no test specified\" && exit 1"},"repository":{"type":"git","url":"git+https://github.com/maana-io/q-assistant-client.git"},"keywords":["Maana","Q"],"author":{"name":"Logan Gore @ Maana.io"},"license":"MIT","bugs":{"url":"https://github.com/maana-io/q-assistant-client/issues"},"homepage":"https://github.com/maana-io/q-assistant-client#readme","dependencies":{"post-robot":"^10.0.18"},"devDependencies":{"@babel/cli":"^7.5.5","@babel/core":"^7.5.5","@babel/plugin-proposal-class-properties":"^7.5.5","@babel/preset-env":"^7.5.5"},"readme":"# q-assistant-client\nA lightweight JavaScript client for Maana-Q Assistant developers that wraps post-message communication between an embedded Maana-Q assistant and the Maana-Q UI.\n\n## Usage\nThis is intented to be used in a web application being leveraged as a Maana Q assistant (embedded as an iframe).\nThis assistant client will facilitate communication between the assistant and the parent frame.\nThe client provides a rich, asynchronous experience over what would otherwise be 'fire-and-forget'-style messaging \nvia post-post message communication. \n\n## Requirements and Assumptions\n@TODO Logan\n\n## Singleton Instance\nThe client is exported as a singleton to avoid duplicate registration on event listeners.\nYou can import the instance like this:\n\n```js\nimport AssistantAPIClient from '@io-maana/q-assistant-client';\n```\n\n## Interacting with the API\n### API Surface Area\n\n### Function Calls\nFunction calls can be made against the client like any other javascript object. They are all async.\n```js\nconst workspace = await AssistantAPIClient.getWorkspace(); \nconsole.log(\"Workspace:\", workspace)\n\nconst functions = await workspace.getFunctions()\nconsole.log(\"Functions:\", functions)\n```\n\n### Event Subscription\nOnly workspace selection events are currently supported.\nSubscriptions are added explictly by registering a callback:\n```js\nAssistantAPIClient.addSelectionChangedListener((selection)=>{\n  console.log('Workspace selection changed:', selection)\n})\n```\n\nThese are removed on a per-callback basis with the 'removeSelectionChangedListener' call. \n\n## Dependencies\nPost-Robot\nhttps://github.com/krakenjs/post-robot\n\nPost-robot is used to provide a richer communication layer atop post-message.\n\n## Examples\n@TODO Logan\n\n## API Documentation\n@TODO Logan\nThis will presumably link to Gitbook Maana Q Documentation that explicates the full K Portal API functionality.\n","readmeFilename":"README.md","gitHead":"62ef8a46e4ab88b18fd6bb40b86df22f66e42808","_id":"@io-maana/q-assistant-client@3.2.1-beta.4","_npmVersion":"6.4.1","_nodeVersion":"10.15.3","_npmUser":{"name":"teamcitymaana","email":"teamcity@maana.io"},"dist":{"integrity":"sha512-Q5vZADxwccEMFneebysBCYdZAarQWO369eCWn9kGlWdd+aOBokd6ZtkzYGst8WR6pER7YrmuFEpMFrJLJpIKmA==","shasum":"eda023028882afb41a4764f5637b9c9476d4d312","tarball":"https://registry.npmjs.org/@io-maana/q-assistant-client/-/q-assistant-client-3.2.1-beta.4.tgz","fileCount":5,"unpackedSize":7843,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJdWysfCRA9TVsSAnZWagAA2hQP/jHRJidYFO3enZJ8KUUr\nW41IVv6uAFpiAmrjQocGeVxCOGk65W96fMil+1QhZET4GY5SV2PPrkZTT7jt\nbMFus7hF9zq7UrZs7pHPZAsCRLn046n9gN3vJOd5mrH6z8E4/ONwWN/38SqZ\nOJk3Z4jMOMmx4TU+1HXVbTQoARQiydszxjQ52/t2Y5vNk8ag6NwrJKjvl0eC\njXHIITIawuNpryxR4fweceTeIN75VCZAzThWT8sWvVbympTls4gVVIqKPBJD\neEU0WFA4ffWtMDJ8654aDJuMO3WPcxVrPOyGIRqCt0237afhrA0snrMpHMc0\nufe4vZFw2HcdAtIpP3CQZ43syN9Lw8bMZz41EnXR8L6xete014IJL1MjF0uW\nvvh7g3ccRunlbN9xUoHFv2byuH2u4yX2ce3riWP9HqxzMtb4CL2zJ232ynPb\nf7RcRvBDW+n8XV3MvCr8zAvAAMaUJOIpJEwZ9hKj+r/kBhnO0LskIO1E7Kf+\nFsIvBSpn+ckTzyyiyfIEg9lw8hSO8OBXUwt3rczQKdxkVn7rbBKQ8rAd6VU6\nirg8ocmAxiHOFMX89um1bJ+DZkH1xv5Ea2WQeRNKZxbI6NR7GNnaw2iBJ3kV\n7TpkIgx6W9j1UELYPxcIrgdHDkMEGgvVvcdWoHpJ2/IfFjb05sBmvwcuqZo5\nHvLK\r\n=prE2\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIFRbpBYIg6rSMVZEBTZrq1bbXt2dRIsTYgSsb3tA7kUSAiEAzeYBlrNlldknq1/s0F5ffdcCyvzHNlR14zzDpTCTmvw="}]},"maintainers":[{"name":"abatyuk","email":"andrey@maana.io"},{"name":"bzvetey","email":"bzvestey@gmail.com"},{"name":"rpovey","email":"rob@maana.io"},{"name":"teamcitymaana","email":"teamcity@maana.io"},{"name":"witt3rd","email":"witt3rd@witt3rd.com"}],"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/q-assistant-client_3.2.1-beta.4_1566255902659_0.01161090019711275"},"_hasShrinkwrap":false},"3.2.1-beta.5":{"name":"@io-maana/q-assistant-client","version":"3.2.1-beta.5","description":"JavaScript package to streamline communication between an assistant and the Maana Q Assistant API.","main":"build/AssistantAPIClient.js","scripts":{"build":"babel src --out-dir build","prepack":"npm run build","test":"echo \"Error: no test specified\" && exit 1"},"repository":{"type":"git","url":"git+https://github.com/maana-io/q-assistant-client.git"},"keywords":["Maana","Q"],"author":{"name":"Logan Gore @ Maana.io"},"license":"MIT","bugs":{"url":"https://github.com/maana-io/q-assistant-client/issues"},"homepage":"https://github.com/maana-io/q-assistant-client#readme","dependencies":{"post-robot":"^10.0.18"},"devDependencies":{"@babel/cli":"^7.5.5","@babel/core":"^7.5.5","@babel/plugin-proposal-class-properties":"^7.5.5","@babel/preset-env":"^7.5.5"},"readme":"# q-assistant-client\nA lightweight JavaScript client for Maana-Q Assistant developers that wraps post-message communication between an embedded Maana-Q assistant and the Maana-Q UI.\n\n## Usage\nThis is intented to be used in a web application being leveraged as a Maana Q assistant (embedded as an iframe).\nThis assistant client will facilitate communication between the assistant and the parent frame.\nThe client provides a rich, asynchronous experience over what would otherwise be 'fire-and-forget'-style messaging \nvia post-post message communication. \n\n## Requirements and Assumptions\n@TODO Logan\n\n## Singleton Instance\nThe client is exported as a singleton to avoid duplicate registration on event listeners.\nYou can import the instance like this:\n\n```js\nimport AssistantAPIClient from '@io-maana/q-assistant-client';\n```\n\n## Interacting with the API\n### API Surface Area\n\n### Function Calls\nFunction calls can be made against the client like any other javascript object. They are all async.\n```js\nconst workspace = await AssistantAPIClient.getWorkspace(); \nconsole.log(\"Workspace:\", workspace)\n\nconst functions = await workspace.getFunctions()\nconsole.log(\"Functions:\", functions)\n```\n\n### Event Subscription\nOnly workspace selection events are currently supported.\nSubscriptions are added explictly by registering a callback:\n```js\nAssistantAPIClient.addSelectionChangedListener((selection)=>{\n  console.log('Workspace selection changed:', selection)\n})\n```\n\nThese are removed on a per-callback basis with the 'removeSelectionChangedListener' call. \n\n## Dependencies\nPost-Robot\nhttps://github.com/krakenjs/post-robot\n\nPost-robot is used to provide a richer communication layer atop post-message.\n\n## Examples\n@TODO Logan\n\n## API Documentation\n@TODO Logan\nThis will presumably link to Gitbook Maana Q Documentation that explicates the full K Portal API functionality.\n","readmeFilename":"README.md","gitHead":"6bd4561e1a8839e9e912b953029e3d90ea29503c","_id":"@io-maana/q-assistant-client@3.2.1-beta.5","_npmVersion":"6.4.1","_nodeVersion":"10.15.3","_npmUser":{"name":"teamcitymaana","email":"teamcity@maana.io"},"dist":{"integrity":"sha512-hmoHIv5qNbG5BO54tA4zuHTLV6dRa3/OK6TzogVEbbzLfrkd40E+eW/nkFTpt4PdG1fVubQf8CW1UjCDPdfzJg==","shasum":"3101938d4334aecd294cf7bbafa21eb288f5942e","tarball":"https://registry.npmjs.org/@io-maana/q-assistant-client/-/q-assistant-client-3.2.1-beta.5.tgz","fileCount":5,"unpackedSize":7987,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJdcUPWCRA9TVsSAnZWagAAOoIP/0Y2UHjrFAWZW60TfNN/\nuLhMLsMHniQ3P6hPUrw25fKBWJ4N5UYOuwLOBolZr1HklnmPkPtbT576N2nM\nKRCKI70Jk/IPUpTjZNzQpy5GWr7td032Yz8Trq1WLmC+r+/ZouBl9Dup8zxQ\n70ftW4bZDn/iFZTOuEsJT4jVfutFJwSO1MSWDkIpUriO/njkv2OcLLtDCnYG\n/fssawh6RdUWbr3ZdwAKJiEsqiZ9T9wnVkQCqGSAH1lMR6upjmBpT+wMsNJF\nmmIQCGra7JbFY/cmtaxZlQZl7PmXzXqObHop+EOWmoaoGd22nwCSf8JwhohB\nNpsCDN0ehEc+JsXOW/QbYZy4QVe3VjnYxSCKTWaMCh96H1VJOo3cPr6WgQ1c\nhNi7KlyIwpHT4gqIJ/jmJheglYhzgQNDcRH6Yx4R517/emSbKxLIK2rOKv9T\nWOJfDl3hJrUcUWiZqNKGvM5gOiOar6eEdultqvB9BEcQBg/sqZcdthiHhTrU\n4uJu/LlikDUxMlDLVssnWL3SIWm9XwC5IzMrujS4mGRLJi4cW3V1bAUny7xT\n8ewEAf4o766lE/YxPrxDqLAXnURoJ4kV0uKPhKD5PL9TVXkTmXO6QIxOQsAN\nxenNVC6EHCdNw20Y62jxMdjF+n48WD4Y+rMeWgSgvp4FCODE5ZZ3bpFrrGgJ\nPiWb\r\n=JF4O\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEYCIQCKZcbGKe7BzBH9O6WkWTMbv9HfYUQp2NDDbYiXwfHWNwIhAJHudZoK14+9S6XQulNHFrIuNAu6l0Jz5ZYvvmUBscAn"}]},"maintainers":[{"name":"abatyuk","email":"andrey@maana.io"},{"name":"bzvetey","email":"bzvestey@gmail.com"},{"name":"rpovey","email":"rob@maana.io"},{"name":"teamcitymaana","email":"teamcity@maana.io"},{"name":"witt3rd","email":"witt3rd@witt3rd.com"}],"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/q-assistant-client_3.2.1-beta.5_1567704021329_0.43363493107913853"},"_hasShrinkwrap":false},"3.2.1-beta.6":{"name":"@io-maana/q-assistant-client","version":"3.2.1-beta.6","description":"JavaScript package to streamline communication between an assistant and the Maana Q Assistant API.","main":"build/AssistantAPIClient.js","scripts":{"build":"babel src --out-dir build","prepack":"npm run build","test":"echo \"Error: no test specified\" && exit 1"},"repository":{"type":"git","url":"git+https://github.com/maana-io/q-assistant-client.git"},"keywords":["Maana","Q"],"author":{"name":"Logan Gore @ Maana.io"},"license":"MIT","bugs":{"url":"https://github.com/maana-io/q-assistant-client/issues"},"homepage":"https://github.com/maana-io/q-assistant-client#readme","dependencies":{"post-robot":"^10.0.18"},"devDependencies":{"@babel/cli":"^7.5.5","@babel/core":"^7.5.5","@babel/plugin-proposal-class-properties":"^7.5.5","@babel/preset-env":"^7.5.5"},"readme":"# q-assistant-client\nA lightweight JavaScript client for Maana-Q Assistant developers that wraps post-message communication between an embedded Maana-Q assistant and the Maana-Q UI.\n\n## Usage\nThis is intented to be used in a web application being leveraged as a Maana Q assistant (embedded as an iframe).\nThis assistant client will facilitate communication between the assistant and the parent frame.\nThe client provides a rich, asynchronous experience over what would otherwise be 'fire-and-forget'-style messaging \nvia post-post message communication. \n\n## Requirements and Assumptions\n@TODO Logan\n\n## Singleton Instance\nThe client is exported as a singleton to avoid duplicate registration on event listeners.\nYou can import the instance like this:\n\n```js\nimport AssistantAPIClient from '@io-maana/q-assistant-client';\n```\n\n## Interacting with the API\n### API Surface Area\n\n### Function Calls\nFunction calls can be made against the client like any other javascript object. They are all async.\n```js\nconst workspace = await AssistantAPIClient.getWorkspace(); \nconsole.log(\"Workspace:\", workspace)\n\nconst functions = await workspace.getFunctions()\nconsole.log(\"Functions:\", functions)\n```\n\n### Event Subscription\nOnly workspace selection events are currently supported.\nSubscriptions are added explictly by registering a callback:\n```js\nAssistantAPIClient.addSelectionChangedListener((selection)=>{\n  console.log('Workspace selection changed:', selection)\n})\n```\n\nThese are removed on a per-callback basis with the 'removeSelectionChangedListener' call. \n\n## Dependencies\nPost-Robot\nhttps://github.com/krakenjs/post-robot\n\nPost-robot is used to provide a richer communication layer atop post-message.\n\n## Examples\n@TODO Logan\n\n## API Documentation\n@TODO Logan\nThis will presumably link to Gitbook Maana Q Documentation that explicates the full K Portal API functionality.\n","readmeFilename":"README.md","gitHead":"9e24edb11d54a1c8e91366923bb312e57035b8dd","_id":"@io-maana/q-assistant-client@3.2.1-beta.6","_npmVersion":"6.4.1","_nodeVersion":"10.15.3","_npmUser":{"name":"teamcitymaana","email":"teamcity@maana.io"},"dist":{"integrity":"sha512-ZPKbprkAA0dSMtEJZEf0/R03OxPoZ0Zy/tZBgEkwPiwafI74Nat2sFU4zMqcvmjjc6KadHWV5qPg9f/3twm2/w==","shasum":"908d47eb96c4b37339ef0d87a19bbd351cae027b","tarball":"https://registry.npmjs.org/@io-maana/q-assistant-client/-/q-assistant-client-3.2.1-beta.6.tgz","fileCount":5,"unpackedSize":9713,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJdeZ75CRA9TVsSAnZWagAAjhcP+wWjqGc+QVHw7N/FnFOr\nRSWmG52bpHctLFnFNfZwJUd9pZp9PMiEf9R054HrbE9ZNU64toiXDFdWFs19\nWz2HCDV4ytSggQVd854WZ5OtSPf1KysTB5qC1CcRWnq9ivtaLtws9lMDoRwQ\ncOzBV8fE+xb2ub2FbRY5P5DlgebtGihzIHphMEWeavdXc/SLzX98D7y1YVs+\niiNZjmY5V19/xJmXFhuyHezpPfCyUtN8O743XACuP9KUGmVjL/M29/XUpYBX\neQ9A0BzxiUKEzqvnTjDzdctQ+ex44WWXv9g00eOOUKK3MxoJceNvJlQxEWlf\ndQWtCZzUfoxqK9Yp+1jfI0zaQOv3l0KNjBSYsqryZtRRpkSbQ9HxatP2TVFZ\n5J2ZO9P4dnkykoDXKmVcgln8X+tZtcRlZytt04iLzG+Cd+rOHdPLJX9SFuph\n2aLGWFCjJQo1AkwuXjtZ728pjtFHyMUDwUccQ7bIsr8sy74qGrpSk+6f+R/g\n99RBAjuQ4TaDmS46bFx2rcrL8IBjCwHEILhMo2P0BTkqQRvfLbPz4tkaT3Ey\no0j1ZQwPMM0m3XYCQrj1iH88QFGrGD21vClLcwdqp9RASHeAqUH6Ec+W2asK\nOkuhJUzOutqtMtyX5WEQH05heY3oerZOTfpu/+f770JAaPlAE6ecMTFaMR5/\nGSu0\r\n=JnKN\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEQCIBAKCfSCNSQPruGxjAcpi8qlHGx0W1cbjG5fmQ+ELxE6AiA2/SHv534rgCbWotUAS7433qA41pjHyKu9jp7ZSbJ/Qw=="}]},"maintainers":[{"name":"abatyuk","email":"andrey@maana.io"},{"name":"bzvetey","email":"bzvestey@gmail.com"},{"name":"rpovey","email":"rob@maana.io"},{"name":"teamcitymaana","email":"teamcity@maana.io"},{"name":"witt3rd","email":"witt3rd@witt3rd.com"}],"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/q-assistant-client_3.2.1-beta.6_1568251640941_0.03982777607623178"},"_hasShrinkwrap":false},"3.2.1-beta.7":{"name":"@io-maana/q-assistant-client","version":"3.2.1-beta.7","description":"JavaScript package to streamline communication between an assistant and the Maana Q Assistant API.","main":"build/AssistantAPIClient.js","scripts":{"build":"babel src --out-dir build","prepack":"npm run build","test":"echo \"Error: no test specified\" && exit 1"},"repository":{"type":"git","url":"git+https://github.com/maana-io/q-assistant-client.git"},"keywords":["Maana","Q"],"author":{"name":"Logan Gore @ Maana.io"},"license":"MIT","bugs":{"url":"https://github.com/maana-io/q-assistant-client/issues"},"homepage":"https://github.com/maana-io/q-assistant-client#readme","dependencies":{"post-robot":"^10.0.18"},"devDependencies":{"@babel/cli":"^7.5.5","@babel/core":"^7.5.5","@babel/plugin-proposal-class-properties":"^7.5.5","@babel/preset-env":"^7.5.5"},"readme":"# q-assistant-client\nA lightweight JavaScript client for Maana-Q Assistant developers that wraps post-message communication between an embedded Maana-Q assistant and the Maana-Q UI.\n\n## Usage\nThis is intented to be used in a web application being leveraged as a Maana Q assistant (embedded as an iframe).\nThis assistant client will facilitate communication between the assistant and the parent frame.\nThe client provides a rich, asynchronous experience over what would otherwise be 'fire-and-forget'-style messaging \nvia post-post message communication. \n\n## Requirements and Assumptions\n@TODO Logan\n\n## Singleton Instance\nThe client is exported as a singleton to avoid duplicate registration on event listeners.\nYou can import the instance like this:\n\n```js\nimport AssistantAPIClient from '@io-maana/q-assistant-client';\n```\n\n## Interacting with the API\n### API Surface Area\n\n### Function Calls\nFunction calls can be made against the client like any other javascript object. They are all async.\n```js\nconst workspace = await AssistantAPIClient.getWorkspace(); \nconsole.log(\"Workspace:\", workspace)\n\nconst functions = await workspace.getFunctions()\nconsole.log(\"Functions:\", functions)\n```\n\n### Event Subscription\nOnly workspace selection events are currently supported.\nSubscriptions are added explictly by registering a callback:\n```js\nAssistantAPIClient.addSelectionChangedListener((selection)=>{\n  console.log('Workspace selection changed:', selection)\n})\n```\n\nThese are removed on a per-callback basis with the 'removeSelectionChangedListener' call. \n\n## Dependencies\nPost-Robot\nhttps://github.com/krakenjs/post-robot\n\nPost-robot is used to provide a richer communication layer atop post-message.\n\n## Examples\n@TODO Logan\n\n## API Documentation\n@TODO Logan\nThis will presumably link to Gitbook Maana Q Documentation that explicates the full K Portal API functionality.\n","readmeFilename":"README.md","gitHead":"6c7f853eb253a1f1a6cea68b1437b8041d7feac1","_id":"@io-maana/q-assistant-client@3.2.1-beta.7","_npmVersion":"6.4.1","_nodeVersion":"10.15.3","_npmUser":{"name":"teamcitymaana","email":"teamcity@maana.io"},"dist":{"integrity":"sha512-upQRQfQXfEd83En6DirwdO4ZzNq3ssASGAjgWZkNBLJNVqch7nBv9nIoKGMSMcXZRQKimsLaupwU2CSCj9/K/w==","shasum":"3b76089f94535dfaa3d39d671af26c1d93d32f9f","tarball":"https://registry.npmjs.org/@io-maana/q-assistant-client/-/q-assistant-client-3.2.1-beta.7.tgz","fileCount":5,"unpackedSize":12107,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJde/j0CRA9TVsSAnZWagAAtH8P/00GIKqwoII8nAMOqrLB\n/iG4r98NOoz7nQ8AbE46I2POIOaIvjBQ71uNxYhO0tjXnxt/qIJbP/f2W27v\ngSuMTtV7kXN7tZKQfxUTrn8JPW7pWJXwi9WUtCuJnjijLlNhPPVZzPqcp5e9\npa0Ss3pODg7kcSBtN+thlsaMZTBfZBWfr8exVAC2qESrScPNWnb7eIO8V8gB\nGMmSdFefqZTWh1t6HiKQIUWBr+J+U/2rbAvPdLWTSwVH+IBnIe3fgZHqcE3S\n5bfErDM8i3iI6IKd1mVGtTrDW4dRQEZpMX7CfCFIfibcqFToI6207gn1s9Rg\nF9pPmVA52gD0/2+9J1dblfrp7WCH12nsATs2LNfKDkrV5u97LMRfFJYuyFrz\nh3Kd538BV2nrcTMj2nkRZQ5Y8DnDoMsUBMtExcn3eU0kVGDlnJL7ebuUOaLP\nfL/X3AgjC6M+pcaRow7LGFeU2gxPJS0yipFSDXMGbGF0z9AoLXO1bTeeeM5H\nS3NUy/p6FAYvBKwg24u3RY5eV2QLumL77dsVEwwd/Dm3UlvOAOOr3TybtAkV\nFTjafyKriviMx7e8UvZjpTnZ3sScZqB6CjPkj/zQ3AxJQdJ05xMaRiPgt70j\ntJPiujm3gv2j48/fV8vZa3elDq3JcMTwb4xAmkpLIyU1gixQqhEQjni96DLH\nqtm7\r\n=r0Da\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIEQ39wvLAQYTxTAWFuygoIn18RoUbY3JatJ39M37/lKoAiEAz3/U81MFW8sR6DYamNp5UNyrT9Vf6yJDT4AYhaE7yng="}]},"maintainers":[{"name":"abatyuk","email":"andrey@maana.io"},{"name":"bzvetey","email":"bzvestey@gmail.com"},{"name":"rpovey","email":"rob@maana.io"},{"name":"teamcitymaana","email":"teamcity@maana.io"},{"name":"witt3rd","email":"witt3rd@witt3rd.com"}],"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/q-assistant-client_3.2.1-beta.7_1568405747992_0.7384548420126478"},"_hasShrinkwrap":false},"3.2.1-beta.8":{"name":"@io-maana/q-assistant-client","version":"3.2.1-beta.8","description":"JavaScript package to streamline communication between an assistant and the Maana Q Assistant API.","main":"build/AssistantAPIClient.js","scripts":{"build":"babel src --out-dir build","prepack":"npm run build","test":"echo \"Error: no test specified\" && exit 1"},"repository":{"type":"git","url":"git+https://github.com/maana-io/q-assistant-client.git"},"keywords":["Maana","Q"],"author":{"name":"Logan Gore @ Maana.io"},"license":"MIT","bugs":{"url":"https://github.com/maana-io/q-assistant-client/issues"},"homepage":"https://github.com/maana-io/q-assistant-client#readme","dependencies":{"post-robot":"^10.0.18"},"devDependencies":{"@babel/cli":"^7.5.5","@babel/core":"^7.5.5","@babel/plugin-proposal-class-properties":"^7.5.5","@babel/preset-env":"^7.5.5"},"readme":"# q-assistant-client\nA lightweight JavaScript client for Maana-Q Assistant developers that wraps post-message communication between an embedded Maana-Q assistant and the Maana-Q UI.\n\n## Usage\nThis is intented to be used in a web application being leveraged as a Maana Q assistant (embedded as an iframe).\nThis assistant client will facilitate communication between the assistant and the parent frame.\nThe client provides a rich, asynchronous experience over what would otherwise be 'fire-and-forget'-style messaging \nvia post-post message communication. \n\n## Requirements and Assumptions\n@TODO Logan\n\n## Singleton Instance\nThe client is exported as a singleton to avoid duplicate registration on event listeners.\nYou can import the instance like this:\n\n```js\nimport AssistantAPIClient from '@io-maana/q-assistant-client';\n```\n\n## Interacting with the API\n### API Surface Area\n\n### Function Calls\nFunction calls can be made against the client like any other javascript object. They are all async.\n```js\nconst workspace = await AssistantAPIClient.getWorkspace(); \nconsole.log(\"Workspace:\", workspace)\n\nconst functions = await workspace.getFunctions()\nconsole.log(\"Functions:\", functions)\n```\n\n### Event Subscription\nOnly workspace selection events are currently supported.\nSubscriptions are added explictly by registering a callback:\n```js\nAssistantAPIClient.addSelectionChangedListener((selection)=>{\n  console.log('Workspace selection changed:', selection)\n})\n```\n\nThese are removed on a per-callback basis with the 'removeSelectionChangedListener' call. \n\n## Dependencies\nPost-Robot\nhttps://github.com/krakenjs/post-robot\n\nPost-robot is used to provide a richer communication layer atop post-message.\n\n## Examples\n@TODO Logan\n\n## API Documentation\n@TODO Logan\nThis will presumably link to Gitbook Maana Q Documentation that explicates the full K Portal API functionality.\n","readmeFilename":"README.md","gitHead":"18cf4cc2a51727bdd2abc04a8e9485fab40c8951","_id":"@io-maana/q-assistant-client@3.2.1-beta.8","_npmVersion":"6.4.1","_nodeVersion":"10.15.3","_npmUser":{"name":"teamcitymaana","email":"teamcity@maana.io"},"dist":{"integrity":"sha512-cg/btPyI5488jp2HI/2wgSA+I5f1Cw9SDJ19AGgDFzpnQ7hb1bPf+/xY/rMf2Z5Aesx0inpd18Pnv11kXMxffg==","shasum":"be62af8db53d18f1d9c184088c3dcef7fa9bf023","tarball":"https://registry.npmjs.org/@io-maana/q-assistant-client/-/q-assistant-client-3.2.1-beta.8.tgz","fileCount":5,"unpackedSize":14472,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJdf98LCRA9TVsSAnZWagAAPwEP/2HRpwipzel6pVtXz/Ty\nh81WX9yOxj6GX9oVIUbYKhHwlJenry6wd3edhVuZQKxWIUkKpKjsSid5QwlP\nscKFCqAZC7dHMJXr9jA+nl+D7oWkV4I9cR7XMJTpnb2FqWNZs0GHz0/WhmoG\nkwhqYrXDzbKYr2jAu6JMO1nrfVvOJcm7evza0n3vBo2LFVYkzi8Yd0DWOesi\nT5K30WnzA67csp5BXuuS6ywRTkd+Wu4g9+UWDjNadwkgaDdcezVO1Z9O20bm\nCKIVqmpLo8mbnc1y03A4GZq/ww0RhUIgGn/NrCzPXbudZBCOXWTLDnwvS4CV\ng02ox77uKSRqEJK8LlEZFW//6BVGNygQYDBZxpObcqQPmuV7UIR80XXXuYbQ\nHgSF+rQIipaUV0ZUDa5zC61/FiDX/IMWMnY8Dy2u3FA7DRyrV4dnSANnBiB2\nxo78GL5jhn53eWo3aHEhMvWyqNvY1nXSrtTjU5Vu99xje0RabAdCuRCUmUsg\nY6v+BkZ8LVS4KLbrva+h/eRbhM6iAzQtOHqMLNnvSzamtIsuDJi4DCwAsB3l\nKz90tAt3GsCvsRiqU2LAZNjfgtqfXZYg4lXbZ7gsH8vXrUXtfC9Bl4CQQYY7\nW6bwo1SRjJDxtbGGjNY/CvljHQKoH1ml4O1JT3Mjf92/EFcViFtT7Wrr/OuR\ntklg\r\n=isky\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIQDoB6L6iQbPM8rmXLMNK/zafYnXJPbLpYbhZe2LyhiuQQIgVqTl9r8u5RBZzmdaZHDCcIjLUuCueWM05dfiGhGZZXQ="}]},"maintainers":[{"name":"abatyuk","email":"andrey@maana.io"},{"name":"bzvetey","email":"bzvestey@gmail.com"},{"name":"rpovey","email":"rob@maana.io"},{"name":"teamcitymaana","email":"teamcity@maana.io"},{"name":"witt3rd","email":"witt3rd@witt3rd.com"}],"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/q-assistant-client_3.2.1-beta.8_1568661258119_0.6845075522800246"},"_hasShrinkwrap":false},"3.2.1-beta.9":{"name":"@io-maana/q-assistant-client","version":"3.2.1-beta.9","description":"JavaScript package to streamline communication between an assistant and the Maana Q Assistant API.","main":"build/AssistantAPIClient.js","scripts":{"build":"babel src --out-dir build","prepack":"npm run build","test":"echo \"Error: no test specified\" && exit 1"},"repository":{"type":"git","url":"git+https://github.com/maana-io/q-assistant-client.git"},"keywords":["Maana","Q"],"author":{"name":"Logan Gore @ Maana.io"},"license":"MIT","bugs":{"url":"https://github.com/maana-io/q-assistant-client/issues"},"homepage":"https://github.com/maana-io/q-assistant-client#readme","dependencies":{"post-robot":"^10.0.18"},"devDependencies":{"@babel/cli":"^7.5.5","@babel/core":"^7.5.5","@babel/plugin-proposal-class-properties":"^7.5.5","@babel/preset-env":"^7.5.5"},"readme":"# q-assistant-client\nA lightweight JavaScript client for Maana-Q Assistant developers that wraps post-message communication between an embedded Maana-Q assistant and the Maana-Q UI.\n\n## Abstract\nThe Q-Assistant-Client is intented to be used in a web application being leveraged as a Maana Q assistant (embedded as an iframe).\nThis assistant client will facilitate communication between the assistant and the parent frame.\nThe client provides a rich, asynchronous experience over what would otherwise be 'fire-and-forget'-style messaging \nvia post-post message communication. \n\n## Requirements and Assumptions\n\n### Post-Robot Library\nThe Maana Knowledge Portal (KPortal) uses the kraken/post-robot library [kraken/post-robot](https://github.com/krakenjs/post-robot) to enrich the communication with the assistant. Post-robot allows for asynchronous, promise-based request/response style behavior between the assistant and the assistant API.\n\nThe API requires that the client use the post-robot library. This assistant-client library is the easiest way to achieve this, and also adds a fair amount of 'sugar' to the process to improve developer productivity. Developers could, however, use post-robot directly in their own client implementation. \n\n### Maana-Gateway Proxy Requirements\nThe Maana-Gateway service requires relative paths (paths relative to the root) in the assistant web application in order to proxy the application and its content. For create-react-apps, for instance, this means setting \"homepage\" to \".\" in the package.json file.\n\n## Singleton Instance\nThe client is exported as a singleton to avoid duplicate registration on event listeners.\nYou can import the instance like this:\n\n```js\nimport AssistantAPIClient from '@io-maana/q-assistant-client';\n```\n\nFunction calls can be made against the client instance like any other javascript object. They are all async.\n\n```js\nconst workspace = await AssistantAPIClient.getWorkspace(); \nconsole.log(\"Workspace:\", workspace)\n```\n\n## Dependencies\nPost-Robot\nhttps://github.com/krakenjs/post-robot\n\nPost-robot is used to provide a richer communication layer atop post-message.\n\n## Examples\n@TODO Logan\n\n## API Documentation\n\n### State management\n\n#### clearState = () =>\n\nThis will clear all ‘attached’ state between the assistant and the API. \n\nSpecifically, this will clear selection and inventory changed event listeners. \n\n```js\nawait AssistantAPIClient.clearState()\n```\n\n### User Info\nThe `UserInfo` object:\n```js\n{\n email: string,\n name: string\n}\n```\n\n#### getUserInfo = () => \n\nReturns a Userinfo object pertaining to the logged in user.\n\n```js\nconst userInfo = await AssistantAPIClient.getUserInfo()\n```\n### Selection\nThe `Selection` object:\n```js\n{\n  kindId: string\n  kindName: string\n  id: string\n}\n```\n\n#### getCurrentSelection = () => \n\nReturns an Array of `Selection` objects:\n\n```js\nconst {selection} = await AssistantAPIClient.getCurrentSelection();\n```\n\n#### addSelectionChangedListener = async cb =>\n\nAdds a callback function to be executed upon a valid workspace selection change.\n\nCallback value is an array of Selection objects:\n\n```js\n// Create the selection callback.\nconst selectionCB = ({selection})=>{\n  console.log('Workspace selection has changed.')\n  selection.forEach(i=>{\n    console.log('Kind: ',i.kindName)\n    console.log('Instance Id:',i.id)\n    console.log('Kind Id:',i.kindId)\n  })\n}\n\n// Add the listener.\nAssistantAPIClient.addSelectionChangedListener(selectionCB);\n```\n\nThis function only exists on the Q-Assistant-Client--only enableSelectionChangedNotification is called on the API. \n\n#### removeSelectionChangedListener = async cb =>\n\nThis will have to be called on a 1:1 basis with addSelectionChangedListener calls if supplying a callback.\n\n```js\nAssistantAPIClient.removeSelectionChangedListener(selectionCB)\n```\n\n**If NOT supplying a callback to this call, all selection changed listeners will be removed.\n\n```js\nAssistantAPIClient.removeSelectionChangedListener()\n```\n\nThis function only exists on the Q-Assistant-Client--only disableSelectionChangedNotification is called on the API. \n\n\n### Services\nThe `Service` object:\n```js\n{\n   id: string,\n   name: string\n   endpointUrl: string,\n   getKinds: () => // Returns [] of Kinds objects\n   getFunctions: () => // Returns [] of Function objects\n}\n```\n\n#### getServiceById = id =>\nThis will return a service that exists within the scope of the workspace. \n** Assistant services will return null. Services outside the scope of the workspace will cause an error to be returned as 'Unable to load a Service from outside of the workspace.'\n\n```js\nconst svc = await AssistantAPIClient.getServiceById(id)\n```\n\n### Workspace\nThe `Workspace` object:\n```js\n{\nid: string,\nname: string,\ngetKinds: () => {\n  // Returns an array of functions in the workspace (includes boilerplate).\n},\ngetFunctions: () =>\n  // Returns an array of functions in the workspace (includes boilerplate).\ngetActiveGraph: () => {\n  // Returns the active Graph object.\n},\ngetKnowledgeGraphs: () => {\n  // Returns [Graph]\n},\ngetImportedServices: () => {\n  // Returns an service imported into the workspace\n  // as a array of Service object (this calls the function\n  // that underlies getServiceById.\n  // No assistant services will be returned.\n}\n}\n```\n\n#### getWorkspace = () =>\n\nReturns a Workspace object representing the workspace. \n\n```js\nconst ws = await AssistantAPIClient.getWorkspace()\n```\n\n### Graphs\nThe `Graph` object:\n```js\n{     \nid,\nname,\ngetNodes: async () => {\n    // Returns [Node]\n},\n\naddNode: async (type, instance, changeSelection) => {\n    // Returns Node\n},\nremoveNode: async id => {\n    // Should return nothing or error.\n    // Currently returning [] in all cases.\n},\nupdateNodeLayout: async (nodeId, { x, y, collapsed }) => {\n    // Returns\n},\nupdateGraphLayout: async ({ offsetX, offsetY, zoom }) => {\n}\n}\n```\n\n#### Getting a graph object:\nGraph objects are obtained through an instance of a Workspace \n\n```js\nconst ag = await ws.getActiveGraph()\n```\n\nor\n\n```js\nconst kgs = await ws.getKnowledgeGraphs()\n```\n\n#### Manipulating Graphs\n\n**Only the active graph may be manipulated.\n\nAll graph manipulations should be ‘visually’ verifiable on the graph itself, i.e., adds/removes/positioning, should all be reflected on the graph itself. \n\nThe `Node` object:\n```js\n{\nid: string\nx: number\ny: number\ncollapsed: boolean\nknowledgeGraphNode {\n  id: string\n  innerKind: Kind\n  innerFunction: Function\n}\n}\n```\n\n#### addNode(type, instance, changeSelection) =>\n\nTakes type (“Function” or “Kind”), instance (the Function or Kind object), and optionally a boolean to indicate whether the selection should be changed to this new node. \n\nReturns the newly created Node object.\n\n```js\nconst node = await ag.addNode('Kind',kind)\n```\n\n#### removeNode(id) =>\n\nTakes the id of Node to be deleted. Returns either undefined or an error. \n\n```js\nawait ag.removeNode(node.id)\n```\n\n#### getNodes() =>\nReturns an array of Node objects from the graph. \n\n```js\nconst nodes = await ag.getNodes()\n```\n\n#### updateNodeLayout: async (nodeId, { x, y, collapsed})=>\n\nUpdates a Node layout given a node ID and node coordinates (`x` and/or `y`) or a `collapsed` value. x/y values must be a number, and collapsed must be a boolean. Whatever is not specified will remain current.\n\n```js\nag.updateNodeLayout(id,{x:100,y:100,collapsed:true})\n```\n\n#### updateGraphLayout: async ({ offsetX, offsetY, zoom})=>\n\nUpdates a Graph layout given numerical values for x/y offsets and the zoom. \n\n```js\nag.updateGraphLayout({offsetX:50, offsetY:50, zoom: 70})\n```\n\n### Functions\n\nThe `Function` object:\n```js\n{\n    id: string\n    name: string\n    service {\n      id: string\n      name: string\n    }\n    arguments {\n      id: string\n      name: string\n      type: string\n      modifiers: Array[string]\n      typeKindId:: string\n      kind {\n        id: string\n        name: string\n      }\n    }\n    isGenerated: boolean\n    outputType: string\n    outputKindId: string\n    outputModifiers: Array[string]\n    kind {\n      id: string\n      name: string\n    }\n}\n```\n\n`FunctionExecutionResult` object:\n```js\n{\n  id: string,\n  result: JSON\n}\n```\n\n#### executeFunction = ( {id, variables, resolve} ) =>\n\nExecutes a function based on its id, with optional inputs for variables and a resolve string (this specifies the fields to be returned, which must be valid based on the result).\n\nReturns : JSON matching shape of result , unless no sub-selection of fields is required in the execution.\n\nThis following piece of code will execute a Function given a function ID, and pass in variables for ‘example’, requesting back id and name fields. \n\n```js \nconst res = await AssistantAPIClient.executeFunction({functionId: func.id, variables: {example: \"example\"}, resolve: \"{ id name }\");\n```\n\n#### createFunction = input =>\n\nCreates a function based on the input provided. \n\nReturns: the created Function object.\n\n**Using create function will only place the function in the workspace’s inventory--it will not place the function as a node on the Graph. In order to do this, you must pass the created function into the addNode function on the active Graph, making sure to specify ‘Function' as the type.\n\n```js\nconst createFunctionInput = {\n  name:\"yourName\",\n  arguments:[],\n  outputType: \"STRING\",\n  graphqlOperationType:\"QUERY\",\n  functionType: \"PROJECTION\"\n}\n  \nconst createdFunction = await AssistantAPIClient.createFunction(createFunctionInput)\n```\n\n#### updateFunction = input =>\n\nInput is the same for creating a function. It’s important to note that the arguments property will be replaced in it’s entirety with whatever is provided (if a value is provided.\n\n@TODO: Return value\n\n```js\nconst updatedFunction = await AssistantAPIClient.updateFunction(input);\n```\n\n#### deleteFunction = input =>\n\nInput is the id of the Function to be deleted. Returns the deleted function as a promise.\n\n```js\nconst deletedFunction = await AssistantAPIClient.deleteFunction('id...');\n```\n\n#### getFunctionById = id =>\n\nReturns a Function as a promise based on the ID provided.\n\n```js\nconst func = await AssistantAPIClient.getFunctionById('id...');\n```\n\n#### addFunctionExecutionListener = async (id, cb) =>\n\nAssociates a callback function with the execution of a particular Function. When the Function matching the id parameter is executed, its FunctionExecutionResult object passed to the callback. Returns undefined.\n\nExample function execution callback and listener registration:\n\n```js\nfunction exampleFunctionCB (result){\n  console.log(`Function executed with result:`, result)\n}\n\nAssistantAPIClient.addFunctionExecutionListener('id...', exampleFunctionCB)\n```\n\n#### removeFunctionExecutionListener = async (id, cb) =>\n\nRemoves a Function execution listener based on the function ID and a reference to the callback function. If no callback is supplied, all listeners associated with the Function ID will be removed. Returns undefined.\n\n```js\nAssistantAPIClient.removeFunctionExecutionListener('id..', exampleFunctionCB)\n```\n\n### Kinds\nThe `Kind` object:\n```js\n{\n    id: string\n    name: string\n    service: {\n      id\n      name\n    }\n    isGenerated: boolean\n    schema {\n      id: string\n      name: string\n      type: string\n      typeKindId: string\n      modifiers: Array[string]\n      kind {\n        id: string\n        name: string\n      }\n    }\n}\n```\n\n#### createKind = input =>\n\nCreates a Kind based on an input object. Returns a promise that resolves to the created Kind object.\n\n```js\nconst kindInput = {\n name: \"someKind\",\n schema:[\n  { name: \"someField1\", type: STRING },\n  { name: \"someField2\", type: STRING }\n ]\n}\n\nconst newKind = await AssistantAPIClient.createKind(kindInput)\n```\n\n#### updateKind = input =>\n\n@TODO return value\n\nUpdates a Kind based on an input object. \n\nUpdate Semantics: Only properties specified will be updated. If updating the schema, the entire schema must be specified as it will be replaced in its entirety. \n\n```js\nconst updated = await AssistantAPIClient.updateKind(input)\n```\n\n#### deleteKind = input =>\n\nDeletes a Kind given a kind ID.\n\n```js\nconst deleted = await AssistantAPIClient.deleteKind(input)\n```\n\n#### getKindById = id =>\n\nReturns a promise that resolves to a Kind object given the specified kind ID. Only kinds in the workspace or those of imported services will be returned. \n\n```js\nconst kind = await AssistantAPIClient.getKindById(id)\n```\n\n### Inventory\n\nThe `InventoryChanged` object:\n```js\n{\n  kinds: {\n    adds: [DiffItem]\n    deletes: [DiffItem]\n    updates: [DiffItem]\n  }\n  functions:{\n    adds: [DiffItem]\n    deletes: [DiffItem]\n    updates: [DiffItem]\n  }\n  services: {\n    adds: [DiffItem]\n    deletes: [DiffItem]\n    updates: [DiffItem]\n  }\n}\n```\n\nThe `DiffItem` object:\n```js\n{\n  id: string,\n  name: string\n}\n```\n\n#### addInventoryChangedListener = async cb =>\n\nRegisters a callback function with the inventory changed event. When workspace inventory changes the callback function will be called with the InventoryChangedobject. Returns undefined.\n\n*Current limitations: Kind and Function updates only occur where the name property is changed. Updates to services outside of the workspace will not be detected. \n\n**Use-case note: an ‘update’ diff for inventory services is unlikely in general usage. \n\n```js\nconst inventoryCB = ({diff}) => {\n  if(diff.kinds) console.log('KINDS CHANGED',diff.kinds)\n  if(diff.functions) console.log('FUNCTIONS CHANGED', diff.functions)\n  if(diff.services) console.log('SERVICES CHANGED',diff.services)\n}\n\nAssistantAPIClient.addInventoryChangedListener(inventoryCB)\n```\n\nThis function exists on the Q-Assisant-Client only--only enableSelectionChangedNotification is used on the API side. \n\n#### removeInventoryChangedListener = async cb =>\n\nRemoves an inventory changed listener given the referenced callback. If no callback is specified, all listeners will be removed. Returns undefined.\n\n```js\nAssistantAPIClient.removeInventoryChangedListener(inventoryCB)\n```\n\nThis function exists on the Q-Assisant-Client only--only disableSelectionChangedNotification is used on the API side. \n\n## Troubleshooting Assistant Issues\n### Assistant root file has loaded, but not other content\nObserving in the browser's dev tools that some resources have loaded correctly (usually the root), but other's haven't (usually nested files or chunks), is indicative of a failure of Q Gateway to proxy due to not having a 'relative' path structure.\n\n### You are seeing post-robot `NO ACK` errors in the console.\nThese errors stem from a failed acknowledgement for a call either between the client and the API or vice-versa. Ensure that your window and window.parent objects are valid and they are able to communicate with one another.","readmeFilename":"README.md","gitHead":"abca0ab0db6ff001f718be9b67fbea860da06b16","_id":"@io-maana/q-assistant-client@3.2.1-beta.9","_npmVersion":"6.4.1","_nodeVersion":"10.15.3","_npmUser":{"name":"teamcitymaana","email":"teamcity@maana.io"},"dist":{"integrity":"sha512-xVf2nkahY0n4TuUi0QkzbT7rgEAP3e0TYRmoi206N6VG8Hmb0ySzhTnLrFGKNN+VUlZgnauVWRd0Tb7J4ys/pQ==","shasum":"fa754d3b3053744f756d5d9812997adf0f5ed253","tarball":"https://registry.npmjs.org/@io-maana/q-assistant-client/-/q-assistant-client-3.2.1-beta.9.tgz","fileCount":5,"unpackedSize":27311,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJdk7YSCRA9TVsSAnZWagAAtjUQAKUn7uP5tLGC6pMEPAdV\nY9q7Z0fggSHvdF+RJ4B70+F1EG1De3AYQoZVuCnDfPN4wAgIb2Fc444s6104\nRej2BOtBXxUEQjCVLLt/NGD/togaclOyY9HrJQoHdb4rPSLWD5wuA6fhz0G6\naQSXylFgqnXkVe7ZUmRqmO4dtH1jab+huAB7qTkTO3K4b/Q5NB1klsdP7x3b\ngRd2wX/SqarYwdu6m6m62Aml11zrsySTVcYXO2tXbhbXJCxRVwJK55GeQOIX\nhcSdKjioc/UAP2WZF39HydqSCaFtX4j9eKL6u5vQrt8N4AVbFu12wKWLuUhD\nWzKADJZgZlIqzY7dzaxKFapZpX6VJt31iJmCXVaO8Kq8gdoGHiFhK9n3+Fw+\naYLP/WgIRG9HeagKgGYZ+xVRGS/UqoQ1r0POg84Uad7eW9GxTQnH2sKQz6+z\nJQgmFqx9Jq17YoAatZQl5XRDQA/J6LxyPRr+1UaOQT+RRTzPFniVIs5c+P3Y\n9H8BelF1zEoL7h/BUVR5abXwuVfEpDeRtJIfk5rIN70QGkFIOeuYU/7ODC9X\nHuq7033lm96RbOMZkjGiyj0D1egvaxDBhxxUqeRmR7EDgwqa0SNWlIFCkWcb\ngSTod8tCgEpE+dJB2vfpdEtSNuahmsOphE8fUmfpDm1r0cRwEJGEMXWc5k9O\nYsfU\r\n=E+q0\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIG2x3/6kRSDdt5S7svY3N6XrBzfvqM/3wuv0Qg6i1F+oAiEA2pIgUQunu7S7akYAWKXn0rX/bJw4vdXde1R1k5gaFvI="}]},"maintainers":[{"name":"abatyuk","email":"andrey@maana.io"},{"name":"bzvetey","email":"bzvestey@gmail.com"},{"name":"rpovey","email":"rob@maana.io"},{"name":"teamcitymaana","email":"teamcity@maana.io"},{"name":"witt3rd","email":"witt3rd@witt3rd.com"}],"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/q-assistant-client_3.2.1-beta.9_1569961490084_0.05760526512579989"},"_hasShrinkwrap":false},"3.2.1-beta.10":{"name":"@io-maana/q-assistant-client","version":"3.2.1-beta.10","description":"JavaScript package to streamline communication between an assistant and the Maana Q Assistant API.","main":"build/AssistantAPIClient.js","scripts":{"build":"babel src --out-dir build","prepack":"npm run build","test":"echo \"Error: no test specified\" && exit 1"},"repository":{"type":"git","url":"git+https://github.com/maana-io/q-assistant-client.git"},"keywords":["Maana","Q"],"author":{"name":"Logan Gore @ Maana.io"},"license":"MIT","bugs":{"url":"https://github.com/maana-io/q-assistant-client/issues"},"homepage":"https://github.com/maana-io/q-assistant-client#readme","dependencies":{"post-robot":"^10.0.18"},"devDependencies":{"@babel/cli":"^7.5.5","@babel/core":"^7.5.5","@babel/plugin-proposal-class-properties":"^7.5.5","@babel/preset-env":"^7.5.5"},"readme":"# q-assistant-client\nA lightweight JavaScript client for Maana-Q Assistant developers that wraps post-message communication between an embedded Maana-Q assistant and the Maana-Q UI.\n\n## Abstract\nThe Q-Assistant-Client is intented to be used in a web application being leveraged as a Maana Q assistant (embedded as an iframe).\nThis assistant client will facilitate communication between the assistant and the parent frame.\nThe client provides a rich, asynchronous experience over what would otherwise be 'fire-and-forget'-style messaging \nvia post-post message communication. \n\n## Requirements and Assumptions\n\n### Post-Robot Library\nThe Maana Knowledge Portal (KPortal) uses the kraken/post-robot library [kraken/post-robot](https://github.com/krakenjs/post-robot) to enrich the communication with the assistant. Post-robot allows for asynchronous, promise-based request/response style behavior between the assistant and the assistant API.\n\nThe API requires that the client use the post-robot library. This assistant-client library is the easiest way to achieve this, and also adds a fair amount of 'sugar' to the process to improve developer productivity. Developers could, however, use post-robot directly in their own client implementation. \n\n### Maana-Gateway Proxy Requirements\nThe Maana-Gateway service requires relative paths (paths relative to the root) in the assistant web application in order to proxy the application and its content. For create-react-apps, for instance, this means setting \"homepage\" to \".\" in the package.json file.\n\n## Singleton Instance\nThe client is exported as a singleton to avoid duplicate registration on event listeners.\nYou can import the instance like this:\n\n```js\nimport AssistantAPIClient from '@io-maana/q-assistant-client';\n```\n\nFunction calls can be made against the client instance like any other javascript object. They are all async.\n\n```js\nconst workspace = await AssistantAPIClient.getWorkspace(); \nconsole.log(\"Workspace:\", workspace)\n```\n\n## Dependencies\nPost-Robot\nhttps://github.com/krakenjs/post-robot\n\nPost-robot is used to provide a richer communication layer atop post-message.\n\n## Examples\n@TODO Logan\n\n## API Documentation\n\n### State management\n\n#### clearState = () =>\n\nThis will clear all ‘attached’ state between the assistant and the API. \n\nSpecifically, this will clear selection and inventory changed event listeners. \n\n```js\nawait AssistantAPIClient.clearState()\n```\n\n### User Info\nThe `UserInfo` object:\n```js\n{\n email: string,\n name: string\n}\n```\n\n#### getUserInfo = () => \n\nReturns a Userinfo object pertaining to the logged in user.\n\n```js\nconst userInfo = await AssistantAPIClient.getUserInfo()\n```\n### Selection\nThe `Selection` object:\n```js\n{\n  kindId: string\n  kindName: string\n  id: string\n}\n```\n\n#### getCurrentSelection = () => \n\nReturns an Array of `Selection` objects:\n\n```js\nconst {selection} = await AssistantAPIClient.getCurrentSelection();\n```\n\n#### addSelectionChangedListener = async cb =>\n\nAdds a callback function to be executed upon a valid workspace selection change.\n\nCallback value is an array of Selection objects:\n\n```js\n// Create the selection callback.\nconst selectionCB = ({selection})=>{\n  console.log('Workspace selection has changed.')\n  selection.forEach(i=>{\n    console.log('Kind: ',i.kindName)\n    console.log('Instance Id:',i.id)\n    console.log('Kind Id:',i.kindId)\n  })\n}\n\n// Add the listener.\nAssistantAPIClient.addSelectionChangedListener(selectionCB);\n```\n\nThis function only exists on the Q-Assistant-Client--only enableSelectionChangedNotification is called on the API. \n\n#### removeSelectionChangedListener = async cb =>\n\nThis will have to be called on a 1:1 basis with addSelectionChangedListener calls if supplying a callback.\n\n```js\nAssistantAPIClient.removeSelectionChangedListener(selectionCB)\n```\n\n**If NOT supplying a callback to this call, all selection changed listeners will be removed.\n\n```js\nAssistantAPIClient.removeSelectionChangedListener()\n```\n\nThis function only exists on the Q-Assistant-Client--only disableSelectionChangedNotification is called on the API. \n\n\n### Services\nThe `Service` object:\n```js\n{\n   id: string,\n   name: string\n   endpointUrl: string,\n   getKinds: () => // Returns [] of Kinds objects\n   getFunctions: () => // Returns [] of Function objects\n}\n```\n\n#### getServiceById = id =>\nThis will return a service that exists within the scope of the workspace. \n** Assistant services will return null. Services outside the scope of the workspace will cause an error to be returned as 'Unable to load a Service from outside of the workspace.'\n\n```js\nconst svc = await AssistantAPIClient.getServiceById(id)\n```\n\n### Workspace\nThe `Workspace` object:\n```js\n{\nid: string,\nname: string,\ngetKinds: () => {\n  // Returns an array of functions in the workspace (includes boilerplate).\n},\ngetFunctions: () =>\n  // Returns an array of functions in the workspace (includes boilerplate).\ngetActiveGraph: () => {\n  // Returns the active Graph object.\n},\ngetKnowledgeGraphs: () => {\n  // Returns [Graph]\n},\ngetImportedServices: () => {\n  // Returns an service imported into the workspace\n  // as a array of Service object (this calls the function\n  // that underlies getServiceById.\n  // No assistant services will be returned.\n}\n}\n```\n\n#### getWorkspace = () =>\n\nReturns a Workspace object representing the workspace. \n\n```js\nconst ws = await AssistantAPIClient.getWorkspace()\n```\n\n### Graphs\nThe `Graph` object:\n```js\n{     \nid,\nname,\ngetNodes: async () => {\n    // Returns [Node]\n},\n\naddNode: async (type, instance, changeSelection) => {\n    // Returns Node\n},\nremoveNode: async id => {\n    // Should return nothing or error.\n    // Currently returning [] in all cases.\n},\nupdateNodeLayout: async (nodeId, { x, y, collapsed }) => {\n    // Returns\n},\nupdateGraphLayout: async ({ offsetX, offsetY, zoom }) => {\n}\n}\n```\n\n#### Getting a graph object:\nGraph objects are obtained through an instance of a Workspace \n\n```js\nconst ag = await ws.getActiveGraph()\n```\n\nor\n\n```js\nconst kgs = await ws.getKnowledgeGraphs()\n```\n\n#### Manipulating Graphs\n\n**Only the active graph may be manipulated.\n\nAll graph manipulations should be ‘visually’ verifiable on the graph itself, i.e., adds/removes/positioning, should all be reflected on the graph itself. \n\nThe `Node` object:\n```js\n{\nid: string\nx: number\ny: number\ncollapsed: boolean\nknowledgeGraphNode {\n  id: string\n  innerKind: Kind\n  innerFunction: Function\n}\n}\n```\n\n#### addNode(type, instance, changeSelection) =>\n\nTakes type (“Function” or “Kind”), instance (the Function or Kind object), and optionally a boolean to indicate whether the selection should be changed to this new node. \n\nReturns the newly created Node object.\n\n```js\nconst node = await ag.addNode('Kind',kind)\n```\n\n#### removeNode(id) =>\n\nTakes the id of Node to be deleted. Returns either undefined or an error. \n\n```js\nawait ag.removeNode(node.id)\n```\n\n#### getNodes() =>\nReturns an array of Node objects from the graph. \n\n```js\nconst nodes = await ag.getNodes()\n```\n\n#### updateNodeLayout: async (nodeId, { x, y, collapsed})=>\n\nUpdates a Node layout given a node ID and node coordinates (`x` and/or `y`) or a `collapsed` value. x/y values must be a number, and collapsed must be a boolean. Whatever is not specified will remain current.\n\n```js\nag.updateNodeLayout(id,{x:100,y:100,collapsed:true})\n```\n\n#### updateGraphLayout: async ({ offsetX, offsetY, zoom})=>\n\nUpdates a Graph layout given numerical values for x/y offsets and the zoom. \n\n```js\nag.updateGraphLayout({offsetX:50, offsetY:50, zoom: 70})\n```\n\n### Functions\n\nThe `Function` object:\n```js\n{\n    id: string\n    name: string\n    service {\n      id: string\n      name: string\n    }\n    arguments {\n      id: string\n      name: string\n      type: string\n      modifiers: Array[string]\n      typeKindId:: string\n      kind {\n        id: string\n        name: string\n      }\n    }\n    implementation {\n      id: string\n      entrypoint {\n        id: string\n      }\n      operations {\n        id: string\n        type: string\n        function {\n          id: string\n          name: string\n        }\n        argumentValues {\n          id: string\n          argument {\n            id: string\n          }\n          operation {\n            id: string\n          }\n          argumentRef: string\n        }\n      }\n    }\n    isGenerated: boolean\n    outputType: string\n    outputKindId: string\n    outputModifiers: Array[string]\n    kind {\n      id: string\n      name: string\n    }\n}\n```\n\n`FunctionExecutionResult` object:\n```js\n{\n  id: string,\n  result: JSON\n}\n```\n\n#### executeFunction = ( {id, variables, resolve} ) =>\n\nExecutes a function based on its id, with optional inputs for variables and a resolve string (this specifies the fields to be returned, which must be valid based on the result).\n\nReturns : JSON matching shape of result , unless no sub-selection of fields is required in the execution.\n\nThis following piece of code will execute a Function given a function ID, and pass in variables for ‘example’, requesting back id and name fields. \n\n```js \nconst res = await AssistantAPIClient.executeFunction({functionId: func.id, variables: {\"variableName\": \"variableValue\"}, resolve: \"{ id name }\");\n```\n\n#### createFunction = input =>\n\nCreates a function based on the input provided. \n\nReturns: the created Function object.\n\n**Using create function will only place the function in the workspace’s inventory--it will not place the function as a node on the Graph. In order to do this, you must pass the created function into the addNode function on the active Graph, making sure to specify ‘Function' as the type.\n\n```js\nconst createFunctionInput = {\n  name:\"yourName\",\n  arguments:[],\n  outputType: \"STRING\",\n  graphqlOperationType:\"QUERY\",\n  functionType: \"PROJECTION\"\n}\n  \nconst createdFunction = await AssistantAPIClient.createFunction(createFunctionInput)\n```\n\n#### updateFunction = input =>\n\nInput is the same for creating a function. It’s important to note that the arguments property will be replaced in it’s entirety with whatever is provided (if a value is provided.\n\n@TODO: Return value\n\n```js\nconst updatedFunction = await AssistantAPIClient.updateFunction(input);\n```\n\n#### deleteFunction = input =>\n\nInput is the id of the Function to be deleted. Returns the deleted function as a promise.\n\n```js\nconst deletedFunction = await AssistantAPIClient.deleteFunction('id...');\n```\n\n#### getFunctionById = id =>\n\nReturns a Function as a promise based on the ID provided.\n\n```js\nconst func = await AssistantAPIClient.getFunctionById('id...');\n```\n\n#### addFunctionExecutionListener = async (id, cb) =>\n\nAssociates a callback function with the execution of a particular Function. When the Function matching the id parameter is executed, its FunctionExecutionResult object passed to the callback. Returns undefined.\n\nExample function execution callback and listener registration:\n\n```js\nfunction exampleFunctionCB (result){\n  console.log(`Function executed with result:`, result)\n}\n\nAssistantAPIClient.addFunctionExecutionListener('id...', exampleFunctionCB)\n```\n\n#### removeFunctionExecutionListener = async (id, cb) =>\n\nRemoves a Function execution listener based on the function ID and a reference to the callback function. If no callback is supplied, all listeners associated with the Function ID will be removed. Returns undefined.\n\n```js\nAssistantAPIClient.removeFunctionExecutionListener('id..', exampleFunctionCB)\n```\n\n### Kinds\nThe `Kind` object:\n```js\n{\n    id: string\n    name: string\n    service: {\n      id\n      name\n    }\n    isGenerated: boolean\n    schema {\n      id: string\n      name: string\n      type: string\n      typeKindId: string\n      modifiers: Array[string]\n      kind {\n        id: string\n        name: string\n      }\n    }\n}\n```\n\n#### createKind = input =>\n\nCreates a Kind based on an input object. Returns a promise that resolves to the created Kind object.\n\n```js\nconst kindInput = {\n name: \"someKind\",\n schema:[\n  { name: \"someField1\", type: STRING },\n  { name: \"someField2\", type: STRING }\n ]\n}\n\nconst newKind = await AssistantAPIClient.createKind(kindInput)\n```\n\n#### updateKind = input =>\n\n@TODO return value\n\nUpdates a Kind based on an input object. \n\nUpdate Semantics: Only properties specified will be updated. If updating the schema, the entire schema must be specified as it will be replaced in its entirety. \n\n```js\nconst updated = await AssistantAPIClient.updateKind(input)\n```\n\n#### deleteKind = input =>\n\nDeletes a Kind given a kind ID.\n\n```js\nconst deleted = await AssistantAPIClient.deleteKind(input)\n```\n\n#### getKindById = id =>\n\nReturns a promise that resolves to a Kind object given the specified kind ID. Only kinds in the workspace or those of imported services will be returned. \n\n```js\nconst kind = await AssistantAPIClient.getKindById(id)\n```\n\n### Inventory\n\nThe `InventoryChanged` object:\n```js\n{\n  kinds: {\n    adds: [DiffItem]\n    deletes: [DiffItem]\n    updates: [DiffItem]\n  }\n  functions:{\n    adds: [DiffItem]\n    deletes: [DiffItem]\n    updates: [DiffItem]\n  }\n  services: {\n    adds: [DiffItem]\n    deletes: [DiffItem]\n    updates: [DiffItem]\n  }\n}\n```\n\nThe `DiffItem` object:\n```js\n{\n  id: string,\n  name: string\n}\n```\n\n#### addInventoryChangedListener = async cb =>\n\nRegisters a callback function with the inventory changed event. When workspace inventory changes the callback function will be called with the InventoryChangedobject. Returns undefined.\n\n*Current limitations: Kind and Function updates only occur where the name property is changed. Updates to services outside of the workspace will not be detected. \n\n**Use-case note: an ‘update’ diff for inventory services is unlikely in general usage. \n\n```js\nconst inventoryCB = ({diff}) => {\n  if(diff.kinds) console.log('KINDS CHANGED',diff.kinds)\n  if(diff.functions) console.log('FUNCTIONS CHANGED', diff.functions)\n  if(diff.services) console.log('SERVICES CHANGED',diff.services)\n}\n\nAssistantAPIClient.addInventoryChangedListener(inventoryCB)\n```\n\nThis function exists on the Q-Assisant-Client only--only enableSelectionChangedNotification is used on the API side. \n\n#### removeInventoryChangedListener = async cb =>\n\nRemoves an inventory changed listener given the referenced callback. If no callback is specified, all listeners will be removed. Returns undefined.\n\n```js\nAssistantAPIClient.removeInventoryChangedListener(inventoryCB)\n```\n\nThis function exists on the Q-Assisant-Client only--only disableSelectionChangedNotification is used on the API side. \n\n## Troubleshooting Assistant Issues\n### Assistant root file has loaded, but not other content\nObserving in the browser's dev tools that some resources have loaded correctly (usually the root), but other's haven't (usually nested files or chunks), is indicative of a failure of Q Gateway to proxy due to not having a 'relative' path structure.\n\n### You are seeing post-robot `NO ACK` errors in the console.\nThese errors stem from a failed acknowledgement for a call either between the client and the API or vice-versa. Ensure that your window and window.parent objects are valid and they are able to communicate with one another.","readmeFilename":"README.md","gitHead":"748cfb0c8728b15ab39cb71727b39330f2c989a5","_id":"@io-maana/q-assistant-client@3.2.1-beta.10","_npmVersion":"6.4.1","_nodeVersion":"10.15.3","_npmUser":{"name":"teamcitymaana","email":"teamcity@maana.io"},"dist":{"integrity":"sha512-1KYdyklkHCeF+S/7UW0EirrQO0P9KaEnmtyHFSdpjRqyawfHiuHPE4GIdyuDjhS9AZFlaejBUBE39og9fd74xw==","shasum":"8c0b754cd11d339d1118239b970ad1a96ab5010f","tarball":"https://registry.npmjs.org/@io-maana/q-assistant-client/-/q-assistant-client-3.2.1-beta.10.tgz","fileCount":5,"unpackedSize":27754,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJdlsCQCRA9TVsSAnZWagAAiuQP/0m/2yI4+brdQBLuhtvk\n2nvZ9G7ej2WIJy+GoCYAFptftLhjn0Yu66vDr2Z875/nT3/Q4CJEHiI4LJl1\nnyCx+8bWeqo0djbS8ZZiZ8+scBrKoG2VEpbaG3p1JKCSx5KJ/bUV60ZJBM7S\nkAwGksZXnZvCba11+IkapNcrEFadkUPLB8MBuuf/Jn06FFcn/HW8vs9bJoGC\nkOik5JqyvmECrTfZ8dcnU/fcEUkl5gE1u8/l+Z1l6YoafvOuJ4qZVkjKK04J\naF4hWH4bnXWfloZ9ap0UBBPWiDPDw+jFjYrlc9btER/6gXCM5x7RUAY93xCc\nHht5/y9dcRFBNxTHtm5cXIkmzs/qL5uRc65wTunJgwrCCUELbjYcKT4DA4P0\n8Jng5DOpGbpDJjxlJz8vcWrMijNPF+m12iEWr+zwzN+mumljTcTbFsk+ejsn\nZ/6UtORU2p7V2KazXdQCEaokx6k7AgaYpQpmzfgwlWIyrXoP3lNAOnfAPEIg\nd19PDohB6A40RvqF+BU7kUfhbKwCFaP5R/SnfpiWxUN8xjJh5HNRXRl51kdc\nmu6lC3F1VRTRkR8Mtv/IRyW5YB5oK+Ph5axgFCtcKtcFXPukAg6WvMwLLkEE\nSOrhp9afLIKNQT/i2dSDQ9shGAnYRUInvQY+n0DbjbtU8uvUDhk6OTcj7zjk\n8v3x\r\n=xBZ3\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEYCIQDN1xK5cpTPn9gAJqS5pfUwR5JZxN4G+A4v1Mvi0vOsIAIhAKzlOYgLWkZXXFDm9SKz7obtdKxcqIODnVfr1jHV8vla"}]},"maintainers":[{"name":"abatyuk","email":"andrey@maana.io"},{"name":"bzvetey","email":"bzvestey@gmail.com"},{"name":"rpovey","email":"rob@maana.io"},{"name":"teamcitymaana","email":"teamcity@maana.io"},{"name":"witt3rd","email":"witt3rd@witt3rd.com"}],"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/q-assistant-client_3.2.1-beta.10_1570160783808_0.8716090766783975"},"_hasShrinkwrap":false},"3.2.1-beta.11":{"name":"@io-maana/q-assistant-client","version":"3.2.1-beta.11","description":"JavaScript package to streamline communication between an assistant and the Maana Q Assistant API.","main":"build/AssistantAPIClient.js","scripts":{"build":"babel src --out-dir build","prepack":"npm run build","test":"echo \"Error: no test specified\" && exit 1"},"repository":{"type":"git","url":"git+https://github.com/maana-io/q-assistant-client.git"},"keywords":["Maana","Q"],"author":{"name":"Logan Gore @ Maana.io"},"license":"MIT","bugs":{"url":"https://github.com/maana-io/q-assistant-client/issues"},"homepage":"https://github.com/maana-io/q-assistant-client#readme","dependencies":{"post-robot":"^10.0.18"},"devDependencies":{"@babel/cli":"^7.5.5","@babel/core":"^7.5.5","@babel/plugin-proposal-class-properties":"^7.5.5","@babel/preset-env":"^7.5.5"},"readme":"# q-assistant-client\nA lightweight JavaScript client for Maana-Q Assistant developers that wraps post-message communication between an embedded Maana-Q assistant and the Maana-Q UI.\n\n## Abstract\nThe Q-Assistant-Client is intented to be used in a web application being leveraged as a Maana Q assistant (embedded as an iframe).\nThis assistant client will facilitate communication between the assistant and the parent frame.\nThe client provides a rich, asynchronous experience over what would otherwise be 'fire-and-forget'-style messaging \nvia post-post message communication. \n\n## Requirements and Assumptions\n\n### Post-Robot Library\nThe Maana Knowledge Portal (KPortal) uses the kraken/post-robot library [kraken/post-robot](https://github.com/krakenjs/post-robot) to enrich the communication with the assistant. Post-robot allows for asynchronous, promise-based request/response style behavior between the assistant and the assistant API.\n\nThe API requires that the client use the post-robot library. This assistant-client library is the easiest way to achieve this, and also adds a fair amount of 'sugar' to the process to improve developer productivity. Developers could, however, use post-robot directly in their own client implementation. \n\n### Maana-Gateway Proxy Requirements\nThe Maana-Gateway service requires relative paths (paths relative to the root) in the assistant web application in order to proxy the application and its content. For create-react-apps, for instance, this means setting \"homepage\" to \".\" in the package.json file.\n\n## Singleton Instance\nThe client is exported as a singleton to avoid duplicate registration on event listeners.\nYou can import the instance like this:\n\n```js\nimport AssistantAPIClient from '@io-maana/q-assistant-client';\n```\n\nFunction calls can be made against the client instance like any other javascript object. They are all async.\n\n```js\nconst workspace = await AssistantAPIClient.getWorkspace(); \nconsole.log(\"Workspace:\", workspace)\n```\n\n## Dependencies\nPost-Robot\nhttps://github.com/krakenjs/post-robot\n\nPost-robot is used to provide a richer communication layer atop post-message.\n\n## Examples\n@TODO Logan\n\n## API Documentation\n\n### State management\n\n#### clearState = () =>\n\nThis will clear all ‘attached’ state between the assistant and the API. \n\nSpecifically, this will clear selection and inventory changed event listeners. \n\n```js\nawait AssistantAPIClient.clearState()\n```\n\n### User Info\nThe `UserInfo` object:\n```js\n{\n email: string,\n name: string\n}\n```\n\n#### getUserInfo = () => \n\nReturns a Userinfo object pertaining to the logged in user.\n\n```js\nconst userInfo = await AssistantAPIClient.getUserInfo()\n```\n### Selection\nThe `Selection` object:\n```js\n{\n  kindId: string\n  kindName: string\n  id: string\n}\n```\n\n#### getCurrentSelection = () => \n\nReturns an Array of `Selection` objects:\n\n```js\nconst {selection} = await AssistantAPIClient.getCurrentSelection();\n```\n\n#### addSelectionChangedListener = async cb =>\n\nAdds a callback function to be executed upon a valid workspace selection change.\n\nCallback value is an array of Selection objects:\n\n```js\n// Create the selection callback.\nconst selectionCB = ({selection})=>{\n  console.log('Workspace selection has changed.')\n  selection.forEach(i=>{\n    console.log('Kind: ',i.kindName)\n    console.log('Instance Id:',i.id)\n    console.log('Kind Id:',i.kindId)\n  })\n}\n\n// Add the listener.\nAssistantAPIClient.addSelectionChangedListener(selectionCB);\n```\n\nThis function only exists on the Q-Assistant-Client--only enableSelectionChangedNotification is called on the API. \n\n#### removeSelectionChangedListener = async cb =>\n\nThis will have to be called on a 1:1 basis with addSelectionChangedListener calls if supplying a callback.\n\n```js\nAssistantAPIClient.removeSelectionChangedListener(selectionCB)\n```\n\n**If NOT supplying a callback to this call, all selection changed listeners will be removed.\n\n```js\nAssistantAPIClient.removeSelectionChangedListener()\n```\n\nThis function only exists on the Q-Assistant-Client--only disableSelectionChangedNotification is called on the API. \n\n\n### Services\nThe `Service` object:\n```js\n{\n   id: string,\n   name: string\n   endpointUrl: string,\n   getKinds: () => // Returns [] of Kinds objects\n   getFunctions: () => // Returns [] of Function objects\n}\n```\n\n#### getServiceById = id =>\nThis will return a service that exists within the scope of the workspace. \n** Assistant services will return null. Services outside the scope of the workspace will cause an error to be returned as 'Unable to load a Service from outside of the workspace.'\n\n```js\nconst svc = await AssistantAPIClient.getServiceById(id)\n```\n\n### Workspace\nThe `Workspace` object:\n```js\n{\nid: string,\nname: string,\ngetKinds: () => {\n  // Returns an array of functions in the workspace (includes boilerplate).\n},\ngetFunctions: () =>\n  // Returns an array of functions in the workspace (includes boilerplate).\ngetActiveGraph: () => {\n  // Returns the active Graph object.\n},\ngetKnowledgeGraphs: () => {\n  // Returns [Graph]\n},\ngetImportedServices: () => {\n  // Returns an service imported into the workspace\n  // as a array of Service object (this calls the function\n  // that underlies getServiceById.\n  // No assistant services will be returned.\n}\n}\n```\n\n#### getWorkspace = () =>\n\nReturns a Workspace object representing the workspace. \n\n```js\nconst ws = await AssistantAPIClient.getWorkspace()\n```\n\n### Graphs\nThe `Graph` object:\n```js\n{     \nid: string,\nname: string,\noffsetX: Number,\noffsetY: Number,\nzoom: Number,\ngetNodes: async () => {\n    // Returns [Node]\n},\n\naddNode: async (type, instance, changeSelection) => {\n    // Returns Node\n},\nremoveNode: async id => {\n    // Should return nothing or error.\n    // Currently returning [] in all cases.\n},\nupdateNodeLayout: async (nodeId, { x, y, collapsed }) => {\n    // Returns\n},\nupdateGraphLayout: async ({ offsetX, offsetY, zoom }) => {\n}\n}\n```\n\n#### Getting a graph object:\nGraph objects are obtained through an instance of a Workspace \n\n```js\nconst ag = await ws.getActiveGraph()\n```\n\nor\n\n```js\nconst kgs = await ws.getKnowledgeGraphs()\n```\n\n#### Manipulating Graphs\n\n**Only the active graph may be manipulated.\n\nAll graph manipulations should be ‘visually’ verifiable on the graph itself, i.e., adds/removes/positioning, should all be reflected on the graph itself. \n\nThe `Node` object:\n```js\n{\nid: string\nx: number\ny: number\ncollapsed: boolean\nknowledgeGraphNode {\n  id: string\n  innerKind: Kind\n  innerFunction: Function\n}\n}\n```\n\n#### addNode(type, instance, changeSelection) =>\n\nTakes type (“Function” or “Kind”), instance (the Function or Kind object), and optionally a boolean to indicate whether the selection should be changed to this new node. \n\nReturns the newly created Node object.\n\n```js\nconst node = await ag.addNode('Kind',kind)\n```\n\n#### removeNode(id) =>\n\nTakes the id of Node to be deleted. Returns either undefined or an error. \n\n```js\nawait ag.removeNode(node.id)\n```\n\n#### getNodes() =>\nReturns an array of Node objects from the graph. \n\n```js\nconst nodes = await ag.getNodes()\n```\n\n#### updateNodeLayout: async (nodeId, { x, y, collapsed})=>\n\nUpdates a Node layout given a node ID and node coordinates (`x` and/or `y`) or a `collapsed` value. x/y values must be a number, and collapsed must be a boolean. Whatever is not specified will remain current.\n\n```js\nag.updateNodeLayout(id,{x:100,y:100,collapsed:true})\n```\n\n#### updateGraphLayout: async ({ offsetX, offsetY, zoom})=>\n\nUpdates a Graph layout given numerical values for x/y offsets and the zoom. \n\n```js\nag.updateGraphLayout({offsetX:50, offsetY:50, zoom: 70})\n```\n\n### Functions\n\nThe `Function` object:\n```js\n{\n    id: string\n    name: string\n    service {\n      id: string\n      name: string\n    }\n    arguments {\n      id: string\n      name: string\n      type: string\n      modifiers: Array[string]\n      typeKindId:: string\n      kind {\n        id: string\n        name: string\n      }\n    }\n    implementation {\n      id: string\n      entrypoint {\n        id: string\n      }\n      operations {\n        id: string\n        type: string\n        function {\n          id: string\n          name: string\n        }\n        argumentValues {\n          id: string\n          argument {\n            id: string\n          }\n          operation {\n            id: string\n          }\n          argumentRef: string\n        }\n      }\n    }\n    isGenerated: boolean\n    outputType: string\n    outputKindId: string\n    outputModifiers: Array[string]\n    kind {\n      id: string\n      name: string\n    }\n}\n```\n\n`FunctionExecutionResult` object:\n```js\n{\n  id: string,\n  result: JSON\n}\n```\n\n#### executeFunction = ( {id, variables, resolve} ) =>\n\nExecutes a function based on its id, with optional inputs for variables and a resolve string (this specifies the fields to be returned, which must be valid based on the result).\n\nReturns : JSON matching shape of result , unless no sub-selection of fields is required in the execution.\n\nThis following piece of code will execute a Function given a function ID, and pass in variables for ‘example’, requesting back id and name fields. \n\n```js \nconst res = await AssistantAPIClient.executeFunction({functionId: func.id, variables: {\"variableName\": \"variableValue\"}, resolve: \"{ id name }\");\n```\n\n#### createFunction = input =>\n\nCreates a function based on the input provided. \n\nReturns: the created Function object.\n\n**Using create function will only place the function in the workspace’s inventory--it will not place the function as a node on the Graph. In order to do this, you must pass the created function into the addNode function on the active Graph, making sure to specify ‘Function' as the type.\n\n```js\nconst createFunctionInput = {\n  name:\"yourName\",\n  arguments:[],\n  outputType: \"STRING\",\n  graphqlOperationType:\"QUERY\",\n  functionType: \"PROJECTION\"\n}\n  \nconst createdFunction = await AssistantAPIClient.createFunction(createFunctionInput)\n```\n\n#### updateFunction = input =>\n\nInput is the same for creating a function. It’s important to note that the arguments property will be replaced in it’s entirety with whatever is provided (if a value is provided.\n\n@TODO: Return value\n\n```js\nconst updatedFunction = await AssistantAPIClient.updateFunction(input);\n```\n\n#### deleteFunction = input =>\n\nInput is the id of the Function to be deleted. Returns the deleted function as a promise.\n\n```js\nconst deletedFunction = await AssistantAPIClient.deleteFunction('id...');\n```\n\n#### getFunctionById = id =>\n\nReturns a Function as a promise based on the ID provided.\n\n```js\nconst func = await AssistantAPIClient.getFunctionById('id...');\n```\n\n#### addFunctionExecutionListener = async (id, cb) =>\n\nAssociates a callback function with the execution of a particular Function. When the Function matching the id parameter is executed, its FunctionExecutionResult object passed to the callback. Returns undefined.\n\nExample function execution callback and listener registration:\n\n```js\nfunction exampleFunctionCB (result){\n  console.log(`Function executed with result:`, result)\n}\n\nAssistantAPIClient.addFunctionExecutionListener('id...', exampleFunctionCB)\n```\n\n#### removeFunctionExecutionListener = async (id, cb) =>\n\nRemoves a Function execution listener based on the function ID and a reference to the callback function. If no callback is supplied, all listeners associated with the Function ID will be removed. Returns undefined.\n\n```js\nAssistantAPIClient.removeFunctionExecutionListener('id..', exampleFunctionCB)\n```\n\n### Kinds\nThe `Kind` object:\n```js\n{\n    id: string\n    name: string\n    service: {\n      id\n      name\n    }\n    isGenerated: boolean\n    schema {\n      id: string\n      name: string\n      type: string\n      typeKindId: string\n      modifiers: Array[string]\n      kind {\n        id: string\n        name: string\n      }\n    }\n}\n```\n\n#### createKind = input =>\n\nCreates a Kind based on an input object. Returns a promise that resolves to the created Kind object.\n\n```js\nconst kindInput = {\n name: \"someKind\",\n schema:[\n  { name: \"someField1\", type: STRING },\n  { name: \"someField2\", type: STRING }\n ]\n}\n\nconst newKind = await AssistantAPIClient.createKind(kindInput)\n```\n\n#### updateKind = input =>\n\n@TODO return value\n\nUpdates a Kind based on an input object. \n\nUpdate Semantics: Only properties specified will be updated. If updating the schema, the entire schema must be specified as it will be replaced in its entirety. \n\n```js\nconst updated = await AssistantAPIClient.updateKind(input)\n```\n\n#### deleteKind = input =>\n\nDeletes a Kind given a kind ID.\n\n```js\nconst deleted = await AssistantAPIClient.deleteKind(input)\n```\n\n#### getKindById = id =>\n\nReturns a promise that resolves to a Kind object given the specified kind ID. Only kinds in the workspace or those of imported services will be returned. \n\n```js\nconst kind = await AssistantAPIClient.getKindById(id)\n```\n\n### Inventory\n\nThe `InventoryChanged` object:\n```js\n{\n  kinds: {\n    adds: [DiffItem]\n    deletes: [DiffItem]\n    updates: [DiffItem]\n  }\n  functions:{\n    adds: [DiffItem]\n    deletes: [DiffItem]\n    updates: [DiffItem]\n  }\n  services: {\n    adds: [DiffItem]\n    deletes: [DiffItem]\n    updates: [DiffItem]\n  }\n}\n```\n\nThe `DiffItem` object:\n```js\n{\n  id: string,\n  name: string\n}\n```\n\n#### addInventoryChangedListener = async cb =>\n\nRegisters a callback function with the inventory changed event. When workspace inventory changes the callback function will be called with the InventoryChangedobject. Returns undefined.\n\n*Current limitations: Kind and Function updates only occur where the name property is changed. Updates to services outside of the workspace will not be detected. \n\n**Use-case note: an ‘update’ diff for inventory services is unlikely in general usage. \n\n```js\nconst inventoryCB = ({diff}) => {\n  if(diff.kinds) console.log('KINDS CHANGED',diff.kinds)\n  if(diff.functions) console.log('FUNCTIONS CHANGED', diff.functions)\n  if(diff.services) console.log('SERVICES CHANGED',diff.services)\n}\n\nAssistantAPIClient.addInventoryChangedListener(inventoryCB)\n```\n\nThis function exists on the Q-Assisant-Client only--only enableSelectionChangedNotification is used on the API side. \n\n#### removeInventoryChangedListener = async cb =>\n\nRemoves an inventory changed listener given the referenced callback. If no callback is specified, all listeners will be removed. Returns undefined.\n\n```js\nAssistantAPIClient.removeInventoryChangedListener(inventoryCB)\n```\n\nThis function exists on the Q-Assisant-Client only--only disableSelectionChangedNotification is used on the API side. \n\n## Troubleshooting Assistant Issues\n### Assistant root file has loaded, but not other content\nObserving in the browser's dev tools that some resources have loaded correctly (usually the root), but other's haven't (usually nested files or chunks), is indicative of a failure of Q Gateway to proxy due to not having a 'relative' path structure.\n\n### You are seeing post-robot `NO ACK` errors in the console.\nThese errors stem from a failed acknowledgement for a call either between the client and the API or vice-versa. Ensure that your window and window.parent objects are valid and they are able to communicate with one another.","readmeFilename":"README.md","gitHead":"f02f25344a8aa95caeded52b6dc3fe147e39f957","_id":"@io-maana/q-assistant-client@3.2.1-beta.11","_npmVersion":"6.4.1","_nodeVersion":"10.15.3","_npmUser":{"name":"teamcitymaana","email":"teamcity@maana.io"},"dist":{"integrity":"sha512-1HG4ntRi6ZOw0bdAkCrSDTbqPKesZcpnwVc+Ks9KqRyG1WEa3lp9RXtxy6xr5qFh64CTAF9yLsnluUwRkHEEsQ==","shasum":"8e35c8dbd9d44f65e3c6d0db41c54a3daa108492","tarball":"https://registry.npmjs.org/@io-maana/q-assistant-client/-/q-assistant-client-3.2.1-beta.11.tgz","fileCount":5,"unpackedSize":27818,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJdl6ELCRA9TVsSAnZWagAAMBoP/AlKiK8inmahd1NhNugg\nhZHGQFYQgfKPFI7xYpjBl9BNY1pDcZVQSmgrY3NJIlKIP8lt+DRtTxifNpb4\n49YrP4anWNA1lQTrpiZJ2IhewZ2KQ2lKqzs7nmQXDMM2V80xorkvn7fQfXU0\nhiJ/NJ1mrulGDglLNDt0dNrfJWVoL8hfXtUdHiCOPPqTQ9CXxP/K9/YqYI+0\nsnzH3IkD1+rpSVWFQDmTOX5jPZK/iwqyE7YCEuhbTgViV8d4P0CM0E2Nttp9\nmVw5U9D7r8Wr5gcsR+NYX0Hx+K2AQ91KN3NWrS1joKvd/qQt6TlQt9kISc2m\nnwhccisxr57NJXKRxBVhG4/wPl/7SEfDNX4bUBspwWazktjdbFfwRkeZpNQy\nt93+J14PLYSXANzLXnLcjnBtTDchfYMvFpkC/nrnHpUd9fW3c0A7VchVuQu2\n5p15CZSvi61zCQ8sLABzIJ63cjRdgaDg6FwBk7LhbHiXjlAzWCvFt9Xt8qX/\nqNJ/yVR7++b0cB4a8LT6WlYzpmBLwVZ1KoFk+U6eCTE3/LlVD6XAQdEEkLo8\n5ON0+eGz5JDS9q4pCq6sIZlMvnN9GpPrQ8VJx55uLN0u4T6cQIhSqKrEnarh\nDx4QlSvSVxVf5g5rxjJM8XI2bmhjRDjEf/hle9QLaAtducafX/QHgTfR+31t\nnnnx\r\n=tCSE\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEQCIGVPHhIZZofSnewrSsXnKcXCseTvID+GDlMO3BOzEiekAiAa0sxWrKjyaV9zvpftIUtwO7mSgw6VWsG5v2+Zhe8IJA=="}]},"maintainers":[{"name":"abatyuk","email":"andrey@maana.io"},{"name":"bzvetey","email":"bzvestey@gmail.com"},{"name":"rpovey","email":"rob@maana.io"},{"name":"teamcitymaana","email":"teamcity@maana.io"},{"name":"witt3rd","email":"witt3rd@witt3rd.com"}],"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/q-assistant-client_3.2.1-beta.11_1570218250362_0.30750442144324275"},"_hasShrinkwrap":false},"3.2.1-beta.12":{"name":"@io-maana/q-assistant-client","version":"3.2.1-beta.12","description":"JavaScript package to streamline communication between an assistant and the Maana Q Assistant API.","main":"build/AssistantAPIClient.js","scripts":{"build":"babel src --out-dir build","prepack":"npm run build","test":"echo \"Error: no test specified\" && exit 1"},"repository":{"type":"git","url":"git+https://github.com/maana-io/q-assistant-client.git"},"keywords":["Maana","Q"],"author":{"name":"Logan Gore @ Maana.io"},"license":"MIT","bugs":{"url":"https://github.com/maana-io/q-assistant-client/issues"},"homepage":"https://github.com/maana-io/q-assistant-client#readme","dependencies":{"post-robot":"^10.0.18"},"devDependencies":{"@babel/cli":"^7.5.5","@babel/core":"^7.5.5","@babel/plugin-proposal-class-properties":"^7.5.5","@babel/preset-env":"^7.5.5"},"readme":"# q-assistant-client\nA lightweight JavaScript client for Maana-Q Assistant developers that wraps post-message communication between an embedded Maana-Q assistant and the Maana-Q UI.\n\n## Abstract\nThe Q-Assistant-Client is intented to be used in a web application being leveraged as a Maana Q assistant (embedded as an iframe).\nThis assistant client will facilitate communication between the assistant and the parent frame.\nThe client provides a rich, asynchronous experience over what would otherwise be 'fire-and-forget'-style messaging \nvia post-post message communication. \n\n## Requirements and Assumptions\n\n### Post-Robot Library\nThe Maana Knowledge Portal (KPortal) uses the kraken/post-robot library [kraken/post-robot](https://github.com/krakenjs/post-robot) to enrich the communication with the assistant. Post-robot allows for asynchronous, promise-based request/response style behavior between the assistant and the assistant API.\n\nThe API requires that the client use the post-robot library. This assistant-client library is the easiest way to achieve this, and also adds a fair amount of 'sugar' to the process to improve developer productivity. Developers could, however, use post-robot directly in their own client implementation. \n\n### Maana-Gateway Proxy Requirements\nThe Maana-Gateway service requires relative paths (paths relative to the root) in the assistant web application in order to proxy the application and its content. For create-react-apps, for instance, this means setting \"homepage\" to \".\" in the package.json file.\n\n## Singleton Instance\nThe client is exported as a singleton to avoid duplicate registration on event listeners.\nYou can import the instance like this:\n\n```js\nimport AssistantAPIClient from '@io-maana/q-assistant-client';\n```\n\nFunction calls can be made against the client instance like any other javascript object. They are all async.\n\n```js\nconst workspace = await AssistantAPIClient.getWorkspace(); \nconsole.log(\"Workspace:\", workspace)\n```\n\n## Dependencies\nPost-Robot\nhttps://github.com/krakenjs/post-robot\n\nPost-robot is used to provide a richer communication layer atop post-message.\n\n## Examples\n@TODO Logan\n\n## API Documentation\n\n### State management\n\n#### clearState = () =>\n\nThis will clear all ‘attached’ state between the assistant and the API. \n\nSpecifically, this will clear selection and inventory changed event listeners. \n\n```js\nawait AssistantAPIClient.clearState()\n```\n\n### User Info\nThe `UserInfo` object:\n```js\n{\n email: string,\n name: string\n}\n```\n\n#### getUserInfo = () => \n\nReturns a Userinfo object pertaining to the logged in user.\n\n```js\nconst userInfo = await AssistantAPIClient.getUserInfo()\n```\n### Selection\nThe `Selection` object:\n```js\n{\n  kindId: string\n  kindName: string\n  id: string\n}\n```\n\n#### getCurrentSelection = () => \n\nReturns an Array of `Selection` objects:\n\n```js\nconst {selection} = await AssistantAPIClient.getCurrentSelection();\n```\n\n#### addSelectionChangedListener = async cb =>\n\nAdds a callback function to be executed upon a valid workspace selection change.\n\nCallback value is an array of Selection objects:\n\n```js\n// Create the selection callback.\nconst selectionCB = ({selection})=>{\n  console.log('Workspace selection has changed.')\n  selection.forEach(i=>{\n    console.log('Kind: ',i.kindName)\n    console.log('Instance Id:',i.id)\n    console.log('Kind Id:',i.kindId)\n  })\n}\n\n// Add the listener.\nAssistantAPIClient.addSelectionChangedListener(selectionCB);\n```\n\nThis function only exists on the Q-Assistant-Client--only enableSelectionChangedNotification is called on the API. \n\n#### removeSelectionChangedListener = async cb =>\n\nThis will have to be called on a 1:1 basis with addSelectionChangedListener calls if supplying a callback.\n\n```js\nAssistantAPIClient.removeSelectionChangedListener(selectionCB)\n```\n\n**If NOT supplying a callback to this call, all selection changed listeners will be removed.\n\n```js\nAssistantAPIClient.removeSelectionChangedListener()\n```\n\nThis function only exists on the Q-Assistant-Client--only disableSelectionChangedNotification is called on the API. \n\n\n### Services\nThe `Service` object:\n```js\n{\n   id: string,\n   name: string\n   endpointUrl: string,\n   getKinds: () => // Returns [] of Kinds objects\n   getFunctions: () => // Returns [] of Function objects\n}\n```\n\n#### getServiceById = id =>\nThis will return a service that exists within the scope of the workspace. \n** Assistant services will return null. Services outside the scope of the workspace will cause an error to be returned as 'Unable to load a Service from outside of the workspace.'\n\n```js\nconst svc = await AssistantAPIClient.getServiceById(id)\n```\n\n### Workspace\nThe `Workspace` object:\n```js\n{\nid: string,\nname: string,\ngetKinds: () => {\n  // Returns an array of functions in the workspace (includes boilerplate).\n},\ngetFunctions: () =>\n  // Returns an array of functions in the workspace (includes boilerplate).\ngetActiveGraph: () => {\n  // Returns the active Graph object.\n  // Returns null if active graph is not of type 'Knowledge Graph', or if an\n  // active graph is deleted, thereby setting active graph to null.\n},\ngetKnowledgeGraphs: () => {\n  // Returns [Graph]\n},\ngetImportedServices: () => {\n  // Returns an service imported into the workspace\n  // as a array of Service object (this calls the function\n  // that underlies getServiceById.\n  // No assistant services will be returned.\n}\n}\n```\n\n#### getWorkspace = () =>\n\nReturns a Workspace object representing the workspace. \n\n```js\nconst ws = await AssistantAPIClient.getWorkspace()\n```\n\n### Graphs\nThe `Graph` object:\n```js\n{     \nid: string,\nname: string,\noffsetX: Number,\noffsetY: Number,\nzoom: Number,\ngetNodes: async () => {\n    // Returns [Node]\n},\n\naddNode: async (type, instance, changeSelection) => {\n    // Returns Node\n},\nremoveNode: async id => {\n    // Should return nothing or error.\n    // Currently returning [] in all cases.\n},\nupdateNodeLayout: async (nodeId, { x, y, collapsed }) => {\n},\nupdateGraphLayout: async ({ offsetX, offsetY, zoom }) => {\n}\n}\n```\n\n#### Getting a graph object:\nGraph objects are obtained through an instance of a Workspace \n\n```js\nconst ag = await ws.getActiveGraph()\n```\n\nor\n\n```js\nconst kgs = await ws.getKnowledgeGraphs()\n```\n\n#### Manipulating Graphs\n\n**Only the active graph may be manipulated.\n\nAll graph manipulations should be ‘visually’ verifiable on the graph itself, i.e., adds/removes/positioning, should all be reflected on the graph itself. \n\nThe `Node` object:\n```js\n{\nid: string\nx: number\ny: number\ncollapsed: boolean\nknowledgeGraphNode {\n  id: string\n  innerKind: Kind\n  innerFunction: Function\n}\n}\n```\n\n#### addNode(type, instance, changeSelection) =>\n\nTakes type (“Function” or “Kind”), instance (the Function or Kind object), and optionally a boolean to indicate whether the selection should be changed to this new node. \n\nReturns the newly created Node object.\n\n```js\nconst node = await ag.addNode('Kind',kind)\n```\n\n#### removeNode(id) =>\n\nTakes the id of Node to be deleted. Returns either undefined or an error. \n\n```js\nawait ag.removeNode(node.id)\n```\n\n#### getNodes() =>\nReturns an array of Node objects from the graph. \n\n```js\nconst nodes = await ag.getNodes()\n```\n\n#### updateNodeLayout: async (nodeId, { x, y, collapsed})=>\n\nUpdates a Node layout given a node ID and node coordinates (`x` and/or `y`) or a `collapsed` value. x/y values must be a number, and collapsed must be a boolean. Whatever is not specified will remain current.\n\n```js\nag.updateNodeLayout(id,{x:100,y:100,collapsed:true})\n```\n\n#### updateGraphLayout: async ({ offsetX, offsetY, zoom})=>\n\nUpdates a Graph layout given numerical values for x/y offsets and the zoom. \n\n```js\nag.updateGraphLayout({offsetX:50, offsetY:50, zoom: 70})\n```\n\n### Functions\n\nThe `Function` object:\n```js\n{\n    id: string\n    name: string\n    service {\n      id: string\n      name: string\n    }\n    arguments {\n      id: string\n      name: string\n      type: string\n      modifiers: Array[string]\n      typeKindId:: string\n      kind {\n        id: string\n        name: string\n      }\n    }\n    implementation {\n      id: string\n      entrypoint {\n        id: string\n      }\n      operations {\n        id: string\n        type: string\n        function {\n          id: string\n          name: string\n        }\n        argumentValues {\n          id: string\n          argument {\n            id: string\n          }\n          operation {\n            id: string\n          }\n          argumentRef: string\n        }\n      }\n    }\n    isGenerated: boolean\n    functionType: string\n    graphqlOperationType: string\n    outputType: string\n    outputKindId: string\n    outputModifiers: Array[string]\n    kind {\n      id: string\n      name: string\n    }\n}\n```\n\n`FunctionExecutionResult` object:\n```js\n{\n  id: string,\n  result: JSON\n}\n```\n\n#### executeFunction = ( {id, variables, resolve} ) =>\n\nExecutes a function based on its id, with optional inputs for variables and a resolve string (this specifies the fields to be returned, which must be valid based on the result).\n\nReturns : JSON matching shape of result , unless no sub-selection of fields is required in the execution.\n\nThis following piece of code will execute a Function given a function ID, and pass in variables for ‘example’, requesting back id and name fields. \n\n```js \nconst res = await AssistantAPIClient.executeFunction({functionId: func.id, variables: {\"variableName\": \"variableValue\"}, resolve: \"{ id name }\");\n```\n\n#### createFunction = input =>\n\nCreates a function based on the input provided. \n\nReturns: the created Function object.\n\n**Using create function will only place the function in the workspace’s inventory--it will not place the function as a node on the Graph. In order to do this, you must pass the created function into the addNode function on the active Graph, making sure to specify ‘Function' as the type.\n\n```js\nconst createFunctionInput = {\n  name:\"yourName\",\n  arguments:[],\n  outputType: \"STRING\",\n  graphqlOperationType:\"QUERY\",\n  functionType: \"CKG\"\n}\n  \nconst createdFunction = await AssistantAPIClient.createFunction(createFunctionInput)\n```\n\n#### updateFunction = input =>\n\nInput is the same for creating a function. It’s important to note that the arguments property will be replaced in it’s entirety with whatever is provided (if a value is provided.\n\nReturns the updated `Function` object.\n\n```js\nconst updatedFunction = await AssistantAPIClient.updateFunction(input);\n```\n\n#### deleteFunction = input =>\n\nInput is the id of the Function to be deleted. Returns the deleted function as a promise.\n\n```js\nconst deletedFunction = await AssistantAPIClient.deleteFunction('id...');\n```\n\n#### getFunctionById = id =>\n\nReturns a Function as a promise based on the ID provided.\n\n```js\nconst func = await AssistantAPIClient.getFunctionById('id...');\n```\n\n#### addFunctionExecutionListener = async (id, cb) =>\n\nAssociates a callback function with the execution of a particular Function. When the Function matching the id parameter is executed, its FunctionExecutionResult object passed to the callback. Returns undefined.\n\nExample function execution callback and listener registration:\n\n```js\nfunction exampleFunctionCB (result){\n  console.log(`Function executed with result:`, result)\n}\n\nAssistantAPIClient.addFunctionExecutionListener('id...', exampleFunctionCB)\n```\n\n#### removeFunctionExecutionListener = async (id, cb) =>\n\nRemoves a Function execution listener based on the function ID and a reference to the callback function. If no callback is supplied, all listeners associated with the Function ID will be removed. Returns undefined.\n\n```js\nAssistantAPIClient.removeFunctionExecutionListener('id..', exampleFunctionCB)\n```\n\n### Kinds\nThe `Kind` object:\n```js\n{\n    id: string\n    name: string\n    service: {\n      id\n      name\n    }\n    isGenerated: boolean\n    schema {\n      id: string\n      name: string\n      type: string\n      typeKindId: string\n      modifiers: Array[string]\n      kind {\n        id: string\n        name: string\n      }\n    }\n}\n```\n\n#### createKind = input =>\n\nCreates a Kind based on an input object. Returns a promise that resolves to the created Kind object.\n\n```js\nconst kindInput = {\n name: \"someKind\",\n schema:[\n  { name: \"someField1\", type: STRING },\n  { name: \"someField2\", type: STRING }\n ]\n}\n\nconst newKind = await AssistantAPIClient.createKind(kindInput)\n```\n\n#### updateKind = input =>\n\nUpdates a Kind based on an input object. \n\nUpdate Semantics: Only properties specified will be updated. If updating the schema, the entire schema must be specified as it will be replaced in its entirety. \n\nReturns the updated `Kind` object.\n\n```js\nconst updated = await AssistantAPIClient.updateKind(input)\n```\n\n#### deleteKind = input =>\n\nDeletes a Kind given a kind ID.\n\n```js\nconst deleted = await AssistantAPIClient.deleteKind(input)\n```\n\n#### getKindById = id =>\n\nReturns a promise that resolves to a Kind object given the specified kind ID. Only kinds in the workspace or those of imported services will be returned. \n\n```js\nconst kind = await AssistantAPIClient.getKindById(id)\n```\n\n### Inventory\n\nThe `InventoryChanged` object:\n```js\n{\n  kinds: {\n    adds: [DiffItem]\n    deletes: [DiffItem]\n    updates: [DiffItem]\n  }\n  functions:{\n    adds: [DiffItem]\n    deletes: [DiffItem]\n    updates: [DiffItem]\n  }\n  services: {\n    adds: [DiffItem]\n    deletes: [DiffItem]\n    updates: [DiffItem]\n  }\n}\n```\n\nThe `DiffItem` object:\n```js\n{\n  id: string,\n  name: string\n}\n```\n\n#### addInventoryChangedListener = async cb =>\n\nRegisters a callback function with the inventory changed event. When workspace inventory changes the callback function will be called with the InventoryChangedobject. Returns undefined.\n\n*Current limitations: Kind and Function updates only occur where the name property is changed. Updates to services outside of the workspace will not be detected. \n\n**Use-case note: an ‘update’ diff for inventory services is unlikely in general usage. \n\n```js\nconst inventoryCB = ({diff}) => {\n  if(diff.kinds) console.log('KINDS CHANGED',diff.kinds)\n  if(diff.functions) console.log('FUNCTIONS CHANGED', diff.functions)\n  if(diff.services) console.log('SERVICES CHANGED',diff.services)\n}\n\nAssistantAPIClient.addInventoryChangedListener(inventoryCB)\n```\n\nThis function exists on the Q-Assisant-Client only--only enableSelectionChangedNotification is used on the API side. \n\n#### removeInventoryChangedListener = async cb =>\n\nRemoves an inventory changed listener given the referenced callback. If no callback is specified, all listeners will be removed. Returns undefined.\n\n```js\nAssistantAPIClient.removeInventoryChangedListener(inventoryCB)\n```\n\nThis function exists on the Q-Assisant-Client only--only disableSelectionChangedNotification is used on the API side. \n\n## Troubleshooting Assistant Issues\n### Assistant root file has loaded, but not other content\nObserving in the browser's dev tools that some resources have loaded correctly (usually the root), but other's haven't (usually nested files or chunks), is indicative of a failure of Q Gateway to proxy due to not having a 'relative' path structure.\n\n### You are seeing post-robot `NO ACK` errors in the console.\nThese errors stem from a failed acknowledgement for a call either between the client and the API or vice-versa. Here, this means that the web app 'window' (the assistant) cannot communicate with, or access, the 'window.parent' (Maana K-Portal) object. Improper CORS configuration is a common culprit (also verify if using docker or nginx that your proxying and networking is configured correctly to allow communication and to accout for CORS).","readmeFilename":"README.md","gitHead":"80821f5022c1fa0bf6f803a12472555cf0bb0fdd","_id":"@io-maana/q-assistant-client@3.2.1-beta.12","_npmVersion":"6.4.1","_nodeVersion":"10.15.3","_npmUser":{"name":"teamcitymaana","email":"teamcity@maana.io"},"dist":{"integrity":"sha512-rR/IeqTAU55WJgtgfBYq9Eek1B0ztCUdo9g/UoIZMfYIamHnxeIXDmNh/DNmVqMX017xw00+NqEGMdfS81wDmQ==","shasum":"4aa48634410e3b1c6dee2776e1aa6a089bf0b9cf","tarball":"https://registry.npmjs.org/@io-maana/q-assistant-client/-/q-assistant-client-3.2.1-beta.12.tgz","fileCount":5,"unpackedSize":28255,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJdo8ihCRA9TVsSAnZWagAAD2cP/RCPgHXo8MVFDSF9rcnl\netvUQdSCizGxzEYdFRLFtbhlR/+bfDbXe8asONvavQG9qlkm6ofZ3hs3QxVb\nOnxnBwgMviVxmHYrJwq1LXmzKnVCWm92sn+AgBgZcefalMIkGsOzf8xUAECT\nWNTQgT/PR750sjzm5ZghRZXct4Xzu4qYqfmll76hVwmD9SQhXn+p8kQfzM9m\nv25fRe3J4DcykGb1G1oQxo+ULSQZZjnti0tbyivcr32ofzB9yaXB3ZOSc2Ym\nhS3GwIR5/u8yBd8LXMIKw9nsYO0rzUUw3LPSG06QiVCQhp8rCKQYvtcpHmAA\nZOWZhUViPmu9/keAiHCq4H4z6bto9lqkJiHIpRdBxD6ZhbFEcRotBdUbUhjV\nxnlxs/nYiyJgPTapCYgt5Uv6KatUXZR3OXUWL7tYk90SeKaDS8Nk9Fvza3TM\n2Zp/mkNji1rWbnC0AOe8FjwOnyG1OwHz0+A9nzkAYE6LFL6MjHXVdUh8TSVC\noSSSqkoA9My/aujX6MjnnKyO4wvmh6Bv97BoJC0EVgPZMMHlA8EXOeTQE0Mu\nSc5dg/iBvuymrF6hec/Tx+giXqKWNChcAHsySDCCpQcXlV/GWY3PnoXH9wWy\negqO58myuy4336rp10+T+p2OTFwwUylctytznvZ3DllZK0n2Vm9wcjU4bPga\nvfUb\r\n=fGPs\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEQCIGO3cDVtXjdhXcy4e00BgQE3g1HnFySt5dKG9H97V5onAiAgV73l1b/i8WhIVdpwN7o/xyTpjPiNklkajdEhma/d1g=="}]},"maintainers":[{"name":"abatyuk","email":"andrey@maana.io"},{"name":"bzvetey","email":"bzvestey@gmail.com"},{"name":"rpovey","email":"rob@maana.io"},{"name":"teamcitymaana","email":"teamcity@maana.io"},{"name":"witt3rd","email":"witt3rd@witt3rd.com"}],"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/q-assistant-client_3.2.1-beta.12_1571014816947_0.9163481090801104"},"_hasShrinkwrap":false},"3.2.1-beta.13":{"name":"@io-maana/q-assistant-client","version":"3.2.1-beta.13","description":"JavaScript package to streamline communication between an assistant and the Maana Q Assistant API.","main":"build/AssistantAPIClient.js","scripts":{"build":"babel src --out-dir build","prepack":"npm run build","test":"echo \"Error: no test specified\" && exit 1"},"repository":{"type":"git","url":"git+https://github.com/maana-io/q-assistant-client.git"},"keywords":["Maana","Q"],"author":{"name":"Logan Gore @ Maana.io"},"license":"MIT","bugs":{"url":"https://github.com/maana-io/q-assistant-client/issues"},"homepage":"https://github.com/maana-io/q-assistant-client#readme","dependencies":{"post-robot":"^10.0.18"},"devDependencies":{"@babel/cli":"^7.5.5","@babel/core":"^7.5.5","@babel/plugin-proposal-class-properties":"^7.5.5","@babel/preset-env":"^7.5.5"},"readme":"# q-assistant-client\nA lightweight JavaScript client for Maana-Q Assistant developers that wraps post-message communication between an embedded Maana-Q assistant and the Maana-Q UI.\n\n## Abstract\nThe Q-Assistant-Client is intented to be used in a web application being leveraged as a Maana Q assistant (embedded as an iframe).\nThis assistant client will facilitate communication between the assistant and the parent frame.\nThe client provides a rich, asynchronous experience over what would otherwise be 'fire-and-forget'-style messaging \nvia post-post message communication. \n\n## Requirements and Assumptions\n\n### Post-Robot Library\nThe Maana Knowledge Portal (KPortal) uses the kraken/post-robot library [kraken/post-robot](https://github.com/krakenjs/post-robot) to enrich the communication with the assistant. Post-robot allows for asynchronous, promise-based request/response style behavior between the assistant and the assistant API.\n\nThe API requires that the client use the post-robot library. This assistant-client library is the easiest way to achieve this, and also adds a fair amount of 'sugar' to the process to improve developer productivity. Developers could, however, use post-robot directly in their own client implementation. \n\n### Maana-Gateway Proxy Requirements\nThe Maana-Gateway service requires relative paths (paths relative to the root) in the assistant web application in order to proxy the application and its content. For create-react-apps, for instance, this means setting \"homepage\" to \".\" in the package.json file.\n\n## Singleton Instance\nThe client is exported as a singleton to avoid duplicate registration on event listeners.\nYou can import the instance like this:\n\n```js\nimport AssistantAPIClient from '@io-maana/q-assistant-client';\n```\n\nFunction calls can be made against the client instance like any other javascript object. They are all async.\n\n```js\nconst workspace = await AssistantAPIClient.getWorkspace(); \nconsole.log(\"Workspace:\", workspace)\n```\n\n## Dependencies\nPost-Robot\nhttps://github.com/krakenjs/post-robot\n\nPost-robot is used to provide a richer communication layer atop post-message.\n\n## Examples\n@TODO Logan\n\n## API Documentation\n\n### State management\n\n#### clearState = () =>\n\nThis will clear all ‘attached’ state between the assistant and the API. \n\nSpecifically, this will clear selection and inventory changed event listeners. \n\n```js\nawait AssistantAPIClient.clearState()\n```\n\n### User Info\nThe `UserInfo` object:\n```js\n{\n email: string,\n name: string\n}\n```\n\n#### getUserInfo = () => \n\nReturns a Userinfo object pertaining to the logged in user.\n\n```js\nconst userInfo = await AssistantAPIClient.getUserInfo()\n```\n### Selection\nThe `Selection` object:\n```js\n{\n  kindId: string\n  kindName: string\n  id: string\n}\n```\n\n#### getCurrentSelection = () => \n\nReturns an Array of `Selection` objects:\n\n```js\nconst {selection} = await AssistantAPIClient.getCurrentSelection();\n```\n\n#### addSelectionChangedListener = async cb =>\n\nAdds a callback function to be executed upon a valid workspace selection change.\n\nCallback value is an array of Selection objects:\n\n```js\n// Create the selection callback.\nconst selectionCB = ({selection})=>{\n  console.log('Workspace selection has changed.')\n  selection.forEach(i=>{\n    console.log('Kind: ',i.kindName)\n    console.log('Instance Id:',i.id)\n    console.log('Kind Id:',i.kindId)\n  })\n}\n\n// Add the listener.\nAssistantAPIClient.addSelectionChangedListener(selectionCB);\n```\n\nThis function only exists on the Q-Assistant-Client--only enableSelectionChangedNotification is called on the API. \n\n#### removeSelectionChangedListener = async cb =>\n\nThis will have to be called on a 1:1 basis with addSelectionChangedListener calls if supplying a callback.\n\n```js\nAssistantAPIClient.removeSelectionChangedListener(selectionCB)\n```\n\n**If NOT supplying a callback to this call, all selection changed listeners will be removed.\n\n```js\nAssistantAPIClient.removeSelectionChangedListener()\n```\n\nThis function only exists on the Q-Assistant-Client--only disableSelectionChangedNotification is called on the API. \n\n\n### Services\nThe `Service` object:\n```js\n{\n   id: string,\n   name: string\n   endpointUrl: string,\n   getKinds: () => // Returns [] of Kinds objects\n   getFunctions: () => // Returns [] of Function objects\n}\n```\n\n#### getServiceById = id =>\nThis will return a service that exists within the scope of the workspace. \n** Assistant services will return null. Services outside the scope of the workspace will cause an error to be returned as 'Unable to load a Service from outside of the workspace.'\n\n```js\nconst svc = await AssistantAPIClient.getServiceById(id)\n```\n\n### Workspace\nThe `Workspace` object:\n```js\n{\nid: string,\nname: string,\ngetKinds: () => {\n  // Returns an array of functions in the workspace (includes boilerplate).\n},\ngetFunctions: () =>\n  // Returns an array of functions in the workspace (includes boilerplate).\ngetActiveGraph: () => {\n  // Returns the active Graph object.\n  // Returns null if active graph is not of type 'Knowledge Graph', or if an\n  // active graph is deleted, thereby setting active graph to null.\n},\ngetKnowledgeGraphs: () => {\n  // Returns [Graph]\n},\ngetImportedServices: () => {\n  // Returns an service imported into the workspace\n  // as a array of Service object (this calls the function\n  // that underlies getServiceById.\n  // No assistant services will be returned.\n}\n}\n```\n\n#### getWorkspace = () =>\n\nReturns a Workspace object representing the workspace. \n\n```js\nconst ws = await AssistantAPIClient.getWorkspace()\n```\n\n### Graphs\nThe `Graph` object:\n```js\n{     \nid: string,\nname: string,\noffsetX: Number,\noffsetY: Number,\nzoom: Number,\ngetNodes: async () => {\n    // Returns [Node]\n},\n\naddNode: async (type, instance, changeSelection) => {\n    // Returns Node\n},\nremoveNode: async id => {\n    // Should return nothing or error.\n    // Currently returning [] in all cases.\n},\nupdateNodeLayout: async (nodeId, { x, y, collapsed }) => {\n},\nupdateGraphLayout: async ({ offsetX, offsetY, zoom }) => {\n}\n}\n```\n\n#### Getting a graph object:\nGraph objects are obtained through an instance of a Workspace \n\n```js\nconst ag = await ws.getActiveGraph()\n```\n\nor\n\n```js\nconst kgs = await ws.getKnowledgeGraphs()\n```\n\n#### Manipulating Graphs\n\n**Only the active graph may be manipulated.\n\nAll graph manipulations should be ‘visually’ verifiable on the graph itself, i.e., adds/removes/positioning, should all be reflected on the graph itself. \n\nThe `Node` object:\n```js\n{\nid: string\nx: number\ny: number\ncollapsed: boolean\nknowledgeGraphNode {\n  id: string\n  innerKind: Kind\n  innerFunction: Function\n}\n}\n```\n\n#### addNode(type, instance, changeSelection) =>\n\nTakes type (“Function” or “Kind”), instance (the Function or Kind object), and optionally a boolean to indicate whether the selection should be changed to this new node. \n\nReturns the newly created Node object.\n\n```js\nconst node = await ag.addNode('Kind',kind)\n```\n\n#### removeNode(id) =>\n\nTakes the id of Node to be deleted. Returns either undefined or an error. \n\n```js\nawait ag.removeNode(node.id)\n```\n\n#### getNodes() =>\nReturns an array of Node objects from the graph. \n\n```js\nconst nodes = await ag.getNodes()\n```\n\n#### updateNodeLayout: async (nodeId, { x, y, collapsed})=>\n\nUpdates a Node layout given a node ID and node coordinates (`x` and/or `y`) or a `collapsed` value. x/y values must be a number, and collapsed must be a boolean. Whatever is not specified will remain current.\n\n```js\nag.updateNodeLayout(id,{x:100,y:100,collapsed:true})\n```\n\n#### updateGraphLayout: async ({ offsetX, offsetY, zoom})=>\n\nUpdates a Graph layout given numerical values for x/y offsets and the zoom. \n\n```js\nag.updateGraphLayout({offsetX:50, offsetY:50, zoom: 70})\n```\n\n### Functions\n\nThe `Function` object:\n```js\n{\n    id: string\n    name: string\n    service {\n      id: string\n      name: string\n    }\n    arguments {\n      id: string\n      name: string\n      type: string\n      modifiers: Array[string]\n      typeKindId:: string\n      kind {\n        id: string\n        name: string\n      }\n    }\n    implementation {\n      id: string\n      entrypoint {\n        id: string\n      }\n      operations {\n        id: string\n        type: string\n        function {\n          id: string\n          name: string\n        }\n        argumentValues {\n          id: string\n          argument {\n            id: string\n          }\n          operation {\n            id: string\n          }\n          argumentRef: string\n        }\n      }\n    }\n    isGenerated: boolean\n    functionType: string\n    graphqlOperationType: string\n    outputType: string\n    outputKindId: string\n    outputModifiers: Array[string]\n    kind {\n      id: string\n      name: string\n    }\n}\n```\n\n`FunctionExecutionResult` object:\n```js\n{\n  id: string,\n  result: JSON\n}\n```\n\n#### executeFunction = ( {id, variables, resolve} ) =>\n\nExecutes a function based on its id, with optional inputs for variables and a resolve string (this specifies the fields to be returned, which must be valid based on the result).\n\nReturns : JSON matching shape of result , unless no sub-selection of fields is required in the execution.\n\nThis following piece of code will execute a Function given a function ID, and pass in variables for ‘example’, requesting back id and name fields. \n\n```js \nconst res = await AssistantAPIClient.executeFunction({functionId: func.id, variables: {\"variableName\": \"variableValue\"}, resolve: \"{ id name }\");\n```\n\n#### createFunction = input =>\n\nCreates a function based on the input provided. \n\nReturns: the created Function object.\n\n**Using create function will only place the function in the workspace’s inventory--it will not place the function as a node on the Graph. In order to do this, you must pass the created function into the addNode function on the active Graph, making sure to specify ‘Function' as the type.\n\n```js\nconst createFunctionInput = {\n  name:\"yourName\",\n  arguments:[],\n  outputType: \"STRING\",\n  graphqlOperationType:\"QUERY\",\n  functionType: \"CKG\"\n}\n  \nconst createdFunction = await AssistantAPIClient.createFunction(createFunctionInput)\n```\n\n#### updateFunction = input =>\n\nInput is the same for creating a function. It’s important to note that the arguments property will be replaced in it’s entirety with whatever is provided (if a value is provided.\n\nReturns the updated `Function` object.\n\n```js\nconst updatedFunction = await AssistantAPIClient.updateFunction(input);\n```\n\n#### deleteFunction = input =>\n\nInput is the id of the Function to be deleted. Returns the deleted function as a promise.\n\n```js\nconst deletedFunction = await AssistantAPIClient.deleteFunction('id...');\n```\n\n#### getFunctionById = id =>\n\nReturns a Function as a promise based on the ID provided.\n\n```js\nconst func = await AssistantAPIClient.getFunctionById('id...');\n```\n\n#### addFunctionExecutionListener = async (id, cb) =>\n\nAssociates a callback function with the execution of a particular Function. When the Function matching the id parameter is executed, its FunctionExecutionResult object passed to the callback. Returns undefined.\n\nExample function execution callback and listener registration:\n\n```js\nfunction exampleFunctionCB (result){\n  console.log(`Function executed with result:`, result)\n}\n\nAssistantAPIClient.addFunctionExecutionListener('id...', exampleFunctionCB)\n```\n\n#### removeFunctionExecutionListener = async (id, cb) =>\n\nRemoves a Function execution listener based on the function ID and a reference to the callback function. If no callback is supplied, all listeners associated with the Function ID will be removed. Returns undefined.\n\n```js\nAssistantAPIClient.removeFunctionExecutionListener('id..', exampleFunctionCB)\n```\n\n### Kinds\nThe `Kind` object:\n```js\n{\n    id: string\n    name: string\n    service: {\n      id\n      name\n    }\n    isGenerated: boolean\n    schema {\n      id: string\n      name: string\n      type: string\n      typeKindId: string\n      modifiers: Array[string]\n      kind {\n        id: string\n        name: string\n      }\n    }\n}\n```\n\n#### createKind = input =>\n\nCreates a Kind based on an input object. Returns a promise that resolves to the created Kind object.\n\n```js\nconst kindInput = {\n name: \"someKind\",\n schema:[\n  { name: \"someField1\", type: STRING },\n  { name: \"someField2\", type: STRING }\n ]\n}\n\nconst newKind = await AssistantAPIClient.createKind(kindInput)\n```\n\n#### updateKind = input =>\n\nUpdates a Kind based on an input object. \n\nUpdate Semantics: Only properties specified will be updated. If updating the schema, the entire schema must be specified as it will be replaced in its entirety. \n\nReturns the updated `Kind` object.\n\n```js\nconst updated = await AssistantAPIClient.updateKind(input)\n```\n\n#### deleteKind = input =>\n\nDeletes a Kind given a kind ID.\n\n```js\nconst deleted = await AssistantAPIClient.deleteKind(input)\n```\n\n#### getKindById = id =>\n\nReturns a promise that resolves to a Kind object given the specified kind ID. Only kinds in the workspace or those of imported services will be returned. \n\n```js\nconst kind = await AssistantAPIClient.getKindById(id)\n```\n\n### Inventory\n\nThe `InventoryChanged` object:\n```js\n{\n  kinds: {\n    adds: [DiffItem]\n    deletes: [DiffItem]\n    updates: [DiffItem]\n  }\n  functions:{\n    adds: [DiffItem]\n    deletes: [DiffItem]\n    updates: [DiffItem]\n  }\n  services: {\n    adds: [DiffItem]\n    deletes: [DiffItem]\n    updates: [DiffItem]\n  }\n}\n```\n\nThe `DiffItem` object:\n```js\n{\n  id: string,\n  name: string\n}\n```\n\n#### addInventoryChangedListener = async cb =>\n\nRegisters a callback function with the inventory changed event. When workspace inventory changes the callback function will be called with the InventoryChangedobject. Returns undefined.\n\n*Current limitations: Kind and Function updates only occur where the name property is changed. Updates to services outside of the workspace will not be detected. \n\n**Use-case note: an ‘update’ diff for inventory services is unlikely in general usage. \n\n```js\nconst inventoryCB = ({diff}) => {\n  if(diff.kinds) console.log('KINDS CHANGED',diff.kinds)\n  if(diff.functions) console.log('FUNCTIONS CHANGED', diff.functions)\n  if(diff.services) console.log('SERVICES CHANGED',diff.services)\n}\n\nAssistantAPIClient.addInventoryChangedListener(inventoryCB)\n```\n\nThis function exists on the Q-Assisant-Client only--only enableSelectionChangedNotification is used on the API side. \n\n#### removeInventoryChangedListener = async cb =>\n\nRemoves an inventory changed listener given the referenced callback. If no callback is specified, all listeners will be removed. Returns undefined.\n\n```js\nAssistantAPIClient.removeInventoryChangedListener(inventoryCB)\n```\n\nThis function exists on the Q-Assisant-Client only--only disableSelectionChangedNotification is used on the API side. \n\n## Troubleshooting Assistant Issues\n### Assistant root file has loaded, but not other content\nObserving in the browser's dev tools that some resources have loaded correctly (usually the root), but other's haven't (usually nested files or chunks), is indicative of a failure of Q Gateway to proxy due to not having a 'relative' path structure.\n\n### You are seeing post-robot `NO ACK` errors in the console.\nThese errors stem from a failed acknowledgement for a call either between the client and the API or vice-versa. Here, this means that the web app 'window' (the assistant) cannot communicate with, or access, the 'window.parent' (Maana K-Portal) object. Improper CORS configuration is a common culprit (also verify if using docker or nginx that your proxying and networking is configured correctly to allow communication and to accout for CORS).","readmeFilename":"README.md","gitHead":"c9be9cba0c2067439a26fccd693930f00247c3ac","_id":"@io-maana/q-assistant-client@3.2.1-beta.13","_npmVersion":"6.4.1","_nodeVersion":"10.15.3","_npmUser":{"name":"teamcitymaana","email":"teamcity@maana.io"},"dist":{"integrity":"sha512-XyCwohA3w46BWVakUi4KPf6zgBKWEyz7fxUbHrZz+Kz1Udy2P020CwsSSD8WZC/4UU5LAFMwkZc1F+mTS7arHw==","shasum":"839c5bd9567e77d203c95a11d0f693fb1541709f","tarball":"https://registry.npmjs.org/@io-maana/q-assistant-client/-/q-assistant-client-3.2.1-beta.13.tgz","fileCount":5,"unpackedSize":28138,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJdpJ7DCRA9TVsSAnZWagAAyKgQAIaYWqXTYVJAcvc2Cb/b\nRnMYTQkRt9uuE/Q+bIUGDbTGLBVY3wti1gFEWvnr4bsSPKJhkAXasAeHbSJC\nfPoSxLW9juEzNPHTHKd6XqVlVBk9GPCPcjmlqIgO/yolh1dNbEchD3tKo65H\nrCLweljXAwYj1L0giFnO8NJdXndztYd3jmQ+EeX7sbdaZrREb0T5I2BxZki1\nlED0aEdsoC7a3qUbsuuf7tBTdiHOO0HIdJ+8c0IegpLt2FOeattGxCJ2IF/w\ndabtBZoZp5CG23qSUfJiyqtSUibXhD84PgKD2+I2ffdbuPYLNR2WzGxjVYA1\n/jEgsXFU7sNIV/Vj0wAABH+GczEWavoVOvuaOlsgbJefhdh3gsqxTHpqI4S4\nU1PULTPeMFfHzfBg3qbjg8aEjflpU+TECOuElPkoYRPde+sKs8gkcUJAkSpG\ns3QfmOyntWAwP3Qs+VVCBHK9m4xam8XwFynn7FnC7UgUAjahAxk4aidppqSe\nTfV6vYvU8HJZh3xrICAY7v62uLmNmosA09+hdpjZdmhLBvTrmzqPDLAdSeXQ\n7RH3WP+F+7R3BCVzW73rMM9nMfr9+TWHGvXYTR2WWNluHdnZnoF1ASyPLijH\nJBwwnbXqQf7bfUhq1GQpNmuXftQIYe38Kmb8YMMWPdRzVITCtFzYtM9/tDiN\nHR8q\r\n=w3w7\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEQCIBtXmDUGt4FJirE5V79+7Pvo986iwZlr5yM7qd1lqhYIAiAfEKaXib/5AvJajyAirbXxWzv+rbt0lV8YD875fnarMg=="}]},"maintainers":[{"name":"abatyuk","email":"andrey@maana.io"},{"name":"bzvetey","email":"bzvestey@gmail.com"},{"name":"rpovey","email":"rob@maana.io"},{"name":"teamcitymaana","email":"teamcity@maana.io"},{"name":"witt3rd","email":"witt3rd@witt3rd.com"}],"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/q-assistant-client_3.2.1-beta.13_1571069635147_0.5257181404132603"},"_hasShrinkwrap":false},"3.2.1-beta.14":{"name":"@io-maana/q-assistant-client","version":"3.2.1-beta.14","description":"JavaScript package to streamline communication between an assistant and the Maana Q Assistant API.","main":"build/AssistantAPIClient.js","scripts":{"build":"babel src --out-dir build","prepack":"npm run build","test":"echo \"Error: no test specified\" && exit 1"},"repository":{"type":"git","url":"git+https://github.com/maana-io/q-assistant-client.git"},"keywords":["Maana","Q"],"author":{"name":"Logan Gore @ Maana.io"},"license":"MIT","bugs":{"url":"https://github.com/maana-io/q-assistant-client/issues"},"homepage":"https://github.com/maana-io/q-assistant-client#readme","dependencies":{"post-robot":"^10.0.18"},"devDependencies":{"@babel/cli":"^7.5.5","@babel/core":"^7.5.5","@babel/plugin-proposal-class-properties":"^7.5.5","@babel/preset-env":"^7.5.5"},"readme":"# q-assistant-client\nA lightweight JavaScript client for Maana-Q Assistant developers that wraps post-message communication between an embedded Maana-Q assistant and the Maana-Q UI.\n\n## Abstract\nThe Q-Assistant-Client is intented to be used in a web application being leveraged as a Maana Q assistant (embedded as an iframe).\nThis assistant client will facilitate communication between the assistant and the parent frame.\nThe client provides a rich, asynchronous experience over what would otherwise be 'fire-and-forget'-style messaging \nvia post-post message communication. \n\n## Requirements and Assumptions\n\n### Post-Robot Library\nThe Maana Knowledge Portal (KPortal) uses the kraken/post-robot library [kraken/post-robot](https://github.com/krakenjs/post-robot) to enrich the communication with the assistant. Post-robot allows for asynchronous, promise-based request/response style behavior between the assistant and the assistant API.\n\nThe API requires that the client use the post-robot library. This assistant-client library is the easiest way to achieve this, and also adds a fair amount of 'sugar' to the process to improve developer productivity. Developers could, however, use post-robot directly in their own client implementation. \n\n### Maana-Gateway Proxy Requirements\nThe Maana-Gateway service requires relative paths (paths relative to the root) in the assistant web application in order to proxy the application and its content. For create-react-apps, for instance, this means setting \"homepage\" to \".\" in the package.json file.\n\n## Singleton Instance\nThe client is exported as a singleton to avoid duplicate registration on event listeners.\nYou can import the instance like this:\n\n```js\nimport AssistantAPIClient from '@io-maana/q-assistant-client';\n```\n\nFunction calls can be made against the client instance like any other javascript object. They are all async.\n\n```js\nconst workspace = await AssistantAPIClient.getWorkspace(); \nconsole.log(\"Workspace:\", workspace)\n```\n\n## Dependencies\nPost-Robot\nhttps://github.com/krakenjs/post-robot\n\nPost-robot is used to provide a richer communication layer atop post-message.\n\n## Examples\n@TODO Logan\n\n## API Documentation\n\n### State management\n\n#### clearState = () =>\n\nThis will clear all ‘attached’ state between the assistant and the API. \n\nSpecifically, this will clear selection and inventory changed event listeners. \n\n```js\nawait AssistantAPIClient.clearState()\n```\n\n### User Info\nThe `UserInfo` object:\n```js\n{\n email: string,\n name: string\n}\n```\n\n#### getUserInfo = () => \n\nReturns a Userinfo object pertaining to the logged in user.\n\n```js\nconst userInfo = await AssistantAPIClient.getUserInfo()\n```\n### Selection\nThe `Selection` object:\n```js\n{\n  kindId: string\n  kindName: string\n  id: string\n}\n```\n\n#### getCurrentSelection = () => \n\nReturns an Array of `Selection` objects:\n\n```js\nconst {selection} = await AssistantAPIClient.getCurrentSelection();\n```\n\n#### addSelectionChangedListener = async cb =>\n\nAdds a callback function to be executed upon a valid workspace selection change.\n\nCallback value is an array of Selection objects:\n\n```js\n// Create the selection callback.\nconst selectionCB = ({selection})=>{\n  console.log('Workspace selection has changed.')\n  selection.forEach(i=>{\n    console.log('Kind: ',i.kindName)\n    console.log('Instance Id:',i.id)\n    console.log('Kind Id:',i.kindId)\n  })\n}\n\n// Add the listener.\nAssistantAPIClient.addSelectionChangedListener(selectionCB);\n```\n\nThis function only exists on the Q-Assistant-Client--only enableSelectionChangedNotification is called on the API. \n\n#### removeSelectionChangedListener = async cb =>\n\nThis will have to be called on a 1:1 basis with addSelectionChangedListener calls if supplying a callback.\n\n```js\nAssistantAPIClient.removeSelectionChangedListener(selectionCB)\n```\n\n**If NOT supplying a callback to this call, all selection changed listeners will be removed.\n\n```js\nAssistantAPIClient.removeSelectionChangedListener()\n```\n\nThis function only exists on the Q-Assistant-Client--only disableSelectionChangedNotification is called on the API. \n\n\n### Services\nThe `Service` object:\n```js\n{\n   id: string,\n   name: string\n   endpointUrl: string,\n   getKinds: () => // Returns [] of Kinds objects\n   getFunctions: () => // Returns [] of Function objects\n}\n```\n\n#### getServiceById = id =>\nThis will return a service that exists within the scope of the workspace. \n** Assistant services will return null. Services outside the scope of the workspace will cause an error to be returned as 'Unable to load a Service from outside of the workspace.'\n\n```js\nconst svc = await AssistantAPIClient.getServiceById(id)\n```\n\n### Workspace\nThe `Workspace` object:\n```js\n{\nid: string,\nname: string,\ngetKinds: () => {\n  // Returns an array of functions in the workspace (includes boilerplate).\n},\ngetFunctions: () =>\n  // Returns an array of functions in the workspace (includes boilerplate).\ngetActiveGraph: () => {\n  // Returns the active Graph object.\n  // Returns null if active graph is not of type 'Knowledge Graph', or if an\n  // active graph is deleted, thereby setting active graph to null.\n},\ngetKnowledgeGraphs: () => {\n  // Returns [Graph]\n},\ngetImportedServices: () => {\n  // Returns an service imported into the workspace\n  // as a array of Service object (this calls the function\n  // that underlies getServiceById.\n  // No assistant services will be returned.\n}\n}\n```\n\n#### getWorkspace = () =>\n\nReturns a Workspace object representing the workspace. \n\n```js\nconst ws = await AssistantAPIClient.getWorkspace()\n```\n\n### Graphs\nThe `Graph` object:\n```js\n{     \nid: string,\nname: string,\noffsetX: Number,\noffsetY: Number,\nzoom: Number,\ngetNodes: async () => {\n    // Returns [Node]\n},\n\naddNode: async (type, instance, changeSelection) => {\n    // Returns Node\n},\nremoveNode: async id => {\n    // Should return nothing or error.\n    // Currently returning [] in all cases.\n},\nupdateNodeLayout: async (nodeId, { x, y, collapsed }) => {\n},\nupdateGraphLayout: async ({ offsetX, offsetY, zoom }) => {\n}\n}\n```\n\n#### Getting a graph object:\nGraph objects are obtained through an instance of a Workspace \n\n```js\nconst ag = await ws.getActiveGraph()\n```\n\nor\n\n```js\nconst kgs = await ws.getKnowledgeGraphs()\n```\n\n#### Manipulating Graphs\n\n**Only the active graph may be manipulated.\n\nAll graph manipulations should be ‘visually’ verifiable on the graph itself, i.e., adds/removes/positioning, should all be reflected on the graph itself. \n\nThe `Node` object:\n```js\n{\nid: string\nx: number\ny: number\ncollapsed: boolean\nknowledgeGraphNode {\n  id: string\n  innerKind: Kind\n  innerFunction: Function\n}\n}\n```\n\n#### addNode(type, instance, changeSelection) =>\n\nTakes type (“Function” or “Kind”), instance (the Function or Kind object), and optionally a boolean to indicate whether the selection should be changed to this new node. \n\nReturns the newly created Node object.\n\n```js\nconst node = await ag.addNode('Kind',kind)\n```\n\n#### removeNode(id) =>\n\nTakes the id of Node to be deleted. Returns either undefined or an error. \n\n```js\nawait ag.removeNode(node.id)\n```\n\n#### getNodes() =>\nReturns an array of Node objects from the graph. \n\n```js\nconst nodes = await ag.getNodes()\n```\n\n#### updateNodeLayout: async (nodeId, { x, y, collapsed})=>\n\nUpdates a Node layout given a node ID and node coordinates (`x` and/or `y`) or a `collapsed` value. x/y values must be a number, and collapsed must be a boolean. Whatever is not specified will remain current.\n\n```js\nag.updateNodeLayout(id,{x:100,y:100,collapsed:true})\n```\n\n#### updateGraphLayout: async ({ offsetX, offsetY, zoom})=>\n\nUpdates a Graph layout given numerical values for x/y offsets and the zoom. \n\n```js\nag.updateGraphLayout({offsetX:50, offsetY:50, zoom: 70})\n```\n\n### Functions\n\nThe `Function` object:\n```js\n{\n    id: string\n    name: string\n    service {\n      id: string\n      name: string\n    }\n    arguments {\n      id: string\n      name: string\n      type: string\n      modifiers: Array[string]\n      typeKindId:: string\n      kind {\n        id: string\n        name: string\n      }\n    }\n    implementation {\n      id: string\n      entrypoint {\n        id: string\n      }\n      operations {\n        id: string\n        type: string\n        function {\n          id: string\n          name: string\n        }\n        argumentValues {\n          id: string\n          argument {\n            id: string\n          }\n          operation {\n            id: string\n          }\n          argumentRef: string\n        }\n      }\n    }\n    isGenerated: boolean\n    functionType: string\n    graphqlOperationType: string\n    outputType: string\n    outputKindId: string\n    outputModifiers: Array[string]\n    kind {\n      id: string\n      name: string\n    }\n}\n```\n\n`FunctionExecutionResult` object:\n```js\n{\n  id: string,\n  result: JSON\n}\n```\n\n#### executeFunction = ( {id, variables, resolve} ) =>\n\nExecutes a function based on its id, with optional inputs for variables and a resolve string (this specifies the fields to be returned, which must be valid based on the result).\n\nReturns : JSON matching shape of result , unless no sub-selection of fields is required in the execution.\n\nThis following piece of code will execute a Function given a function ID, and pass in variables for ‘example’, requesting back id and name fields. \n\n```js \nconst res = await AssistantAPIClient.executeFunction({functionId: func.id, variables: {\"variableName\": \"variableValue\"}, resolve: \"{ id name }\");\n```\n\n#### createFunction = input =>\n\nCreates a function based on the input provided. \n\nReturns: the created Function object.\n\n**Using create function will only place the function in the workspace’s inventory--it will not place the function as a node on the Graph. In order to do this, you must pass the created function into the addNode function on the active Graph, making sure to specify ‘Function' as the type.\n\n```js\nconst createFunctionInput = {\n  name:\"yourName\",\n  arguments:[],\n  outputType: \"STRING\",\n  graphqlOperationType:\"QUERY\",\n  functionType: \"CKG\"\n}\n  \nconst createdFunction = await AssistantAPIClient.createFunction(createFunctionInput)\n```\n\n#### updateFunction = input =>\n\nInput is the same for creating a function. It’s important to note that the arguments property will be replaced in it’s entirety with whatever is provided (if a value is provided.\n\nReturns the updated `Function` object.\n\n```js\nconst updatedFunction = await AssistantAPIClient.updateFunction(input);\n```\n\n#### deleteFunction = input =>\n\nInput is the id of the Function to be deleted. Returns the deleted function as a promise.\n\n```js\nconst deletedFunction = await AssistantAPIClient.deleteFunction('id...');\n```\n\n#### getFunctionById = id =>\n\nReturns a Function as a promise based on the ID provided.\n\n```js\nconst func = await AssistantAPIClient.getFunctionById('id...');\n```\n\n#### addFunctionExecutionListener = async (id, cb) =>\n\nAssociates a callback function with the execution of a particular Function. When the Function matching the id parameter is executed, its FunctionExecutionResult object passed to the callback. Returns undefined.\n\nExample function execution callback and listener registration:\n\n```js\nfunction exampleFunctionCB (result){\n  console.log(`Function executed with result:`, result)\n}\n\nAssistantAPIClient.addFunctionExecutionListener('id...', exampleFunctionCB)\n```\n\n#### removeFunctionExecutionListener = async (id, cb) =>\n\nRemoves a Function execution listener based on the function ID and a reference to the callback function. If no callback is supplied, all listeners associated with the Function ID will be removed. Returns undefined.\n\n```js\nAssistantAPIClient.removeFunctionExecutionListener('id..', exampleFunctionCB)\n```\n\n### Kinds\nThe `Kind` object:\n```js\n{\n    id: string\n    name: string\n    service: {\n      id\n      name\n    }\n    isGenerated: boolean\n    schema {\n      id: string\n      name: string\n      type: string\n      typeKindId: string\n      modifiers: Array[string]\n      kind {\n        id: string\n        name: string\n      }\n    }\n}\n```\n\n#### createKind = input =>\n\nCreates a Kind based on an input object. Returns a promise that resolves to the created Kind object.\n\n```js\nconst kindInput = {\n name: \"someKind\",\n schema:[\n  { name: \"someField1\", type: STRING },\n  { name: \"someField2\", type: STRING }\n ]\n}\n\nconst newKind = await AssistantAPIClient.createKind(kindInput)\n```\n\n#### updateKind = input =>\n\nUpdates a Kind based on an input object. \n\nUpdate Semantics: Only properties specified will be updated. If updating the schema, the entire schema must be specified as it will be replaced in its entirety. \n\nReturns the updated `Kind` object.\n\n```js\nconst updated = await AssistantAPIClient.updateKind(input)\n```\n\n#### deleteKind = input =>\n\nDeletes a Kind given a kind ID.\n\n```js\nconst deleted = await AssistantAPIClient.deleteKind(input)\n```\n\n#### getKindById = id =>\n\nReturns a promise that resolves to a Kind object given the specified kind ID. Only kinds in the workspace or those of imported services will be returned. \n\n```js\nconst kind = await AssistantAPIClient.getKindById(id)\n```\n\n### Inventory\n\nThe `InventoryChanged` object:\n```js\n{\n  kinds: {\n    adds: [DiffItem]\n    deletes: [DiffItem]\n    updates: [DiffItem]\n  }\n  functions:{\n    adds: [DiffItem]\n    deletes: [DiffItem]\n    updates: [DiffItem]\n  }\n  services: {\n    adds: [DiffItem]\n    deletes: [DiffItem]\n    updates: [DiffItem]\n  }\n}\n```\n\nThe `DiffItem` object:\n```js\n{\n  id: string,\n  name: string\n}\n```\n\n#### addInventoryChangedListener = async cb =>\n\nRegisters a callback function with the inventory changed event. When workspace inventory changes the callback function will be called with the InventoryChangedobject. Returns undefined.\n\n*Current limitations: Kind and Function updates only occur where the name property is changed. Updates to services outside of the workspace will not be detected. \n\n**Use-case note: an ‘update’ diff for inventory services is unlikely in general usage. \n\n```js\nconst inventoryCB = ({diff}) => {\n  if(diff.kinds) console.log('KINDS CHANGED',diff.kinds)\n  if(diff.functions) console.log('FUNCTIONS CHANGED', diff.functions)\n  if(diff.services) console.log('SERVICES CHANGED',diff.services)\n}\n\nAssistantAPIClient.addInventoryChangedListener(inventoryCB)\n```\n\nThis function exists on the Q-Assisant-Client only--only enableSelectionChangedNotification is used on the API side. \n\n#### removeInventoryChangedListener = async cb =>\n\nRemoves an inventory changed listener given the referenced callback. If no callback is specified, all listeners will be removed. Returns undefined.\n\n```js\nAssistantAPIClient.removeInventoryChangedListener(inventoryCB)\n```\n\nThis function exists on the Q-Assisant-Client only--only disableSelectionChangedNotification is used on the API side. \n\n## Troubleshooting Assistant Issues\n### Assistant root file has loaded, but not other content\nObserving in the browser's dev tools that some resources have loaded correctly (usually the root), but other's haven't (usually nested files or chunks), is indicative of a failure of Q Gateway to proxy due to not having a 'relative' path structure.\n\n### You are seeing post-robot `NO ACK` errors in the console.\nThese errors stem from a failed acknowledgement for a call either between the client and the API or vice-versa. Here, this means that the web app 'window' (the assistant) cannot communicate with, or access, the 'window.parent' (Maana K-Portal) object. Improper CORS configuration is a common culprit (also verify if using docker or nginx that your proxying and networking is configured correctly to allow communication and to accout for CORS).","readmeFilename":"README.md","gitHead":"ce2d1dd652f03fd4442e64a2f350bd764504f9ba","_id":"@io-maana/q-assistant-client@3.2.1-beta.14","_npmVersion":"6.4.1","_nodeVersion":"10.15.3","_npmUser":{"name":"teamcitymaana","email":"teamcity@maana.io"},"dist":{"integrity":"sha512-36ekQ4DFycKIXBdjOUTYThpFWuPq5oMcCGu5DSLKyqYg+HkLAsTd69zYfxc+XJ8dKJAEOx6Dn/fIEUKWc+5NFg==","shasum":"4d03c1110542e16f3cf044aaad30ab8d7a6403b6","tarball":"https://registry.npmjs.org/@io-maana/q-assistant-client/-/q-assistant-client-3.2.1-beta.14.tgz","fileCount":5,"unpackedSize":29024,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJdsJ81CRA9TVsSAnZWagAAXo0P/0R8b+tTAJ8NoT3b5634\nBuZl15rpjp7cOg+YCYjio99dnscgBsn2fYcRzDF51OvfIsN3oAKWm3qb7qci\n9SYt7hIMhqDV0ku5DSNvNuT4g91SHousjubvojrooKD62Fp4AGuY2sTXp/cU\nsnhjIZ+gi4tigCfRK/lFeudg0fqwiQ3R3sBd+tRvZmAbzpReDGyAB8klz4Sh\ndU/oFIj8ekNZebrJDuYCCs/FCDLeFc7DvC08oqY1Hy94nX5Vi4+apSa74vj+\nFG0sYEw981/LsZh4jx6YPeLLmYtq08PdOINDnY7sDiJoOt/FxkxokOPWvYMz\n5Jvpl3/WnFz/rUDfgNQ8TZgp3cxrDmzBLW2ezVE0F5zZHjsGi3XElhs6FmMf\nTv8cws/fAHl7sk/n5YsK1JTygZimuPGmhY/2NJ04zp2jzn262VFIJFjFq5gt\nGi9+r/BFcbqQJDMr0UUPqDyyXStdrBW0aRr7HnG9UhPE5oGVSCEQ/bwgicf9\nYj9w2ghzMoApIPNIG1A705wqZDlWRmQSkDaq/baG3Tp2BeY7Of6226u7zODj\nhVh0pLP6qaenEn3nFbEuUdZjxnAu1Xh0qU+IAbzejGHH300MNgFwZsSUpd8O\nvGgbC4/8JcR85BzSlRaf/VJMKguLXpicz6a4FtoeSr5zAC2dAaFd87ffeUtd\nWM0o\r\n=DwIw\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEQCIHeyx7aK4N44Xo0BEFL+a7nItwUYZjkZ0LAk3NaaOmRwAiAgt0mjP6lys+FO+MKyLTjY20MzdZtS8xAjdr5II48bpw=="}]},"maintainers":[{"name":"abatyuk","email":"andrey@maana.io"},{"name":"bzvetey","email":"bzvestey@gmail.com"},{"name":"rpovey","email":"rob@maana.io"},{"name":"teamcitymaana","email":"teamcity@maana.io"},{"name":"witt3rd","email":"witt3rd@witt3rd.com"}],"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/q-assistant-client_3.2.1-beta.14_1571856180681_0.061718611021173375"},"_hasShrinkwrap":false},"3.2.1-beta.15":{"name":"@io-maana/q-assistant-client","version":"3.2.1-beta.15","description":"JavaScript package to streamline communication between an assistant and the Maana Q Assistant API.","main":"build/AssistantAPIClient.js","scripts":{"build":"babel src --out-dir build","prepack":"npm run build","test":"echo \"Error: no test specified\" && exit 1"},"repository":{"type":"git","url":"git+https://github.com/maana-io/q-assistant-client.git"},"keywords":["Maana","Q"],"author":{"name":"Logan Gore @ Maana.io"},"license":"MIT","bugs":{"url":"https://github.com/maana-io/q-assistant-client/issues"},"homepage":"https://github.com/maana-io/q-assistant-client#readme","dependencies":{"post-robot":"10.0.18"},"devDependencies":{"@babel/cli":"^7.5.5","@babel/core":"^7.5.5","@babel/plugin-proposal-class-properties":"^7.5.5","@babel/preset-env":"^7.5.5"},"readme":"# q-assistant-client\nA lightweight JavaScript client for Maana-Q Assistant developers that wraps post-message communication between an embedded Maana-Q assistant and the Maana-Q UI.\n\n## Abstract\nThe Q-Assistant-Client is intented to be used in a web application being leveraged as a Maana Q assistant (embedded as an iframe).\nThis assistant client will facilitate communication between the assistant and the parent frame.\nThe client provides a rich, asynchronous experience over what would otherwise be 'fire-and-forget'-style messaging \nvia post-post message communication. \n\n## Requirements and Assumptions\n\n### Post-Robot Library\nThe Maana Knowledge Portal (KPortal) uses the kraken/post-robot library [kraken/post-robot](https://github.com/krakenjs/post-robot) to enrich the communication with the assistant. Post-robot allows for asynchronous, promise-based request/response style behavior between the assistant and the assistant API.\n\nThe API requires that the client use the post-robot library. This assistant-client library is the easiest way to achieve this, and also adds a fair amount of 'sugar' to the process to improve developer productivity. Developers could, however, use post-robot directly in their own client implementation. \n\n### Maana-Gateway Proxy Requirements\nThe Maana-Gateway service requires relative paths (paths relative to the root) in the assistant web application in order to proxy the application and its content. For create-react-apps, for instance, this means setting \"homepage\" to \".\" in the package.json file.\n\n## Singleton Instance\nThe client is exported as a singleton to avoid duplicate registration on event listeners.\nYou can import the instance like this:\n\n```js\nimport AssistantAPIClient from '@io-maana/q-assistant-client';\n```\n\nFunction calls can be made against the client instance like any other javascript object. They are all async.\n\n```js\nconst workspace = await AssistantAPIClient.getWorkspace(); \nconsole.log(\"Workspace:\", workspace)\n```\n\n## Dependencies\nPost-Robot\nhttps://github.com/krakenjs/post-robot\n\nPost-robot is used to provide a richer communication layer atop post-message.\n\n## Examples\n@TODO Logan\n\n## API Documentation\n\n### State management\n\n#### clearState = () =>\n\nThis will clear all ‘attached’ state between the assistant and the API. \n\nSpecifically, this will clear selection and inventory changed event listeners. \n\n```js\nawait AssistantAPIClient.clearState()\n```\n\n### User Info\nThe `UserInfo` object:\n```js\n{\n email: string,\n name: string\n}\n```\n\n#### getUserInfo = () => \n\nReturns a Userinfo object pertaining to the logged in user.\n\n```js\nconst userInfo = await AssistantAPIClient.getUserInfo()\n```\n### Selection\nThe `Selection` object:\n```js\n{\n  kindId: string\n  kindName: string\n  id: string\n}\n```\n\n#### getCurrentSelection = () => \n\nReturns an Array of `Selection` objects:\n\n```js\nconst {selection} = await AssistantAPIClient.getCurrentSelection();\n```\n\n#### addSelectionChangedListener = async cb =>\n\nAdds a callback function to be executed upon a valid workspace selection change.\n\nCallback value is an array of Selection objects:\n\n```js\n// Create the selection callback.\nconst selectionCB = ({selection})=>{\n  console.log('Workspace selection has changed.')\n  selection.forEach(i=>{\n    console.log('Kind: ',i.kindName)\n    console.log('Instance Id:',i.id)\n    console.log('Kind Id:',i.kindId)\n  })\n}\n\n// Add the listener.\nAssistantAPIClient.addSelectionChangedListener(selectionCB);\n```\n\nThis function only exists on the Q-Assistant-Client--only enableSelectionChangedNotification is called on the API. \n\n#### removeSelectionChangedListener = async cb =>\n\nThis will have to be called on a 1:1 basis with addSelectionChangedListener calls if supplying a callback.\n\n```js\nAssistantAPIClient.removeSelectionChangedListener(selectionCB)\n```\n\n**If NOT supplying a callback to this call, all selection changed listeners will be removed.\n\n```js\nAssistantAPIClient.removeSelectionChangedListener()\n```\n\nThis function only exists on the Q-Assistant-Client--only disableSelectionChangedNotification is called on the API. \n\n\n### Services\nThe `Service` object:\n```js\n{\n   id: string,\n   name: string\n   endpointUrl: string,\n   getKinds: () => // Returns [] of Kinds objects\n   getFunctions: () => // Returns [] of Function objects\n}\n```\n\n#### getServiceById = id =>\nThis will return a service that exists within the scope of the workspace. \n** Assistant services will return null. Services outside the scope of the workspace will cause an error to be returned as 'Unable to load a Service from outside of the workspace.'\n\n```js\nconst svc = await AssistantAPIClient.getServiceById(id)\n```\n\n### Workspace\nThe `Workspace` object:\n```js\n{\nid: string,\nname: string,\ngetKinds: () => {\n  // Returns an array of functions in the workspace (includes boilerplate).\n},\ngetFunctions: () =>\n  // Returns an array of functions in the workspace (includes boilerplate).\ngetActiveGraph: () => {\n  // Returns the active Graph object.\n  // Returns null if active graph is not of type 'Knowledge Graph', or if an\n  // active graph is deleted, thereby setting active graph to null.\n},\ngetKnowledgeGraphs: () => {\n  // Returns [Graph]\n},\ngetImportedServices: () => {\n  // Returns an service imported into the workspace\n  // as a array of Service object (this calls the function\n  // that underlies getServiceById.\n  // No assistant services will be returned.\n}\n}\n```\n\n#### getWorkspace = () =>\n\nReturns a Workspace object representing the workspace. \n\n```js\nconst ws = await AssistantAPIClient.getWorkspace()\n```\n\n### Graphs\nThe `Graph` object:\n```js\n{     \nid: string,\nname: string,\noffsetX: Number,\noffsetY: Number,\nzoom: Number,\ngetNodes: async () => {\n    // Returns [Node]\n},\n\naddNode: async (type, instance, changeSelection) => {\n    // Returns Node\n},\nremoveNode: async id => {\n    // Should return nothing or error.\n    // Currently returning [] in all cases.\n},\nupdateNodeLayout: async (nodeId, { x, y, collapsed }) => {\n},\nupdateGraphLayout: async ({ offsetX, offsetY, zoom }) => {\n}\n}\n```\n\n#### Getting a graph object:\nGraph objects are obtained through an instance of a Workspace \n\n```js\nconst ag = await ws.getActiveGraph()\n```\n\nor\n\n```js\nconst kgs = await ws.getKnowledgeGraphs()\n```\n\n#### Manipulating Graphs\n\n**Only the active graph may be manipulated.\n\nAll graph manipulations should be ‘visually’ verifiable on the graph itself, i.e., adds/removes/positioning, should all be reflected on the graph itself. \n\nThe `Node` object:\n```js\n{\nid: string\nx: number\ny: number\ncollapsed: boolean\nknowledgeGraphNode {\n  id: string\n  innerKind: Kind\n  innerFunction: Function\n}\n}\n```\n\n#### addNode(type, instance, changeSelection) =>\n\nTakes type (“Function” or “Kind”), instance (the Function or Kind object), and optionally a boolean to indicate whether the selection should be changed to this new node. \n\nReturns the newly created Node object.\n\n```js\nconst node = await ag.addNode('Kind',kind)\n```\n\n#### removeNode(id) =>\n\nTakes the id of Node to be deleted. Returns either undefined or an error. \n\n```js\nawait ag.removeNode(node.id)\n```\n\n#### getNodes() =>\nReturns an array of Node objects from the graph. \n\n```js\nconst nodes = await ag.getNodes()\n```\n\n#### updateNodeLayout: async (nodeId, { x, y, collapsed})=>\n\nUpdates a Node layout given a node ID and node coordinates (`x` and/or `y`) or a `collapsed` value. x/y values must be a number, and collapsed must be a boolean. Whatever is not specified will remain current.\n\n```js\nag.updateNodeLayout(id,{x:100,y:100,collapsed:true})\n```\n\n#### updateGraphLayout: async ({ offsetX, offsetY, zoom})=>\n\nUpdates a Graph layout given numerical values for x/y offsets and the zoom. \n\n```js\nag.updateGraphLayout({offsetX:50, offsetY:50, zoom: 70})\n```\n\n### Functions\n\nThe `Function` object:\n```js\n{\n    id: string\n    name: string\n    service {\n      id: string\n      name: string\n    }\n    arguments {\n      id: string\n      name: string\n      type: string\n      modifiers: Array[string]\n      typeKindId:: string\n      kind {\n        id: string\n        name: string\n      }\n    }\n    implementation {\n      id: string\n      entrypoint {\n        id: string\n      }\n      operations {\n        id: string\n        type: string\n        function {\n          id: string\n          name: string\n        }\n        argumentValues {\n          id: string\n          argument {\n            id: string\n          }\n          operation {\n            id: string\n          }\n          argumentRef: string\n        }\n      }\n    }\n    isGenerated: boolean\n    functionType: string\n    graphqlOperationType: string\n    outputType: string\n    outputKindId: string\n    outputModifiers: Array[string]\n    kind {\n      id: string\n      name: string\n    }\n}\n```\n\n`FunctionExecutionResult` object:\n```js\n{\n  id: string,\n  result: JSON\n}\n```\n\n#### executeFunction = ( {id, variables, resolve} ) =>\n\nExecutes a function based on its id, with optional inputs for variables and a resolve string (this specifies the fields to be returned, which must be valid based on the result).\n\nReturns : JSON matching shape of result , unless no sub-selection of fields is required in the execution.\n\nThis following piece of code will execute a Function given a function ID, and pass in variables for ‘example’, requesting back id and name fields. \n\n```js \nconst res = await AssistantAPIClient.executeFunction({functionId: func.id, variables: {\"variableName\": \"variableValue\"}, resolve: \"{ id name }\");\n```\n\n#### createFunction = input =>\n\nCreates a function based on the input provided. \n\nReturns: the created Function object.\n\n**Using create function will only place the function in the workspace’s inventory--it will not place the function as a node on the Graph. In order to do this, you must pass the created function into the addNode function on the active Graph, making sure to specify ‘Function' as the type.\n\n```js\nconst createFunctionInput = {\n  name:\"yourName\",\n  arguments:[],\n  outputType: \"STRING\",\n  graphqlOperationType:\"QUERY\",\n  functionType: \"CKG\"\n}\n  \nconst createdFunction = await AssistantAPIClient.createFunction(createFunctionInput)\n```\n\n#### updateFunction = input =>\n\nInput is the same for creating a function. It’s important to note that the arguments property will be replaced in it’s entirety with whatever is provided (if a value is provided.\n\nReturns the updated `Function` object.\n\n```js\nconst updatedFunction = await AssistantAPIClient.updateFunction(input);\n```\n\n#### deleteFunction = input =>\n\nInput is the id of the Function to be deleted. Returns the deleted function as a promise.\n\n```js\nconst deletedFunction = await AssistantAPIClient.deleteFunction('id...');\n```\n\n#### getFunctionById = id =>\n\nReturns a Function as a promise based on the ID provided.\n\n```js\nconst func = await AssistantAPIClient.getFunctionById('id...');\n```\n\n#### addFunctionExecutionListener = async (id, cb) =>\n\nAssociates a callback function with the execution of a particular Function. When the Function matching the id parameter is executed, its FunctionExecutionResult object passed to the callback. Returns undefined.\n\nExample function execution callback and listener registration:\n\n```js\nfunction exampleFunctionCB (result){\n  console.log(`Function executed with result:`, result)\n}\n\nAssistantAPIClient.addFunctionExecutionListener('id...', exampleFunctionCB)\n```\n\n#### removeFunctionExecutionListener = async (id, cb) =>\n\nRemoves a Function execution listener based on the function ID and a reference to the callback function. If no callback is supplied, all listeners associated with the Function ID will be removed. Returns undefined.\n\n```js\nAssistantAPIClient.removeFunctionExecutionListener('id..', exampleFunctionCB)\n```\n\n### Kinds\nThe `Kind` object:\n```js\n{\n    id: string\n    name: string\n    service: {\n      id\n      name\n    }\n    isGenerated: boolean\n    schema {\n      id: string\n      name: string\n      type: string\n      typeKindId: string\n      modifiers: Array[string]\n      kind {\n        id: string\n        name: string\n      }\n    }\n}\n```\n\n#### createKind = input =>\n\nCreates a Kind based on an input object. Returns a promise that resolves to the created Kind object.\n\n```js\nconst kindInput = {\n name: \"someKind\",\n schema:[\n  { name: \"someField1\", type: STRING },\n  { name: \"someField2\", type: STRING }\n ]\n}\n\nconst newKind = await AssistantAPIClient.createKind(kindInput)\n```\n\n#### updateKind = input =>\n\nUpdates a Kind based on an input object. \n\nUpdate Semantics: Only properties specified will be updated. If updating the schema, the entire schema must be specified as it will be replaced in its entirety. \n\nReturns the updated `Kind` object.\n\n```js\nconst updated = await AssistantAPIClient.updateKind(input)\n```\n\n#### deleteKind = input =>\n\nDeletes a Kind given a kind ID.\n\n```js\nconst deleted = await AssistantAPIClient.deleteKind(input)\n```\n\n#### getKindById = id =>\n\nReturns a promise that resolves to a Kind object given the specified kind ID. Only kinds in the workspace or those of imported services will be returned. \n\n```js\nconst kind = await AssistantAPIClient.getKindById(id)\n```\n\n### Inventory\n\nThe `InventoryChanged` object:\n```js\n{\n  kinds: {\n    adds: [DiffItem]\n    deletes: [DiffItem]\n    updates: [DiffItem]\n  }\n  functions:{\n    adds: [DiffItem]\n    deletes: [DiffItem]\n    updates: [DiffItem]\n  }\n  services: {\n    adds: [DiffItem]\n    deletes: [DiffItem]\n    updates: [DiffItem]\n  }\n}\n```\n\nThe `DiffItem` object:\n```js\n{\n  id: string,\n  name: string\n}\n```\n\n#### addInventoryChangedListener = async cb =>\n\nRegisters a callback function with the inventory changed event. When workspace inventory changes the callback function will be called with the InventoryChangedobject. Returns undefined.\n\n*Current limitations: Kind and Function updates only occur where the name property is changed. Updates to services outside of the workspace will not be detected. \n\n**Use-case note: an ‘update’ diff for inventory services is unlikely in general usage. \n\n```js\nconst inventoryCB = ({diff}) => {\n  if(diff.kinds) console.log('KINDS CHANGED',diff.kinds)\n  if(diff.functions) console.log('FUNCTIONS CHANGED', diff.functions)\n  if(diff.services) console.log('SERVICES CHANGED',diff.services)\n}\n\nAssistantAPIClient.addInventoryChangedListener(inventoryCB)\n```\n\nThis function exists on the Q-Assisant-Client only--only enableSelectionChangedNotification is used on the API side. \n\n#### removeInventoryChangedListener = async cb =>\n\nRemoves an inventory changed listener given the referenced callback. If no callback is specified, all listeners will be removed. Returns undefined.\n\n```js\nAssistantAPIClient.removeInventoryChangedListener(inventoryCB)\n```\n\nThis function exists on the Q-Assisant-Client only--only disableSelectionChangedNotification is used on the API side. \n\n## Troubleshooting Assistant Issues\n### Assistant root file has loaded, but not other content\nObserving in the browser's dev tools that some resources have loaded correctly (usually the root), but other's haven't (usually nested files or chunks), is indicative of a failure of Q Gateway to proxy due to not having a 'relative' path structure.\n\n### You are seeing post-robot `NO ACK` errors in the console.\nThese errors stem from a failed acknowledgement for a call either between the client and the API or vice-versa. Here, this means that the web app 'window' (the assistant) cannot communicate with, or access, the 'window.parent' (Maana K-Portal) object. Improper CORS configuration is a common culprit (also verify if using docker or nginx that your proxying and networking is configured correctly to allow communication and to accout for CORS).","readmeFilename":"README.md","gitHead":"bbdffd8aa00686daa979f4a4f162dd2c005476a8","_id":"@io-maana/q-assistant-client@3.2.1-beta.15","_npmVersion":"6.4.1","_nodeVersion":"10.15.3","_npmUser":{"name":"teamcitymaana","email":"teamcity@maana.io"},"dist":{"integrity":"sha512-heafdomcND7CF6gE9qw8R+ISvYxuZgfJQiYVSPTQ3f/p/82dc3wT9El3KZuSyu7Bv+mLaVlZnI8Kt/5ue3VNEg==","shasum":"2171eb3958ef43167fe88ae3a0cdad5ac0db2126","tarball":"https://registry.npmjs.org/@io-maana/q-assistant-client/-/q-assistant-client-3.2.1-beta.15.tgz","fileCount":5,"unpackedSize":29023,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJdwz+yCRA9TVsSAnZWagAA70EP/jHAShmO9MLZcRo8/WsC\nSFpm+IHVUa7GP5i/NR6fx8op5PvAQ5aIUOnz9+0Z5d0RYj1tAsTIvhXazjqX\nKSeurNUckSXebosr2EmE22jR7v5L10HAQmXBF/Qu0tk46hYX48FNKP5CzP/T\nCfddKcFhWcrMi0ZaWE4c8NtOqCtdUax3PD61/CP6xTDA5/hOcHh1ZPy6BCxB\nO06cLEDVfTjYn9lsnTxqYnrYKogzeNTAhRJ4FpLLYixXcTJL0q/HV6/EbBN7\n/Nil75DCnksfy5hESOrtjofWa6ynf8p1bmJAf2M2s+yOi1pmABYdWfaLGBFa\nozvpTUjtaxqkWU/mAlcw+zKKTl4TMFnmYVrKNhpQLuxQ5h98K5e+89lNOg6H\nTTGHm5S0sYJp0eHfq593x+jngMfY+TfCfBeP5kB5BEyV5nIZFz10t67BEkL4\n+Q0AlVvwgbgjkxGbbAJSzHTRmkL/SVJnsuBmatqTgoNU3euFa/bW0YPs01YU\nnIzb2wngO+7Xx0ZVTm62f3HNF7b3dOZVl2vK/uIccDowacJ6d9gxrN67niiK\n8MLwusa/1W/Wo68AkkFw0x1keUtTwnJ8AW0aFwiUShSv1eYABd/ijXC8fvbO\nFSGzjYRI1lyN5KLRWzRjus5l6qNcQcLVXPlgvbbsz1i67MQUKzTkCJQVGIXB\nkonB\r\n=JHvM\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIQDlr3wRojFl9GczhoYNpYOjTtb4nJH16SGGX1DPyrBDrgIgL6FuVUw+dsB6metKbDuuHOMV902CztMsdo6Ow6ectrY="}]},"maintainers":[{"name":"abatyuk","email":"andrey@maana.io"},{"name":"bzvetey","email":"bzvestey@gmail.com"},{"name":"rpovey","email":"rob@maana.io"},{"name":"teamcitymaana","email":"teamcity@maana.io"},{"name":"witt3rd","email":"witt3rd@witt3rd.com"}],"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/q-assistant-client_3.2.1-beta.15_1573076914448_0.9941124405830513"},"_hasShrinkwrap":false},"3.2.2-beta.16":{"name":"@io-maana/q-assistant-client","version":"3.2.2-beta.16","description":"JavaScript package to streamline communication between an assistant and the Maana Q Assistant API.","main":"build/AssistantAPIClient.js","scripts":{"build":"babel src --out-dir build","prepack":"npm run build","test":"echo \"Error: no test specified\" && exit 1"},"repository":{"type":"git","url":"git+https://github.com/maana-io/q-assistant-client.git"},"keywords":["Maana","Q"],"author":{"name":"Logan Gore @ Maana.io"},"license":"MIT","bugs":{"url":"https://github.com/maana-io/q-assistant-client/issues"},"homepage":"https://github.com/maana-io/q-assistant-client#readme","dependencies":{"post-robot":"10.0.18"},"devDependencies":{"@babel/cli":"^7.5.5","@babel/core":"^7.5.5","@babel/plugin-proposal-class-properties":"^7.5.5","@babel/preset-env":"^7.5.5"},"readme":"# q-assistant-client\nA lightweight JavaScript client for Maana-Q Assistant developers that wraps post-message communication between an embedded Maana-Q assistant and the Maana-Q UI.\n\n## Abstract\nThe Q-Assistant-Client is intented to be used in a web application being leveraged as a Maana Q assistant (embedded as an iframe).\nThis assistant client will facilitate communication between the assistant and the parent frame.\nThe client provides a rich, asynchronous experience over what would otherwise be 'fire-and-forget'-style messaging \nvia post-post message communication. \n\n## Requirements and Assumptions\n\n### Post-Robot Library\nThe Maana Knowledge Portal (KPortal) uses the kraken/post-robot library [kraken/post-robot](https://github.com/krakenjs/post-robot) to enrich the communication with the assistant. Post-robot allows for asynchronous, promise-based request/response style behavior between the assistant and the assistant API.\n\nThe API requires that the client use the post-robot library. This assistant-client library is the easiest way to achieve this, and also adds a fair amount of 'sugar' to the process to improve developer productivity. Developers could, however, use post-robot directly in their own client implementation. \n\n### Maana-Gateway Proxy Requirements\nThe Maana-Gateway service requires relative paths (paths relative to the root) in the assistant web application in order to proxy the application and its content. For create-react-apps, for instance, this means setting \"homepage\" to \".\" in the package.json file.\n\n## Singleton Instance\nThe client is exported as a singleton to avoid duplicate registration on event listeners.\nYou can import the instance like this:\n\n```js\nimport AssistantAPIClient from '@io-maana/q-assistant-client';\n```\n\nFunction calls can be made against the client instance like any other javascript object. They are all async.\n\n```js\nconst workspace = await AssistantAPIClient.getWorkspace(); \nconsole.log(\"Workspace:\", workspace)\n```\n\n## Dependencies\nPost-Robot\nhttps://github.com/krakenjs/post-robot\n\nPost-robot is used to provide a richer communication layer atop post-message.\n\n## Examples\n@TODO Logan\n\n## API Documentation\n\n### State management\n\n#### clearState = () =>\n\nThis will clear all ‘attached’ state between the assistant and the API. \n\nSpecifically, this will clear selection and inventory changed event listeners. \n\n```js\nawait AssistantAPIClient.clearState()\n```\n\n### User Info\nThe `UserInfo` object:\n```js\n{\n email: string,\n name: string\n}\n```\n\n#### getUserInfo = () => \n\nReturns a Userinfo object pertaining to the logged in user.\n\n```js\nconst userInfo = await AssistantAPIClient.getUserInfo()\n```\n### Selection\nThe `Selection` object:\n```js\n{\n  kindId: string\n  kindName: string\n  id: string\n}\n```\n\n#### getCurrentSelection = () => \n\nReturns an Array of `Selection` objects:\n\n```js\nconst {selection} = await AssistantAPIClient.getCurrentSelection();\n```\n\n#### addSelectionChangedListener = async cb =>\n\nAdds a callback function to be executed upon a valid workspace selection change.\n\nCallback value is an array of Selection objects:\n\n```js\n// Create the selection callback.\nconst selectionCB = ({selection})=>{\n  console.log('Workspace selection has changed.')\n  selection.forEach(i=>{\n    console.log('Kind: ',i.kindName)\n    console.log('Instance Id:',i.id)\n    console.log('Kind Id:',i.kindId)\n  })\n}\n\n// Add the listener.\nAssistantAPIClient.addSelectionChangedListener(selectionCB);\n```\n\nThis function only exists on the Q-Assistant-Client--only enableSelectionChangedNotification is called on the API. \n\n#### removeSelectionChangedListener = async cb =>\n\nThis will have to be called on a 1:1 basis with addSelectionChangedListener calls if supplying a callback.\n\n```js\nAssistantAPIClient.removeSelectionChangedListener(selectionCB)\n```\n\n**If NOT supplying a callback to this call, all selection changed listeners will be removed.\n\n```js\nAssistantAPIClient.removeSelectionChangedListener()\n```\n\nThis function only exists on the Q-Assistant-Client--only disableSelectionChangedNotification is called on the API. \n\n\n### Services\nThe `Service` object:\n```js\n{\n   id: string,\n   name: string\n   endpointUrl: string,\n   getKinds: () => // Returns [] of Kinds objects\n   getFunctions: () => // Returns [] of Function objects\n}\n```\n\n#### getServiceById = id =>\nThis will return a service that exists within the scope of the workspace. \n** Assistant services will return null. Services outside the scope of the workspace will cause an error to be returned as 'Unable to load a Service from outside of the workspace.'\n\n```js\nconst svc = await AssistantAPIClient.getServiceById(id)\n```\n\n### Workspace\nThe `Workspace` object:\n```js\n{\nid: string,\nname: string,\ngetKinds: () => {\n  // Returns an array of functions in the workspace (includes boilerplate).\n},\ngetFunctions: () =>\n  // Returns an array of functions in the workspace (includes boilerplate).\ngetActiveGraph: () => {\n  // Returns the active Graph object.\n  // Returns null if active graph is not of type 'Knowledge Graph', or if an\n  // active graph is deleted, thereby setting active graph to null.\n},\ngetKnowledgeGraphs: () => {\n  // Returns [Graph]\n},\ngetImportedServices: () => {\n  // Returns an service imported into the workspace\n  // as a array of Service object (this calls the function\n  // that underlies getServiceById.\n  // No assistant services will be returned.\n}\n}\n```\n\n#### getWorkspace = () =>\n\nReturns a Workspace object representing the workspace. \n\n```js\nconst ws = await AssistantAPIClient.getWorkspace()\n```\n\n### Graphs\nThe `Graph` object:\n```js\n{     \nid: string,\nname: string,\noffsetX: Number,\noffsetY: Number,\nzoom: Number,\ngetNodes: async () => {\n    // Returns [Node]\n},\n\naddNode: async (type, instance, changeSelection) => {\n    // Returns Node\n},\nremoveNode: async id => {\n    // Should return nothing or error.\n    // Currently returning [] in all cases.\n},\nupdateNodeLayout: async (nodeId, { x, y, collapsed }) => {\n},\nupdateGraphLayout: async ({ offsetX, offsetY, zoom }) => {\n}\n}\n```\n\n#### Getting a graph object:\nGraph objects are obtained through an instance of a Workspace \n\n```js\nconst ag = await ws.getActiveGraph()\n```\n\nor\n\n```js\nconst kgs = await ws.getKnowledgeGraphs()\n```\n\n#### Manipulating Graphs\n\n**Only the active graph may be manipulated.\n\nAll graph manipulations should be ‘visually’ verifiable on the graph itself, i.e., adds/removes/positioning, should all be reflected on the graph itself. \n\nThe `Node` object:\n```js\n{\nid: string\nx: number\ny: number\ncollapsed: boolean\nknowledgeGraphNode {\n  id: string\n  innerKind: Kind\n  innerFunction: Function\n}\n}\n```\n\n#### addNode(type, instance, changeSelection) =>\n\nTakes type (“Function” or “Kind”), instance (the Function or Kind object), and optionally a boolean to indicate whether the selection should be changed to this new node. \n\nReturns the newly created Node object.\n\n```js\nconst node = await ag.addNode('Kind',kind)\n```\n\n#### removeNode(id) =>\n\nTakes the id of Node to be deleted. Returns either undefined or an error. \n\n```js\nawait ag.removeNode(node.id)\n```\n\n#### getNodes() =>\nReturns an array of Node objects from the graph. \n\n```js\nconst nodes = await ag.getNodes()\n```\n\n#### updateNodeLayout: async (nodeId, { x, y, collapsed})=>\n\nUpdates a Node layout given a node ID and node coordinates (`x` and/or `y`) or a `collapsed` value. x/y values must be a number, and collapsed must be a boolean. Whatever is not specified will remain current.\n\n```js\nag.updateNodeLayout(id,{x:100,y:100,collapsed:true})\n```\n\n#### updateGraphLayout: async ({ offsetX, offsetY, zoom})=>\n\nUpdates a Graph layout given numerical values for x/y offsets and the zoom. \n\n```js\nag.updateGraphLayout({offsetX:50, offsetY:50, zoom: 70})\n```\n\n### Functions\n\nThe `Function` object:\n```js\n{\n    id: string\n    name: string\n    service {\n      id: string\n      name: string\n    }\n    arguments {\n      id: string\n      name: string\n      type: string\n      modifiers: Array[string]\n      typeKindId:: string\n      kind {\n        id: string\n        name: string\n      }\n    }\n    implementation {\n      id: string\n      entrypoint {\n        id: string\n      }\n      operations {\n        id: string\n        type: string\n        function {\n          id: string\n          name: string\n        }\n        argumentValues {\n          id: string\n          argument {\n            id: string\n          }\n          operation {\n            id: string\n          }\n          argumentRef: string\n        }\n      }\n    }\n    isGenerated: boolean\n    functionType: string\n    graphqlOperationType: string\n    outputType: string\n    outputKindId: string\n    outputModifiers: Array[string]\n    kind {\n      id: string\n      name: string\n    }\n}\n```\n\n`FunctionExecutionResult` object:\n```js\n{\n  id: string,\n  result: JSON\n}\n```\n\n#### executeFunction = ( {id, variables, resolve} ) =>\n\nExecutes a function based on its id, with optional inputs for variables and a resolve string (this specifies the fields to be returned, which must be valid based on the result).\n\nReturns : JSON matching shape of result , unless no sub-selection of fields is required in the execution.\n\nThis following piece of code will execute a Function given a function ID, and pass in variables for ‘example’, requesting back id and name fields. \n\n```js \nconst res = await AssistantAPIClient.executeFunction({functionId: func.id, variables: {\"variableName\": \"variableValue\"}, resolve: \"{ id name }\");\n```\n\n#### createFunction = input =>\n\nCreates a function based on the input provided. \n\nReturns: the created Function object.\n\n**Using create function will only place the function in the workspace’s inventory--it will not place the function as a node on the Graph. In order to do this, you must pass the created function into the addNode function on the active Graph, making sure to specify ‘Function' as the type.\n\n```js\nconst createFunctionInput = {\n  name:\"yourName\",\n  arguments:[],\n  outputType: \"STRING\",\n  graphqlOperationType:\"QUERY\",\n  functionType: \"CKG\"\n}\n  \nconst createdFunction = await AssistantAPIClient.createFunction(createFunctionInput)\n```\n\n#### updateFunction = input =>\n\nInput is the same for creating a function. It’s important to note that the arguments property will be replaced in it’s entirety with whatever is provided (if a value is provided.\n\nReturns the updated `Function` object.\n\n```js\nconst updatedFunction = await AssistantAPIClient.updateFunction(input);\n```\n\n#### deleteFunction = input =>\n\nInput is the id of the Function to be deleted. Returns the deleted function as a promise.\n\n```js\nconst deletedFunction = await AssistantAPIClient.deleteFunction('id...');\n```\n\n#### getFunctionById = id =>\n\nReturns a Function as a promise based on the ID provided.\n\n```js\nconst func = await AssistantAPIClient.getFunctionById('id...');\n```\n\n#### addFunctionExecutionListener = async (id, cb) =>\n\nAssociates a callback function with the execution of a particular Function. When the Function matching the id parameter is executed, its FunctionExecutionResult object passed to the callback. Returns undefined.\n\nExample function execution callback and listener registration:\n\n```js\nfunction exampleFunctionCB (result){\n  console.log(`Function executed with result:`, result)\n}\n\nAssistantAPIClient.addFunctionExecutionListener('id...', exampleFunctionCB)\n```\n\n#### removeFunctionExecutionListener = async (id, cb) =>\n\nRemoves a Function execution listener based on the function ID and a reference to the callback function. If no callback is supplied, all listeners associated with the Function ID will be removed. Returns undefined.\n\n```js\nAssistantAPIClient.removeFunctionExecutionListener('id..', exampleFunctionCB)\n```\n\n### Kinds\nThe `Kind` object:\n```js\n{\n    id: string\n    name: string\n    service: {\n      id\n      name\n    }\n    isGenerated: boolean\n    schema {\n      id: string\n      name: string\n      type: string\n      typeKindId: string\n      modifiers: Array[string]\n      kind {\n        id: string\n        name: string\n      }\n    }\n}\n```\n\n#### createKind = input =>\n\nCreates a Kind based on an input object. Returns a promise that resolves to the created Kind object.\n\n```js\nconst kindInput = {\n name: \"someKind\",\n schema:[\n  { name: \"someField1\", type: STRING },\n  { name: \"someField2\", type: STRING }\n ]\n}\n\nconst newKind = await AssistantAPIClient.createKind(kindInput)\n```\n\n#### updateKind = input =>\n\nUpdates a Kind based on an input object. \n\nUpdate Semantics: Only properties specified will be updated. If updating the schema, the entire schema must be specified as it will be replaced in its entirety. \n\nReturns the updated `Kind` object.\n\n```js\nconst updated = await AssistantAPIClient.updateKind(input)\n```\n\n#### deleteKind = input =>\n\nDeletes a Kind given a kind ID.\n\n```js\nconst deleted = await AssistantAPIClient.deleteKind(input)\n```\n\n#### getKindById = id =>\n\nReturns a promise that resolves to a Kind object given the specified kind ID. Only kinds in the workspace or those of imported services will be returned. \n\n```js\nconst kind = await AssistantAPIClient.getKindById(id)\n```\n\n### Inventory\n\nThe `InventoryChanged` object:\n```js\n{\n  kinds: {\n    adds: [DiffItem]\n    deletes: [DiffItem]\n    updates: [DiffItem]\n  }\n  functions:{\n    adds: [DiffItem]\n    deletes: [DiffItem]\n    updates: [DiffItem]\n  }\n  services: {\n    adds: [DiffItem]\n    deletes: [DiffItem]\n    updates: [DiffItem]\n  }\n}\n```\n\nThe `DiffItem` object:\n```js\n{\n  id: string,\n  name: string\n}\n```\n\n#### addInventoryChangedListener = async cb =>\n\nRegisters a callback function with the inventory changed event. When workspace inventory changes the callback function will be called with the InventoryChangedobject. Returns undefined.\n\n*Current limitations: Kind and Function updates only occur where the name property is changed. Updates to services outside of the workspace will not be detected. \n\n**Use-case note: an ‘update’ diff for inventory services is unlikely in general usage. \n\n```js\nconst inventoryCB = ({diff}) => {\n  if(diff.kinds) console.log('KINDS CHANGED',diff.kinds)\n  if(diff.functions) console.log('FUNCTIONS CHANGED', diff.functions)\n  if(diff.services) console.log('SERVICES CHANGED',diff.services)\n}\n\nAssistantAPIClient.addInventoryChangedListener(inventoryCB)\n```\n\nThis function exists on the Q-Assisant-Client only--only enableSelectionChangedNotification is used on the API side. \n\n#### removeInventoryChangedListener = async cb =>\n\nRemoves an inventory changed listener given the referenced callback. If no callback is specified, all listeners will be removed. Returns undefined.\n\n```js\nAssistantAPIClient.removeInventoryChangedListener(inventoryCB)\n```\n\nThis function exists on the Q-Assisant-Client only--only disableSelectionChangedNotification is used on the API side. \n\n## Troubleshooting Assistant Issues\n### Assistant root file has loaded, but not other content\nObserving in the browser's dev tools that some resources have loaded correctly (usually the root), but other's haven't (usually nested files or chunks), is indicative of a failure of Q Gateway to proxy due to not having a 'relative' path structure.\n\n### You are seeing post-robot `NO ACK` errors in the console.\nThese errors stem from a failed acknowledgement for a call either between the client and the API or vice-versa. Here, this means that the web app 'window' (the assistant) cannot communicate with, or access, the 'window.parent' (Maana K-Portal) object. Improper CORS configuration is a common culprit (also verify if using docker or nginx that your proxying and networking is configured correctly to allow communication and to accout for CORS).","readmeFilename":"README.md","gitHead":"b225b870fe4fe6109740467e8437ec8471e3c096","_id":"@io-maana/q-assistant-client@3.2.2-beta.16","_npmVersion":"6.4.1","_nodeVersion":"10.15.3","_npmUser":{"name":"teamcitymaana","email":"teamcity@maana.io"},"dist":{"integrity":"sha512-wvEdbTxlctqtcrQ0l/IUQ1d3s4z+nCvL6amPeRQmC0zJQrc8Aiq/twJvI6pd6Itr6EUG9eR48h128mJ6li3hTw==","shasum":"31b4f862e2d2c2131bb6245b6692f801311bc2a7","tarball":"https://registry.npmjs.org/@io-maana/q-assistant-client/-/q-assistant-client-3.2.2-beta.16.tgz","fileCount":5,"unpackedSize":29023,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJd0zqyCRA9TVsSAnZWagAAATgP/RXreVLJl/TSQSzDoBP0\n/YmhCgAway4kZWEgkdL6QuXMTEsq6R4/a8Nrqk4p2kRQm8U8dMTbwQROKp48\nG+tvj2gcjG3iTeEco8A2x0OZeyFdbf+35mBFGsG5aBMIC3O0cbt3oPG0uoFE\nrDP/MyelyWJNOIBALGAm7FmLipzEtKZzleyR3VjsZhAFHVbiHx/dPketOXUs\nptbNTp50cSbETBO02d5HaCenVkb6y0hUXbJghbFhuRAhZKBG9NnoozQh/WEG\nGdiZYLErLwaJy3ZcN2Xm25T+d5zbmunmHFBuG6nGO34HwOTsFqkFwOO+2LTa\nodl6RXkvOgtRxYlyh4YYlbMC76NdcJP3onsjIuXFe+++l/h9Tdex7Upz6p61\narT+JOqQU/pcB0Z2J009F4/bmmK+5EoJEBT5PK84fQz9UF4rkKjA1ismfaSB\nMRASHIPENjXztZiq0JY4chID0d1URm3UTM32p9rpvLB7Z5SVGpVEVsd8ZQ5f\nBzlMxviDTiqKRr3Ltth/8XejFXdqGaV21N1PjjggJSKIQZGWflvT6tznZRFw\nzaks7wHTyZIDxL2WmpOI6jEhsKEo4cmmglkLFYs1tRBWIXR+1Gvf5ala8zax\nye7sqXamBj3zsVZsjwM9nQad89oTMyQ82F1uk6P6qOliKahFKOKNpxLbmOs0\nLnoL\r\n=0Hi7\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIQCkgkIIHes+ZT6xZ1LcjHe4sdwaGX6rotmstHdQP9oJKQIgQJM9fjN69AJ8WglE5Ln3gqV6Ld2z440dYN0jbigRlAw="}]},"maintainers":[{"name":"abatyuk","email":"andrey@maana.io"},{"name":"bzvetey","email":"bzvestey@gmail.com"},{"name":"rpovey","email":"rob@maana.io"},{"name":"teamcitymaana","email":"teamcity@maana.io"},{"name":"witt3rd","email":"witt3rd@witt3rd.com"}],"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/q-assistant-client_3.2.2-beta.16_1574124209606_0.31251027469863146"},"_hasShrinkwrap":false},"3.2.1":{"name":"@io-maana/q-assistant-client","version":"3.2.1","description":"JavaScript package to streamline communication between an assistant and the Maana Q Assistant API.","main":"build/AssistantAPIClient.js","scripts":{"build":"babel src --out-dir build","prepack":"npm run build","test":"echo \"Error: no test specified\" && exit 1"},"repository":{"type":"git","url":"git+https://github.com/maana-io/q-assistant-client.git"},"keywords":["Maana","Q"],"author":{"name":"Logan Gore @ Maana.io"},"license":"MIT","bugs":{"url":"https://github.com/maana-io/q-assistant-client/issues"},"homepage":"https://github.com/maana-io/q-assistant-client#readme","dependencies":{"post-robot":"10.0.18"},"devDependencies":{"@babel/cli":"^7.5.5","@babel/core":"^7.5.5","@babel/plugin-proposal-class-properties":"^7.5.5","@babel/preset-env":"^7.5.5"},"gitHead":"dcb24afcfe0d46b14c8285c7e778d638789a0f24","_id":"@io-maana/q-assistant-client@3.2.1","_npmVersion":"6.4.1","_nodeVersion":"10.15.3","_npmUser":{"name":"teamcitymaana","email":"teamcity@maana.io"},"dist":{"integrity":"sha512-RXy8A1qkpRSYMzimDUhsbfD3rc/tGbRCUHlXv/T63/JS/XUeWdJqEltUbogVLRfu/R2GT284SAgqXpOIEzBEKg==","shasum":"a4883dd29a339f13a288a1aa6dd4e867012b2ff5","tarball":"https://registry.npmjs.org/@io-maana/q-assistant-client/-/q-assistant-client-3.2.1.tgz","fileCount":5,"unpackedSize":29015,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJd02XCCRA9TVsSAnZWagAAHdgP/0sbcWNMCjNnM0ZQ5QY5\nmahjV2LJ7WAfLOF5srImiAa8vaxoyK1PIObT04lESOHYgRltY/dFCoBBHOQs\nkVpYoQq9YFooB7o/Deu4MIgqvhL+LViIXE/AWR3h6Ne5hNzWBb0DG2V+nrvb\nEox4MGnIBAZAgoCb7C/tWcTcFSZTF3PpzQ7EF3xFPcN84YbHNTf0BICfz7Z1\nUfEieKk8flBGVNWoohAatEbjR8lTJP86msMbA+YX8imNG6qzvm9ndf/y6HPl\nUTPuIgLs9Vd4t+d8iWd3KqeZeXqmxqgcHlAUEdaq+tgNZe378d2B+sYMcHI5\ne6IHWIOlPYPtW8ejrLz/eq5gGnvm9OtQB43bcoSs6lMmSKAmJEUu0TQdXuk5\ne7D6dpYCfem+hfJAkh+qewjuyw+ohTkJUU/zK73/UHgQRdW5ClN1hOTBUMDu\nvH/Jxp13rhQV+dUnSC/WJ4yiTi9zIt09KPqre9EkkaBwY6v9TsegQBREYlio\nQP+AgtJ3ENAFptsci5WK4YqTw/jPaZkjEh+YmWM/hbpEzTQobalqqZMVBGSz\nDUo8WZdvvKQIrs5CLW1xt8PYosvDFC8cBDgKEkH9di9x+4AvpR5To7lrT5l7\n2KuaH4/4TilB4tcyo4FJ510/uoQ4lMNyByK9sODPxMky0oV7t6P3gC20DCoq\nxlQB\r\n=DH2p\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEQCIG1yibqQ6b8aTKIsDNppOI7HaUoGYFdfe60YtXIQuYWaAiBAiWOnyHdStmBlfHTJsJkOUjhNWevfQvnqXeOnMKACrw=="}]},"maintainers":[{"name":"abatyuk","email":"andrey@maana.io"},{"name":"bzvetey","email":"bzvestey@gmail.com"},{"name":"rpovey","email":"rob@maana.io"},{"name":"teamcitymaana","email":"teamcity@maana.io"},{"name":"witt3rd","email":"witt3rd@witt3rd.com"}],"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/q-assistant-client_3.2.1_1574135234056_0.25347757946626226"},"_hasShrinkwrap":false},"3.2.2-beta.17":{"name":"@io-maana/q-assistant-client","version":"3.2.2-beta.17","description":"JavaScript package to streamline communication between an assistant and the Maana Q Assistant API.","main":"build/AssistantAPIClient.js","scripts":{"build":"babel src --out-dir build","prepack":"npm run build","test":"echo \"Error: no test specified\" && exit 1"},"repository":{"type":"git","url":"git+https://github.com/maana-io/q-assistant-client.git"},"keywords":["Maana","Q"],"author":{"name":"Logan Gore @ Maana.io"},"license":"MIT","bugs":{"url":"https://github.com/maana-io/q-assistant-client/issues"},"homepage":"https://github.com/maana-io/q-assistant-client#readme","dependencies":{"post-robot":"10.0.18"},"devDependencies":{"@babel/cli":"^7.5.5","@babel/core":"^7.5.5","@babel/plugin-proposal-class-properties":"^7.5.5","@babel/preset-env":"^7.5.5"},"readme":"# q-assistant-client\nA lightweight JavaScript client for Maana-Q Assistant developers that wraps post-message communication between an embedded Maana-Q assistant and the Maana-Q UI.\n\n## Abstract\nThe Q-Assistant-Client is intented to be used in a web application being leveraged as a Maana Q assistant (embedded as an iframe).\nThis assistant client will facilitate communication between the assistant and the parent frame.\nThe client provides a rich, asynchronous experience over what would otherwise be 'fire-and-forget'-style messaging \nvia post-post message communication. \n\n## Requirements and Assumptions\n\n### Post-Robot Library\nThe Maana Knowledge Portal (KPortal) uses the kraken/post-robot library [kraken/post-robot](https://github.com/krakenjs/post-robot) to enrich the communication with the assistant. Post-robot allows for asynchronous, promise-based request/response style behavior between the assistant and the assistant API.\n\nThe API requires that the client use the post-robot library. This assistant-client library is the easiest way to achieve this, and also adds a fair amount of 'sugar' to the process to improve developer productivity. Developers could, however, use post-robot directly in their own client implementation. \n\n### Maana-Gateway Proxy Requirements\nThe Maana-Gateway service requires relative paths (paths relative to the root) in the assistant web application in order to proxy the application and its content. For create-react-apps, for instance, this means setting \"homepage\" to \".\" in the package.json file.\n\n## Singleton Instance\nThe client is exported as a singleton to avoid duplicate registration on event listeners.\nYou can import the instance like this:\n\n```js\nimport AssistantAPIClient from '@io-maana/q-assistant-client';\n```\n\nFunction calls can be made against the client instance like any other javascript object. They are all async.\n\n```js\nconst workspace = await AssistantAPIClient.getWorkspace(); \nconsole.log(\"Workspace:\", workspace)\n```\n\n## Dependencies\nPost-Robot\nhttps://github.com/krakenjs/post-robot\n\nPost-robot is used to provide a richer communication layer atop post-message.\n\n## Examples\n@TODO Logan\n\n## API Documentation\n\n### State management\n\n#### clearState = () =>\n\nThis will clear all ‘attached’ state between the assistant and the API. \n\nSpecifically, this will clear selection and inventory changed event listeners. \n\n```js\nawait AssistantAPIClient.clearState()\n```\n\n### User Info\nThe `UserInfo` object:\n```js\n{\n email: string,\n name: string\n}\n```\n\n#### getUserInfo = () => \n\nReturns a Userinfo object pertaining to the logged in user.\n\n```js\nconst userInfo = await AssistantAPIClient.getUserInfo()\n```\n### Selection\nThe `Selection` object:\n```js\n{\n  kindId: string\n  kindName: string\n  id: string\n}\n```\n\n#### getCurrentSelection = () => \n\nReturns an Array of `Selection` objects:\n\n```js\nconst {selection} = await AssistantAPIClient.getCurrentSelection();\n```\n\n#### addSelectionChangedListener = async cb =>\n\nAdds a callback function to be executed upon a valid workspace selection change.\n\nCallback value is an array of Selection objects:\n\n```js\n// Create the selection callback.\nconst selectionCB = ({selection})=>{\n  console.log('Workspace selection has changed.')\n  selection.forEach(i=>{\n    console.log('Kind: ',i.kindName)\n    console.log('Instance Id:',i.id)\n    console.log('Kind Id:',i.kindId)\n  })\n}\n\n// Add the listener.\nAssistantAPIClient.addSelectionChangedListener(selectionCB);\n```\n\nThis function only exists on the Q-Assistant-Client--only enableSelectionChangedNotification is called on the API. \n\n#### removeSelectionChangedListener = async cb =>\n\nThis will have to be called on a 1:1 basis with addSelectionChangedListener calls if supplying a callback.\n\n```js\nAssistantAPIClient.removeSelectionChangedListener(selectionCB)\n```\n\n**If NOT supplying a callback to this call, all selection changed listeners will be removed.\n\n```js\nAssistantAPIClient.removeSelectionChangedListener()\n```\n\nThis function only exists on the Q-Assistant-Client--only disableSelectionChangedNotification is called on the API. \n\n\n### Services\nThe `Service` object:\n```js\n{\n   id: string,\n   name: string\n   endpointUrl: string,\n   getKinds: () => // Returns [] of Kinds objects\n   getFunctions: () => // Returns [] of Function objects\n}\n```\n\n#### getServiceById = id =>\nThis will return a service that exists within the scope of the workspace. \n** Assistant services will return null. Services outside the scope of the workspace will cause an error to be returned as 'Unable to load a Service from outside of the workspace.'\n\n```js\nconst svc = await AssistantAPIClient.getServiceById(id)\n```\n\n### Workspace\nThe `Workspace` object:\n```js\n{\nid: string,\nname: string,\ngetKinds: () => {\n  // Returns an array of functions in the workspace (includes boilerplate).\n},\ngetFunctions: () =>\n  // Returns an array of functions in the workspace (includes boilerplate).\ngetActiveGraph: () => {\n  // Returns the active Graph object.\n  // Returns null if active graph is not of type 'Knowledge Graph', or if an\n  // active graph is deleted, thereby setting active graph to null.\n},\ngetKnowledgeGraphs: () => {\n  // Returns [Graph]\n},\ngetImportedServices: () => {\n  // Returns an service imported into the workspace\n  // as a array of Service object (this calls the function\n  // that underlies getServiceById.\n  // No assistant services will be returned.\n}\n}\n```\n\n#### getWorkspace = () =>\n\nReturns a Workspace object representing the workspace. \n\n```js\nconst ws = await AssistantAPIClient.getWorkspace()\n```\n\n### Graphs\nThe `Graph` object:\n```js\n{     \nid: string,\nname: string,\noffsetX: Number,\noffsetY: Number,\nzoom: Number,\ngetNodes: async () => {\n    // Returns [Node]\n},\n\naddNode: async (type, instance, changeSelection) => {\n    // Returns Node\n},\nremoveNode: async id => {\n    // Should return nothing or error.\n    // Currently returning [] in all cases.\n},\nupdateNodeLayout: async (nodeId, { x, y, collapsed }) => {\n},\nupdateGraphLayout: async ({ offsetX, offsetY, zoom }) => {\n}\n}\n```\n\n#### Getting a graph object:\nGraph objects are obtained through an instance of a Workspace \n\n```js\nconst ag = await ws.getActiveGraph()\n```\n\nor\n\n```js\nconst kgs = await ws.getKnowledgeGraphs()\n```\n\n#### Manipulating Graphs\n\n**Only the active graph may be manipulated.\n\nAll graph manipulations should be ‘visually’ verifiable on the graph itself, i.e., adds/removes/positioning, should all be reflected on the graph itself. \n\nThe `Node` object:\n```js\n{\nid: string\nx: number\ny: number\ncollapsed: boolean\nknowledgeGraphNode {\n  id: string\n  innerKind: Kind\n  innerFunction: Function\n}\n}\n```\n\n#### addNode(type, instance, changeSelection) =>\n\nTakes type (“Function” or “Kind”), instance (the Function or Kind object), and optionally a boolean to indicate whether the selection should be changed to this new node. \n\nReturns the newly created Node object.\n\n```js\nconst node = await ag.addNode('Kind',kind)\n```\n\n#### removeNode(id) =>\n\nTakes the id of Node to be deleted. Returns either undefined or an error. \n\n```js\nawait ag.removeNode(node.id)\n```\n\n#### getNodes() =>\nReturns an array of Node objects from the graph. \n\n```js\nconst nodes = await ag.getNodes()\n```\n\n#### updateNodeLayout: async (nodeId, { x, y, collapsed})=>\n\nUpdates a Node layout given a node ID and node coordinates (`x` and/or `y`) or a `collapsed` value. x/y values must be a number, and collapsed must be a boolean. Whatever is not specified will remain current.\n\n```js\nag.updateNodeLayout(id,{x:100,y:100,collapsed:true})\n```\n\n#### updateGraphLayout: async ({ offsetX, offsetY, zoom})=>\n\nUpdates a Graph layout given numerical values for x/y offsets and the zoom. \n\n```js\nag.updateGraphLayout({offsetX:50, offsetY:50, zoom: 70})\n```\n\n### Functions\n\nThe `Function` object:\n```js\n{\n    id: string\n    name: string\n    service {\n      id: string\n      name: string\n    }\n    arguments {\n      id: string\n      name: string\n      type: string\n      modifiers: Array[string]\n      typeKindId:: string\n      kind {\n        id: string\n        name: string\n      }\n    }\n    implementation {\n      id: string\n      entrypoint {\n        id: string\n      }\n      operations {\n        id: string\n        type: string\n        function {\n          id: string\n          name: string\n        }\n        argumentValues {\n          id: string\n          argument {\n            id: string\n          }\n          operation {\n            id: string\n          }\n          argumentRef: string\n        }\n      }\n    }\n    isGenerated: boolean\n    functionType: string\n    graphqlOperationType: string\n    outputType: string\n    outputKindId: string\n    outputModifiers: Array[string]\n    kind {\n      id: string\n      name: string\n    }\n}\n```\n\n`FunctionExecutionResult` object:\n```js\n{\n  id: string,\n  result: JSON\n}\n```\n\n#### executeFunction = ( {id, variables, resolve} ) =>\n\nExecutes a function based on its id, with optional inputs for variables and a resolve string (this specifies the fields to be returned, which must be valid based on the result).\n\nReturns : JSON matching shape of result , unless no sub-selection of fields is required in the execution.\n\nThis following piece of code will execute a Function given a function ID, and pass in variables for ‘example’, requesting back id and name fields. \n\n```js \nconst res = await AssistantAPIClient.executeFunction({functionId: func.id, variables: {\"variableName\": \"variableValue\"}, resolve: \"{ id name }\");\n```\n\n#### createFunction = input =>\n\nCreates a function based on the input provided. \n\nReturns: the created Function object.\n\n**Using create function will only place the function in the workspace’s inventory--it will not place the function as a node on the Graph. In order to do this, you must pass the created function into the addNode function on the active Graph, making sure to specify ‘Function' as the type.\n\n```js\nconst createFunctionInput = {\n  name:\"yourName\",\n  arguments:[],\n  outputType: \"STRING\",\n  graphqlOperationType:\"QUERY\",\n  functionType: \"CKG\"\n}\n  \nconst createdFunction = await AssistantAPIClient.createFunction(createFunctionInput)\n```\n\n#### updateFunction = input =>\n\nInput is the same for creating a function. It’s important to note that the arguments property will be replaced in it’s entirety with whatever is provided (if a value is provided.\n\nReturns the updated `Function` object.\n\n```js\nconst updatedFunction = await AssistantAPIClient.updateFunction(input);\n```\n\n#### deleteFunction = input =>\n\nInput is the id of the Function to be deleted. Returns the deleted function as a promise.\n\n```js\nconst deletedFunction = await AssistantAPIClient.deleteFunction('id...');\n```\n\n#### getFunctionById = id =>\n\nReturns a Function as a promise based on the ID provided.\n\n```js\nconst func = await AssistantAPIClient.getFunctionById('id...');\n```\n\n#### addFunctionExecutionListener = async (id, cb) =>\n\nAssociates a callback function with the execution of a particular Function. When the Function matching the id parameter is executed, its FunctionExecutionResult object passed to the callback. Returns undefined.\n\nExample function execution callback and listener registration:\n\n```js\nfunction exampleFunctionCB (result){\n  console.log(`Function executed with result:`, result)\n}\n\nAssistantAPIClient.addFunctionExecutionListener('id...', exampleFunctionCB)\n```\n\n#### removeFunctionExecutionListener = async (id, cb) =>\n\nRemoves a Function execution listener based on the function ID and a reference to the callback function. If no callback is supplied, all listeners associated with the Function ID will be removed. Returns undefined.\n\n```js\nAssistantAPIClient.removeFunctionExecutionListener('id..', exampleFunctionCB)\n```\n\n### Kinds\nThe `Kind` object:\n```js\n{\n    id: string\n    name: string\n    service: {\n      id\n      name\n    }\n    isGenerated: boolean\n    schema {\n      id: string\n      name: string\n      type: string\n      typeKindId: string\n      modifiers: Array[string]\n      kind {\n        id: string\n        name: string\n      }\n    }\n}\n```\n\n#### createKind = input =>\n\nCreates a Kind based on an input object. Returns a promise that resolves to the created Kind object.\n\n```js\nconst kindInput = {\n name: \"someKind\",\n schema:[\n  { name: \"someField1\", type: STRING },\n  { name: \"someField2\", type: STRING }\n ]\n}\n\nconst newKind = await AssistantAPIClient.createKind(kindInput)\n```\n\n#### updateKind = input =>\n\nUpdates a Kind based on an input object. \n\nUpdate Semantics: Only properties specified will be updated. If updating the schema, the entire schema must be specified as it will be replaced in its entirety. \n\nReturns the updated `Kind` object.\n\n```js\nconst updated = await AssistantAPIClient.updateKind(input)\n```\n\n#### deleteKind = input =>\n\nDeletes a Kind given a kind ID.\n\n```js\nconst deleted = await AssistantAPIClient.deleteKind(input)\n```\n\n#### getKindById = id =>\n\nReturns a promise that resolves to a Kind object given the specified kind ID. Only kinds in the workspace or those of imported services will be returned. \n\n```js\nconst kind = await AssistantAPIClient.getKindById(id)\n```\n\n### Inventory\n\nThe `InventoryChanged` object:\n```js\n{\n  kinds: {\n    adds: [DiffItem]\n    deletes: [DiffItem]\n    updates: [DiffItem]\n  }\n  functions:{\n    adds: [DiffItem]\n    deletes: [DiffItem]\n    updates: [DiffItem]\n  }\n  services: {\n    adds: [DiffItem]\n    deletes: [DiffItem]\n    updates: [DiffItem]\n  }\n}\n```\n\nThe `DiffItem` object:\n```js\n{\n  id: string,\n  name: string\n}\n```\n\n#### addInventoryChangedListener = async cb =>\n\nRegisters a callback function with the inventory changed event. When workspace inventory changes the callback function will be called with the InventoryChangedobject. Returns undefined.\n\n*Current limitations: Kind and Function updates only occur where the name property is changed. Updates to services outside of the workspace will not be detected. \n\n**Use-case note: an ‘update’ diff for inventory services is unlikely in general usage. \n\n```js\nconst inventoryCB = ({diff}) => {\n  if(diff.kinds) console.log('KINDS CHANGED',diff.kinds)\n  if(diff.functions) console.log('FUNCTIONS CHANGED', diff.functions)\n  if(diff.services) console.log('SERVICES CHANGED',diff.services)\n}\n\nAssistantAPIClient.addInventoryChangedListener(inventoryCB)\n```\n\nThis function exists on the Q-Assisant-Client only--only enableSelectionChangedNotification is used on the API side. \n\n#### removeInventoryChangedListener = async cb =>\n\nRemoves an inventory changed listener given the referenced callback. If no callback is specified, all listeners will be removed. Returns undefined.\n\n```js\nAssistantAPIClient.removeInventoryChangedListener(inventoryCB)\n```\n\nThis function exists on the Q-Assisant-Client only--only disableSelectionChangedNotification is used on the API side. \n\n## Troubleshooting Assistant Issues\n### Assistant root file has loaded, but not other content\nObserving in the browser's dev tools that some resources have loaded correctly (usually the root), but other's haven't (usually nested files or chunks), is indicative of a failure of Q Gateway to proxy due to not having a 'relative' path structure.\n\n### You are seeing post-robot `NO ACK` errors in the console.\nThese errors stem from a failed acknowledgement for a call either between the client and the API or vice-versa. Here, this means that the web app 'window' (the assistant) cannot communicate with, or access, the 'window.parent' (Maana K-Portal) object. Improper CORS configuration is a common culprit (also verify if using docker or nginx that your proxying and networking is configured correctly to allow communication and to accout for CORS).","readmeFilename":"README.md","gitHead":"b225b870fe4fe6109740467e8437ec8471e3c096","_id":"@io-maana/q-assistant-client@3.2.2-beta.17","_npmVersion":"6.4.1","_nodeVersion":"10.15.3","_npmUser":{"name":"teamcitymaana","email":"teamcity@maana.io"},"dist":{"integrity":"sha512-Y0yUicX9FR5lLl+fIm8TSsU++c1HSK2CNdjVH4tF9d5PNiJFRFHg0lntzgXFkCCXbSGkLeEfGBihKvR8Dg69fA==","shasum":"ea857ead417c439ea87919735153120e76170f43","tarball":"https://registry.npmjs.org/@io-maana/q-assistant-client/-/q-assistant-client-3.2.2-beta.17.tgz","fileCount":5,"unpackedSize":29023,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJd3Jd+CRA9TVsSAnZWagAA/ygQAJzTIKNyj4zA2wubuQSo\nkgddgmnMWaNrMMhc9DxvxNplAXccfdYV9q7BKzPYttwc+ROZKBA+4Byie30c\nECUF1h8kpyA+f9M+z3lxK42yP/51ZrbfDuKajq3mQxzCUwozNekP5SHrNthX\ncktmuAXNvTDILR9IwEeUUxx/5+95wjox808pRl4Nc9lsV+BvMui9cmyZTssm\njqeGjVeAqdyugiam9S9EckK7vsUkBp+5r1nzk5Itx7tFthwcJ0QWkdHsEWOx\nHPtqyuMic2IFD/ud8BDZBWfxxYMwFSdo9Prh26sw1BJBTO+zRNGspJx1QJDM\nHYaGcqTAxaC27MPZJIvWL6bHhST41CvTO4LYuefCiI11HujluLqRwdkYvS+s\nbIE8jBkKy0rYn+O7V+VTFsbM1v5sLz2MbgQlwVwsXsPH7vO0OLhDw3z67BV6\nzHUhO0AoJnYuYQgKZ4V+3UcWCNP5R+cskTllk70uo7/pqLFqCYDIGq/o/OUi\nqmMcyW6O8EKT8ZC/t6/64WlOufwsfbOgV5lGDGRVdGWu3zY7YKvYwxYzUQhu\nKpCMLWrgaL7YrSe+vuoEdKI6AKeFku3ywaXvsZRyJ7pwjyNS8bZ7GzO+g4l1\nDoZeC2JnFko4zlGC98biu/Pn3FT38cNmioyPNe8ci9iF+br91DkENBindnps\niNMQ\r\n=LxAO\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEYCIQCWBJ01ZFhR2HlbNZaF+E17o33Jn1vguYpX+rPhY/AUNAIhANeVkPrYYMx1VBKunXewEN4IlE69XjeWxNbczxRFxMWw"}]},"maintainers":[{"name":"abatyuk","email":"andrey@maana.io"},{"name":"bzvetey","email":"bzvestey@gmail.com"},{"name":"rpovey","email":"rob@maana.io"},{"name":"teamcitymaana","email":"teamcity@maana.io"},{"name":"witt3rd","email":"witt3rd@witt3rd.com"}],"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/q-assistant-client_3.2.2-beta.17_1574737786583_0.14337049799854418"},"_hasShrinkwrap":false},"3.2.2-beta.18":{"name":"@io-maana/q-assistant-client","version":"3.2.2-beta.18","description":"JavaScript package to streamline communication between an assistant and the Maana Q Assistant API.","main":"build/AssistantAPIClient.js","scripts":{"build":"babel src --out-dir build","prepack":"npm run build","test":"echo \"Error: no test specified\" && exit 1"},"repository":{"type":"git","url":"git+https://github.com/maana-io/q-assistant-client.git"},"keywords":["Maana","Q"],"author":{"name":"Logan Gore @ Maana.io"},"license":"MIT","bugs":{"url":"https://github.com/maana-io/q-assistant-client/issues"},"homepage":"https://github.com/maana-io/q-assistant-client#readme","dependencies":{"post-robot":"10.0.18"},"devDependencies":{"@babel/cli":"^7.5.5","@babel/core":"^7.5.5","@babel/plugin-proposal-class-properties":"^7.5.5","@babel/preset-env":"^7.5.5"},"readme":"# q-assistant-client\nA lightweight JavaScript client for Maana-Q Assistant developers that wraps post-message communication between an embedded Maana-Q assistant and the Maana-Q UI.\n\n## Abstract\nThe Q-Assistant-Client is intented to be used in a web application being leveraged as a Maana Q assistant (embedded as an iframe).\nThis assistant client will facilitate communication between the assistant and the parent frame.\nThe client provides a rich, asynchronous experience over what would otherwise be 'fire-and-forget'-style messaging \nvia post-post message communication. \n\n## Requirements and Assumptions\n\n### Post-Robot Library\nThe Maana Knowledge Portal (KPortal) uses the kraken/post-robot library [kraken/post-robot](https://github.com/krakenjs/post-robot) to enrich the communication with the assistant. Post-robot allows for asynchronous, promise-based request/response style behavior between the assistant and the assistant API.\n\nThe API requires that the client use the post-robot library. This assistant-client library is the easiest way to achieve this, and also adds a fair amount of 'sugar' to the process to improve developer productivity. Developers could, however, use post-robot directly in their own client implementation. \n\n### Maana-Gateway Proxy Requirements\nThe Maana-Gateway service requires relative paths (paths relative to the root) in the assistant web application in order to proxy the application and its content. For create-react-apps, for instance, this means setting \"homepage\" to \".\" in the package.json file.\n\n## Singleton Instance\nThe client is exported as a singleton to avoid duplicate registration on event listeners.\nYou can import the instance like this:\n\n```js\nimport AssistantAPIClient from '@io-maana/q-assistant-client';\n```\n\nFunction calls can be made against the client instance like any other javascript object. They are all async.\n\n```js\nconst workspace = await AssistantAPIClient.getWorkspace(); \nconsole.log(\"Workspace:\", workspace)\n```\n\n## Dependencies\nPost-Robot\nhttps://github.com/krakenjs/post-robot\n\nPost-robot is used to provide a richer communication layer atop post-message.\n\n## Examples\n@TODO Logan\n\n## API Documentation\n\n### State management\n\n#### clearState = () =>\n\nThis will clear all ‘attached’ state between the assistant and the API. \n\nSpecifically, this will clear selection and inventory changed event listeners. \n\n```js\nawait AssistantAPIClient.clearState()\n```\n\n### User Info\nThe `UserInfo` object:\n```js\n{\n email: string,\n name: string\n}\n```\n\n#### getUserInfo = () => \n\nReturns a Userinfo object pertaining to the logged in user.\n\n```js\nconst userInfo = await AssistantAPIClient.getUserInfo()\n```\n### Selection\nThe `Selection` object:\n```js\n{\n  kindId: string\n  kindName: string\n  id: string\n}\n```\n\n#### getCurrentSelection = () => \n\nReturns an Array of `Selection` objects:\n\n```js\nconst {selection} = await AssistantAPIClient.getCurrentSelection();\n```\n\n#### addSelectionChangedListener = async cb =>\n\nAdds a callback function to be executed upon a valid workspace selection change.\n\nCallback value is an array of Selection objects:\n\n```js\n// Create the selection callback.\nconst selectionCB = ({selection})=>{\n  console.log('Workspace selection has changed.')\n  selection.forEach(i=>{\n    console.log('Kind: ',i.kindName)\n    console.log('Instance Id:',i.id)\n    console.log('Kind Id:',i.kindId)\n  })\n}\n\n// Add the listener.\nAssistantAPIClient.addSelectionChangedListener(selectionCB);\n```\n\nThis function only exists on the Q-Assistant-Client--only enableSelectionChangedNotification is called on the API. \n\n#### removeSelectionChangedListener = async cb =>\n\nThis will have to be called on a 1:1 basis with addSelectionChangedListener calls if supplying a callback.\n\n```js\nAssistantAPIClient.removeSelectionChangedListener(selectionCB)\n```\n\n**If NOT supplying a callback to this call, all selection changed listeners will be removed.\n\n```js\nAssistantAPIClient.removeSelectionChangedListener()\n```\n\nThis function only exists on the Q-Assistant-Client--only disableSelectionChangedNotification is called on the API. \n\n\n### Services\nThe `Service` object:\n```js\n{\n   id: string,\n   name: string\n   endpointUrl: string,\n   getKinds: () => // Returns [] of Kinds objects\n   getFunctions: () => // Returns [] of Function objects\n}\n```\n\n#### getServiceById = id =>\nThis will return a service that exists within the scope of the workspace. \n** Assistant services will return null. Services outside the scope of the workspace will cause an error to be returned as 'Unable to load a Service from outside of the workspace.'\n\n```js\nconst svc = await AssistantAPIClient.getServiceById(id)\n```\n\n### Workspace\nThe `Workspace` object:\n```js\n{\nid: string,\nname: string,\ngetKinds: () => {\n  // Returns an array of functions in the workspace (includes boilerplate).\n},\ngetFunctions: () =>\n  // Returns an array of functions in the workspace (includes boilerplate).\ngetActiveGraph: () => {\n  // Returns the active Graph object.\n  // Returns null if active graph is not of type 'Knowledge Graph', or if an\n  // active graph is deleted, thereby setting active graph to null.\n},\ngetKnowledgeGraphs: () => {\n  // Returns [Graph]\n},\ngetImportedServices: () => {\n  // Returns an service imported into the workspace\n  // as a array of Service object (this calls the function\n  // that underlies getServiceById.\n  // No assistant services will be returned.\n}\n}\n```\n\n#### getWorkspace = () =>\n\nReturns a Workspace object representing the workspace. \n\n```js\nconst ws = await AssistantAPIClient.getWorkspace()\n```\n\n### Graphs\nThe `Graph` object:\n```js\n{     \nid: string,\nname: string,\noffsetX: Number,\noffsetY: Number,\nzoom: Number,\ngetNodes: async () => {\n    // Returns [Node]\n},\n\naddNode: async (type, instance, changeSelection) => {\n    // Returns Node\n},\nremoveNode: async id => {\n    // Should return nothing or error.\n    // Currently returning [] in all cases.\n},\nupdateNodeLayout: async (nodeId, { x, y, collapsed }) => {\n},\nupdateGraphLayout: async ({ offsetX, offsetY, zoom }) => {\n}\n}\n```\n\n#### Getting a graph object:\nGraph objects are obtained through an instance of a Workspace \n\n```js\nconst ag = await ws.getActiveGraph()\n```\n\nor\n\n```js\nconst kgs = await ws.getKnowledgeGraphs()\n```\n\n#### Manipulating Graphs\n\n**Only the active graph may be manipulated.\n\nAll graph manipulations should be ‘visually’ verifiable on the graph itself, i.e., adds/removes/positioning, should all be reflected on the graph itself. \n\nThe `Node` object:\n```js\n{\nid: string\nx: number\ny: number\ncollapsed: boolean\nknowledgeGraphNode {\n  id: string\n  innerKind: Kind\n  innerFunction: Function\n}\n}\n```\n\n#### addNode(type, instance, changeSelection) =>\n\nTakes type (“Function” or “Kind”), instance (the Function or Kind object), and optionally a boolean to indicate whether the selection should be changed to this new node. \n\nReturns the newly created Node object.\n\n```js\nconst node = await ag.addNode('Kind',kind)\n```\n\n#### removeNode(id) =>\n\nTakes the id of Node to be deleted. Returns either undefined or an error. \n\n```js\nawait ag.removeNode(node.id)\n```\n\n#### getNodes() =>\nReturns an array of Node objects from the graph. \n\n```js\nconst nodes = await ag.getNodes()\n```\n\n#### updateNodeLayout: async (nodeId, { x, y, collapsed})=>\n\nUpdates a Node layout given a node ID and node coordinates (`x` and/or `y`) or a `collapsed` value. x/y values must be a number, and collapsed must be a boolean. Whatever is not specified will remain current.\n\n```js\nag.updateNodeLayout(id,{x:100,y:100,collapsed:true})\n```\n\n#### updateGraphLayout: async ({ offsetX, offsetY, zoom})=>\n\nUpdates a Graph layout given numerical values for x/y offsets and the zoom. \n\n```js\nag.updateGraphLayout({offsetX:50, offsetY:50, zoom: 70})\n```\n\n### Functions\n\nThe `Function` object:\n```js\n{\n    id: string\n    name: string\n    service {\n      id: string\n      name: string\n    }\n    arguments {\n      id: string\n      name: string\n      type: string\n      modifiers: Array[string]\n      typeKindId:: string\n      kind {\n        id: string\n        name: string\n      }\n    }\n    implementation {\n      id: string\n      entrypoint {\n        id: string\n      }\n      operations {\n        id: string\n        type: string\n        function {\n          id: string\n          name: string\n        }\n        argumentValues {\n          id: string\n          argument {\n            id: string\n          }\n          operation {\n            id: string\n          }\n          argumentRef: string\n        }\n      }\n    }\n    isGenerated: boolean\n    functionType: string\n    graphqlOperationType: string\n    outputType: string\n    outputKindId: string\n    outputModifiers: Array[string]\n    kind {\n      id: string\n      name: string\n    }\n}\n```\n\n`FunctionExecutionResult` object:\n```js\n{\n  id: string,\n  result: JSON\n}\n```\n\n#### executeFunction = ( {id, variables, resolve} ) =>\n\nExecutes a function based on its id, with optional inputs for variables and a resolve string (this specifies the fields to be returned, which must be valid based on the result).\n\nReturns : JSON matching shape of result , unless no sub-selection of fields is required in the execution.\n\nThis following piece of code will execute a Function given a function ID, and pass in variables for ‘example’, requesting back id and name fields. \n\n```js \nconst res = await AssistantAPIClient.executeFunction({functionId: func.id, variables: {\"variableName\": \"variableValue\"}, resolve: \"{ id name }\");\n```\n\n#### createFunction = input =>\n\nCreates a function based on the input provided. \n\nReturns: the created Function object.\n\n**Using create function will only place the function in the workspace’s inventory--it will not place the function as a node on the Graph. In order to do this, you must pass the created function into the addNode function on the active Graph, making sure to specify ‘Function' as the type.\n\n```js\nconst createFunctionInput = {\n  name:\"yourName\",\n  arguments:[],\n  outputType: \"STRING\",\n  graphqlOperationType:\"QUERY\",\n  functionType: \"CKG\"\n}\n  \nconst createdFunction = await AssistantAPIClient.createFunction(createFunctionInput)\n```\n\n#### updateFunction = input =>\n\nInput is the same for creating a function. It’s important to note that the arguments property will be replaced in it’s entirety with whatever is provided (if a value is provided.\n\nReturns the updated `Function` object.\n\n```js\nconst updatedFunction = await AssistantAPIClient.updateFunction(input);\n```\n\n#### deleteFunction = input =>\n\nInput is the id of the Function to be deleted. Returns the deleted function as a promise.\n\n```js\nconst deletedFunction = await AssistantAPIClient.deleteFunction('id...');\n```\n\n#### getFunctionById = id =>\n\nReturns a Function as a promise based on the ID provided.\n\n```js\nconst func = await AssistantAPIClient.getFunctionById('id...');\n```\n\n#### addFunctionExecutionListener = async (id, cb) =>\n\nAssociates a callback function with the execution of a particular Function. When the Function matching the id parameter is executed, its FunctionExecutionResult object passed to the callback. Returns undefined.\n\nExample function execution callback and listener registration:\n\n```js\nfunction exampleFunctionCB (result){\n  console.log(`Function executed with result:`, result)\n}\n\nAssistantAPIClient.addFunctionExecutionListener('id...', exampleFunctionCB)\n```\n\n#### removeFunctionExecutionListener = async (id, cb) =>\n\nRemoves a Function execution listener based on the function ID and a reference to the callback function. If no callback is supplied, all listeners associated with the Function ID will be removed. Returns undefined.\n\n```js\nAssistantAPIClient.removeFunctionExecutionListener('id..', exampleFunctionCB)\n```\n\n### Kinds\nThe `Kind` object:\n```js\n{\n    id: string\n    name: string\n    service: {\n      id\n      name\n    }\n    isGenerated: boolean\n    schema {\n      id: string\n      name: string\n      type: string\n      typeKindId: string\n      modifiers: Array[string]\n      kind {\n        id: string\n        name: string\n      }\n    }\n}\n```\n\n#### createKind = input =>\n\nCreates a Kind based on an input object. Returns a promise that resolves to the created Kind object.\n\n```js\nconst kindInput = {\n name: \"someKind\",\n schema:[\n  { name: \"someField1\", type: STRING },\n  { name: \"someField2\", type: STRING }\n ]\n}\n\nconst newKind = await AssistantAPIClient.createKind(kindInput)\n```\n\n#### updateKind = input =>\n\nUpdates a Kind based on an input object. \n\nUpdate Semantics: Only properties specified will be updated. If updating the schema, the entire schema must be specified as it will be replaced in its entirety. \n\nReturns the updated `Kind` object.\n\n```js\nconst updated = await AssistantAPIClient.updateKind(input)\n```\n\n#### deleteKind = input =>\n\nDeletes a Kind given a kind ID.\n\n```js\nconst deleted = await AssistantAPIClient.deleteKind(input)\n```\n\n#### getKindById = id =>\n\nReturns a promise that resolves to a Kind object given the specified kind ID. Only kinds in the workspace or those of imported services will be returned. \n\n```js\nconst kind = await AssistantAPIClient.getKindById(id)\n```\n\n### Inventory\n\nThe `InventoryChanged` object:\n```js\n{\n  kinds: {\n    adds: [DiffItem]\n    deletes: [DiffItem]\n    updates: [DiffItem]\n  }\n  functions:{\n    adds: [DiffItem]\n    deletes: [DiffItem]\n    updates: [DiffItem]\n  }\n  services: {\n    adds: [DiffItem]\n    deletes: [DiffItem]\n    updates: [DiffItem]\n  }\n}\n```\n\nThe `DiffItem` object:\n```js\n{\n  id: string,\n  name: string\n}\n```\n\n#### addInventoryChangedListener = async cb =>\n\nRegisters a callback function with the inventory changed event. When workspace inventory changes the callback function will be called with the InventoryChangedobject. Returns undefined.\n\n*Current limitations: Kind and Function updates only occur where the name property is changed. Updates to services outside of the workspace will not be detected. \n\n**Use-case note: an ‘update’ diff for inventory services is unlikely in general usage. \n\n```js\nconst inventoryCB = ({diff}) => {\n  if(diff.kinds) console.log('KINDS CHANGED',diff.kinds)\n  if(diff.functions) console.log('FUNCTIONS CHANGED', diff.functions)\n  if(diff.services) console.log('SERVICES CHANGED',diff.services)\n}\n\nAssistantAPIClient.addInventoryChangedListener(inventoryCB)\n```\n\nThis function exists on the Q-Assisant-Client only--only enableSelectionChangedNotification is used on the API side. \n\n#### removeInventoryChangedListener = async cb =>\n\nRemoves an inventory changed listener given the referenced callback. If no callback is specified, all listeners will be removed. Returns undefined.\n\n```js\nAssistantAPIClient.removeInventoryChangedListener(inventoryCB)\n```\n\nThis function exists on the Q-Assisant-Client only--only disableSelectionChangedNotification is used on the API side. \n\n## Troubleshooting Assistant Issues\n### Assistant root file has loaded, but not other content\nObserving in the browser's dev tools that some resources have loaded correctly (usually the root), but other's haven't (usually nested files or chunks), is indicative of a failure of Q Gateway to proxy due to not having a 'relative' path structure.\n\n### You are seeing post-robot `NO ACK` errors in the console.\nThese errors stem from a failed acknowledgement for a call either between the client and the API or vice-versa. Here, this means that the web app 'window' (the assistant) cannot communicate with, or access, the 'window.parent' (Maana K-Portal) object. Improper CORS configuration is a common culprit (also verify if using docker or nginx that your proxying and networking is configured correctly to allow communication and to accout for CORS).","readmeFilename":"README.md","gitHead":"f685b35ab7f8f6772118d0416bddcc7cacc9ad02","_id":"@io-maana/q-assistant-client@3.2.2-beta.18","_npmVersion":"6.4.1","_nodeVersion":"10.15.3","_npmUser":{"name":"teamcitymaana","email":"teamcity@maana.io"},"dist":{"integrity":"sha512-r4Ebmpx++OG9BCq5wzAKuyQnMbanbWTgJATs3Zh0r0wUnLDe6Rz2DxUTtvtws88MbSu60Ve4Qf+oZd0Deq+z7Q==","shasum":"1e38a31a9a9804937815f948e2d6936b38cbe94f","tarball":"https://registry.npmjs.org/@io-maana/q-assistant-client/-/q-assistant-client-3.2.2-beta.18.tgz","fileCount":5,"unpackedSize":29931,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJd3KPbCRA9TVsSAnZWagAAwboQAImhMchHLr2C8pYGfI7C\nrTwj8Ar6crmogRqF4c9oWqRwAFmGuMd+pHgqTr2qvYrKF+rk3lsntVAIZ5V/\nCtLr00+orACATOZr7h060cgX+Eiq7beK3a8YRF3SVw5k28s5fDy7kOUO9GKc\nBHuD8Qhe0BpbgVGS7K8GdmkH2VTgYo/lgUO64Ke4ZYHq37LiF6BJONdpCk/a\nihTBIawKEccyu0hOvRpOYdILNVcS0l0TmXDFU41/ODh4LpM6Jh/gn/IzM4aL\nlcDkF1r8pREP9eafnrqtZg7wV7zfOIXjQtBBLktabnWpaTVz15HFsx0N7X1o\nk1QsBHOB/EzGokp15CkwMeqsuytdHEfXOGFIJQZaoS48LyHg43rcBMA0fDAM\nO47smyWaptLoAmJ3JFXk0QjiT2RZKCFSSKPQTes0TLSzAYKUX848wC7U16b2\nXcJNWp8EsvwrenQ0KbbVE+QtSkcZ6eItBdRCqFNfNVapz3vxqLtpyTTqIncu\n+3VQluperYhNOghAhLq+yPMTAzmofXrIL6Kz9tj4clL4wFge+FzQHa8Qd1tS\nDRZ0erXIbgvGYs9/r8J+MId0DwkWHXE/ogPPQ/CDgd1PojUFFw4C3rszccdp\nY4OrQToB2ybg9xMJbDW0hAX0tcZfU5ixOAw5G0Jm5EQdZZd1e7qDYA15IHjY\nqO4N\r\n=li+g\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIQCdDO56BqNac2oZg1VBKUwKdjN0yCYE+ykB3lYGaIPcngIgLvnRTEPdVztERz/fsVqNDo5SYzgtPL5MmDIiZPa0Owg="}]},"maintainers":[{"name":"abatyuk","email":"andrey@maana.io"},{"name":"bzvetey","email":"bzvestey@gmail.com"},{"name":"rpovey","email":"rob@maana.io"},{"name":"teamcitymaana","email":"teamcity@maana.io"},{"name":"witt3rd","email":"witt3rd@witt3rd.com"}],"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/q-assistant-client_3.2.2-beta.18_1574740955181_0.9015554033586131"},"_hasShrinkwrap":false},"3.2.2-beta.19":{"name":"@io-maana/q-assistant-client","version":"3.2.2-beta.19","description":"JavaScript package to streamline communication between an assistant and the Maana Q Assistant API.","main":"build/AssistantAPIClient.js","scripts":{"build":"babel src --out-dir build","prepack":"npm run build","test":"echo \"Error: no test specified\" && exit 1"},"repository":{"type":"git","url":"git+https://github.com/maana-io/q-assistant-client.git"},"keywords":["Maana","Q"],"author":{"name":"Logan Gore @ Maana.io"},"license":"MIT","bugs":{"url":"https://github.com/maana-io/q-assistant-client/issues"},"homepage":"https://github.com/maana-io/q-assistant-client#readme","dependencies":{"post-robot":"10.0.29"},"devDependencies":{"@babel/cli":"^7.5.5","@babel/core":"^7.5.5","@babel/plugin-proposal-class-properties":"^7.5.5","@babel/preset-env":"^7.5.5"},"readme":"# q-assistant-client\nA lightweight JavaScript client for Maana-Q Assistant developers that wraps post-message communication between an embedded Maana-Q assistant and the Maana-Q UI.\n\n## Abstract\nThe Q-Assistant-Client is intented to be used in a web application being leveraged as a Maana Q assistant (embedded as an iframe).\nThis assistant client will facilitate communication between the assistant and the parent frame.\nThe client provides a rich, asynchronous experience over what would otherwise be 'fire-and-forget'-style messaging \nvia post-post message communication. \n\n## Requirements and Assumptions\n\n### Post-Robot Library\nThe Maana Knowledge Portal (KPortal) uses the kraken/post-robot library [kraken/post-robot](https://github.com/krakenjs/post-robot) to enrich the communication with the assistant. Post-robot allows for asynchronous, promise-based request/response style behavior between the assistant and the assistant API.\n\nThe API requires that the client use the post-robot library. This assistant-client library is the easiest way to achieve this, and also adds a fair amount of 'sugar' to the process to improve developer productivity. Developers could, however, use post-robot directly in their own client implementation. \n\n### Maana-Gateway Proxy Requirements\nThe Maana-Gateway service requires relative paths (paths relative to the root) in the assistant web application in order to proxy the application and its content. For create-react-apps, for instance, this means setting \"homepage\" to \".\" in the package.json file.\n\n## Singleton Instance\nThe client is exported as a singleton to avoid duplicate registration on event listeners.\nYou can import the instance like this:\n\n```js\nimport AssistantAPIClient from '@io-maana/q-assistant-client';\n```\n\nFunction calls can be made against the client instance like any other javascript object. They are all async.\n\n```js\nconst workspace = await AssistantAPIClient.getWorkspace(); \nconsole.log(\"Workspace:\", workspace)\n```\n\n## Dependencies\nPost-Robot\nhttps://github.com/krakenjs/post-robot\n\nPost-robot is used to provide a richer communication layer atop post-message.\n\n## Examples\n@TODO Logan\n\n## API Documentation\n\n### State management\n\n#### clearState = () =>\n\nThis will clear all ‘attached’ state between the assistant and the API. \n\nSpecifically, this will clear selection and inventory changed event listeners. \n\n```js\nawait AssistantAPIClient.clearState()\n```\n\n### User Info\nThe `UserInfo` object:\n```js\n{\n email: string,\n name: string\n}\n```\n\n#### getUserInfo = () => \n\nReturns a Userinfo object pertaining to the logged in user.\n\n```js\nconst userInfo = await AssistantAPIClient.getUserInfo()\n```\n### Selection\nThe `Selection` object:\n```js\n{\n  kindId: string\n  kindName: string\n  id: string\n}\n```\n\n#### getCurrentSelection = () => \n\nReturns an Array of `Selection` objects:\n\n```js\nconst {selection} = await AssistantAPIClient.getCurrentSelection();\n```\n\n#### addSelectionChangedListener = async cb =>\n\nAdds a callback function to be executed upon a valid workspace selection change.\n\nCallback value is an array of Selection objects:\n\n```js\n// Create the selection callback.\nconst selectionCB = ({selection})=>{\n  console.log('Workspace selection has changed.')\n  selection.forEach(i=>{\n    console.log('Kind: ',i.kindName)\n    console.log('Instance Id:',i.id)\n    console.log('Kind Id:',i.kindId)\n  })\n}\n\n// Add the listener.\nAssistantAPIClient.addSelectionChangedListener(selectionCB);\n```\n\nThis function only exists on the Q-Assistant-Client--only enableSelectionChangedNotification is called on the API. \n\n#### removeSelectionChangedListener = async cb =>\n\nThis will have to be called on a 1:1 basis with addSelectionChangedListener calls if supplying a callback.\n\n```js\nAssistantAPIClient.removeSelectionChangedListener(selectionCB)\n```\n\n**If NOT supplying a callback to this call, all selection changed listeners will be removed.\n\n```js\nAssistantAPIClient.removeSelectionChangedListener()\n```\n\nThis function only exists on the Q-Assistant-Client--only disableSelectionChangedNotification is called on the API. \n\n\n### Services\nThe `Service` object:\n```js\n{\n   id: string,\n   name: string\n   endpointUrl: string,\n   getKinds: () => // Returns [] of Kinds objects\n   getFunctions: () => // Returns [] of Function objects\n}\n```\n\n#### getServiceById = id =>\nThis will return a service that exists within the scope of the workspace. \n** Assistant services will return null. Services outside the scope of the workspace will cause an error to be returned as 'Unable to load a Service from outside of the workspace.'\n\n```js\nconst svc = await AssistantAPIClient.getServiceById(id)\n```\n\n### Workspace\nThe `Workspace` object:\n```js\n{\nid: string,\nname: string,\ngetKinds: () => {\n  // Returns an array of functions in the workspace (includes boilerplate).\n},\ngetFunctions: () =>\n  // Returns an array of functions in the workspace (includes boilerplate).\ngetActiveGraph: () => {\n  // Returns the active Graph object.\n  // Returns null if active graph is not of type 'Knowledge Graph', or if an\n  // active graph is deleted, thereby setting active graph to null.\n},\ngetKnowledgeGraphs: () => {\n  // Returns [Graph]\n},\ngetImportedServices: () => {\n  // Returns an service imported into the workspace\n  // as a array of Service object (this calls the function\n  // that underlies getServiceById.\n  // No assistant services will be returned.\n}\n}\n```\n\n#### getWorkspace = () =>\n\nReturns a Workspace object representing the workspace. \n\n```js\nconst ws = await AssistantAPIClient.getWorkspace()\n```\n\n### Graphs\nThe `Graph` object:\n```js\n{     \nid: string,\nname: string,\noffsetX: Number,\noffsetY: Number,\nzoom: Number,\ngetNodes: async () => {\n    // Returns [Node]\n},\n\naddNode: async (type, instance, changeSelection) => {\n    // Returns Node\n},\nremoveNode: async id => {\n    // Should return nothing or error.\n    // Currently returning [] in all cases.\n},\nupdateNodeLayout: async (nodeId, { x, y, collapsed }) => {\n},\nupdateGraphLayout: async ({ offsetX, offsetY, zoom }) => {\n}\n}\n```\n\n#### Getting a graph object:\nGraph objects are obtained through an instance of a Workspace \n\n```js\nconst ag = await ws.getActiveGraph()\n```\n\nor\n\n```js\nconst kgs = await ws.getKnowledgeGraphs()\n```\n\n#### Manipulating Graphs\n\n**Only the active graph may be manipulated.\n\nAll graph manipulations should be ‘visually’ verifiable on the graph itself, i.e., adds/removes/positioning, should all be reflected on the graph itself. \n\nThe `Node` object:\n```js\n{\nid: string\nx: number\ny: number\ncollapsed: boolean\nknowledgeGraphNode {\n  id: string\n  innerKind: Kind\n  innerFunction: Function\n}\n}\n```\n\n#### addNode(type, instance, changeSelection) =>\n\nTakes type (“Function” or “Kind”), instance (the Function or Kind object), and optionally a boolean to indicate whether the selection should be changed to this new node. \n\nReturns the newly created Node object.\n\n```js\nconst node = await ag.addNode('Kind',kind)\n```\n\n#### removeNode(id) =>\n\nTakes the id of Node to be deleted. Returns either undefined or an error. \n\n```js\nawait ag.removeNode(node.id)\n```\n\n#### getNodes() =>\nReturns an array of Node objects from the graph. \n\n```js\nconst nodes = await ag.getNodes()\n```\n\n#### updateNodeLayout: async (nodeId, { x, y, collapsed})=>\n\nUpdates a Node layout given a node ID and node coordinates (`x` and/or `y`) or a `collapsed` value. x/y values must be a number, and collapsed must be a boolean. Whatever is not specified will remain current.\n\n```js\nag.updateNodeLayout(id,{x:100,y:100,collapsed:true})\n```\n\n#### updateGraphLayout: async ({ offsetX, offsetY, zoom})=>\n\nUpdates a Graph layout given numerical values for x/y offsets and the zoom. \n\n```js\nag.updateGraphLayout({offsetX:50, offsetY:50, zoom: 70})\n```\n\n### Functions\n\nThe `Function` object:\n```js\n{\n    id: string\n    name: string\n    service {\n      id: string\n      name: string\n    }\n    arguments {\n      id: string\n      name: string\n      type: string\n      modifiers: Array[string]\n      typeKindId:: string\n      kind {\n        id: string\n        name: string\n      }\n    }\n    implementation {\n      id: string\n      entrypoint {\n        id: string\n      }\n      operations {\n        id: string\n        type: string\n        function {\n          id: string\n          name: string\n        }\n        argumentValues {\n          id: string\n          argument {\n            id: string\n          }\n          operation {\n            id: string\n          }\n          argumentRef: string\n        }\n      }\n    }\n    isGenerated: boolean\n    functionType: string\n    graphqlOperationType: string\n    outputType: string\n    outputKindId: string\n    outputModifiers: Array[string]\n    kind {\n      id: string\n      name: string\n    }\n}\n```\n\n`FunctionExecutionResult` object:\n```js\n{\n  id: string,\n  result: JSON\n}\n```\n\n#### executeFunction = ( {id, variables, resolve} ) =>\n\nExecutes a function based on its id, with optional inputs for variables and a resolve string (this specifies the fields to be returned, which must be valid based on the result).\n\nReturns : JSON matching shape of result , unless no sub-selection of fields is required in the execution.\n\nThis following piece of code will execute a Function given a function ID, and pass in variables for ‘example’, requesting back id and name fields. \n\n```js \nconst res = await AssistantAPIClient.executeFunction({functionId: func.id, variables: {\"variableName\": \"variableValue\"}, resolve: \"{ id name }\");\n```\n\n#### createFunction = input =>\n\nCreates a function based on the input provided. \n\nReturns: the created Function object.\n\n**Using create function will only place the function in the workspace’s inventory--it will not place the function as a node on the Graph. In order to do this, you must pass the created function into the addNode function on the active Graph, making sure to specify ‘Function' as the type.\n\n```js\nconst createFunctionInput = {\n  name:\"yourName\",\n  arguments:[],\n  outputType: \"STRING\",\n  graphqlOperationType:\"QUERY\",\n  functionType: \"CKG\"\n}\n  \nconst createdFunction = await AssistantAPIClient.createFunction(createFunctionInput)\n```\n\n#### updateFunction = input =>\n\nInput is the same for creating a function. It’s important to note that the arguments property will be replaced in it’s entirety with whatever is provided (if a value is provided.\n\nReturns the updated `Function` object.\n\n```js\nconst updatedFunction = await AssistantAPIClient.updateFunction(input);\n```\n\n#### deleteFunction = input =>\n\nInput is the id of the Function to be deleted. Returns the deleted function as a promise.\n\n```js\nconst deletedFunction = await AssistantAPIClient.deleteFunction('id...');\n```\n\n#### getFunctionById = id =>\n\nReturns a Function as a promise based on the ID provided.\n\n```js\nconst func = await AssistantAPIClient.getFunctionById('id...');\n```\n\n#### addFunctionExecutionListener = async (id, cb) =>\n\nAssociates a callback function with the execution of a particular Function. When the Function matching the id parameter is executed, its FunctionExecutionResult object passed to the callback. Returns undefined.\n\nExample function execution callback and listener registration:\n\n```js\nfunction exampleFunctionCB (result){\n  console.log(`Function executed with result:`, result)\n}\n\nAssistantAPIClient.addFunctionExecutionListener('id...', exampleFunctionCB)\n```\n\n#### removeFunctionExecutionListener = async (id, cb) =>\n\nRemoves a Function execution listener based on the function ID and a reference to the callback function. If no callback is supplied, all listeners associated with the Function ID will be removed. Returns undefined.\n\n```js\nAssistantAPIClient.removeFunctionExecutionListener('id..', exampleFunctionCB)\n```\n\n### Kinds\nThe `Kind` object:\n```js\n{\n    id: string\n    name: string\n    service: {\n      id\n      name\n    }\n    isGenerated: boolean\n    schema {\n      id: string\n      name: string\n      type: string\n      typeKindId: string\n      modifiers: Array[string]\n      kind {\n        id: string\n        name: string\n      }\n    }\n}\n```\n\n#### createKind = input =>\n\nCreates a Kind based on an input object. Returns a promise that resolves to the created Kind object.\n\n```js\nconst kindInput = {\n name: \"someKind\",\n schema:[\n  { name: \"someField1\", type: STRING },\n  { name: \"someField2\", type: STRING }\n ]\n}\n\nconst newKind = await AssistantAPIClient.createKind(kindInput)\n```\n\n#### updateKind = input =>\n\nUpdates a Kind based on an input object. \n\nUpdate Semantics: Only properties specified will be updated. If updating the schema, the entire schema must be specified as it will be replaced in its entirety. \n\nReturns the updated `Kind` object.\n\n```js\nconst updated = await AssistantAPIClient.updateKind(input)\n```\n\n#### deleteKind = input =>\n\nDeletes a Kind given a kind ID.\n\n```js\nconst deleted = await AssistantAPIClient.deleteKind(input)\n```\n\n#### getKindById = id =>\n\nReturns a promise that resolves to a Kind object given the specified kind ID. Only kinds in the workspace or those of imported services will be returned. \n\n```js\nconst kind = await AssistantAPIClient.getKindById(id)\n```\n\n### Inventory\n\nThe `InventoryChanged` object:\n```js\n{\n  kinds: {\n    adds: [DiffItem]\n    deletes: [DiffItem]\n    updates: [DiffItem]\n  }\n  functions:{\n    adds: [DiffItem]\n    deletes: [DiffItem]\n    updates: [DiffItem]\n  }\n  services: {\n    adds: [DiffItem]\n    deletes: [DiffItem]\n    updates: [DiffItem]\n  }\n}\n```\n\nThe `DiffItem` object:\n```js\n{\n  id: string,\n  name: string\n}\n```\n\n#### addInventoryChangedListener = async cb =>\n\nRegisters a callback function with the inventory changed event. When workspace inventory changes the callback function will be called with the InventoryChangedobject. Returns undefined.\n\n*Current limitations: Kind and Function updates only occur where the name property is changed. Updates to services outside of the workspace will not be detected. \n\n**Use-case note: an ‘update’ diff for inventory services is unlikely in general usage. \n\n```js\nconst inventoryCB = ({diff}) => {\n  if(diff.kinds) console.log('KINDS CHANGED',diff.kinds)\n  if(diff.functions) console.log('FUNCTIONS CHANGED', diff.functions)\n  if(diff.services) console.log('SERVICES CHANGED',diff.services)\n}\n\nAssistantAPIClient.addInventoryChangedListener(inventoryCB)\n```\n\nThis function exists on the Q-Assisant-Client only--only enableSelectionChangedNotification is used on the API side. \n\n#### removeInventoryChangedListener = async cb =>\n\nRemoves an inventory changed listener given the referenced callback. If no callback is specified, all listeners will be removed. Returns undefined.\n\n```js\nAssistantAPIClient.removeInventoryChangedListener(inventoryCB)\n```\n\nThis function exists on the Q-Assisant-Client only--only disableSelectionChangedNotification is used on the API side. \n\n## Troubleshooting Assistant Issues\n### Assistant root file has loaded, but not other content\nObserving in the browser's dev tools that some resources have loaded correctly (usually the root), but other's haven't (usually nested files or chunks), is indicative of a failure of Q Gateway to proxy due to not having a 'relative' path structure.\n\n### You are seeing post-robot `NO ACK` errors in the console.\nThese errors stem from a failed acknowledgement for a call either between the client and the API or vice-versa. Here, this means that the web app 'window' (the assistant) cannot communicate with, or access, the 'window.parent' (Maana K-Portal) object. Improper CORS configuration is a common culprit (also verify if using docker or nginx that your proxying and networking is configured correctly to allow communication and to accout for CORS).","readmeFilename":"README.md","gitHead":"aec775c5d5a65752212ceb49274e989c2f94c007","_id":"@io-maana/q-assistant-client@3.2.2-beta.19","_npmVersion":"6.4.1","_nodeVersion":"10.15.3","_npmUser":{"name":"teamcitymaana","email":"teamcity@maana.io"},"dist":{"integrity":"sha512-bi60JpyEh5e3WiRPCYKVCWgQyWo8WaTepBT+HvZvKOdakF7DYXleeX0vKD9hm7oD2dvAGq1ixE0GKZcXVfvlYw==","shasum":"7ee8684d6c12efbb394db39460cea9a388a971df","tarball":"https://registry.npmjs.org/@io-maana/q-assistant-client/-/q-assistant-client-3.2.2-beta.19.tgz","fileCount":5,"unpackedSize":29931,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJd+SsZCRA9TVsSAnZWagAADckP/ikwZSDVSeavNAM93N1u\nsNM19VwpCFBRtM/ubrAjG5B/wSdCvObyf1siExU8TW2OcExGpll6xDQ/7iC2\nyZN1R2Md1wn8+U8hvaIvsnvTLXAPRtdvaABaTR94yJfv82+E6/VZ+56XsKUU\nvpRpFiyh+BWOviv+TqaRfDclHNY9QwkjqCHZVvWv3e38Q5H9b4zrDh8o7HrN\nQtR3Y4sorG4QmWMwOPTFt48KogJfVeLnNwDXdIkQjNZtfyu9/1rB0uaBQKL1\nTu1bZa9T4ZGwjgW9BL0Os60cnp6cE6xVVdPdTWJZwULm4bHulNJ9JiLBJXov\nX/rwoIePybaiLSBs6UzYCJ3nQZoJwbxTcv4EiMUcsiWROxuFFPyW0Ca3sp9r\nYEk/YyITf4K4IsozFUH0iRByM9qpJaqFJ86jXuo0kywMmxqAeir/e4sEPgaD\nUHGhrfJ/pa98N5uCUOYNAGzPXFKYzQXtV7YXunkxBgKTkAWyUtjfxXRacLAM\nLZMaPOma6SU+3wo/zG3fnOS2QtOlA7ickQtkSx/uBF2E2RhcC487XJJvwmba\nx/HlyRWA6639tu6k5bztApwBLB7epIjPEAhbsrewRXYwFzQtxSHKkFWE1rGu\nBxTHCey7jC+XtD+z+k2oVsmisckCSUwBnCo0gmiXqAo9YeJNQJwJBCvrLYeS\npJp5\r\n=sMUK\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEYCIQDlhMf2yLnOF+ZZGbM+wwnXrmPGpsBZ0EFsJcJcLXftzgIhAOs9kVHb8cuy/8cbBunJLpwdqHSvYlJXNpAOBz37iM/j"}]},"maintainers":[{"name":"abatyuk","email":"andrey@maana.io"},{"name":"bzvetey","email":"bzvestey@gmail.com"},{"name":"rpovey","email":"rob@maana.io"},{"name":"teamcitymaana","email":"teamcity@maana.io"},{"name":"witt3rd","email":"witt3rd@witt3rd.com"}],"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/q-assistant-client_3.2.2-beta.19_1576610585202_0.7168063831780576"},"_hasShrinkwrap":false},"3.2.2-beta.20":{"name":"@io-maana/q-assistant-client","version":"3.2.2-beta.20","description":"JavaScript package to streamline communication between an assistant and the Maana Q Assistant API.","main":"build/AssistantAPIClient.js","scripts":{"build":"babel src --out-dir build","prepack":"npm run build","test":"echo \"Error: no test specified\" && exit 1"},"repository":{"type":"git","url":"git+https://github.com/maana-io/q-assistant-client.git"},"keywords":["Maana","Q"],"author":{"name":"Logan Gore @ Maana.io"},"license":"MIT","bugs":{"url":"https://github.com/maana-io/q-assistant-client/issues"},"homepage":"https://github.com/maana-io/q-assistant-client#readme","dependencies":{"post-robot":"10.0.29"},"devDependencies":{"@babel/cli":"^7.5.5","@babel/core":"^7.5.5","@babel/plugin-proposal-class-properties":"^7.5.5","@babel/preset-env":"^7.5.5"},"readme":"# q-assistant-client\nA lightweight JavaScript client for Maana-Q Assistant developers that wraps post-message communication between an embedded Maana-Q assistant and the Maana-Q UI.\n\n## Abstract\nThe Q-Assistant-Client is intented to be used in a web application being leveraged as a Maana Q assistant (embedded as an iframe).\nThis assistant client will facilitate communication between the assistant and the parent frame.\nThe client provides a rich, asynchronous experience over what would otherwise be 'fire-and-forget'-style messaging \nvia post-post message communication. \n\n## Requirements and Assumptions\n\n### Post-Robot Library\nThe Maana Knowledge Portal (KPortal) uses the kraken/post-robot library [kraken/post-robot](https://github.com/krakenjs/post-robot) to enrich the communication with the assistant. Post-robot allows for asynchronous, promise-based request/response style behavior between the assistant and the assistant API.\n\nThe API requires that the client use the post-robot library. This assistant-client library is the easiest way to achieve this, and also adds a fair amount of 'sugar' to the process to improve developer productivity. Developers could, however, use post-robot directly in their own client implementation. \n\n### Maana-Gateway Proxy Requirements\nThe Maana-Gateway service requires relative paths (paths relative to the root) in the assistant web application in order to proxy the application and its content. For create-react-apps, for instance, this means setting \"homepage\" to \".\" in the package.json file.\n\n## Singleton Instance\nThe client is exported as a singleton to avoid duplicate registration on event listeners.\nYou can import the instance like this:\n\n```js\nimport AssistantAPIClient from '@io-maana/q-assistant-client';\n```\n\nFunction calls can be made against the client instance like any other javascript object. They are all async.\n\n```js\nconst workspace = await AssistantAPIClient.getWorkspace(); \nconsole.log(\"Workspace:\", workspace)\n```\n\n## Dependencies\nPost-Robot\nhttps://github.com/krakenjs/post-robot\n\nPost-robot is used to provide a richer communication layer atop post-message.\n\n## Examples\n@TODO Logan\n\n## API Documentation\n\n### State management\n\n#### clearState = () =>\n\nThis will clear all ‘attached’ state between the assistant and the API. \n\nSpecifically, this will clear selection and inventory changed event listeners. \n\n```js\nawait AssistantAPIClient.clearState()\n```\n\n### User Info\nThe `UserInfo` object:\n```js\n{\n email: string,\n name: string\n}\n```\n\n#### getUserInfo = () => \n\nReturns a Userinfo object pertaining to the logged in user.\n\n```js\nconst userInfo = await AssistantAPIClient.getUserInfo()\n```\n### Selection\nThe `Selection` object:\n```js\n{\n  kindId: string\n  kindName: string\n  id: string\n}\n```\n\n#### getCurrentSelection = () => \n\nReturns an Array of `Selection` objects:\n\n```js\nconst {selection} = await AssistantAPIClient.getCurrentSelection();\n```\n\n#### addSelectionChangedListener = async cb =>\n\nAdds a callback function to be executed upon a valid workspace selection change.\n\nCallback value is an array of Selection objects:\n\n```js\n// Create the selection callback.\nconst selectionCB = ({selection})=>{\n  console.log('Workspace selection has changed.')\n  selection.forEach(i=>{\n    console.log('Kind: ',i.kindName)\n    console.log('Instance Id:',i.id)\n    console.log('Kind Id:',i.kindId)\n  })\n}\n\n// Add the listener.\nAssistantAPIClient.addSelectionChangedListener(selectionCB);\n```\n\nThis function only exists on the Q-Assistant-Client--only enableSelectionChangedNotification is called on the API. \n\n#### removeSelectionChangedListener = async cb =>\n\nThis will have to be called on a 1:1 basis with addSelectionChangedListener calls if supplying a callback.\n\n```js\nAssistantAPIClient.removeSelectionChangedListener(selectionCB)\n```\n\n**If NOT supplying a callback to this call, all selection changed listeners will be removed.\n\n```js\nAssistantAPIClient.removeSelectionChangedListener()\n```\n\nThis function only exists on the Q-Assistant-Client--only disableSelectionChangedNotification is called on the API. \n\n\n### Services\nThe `Service` object:\n```js\n{\n   id: string,\n   name: string\n   endpointUrl: string,\n   getKinds: () => // Returns [] of Kinds objects\n   getFunctions: () => // Returns [] of Function objects\n}\n```\n\n#### getServiceById = id =>\nThis will return a service that exists within the scope of the workspace. \n** Assistant services will return null. Services outside the scope of the workspace will cause an error to be returned as 'Unable to load a Service from outside of the workspace.'\n\n```js\nconst svc = await AssistantAPIClient.getServiceById(id)\n```\n\n### Workspace\nThe `Workspace` object:\n```js\n{\nid: string,\nname: string,\ngetKinds: () => {\n  // Returns an array of functions in the workspace (includes boilerplate).\n},\ngetFunctions: () =>\n  // Returns an array of functions in the workspace (includes boilerplate).\ngetActiveGraph: () => {\n  // Returns the active Graph object.\n  // Returns null if active graph is not of type 'Knowledge Graph', or if an\n  // active graph is deleted, thereby setting active graph to null.\n},\ngetKnowledgeGraphs: () => {\n  // Returns [Graph]\n},\ngetImportedServices: () => {\n  // Returns an service imported into the workspace\n  // as a array of Service object (this calls the function\n  // that underlies getServiceById.\n  // No assistant services will be returned.\n}\n}\n```\n\n#### getWorkspace = () =>\n\nReturns a Workspace object representing the workspace. \n\n```js\nconst ws = await AssistantAPIClient.getWorkspace()\n```\n\n### Graphs\nThe `Graph` object:\n```js\n{     \nid: string,\nname: string,\noffsetX: Number,\noffsetY: Number,\nzoom: Number,\ngetNodes: async () => {\n    // Returns [Node]\n},\n\naddNode: async (type, instance, changeSelection) => {\n    // Returns Node\n},\nremoveNode: async id => {\n    // Should return nothing or error.\n    // Currently returning [] in all cases.\n},\nupdateNodeLayout: async (nodeId, { x, y, collapsed }) => {\n},\nupdateGraphLayout: async ({ offsetX, offsetY, zoom }) => {\n}\n}\n```\n\n#### Getting a graph object:\nGraph objects are obtained through an instance of a Workspace \n\n```js\nconst ag = await ws.getActiveGraph()\n```\n\nor\n\n```js\nconst kgs = await ws.getKnowledgeGraphs()\n```\n\n#### Manipulating Graphs\n\n**Only the active graph may be manipulated.\n\nAll graph manipulations should be ‘visually’ verifiable on the graph itself, i.e., adds/removes/positioning, should all be reflected on the graph itself. \n\nThe `Node` object:\n```js\n{\nid: string\nx: number\ny: number\ncollapsed: boolean\nknowledgeGraphNode {\n  id: string\n  innerKind: Kind\n  innerFunction: Function\n}\n}\n```\n\n#### addNode(type, instance, changeSelection) =>\n\nTakes type (“Function” or “Kind”), instance (the Function or Kind object), and optionally a boolean to indicate whether the selection should be changed to this new node. \n\nReturns the newly created Node object.\n\n```js\nconst node = await ag.addNode('Kind',kind)\n```\n\n#### removeNode(id) =>\n\nTakes the id of Node to be deleted. Returns either undefined or an error. \n\n```js\nawait ag.removeNode(node.id)\n```\n\n#### getNodes() =>\nReturns an array of Node objects from the graph. \n\n```js\nconst nodes = await ag.getNodes()\n```\n\n#### updateNodeLayout: async (nodeId, { x, y, collapsed})=>\n\nUpdates a Node layout given a node ID and node coordinates (`x` and/or `y`) or a `collapsed` value. x/y values must be a number, and collapsed must be a boolean. Whatever is not specified will remain current.\n\n```js\nag.updateNodeLayout(id,{x:100,y:100,collapsed:true})\n```\n\n#### updateGraphLayout: async ({ offsetX, offsetY, zoom})=>\n\nUpdates a Graph layout given numerical values for x/y offsets and the zoom. \n\n```js\nag.updateGraphLayout({offsetX:50, offsetY:50, zoom: 70})\n```\n\n### Functions\n\nThe `Function` object:\n```js\n{\n    id: string\n    name: string\n    service {\n      id: string\n      name: string\n    }\n    arguments {\n      id: string\n      name: string\n      type: string\n      modifiers: Array[string]\n      typeKindId:: string\n      kind {\n        id: string\n        name: string\n      }\n    }\n    implementation {\n      id: string\n      entrypoint {\n        id: string\n      }\n      operations {\n        id: string\n        type: string\n        function {\n          id: string\n          name: string\n        }\n        argumentValues {\n          id: string\n          argument {\n            id: string\n          }\n          operation {\n            id: string\n          }\n          argumentRef: string\n        }\n      }\n    }\n    isGenerated: boolean\n    functionType: string\n    graphqlOperationType: string\n    outputType: string\n    outputKindId: string\n    outputModifiers: Array[string]\n    kind {\n      id: string\n      name: string\n    }\n}\n```\n\n`FunctionExecutionResult` object:\n```js\n{\n  id: string,\n  result: JSON\n}\n```\n\n#### executeFunction = ( {id, variables, resolve} ) =>\n\nExecutes a function based on its id, with optional inputs for variables and a resolve string (this specifies the fields to be returned, which must be valid based on the result).\n\nReturns : JSON matching shape of result , unless no sub-selection of fields is required in the execution.\n\nThis following piece of code will execute a Function given a function ID, and pass in variables for ‘example’, requesting back id and name fields. \n\n```js \nconst res = await AssistantAPIClient.executeFunction({functionId: func.id, variables: {\"variableName\": \"variableValue\"}, resolve: \"{ id name }\");\n```\n\n#### createFunction = input =>\n\nCreates a function based on the input provided. \n\nReturns: the created Function object.\n\n**Using create function will only place the function in the workspace’s inventory--it will not place the function as a node on the Graph. In order to do this, you must pass the created function into the addNode function on the active Graph, making sure to specify ‘Function' as the type.\n\n```js\nconst createFunctionInput = {\n  name:\"yourName\",\n  arguments:[],\n  outputType: \"STRING\",\n  graphqlOperationType:\"QUERY\",\n  functionType: \"CKG\"\n}\n  \nconst createdFunction = await AssistantAPIClient.createFunction(createFunctionInput)\n```\n\n#### updateFunction = input =>\n\nInput is the same for creating a function. It’s important to note that the arguments property will be replaced in it’s entirety with whatever is provided (if a value is provided.\n\nReturns the updated `Function` object.\n\n```js\nconst updatedFunction = await AssistantAPIClient.updateFunction(input);\n```\n\n#### deleteFunction = input =>\n\nInput is the id of the Function to be deleted. Returns the deleted function as a promise.\n\n```js\nconst deletedFunction = await AssistantAPIClient.deleteFunction('id...');\n```\n\n#### getFunctionById = id =>\n\nReturns a Function as a promise based on the ID provided.\n\n```js\nconst func = await AssistantAPIClient.getFunctionById('id...');\n```\n\n#### addFunctionExecutionListener = async (id, cb) =>\n\nAssociates a callback function with the execution of a particular Function. When the Function matching the id parameter is executed, its FunctionExecutionResult object passed to the callback. Returns undefined.\n\nExample function execution callback and listener registration:\n\n```js\nfunction exampleFunctionCB (result){\n  console.log(`Function executed with result:`, result)\n}\n\nAssistantAPIClient.addFunctionExecutionListener('id...', exampleFunctionCB)\n```\n\n#### removeFunctionExecutionListener = async (id, cb) =>\n\nRemoves a Function execution listener based on the function ID and a reference to the callback function. If no callback is supplied, all listeners associated with the Function ID will be removed. Returns undefined.\n\n```js\nAssistantAPIClient.removeFunctionExecutionListener('id..', exampleFunctionCB)\n```\n\n### Kinds\nThe `Kind` object:\n```js\n{\n    id: string\n    name: string\n    service: {\n      id\n      name\n    }\n    isGenerated: boolean\n    schema {\n      id: string\n      name: string\n      type: string\n      typeKindId: string\n      modifiers: Array[string]\n      kind {\n        id: string\n        name: string\n      }\n    }\n}\n```\n\n#### createKind = input =>\n\nCreates a Kind based on an input object. Returns a promise that resolves to the created Kind object.\n\n```js\nconst kindInput = {\n name: \"someKind\",\n schema:[\n  { name: \"someField1\", type: STRING },\n  { name: \"someField2\", type: STRING }\n ]\n}\n\nconst newKind = await AssistantAPIClient.createKind(kindInput)\n```\n\n#### updateKind = input =>\n\nUpdates a Kind based on an input object. \n\nUpdate Semantics: Only properties specified will be updated. If updating the schema, the entire schema must be specified as it will be replaced in its entirety. \n\nReturns the updated `Kind` object.\n\n```js\nconst updated = await AssistantAPIClient.updateKind(input)\n```\n\n#### deleteKind = input =>\n\nDeletes a Kind given a kind ID.\n\n```js\nconst deleted = await AssistantAPIClient.deleteKind(input)\n```\n\n#### getKindById = id =>\n\nReturns a promise that resolves to a Kind object given the specified kind ID. Only kinds in the workspace or those of imported services will be returned. \n\n```js\nconst kind = await AssistantAPIClient.getKindById(id)\n```\n\n### Inventory\n\nThe `InventoryChanged` object:\n```js\n{\n  kinds: {\n    adds: [DiffItem]\n    deletes: [DiffItem]\n    updates: [DiffItem]\n  }\n  functions:{\n    adds: [DiffItem]\n    deletes: [DiffItem]\n    updates: [DiffItem]\n  }\n  services: {\n    adds: [DiffItem]\n    deletes: [DiffItem]\n    updates: [DiffItem]\n  }\n}\n```\n\nThe `DiffItem` object:\n```js\n{\n  id: string,\n  name: string\n}\n```\n\n#### addInventoryChangedListener = async cb =>\n\nRegisters a callback function with the inventory changed event. When workspace inventory changes the callback function will be called with the InventoryChangedobject. Returns undefined.\n\n*Current limitations: Kind and Function updates only occur where the name property is changed. Updates to services outside of the workspace will not be detected. \n\n**Use-case note: an ‘update’ diff for inventory services is unlikely in general usage. \n\n```js\nconst inventoryCB = ({diff}) => {\n  if(diff.kinds) console.log('KINDS CHANGED',diff.kinds)\n  if(diff.functions) console.log('FUNCTIONS CHANGED', diff.functions)\n  if(diff.services) console.log('SERVICES CHANGED',diff.services)\n}\n\nAssistantAPIClient.addInventoryChangedListener(inventoryCB)\n```\n\nThis function exists on the Q-Assisant-Client only--only enableSelectionChangedNotification is used on the API side. \n\n#### removeInventoryChangedListener = async cb =>\n\nRemoves an inventory changed listener given the referenced callback. If no callback is specified, all listeners will be removed. Returns undefined.\n\n```js\nAssistantAPIClient.removeInventoryChangedListener(inventoryCB)\n```\n\nThis function exists on the Q-Assisant-Client only--only disableSelectionChangedNotification is used on the API side. \n\n## Troubleshooting Assistant Issues\n### Assistant root file has loaded, but not other content\nObserving in the browser's dev tools that some resources have loaded correctly (usually the root), but other's haven't (usually nested files or chunks), is indicative of a failure of Q Gateway to proxy due to not having a 'relative' path structure.\n\n### You are seeing post-robot `NO ACK` errors in the console.\nThese errors stem from a failed acknowledgement for a call either between the client and the API or vice-versa. Here, this means that the web app 'window' (the assistant) cannot communicate with, or access, the 'window.parent' (Maana K-Portal) object. Improper CORS configuration is a common culprit (also verify if using docker or nginx that your proxying and networking is configured correctly to allow communication and to accout for CORS).","readmeFilename":"README.md","gitHead":"da83232c1b7c93b520cec86c4592c60aeed64e0f","_id":"@io-maana/q-assistant-client@3.2.2-beta.20","_npmVersion":"6.4.1","_nodeVersion":"10.15.3","_npmUser":{"name":"teamcitymaana","email":"teamcity@maana.io"},"dist":{"integrity":"sha512-FDpnSeJxCMduFdIPdzjNpbyMy9BHQXxIP6d67w2hegBv1WxCXPC+3e3JJyfa0dVP/vCkJCm1bjU85QZdSEkRdw==","shasum":"841d5a6c89bcef36e19e759f5bf4f92c8ae9a1ac","tarball":"https://registry.npmjs.org/@io-maana/q-assistant-client/-/q-assistant-client-3.2.2-beta.20.tgz","fileCount":5,"unpackedSize":33462,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJeQzwfCRA9TVsSAnZWagAAwwUP/R6VZLONpVbJpQR4o1WA\njpwww/p1aTrD/Sfvx2TJ3g+L4fWNCiRc1JbOXFlPUkrcwRdfshoaAO2w0Dnk\nJccu9DHE2GNR/++FVWSZ5X8ZEtuv5GsX+IJSjBi4bXeOtQziC/VKz/5kbWll\nhCjnc8CP111uSDxh/Kisj1kCfNvE2XV4qx+WvcJTefN6m8iqGsHSl6CiGYQg\nwerz1/Ecivf3LoEdrZ97Ca4twNsrraPItVV0vZ+XORONMY92qnWCeBRfjQiF\nIkhPZIGU3ilHQcrBf8Pw2ALVMqWvFZquCRuTyh3a5F9hZpuX8jSQNI85JdQ8\nI8LaKw0K3gxvUc2jzKtmDSXHQVVy6brkborf73ZGHLXOae0yISCkex2S7saJ\nd8OMOZMjYa2C/Y9uUhoYbeEvDV0Dp/SmvzDtfIZcaMYzujdYWKh+TuJZlGnP\nU7Crm0tWUD8DWPpCjlIUukuFOkHuiw5Mra3gmwNofwsXM7sndHlI8Z3oJWbN\n9hwx8/pDEw+Z32URUCUTJCAyFFUhOfHAUNW04YJZ2sVusHPiax+22CDBA1I2\nzzlgqs05IuUf6EyV302ppq7DcMDCrQsagOlAWJZI5RZpLo6jnitbe3iiZ835\noqHIE6fBOw7or72+Conz/w2OvcBZqUl9GRV/QKGBR8b8ynD6403nrQDux7YB\nt8/5\r\n=C4w+\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCICiMqsU0qa5+rM6g3xtvtIJ1X0KAIx2cFQuD00HWxeA1AiEAql9/8fcIcS/G8SW8bPcLziQKcn5VZjs2eST3l5HwDRY="}]},"maintainers":[{"name":"abatyuk","email":"andrey@maana.io"},{"name":"bzvetey","email":"bzvestey@gmail.com"},{"name":"rpovey","email":"rob@maana.io"},{"name":"teamcitymaana","email":"teamcity@maana.io"},{"name":"witt3rd","email":"witt3rd@witt3rd.com"}],"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/q-assistant-client_3.2.2-beta.20_1581464606588_0.6493731926960566"},"_hasShrinkwrap":false},"3.2.2-beta.21":{"name":"@io-maana/q-assistant-client","version":"3.2.2-beta.21","description":"JavaScript package to streamline communication between an assistant and the Maana Q Assistant API.","main":"build/AssistantAPIClient.js","scripts":{"build":"babel src --out-dir build","prepack":"npm run build","test":"echo \"Error: no test specified\" && exit 1","format":"prettier --write \"src/**/*.js\""},"repository":{"type":"git","url":"git+https://github.com/maana-io/q-assistant-client.git"},"keywords":["Maana","Q"],"author":{"name":"Logan Gore @ Maana.io"},"license":"MIT","bugs":{"url":"https://github.com/maana-io/q-assistant-client/issues"},"homepage":"https://github.com/maana-io/q-assistant-client#readme","dependencies":{"post-robot":"10.0.29"},"devDependencies":{"@babel/cli":"^7.5.5","@babel/core":"^7.5.5","@babel/plugin-proposal-class-properties":"^7.5.5","@babel/preset-env":"^7.5.5","prettier":"1.19.1"},"readme":"# q-assistant-client\nA lightweight JavaScript client for Maana-Q Assistant developers that wraps post-message communication between an embedded Maana-Q assistant and the Maana-Q UI.\n\n## Abstract\nThe Q-Assistant-Client is intented to be used in a web application being leveraged as a Maana Q assistant (embedded as an iframe).\nThis assistant client will facilitate communication between the assistant and the parent frame.\nThe client provides a rich, asynchronous experience over what would otherwise be 'fire-and-forget'-style messaging \nvia post-post message communication. \n\n## Requirements and Assumptions\n\n### Post-Robot Library\nThe Maana Knowledge Portal (KPortal) uses the kraken/post-robot library [kraken/post-robot](https://github.com/krakenjs/post-robot) to enrich the communication with the assistant. Post-robot allows for asynchronous, promise-based request/response style behavior between the assistant and the assistant API.\n\nThe API requires that the client use the post-robot library. This assistant-client library is the easiest way to achieve this, and also adds a fair amount of 'sugar' to the process to improve developer productivity. Developers could, however, use post-robot directly in their own client implementation. \n\n### Maana-Gateway Proxy Requirements\nThe Maana-Gateway service requires relative paths (paths relative to the root) in the assistant web application in order to proxy the application and its content. For create-react-apps, for instance, this means setting \"homepage\" to \".\" in the package.json file.\n\n## Singleton Instance\nThe client is exported as a singleton to avoid duplicate registration on event listeners.\nYou can import the instance like this:\n\n```js\nimport AssistantAPIClient from '@io-maana/q-assistant-client';\n```\n\nFunction calls can be made against the client instance like any other javascript object. They are all async.\n\n```js\nconst workspace = await AssistantAPIClient.getWorkspace(); \nconsole.log(\"Workspace:\", workspace)\n```\n\n## Dependencies\nPost-Robot\nhttps://github.com/krakenjs/post-robot\n\nPost-robot is used to provide a richer communication layer atop post-message.\n\n## Examples\n@TODO Logan\n\n## API Documentation\n\n### State management\n\n#### clearState = () =>\n\nThis will clear all ‘attached’ state between the assistant and the API. \n\nSpecifically, this will clear selection and inventory changed event listeners. \n\n```js\nawait AssistantAPIClient.clearState()\n```\n\n### User Info\nThe `UserInfo` object:\n```js\n{\n email: string,\n name: string\n}\n```\n\n#### getUserInfo = () => \n\nReturns a Userinfo object pertaining to the logged in user.\n\n```js\nconst userInfo = await AssistantAPIClient.getUserInfo()\n```\n### Selection\nThe `Selection` object:\n```js\n{\n  kindId: string\n  kindName: string\n  id: string\n}\n```\n\n#### getCurrentSelection = () => \n\nReturns an Array of `Selection` objects:\n\n```js\nconst {selection} = await AssistantAPIClient.getCurrentSelection();\n```\n\n#### addSelectionChangedListener = async cb =>\n\nAdds a callback function to be executed upon a valid workspace selection change.\n\nCallback value is an array of Selection objects:\n\n```js\n// Create the selection callback.\nconst selectionCB = ({selection})=>{\n  console.log('Workspace selection has changed.')\n  selection.forEach(i=>{\n    console.log('Kind: ',i.kindName)\n    console.log('Instance Id:',i.id)\n    console.log('Kind Id:',i.kindId)\n  })\n}\n\n// Add the listener.\nAssistantAPIClient.addSelectionChangedListener(selectionCB);\n```\n\nThis function only exists on the Q-Assistant-Client--only enableSelectionChangedNotification is called on the API. \n\n#### removeSelectionChangedListener = async cb =>\n\nThis will have to be called on a 1:1 basis with addSelectionChangedListener calls if supplying a callback.\n\n```js\nAssistantAPIClient.removeSelectionChangedListener(selectionCB)\n```\n\n**If NOT supplying a callback to this call, all selection changed listeners will be removed.\n\n```js\nAssistantAPIClient.removeSelectionChangedListener()\n```\n\nThis function only exists on the Q-Assistant-Client--only disableSelectionChangedNotification is called on the API. \n\n\n### Services\nThe `Service` object:\n```js\n{\n   id: string,\n   name: string\n   endpointUrl: string,\n   getKinds: () => // Returns [] of Kinds objects\n   getFunctions: () => // Returns [] of Function objects\n}\n```\n\n#### getServiceById = id =>\nThis will return a service that exists within the scope of the workspace. \n** Assistant services will return null. Services outside the scope of the workspace will cause an error to be returned as 'Unable to load a Service from outside of the workspace.'\n\n```js\nconst svc = await AssistantAPIClient.getServiceById(id)\n```\n\n### Workspace\nThe `Workspace` object:\n```js\n{\nid: string,\nname: string,\ngetKinds: () => {\n  // Returns an array of functions in the workspace (includes boilerplate).\n},\ngetFunctions: () =>\n  // Returns an array of functions in the workspace (includes boilerplate).\ngetActiveGraph: () => {\n  // Returns the active Graph object.\n  // Returns null if active graph is not of type 'Knowledge Graph', or if an\n  // active graph is deleted, thereby setting active graph to null.\n},\ngetKnowledgeGraphs: () => {\n  // Returns [Graph]\n},\ngetImportedServices: () => {\n  // Returns an service imported into the workspace\n  // as a array of Service object (this calls the function\n  // that underlies getServiceById.\n  // No assistant services will be returned.\n}\n}\n```\n\n#### getWorkspace = () =>\n\nReturns a Workspace object representing the workspace. \n\n```js\nconst ws = await AssistantAPIClient.getWorkspace()\n```\n\n### Graphs\nThe `Graph` object:\n```js\n{     \nid: string,\nname: string,\noffsetX: Number,\noffsetY: Number,\nzoom: Number,\ngetNodes: async () => {\n    // Returns [Node]\n},\n\naddNode: async (type, instance, changeSelection) => {\n    // Returns Node\n},\nremoveNode: async id => {\n    // Should return nothing or error.\n    // Currently returning [] in all cases.\n},\nupdateNodeLayout: async (nodeId, { x, y, collapsed }) => {\n},\nupdateGraphLayout: async ({ offsetX, offsetY, zoom }) => {\n}\n}\n```\n\n#### Getting a graph object:\nGraph objects are obtained through an instance of a Workspace \n\n```js\nconst ag = await ws.getActiveGraph()\n```\n\nor\n\n```js\nconst kgs = await ws.getKnowledgeGraphs()\n```\n\n#### Manipulating Graphs\n\n**Only the active graph may be manipulated.\n\nAll graph manipulations should be ‘visually’ verifiable on the graph itself, i.e., adds/removes/positioning, should all be reflected on the graph itself. \n\nThe `Node` object:\n```js\n{\nid: string\nx: number\ny: number\ncollapsed: boolean\nknowledgeGraphNode {\n  id: string\n  innerKind: Kind\n  innerFunction: Function\n}\n}\n```\n\n#### addNode(type, instance, changeSelection) =>\n\nTakes type (“Function” or “Kind”), instance (the Function or Kind object), and optionally a boolean to indicate whether the selection should be changed to this new node. \n\nReturns the newly created Node object.\n\n```js\nconst node = await ag.addNode('Kind',kind)\n```\n\n#### removeNode(id) =>\n\nTakes the id of Node to be deleted. Returns either undefined or an error. \n\n```js\nawait ag.removeNode(node.id)\n```\n\n#### getNodes() =>\nReturns an array of Node objects from the graph. \n\n```js\nconst nodes = await ag.getNodes()\n```\n\n#### updateNodeLayout: async (nodeId, { x, y, collapsed})=>\n\nUpdates a Node layout given a node ID and node coordinates (`x` and/or `y`) or a `collapsed` value. x/y values must be a number, and collapsed must be a boolean. Whatever is not specified will remain current.\n\n```js\nag.updateNodeLayout(id,{x:100,y:100,collapsed:true})\n```\n\n#### updateGraphLayout: async ({ offsetX, offsetY, zoom})=>\n\nUpdates a Graph layout given numerical values for x/y offsets and the zoom. \n\n```js\nag.updateGraphLayout({offsetX:50, offsetY:50, zoom: 70})\n```\n\n### Functions\n\nThe `Function` object:\n```js\n{\n    id: string\n    name: string\n    service {\n      id: string\n      name: string\n    }\n    arguments {\n      id: string\n      name: string\n      type: string\n      modifiers: Array[string]\n      typeKindId:: string\n      kind {\n        id: string\n        name: string\n      }\n    }\n    implementation {\n      id: string\n      entrypoint {\n        id: string\n      }\n      operations {\n        id: string\n        type: string\n        function {\n          id: string\n          name: string\n        }\n        argumentValues {\n          id: string\n          argument {\n            id: string\n          }\n          operation {\n            id: string\n          }\n          argumentRef: string\n        }\n      }\n    }\n    isGenerated: boolean\n    functionType: string\n    graphqlOperationType: string\n    outputType: string\n    outputKindId: string\n    outputModifiers: Array[string]\n    kind {\n      id: string\n      name: string\n    }\n}\n```\n\n`FunctionExecutionResult` object:\n```js\n{\n  id: string,\n  result: JSON\n}\n```\n\n#### executeFunction = ( {id, variables, resolve} ) =>\n\nExecutes a function based on its id, with optional inputs for variables and a resolve string (this specifies the fields to be returned, which must be valid based on the result).\n\nReturns : JSON matching shape of result , unless no sub-selection of fields is required in the execution.\n\nThis following piece of code will execute a Function given a function ID, and pass in variables for ‘example’, requesting back id and name fields. \n\n```js \nconst res = await AssistantAPIClient.executeFunction({functionId: func.id, variables: {\"variableName\": \"variableValue\"}, resolve: \"{ id name }\");\n```\n\n#### createFunction = input =>\n\nCreates a function based on the input provided. \n\nReturns: the created Function object.\n\n**Using create function will only place the function in the workspace’s inventory--it will not place the function as a node on the Graph. In order to do this, you must pass the created function into the addNode function on the active Graph, making sure to specify ‘Function' as the type.\n\n```js\nconst createFunctionInput = {\n  name:\"yourName\",\n  arguments:[],\n  outputType: \"STRING\",\n  graphqlOperationType:\"QUERY\",\n  functionType: \"CKG\"\n}\n  \nconst createdFunction = await AssistantAPIClient.createFunction(createFunctionInput)\n```\n\n#### updateFunction = input =>\n\nInput is the same for creating a function. It’s important to note that the arguments property will be replaced in it’s entirety with whatever is provided (if a value is provided.\n\nReturns the updated `Function` object.\n\n```js\nconst updatedFunction = await AssistantAPIClient.updateFunction(input);\n```\n\n#### deleteFunction = input =>\n\nInput is the id of the Function to be deleted. Returns the deleted function as a promise.\n\n```js\nconst deletedFunction = await AssistantAPIClient.deleteFunction('id...');\n```\n\n#### getFunctionById = id =>\n\nReturns a Function as a promise based on the ID provided.\n\n```js\nconst func = await AssistantAPIClient.getFunctionById('id...');\n```\n\n#### addFunctionExecutionListener = async (id, cb) =>\n\nAssociates a callback function with the execution of a particular Function. When the Function matching the id parameter is executed, its FunctionExecutionResult object passed to the callback. Returns undefined.\n\nExample function execution callback and listener registration:\n\n```js\nfunction exampleFunctionCB (result){\n  console.log(`Function executed with result:`, result)\n}\n\nAssistantAPIClient.addFunctionExecutionListener('id...', exampleFunctionCB)\n```\n\n#### removeFunctionExecutionListener = async (id, cb) =>\n\nRemoves a Function execution listener based on the function ID and a reference to the callback function. If no callback is supplied, all listeners associated with the Function ID will be removed. Returns undefined.\n\n```js\nAssistantAPIClient.removeFunctionExecutionListener('id..', exampleFunctionCB)\n```\n\n### Kinds\nThe `Kind` object:\n```js\n{\n    id: string\n    name: string\n    service: {\n      id\n      name\n    }\n    isGenerated: boolean\n    schema {\n      id: string\n      name: string\n      type: string\n      typeKindId: string\n      modifiers: Array[string]\n      kind {\n        id: string\n        name: string\n      }\n    }\n}\n```\n\n#### createKind = input =>\n\nCreates a Kind based on an input object. Returns a promise that resolves to the created Kind object.\n\n```js\nconst kindInput = {\n name: \"someKind\",\n schema:[\n  { name: \"someField1\", type: STRING },\n  { name: \"someField2\", type: STRING }\n ]\n}\n\nconst newKind = await AssistantAPIClient.createKind(kindInput)\n```\n\n#### updateKind = input =>\n\nUpdates a Kind based on an input object. \n\nUpdate Semantics: Only properties specified will be updated. If updating the schema, the entire schema must be specified as it will be replaced in its entirety. \n\nReturns the updated `Kind` object.\n\n```js\nconst updated = await AssistantAPIClient.updateKind(input)\n```\n\n#### deleteKind = input =>\n\nDeletes a Kind given a kind ID.\n\n```js\nconst deleted = await AssistantAPIClient.deleteKind(input)\n```\n\n#### getKindById = id =>\n\nReturns a promise that resolves to a Kind object given the specified kind ID. Only kinds in the workspace or those of imported services will be returned. \n\n```js\nconst kind = await AssistantAPIClient.getKindById(id)\n```\n\n### Inventory\n\nThe `InventoryChanged` object:\n```js\n{\n  kinds: {\n    adds: [DiffItem]\n    deletes: [DiffItem]\n    updates: [DiffItem]\n  }\n  functions:{\n    adds: [DiffItem]\n    deletes: [DiffItem]\n    updates: [DiffItem]\n  }\n  services: {\n    adds: [DiffItem]\n    deletes: [DiffItem]\n    updates: [DiffItem]\n  }\n}\n```\n\nThe `DiffItem` object:\n```js\n{\n  id: string,\n  name: string\n}\n```\n\n#### addInventoryChangedListener = async cb =>\n\nRegisters a callback function with the inventory changed event. When workspace inventory changes the callback function will be called with the InventoryChangedobject. Returns undefined.\n\n*Current limitations: Kind and Function updates only occur where the name property is changed. Updates to services outside of the workspace will not be detected. \n\n**Use-case note: an ‘update’ diff for inventory services is unlikely in general usage. \n\n```js\nconst inventoryCB = ({diff}) => {\n  if(diff.kinds) console.log('KINDS CHANGED',diff.kinds)\n  if(diff.functions) console.log('FUNCTIONS CHANGED', diff.functions)\n  if(diff.services) console.log('SERVICES CHANGED',diff.services)\n}\n\nAssistantAPIClient.addInventoryChangedListener(inventoryCB)\n```\n\nThis function exists on the Q-Assisant-Client only--only enableSelectionChangedNotification is used on the API side. \n\n#### removeInventoryChangedListener = async cb =>\n\nRemoves an inventory changed listener given the referenced callback. If no callback is specified, all listeners will be removed. Returns undefined.\n\n```js\nAssistantAPIClient.removeInventoryChangedListener(inventoryCB)\n```\n\nThis function exists on the Q-Assisant-Client only--only disableSelectionChangedNotification is used on the API side. \n\n## Troubleshooting Assistant Issues\n### Assistant root file has loaded, but not other content\nObserving in the browser's dev tools that some resources have loaded correctly (usually the root), but other's haven't (usually nested files or chunks), is indicative of a failure of Q Gateway to proxy due to not having a 'relative' path structure.\n\n### You are seeing post-robot `NO ACK` errors in the console.\nThese errors stem from a failed acknowledgement for a call either between the client and the API or vice-versa. Here, this means that the web app 'window' (the assistant) cannot communicate with, or access, the 'window.parent' (Maana K-Portal) object. Improper CORS configuration is a common culprit (also verify if using docker or nginx that your proxying and networking is configured correctly to allow communication and to accout for CORS).","readmeFilename":"README.md","gitHead":"8781a589896e15ccdd367b342e9f57ffa86c170d","_id":"@io-maana/q-assistant-client@3.2.2-beta.21","_npmVersion":"6.4.1","_nodeVersion":"10.15.3","_npmUser":{"name":"teamcitymaana","email":"teamcity@maana.io"},"dist":{"integrity":"sha512-0ilN3j2Dal/RkbhyREszUu0CnqA0FsUdShDAwbyHPFtLmpo50RthifbgG0ozVSgMhn6PO8Xl//kV1ZMu46ftVw==","shasum":"248cb8dccea27da240afd176e6a431f846007635","tarball":"https://registry.npmjs.org/@io-maana/q-assistant-client/-/q-assistant-client-3.2.2-beta.21.tgz","fileCount":6,"unpackedSize":33581,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJeRDKjCRA9TVsSAnZWagAAXz8QAIyXD/ctEJ3okdL4YGXn\nqKUDXWzKM/Y1WOkf0udb2LFZI7rR3Gb9vJ2ai4k1pUy6SPra2hc3K84vR9RS\nk/wg4x8A33tr/ZdFY9PnJs0SyOVLPlQi075zrC1w8RnjncQ4VmdSQI8rPB6r\nzMdD6pSyP+HAtFbI5yGlbIFW7vGfxFGVDCbBg6GekR/62dG0bTMK2ge3LB+W\ny68Wa3ThaorICHuconXe+1NxVTRyev8aaH6iRo52yTTFm3Rr2jnZWPaBanqW\n4xjqhDYzZX4FM2uvM1oLKf7QK6vGCMoF1Zi5vD53uCXIM9huqDOxp3CSMwJy\nz4tzG4CQGQyoIip6lLmVgeRkwtfag97xlBOVk1JPai748LGTgRMsetHe+TLp\nvHVXYBFxpX+kb7/y0hC2ZxoOefNc7Co7ye29+Clkd6GQXYQJ3X3gtZhOxSj0\nyNrCIPYtTvO+mv7ZAaM4llFgGTkcQZOUZTJbllCn+5L/XkH5QemVNVLQ19jx\n74BIfO95YI4rATRc561MyX4Mhz53HsmPGUS20VGGFywBOBgwss5Y5XmNVo0U\n0h3SzsyKwxCyxE6UcXHEwNMc2Pz2IB11aKsly+nEQyqdhVkrxHEeiqQXFOrh\nSgy1SaAPcSaJk+YYvAX9chd3F4c654CgvHNxwLf10G+TLy2kdPmFhx4+/iTm\nidE4\r\n=CGLf\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIDvWi9bImxdCkUZUzMyEHG07BPRyrV4tcvCV2Tj9ZpmVAiEA0KKJ95ALPnd54AuJZuirKD0hhcBvHEYw/DBopHX+jVg="}]},"maintainers":[{"name":"abatyuk","email":"andrey@maana.io"},{"name":"bzvetey","email":"bzvestey@gmail.com"},{"name":"rpovey","email":"rob@maana.io"},{"name":"teamcitymaana","email":"teamcity@maana.io"},{"name":"witt3rd","email":"witt3rd@witt3rd.com"}],"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/q-assistant-client_3.2.2-beta.21_1581527715300_0.5096573047901445"},"_hasShrinkwrap":false},"3.2.2-beta.22":{"name":"@io-maana/q-assistant-client","version":"3.2.2-beta.22","description":"JavaScript package to streamline communication between an assistant and the Maana Q Assistant API.","main":"build/AssistantAPIClient.js","scripts":{"build":"babel src --out-dir build","prepack":"npm run build","test":"echo \"Error: no test specified\" && exit 1","format":"prettier --write \"src/**/*.js\""},"repository":{"type":"git","url":"git+https://github.com/maana-io/q-assistant-client.git"},"keywords":["Maana","Q"],"author":{"name":"Logan Gore @ Maana.io"},"license":"MIT","bugs":{"url":"https://github.com/maana-io/q-assistant-client/issues"},"homepage":"https://github.com/maana-io/q-assistant-client#readme","dependencies":{"post-robot":"10.0.29"},"devDependencies":{"@babel/cli":"^7.5.5","@babel/core":"^7.5.5","@babel/plugin-proposal-class-properties":"^7.5.5","@babel/preset-env":"^7.5.5","prettier":"1.19.1"},"readme":"# q-assistant-client\nA lightweight JavaScript client for Maana-Q Assistant developers that wraps post-message communication between an embedded Maana-Q assistant and the Maana-Q UI.\n\n## Abstract\nThe Q-Assistant-Client is intented to be used in a web application being leveraged as a Maana Q assistant (embedded as an iframe).\nThis assistant client will facilitate communication between the assistant and the parent frame.\nThe client provides a rich, asynchronous experience over what would otherwise be 'fire-and-forget'-style messaging \nvia post-post message communication. \n\n## Requirements and Assumptions\n\n### Post-Robot Library\nThe Maana Knowledge Portal (KPortal) uses the kraken/post-robot library [kraken/post-robot](https://github.com/krakenjs/post-robot) to enrich the communication with the assistant. Post-robot allows for asynchronous, promise-based request/response style behavior between the assistant and the assistant API.\n\nThe API requires that the client use the post-robot library. This assistant-client library is the easiest way to achieve this, and also adds a fair amount of 'sugar' to the process to improve developer productivity. Developers could, however, use post-robot directly in their own client implementation. \n\n### Maana-Gateway Proxy Requirements\nThe Maana-Gateway service requires relative paths (paths relative to the root) in the assistant web application in order to proxy the application and its content. For create-react-apps, for instance, this means setting \"homepage\" to \".\" in the package.json file.\n\n## Singleton Instance\nThe client is exported as a singleton to avoid duplicate registration on event listeners.\nYou can import the instance like this:\n\n```js\nimport AssistantAPIClient from '@io-maana/q-assistant-client';\n```\n\nFunction calls can be made against the client instance like any other javascript object. They are all async.\n\n```js\nconst workspace = await AssistantAPIClient.getWorkspace(); \nconsole.log(\"Workspace:\", workspace)\n```\n\n## Dependencies\nPost-Robot\nhttps://github.com/krakenjs/post-robot\n\nPost-robot is used to provide a richer communication layer atop post-message.\n\n## Examples\n@TODO Logan\n\n## API Documentation\n\n### State management\n\n#### clearState = () =>\n\nThis will clear all ‘attached’ state between the assistant and the API. \n\nSpecifically, this will clear selection and inventory changed event listeners. \n\n```js\nawait AssistantAPIClient.clearState()\n```\n\n### User Info\nThe `UserInfo` object:\n```js\n{\n email: string,\n name: string\n}\n```\n\n#### getUserInfo = () => \n\nReturns a Userinfo object pertaining to the logged in user.\n\n```js\nconst userInfo = await AssistantAPIClient.getUserInfo()\n```\n### Selection\nThe `Selection` object:\n```js\n{\n  kindId: string\n  kindName: string\n  id: string\n}\n```\n\n#### getCurrentSelection = () => \n\nReturns an Array of `Selection` objects:\n\n```js\nconst {selection} = await AssistantAPIClient.getCurrentSelection();\n```\n\n#### addSelectionChangedListener = async cb =>\n\nAdds a callback function to be executed upon a valid workspace selection change.\n\nCallback value is an array of Selection objects:\n\n```js\n// Create the selection callback.\nconst selectionCB = ({selection})=>{\n  console.log('Workspace selection has changed.')\n  selection.forEach(i=>{\n    console.log('Kind: ',i.kindName)\n    console.log('Instance Id:',i.id)\n    console.log('Kind Id:',i.kindId)\n  })\n}\n\n// Add the listener.\nAssistantAPIClient.addSelectionChangedListener(selectionCB);\n```\n\nThis function only exists on the Q-Assistant-Client--only enableSelectionChangedNotification is called on the API. \n\n#### removeSelectionChangedListener = async cb =>\n\nThis will have to be called on a 1:1 basis with addSelectionChangedListener calls if supplying a callback.\n\n```js\nAssistantAPIClient.removeSelectionChangedListener(selectionCB)\n```\n\n**If NOT supplying a callback to this call, all selection changed listeners will be removed.\n\n```js\nAssistantAPIClient.removeSelectionChangedListener()\n```\n\nThis function only exists on the Q-Assistant-Client--only disableSelectionChangedNotification is called on the API. \n\n\n### Services\nThe `Service` object:\n```js\n{\n   id: string,\n   name: string\n   endpointUrl: string,\n   getKinds: () => // Returns [] of Kinds objects\n   getFunctions: () => // Returns [] of Function objects\n}\n```\n\n#### getServiceById = id =>\nThis will return a service that exists within the scope of the workspace. \n** Assistant services will return null. Services outside the scope of the workspace will cause an error to be returned as 'Unable to load a Service from outside of the workspace.'\n\n```js\nconst svc = await AssistantAPIClient.getServiceById(id)\n```\n\n### Workspace\nThe `Workspace` object:\n```js\n{\nid: string,\nname: string,\ngetKinds: () => {\n  // Returns an array of functions in the workspace (includes boilerplate).\n},\ngetFunctions: () =>\n  // Returns an array of functions in the workspace (includes boilerplate).\ngetActiveGraph: () => {\n  // Returns the active Graph object.\n  // Returns null if active graph is not of type 'Knowledge Graph', or if an\n  // active graph is deleted, thereby setting active graph to null.\n},\ngetKnowledgeGraphs: () => {\n  // Returns [Graph]\n},\ngetImportedServices: () => {\n  // Returns an service imported into the workspace\n  // as a array of Service object (this calls the function\n  // that underlies getServiceById.\n  // No assistant services will be returned.\n}\n}\n```\n\n#### getWorkspace = () =>\n\nReturns a Workspace object representing the workspace. \n\n```js\nconst ws = await AssistantAPIClient.getWorkspace()\n```\n\n### Graphs\nThe `Graph` object:\n```js\n{     \nid: string,\nname: string,\noffsetX: Number,\noffsetY: Number,\nzoom: Number,\ngetNodes: async () => {\n    // Returns [Node]\n},\n\naddNode: async (type, instance, changeSelection) => {\n    // Returns Node\n},\nremoveNode: async id => {\n    // Should return nothing or error.\n    // Currently returning [] in all cases.\n},\nupdateNodeLayout: async (nodeId, { x, y, collapsed }) => {\n},\nupdateGraphLayout: async ({ offsetX, offsetY, zoom }) => {\n}\n}\n```\n\n#### Getting a graph object:\nGraph objects are obtained through an instance of a Workspace \n\n```js\nconst ag = await ws.getActiveGraph()\n```\n\nor\n\n```js\nconst kgs = await ws.getKnowledgeGraphs()\n```\n\n#### Manipulating Graphs\n\n**Only the active graph may be manipulated.\n\nAll graph manipulations should be ‘visually’ verifiable on the graph itself, i.e., adds/removes/positioning, should all be reflected on the graph itself. \n\nThe `Node` object:\n```js\n{\nid: string\nx: number\ny: number\ncollapsed: boolean\nknowledgeGraphNode {\n  id: string\n  innerKind: Kind\n  innerFunction: Function\n}\n}\n```\n\n#### addNode(type, instance, changeSelection) =>\n\nTakes type (“Function” or “Kind”), instance (the Function or Kind object), and optionally a boolean to indicate whether the selection should be changed to this new node. \n\nReturns the newly created Node object.\n\n```js\nconst node = await ag.addNode('Kind',kind)\n```\n\n#### removeNode(id) =>\n\nTakes the id of Node to be deleted. Returns either undefined or an error. \n\n```js\nawait ag.removeNode(node.id)\n```\n\n#### getNodes() =>\nReturns an array of Node objects from the graph. \n\n```js\nconst nodes = await ag.getNodes()\n```\n\n#### updateNodeLayout: async (nodeId, { x, y, collapsed})=>\n\nUpdates a Node layout given a node ID and node coordinates (`x` and/or `y`) or a `collapsed` value. x/y values must be a number, and collapsed must be a boolean. Whatever is not specified will remain current.\n\n```js\nag.updateNodeLayout(id,{x:100,y:100,collapsed:true})\n```\n\n#### updateGraphLayout: async ({ offsetX, offsetY, zoom})=>\n\nUpdates a Graph layout given numerical values for x/y offsets and the zoom. \n\n```js\nag.updateGraphLayout({offsetX:50, offsetY:50, zoom: 70})\n```\n\n### Functions\n\nThe `Function` object:\n```js\n{\n    id: string\n    name: string\n    service {\n      id: string\n      name: string\n    }\n    arguments {\n      id: string\n      name: string\n      type: string\n      modifiers: Array[string]\n      typeKindId:: string\n      kind {\n        id: string\n        name: string\n      }\n    }\n    implementation {\n      id: string\n      entrypoint {\n        id: string\n      }\n      operations {\n        id: string\n        type: string\n        function {\n          id: string\n          name: string\n        }\n        argumentValues {\n          id: string\n          argument {\n            id: string\n          }\n          operation {\n            id: string\n          }\n          argumentRef: string\n        }\n      }\n    }\n    isGenerated: boolean\n    functionType: string\n    graphqlOperationType: string\n    outputType: string\n    outputKindId: string\n    outputModifiers: Array[string]\n    kind {\n      id: string\n      name: string\n    }\n}\n```\n\n`FunctionExecutionResult` object:\n```js\n{\n  id: string,\n  result: JSON\n}\n```\n\n#### executeFunction = ( {id, variables, resolve} ) =>\n\nExecutes a function based on its id, with optional inputs for variables and a resolve string (this specifies the fields to be returned, which must be valid based on the result).\n\nReturns : JSON matching shape of result , unless no sub-selection of fields is required in the execution.\n\nThis following piece of code will execute a Function given a function ID, and pass in variables for ‘example’, requesting back id and name fields. \n\n```js \nconst res = await AssistantAPIClient.executeFunction({functionId: func.id, variables: {\"variableName\": \"variableValue\"}, resolve: \"{ id name }\");\n```\n\n#### createFunction = input =>\n\nCreates a function based on the input provided. \n\nReturns: the created Function object.\n\n**Using create function will only place the function in the workspace’s inventory--it will not place the function as a node on the Graph. In order to do this, you must pass the created function into the addNode function on the active Graph, making sure to specify ‘Function' as the type.\n\n```js\nconst createFunctionInput = {\n  name:\"yourName\",\n  arguments:[],\n  outputType: \"STRING\",\n  graphqlOperationType:\"QUERY\",\n  functionType: \"CKG\"\n}\n  \nconst createdFunction = await AssistantAPIClient.createFunction(createFunctionInput)\n```\n\n#### updateFunction = input =>\n\nInput is the same for creating a function. It’s important to note that the arguments property will be replaced in it’s entirety with whatever is provided (if a value is provided.\n\nReturns the updated `Function` object.\n\n```js\nconst updatedFunction = await AssistantAPIClient.updateFunction(input);\n```\n\n#### deleteFunction = input =>\n\nInput is the id of the Function to be deleted. Returns the deleted function as a promise.\n\n```js\nconst deletedFunction = await AssistantAPIClient.deleteFunction('id...');\n```\n\n#### getFunctionById = id =>\n\nReturns a Function as a promise based on the ID provided.\n\n```js\nconst func = await AssistantAPIClient.getFunctionById('id...');\n```\n\n#### addFunctionExecutionListener = async (id, cb) =>\n\nAssociates a callback function with the execution of a particular Function. When the Function matching the id parameter is executed, its FunctionExecutionResult object passed to the callback. Returns undefined.\n\nExample function execution callback and listener registration:\n\n```js\nfunction exampleFunctionCB (result){\n  console.log(`Function executed with result:`, result)\n}\n\nAssistantAPIClient.addFunctionExecutionListener('id...', exampleFunctionCB)\n```\n\n#### removeFunctionExecutionListener = async (id, cb) =>\n\nRemoves a Function execution listener based on the function ID and a reference to the callback function. If no callback is supplied, all listeners associated with the Function ID will be removed. Returns undefined.\n\n```js\nAssistantAPIClient.removeFunctionExecutionListener('id..', exampleFunctionCB)\n```\n\n### Kinds\nThe `Kind` object:\n```js\n{\n    id: string\n    name: string\n    service: {\n      id\n      name\n    }\n    isGenerated: boolean\n    schema {\n      id: string\n      name: string\n      type: string\n      typeKindId: string\n      modifiers: Array[string]\n      kind {\n        id: string\n        name: string\n      }\n    }\n}\n```\n\n#### createKind = input =>\n\nCreates a Kind based on an input object. Returns a promise that resolves to the created Kind object.\n\n```js\nconst kindInput = {\n name: \"someKind\",\n schema:[\n  { name: \"someField1\", type: STRING },\n  { name: \"someField2\", type: STRING }\n ]\n}\n\nconst newKind = await AssistantAPIClient.createKind(kindInput)\n```\n\n#### updateKind = input =>\n\nUpdates a Kind based on an input object. \n\nUpdate Semantics: Only properties specified will be updated. If updating the schema, the entire schema must be specified as it will be replaced in its entirety. \n\nReturns the updated `Kind` object.\n\n```js\nconst updated = await AssistantAPIClient.updateKind(input)\n```\n\n#### deleteKind = input =>\n\nDeletes a Kind given a kind ID.\n\n```js\nconst deleted = await AssistantAPIClient.deleteKind(input)\n```\n\n#### getKindById = id =>\n\nReturns a promise that resolves to a Kind object given the specified kind ID. Only kinds in the workspace or those of imported services will be returned. \n\n```js\nconst kind = await AssistantAPIClient.getKindById(id)\n```\n\n### Inventory\n\nThe `InventoryChanged` object:\n```js\n{\n  kinds: {\n    adds: [DiffItem]\n    deletes: [DiffItem]\n    updates: [DiffItem]\n  }\n  functions:{\n    adds: [DiffItem]\n    deletes: [DiffItem]\n    updates: [DiffItem]\n  }\n  services: {\n    adds: [DiffItem]\n    deletes: [DiffItem]\n    updates: [DiffItem]\n  }\n}\n```\n\nThe `DiffItem` object:\n```js\n{\n  id: string,\n  name: string\n}\n```\n\n#### addInventoryChangedListener = async cb =>\n\nRegisters a callback function with the inventory changed event. When workspace inventory changes the callback function will be called with the InventoryChangedobject. Returns undefined.\n\n*Current limitations: Kind and Function updates only occur where the name property is changed. Updates to services outside of the workspace will not be detected. \n\n**Use-case note: an ‘update’ diff for inventory services is unlikely in general usage. \n\n```js\nconst inventoryCB = ({diff}) => {\n  if(diff.kinds) console.log('KINDS CHANGED',diff.kinds)\n  if(diff.functions) console.log('FUNCTIONS CHANGED', diff.functions)\n  if(diff.services) console.log('SERVICES CHANGED',diff.services)\n}\n\nAssistantAPIClient.addInventoryChangedListener(inventoryCB)\n```\n\nThis function exists on the Q-Assisant-Client only--only enableSelectionChangedNotification is used on the API side. \n\n#### removeInventoryChangedListener = async cb =>\n\nRemoves an inventory changed listener given the referenced callback. If no callback is specified, all listeners will be removed. Returns undefined.\n\n```js\nAssistantAPIClient.removeInventoryChangedListener(inventoryCB)\n```\n\nThis function exists on the Q-Assisant-Client only--only disableSelectionChangedNotification is used on the API side. \n\n## Troubleshooting Assistant Issues\n### Assistant root file has loaded, but not other content\nObserving in the browser's dev tools that some resources have loaded correctly (usually the root), but other's haven't (usually nested files or chunks), is indicative of a failure of Q Gateway to proxy due to not having a 'relative' path structure.\n\n### You are seeing post-robot `NO ACK` errors in the console.\nThese errors stem from a failed acknowledgement for a call either between the client and the API or vice-versa. Here, this means that the web app 'window' (the assistant) cannot communicate with, or access, the 'window.parent' (Maana K-Portal) object. Improper CORS configuration is a common culprit (also verify if using docker or nginx that your proxying and networking is configured correctly to allow communication and to accout for CORS).","readmeFilename":"README.md","gitHead":"dba1e2b550bff6d9eabc3a6e588d1600971d8eb5","_id":"@io-maana/q-assistant-client@3.2.2-beta.22","_npmVersion":"6.4.1","_nodeVersion":"10.15.3","_npmUser":{"name":"teamcitymaana","email":"teamcity@maana.io"},"dist":{"integrity":"sha512-3SDgCjJgwbTZcTrVM2x+QfFOR1cLItOapdOZKBM7Q67/lya1bnbgXQzBZjKSYyqRWlM/9kT6RqUaLmEZHIukSA==","shasum":"9e038d160a07a3d5f07004e96d2350786f41fb5a","tarball":"https://registry.npmjs.org/@io-maana/q-assistant-client/-/q-assistant-client-3.2.2-beta.22.tgz","fileCount":6,"unpackedSize":33623,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJeRIwPCRA9TVsSAnZWagAANhEQAI33Cy9Vq5Hk9JFQGuo6\nDyRPUfowFV0gF5L0jXd6GEc+0CogvDKuqW2F4eApZeOQHzC8xfCEFp27yd9Z\nxbGHj8HdGejwjaLWzYQq+ZBfqBxTxeK4w4HiOW/q9TPkuh0ou8KZTgc+sCE2\nA++QiXlgbMcmy6pD18/V5MBaMhXCKvbjk16wWHbBPXfiCRtIIeyBIapqVW3L\n1DnDmkCby1l7UxW+T2DQ1KUXue0njJu95676iZjehKpAFyzqFGt5qxglXZZn\nqNQPJ59mcHkK8L8oJ9xKH7QINS5gS/Jtx5ApDCHC0XAmXJYExJJJUMvLbr8D\nkLc9o0wFchqusObNdM3w5vVrmaFb+zo41/g9Woqq8qhXW5We1PKefrkq5Pfl\nd3pnqJJxzsx1qcz0qjcxy39BHbFO9Al5BcBvaVnZmnd21KHph23cvhnzj42T\nmweTNOggeQsULCAXibZ6ThmMVJlKm8q+L3C5E+rv+/hnKOrVc7EpUSr7zzIh\nBPjBncJJ9CwqyyhaZJsgd3jnF74fQzdzEPpBdh6410WGSYSsRHrUtaY7kGU+\nULTPMfGeu+SC7wv5dNH/5Mhgi6db++jvjNOJUIDRTqbLH8VhFqAfouGVJnpf\nMWbtxQEwikgnkrI3+NC6QfKCZJZIr3t/Jz8Nm7zDfoyUan915ubziqAV9vtv\n+qYu\r\n=sE/d\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEYCIQDjq33wWGYl1VdUx37llkNqo7ilfa/k4ppTve/YjPcqNgIhAL6L7BrG0pdltmDy+dy2NG8JykXOPCMpekMszc0yYRyC"}]},"maintainers":[{"name":"abatyuk","email":"andrey@maana.io"},{"name":"bzvetey","email":"bzvestey@gmail.com"},{"name":"rpovey","email":"rob@maana.io"},{"name":"teamcitymaana","email":"teamcity@maana.io"},{"name":"witt3rd","email":"witt3rd@witt3rd.com"}],"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/q-assistant-client_3.2.2-beta.22_1581550606622_0.03457949130253346"},"_hasShrinkwrap":false},"3.2.2-beta.23":{"name":"@io-maana/q-assistant-client","version":"3.2.2-beta.23","description":"JavaScript package to streamline communication between an assistant and the Maana Q Assistant API.","main":"build/AssistantAPIClient.js","scripts":{"build":"babel src --out-dir build","prepack":"npm run build","test":"echo \"Error: no test specified\" && exit 1","format":"prettier --write \"src/**/*.js\""},"repository":{"type":"git","url":"git+https://github.com/maana-io/q-assistant-client.git"},"keywords":["Maana","Q"],"author":{"name":"Logan Gore @ Maana.io"},"license":"MIT","bugs":{"url":"https://github.com/maana-io/q-assistant-client/issues"},"homepage":"https://github.com/maana-io/q-assistant-client#readme","dependencies":{"post-robot":"10.0.29"},"devDependencies":{"@babel/cli":"^7.5.5","@babel/core":"^7.5.5","@babel/plugin-proposal-class-properties":"^7.5.5","@babel/preset-env":"^7.5.5","prettier":"1.19.1"},"readme":"# q-assistant-client\nA lightweight JavaScript client for Maana-Q Assistant developers that wraps post-message communication between an embedded Maana-Q assistant and the Maana-Q UI.\n\n## Abstract\nThe Q-Assistant-Client is intented to be used in a web application being leveraged as a Maana Q assistant (embedded as an iframe).\nThis assistant client will facilitate communication between the assistant and the parent frame.\nThe client provides a rich, asynchronous experience over what would otherwise be 'fire-and-forget'-style messaging \nvia post-post message communication. \n\n## Requirements and Assumptions\n\n### Post-Robot Library\nThe Maana Knowledge Portal (KPortal) uses the kraken/post-robot library [kraken/post-robot](https://github.com/krakenjs/post-robot) to enrich the communication with the assistant. Post-robot allows for asynchronous, promise-based request/response style behavior between the assistant and the assistant API.\n\nThe API requires that the client use the post-robot library. This assistant-client library is the easiest way to achieve this, and also adds a fair amount of 'sugar' to the process to improve developer productivity. Developers could, however, use post-robot directly in their own client implementation. \n\n### Maana-Gateway Proxy Requirements\nThe Maana-Gateway service requires relative paths (paths relative to the root) in the assistant web application in order to proxy the application and its content. For create-react-apps, for instance, this means setting \"homepage\" to \".\" in the package.json file.\n\n## Singleton Instance\nThe client is exported as a singleton to avoid duplicate registration on event listeners.\nYou can import the instance like this:\n\n```js\nimport AssistantAPIClient from '@io-maana/q-assistant-client';\n```\n\nFunction calls can be made against the client instance like any other javascript object. They are all async.\n\n```js\nconst workspace = await AssistantAPIClient.getWorkspace(); \nconsole.log(\"Workspace:\", workspace)\n```\n\n## Dependencies\nPost-Robot\nhttps://github.com/krakenjs/post-robot\n\nPost-robot is used to provide a richer communication layer atop post-message.\n\n## Examples\n@TODO Logan\n\n## API Documentation\n\n### State management\n\n#### clearState = () =>\n\nThis will clear all ‘attached’ state between the assistant and the API. \n\nSpecifically, this will clear selection and inventory changed event listeners. \n\n```js\nawait AssistantAPIClient.clearState()\n```\n\n### User Info\nThe `UserInfo` object:\n```js\n{\n email: string,\n name: string\n}\n```\n\n#### getUserInfo = () => \n\nReturns a Userinfo object pertaining to the logged in user.\n\n```js\nconst userInfo = await AssistantAPIClient.getUserInfo()\n```\n### Selection\nThe `Selection` object:\n```js\n{\n  kindId: string\n  kindName: string\n  id: string\n}\n```\n\n#### getCurrentSelection = () => \n\nReturns an Array of `Selection` objects:\n\n```js\nconst {selection} = await AssistantAPIClient.getCurrentSelection();\n```\n\n#### addSelectionChangedListener = async cb =>\n\nAdds a callback function to be executed upon a valid workspace selection change.\n\nCallback value is an array of Selection objects:\n\n```js\n// Create the selection callback.\nconst selectionCB = ({selection})=>{\n  console.log('Workspace selection has changed.')\n  selection.forEach(i=>{\n    console.log('Kind: ',i.kindName)\n    console.log('Instance Id:',i.id)\n    console.log('Kind Id:',i.kindId)\n  })\n}\n\n// Add the listener.\nAssistantAPIClient.addSelectionChangedListener(selectionCB);\n```\n\nThis function only exists on the Q-Assistant-Client--only enableSelectionChangedNotification is called on the API. \n\n#### removeSelectionChangedListener = async cb =>\n\nThis will have to be called on a 1:1 basis with addSelectionChangedListener calls if supplying a callback.\n\n```js\nAssistantAPIClient.removeSelectionChangedListener(selectionCB)\n```\n\n**If NOT supplying a callback to this call, all selection changed listeners will be removed.\n\n```js\nAssistantAPIClient.removeSelectionChangedListener()\n```\n\nThis function only exists on the Q-Assistant-Client--only disableSelectionChangedNotification is called on the API. \n\n\n### Services\nThe `Service` object:\n```js\n{\n   id: string,\n   name: string\n   endpointUrl: string,\n   getKinds: () => // Returns [] of Kinds objects\n   getFunctions: () => // Returns [] of Function objects\n}\n```\n\n#### getServiceById = id =>\nThis will return a service that exists within the scope of the workspace. \n** Assistant services will return null. Services outside the scope of the workspace will cause an error to be returned as 'Unable to load a Service from outside of the workspace.'\n\n```js\nconst svc = await AssistantAPIClient.getServiceById(id)\n```\n\n### Workspace\nThe `Workspace` object:\n```js\n{\nid: string,\nname: string,\ngetKinds: () => {\n  // Returns an array of functions in the workspace (includes boilerplate).\n},\ngetFunctions: () =>\n  // Returns an array of functions in the workspace (includes boilerplate).\ngetActiveGraph: () => {\n  // Returns the active Graph object.\n  // Returns null if active graph is not of type 'Knowledge Graph', or if an\n  // active graph is deleted, thereby setting active graph to null.\n},\ngetKnowledgeGraphs: () => {\n  // Returns [Graph]\n},\ngetImportedServices: () => {\n  // Returns an service imported into the workspace\n  // as a array of Service object (this calls the function\n  // that underlies getServiceById.\n  // No assistant services will be returned.\n}\n}\n```\n\n#### getWorkspace = () =>\n\nReturns a Workspace object representing the workspace. \n\n```js\nconst ws = await AssistantAPIClient.getWorkspace()\n```\n\n### Graphs\nThe `Graph` object:\n```js\n{     \nid: string,\nname: string,\noffsetX: Number,\noffsetY: Number,\nzoom: Number,\ngetNodes: async () => {\n    // Returns [Node]\n},\n\naddNode: async (type, instance, changeSelection) => {\n    // Returns Node\n},\nremoveNode: async id => {\n    // Should return nothing or error.\n    // Currently returning [] in all cases.\n},\nupdateNodeLayout: async (nodeId, { x, y, collapsed }) => {\n},\nupdateGraphLayout: async ({ offsetX, offsetY, zoom }) => {\n}\n}\n```\n\n#### Getting a graph object:\nGraph objects are obtained through an instance of a Workspace \n\n```js\nconst ag = await ws.getActiveGraph()\n```\n\nor\n\n```js\nconst kgs = await ws.getKnowledgeGraphs()\n```\n\n#### Manipulating Graphs\n\n**Only the active graph may be manipulated.\n\nAll graph manipulations should be ‘visually’ verifiable on the graph itself, i.e., adds/removes/positioning, should all be reflected on the graph itself. \n\nThe `Node` object:\n```js\n{\nid: string\nx: number\ny: number\ncollapsed: boolean\nknowledgeGraphNode {\n  id: string\n  innerKind: Kind\n  innerFunction: Function\n}\n}\n```\n\n#### addNode(type, instance, changeSelection) =>\n\nTakes type (“Function” or “Kind”), instance (the Function or Kind object), and optionally a boolean to indicate whether the selection should be changed to this new node. \n\nReturns the newly created Node object.\n\n```js\nconst node = await ag.addNode('Kind',kind)\n```\n\n#### removeNode(id) =>\n\nTakes the id of Node to be deleted. Returns either undefined or an error. \n\n```js\nawait ag.removeNode(node.id)\n```\n\n#### getNodes() =>\nReturns an array of Node objects from the graph. \n\n```js\nconst nodes = await ag.getNodes()\n```\n\n#### updateNodeLayout: async (nodeId, { x, y, collapsed})=>\n\nUpdates a Node layout given a node ID and node coordinates (`x` and/or `y`) or a `collapsed` value. x/y values must be a number, and collapsed must be a boolean. Whatever is not specified will remain current.\n\n```js\nag.updateNodeLayout(id,{x:100,y:100,collapsed:true})\n```\n\n#### updateGraphLayout: async ({ offsetX, offsetY, zoom})=>\n\nUpdates a Graph layout given numerical values for x/y offsets and the zoom. \n\n```js\nag.updateGraphLayout({offsetX:50, offsetY:50, zoom: 70})\n```\n\n### Functions\n\nThe `Function` object:\n```js\n{\n    id: string\n    name: string\n    service {\n      id: string\n      name: string\n    }\n    arguments {\n      id: string\n      name: string\n      type: string\n      modifiers: Array[string]\n      typeKindId:: string\n      kind {\n        id: string\n        name: string\n      }\n    }\n    implementation {\n      id: string\n      entrypoint {\n        id: string\n      }\n      operations {\n        id: string\n        type: string\n        function {\n          id: string\n          name: string\n        }\n        argumentValues {\n          id: string\n          argument {\n            id: string\n          }\n          operation {\n            id: string\n          }\n          argumentRef: string\n        }\n      }\n    }\n    isGenerated: boolean\n    functionType: string\n    graphqlOperationType: string\n    outputType: string\n    outputKindId: string\n    outputModifiers: Array[string]\n    kind {\n      id: string\n      name: string\n    }\n}\n```\n\n`FunctionExecutionResult` object:\n```js\n{\n  id: string,\n  result: JSON\n}\n```\n\n#### executeFunction = ( {id, variables, resolve} ) =>\n\nExecutes a function based on its id, with optional inputs for variables and a resolve string (this specifies the fields to be returned, which must be valid based on the result).\n\nReturns : JSON matching shape of result , unless no sub-selection of fields is required in the execution.\n\nThis following piece of code will execute a Function given a function ID, and pass in variables for ‘example’, requesting back id and name fields. \n\n```js \nconst res = await AssistantAPIClient.executeFunction({functionId: func.id, variables: {\"variableName\": \"variableValue\"}, resolve: \"{ id name }\");\n```\n\n#### createFunction = input =>\n\nCreates a function based on the input provided. \n\nReturns: the created Function object.\n\n**Using create function will only place the function in the workspace’s inventory--it will not place the function as a node on the Graph. In order to do this, you must pass the created function into the addNode function on the active Graph, making sure to specify ‘Function' as the type.\n\n```js\nconst createFunctionInput = {\n  name:\"yourName\",\n  arguments:[],\n  outputType: \"STRING\",\n  graphqlOperationType:\"QUERY\",\n  functionType: \"CKG\"\n}\n  \nconst createdFunction = await AssistantAPIClient.createFunction(createFunctionInput)\n```\n\n#### updateFunction = input =>\n\nInput is the same for creating a function. It’s important to note that the arguments property will be replaced in it’s entirety with whatever is provided (if a value is provided.\n\nReturns the updated `Function` object.\n\n```js\nconst updatedFunction = await AssistantAPIClient.updateFunction(input);\n```\n\n#### deleteFunction = input =>\n\nInput is the id of the Function to be deleted. Returns the deleted function as a promise.\n\n```js\nconst deletedFunction = await AssistantAPIClient.deleteFunction('id...');\n```\n\n#### getFunctionById = id =>\n\nReturns a Function as a promise based on the ID provided.\n\n```js\nconst func = await AssistantAPIClient.getFunctionById('id...');\n```\n\n#### addFunctionExecutionListener = async (id, cb) =>\n\nAssociates a callback function with the execution of a particular Function. When the Function matching the id parameter is executed, its FunctionExecutionResult object passed to the callback. Returns undefined.\n\nExample function execution callback and listener registration:\n\n```js\nfunction exampleFunctionCB (result){\n  console.log(`Function executed with result:`, result)\n}\n\nAssistantAPIClient.addFunctionExecutionListener('id...', exampleFunctionCB)\n```\n\n#### removeFunctionExecutionListener = async (id, cb) =>\n\nRemoves a Function execution listener based on the function ID and a reference to the callback function. If no callback is supplied, all listeners associated with the Function ID will be removed. Returns undefined.\n\n```js\nAssistantAPIClient.removeFunctionExecutionListener('id..', exampleFunctionCB)\n```\n\n### Kinds\nThe `Kind` object:\n```js\n{\n    id: string\n    name: string\n    service: {\n      id\n      name\n    }\n    isGenerated: boolean\n    schema {\n      id: string\n      name: string\n      type: string\n      typeKindId: string\n      modifiers: Array[string]\n      kind {\n        id: string\n        name: string\n      }\n    }\n}\n```\n\n#### createKind = input =>\n\nCreates a Kind based on an input object. Returns a promise that resolves to the created Kind object.\n\n```js\nconst kindInput = {\n name: \"someKind\",\n schema:[\n  { name: \"someField1\", type: STRING },\n  { name: \"someField2\", type: STRING }\n ]\n}\n\nconst newKind = await AssistantAPIClient.createKind(kindInput)\n```\n\n#### updateKind = input =>\n\nUpdates a Kind based on an input object. \n\nUpdate Semantics: Only properties specified will be updated. If updating the schema, the entire schema must be specified as it will be replaced in its entirety. \n\nReturns the updated `Kind` object.\n\n```js\nconst updated = await AssistantAPIClient.updateKind(input)\n```\n\n#### deleteKind = input =>\n\nDeletes a Kind given a kind ID.\n\n```js\nconst deleted = await AssistantAPIClient.deleteKind(input)\n```\n\n#### getKindById = id =>\n\nReturns a promise that resolves to a Kind object given the specified kind ID. Only kinds in the workspace or those of imported services will be returned. \n\n```js\nconst kind = await AssistantAPIClient.getKindById(id)\n```\n\n### Inventory\n\nThe `InventoryChanged` object:\n```js\n{\n  kinds: {\n    adds: [DiffItem]\n    deletes: [DiffItem]\n    updates: [DiffItem]\n  }\n  functions:{\n    adds: [DiffItem]\n    deletes: [DiffItem]\n    updates: [DiffItem]\n  }\n  services: {\n    adds: [DiffItem]\n    deletes: [DiffItem]\n    updates: [DiffItem]\n  }\n}\n```\n\nThe `DiffItem` object:\n```js\n{\n  id: string,\n  name: string\n}\n```\n\n#### addInventoryChangedListener = async cb =>\n\nRegisters a callback function with the inventory changed event. When workspace inventory changes the callback function will be called with the InventoryChangedobject. Returns undefined.\n\n*Current limitations: Kind and Function updates only occur where the name property is changed. Updates to services outside of the workspace will not be detected. \n\n**Use-case note: an ‘update’ diff for inventory services is unlikely in general usage. \n\n```js\nconst inventoryCB = ({diff}) => {\n  if(diff.kinds) console.log('KINDS CHANGED',diff.kinds)\n  if(diff.functions) console.log('FUNCTIONS CHANGED', diff.functions)\n  if(diff.services) console.log('SERVICES CHANGED',diff.services)\n}\n\nAssistantAPIClient.addInventoryChangedListener(inventoryCB)\n```\n\nThis function exists on the Q-Assisant-Client only--only enableSelectionChangedNotification is used on the API side. \n\n#### removeInventoryChangedListener = async cb =>\n\nRemoves an inventory changed listener given the referenced callback. If no callback is specified, all listeners will be removed. Returns undefined.\n\n```js\nAssistantAPIClient.removeInventoryChangedListener(inventoryCB)\n```\n\nThis function exists on the Q-Assisant-Client only--only disableSelectionChangedNotification is used on the API side. \n\n## Troubleshooting Assistant Issues\n### Assistant root file has loaded, but not other content\nObserving in the browser's dev tools that some resources have loaded correctly (usually the root), but other's haven't (usually nested files or chunks), is indicative of a failure of Q Gateway to proxy due to not having a 'relative' path structure.\n\n### You are seeing post-robot `NO ACK` errors in the console.\nThese errors stem from a failed acknowledgement for a call either between the client and the API or vice-versa. Here, this means that the web app 'window' (the assistant) cannot communicate with, or access, the 'window.parent' (Maana K-Portal) object. Improper CORS configuration is a common culprit (also verify if using docker or nginx that your proxying and networking is configured correctly to allow communication and to accout for CORS).","readmeFilename":"README.md","gitHead":"b20fe672c1d8e2165dc93bb39bf4a62c1b131a41","_id":"@io-maana/q-assistant-client@3.2.2-beta.23","_npmVersion":"6.4.1","_nodeVersion":"10.15.3","_npmUser":{"name":"teamcitymaana","email":"teamcity@maana.io"},"dist":{"integrity":"sha512-NI3dUZ/1GqcXGdqJDNAslUq81QqqW+hxA7+qfi8WBU1h17eQPl2MCSe1yln+3AJX2wK2qwTh4yCQ8/YRtndgog==","shasum":"78e1d9674daa94a2a4b0c38341dc26a0dae49266","tarball":"https://registry.npmjs.org/@io-maana/q-assistant-client/-/q-assistant-client-3.2.2-beta.23.tgz","fileCount":6,"unpackedSize":33645,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJeVw7GCRA9TVsSAnZWagAAdu0P/08akROa91obicuNIitH\nq2ICCp5wEbrsiC4Nmr3Xit5r/uqvBZZkWJVuf0hJ8QIhWyAlJNKggxdxjr1b\nOZ9m/i8GoQMO2fhiU6qxUTG0l4ss4uEU8y9oGcHQwBk6rEuEJNuRKD29zIMJ\nB0Vi5WX+kRTXWaWNExpB0GtU+2mhqdgzjkneWFYWvSqc5eezB9E7mCBasrYE\ngdPXrLmLJOMvKr1QYEJgdR5bT81YHWO5AIize75LAqIhNW9Do5D2hIU4taY/\nfMXcwlWdhg7hp1mK1kF5+dg+5Ymrxh+K59WWk/u8d63DseaHKHPzWWz4qktC\nmjtMGopmvUUSGxzZk/mq1Z/2E3qQYVo7SPw8UMSWdWTD8KD7qYtjLxH8/zHb\nXokjf7JR5N+ZIWFL/hnRi3gJEwtdK1Z3P47t2lB7kUt+Po0bEwX0IxvwT+QH\nqfzoW/14b21IhyO5MGmVM96bQ3OmUqwH7+dZYKDkgWR49kCOmtoK7JHt696e\n7MHqEdYQaq5DMWdPJ6hMUUjHXAZdT21soojyxmmOtx9peyaxm3L91Nayexkb\nbZnsiLxjp/GqpKnzJlHLLdR9sTGzELFPEwY47zKxGxa4hjOrWrgyo+AKRWsy\nV+w9Xswu9Os0U7LF34e6gD6lOvTVJKaUYCMBci3oz5HpfcmrjHwBdMv2faqu\nnftk\r\n=MtGm\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEYCIQDCLhzSqG92Z73/suHs3MADnG5dqRx+yDbzrMfIE0bM0QIhAJpZyaaG/R6X3ZG1EEOOmnvBagLEMSAPr7qJl2Juh8rJ"}]},"maintainers":[{"email":"andrey@maana.io","name":"abatyuk"},{"email":"bzvestey@gmail.com","name":"bzvetey"},{"email":"dlewissandy@maana.io","name":"dlsmaana"},{"email":"rob@maana.io","name":"rpovey"},{"email":"teamcity@maana.io","name":"teamcitymaana"},{"email":"witt3rd@witt3rd.com","name":"witt3rd"}],"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/q-assistant-client_3.2.2-beta.23_1582763717921_0.8467869525052465"},"_hasShrinkwrap":false},"3.2.2-beta.24":{"name":"@io-maana/q-assistant-client","version":"3.2.2-beta.24","description":"JavaScript package to streamline communication between an assistant and the Maana Q Assistant API.","main":"build/AssistantAPIClient.js","scripts":{"build":"babel src --out-dir build","prepack":"npm run build","test":"echo \"Error: no test specified\" && exit 1","format":"prettier --write \"src/**/*.js\""},"repository":{"type":"git","url":"git+https://github.com/maana-io/q-assistant-client.git"},"keywords":["Maana","Q"],"author":{"name":"Logan Gore @ Maana.io"},"license":"MIT","bugs":{"url":"https://github.com/maana-io/q-assistant-client/issues"},"homepage":"https://github.com/maana-io/q-assistant-client#readme","dependencies":{"post-robot":"10.0.29"},"devDependencies":{"@babel/cli":"^7.5.5","@babel/core":"^7.5.5","@babel/plugin-proposal-class-properties":"^7.5.5","@babel/preset-env":"^7.5.5","prettier":"1.19.1"},"readme":"# q-assistant-client\nA lightweight JavaScript client for Maana-Q Assistant developers that wraps post-message communication between an embedded Maana-Q assistant and the Maana-Q UI.\n\n## Abstract\nThe Q-Assistant-Client is intented to be used in a web application being leveraged as a Maana Q assistant (embedded as an iframe).\nThis assistant client will facilitate communication between the assistant and the parent frame.\nThe client provides a rich, asynchronous experience over what would otherwise be 'fire-and-forget'-style messaging \nvia post-post message communication. \n\n## Requirements and Assumptions\n\n### Post-Robot Library\nThe Maana Knowledge Portal (KPortal) uses the kraken/post-robot library [kraken/post-robot](https://github.com/krakenjs/post-robot) to enrich the communication with the assistant. Post-robot allows for asynchronous, promise-based request/response style behavior between the assistant and the assistant API.\n\nThe API requires that the client use the post-robot library. This assistant-client library is the easiest way to achieve this, and also adds a fair amount of 'sugar' to the process to improve developer productivity. Developers could, however, use post-robot directly in their own client implementation. \n\n### Maana-Gateway Proxy Requirements\nThe Maana-Gateway service requires relative paths (paths relative to the root) in the assistant web application in order to proxy the application and its content. For create-react-apps, for instance, this means setting \"homepage\" to \".\" in the package.json file.\n\n## Singleton Instance\nThe client is exported as a singleton to avoid duplicate registration on event listeners.\nYou can import the instance like this:\n\n```js\nimport AssistantAPIClient from '@io-maana/q-assistant-client';\n```\n\nFunction calls can be made against the client instance like any other javascript object. They are all async.\n\n```js\nconst workspace = await AssistantAPIClient.getWorkspace(); \nconsole.log(\"Workspace:\", workspace)\n```\n\n## Dependencies\nPost-Robot\nhttps://github.com/krakenjs/post-robot\n\nPost-robot is used to provide a richer communication layer atop post-message.\n\n## Examples\n@TODO Logan\n\n## API Documentation\n\n### State management\n\n#### clearState = () =>\n\nThis will clear all ‘attached’ state between the assistant and the API. \n\nSpecifically, this will clear selection and inventory changed event listeners. \n\n```js\nawait AssistantAPIClient.clearState()\n```\n\n### User Info\nThe `UserInfo` object:\n```js\n{\n email: string,\n name: string\n}\n```\n\n#### getUserInfo = () => \n\nReturns a Userinfo object pertaining to the logged in user.\n\n```js\nconst userInfo = await AssistantAPIClient.getUserInfo()\n```\n### Selection\nThe `Selection` object:\n```js\n{\n  kindId: string\n  kindName: string\n  id: string\n}\n```\n\n#### getCurrentSelection = () => \n\nReturns an Array of `Selection` objects:\n\n```js\nconst {selection} = await AssistantAPIClient.getCurrentSelection();\n```\n\n#### addSelectionChangedListener = async cb =>\n\nAdds a callback function to be executed upon a valid workspace selection change.\n\nCallback value is an array of Selection objects:\n\n```js\n// Create the selection callback.\nconst selectionCB = ({selection})=>{\n  console.log('Workspace selection has changed.')\n  selection.forEach(i=>{\n    console.log('Kind: ',i.kindName)\n    console.log('Instance Id:',i.id)\n    console.log('Kind Id:',i.kindId)\n  })\n}\n\n// Add the listener.\nAssistantAPIClient.addSelectionChangedListener(selectionCB);\n```\n\nThis function only exists on the Q-Assistant-Client--only enableSelectionChangedNotification is called on the API. \n\n#### removeSelectionChangedListener = async cb =>\n\nThis will have to be called on a 1:1 basis with addSelectionChangedListener calls if supplying a callback.\n\n```js\nAssistantAPIClient.removeSelectionChangedListener(selectionCB)\n```\n\n**If NOT supplying a callback to this call, all selection changed listeners will be removed.\n\n```js\nAssistantAPIClient.removeSelectionChangedListener()\n```\n\nThis function only exists on the Q-Assistant-Client--only disableSelectionChangedNotification is called on the API. \n\n\n### Services\nThe `Service` object:\n```js\n{\n   id: string,\n   name: string\n   endpointUrl: string,\n   getKinds: () => // Returns [] of Kinds objects\n   getFunctions: () => // Returns [] of Function objects\n}\n```\n\n#### getServiceById = id =>\nThis will return a service that exists within the scope of the workspace. \n** Assistant services will return null. Services outside the scope of the workspace will cause an error to be returned as 'Unable to load a Service from outside of the workspace.'\n\n```js\nconst svc = await AssistantAPIClient.getServiceById(id)\n```\n\n### Workspace\nThe `Workspace` object:\n```js\n{\nid: string,\nname: string,\ngetKinds: () => {\n  // Returns an array of functions in the workspace (includes boilerplate).\n},\ngetFunctions: () =>\n  // Returns an array of functions in the workspace (includes boilerplate).\ngetActiveGraph: () => {\n  // Returns the active Graph object.\n  // Returns null if active graph is not of type 'Knowledge Graph', or if an\n  // active graph is deleted, thereby setting active graph to null.\n},\ngetKnowledgeGraphs: () => {\n  // Returns [Graph]\n},\ngetImportedServices: () => {\n  // Returns an service imported into the workspace\n  // as a array of Service object (this calls the function\n  // that underlies getServiceById.\n  // No assistant services will be returned.\n}\n}\n```\n\n#### getWorkspace = () =>\n\nReturns a Workspace object representing the workspace. \n\n```js\nconst ws = await AssistantAPIClient.getWorkspace()\n```\n\n### Graphs\nThe `Graph` object:\n```js\n{     \nid: string,\nname: string,\noffsetX: Number,\noffsetY: Number,\nzoom: Number,\ngetNodes: async () => {\n    // Returns [Node]\n},\n\naddNode: async (type, instance, changeSelection) => {\n    // Returns Node\n},\nremoveNode: async id => {\n    // Should return nothing or error.\n    // Currently returning [] in all cases.\n},\nupdateNodeLayout: async (nodeId, { x, y, collapsed }) => {\n},\nupdateGraphLayout: async ({ offsetX, offsetY, zoom }) => {\n}\n}\n```\n\n#### Getting a graph object:\nGraph objects are obtained through an instance of a Workspace \n\n```js\nconst ag = await ws.getActiveGraph()\n```\n\nor\n\n```js\nconst kgs = await ws.getKnowledgeGraphs()\n```\n\n#### Manipulating Graphs\n\n**Only the active graph may be manipulated.\n\nAll graph manipulations should be ‘visually’ verifiable on the graph itself, i.e., adds/removes/positioning, should all be reflected on the graph itself. \n\nThe `Node` object:\n```js\n{\nid: string\nx: number\ny: number\ncollapsed: boolean\nknowledgeGraphNode {\n  id: string\n  innerKind: Kind\n  innerFunction: Function\n}\n}\n```\n\n#### addNode(type, instance, changeSelection) =>\n\nTakes type (“Function” or “Kind”), instance (the Function or Kind object), and optionally a boolean to indicate whether the selection should be changed to this new node. \n\nReturns the newly created Node object.\n\n```js\nconst node = await ag.addNode('Kind',kind)\n```\n\n#### removeNode(id) =>\n\nTakes the id of Node to be deleted. Returns either undefined or an error. \n\n```js\nawait ag.removeNode(node.id)\n```\n\n#### getNodes() =>\nReturns an array of Node objects from the graph. \n\n```js\nconst nodes = await ag.getNodes()\n```\n\n#### updateNodeLayout: async (nodeId, { x, y, collapsed})=>\n\nUpdates a Node layout given a node ID and node coordinates (`x` and/or `y`) or a `collapsed` value. x/y values must be a number, and collapsed must be a boolean. Whatever is not specified will remain current.\n\n```js\nag.updateNodeLayout(id,{x:100,y:100,collapsed:true})\n```\n\n#### updateGraphLayout: async ({ offsetX, offsetY, zoom})=>\n\nUpdates a Graph layout given numerical values for x/y offsets and the zoom. \n\n```js\nag.updateGraphLayout({offsetX:50, offsetY:50, zoom: 70})\n```\n\n### Functions\n\nThe `Function` object:\n```js\n{\n    id: string\n    name: string\n    service {\n      id: string\n      name: string\n    }\n    arguments {\n      id: string\n      name: string\n      type: string\n      modifiers: Array[string]\n      typeKindId:: string\n      kind {\n        id: string\n        name: string\n      }\n    }\n    implementation {\n      id: string\n      entrypoint {\n        id: string\n      }\n      operations {\n        id: string\n        type: string\n        function {\n          id: string\n          name: string\n        }\n        argumentValues {\n          id: string\n          argument {\n            id: string\n          }\n          operation {\n            id: string\n          }\n          argumentRef: string\n        }\n      }\n    }\n    isGenerated: boolean\n    functionType: string\n    graphqlOperationType: string\n    outputType: string\n    outputKindId: string\n    outputModifiers: Array[string]\n    kind {\n      id: string\n      name: string\n    }\n}\n```\n\n`FunctionExecutionResult` object:\n```js\n{\n  id: string,\n  result: JSON\n}\n```\n\n#### executeFunction = ( {id, variables, resolve} ) =>\n\nExecutes a function based on its id, with optional inputs for variables and a resolve string (this specifies the fields to be returned, which must be valid based on the result).\n\nReturns : JSON matching shape of result , unless no sub-selection of fields is required in the execution.\n\nThis following piece of code will execute a Function given a function ID, and pass in variables for ‘example’, requesting back id and name fields. \n\n```js \nconst res = await AssistantAPIClient.executeFunction({functionId: func.id, variables: {\"variableName\": \"variableValue\"}, resolve: \"{ id name }\");\n```\n\n#### createFunction = input =>\n\nCreates a function based on the input provided. \n\nReturns: the created Function object.\n\n**Using create function will only place the function in the workspace’s inventory--it will not place the function as a node on the Graph. In order to do this, you must pass the created function into the addNode function on the active Graph, making sure to specify ‘Function' as the type.\n\n```js\nconst createFunctionInput = {\n  name:\"yourName\",\n  arguments:[],\n  outputType: \"STRING\",\n  graphqlOperationType:\"QUERY\",\n  functionType: \"CKG\"\n}\n  \nconst createdFunction = await AssistantAPIClient.createFunction(createFunctionInput)\n```\n\n#### updateFunction = input =>\n\nInput is the same for creating a function. It’s important to note that the arguments property will be replaced in it’s entirety with whatever is provided (if a value is provided.\n\nReturns the updated `Function` object.\n\n```js\nconst updatedFunction = await AssistantAPIClient.updateFunction(input);\n```\n\n#### deleteFunction = input =>\n\nInput is the id of the Function to be deleted. Returns the deleted function as a promise.\n\n```js\nconst deletedFunction = await AssistantAPIClient.deleteFunction('id...');\n```\n\n#### getFunctionById = id =>\n\nReturns a Function as a promise based on the ID provided.\n\n```js\nconst func = await AssistantAPIClient.getFunctionById('id...');\n```\n\n#### addFunctionExecutionListener = async (id, cb) =>\n\nAssociates a callback function with the execution of a particular Function. When the Function matching the id parameter is executed, its FunctionExecutionResult object passed to the callback. Returns undefined.\n\nExample function execution callback and listener registration:\n\n```js\nfunction exampleFunctionCB (result){\n  console.log(`Function executed with result:`, result)\n}\n\nAssistantAPIClient.addFunctionExecutionListener('id...', exampleFunctionCB)\n```\n\n#### removeFunctionExecutionListener = async (id, cb) =>\n\nRemoves a Function execution listener based on the function ID and a reference to the callback function. If no callback is supplied, all listeners associated with the Function ID will be removed. Returns undefined.\n\n```js\nAssistantAPIClient.removeFunctionExecutionListener('id..', exampleFunctionCB)\n```\n\n### Kinds\nThe `Kind` object:\n```js\n{\n    id: string\n    name: string\n    service: {\n      id\n      name\n    }\n    isGenerated: boolean\n    schema {\n      id: string\n      name: string\n      type: string\n      typeKindId: string\n      modifiers: Array[string]\n      kind {\n        id: string\n        name: string\n      }\n    }\n}\n```\n\n#### createKind = input =>\n\nCreates a Kind based on an input object. Returns a promise that resolves to the created Kind object.\n\n```js\nconst kindInput = {\n name: \"someKind\",\n schema:[\n  { name: \"someField1\", type: STRING },\n  { name: \"someField2\", type: STRING }\n ]\n}\n\nconst newKind = await AssistantAPIClient.createKind(kindInput)\n```\n\n#### updateKind = input =>\n\nUpdates a Kind based on an input object. \n\nUpdate Semantics: Only properties specified will be updated. If updating the schema, the entire schema must be specified as it will be replaced in its entirety. \n\nReturns the updated `Kind` object.\n\n```js\nconst updated = await AssistantAPIClient.updateKind(input)\n```\n\n#### deleteKind = input =>\n\nDeletes a Kind given a kind ID.\n\n```js\nconst deleted = await AssistantAPIClient.deleteKind(input)\n```\n\n#### getKindById = id =>\n\nReturns a promise that resolves to a Kind object given the specified kind ID. Only kinds in the workspace or those of imported services will be returned. \n\n```js\nconst kind = await AssistantAPIClient.getKindById(id)\n```\n\n### Inventory\n\nThe `InventoryChanged` object:\n```js\n{\n  kinds: {\n    adds: [DiffItem]\n    deletes: [DiffItem]\n    updates: [DiffItem]\n  }\n  functions:{\n    adds: [DiffItem]\n    deletes: [DiffItem]\n    updates: [DiffItem]\n  }\n  services: {\n    adds: [DiffItem]\n    deletes: [DiffItem]\n    updates: [DiffItem]\n  }\n}\n```\n\nThe `DiffItem` object:\n```js\n{\n  id: string,\n  name: string\n}\n```\n\n#### addInventoryChangedListener = async cb =>\n\nRegisters a callback function with the inventory changed event. When workspace inventory changes the callback function will be called with the InventoryChangedobject. Returns undefined.\n\n*Current limitations: Kind and Function updates only occur where the name property is changed. Updates to services outside of the workspace will not be detected. \n\n**Use-case note: an ‘update’ diff for inventory services is unlikely in general usage. \n\n```js\nconst inventoryCB = ({diff}) => {\n  if(diff.kinds) console.log('KINDS CHANGED',diff.kinds)\n  if(diff.functions) console.log('FUNCTIONS CHANGED', diff.functions)\n  if(diff.services) console.log('SERVICES CHANGED',diff.services)\n}\n\nAssistantAPIClient.addInventoryChangedListener(inventoryCB)\n```\n\nThis function exists on the Q-Assisant-Client only--only enableSelectionChangedNotification is used on the API side. \n\n#### removeInventoryChangedListener = async cb =>\n\nRemoves an inventory changed listener given the referenced callback. If no callback is specified, all listeners will be removed. Returns undefined.\n\n```js\nAssistantAPIClient.removeInventoryChangedListener(inventoryCB)\n```\n\nThis function exists on the Q-Assisant-Client only--only disableSelectionChangedNotification is used on the API side. \n\n## Troubleshooting Assistant Issues\n### Assistant root file has loaded, but not other content\nObserving in the browser's dev tools that some resources have loaded correctly (usually the root), but other's haven't (usually nested files or chunks), is indicative of a failure of Q Gateway to proxy due to not having a 'relative' path structure.\n\n### You are seeing post-robot `NO ACK` errors in the console.\nThese errors stem from a failed acknowledgement for a call either between the client and the API or vice-versa. Here, this means that the web app 'window' (the assistant) cannot communicate with, or access, the 'window.parent' (Maana K-Portal) object. Improper CORS configuration is a common culprit (also verify if using docker or nginx that your proxying and networking is configured correctly to allow communication and to accout for CORS).","readmeFilename":"README.md","gitHead":"d8ab6553abcd9e50ec7330759b9a4526d69e21a8","_id":"@io-maana/q-assistant-client@3.2.2-beta.24","_npmVersion":"6.4.1","_nodeVersion":"10.15.3","_npmUser":{"name":"teamcitymaana","email":"teamcity@maana.io"},"dist":{"integrity":"sha512-6ZXmutm5WW1g5ZdVuLpGvgluSPdYcplyy0mx328ddiXweM+dUSyMkJ808esclDjQnwHWjvEVxlWGwWI1Cw9LxQ==","shasum":"226059d66c19a504620987605e10aebd97d7f781","tarball":"https://registry.npmjs.org/@io-maana/q-assistant-client/-/q-assistant-client-3.2.2-beta.24.tgz","fileCount":6,"unpackedSize":33128,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJeXvWmCRA9TVsSAnZWagAA5+cP/i/mtYvug7TX6CgfmEGE\npvtde7Np7I+v/c9icHHxzh95RgqoxWRKFnMc8qrM4YjDrW2pSlM+LFg3QLYt\nG0pe/fYG5yfJRKJIs/5HNHUq7cogYMsK7yFgU8vcA+f4bCPOEDkftTkJV1L2\nOiJQxJd1Tip1IF+wUryrsD95ktto5ScTOCz4adem5kDshyn+VVYVyENckMDn\nHBOFHQj19/Ij7OL01ZRiTld58el/eknffHu4qLKu9vxQ6Gsmq7AjILHJOrjv\niKFcGe515EQXyt3SFKU7qvuOC+JjMm3xpY/ILzvl18wwD/er+wZgHYExmqwl\nQWXeYLHEp+yEKjeOBm4XdfcKBCkSnw74dYv8PlUIBxO4AjzBOnWJiU3WQb5P\nlORXXJw38LpdgifzEq6URRFDJ1PimKzqCCB8mQNXdsYGLg1Cch5+ElehFhEb\nwhrHvdrJWgY9T5gu7FP3WRi79vaQndm+p0ryCvr9uskG3L3wvCkYseNJs2O8\nZvmezt8+kVYFahnLdDjweSg0z6FwT5ZFlvQ0pejvi1WDyS0AqhIwl8xuhoLg\nVQPBogrgjQ5HXILbBbhRCNvrr3LfS3+Bu6wImtHZKHIgDUtBFYxBIXv/JwLV\no5Ov5Ntt4foROTaJKEq+VYj0EcVFHMNjk0GxIXVcQqDqlPVWWHt0pGPBVUqY\nXADg\r\n=mWJj\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEQCIEyUDJEiv1mdghYQpAWjA/Hfmqgb/Muv+xLuo+urDbf9AiAkF7NpfMb4S3IqtR9wmkO5eKtFEYVLGdv4neTVSd4IOA=="}]},"maintainers":[{"email":"andrey@maana.io","name":"abatyuk"},{"email":"bzvestey@gmail.com","name":"bzvetey"},{"email":"dlewissandy@maana.io","name":"dlsmaana"},{"email":"rob@maana.io","name":"rpovey"},{"email":"teamcity@maana.io","name":"teamcitymaana"},{"email":"witt3rd@witt3rd.com","name":"witt3rd"}],"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/q-assistant-client_3.2.2-beta.24_1583281573802_0.5323351466976862"},"_hasShrinkwrap":false},"3.2.2-beta.25":{"name":"@io-maana/q-assistant-client","version":"3.2.2-beta.25","description":"JavaScript package to streamline communication between an assistant and the Maana Q Assistant API.","main":"build/AssistantAPIClient.js","scripts":{"build":"babel src --out-dir build","prepack":"npm run build","test":"echo \"Error: no test specified\" && exit 1","format":"prettier --write \"src/**/*.js\""},"repository":{"type":"git","url":"git+https://github.com/maana-io/q-assistant-client.git"},"keywords":["Maana","Q"],"author":{"name":"Logan Gore @ Maana.io"},"license":"MIT","bugs":{"url":"https://github.com/maana-io/q-assistant-client/issues"},"homepage":"https://github.com/maana-io/q-assistant-client#readme","dependencies":{"post-robot":"10.0.29"},"devDependencies":{"@babel/cli":"^7.5.5","@babel/core":"^7.5.5","@babel/plugin-proposal-class-properties":"^7.5.5","@babel/preset-env":"^7.5.5","prettier":"1.19.1"},"readme":"# q-assistant-client\nA lightweight JavaScript client for Maana-Q Assistant developers that wraps post-message communication between an embedded Maana-Q assistant and the Maana-Q UI.\n\n## Abstract\nThe Q-Assistant-Client is intented to be used in a web application being leveraged as a Maana Q assistant (embedded as an iframe).\nThis assistant client will facilitate communication between the assistant and the parent frame.\nThe client provides a rich, asynchronous experience over what would otherwise be 'fire-and-forget'-style messaging \nvia post-post message communication. \n\n## Requirements and Assumptions\n\n### Post-Robot Library\nThe Maana Knowledge Portal (KPortal) uses the kraken/post-robot library [kraken/post-robot](https://github.com/krakenjs/post-robot) to enrich the communication with the assistant. Post-robot allows for asynchronous, promise-based request/response style behavior between the assistant and the assistant API.\n\nThe API requires that the client use the post-robot library. This assistant-client library is the easiest way to achieve this, and also adds a fair amount of 'sugar' to the process to improve developer productivity. Developers could, however, use post-robot directly in their own client implementation. \n\n### Maana-Gateway Proxy Requirements\nThe Maana-Gateway service requires relative paths (paths relative to the root) in the assistant web application in order to proxy the application and its content. For create-react-apps, for instance, this means setting \"homepage\" to \".\" in the package.json file.\n\n## Singleton Instance\nThe client is exported as a singleton to avoid duplicate registration on event listeners.\nYou can import the instance like this:\n\n```js\nimport AssistantAPIClient from '@io-maana/q-assistant-client';\n```\n\nFunction calls can be made against the client instance like any other javascript object. They are all async.\n\n```js\nconst workspace = await AssistantAPIClient.getWorkspace(); \nconsole.log(\"Workspace:\", workspace)\n```\n\n## Dependencies\nPost-Robot\nhttps://github.com/krakenjs/post-robot\n\nPost-robot is used to provide a richer communication layer atop post-message.\n\n## Examples\n@TODO Logan\n\n## API Documentation\n\n### State management\n\n#### clearState = () =>\n\nThis will clear all ‘attached’ state between the assistant and the API. \n\nSpecifically, this will clear selection and inventory changed event listeners. \n\n```js\nawait AssistantAPIClient.clearState()\n```\n\n### User Info\nThe `UserInfo` object:\n```js\n{\n email: string,\n name: string\n}\n```\n\n#### getUserInfo = () => \n\nReturns a Userinfo object pertaining to the logged in user.\n\n```js\nconst userInfo = await AssistantAPIClient.getUserInfo()\n```\n### Selection\nThe `Selection` object:\n```js\n{\n  kindId: string\n  kindName: string\n  id: string\n}\n```\n\n#### getCurrentSelection = () => \n\nReturns an Array of `Selection` objects:\n\n```js\nconst {selection} = await AssistantAPIClient.getCurrentSelection();\n```\n\n#### addSelectionChangedListener = async cb =>\n\nAdds a callback function to be executed upon a valid workspace selection change.\n\nCallback value is an array of Selection objects:\n\n```js\n// Create the selection callback.\nconst selectionCB = ({selection})=>{\n  console.log('Workspace selection has changed.')\n  selection.forEach(i=>{\n    console.log('Kind: ',i.kindName)\n    console.log('Instance Id:',i.id)\n    console.log('Kind Id:',i.kindId)\n  })\n}\n\n// Add the listener.\nAssistantAPIClient.addSelectionChangedListener(selectionCB);\n```\n\nThis function only exists on the Q-Assistant-Client--only enableSelectionChangedNotification is called on the API. \n\n#### removeSelectionChangedListener = async cb =>\n\nThis will have to be called on a 1:1 basis with addSelectionChangedListener calls if supplying a callback.\n\n```js\nAssistantAPIClient.removeSelectionChangedListener(selectionCB)\n```\n\n**If NOT supplying a callback to this call, all selection changed listeners will be removed.\n\n```js\nAssistantAPIClient.removeSelectionChangedListener()\n```\n\nThis function only exists on the Q-Assistant-Client--only disableSelectionChangedNotification is called on the API. \n\n\n### Services\nThe `Service` object:\n```js\n{\n   id: string,\n   name: string\n   endpointUrl: string,\n   getKinds: () => // Returns [] of Kinds objects\n   getFunctions: () => // Returns [] of Function objects\n}\n```\n\n#### getServiceById = id =>\nThis will return a service that exists within the scope of the workspace. \n** Assistant services will return null. Services outside the scope of the workspace will cause an error to be returned as 'Unable to load a Service from outside of the workspace.'\n\n```js\nconst svc = await AssistantAPIClient.getServiceById(id)\n```\n\n### Workspace\nThe `Workspace` object:\n```js\n{\nid: string,\nname: string,\ngetKinds: () => {\n  // Returns an array of functions in the workspace (includes boilerplate).\n},\ngetFunctions: () =>\n  // Returns an array of functions in the workspace (includes boilerplate).\ngetActiveGraph: () => {\n  // Returns the active Graph object.\n  // Returns null if active graph is not of type 'Knowledge Graph', or if an\n  // active graph is deleted, thereby setting active graph to null.\n},\ngetKnowledgeGraphs: () => {\n  // Returns [Graph]\n},\ngetImportedServices: () => {\n  // Returns an service imported into the workspace\n  // as a array of Service object (this calls the function\n  // that underlies getServiceById.\n  // No assistant services will be returned.\n}\n}\n```\n\n#### getWorkspace = () =>\n\nReturns a Workspace object representing the workspace. \n\n```js\nconst ws = await AssistantAPIClient.getWorkspace()\n```\n\n### Graphs\nThe `Graph` object:\n```js\n{     \nid: string,\nname: string,\noffsetX: Number,\noffsetY: Number,\nzoom: Number,\ngetNodes: async () => {\n    // Returns [Node]\n},\n\naddNode: async (type, instance, changeSelection) => {\n    // Returns Node\n},\nremoveNode: async id => {\n    // Should return nothing or error.\n    // Currently returning [] in all cases.\n},\nupdateNodeLayout: async (nodeId, { x, y, collapsed }) => {\n},\nupdateGraphLayout: async ({ offsetX, offsetY, zoom }) => {\n}\n}\n```\n\n#### Getting a graph object:\nGraph objects are obtained through an instance of a Workspace \n\n```js\nconst ag = await ws.getActiveGraph()\n```\n\nor\n\n```js\nconst kgs = await ws.getKnowledgeGraphs()\n```\n\n#### Manipulating Graphs\n\n**Only the active graph may be manipulated.\n\nAll graph manipulations should be ‘visually’ verifiable on the graph itself, i.e., adds/removes/positioning, should all be reflected on the graph itself. \n\nThe `Node` object:\n```js\n{\nid: string\nx: number\ny: number\ncollapsed: boolean\nknowledgeGraphNode {\n  id: string\n  innerKind: Kind\n  innerFunction: Function\n}\n}\n```\n\n#### addNode(type, instance, changeSelection) =>\n\nTakes type (“Function” or “Kind”), instance (the Function or Kind object), and optionally a boolean to indicate whether the selection should be changed to this new node. \n\nReturns the newly created Node object.\n\n```js\nconst node = await ag.addNode('Kind',kind)\n```\n\n#### removeNode(id) =>\n\nTakes the id of Node to be deleted. Returns either undefined or an error. \n\n```js\nawait ag.removeNode(node.id)\n```\n\n#### getNodes() =>\nReturns an array of Node objects from the graph. \n\n```js\nconst nodes = await ag.getNodes()\n```\n\n#### updateNodeLayout: async (nodeId, { x, y, collapsed})=>\n\nUpdates a Node layout given a node ID and node coordinates (`x` and/or `y`) or a `collapsed` value. x/y values must be a number, and collapsed must be a boolean. Whatever is not specified will remain current.\n\n```js\nag.updateNodeLayout(id,{x:100,y:100,collapsed:true})\n```\n\n#### updateGraphLayout: async ({ offsetX, offsetY, zoom})=>\n\nUpdates a Graph layout given numerical values for x/y offsets and the zoom. \n\n```js\nag.updateGraphLayout({offsetX:50, offsetY:50, zoom: 70})\n```\n\n### Functions\n\nThe `Function` object:\n```js\n{\n    id: string\n    name: string\n    service {\n      id: string\n      name: string\n    }\n    arguments {\n      id: string\n      name: string\n      type: string\n      modifiers: Array[string]\n      typeKindId:: string\n      kind {\n        id: string\n        name: string\n      }\n    }\n    implementation {\n      id: string\n      entrypoint {\n        id: string\n      }\n      operations {\n        id: string\n        type: string\n        function {\n          id: string\n          name: string\n        }\n        argumentValues {\n          id: string\n          argument {\n            id: string\n          }\n          operation {\n            id: string\n          }\n          argumentRef: string\n        }\n      }\n    }\n    isGenerated: boolean\n    functionType: string\n    graphqlOperationType: string\n    outputType: string\n    outputKindId: string\n    outputModifiers: Array[string]\n    kind {\n      id: string\n      name: string\n    }\n}\n```\n\n`FunctionExecutionResult` object:\n```js\n{\n  id: string,\n  result: JSON\n}\n```\n\n#### executeFunction = ( {id, variables, resolve} ) =>\n\nExecutes a function based on its id, with optional inputs for variables and a resolve string (this specifies the fields to be returned, which must be valid based on the result).\n\nReturns : JSON matching shape of result , unless no sub-selection of fields is required in the execution.\n\nThis following piece of code will execute a Function given a function ID, and pass in variables for ‘example’, requesting back id and name fields. \n\n```js \nconst res = await AssistantAPIClient.executeFunction({functionId: func.id, variables: {\"variableName\": \"variableValue\"}, resolve: \"{ id name }\");\n```\n\n#### createFunction = input =>\n\nCreates a function based on the input provided. \n\nReturns: the created Function object.\n\n**Using create function will only place the function in the workspace’s inventory--it will not place the function as a node on the Graph. In order to do this, you must pass the created function into the addNode function on the active Graph, making sure to specify ‘Function' as the type.\n\n```js\nconst createFunctionInput = {\n  name:\"yourName\",\n  arguments:[],\n  outputType: \"STRING\",\n  graphqlOperationType:\"QUERY\",\n  functionType: \"CKG\"\n}\n  \nconst createdFunction = await AssistantAPIClient.createFunction(createFunctionInput)\n```\n\n#### updateFunction = input =>\n\nInput is the same for creating a function. It’s important to note that the arguments property will be replaced in it’s entirety with whatever is provided (if a value is provided.\n\nReturns the updated `Function` object.\n\n```js\nconst updatedFunction = await AssistantAPIClient.updateFunction(input);\n```\n\n#### deleteFunction = input =>\n\nInput is the id of the Function to be deleted. Returns the deleted function as a promise.\n\n```js\nconst deletedFunction = await AssistantAPIClient.deleteFunction('id...');\n```\n\n#### getFunctionById = id =>\n\nReturns a Function as a promise based on the ID provided.\n\n```js\nconst func = await AssistantAPIClient.getFunctionById('id...');\n```\n\n#### addFunctionExecutionListener = async (id, cb) =>\n\nAssociates a callback function with the execution of a particular Function. When the Function matching the id parameter is executed, its FunctionExecutionResult object passed to the callback. Returns undefined.\n\nExample function execution callback and listener registration:\n\n```js\nfunction exampleFunctionCB (result){\n  console.log(`Function executed with result:`, result)\n}\n\nAssistantAPIClient.addFunctionExecutionListener('id...', exampleFunctionCB)\n```\n\n#### removeFunctionExecutionListener = async (id, cb) =>\n\nRemoves a Function execution listener based on the function ID and a reference to the callback function. If no callback is supplied, all listeners associated with the Function ID will be removed. Returns undefined.\n\n```js\nAssistantAPIClient.removeFunctionExecutionListener('id..', exampleFunctionCB)\n```\n\n### Kinds\nThe `Kind` object:\n```js\n{\n    id: string\n    name: string\n    service: {\n      id\n      name\n    }\n    isGenerated: boolean\n    schema {\n      id: string\n      name: string\n      type: string\n      typeKindId: string\n      modifiers: Array[string]\n      kind {\n        id: string\n        name: string\n      }\n    }\n}\n```\n\n#### createKind = input =>\n\nCreates a Kind based on an input object. Returns a promise that resolves to the created Kind object.\n\n```js\nconst kindInput = {\n name: \"someKind\",\n schema:[\n  { name: \"someField1\", type: STRING },\n  { name: \"someField2\", type: STRING }\n ]\n}\n\nconst newKind = await AssistantAPIClient.createKind(kindInput)\n```\n\n#### updateKind = input =>\n\nUpdates a Kind based on an input object. \n\nUpdate Semantics: Only properties specified will be updated. If updating the schema, the entire schema must be specified as it will be replaced in its entirety. \n\nReturns the updated `Kind` object.\n\n```js\nconst updated = await AssistantAPIClient.updateKind(input)\n```\n\n#### deleteKind = input =>\n\nDeletes a Kind given a kind ID.\n\n```js\nconst deleted = await AssistantAPIClient.deleteKind(input)\n```\n\n#### getKindById = id =>\n\nReturns a promise that resolves to a Kind object given the specified kind ID. Only kinds in the workspace or those of imported services will be returned. \n\n```js\nconst kind = await AssistantAPIClient.getKindById(id)\n```\n\n### Inventory\n\nThe `InventoryChanged` object:\n```js\n{\n  kinds: {\n    adds: [DiffItem]\n    deletes: [DiffItem]\n    updates: [DiffItem]\n  }\n  functions:{\n    adds: [DiffItem]\n    deletes: [DiffItem]\n    updates: [DiffItem]\n  }\n  services: {\n    adds: [DiffItem]\n    deletes: [DiffItem]\n    updates: [DiffItem]\n  }\n}\n```\n\nThe `DiffItem` object:\n```js\n{\n  id: string,\n  name: string\n}\n```\n\n#### addInventoryChangedListener = async cb =>\n\nRegisters a callback function with the inventory changed event. When workspace inventory changes the callback function will be called with the InventoryChangedobject. Returns undefined.\n\n*Current limitations: Kind and Function updates only occur where the name property is changed. Updates to services outside of the workspace will not be detected. \n\n**Use-case note: an ‘update’ diff for inventory services is unlikely in general usage. \n\n```js\nconst inventoryCB = ({diff}) => {\n  if(diff.kinds) console.log('KINDS CHANGED',diff.kinds)\n  if(diff.functions) console.log('FUNCTIONS CHANGED', diff.functions)\n  if(diff.services) console.log('SERVICES CHANGED',diff.services)\n}\n\nAssistantAPIClient.addInventoryChangedListener(inventoryCB)\n```\n\nThis function exists on the Q-Assisant-Client only--only enableSelectionChangedNotification is used on the API side. \n\n#### removeInventoryChangedListener = async cb =>\n\nRemoves an inventory changed listener given the referenced callback. If no callback is specified, all listeners will be removed. Returns undefined.\n\n```js\nAssistantAPIClient.removeInventoryChangedListener(inventoryCB)\n```\n\nThis function exists on the Q-Assisant-Client only--only disableSelectionChangedNotification is used on the API side. \n\n## Troubleshooting Assistant Issues\n### Assistant root file has loaded, but not other content\nObserving in the browser's dev tools that some resources have loaded correctly (usually the root), but other's haven't (usually nested files or chunks), is indicative of a failure of Q Gateway to proxy due to not having a 'relative' path structure.\n\n### You are seeing post-robot `NO ACK` errors in the console.\nThese errors stem from a failed acknowledgement for a call either between the client and the API or vice-versa. Here, this means that the web app 'window' (the assistant) cannot communicate with, or access, the 'window.parent' (Maana K-Portal) object. Improper CORS configuration is a common culprit (also verify if using docker or nginx that your proxying and networking is configured correctly to allow communication and to accout for CORS).","readmeFilename":"README.md","gitHead":"1499a2b0a633add947a5894d57a6089046ecdf5e","_id":"@io-maana/q-assistant-client@3.2.2-beta.25","_npmVersion":"6.4.1","_nodeVersion":"10.15.3","_npmUser":{"name":"teamcitymaana","email":"teamcity@maana.io"},"dist":{"integrity":"sha512-Wap7icGp+wHiX0XQ2eNX4qz8kR7xFhBRXQRZQmf6xex7QxwadjXyr8RW4AZL332DuqbWzH3IiGNqBaIN0bcyBw==","shasum":"c6d848235de797620c3e76b019a9329e87e76250","tarball":"https://registry.npmjs.org/@io-maana/q-assistant-client/-/q-assistant-client-3.2.2-beta.25.tgz","fileCount":6,"unpackedSize":33414,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJeYZjqCRA9TVsSAnZWagAAUmAP/A5hGy2DQWqa67OnMQHC\nOxXHFcIQLwfWth23Qrpc3S55DzHWHLrmayFQ5zoIE3x4eTYOvlBmq0FS1URX\njoQ3sf+nMh/BYZfRy45BZNuRHdOi/5STSrKz7qpgQoevzeIOwgDHRRvPpKV1\nwGdWu9skJiVkphO8h3kFPOWUWUZouFNR/OO2T8zuHzy5VNOH0qjUAHrn799o\n3yPD2zhwssPGr0ushQ1qfYldx4tZdOscvXzsGpAbxSA+JH4EIXtrQ/aC52YH\nfa0VDfh31/TZHdFMX29EsXB05ukqXlTimK3vfG6/aj3SP+iXzaCletIUNZoS\nyelWrOHP0ckCSXZjiEkSHlHzru3xhLJz77JcKtNpsvm9Akh0tr9JoNMDZ1cp\nhLBegBRNzJbvHeLF7i5mbc8G7wRngAUc05GvsVUyVbrmpnVAhyY9ysk7jvHO\n7X+uCWqXoaNU9nPrWLwRsltmxhszPzNjjFbzsnKfevO/YjwSQLoaesKcFmmY\n41m3Tnficpz3s/VNLrjYYmRatuZFSYd9D67fRWDAn6CcPKk6pe7V3V2I2Mgp\niRTem38UvwEV7+DkdFORo1//K+Chdf0E99uyXzLnCsZbMp4jJFMZEZ/sm0j8\nckR9EVtbmOVmvhD4uYP67Y/hcLvbLx5NvD2jdKxZ54vijwGPmq5A2cyMBBXW\ntIbF\r\n=1brJ\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEQCIFeVB4voSw8zPX4fdOwolFr8RgmfdnWO8KYsEnegmqOMAiBmD28GBA43AS5MTpnJwiHp0qovxIhHeOA5l2orsKUyrA=="}]},"maintainers":[{"email":"andrey@maana.io","name":"abatyuk"},{"email":"bzvestey@gmail.com","name":"bzvetey"},{"email":"dlewissandy@maana.io","name":"dlsmaana"},{"email":"rob@maana.io","name":"rpovey"},{"email":"teamcity@maana.io","name":"teamcitymaana"},{"email":"witt3rd@witt3rd.com","name":"witt3rd"}],"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/q-assistant-client_3.2.2-beta.25_1583454441564_0.08807914625071689"},"_hasShrinkwrap":false},"3.2.2-beta.26":{"name":"@io-maana/q-assistant-client","version":"3.2.2-beta.26","description":"JavaScript package to streamline communication between an assistant and the Maana Q Assistant API.","main":"build/AssistantAPIClient.js","scripts":{"build":"babel src --out-dir build","prepack":"npm run build","test":"echo \"Error: no test specified\" && exit 1","format":"prettier --write \"src/**/*.js\""},"repository":{"type":"git","url":"git+https://github.com/maana-io/q-assistant-client.git"},"keywords":["Maana","Q"],"author":{"name":"Logan Gore @ Maana.io"},"license":"MIT","bugs":{"url":"https://github.com/maana-io/q-assistant-client/issues"},"homepage":"https://github.com/maana-io/q-assistant-client#readme","dependencies":{"post-robot":"10.0.29"},"devDependencies":{"@babel/cli":"^7.5.5","@babel/core":"^7.5.5","@babel/plugin-proposal-class-properties":"^7.5.5","@babel/preset-env":"^7.5.5","prettier":"1.19.1"},"readme":"# q-assistant-client\nA lightweight JavaScript client for Maana-Q Assistant developers that wraps post-message communication between an embedded Maana-Q assistant and the Maana-Q UI.\n\n## Abstract\nThe Q-Assistant-Client is intented to be used in a web application being leveraged as a Maana Q assistant (embedded as an iframe).\nThis assistant client will facilitate communication between the assistant and the parent frame.\nThe client provides a rich, asynchronous experience over what would otherwise be 'fire-and-forget'-style messaging \nvia post-post message communication. \n\n## Requirements and Assumptions\n\n### Post-Robot Library\nThe Maana Knowledge Portal (KPortal) uses the kraken/post-robot library [kraken/post-robot](https://github.com/krakenjs/post-robot) to enrich the communication with the assistant. Post-robot allows for asynchronous, promise-based request/response style behavior between the assistant and the assistant API.\n\nThe API requires that the client use the post-robot library. This assistant-client library is the easiest way to achieve this, and also adds a fair amount of 'sugar' to the process to improve developer productivity. Developers could, however, use post-robot directly in their own client implementation. \n\n### Maana-Gateway Proxy Requirements\nThe Maana-Gateway service requires relative paths (paths relative to the root) in the assistant web application in order to proxy the application and its content. For create-react-apps, for instance, this means setting \"homepage\" to \".\" in the package.json file.\n\n## Singleton Instance\nThe client is exported as a singleton to avoid duplicate registration on event listeners.\nYou can import the instance like this:\n\n```js\nimport AssistantAPIClient from '@io-maana/q-assistant-client';\n```\n\nFunction calls can be made against the client instance like any other javascript object. They are all async.\n\n```js\nconst workspace = await AssistantAPIClient.getWorkspace(); \nconsole.log(\"Workspace:\", workspace)\n```\n\n## Dependencies\nPost-Robot\nhttps://github.com/krakenjs/post-robot\n\nPost-robot is used to provide a richer communication layer atop post-message.\n\n## Examples\n@TODO Logan\n\n## API Documentation\n\n### State management\n\n#### clearState = () =>\n\nThis will clear all ‘attached’ state between the assistant and the API. \n\nSpecifically, this will clear selection and inventory changed event listeners. \n\n```js\nawait AssistantAPIClient.clearState()\n```\n\n### User Info\nThe `UserInfo` object:\n```js\n{\n email: string,\n name: string\n}\n```\n\n#### getUserInfo = () => \n\nReturns a Userinfo object pertaining to the logged in user.\n\n```js\nconst userInfo = await AssistantAPIClient.getUserInfo()\n```\n### Selection\nThe `Selection` object:\n```js\n{\n  kindId: string\n  kindName: string\n  id: string\n}\n```\n\n#### getCurrentSelection = () => \n\nReturns an Array of `Selection` objects:\n\n```js\nconst {selection} = await AssistantAPIClient.getCurrentSelection();\n```\n\n#### addSelectionChangedListener = async cb =>\n\nAdds a callback function to be executed upon a valid workspace selection change.\n\nCallback value is an array of Selection objects:\n\n```js\n// Create the selection callback.\nconst selectionCB = ({selection})=>{\n  console.log('Workspace selection has changed.')\n  selection.forEach(i=>{\n    console.log('Kind: ',i.kindName)\n    console.log('Instance Id:',i.id)\n    console.log('Kind Id:',i.kindId)\n  })\n}\n\n// Add the listener.\nAssistantAPIClient.addSelectionChangedListener(selectionCB);\n```\n\nThis function only exists on the Q-Assistant-Client--only enableSelectionChangedNotification is called on the API. \n\n#### removeSelectionChangedListener = async cb =>\n\nThis will have to be called on a 1:1 basis with addSelectionChangedListener calls if supplying a callback.\n\n```js\nAssistantAPIClient.removeSelectionChangedListener(selectionCB)\n```\n\n**If NOT supplying a callback to this call, all selection changed listeners will be removed.\n\n```js\nAssistantAPIClient.removeSelectionChangedListener()\n```\n\nThis function only exists on the Q-Assistant-Client--only disableSelectionChangedNotification is called on the API. \n\n\n### Services\nThe `Service` object:\n```js\n{\n   id: string,\n   name: string\n   endpointUrl: string,\n   getKinds: () => // Returns [] of Kinds objects\n   getFunctions: () => // Returns [] of Function objects\n}\n```\n\n#### getServiceById = id =>\nThis will return a service that exists within the scope of the workspace. \n** Assistant services will return null. Services outside the scope of the workspace will cause an error to be returned as 'Unable to load a Service from outside of the workspace.'\n\n```js\nconst svc = await AssistantAPIClient.getServiceById(id)\n```\n\n### Workspace\nThe `Workspace` object:\n```js\n{\nid: string,\nname: string,\ngetKinds: () => {\n  // Returns an array of functions in the workspace (includes boilerplate).\n},\ngetFunctions: () =>\n  // Returns an array of functions in the workspace (includes boilerplate).\ngetActiveGraph: () => {\n  // Returns the active Graph object.\n  // Returns null if active graph is not of type 'Knowledge Graph', or if an\n  // active graph is deleted, thereby setting active graph to null.\n},\ngetKnowledgeGraphs: () => {\n  // Returns [Graph]\n},\ngetImportedServices: () => {\n  // Returns an service imported into the workspace\n  // as a array of Service object (this calls the function\n  // that underlies getServiceById.\n  // No assistant services will be returned.\n}\n}\n```\n\n#### getWorkspace = () =>\n\nReturns a Workspace object representing the workspace. \n\n```js\nconst ws = await AssistantAPIClient.getWorkspace()\n```\n\n### Graphs\nThe `Graph` object:\n```js\n{     \nid: string,\nname: string,\noffsetX: Number,\noffsetY: Number,\nzoom: Number,\ngetNodes: async () => {\n    // Returns [Node]\n},\n\naddNode: async (type, instance, changeSelection) => {\n    // Returns Node\n},\nremoveNode: async id => {\n    // Should return nothing or error.\n    // Currently returning [] in all cases.\n},\nupdateNodeLayout: async (nodeId, { x, y, collapsed }) => {\n},\nupdateGraphLayout: async ({ offsetX, offsetY, zoom }) => {\n}\n}\n```\n\n#### Getting a graph object:\nGraph objects are obtained through an instance of a Workspace \n\n```js\nconst ag = await ws.getActiveGraph()\n```\n\nor\n\n```js\nconst kgs = await ws.getKnowledgeGraphs()\n```\n\n#### Manipulating Graphs\n\n**Only the active graph may be manipulated.\n\nAll graph manipulations should be ‘visually’ verifiable on the graph itself, i.e., adds/removes/positioning, should all be reflected on the graph itself. \n\nThe `Node` object:\n```js\n{\nid: string\nx: number\ny: number\ncollapsed: boolean\nknowledgeGraphNode {\n  id: string\n  innerKind: Kind\n  innerFunction: Function\n}\n}\n```\n\n#### addNode(type, instance, changeSelection) =>\n\nTakes type (“Function” or “Kind”), instance (the Function or Kind object), and optionally a boolean to indicate whether the selection should be changed to this new node. \n\nReturns the newly created Node object.\n\n```js\nconst node = await ag.addNode('Kind',kind)\n```\n\n#### removeNode(id) =>\n\nTakes the id of Node to be deleted. Returns either undefined or an error. \n\n```js\nawait ag.removeNode(node.id)\n```\n\n#### getNodes() =>\nReturns an array of Node objects from the graph. \n\n```js\nconst nodes = await ag.getNodes()\n```\n\n#### updateNodeLayout: async (nodeId, { x, y, collapsed})=>\n\nUpdates a Node layout given a node ID and node coordinates (`x` and/or `y`) or a `collapsed` value. x/y values must be a number, and collapsed must be a boolean. Whatever is not specified will remain current.\n\n```js\nag.updateNodeLayout(id,{x:100,y:100,collapsed:true})\n```\n\n#### updateGraphLayout: async ({ offsetX, offsetY, zoom})=>\n\nUpdates a Graph layout given numerical values for x/y offsets and the zoom. \n\n```js\nag.updateGraphLayout({offsetX:50, offsetY:50, zoom: 70})\n```\n\n### Functions\n\nThe `Function` object:\n```js\n{\n    id: string\n    name: string\n    service {\n      id: string\n      name: string\n    }\n    arguments {\n      id: string\n      name: string\n      type: string\n      modifiers: Array[string]\n      typeKindId:: string\n      kind {\n        id: string\n        name: string\n      }\n    }\n    implementation {\n      id: string\n      entrypoint {\n        id: string\n      }\n      operations {\n        id: string\n        type: string\n        function {\n          id: string\n          name: string\n        }\n        argumentValues {\n          id: string\n          argument {\n            id: string\n          }\n          operation {\n            id: string\n          }\n          argumentRef: string\n        }\n      }\n    }\n    isGenerated: boolean\n    functionType: string\n    graphqlOperationType: string\n    outputType: string\n    outputKindId: string\n    outputModifiers: Array[string]\n    kind {\n      id: string\n      name: string\n    }\n}\n```\n\n`FunctionExecutionResult` object:\n```js\n{\n  id: string,\n  result: JSON\n}\n```\n\n#### executeFunction = ( {id, variables, resolve} ) =>\n\nExecutes a function based on its id, with optional inputs for variables and a resolve string (this specifies the fields to be returned, which must be valid based on the result).\n\nReturns : JSON matching shape of result , unless no sub-selection of fields is required in the execution.\n\nThis following piece of code will execute a Function given a function ID, and pass in variables for ‘example’, requesting back id and name fields. \n\n```js \nconst res = await AssistantAPIClient.executeFunction({functionId: func.id, variables: {\"variableName\": \"variableValue\"}, resolve: \"{ id name }\");\n```\n\n#### createFunction = input =>\n\nCreates a function based on the input provided. \n\nReturns: the created Function object.\n\n**Using create function will only place the function in the workspace’s inventory--it will not place the function as a node on the Graph. In order to do this, you must pass the created function into the addNode function on the active Graph, making sure to specify ‘Function' as the type.\n\n```js\nconst createFunctionInput = {\n  name:\"yourName\",\n  arguments:[],\n  outputType: \"STRING\",\n  graphqlOperationType:\"QUERY\",\n  functionType: \"CKG\"\n}\n  \nconst createdFunction = await AssistantAPIClient.createFunction(createFunctionInput)\n```\n\n#### updateFunction = input =>\n\nInput is the same for creating a function. It’s important to note that the arguments property will be replaced in it’s entirety with whatever is provided (if a value is provided.\n\nReturns the updated `Function` object.\n\n```js\nconst updatedFunction = await AssistantAPIClient.updateFunction(input);\n```\n\n#### deleteFunction = input =>\n\nInput is the id of the Function to be deleted. Returns the deleted function as a promise.\n\n```js\nconst deletedFunction = await AssistantAPIClient.deleteFunction('id...');\n```\n\n#### getFunctionById = id =>\n\nReturns a Function as a promise based on the ID provided.\n\n```js\nconst func = await AssistantAPIClient.getFunctionById('id...');\n```\n\n#### addFunctionExecutionListener = async (id, cb) =>\n\nAssociates a callback function with the execution of a particular Function. When the Function matching the id parameter is executed, its FunctionExecutionResult object passed to the callback. Returns undefined.\n\nExample function execution callback and listener registration:\n\n```js\nfunction exampleFunctionCB (result){\n  console.log(`Function executed with result:`, result)\n}\n\nAssistantAPIClient.addFunctionExecutionListener('id...', exampleFunctionCB)\n```\n\n#### removeFunctionExecutionListener = async (id, cb) =>\n\nRemoves a Function execution listener based on the function ID and a reference to the callback function. If no callback is supplied, all listeners associated with the Function ID will be removed. Returns undefined.\n\n```js\nAssistantAPIClient.removeFunctionExecutionListener('id..', exampleFunctionCB)\n```\n\n### Kinds\nThe `Kind` object:\n```js\n{\n    id: string\n    name: string\n    service: {\n      id\n      name\n    }\n    isGenerated: boolean\n    schema {\n      id: string\n      name: string\n      type: string\n      typeKindId: string\n      modifiers: Array[string]\n      kind {\n        id: string\n        name: string\n      }\n    }\n}\n```\n\n#### createKind = input =>\n\nCreates a Kind based on an input object. Returns a promise that resolves to the created Kind object.\n\n```js\nconst kindInput = {\n name: \"someKind\",\n schema:[\n  { name: \"someField1\", type: STRING },\n  { name: \"someField2\", type: STRING }\n ]\n}\n\nconst newKind = await AssistantAPIClient.createKind(kindInput)\n```\n\n#### updateKind = input =>\n\nUpdates a Kind based on an input object. \n\nUpdate Semantics: Only properties specified will be updated. If updating the schema, the entire schema must be specified as it will be replaced in its entirety. \n\nReturns the updated `Kind` object.\n\n```js\nconst updated = await AssistantAPIClient.updateKind(input)\n```\n\n#### deleteKind = input =>\n\nDeletes a Kind given a kind ID.\n\n```js\nconst deleted = await AssistantAPIClient.deleteKind(input)\n```\n\n#### getKindById = id =>\n\nReturns a promise that resolves to a Kind object given the specified kind ID. Only kinds in the workspace or those of imported services will be returned. \n\n```js\nconst kind = await AssistantAPIClient.getKindById(id)\n```\n\n### Inventory\n\nThe `InventoryChanged` object:\n```js\n{\n  kinds: {\n    adds: [DiffItem]\n    deletes: [DiffItem]\n    updates: [DiffItem]\n  }\n  functions:{\n    adds: [DiffItem]\n    deletes: [DiffItem]\n    updates: [DiffItem]\n  }\n  services: {\n    adds: [DiffItem]\n    deletes: [DiffItem]\n    updates: [DiffItem]\n  }\n}\n```\n\nThe `DiffItem` object:\n```js\n{\n  id: string,\n  name: string\n}\n```\n\n#### addInventoryChangedListener = async cb =>\n\nRegisters a callback function with the inventory changed event. When workspace inventory changes the callback function will be called with the InventoryChangedobject. Returns undefined.\n\n*Current limitations: Kind and Function updates only occur where the name property is changed. Updates to services outside of the workspace will not be detected. \n\n**Use-case note: an ‘update’ diff for inventory services is unlikely in general usage. \n\n```js\nconst inventoryCB = ({diff}) => {\n  if(diff.kinds) console.log('KINDS CHANGED',diff.kinds)\n  if(diff.functions) console.log('FUNCTIONS CHANGED', diff.functions)\n  if(diff.services) console.log('SERVICES CHANGED',diff.services)\n}\n\nAssistantAPIClient.addInventoryChangedListener(inventoryCB)\n```\n\nThis function exists on the Q-Assisant-Client only--only enableSelectionChangedNotification is used on the API side. \n\n#### removeInventoryChangedListener = async cb =>\n\nRemoves an inventory changed listener given the referenced callback. If no callback is specified, all listeners will be removed. Returns undefined.\n\n```js\nAssistantAPIClient.removeInventoryChangedListener(inventoryCB)\n```\n\nThis function exists on the Q-Assisant-Client only--only disableSelectionChangedNotification is used on the API side. \n\n## Troubleshooting Assistant Issues\n### Assistant root file has loaded, but not other content\nObserving in the browser's dev tools that some resources have loaded correctly (usually the root), but other's haven't (usually nested files or chunks), is indicative of a failure of Q Gateway to proxy due to not having a 'relative' path structure.\n\n### You are seeing post-robot `NO ACK` errors in the console.\nThese errors stem from a failed acknowledgement for a call either between the client and the API or vice-versa. Here, this means that the web app 'window' (the assistant) cannot communicate with, or access, the 'window.parent' (Maana K-Portal) object. Improper CORS configuration is a common culprit (also verify if using docker or nginx that your proxying and networking is configured correctly to allow communication and to accout for CORS).","readmeFilename":"README.md","gitHead":"86fc52fe0e5bd0630fe55555bf6c773097f5924a","_id":"@io-maana/q-assistant-client@3.2.2-beta.26","_npmVersion":"6.4.1","_nodeVersion":"10.15.3","_npmUser":{"name":"teamcitymaana","email":"teamcity@maana.io"},"dist":{"integrity":"sha512-3zwYQocMFQcq3kRPioUQMutl9assnkLWeOVfqvyiI8rwFP0AyJuVUSXGAJD5pNmH9o+x9eoxru8sj9WWgV1t7w==","shasum":"95958c9d9d53b6ba3970980d4672eb8e8b0081bc","tarball":"https://registry.npmjs.org/@io-maana/q-assistant-client/-/q-assistant-client-3.2.2-beta.26.tgz","fileCount":6,"unpackedSize":33401,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJeZrLbCRA9TVsSAnZWagAAP9IP/0fa4cooqsY7KELErTkT\nWIZ470EOV/lVUNEayR7/WinHQeNx0U6NfhuXtjmPpe75M7e4i5PdMene0W4w\nqSrrsnJKZDQn20ZhNj6gvAvLVLSTNtLflU0Ha6/bDW7sxeAlkv4kpjhrhOOK\nmhIgVIJsdkVPoPLaWBglYJ7X6BT8Dr+9UaM/8ol5l7sK60wU8hbxlwIau4Ou\nlaIHWn/cVTx1+OwgqibB8NFbKZFjPIL4peg/vdh/0MiZigM92uQZfi3yVtCO\nunncamQ/boBYCQsr79Et1xqdM3IazJOlGJwM1d85TJ4fW4FKNbObu2/j+ZYw\nY2G3YDISyVpOQ9pvfZSwRjMUB6uNYxERtaWzl1faNuiwaFQj5xxaotXtcetC\naTqfMVh7bRRUONpXCarVXdknWjRtftBxet4FV0yF9/S1i1yE9srVG3Ssdlmo\ne9Xi01K/H7BC0S3Y74VRuNlssIhKyTTJxKe/8TpZ4afAkHz65BV2XnnD3Ool\n/TfHKwI+YplRhWfMWpsVpoarskvbbuTNCkyFYkc/pEDMKE36vo6sWAAgiEXJ\nE77GQjBKM59WIeXtmA6T39+FhdRxTYrtpd0jFPnqKNS5unCzgkJg+XAMD4UH\nrq/36nToAq6FJA8yjmqFjxiUIt56nC2DPYx0n2v3Jr4wqHRefX6HP/i1iYbz\nZv/6\r\n=Ftt3\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIC1y5+BGHoIXBOy2Mgti5NY7Cn5TEpiaqm+a17UB2qFvAiEArh7MiuXu9X0L+Tp2l9J1x0TSQyBAT7SuKnznfXrOWMQ="}]},"maintainers":[{"email":"andrey@maana.io","name":"abatyuk"},{"email":"bzvestey@gmail.com","name":"bzvetey"},{"email":"dlewissandy@maana.io","name":"dlsmaana"},{"email":"rob@maana.io","name":"rpovey"},{"email":"teamcity@maana.io","name":"teamcitymaana"},{"email":"witt3rd@witt3rd.com","name":"witt3rd"}],"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/q-assistant-client_3.2.2-beta.26_1583788762840_0.4515041925366785"},"_hasShrinkwrap":false},"3.2.2-beta.27":{"name":"@io-maana/q-assistant-client","version":"3.2.2-beta.27","description":"JavaScript package to streamline communication between an assistant and the Maana Q Assistant API.","main":"build/AssistantAPIClient.js","scripts":{"build":"babel src --out-dir build","prepack":"npm run build","test":"echo \"Error: no test specified\" && exit 1","format":"prettier --write \"src/**/*.js\""},"repository":{"type":"git","url":"git+https://github.com/maana-io/q-assistant-client.git"},"keywords":["Maana","Q"],"author":{"name":"Logan Gore @ Maana.io"},"license":"MIT","bugs":{"url":"https://github.com/maana-io/q-assistant-client/issues"},"homepage":"https://github.com/maana-io/q-assistant-client#readme","dependencies":{"post-robot":"10.0.29"},"devDependencies":{"@babel/cli":"^7.5.5","@babel/core":"^7.5.5","@babel/plugin-proposal-class-properties":"^7.5.5","@babel/preset-env":"^7.5.5","prettier":"1.19.1"},"readme":"# q-assistant-client\nA lightweight JavaScript client for Maana-Q Assistant developers that wraps post-message communication between an embedded Maana-Q assistant and the Maana-Q UI.\n\n## Abstract\nThe Q-Assistant-Client is intented to be used in a web application being leveraged as a Maana Q assistant (embedded as an iframe).\nThis assistant client will facilitate communication between the assistant and the parent frame.\nThe client provides a rich, asynchronous experience over what would otherwise be 'fire-and-forget'-style messaging \nvia post-post message communication. \n\n## Requirements and Assumptions\n\n### Post-Robot Library\nThe Maana Knowledge Portal (KPortal) uses the kraken/post-robot library [kraken/post-robot](https://github.com/krakenjs/post-robot) to enrich the communication with the assistant. Post-robot allows for asynchronous, promise-based request/response style behavior between the assistant and the assistant API.\n\nThe API requires that the client use the post-robot library. This assistant-client library is the easiest way to achieve this, and also adds a fair amount of 'sugar' to the process to improve developer productivity. Developers could, however, use post-robot directly in their own client implementation. \n\n### Maana-Gateway Proxy Requirements\nThe Maana-Gateway service requires relative paths (paths relative to the root) in the assistant web application in order to proxy the application and its content. For create-react-apps, for instance, this means setting \"homepage\" to \".\" in the package.json file.\n\n## Singleton Instance\nThe client is exported as a singleton to avoid duplicate registration on event listeners.\nYou can import the instance like this:\n\n```js\nimport AssistantAPIClient from '@io-maana/q-assistant-client';\n```\n\nFunction calls can be made against the client instance like any other javascript object. They are all async.\n\n```js\nconst workspace = await AssistantAPIClient.getWorkspace(); \nconsole.log(\"Workspace:\", workspace)\n```\n\n## Dependencies\nPost-Robot\nhttps://github.com/krakenjs/post-robot\n\nPost-robot is used to provide a richer communication layer atop post-message.\n\n## Examples\n@TODO Logan\n\n## API Documentation\n\n### State management\n\n#### clearState = () =>\n\nThis will clear all ‘attached’ state between the assistant and the API. \n\nSpecifically, this will clear selection and inventory changed event listeners. \n\n```js\nawait AssistantAPIClient.clearState()\n```\n\n### User Info\nThe `UserInfo` object:\n```js\n{\n email: string,\n name: string\n}\n```\n\n#### getUserInfo = () => \n\nReturns a Userinfo object pertaining to the logged in user.\n\n```js\nconst userInfo = await AssistantAPIClient.getUserInfo()\n```\n### Selection\nThe `Selection` object:\n```js\n{\n  kindId: string\n  kindName: string\n  id: string\n}\n```\n\n#### getCurrentSelection = () => \n\nReturns an Array of `Selection` objects:\n\n```js\nconst {selection} = await AssistantAPIClient.getCurrentSelection();\n```\n\n#### addSelectionChangedListener = async cb =>\n\nAdds a callback function to be executed upon a valid workspace selection change.\n\nCallback value is an array of Selection objects:\n\n```js\n// Create the selection callback.\nconst selectionCB = ({selection})=>{\n  console.log('Workspace selection has changed.')\n  selection.forEach(i=>{\n    console.log('Kind: ',i.kindName)\n    console.log('Instance Id:',i.id)\n    console.log('Kind Id:',i.kindId)\n  })\n}\n\n// Add the listener.\nAssistantAPIClient.addSelectionChangedListener(selectionCB);\n```\n\nThis function only exists on the Q-Assistant-Client--only enableSelectionChangedNotification is called on the API. \n\n#### removeSelectionChangedListener = async cb =>\n\nThis will have to be called on a 1:1 basis with addSelectionChangedListener calls if supplying a callback.\n\n```js\nAssistantAPIClient.removeSelectionChangedListener(selectionCB)\n```\n\n**If NOT supplying a callback to this call, all selection changed listeners will be removed.\n\n```js\nAssistantAPIClient.removeSelectionChangedListener()\n```\n\nThis function only exists on the Q-Assistant-Client--only disableSelectionChangedNotification is called on the API. \n\n\n### Services\nThe `Service` object:\n```js\n{\n   id: string,\n   name: string\n   endpointUrl: string,\n   getKinds: () => // Returns [] of Kinds objects\n   getFunctions: () => // Returns [] of Function objects\n}\n```\n\n#### getServiceById = id =>\nThis will return a service that exists within the scope of the workspace. \n** Assistant services will return null. Services outside the scope of the workspace will cause an error to be returned as 'Unable to load a Service from outside of the workspace.'\n\n```js\nconst svc = await AssistantAPIClient.getServiceById(id)\n```\n\n### Workspace\nThe `Workspace` object:\n```js\n{\nid: string,\nname: string,\ngetKinds: () => {\n  // Returns an array of functions in the workspace (includes boilerplate).\n},\ngetFunctions: () =>\n  // Returns an array of functions in the workspace (includes boilerplate).\ngetActiveGraph: () => {\n  // Returns the active Graph object.\n  // Returns null if active graph is not of type 'Knowledge Graph', or if an\n  // active graph is deleted, thereby setting active graph to null.\n},\ngetKnowledgeGraphs: () => {\n  // Returns [Graph]\n},\ngetImportedServices: () => {\n  // Returns an service imported into the workspace\n  // as a array of Service object (this calls the function\n  // that underlies getServiceById.\n  // No assistant services will be returned.\n}\n}\n```\n\n#### getWorkspace = () =>\n\nReturns a Workspace object representing the workspace. \n\n```js\nconst ws = await AssistantAPIClient.getWorkspace()\n```\n\n### Graphs\nThe `Graph` object:\n```js\n{     \nid: string,\nname: string,\noffsetX: Number,\noffsetY: Number,\nzoom: Number,\ngetNodes: async () => {\n    // Returns [Node]\n},\n\naddNode: async (type, instance, changeSelection) => {\n    // Returns Node\n},\nremoveNode: async id => {\n    // Should return nothing or error.\n    // Currently returning [] in all cases.\n},\nupdateNodeLayout: async (nodeId, { x, y, collapsed }) => {\n},\nupdateGraphLayout: async ({ offsetX, offsetY, zoom }) => {\n}\n}\n```\n\n#### Getting a graph object:\nGraph objects are obtained through an instance of a Workspace \n\n```js\nconst ag = await ws.getActiveGraph()\n```\n\nor\n\n```js\nconst kgs = await ws.getKnowledgeGraphs()\n```\n\n#### Manipulating Graphs\n\n**Only the active graph may be manipulated.\n\nAll graph manipulations should be ‘visually’ verifiable on the graph itself, i.e., adds/removes/positioning, should all be reflected on the graph itself. \n\nThe `Node` object:\n```js\n{\nid: string\nx: number\ny: number\ncollapsed: boolean\nknowledgeGraphNode {\n  id: string\n  innerKind: Kind\n  innerFunction: Function\n}\n}\n```\n\n#### addNode(type, instance, changeSelection) =>\n\nTakes type (“Function” or “Kind”), instance (the Function or Kind object), and optionally a boolean to indicate whether the selection should be changed to this new node. \n\nReturns the newly created Node object.\n\n```js\nconst node = await ag.addNode('Kind',kind)\n```\n\n#### removeNode(id) =>\n\nTakes the id of Node to be deleted. Returns either undefined or an error. \n\n```js\nawait ag.removeNode(node.id)\n```\n\n#### getNodes() =>\nReturns an array of Node objects from the graph. \n\n```js\nconst nodes = await ag.getNodes()\n```\n\n#### updateNodeLayout: async (nodeId, { x, y, collapsed})=>\n\nUpdates a Node layout given a node ID and node coordinates (`x` and/or `y`) or a `collapsed` value. x/y values must be a number, and collapsed must be a boolean. Whatever is not specified will remain current.\n\n```js\nag.updateNodeLayout(id,{x:100,y:100,collapsed:true})\n```\n\n#### updateGraphLayout: async ({ offsetX, offsetY, zoom})=>\n\nUpdates a Graph layout given numerical values for x/y offsets and the zoom. \n\n```js\nag.updateGraphLayout({offsetX:50, offsetY:50, zoom: 70})\n```\n\n### Functions\n\nThe `Function` object:\n```js\n{\n    id: string\n    name: string\n    service {\n      id: string\n      name: string\n    }\n    arguments {\n      id: string\n      name: string\n      type: string\n      modifiers: Array[string]\n      typeKindId:: string\n      kind {\n        id: string\n        name: string\n      }\n    }\n    implementation {\n      id: string\n      entrypoint {\n        id: string\n      }\n      operations {\n        id: string\n        type: string\n        function {\n          id: string\n          name: string\n        }\n        argumentValues {\n          id: string\n          argument {\n            id: string\n          }\n          operation {\n            id: string\n          }\n          argumentRef: string\n        }\n      }\n    }\n    isGenerated: boolean\n    functionType: string\n    graphqlOperationType: string\n    outputType: string\n    outputKindId: string\n    outputModifiers: Array[string]\n    kind {\n      id: string\n      name: string\n    }\n}\n```\n\n`FunctionExecutionResult` object:\n```js\n{\n  id: string,\n  result: JSON\n}\n```\n\n#### executeFunction = ( {id, variables, resolve} ) =>\n\nExecutes a function based on its id, with optional inputs for variables and a resolve string (this specifies the fields to be returned, which must be valid based on the result).\n\nReturns : JSON matching shape of result , unless no sub-selection of fields is required in the execution.\n\nThis following piece of code will execute a Function given a function ID, and pass in variables for ‘example’, requesting back id and name fields. \n\n```js \nconst res = await AssistantAPIClient.executeFunction({functionId: func.id, variables: {\"variableName\": \"variableValue\"}, resolve: \"{ id name }\");\n```\n\n#### createFunction = input =>\n\nCreates a function based on the input provided. \n\nReturns: the created Function object.\n\n**Using create function will only place the function in the workspace’s inventory--it will not place the function as a node on the Graph. In order to do this, you must pass the created function into the addNode function on the active Graph, making sure to specify ‘Function' as the type.\n\n```js\nconst createFunctionInput = {\n  name:\"yourName\",\n  arguments:[],\n  outputType: \"STRING\",\n  graphqlOperationType:\"QUERY\",\n  functionType: \"CKG\"\n}\n  \nconst createdFunction = await AssistantAPIClient.createFunction(createFunctionInput)\n```\n\n#### updateFunction = input =>\n\nInput is the same for creating a function. It’s important to note that the arguments property will be replaced in it’s entirety with whatever is provided (if a value is provided.\n\nReturns the updated `Function` object.\n\n```js\nconst updatedFunction = await AssistantAPIClient.updateFunction(input);\n```\n\n#### deleteFunction = input =>\n\nInput is the id of the Function to be deleted. Returns the deleted function as a promise.\n\n```js\nconst deletedFunction = await AssistantAPIClient.deleteFunction('id...');\n```\n\n#### getFunctionById = id =>\n\nReturns a Function as a promise based on the ID provided.\n\n```js\nconst func = await AssistantAPIClient.getFunctionById('id...');\n```\n\n#### addFunctionExecutionListener = async (id, cb) =>\n\nAssociates a callback function with the execution of a particular Function. When the Function matching the id parameter is executed, its FunctionExecutionResult object passed to the callback. Returns undefined.\n\nExample function execution callback and listener registration:\n\n```js\nfunction exampleFunctionCB (result){\n  console.log(`Function executed with result:`, result)\n}\n\nAssistantAPIClient.addFunctionExecutionListener('id...', exampleFunctionCB)\n```\n\n#### removeFunctionExecutionListener = async (id, cb) =>\n\nRemoves a Function execution listener based on the function ID and a reference to the callback function. If no callback is supplied, all listeners associated with the Function ID will be removed. Returns undefined.\n\n```js\nAssistantAPIClient.removeFunctionExecutionListener('id..', exampleFunctionCB)\n```\n\n### Kinds\nThe `Kind` object:\n```js\n{\n    id: string\n    name: string\n    service: {\n      id\n      name\n    }\n    isGenerated: boolean\n    schema {\n      id: string\n      name: string\n      type: string\n      typeKindId: string\n      modifiers: Array[string]\n      kind {\n        id: string\n        name: string\n      }\n    }\n}\n```\n\n#### createKind = input =>\n\nCreates a Kind based on an input object. Returns a promise that resolves to the created Kind object.\n\n```js\nconst kindInput = {\n name: \"someKind\",\n schema:[\n  { name: \"someField1\", type: STRING },\n  { name: \"someField2\", type: STRING }\n ]\n}\n\nconst newKind = await AssistantAPIClient.createKind(kindInput)\n```\n\n#### updateKind = input =>\n\nUpdates a Kind based on an input object. \n\nUpdate Semantics: Only properties specified will be updated. If updating the schema, the entire schema must be specified as it will be replaced in its entirety. \n\nReturns the updated `Kind` object.\n\n```js\nconst updated = await AssistantAPIClient.updateKind(input)\n```\n\n#### deleteKind = input =>\n\nDeletes a Kind given a kind ID.\n\n```js\nconst deleted = await AssistantAPIClient.deleteKind(input)\n```\n\n#### getKindById = id =>\n\nReturns a promise that resolves to a Kind object given the specified kind ID. Only kinds in the workspace or those of imported services will be returned. \n\n```js\nconst kind = await AssistantAPIClient.getKindById(id)\n```\n\n### Inventory\n\nThe `InventoryChanged` object:\n```js\n{\n  kinds: {\n    adds: [DiffItem]\n    deletes: [DiffItem]\n    updates: [DiffItem]\n  }\n  functions:{\n    adds: [DiffItem]\n    deletes: [DiffItem]\n    updates: [DiffItem]\n  }\n  services: {\n    adds: [DiffItem]\n    deletes: [DiffItem]\n    updates: [DiffItem]\n  }\n}\n```\n\nThe `DiffItem` object:\n```js\n{\n  id: string,\n  name: string\n}\n```\n\n#### addInventoryChangedListener = async cb =>\n\nRegisters a callback function with the inventory changed event. When workspace inventory changes the callback function will be called with the InventoryChangedobject. Returns undefined.\n\n*Current limitations: Kind and Function updates only occur where the name property is changed. Updates to services outside of the workspace will not be detected. \n\n**Use-case note: an ‘update’ diff for inventory services is unlikely in general usage. \n\n```js\nconst inventoryCB = ({diff}) => {\n  if(diff.kinds) console.log('KINDS CHANGED',diff.kinds)\n  if(diff.functions) console.log('FUNCTIONS CHANGED', diff.functions)\n  if(diff.services) console.log('SERVICES CHANGED',diff.services)\n}\n\nAssistantAPIClient.addInventoryChangedListener(inventoryCB)\n```\n\nThis function exists on the Q-Assisant-Client only--only enableSelectionChangedNotification is used on the API side. \n\n#### removeInventoryChangedListener = async cb =>\n\nRemoves an inventory changed listener given the referenced callback. If no callback is specified, all listeners will be removed. Returns undefined.\n\n```js\nAssistantAPIClient.removeInventoryChangedListener(inventoryCB)\n```\n\nThis function exists on the Q-Assisant-Client only--only disableSelectionChangedNotification is used on the API side. \n\n## Troubleshooting Assistant Issues\n### Assistant root file has loaded, but not other content\nObserving in the browser's dev tools that some resources have loaded correctly (usually the root), but other's haven't (usually nested files or chunks), is indicative of a failure of Q Gateway to proxy due to not having a 'relative' path structure.\n\n### You are seeing post-robot `NO ACK` errors in the console.\nThese errors stem from a failed acknowledgement for a call either between the client and the API or vice-versa. Here, this means that the web app 'window' (the assistant) cannot communicate with, or access, the 'window.parent' (Maana K-Portal) object. Improper CORS configuration is a common culprit (also verify if using docker or nginx that your proxying and networking is configured correctly to allow communication and to accout for CORS).","readmeFilename":"README.md","gitHead":"544385e6844966303974257ebf7499a4d7eac179","_id":"@io-maana/q-assistant-client@3.2.2-beta.27","_npmVersion":"6.4.1","_nodeVersion":"10.15.3","_npmUser":{"name":"teamcitymaana","email":"teamcity@maana.io"},"dist":{"integrity":"sha512-VwH//0qO8B+a2C78rZrXUxjgEUJjXZ5Ke2mP70RUGGxaf09jSuYiPXsJP7BZO2DvzcHKAMZkwNAUpzVNYuTRtg==","shasum":"660ac765058cb8c820e339fcd62928a2dac74a29","tarball":"https://registry.npmjs.org/@io-maana/q-assistant-client/-/q-assistant-client-3.2.2-beta.27.tgz","fileCount":6,"unpackedSize":33528,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJeZ//4CRA9TVsSAnZWagAA2U0QAIbqw1bLLQRsBVY+Zz5o\nF2I6kD3ioZzRd/X/4pub7E1AlFIU1zk0uyMrAxb1EPnFGaghGPJYj5fihb8u\n1FjeLwZ9fbNJzAnwRkI9lc7Xl0+n1QriqooW6EZLNhzMBSu4QODwhwBFqAVg\nLWMaHiSoRjTmYmBipg3m36V9imp6S+bzLdBynrhbttPYKWOk02SybbfY9zLa\nsyzbgBlT1i8wticKGcBNgyNTJ2WbKYfDfWkjHPd1jE3sPCUdEVSqvSajIFCQ\nFk2oe7szBSTyZjArADKTDNeaoFht5HZ/MiJtLg8GtG20MW3axhlYfZKOQkVG\nOJHyRUzGutNh94ZmSCMc+P+n1qzeFnUBssC5FEbi/R7xvH67WsJbUXvcHbSc\nJW9zNNzyZJBmQI5Q41u6s9KeUmHJX8rTiQmABAMQSEluKVPWwwnpg3PaUft0\nXkEhNhEedlNb3bPuxROvQfehc8FN/kPf5v1Mqyl+b3uasGG92EJEHT0qUQMt\nb9wzQnopaOBStgQuvr8Tagz1mPDWo0Wc5G32ZhMzlkWWjbUZHyPY1pJEvnYv\nZE7tWw3oSW9GEGUr8TwDaPAGqkya8rCDGpE/iCXNA1dxb4Zas0OUVvV3jdbs\nRj7P+OrDnN7sBEnlfWW9n+PxicikVJ/SsHK4j0Su8kHrFgbQ3bccG5S6M+hT\njw87\r\n=xM4a\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIFAKrrIcN+rhTU6eSFEDcWZLZjQskoknfBueMlN3TTScAiEA64q/41gneCPzy3ayuP54yO7nX/N/2TFW6doBrl+y/1c="}]},"maintainers":[{"email":"andrey@maana.io","name":"abatyuk"},{"email":"bzvestey@gmail.com","name":"bzvetey"},{"email":"dlewissandy@maana.io","name":"dlsmaana"},{"email":"rob@maana.io","name":"rpovey"},{"email":"teamcity@maana.io","name":"teamcitymaana"},{"email":"witt3rd@witt3rd.com","name":"witt3rd"}],"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/q-assistant-client_3.2.2-beta.27_1583874039763_0.4768867216653623"},"_hasShrinkwrap":false},"3.2.2-beta.28":{"name":"@io-maana/q-assistant-client","version":"3.2.2-beta.28","description":"JavaScript package to streamline communication between an assistant and the Maana Q Assistant API.","main":"build/index.js","exports":{"./":"./build/"},"scripts":{"build":"babel src --out-dir build","prepack":"npm run build","test":"echo \"Error: no test specified\" && exit 1","format":"prettier --write \"src/**/*.js\""},"repository":{"type":"git","url":"git+https://github.com/maana-io/q-assistant-client.git"},"keywords":["Maana","Q"],"author":{"name":"Logan Gore @ Maana.io"},"license":"MIT","bugs":{"url":"https://github.com/maana-io/q-assistant-client/issues"},"homepage":"https://github.com/maana-io/q-assistant-client#readme","dependencies":{"core-js":"3.6.4","post-robot":"10.0.29"},"devDependencies":{"@babel/cli":"^7.5.5","@babel/core":"^7.5.5","@babel/plugin-proposal-class-properties":"^7.5.5","@babel/preset-env":"^7.5.5","prettier":"1.19.1"},"readme":"# q-assistant-client\nA lightweight JavaScript client for Maana-Q Assistant developers that wraps post-message communication between an embedded Maana-Q assistant and the Maana-Q UI.\n\n## Abstract\nThe Q-Assistant-Client is intented to be used in a web application being leveraged as a Maana Q assistant (embedded as an iframe).\nThis assistant client will facilitate communication between the assistant and the parent frame.\nThe client provides a rich, asynchronous experience over what would otherwise be 'fire-and-forget'-style messaging \nvia post-post message communication. \n\n## Requirements and Assumptions\n\n### Post-Robot Library\nThe Maana Knowledge Portal (KPortal) uses the kraken/post-robot library [kraken/post-robot](https://github.com/krakenjs/post-robot) to enrich the communication with the assistant. Post-robot allows for asynchronous, promise-based request/response style behavior between the assistant and the assistant API.\n\nThe API requires that the client use the post-robot library. This assistant-client library is the easiest way to achieve this, and also adds a fair amount of 'sugar' to the process to improve developer productivity. Developers could, however, use post-robot directly in their own client implementation. \n\n### Maana-Gateway Proxy Requirements\nThe Maana-Gateway service requires relative paths (paths relative to the root) in the assistant web application in order to proxy the application and its content. For create-react-apps, for instance, this means setting \"homepage\" to \".\" in the package.json file.\n\n## Singleton Instance\nThe client is exported as a singleton to avoid duplicate registration on event listeners.\nYou can import the instance like this:\n\n```js\nimport AssistantAPIClient from '@io-maana/q-assistant-client';\n```\n\nFunction calls can be made against the client instance like any other javascript object. They are all async.\n\n```js\nconst workspace = await AssistantAPIClient.getWorkspace(); \nconsole.log(\"Workspace:\", workspace)\n```\n\n## Dependencies\nPost-Robot\nhttps://github.com/krakenjs/post-robot\n\nPost-robot is used to provide a richer communication layer atop post-message.\n\n## Examples\n@TODO Logan\n\n## API Documentation\n\n### State management\n\n#### clearState = () =>\n\nThis will clear all ‘attached’ state between the assistant and the API. \n\nSpecifically, this will clear selection and inventory changed event listeners. \n\n```js\nawait AssistantAPIClient.clearState()\n```\n\n### User Info\nThe `UserInfo` object:\n```js\n{\n email: string,\n name: string\n}\n```\n\n#### getUserInfo = () => \n\nReturns a Userinfo object pertaining to the logged in user.\n\n```js\nconst userInfo = await AssistantAPIClient.getUserInfo()\n```\n### Selection\nThe `Selection` object:\n```js\n{\n  kindId: string\n  kindName: string\n  id: string\n}\n```\n\n#### getCurrentSelection = () => \n\nReturns an Array of `Selection` objects:\n\n```js\nconst {selection} = await AssistantAPIClient.getCurrentSelection();\n```\n\n#### addSelectionChangedListener = async cb =>\n\nAdds a callback function to be executed upon a valid workspace selection change.\n\nCallback value is an array of Selection objects:\n\n```js\n// Create the selection callback.\nconst selectionCB = ({selection})=>{\n  console.log('Workspace selection has changed.')\n  selection.forEach(i=>{\n    console.log('Kind: ',i.kindName)\n    console.log('Instance Id:',i.id)\n    console.log('Kind Id:',i.kindId)\n  })\n}\n\n// Add the listener.\nAssistantAPIClient.addSelectionChangedListener(selectionCB);\n```\n\nThis function only exists on the Q-Assistant-Client--only enableSelectionChangedNotification is called on the API. \n\n#### removeSelectionChangedListener = async cb =>\n\nThis will have to be called on a 1:1 basis with addSelectionChangedListener calls if supplying a callback.\n\n```js\nAssistantAPIClient.removeSelectionChangedListener(selectionCB)\n```\n\n**If NOT supplying a callback to this call, all selection changed listeners will be removed.\n\n```js\nAssistantAPIClient.removeSelectionChangedListener()\n```\n\nThis function only exists on the Q-Assistant-Client--only disableSelectionChangedNotification is called on the API. \n\n\n### Services\nThe `Service` object:\n```js\n{\n   id: string,\n   name: string\n   endpointUrl: string,\n   getKinds: () => // Returns [] of Kinds objects\n   getFunctions: () => // Returns [] of Function objects\n}\n```\n\n#### getServiceById = id =>\nThis will return a service that exists within the scope of the workspace. \n** Assistant services will return null. Services outside the scope of the workspace will cause an error to be returned as 'Unable to load a Service from outside of the workspace.'\n\n```js\nconst svc = await AssistantAPIClient.getServiceById(id)\n```\n\n### Workspace\nThe `Workspace` object:\n```js\n{\nid: string,\nname: string,\ngetKinds: () => {\n  // Returns an array of functions in the workspace (includes boilerplate).\n},\ngetFunctions: () =>\n  // Returns an array of functions in the workspace (includes boilerplate).\ngetActiveGraph: () => {\n  // Returns the active Graph object.\n  // Returns null if active graph is not of type 'Knowledge Graph', or if an\n  // active graph is deleted, thereby setting active graph to null.\n},\ngetKnowledgeGraphs: () => {\n  // Returns [Graph]\n},\ngetImportedServices: () => {\n  // Returns an service imported into the workspace\n  // as a array of Service object (this calls the function\n  // that underlies getServiceById.\n  // No assistant services will be returned.\n}\n}\n```\n\n#### getWorkspace = () =>\n\nReturns a Workspace object representing the workspace. \n\n```js\nconst ws = await AssistantAPIClient.getWorkspace()\n```\n\n### Graphs\nThe `Graph` object:\n```js\n{     \nid: string,\nname: string,\noffsetX: Number,\noffsetY: Number,\nzoom: Number,\ngetNodes: async () => {\n    // Returns [Node]\n},\n\naddNode: async (type, instance, changeSelection) => {\n    // Returns Node\n},\nremoveNode: async id => {\n    // Should return nothing or error.\n    // Currently returning [] in all cases.\n},\nupdateNodeLayout: async (nodeId, { x, y, collapsed }) => {\n},\nupdateGraphLayout: async ({ offsetX, offsetY, zoom }) => {\n}\n}\n```\n\n#### Getting a graph object:\nGraph objects are obtained through an instance of a Workspace \n\n```js\nconst ag = await ws.getActiveGraph()\n```\n\nor\n\n```js\nconst kgs = await ws.getKnowledgeGraphs()\n```\n\n#### Manipulating Graphs\n\n**Only the active graph may be manipulated.\n\nAll graph manipulations should be ‘visually’ verifiable on the graph itself, i.e., adds/removes/positioning, should all be reflected on the graph itself. \n\nThe `Node` object:\n```js\n{\nid: string\nx: number\ny: number\ncollapsed: boolean\nknowledgeGraphNode {\n  id: string\n  innerKind: Kind\n  innerFunction: Function\n}\n}\n```\n\n#### addNode(type, instance, changeSelection) =>\n\nTakes type (“Function” or “Kind”), instance (the Function or Kind object), and optionally a boolean to indicate whether the selection should be changed to this new node. \n\nReturns the newly created Node object.\n\n```js\nconst node = await ag.addNode('Kind',kind)\n```\n\n#### removeNode(id) =>\n\nTakes the id of Node to be deleted. Returns either undefined or an error. \n\n```js\nawait ag.removeNode(node.id)\n```\n\n#### getNodes() =>\nReturns an array of Node objects from the graph. \n\n```js\nconst nodes = await ag.getNodes()\n```\n\n#### updateNodeLayout: async (nodeId, { x, y, collapsed})=>\n\nUpdates a Node layout given a node ID and node coordinates (`x` and/or `y`) or a `collapsed` value. x/y values must be a number, and collapsed must be a boolean. Whatever is not specified will remain current.\n\n```js\nag.updateNodeLayout(id,{x:100,y:100,collapsed:true})\n```\n\n#### updateGraphLayout: async ({ offsetX, offsetY, zoom})=>\n\nUpdates a Graph layout given numerical values for x/y offsets and the zoom. \n\n```js\nag.updateGraphLayout({offsetX:50, offsetY:50, zoom: 70})\n```\n\n### Functions\n\nThe `Function` object:\n```js\n{\n    id: string\n    name: string\n    service {\n      id: string\n      name: string\n    }\n    arguments {\n      id: string\n      name: string\n      type: string\n      modifiers: Array[string]\n      typeKindId:: string\n      kind {\n        id: string\n        name: string\n      }\n    }\n    implementation {\n      id: string\n      entrypoint {\n        id: string\n      }\n      operations {\n        id: string\n        type: string\n        function {\n          id: string\n          name: string\n        }\n        argumentValues {\n          id: string\n          argument {\n            id: string\n          }\n          operation {\n            id: string\n          }\n          argumentRef: string\n        }\n      }\n    }\n    isGenerated: boolean\n    functionType: string\n    graphqlOperationType: string\n    outputType: string\n    outputKindId: string\n    outputModifiers: Array[string]\n    kind {\n      id: string\n      name: string\n    }\n}\n```\n\n`FunctionExecutionResult` object:\n```js\n{\n  id: string,\n  result: JSON\n}\n```\n\n#### executeFunction = ( {id, variables, resolve} ) =>\n\nExecutes a function based on its id, with optional inputs for variables and a resolve string (this specifies the fields to be returned, which must be valid based on the result).\n\nReturns : JSON matching shape of result , unless no sub-selection of fields is required in the execution.\n\nThis following piece of code will execute a Function given a function ID, and pass in variables for ‘example’, requesting back id and name fields. \n\n```js \nconst res = await AssistantAPIClient.executeFunction({functionId: func.id, variables: {\"variableName\": \"variableValue\"}, resolve: \"{ id name }\");\n```\n\n#### createFunction = input =>\n\nCreates a function based on the input provided. \n\nReturns: the created Function object.\n\n**Using create function will only place the function in the workspace’s inventory--it will not place the function as a node on the Graph. In order to do this, you must pass the created function into the addNode function on the active Graph, making sure to specify ‘Function' as the type.\n\n```js\nconst createFunctionInput = {\n  name:\"yourName\",\n  arguments:[],\n  outputType: \"STRING\",\n  graphqlOperationType:\"QUERY\",\n  functionType: \"CKG\"\n}\n  \nconst createdFunction = await AssistantAPIClient.createFunction(createFunctionInput)\n```\n\n#### updateFunction = input =>\n\nInput is the same for creating a function. It’s important to note that the arguments property will be replaced in it’s entirety with whatever is provided (if a value is provided.\n\nReturns the updated `Function` object.\n\n```js\nconst updatedFunction = await AssistantAPIClient.updateFunction(input);\n```\n\n#### deleteFunction = input =>\n\nInput is the id of the Function to be deleted. Returns the deleted function as a promise.\n\n```js\nconst deletedFunction = await AssistantAPIClient.deleteFunction('id...');\n```\n\n#### getFunctionById = id =>\n\nReturns a Function as a promise based on the ID provided.\n\n```js\nconst func = await AssistantAPIClient.getFunctionById('id...');\n```\n\n#### addFunctionExecutionListener = async (id, cb) =>\n\nAssociates a callback function with the execution of a particular Function. When the Function matching the id parameter is executed, its FunctionExecutionResult object passed to the callback. Returns undefined.\n\nExample function execution callback and listener registration:\n\n```js\nfunction exampleFunctionCB (result){\n  console.log(`Function executed with result:`, result)\n}\n\nAssistantAPIClient.addFunctionExecutionListener('id...', exampleFunctionCB)\n```\n\n#### removeFunctionExecutionListener = async (id, cb) =>\n\nRemoves a Function execution listener based on the function ID and a reference to the callback function. If no callback is supplied, all listeners associated with the Function ID will be removed. Returns undefined.\n\n```js\nAssistantAPIClient.removeFunctionExecutionListener('id..', exampleFunctionCB)\n```\n\n### Kinds\nThe `Kind` object:\n```js\n{\n    id: string\n    name: string\n    service: {\n      id\n      name\n    }\n    isGenerated: boolean\n    schema {\n      id: string\n      name: string\n      type: string\n      typeKindId: string\n      modifiers: Array[string]\n      kind {\n        id: string\n        name: string\n      }\n    }\n}\n```\n\n#### createKind = input =>\n\nCreates a Kind based on an input object. Returns a promise that resolves to the created Kind object.\n\n```js\nconst kindInput = {\n name: \"someKind\",\n schema:[\n  { name: \"someField1\", type: STRING },\n  { name: \"someField2\", type: STRING }\n ]\n}\n\nconst newKind = await AssistantAPIClient.createKind(kindInput)\n```\n\n#### updateKind = input =>\n\nUpdates a Kind based on an input object. \n\nUpdate Semantics: Only properties specified will be updated. If updating the schema, the entire schema must be specified as it will be replaced in its entirety. \n\nReturns the updated `Kind` object.\n\n```js\nconst updated = await AssistantAPIClient.updateKind(input)\n```\n\n#### deleteKind = input =>\n\nDeletes a Kind given a kind ID.\n\n```js\nconst deleted = await AssistantAPIClient.deleteKind(input)\n```\n\n#### getKindById = id =>\n\nReturns a promise that resolves to a Kind object given the specified kind ID. Only kinds in the workspace or those of imported services will be returned. \n\n```js\nconst kind = await AssistantAPIClient.getKindById(id)\n```\n\n### Inventory\n\nThe `InventoryChanged` object:\n```js\n{\n  kinds: {\n    adds: [DiffItem]\n    deletes: [DiffItem]\n    updates: [DiffItem]\n  }\n  functions:{\n    adds: [DiffItem]\n    deletes: [DiffItem]\n    updates: [DiffItem]\n  }\n  services: {\n    adds: [DiffItem]\n    deletes: [DiffItem]\n    updates: [DiffItem]\n  }\n}\n```\n\nThe `DiffItem` object:\n```js\n{\n  id: string,\n  name: string\n}\n```\n\n#### addInventoryChangedListener = async cb =>\n\nRegisters a callback function with the inventory changed event. When workspace inventory changes the callback function will be called with the InventoryChangedobject. Returns undefined.\n\n*Current limitations: Kind and Function updates only occur where the name property is changed. Updates to services outside of the workspace will not be detected. \n\n**Use-case note: an ‘update’ diff for inventory services is unlikely in general usage. \n\n```js\nconst inventoryCB = ({diff}) => {\n  if(diff.kinds) console.log('KINDS CHANGED',diff.kinds)\n  if(diff.functions) console.log('FUNCTIONS CHANGED', diff.functions)\n  if(diff.services) console.log('SERVICES CHANGED',diff.services)\n}\n\nAssistantAPIClient.addInventoryChangedListener(inventoryCB)\n```\n\nThis function exists on the Q-Assisant-Client only--only enableSelectionChangedNotification is used on the API side. \n\n#### removeInventoryChangedListener = async cb =>\n\nRemoves an inventory changed listener given the referenced callback. If no callback is specified, all listeners will be removed. Returns undefined.\n\n```js\nAssistantAPIClient.removeInventoryChangedListener(inventoryCB)\n```\n\nThis function exists on the Q-Assisant-Client only--only disableSelectionChangedNotification is used on the API side. \n\n## Troubleshooting Assistant Issues\n### Assistant root file has loaded, but not other content\nObserving in the browser's dev tools that some resources have loaded correctly (usually the root), but other's haven't (usually nested files or chunks), is indicative of a failure of Q Gateway to proxy due to not having a 'relative' path structure.\n\n### You are seeing post-robot `NO ACK` errors in the console.\nThese errors stem from a failed acknowledgement for a call either between the client and the API or vice-versa. Here, this means that the web app 'window' (the assistant) cannot communicate with, or access, the 'window.parent' (Maana K-Portal) object. Improper CORS configuration is a common culprit (also verify if using docker or nginx that your proxying and networking is configured correctly to allow communication and to accout for CORS).","readmeFilename":"README.md","gitHead":"3ff4fac02b4056dd6432436f135f999db4ed5c29","_id":"@io-maana/q-assistant-client@3.2.2-beta.28","_npmVersion":"6.4.1","_nodeVersion":"10.15.3","_npmUser":{"name":"teamcitymaana","email":"teamcity@maana.io"},"dist":{"integrity":"sha512-g4540VHaR7zjVcQ0iYB79KJoxtQ/FCFev8Lci98fOVn+2vjPHfOlLOhBF1pqM6rGktgwk9yBNkIu9nxyPMRxeg==","shasum":"76f96805335495319bbbb553cd538fb55d7dcc50","tarball":"https://registry.npmjs.org/@io-maana/q-assistant-client/-/q-assistant-client-3.2.2-beta.28.tgz","fileCount":10,"unpackedSize":48386,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJeg2w5CRA9TVsSAnZWagAAtaYP/iFU7epg0l7n2ZUDvlGz\nfXOWD5NxQS5ipPhdEZmXMWfPOpGLoOkqxZB5s1yMLxqOD6LVM7KdZZLQ8AUP\nDPeYTEpwyTDQ8MAjotjohBjWx7Qyr3kBso4ZD7+6gXG8kNTm1mNfP1BVVWGV\nYRnDPyH6mmQIK5ba/+8N37/7cbeGrRswNVoOaTnzBPuNGFe4opxGpFt94Ni+\ncC+Suskmn2U+c7cHc4In2lHnViJxooBy+TF2hvpV3Ku/iHaqKzfV2fcezLTy\nJX9dfKtCn0AOpw3OnrUv/Jfozgl6DzOxwNyCx1A+BnF92yM3wqzEJyYiysn7\n7qXv7NgsnSgJq59CqiIyQhZTujo7ib2wgblslm1ynxocz6t85PQ37HmzqxtF\ngk54vlyGt51e/pdYts76pRRMixTlkI4x/tmWzaAzH9Q4uXPAjnjRI0BO8wGj\nq7svlwblZZWgFeqk04xK5QAxkx4+4oPOIAgHIqWEO0J3A8F//VHEt15epemu\nruzcaGOkqklYaDQMfGibKJ1ZPwHv4hH342pmhU8XPtyoC0mc48YOleY03zRe\nngZ++Vr4k1/cTcNCnlnprsvDSJ+CqbAEFstNNMxUNOgukVLBquLi9CIAHTWM\ng8IABHUnqHW7WOvZu9Z+ToE4D6j+KzJs4/2D7K4lzYjAOVS5Aq0D68oIvx4b\nmzpU\r\n=Q56p\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIQCHJTU5NhS7du535HUOB5LPG9UVy+ilqiOVL8Hki3nMEAIgCxHobb2iHb4xt69vcyP7dwomn588S4/77xvMaGcTecY="}]},"maintainers":[{"email":"andrey@maana.io","name":"abatyuk"},{"email":"bzvestey@gmail.com","name":"bzvetey"},{"email":"dlewissandy@maana.io","name":"dlsmaana"},{"email":"rob@maana.io","name":"rpovey"},{"email":"teamcity@maana.io","name":"teamcitymaana"},{"email":"witt3rd@witt3rd.com","name":"witt3rd"}],"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/q-assistant-client_3.2.2-beta.28_1585671225321_0.5708906887305318"},"_hasShrinkwrap":false},"3.2.2-beta.29":{"name":"@io-maana/q-assistant-client","version":"3.2.2-beta.29","description":"JavaScript package to streamline communication between an assistant and the Maana Q Assistant API.","main":"build/index.js","exports":{"./":"./build/"},"scripts":{"build":"babel src --out-dir build","prepack":"npm run build","test":"echo \"Error: no test specified\" && exit 1","format":"prettier --write \"src/**/*.js\""},"repository":{"type":"git","url":"git+https://github.com/maana-io/q-assistant-client.git"},"keywords":["Maana","Q"],"author":{"name":"Logan Gore @ Maana.io"},"license":"MIT","bugs":{"url":"https://github.com/maana-io/q-assistant-client/issues"},"homepage":"https://github.com/maana-io/q-assistant-client#readme","dependencies":{"core-js":"3.6.4","post-robot":"10.0.29"},"devDependencies":{"@babel/cli":"^7.5.5","@babel/core":"^7.5.5","@babel/plugin-proposal-class-properties":"^7.5.5","@babel/preset-env":"^7.5.5","prettier":"1.19.1"},"readme":"# q-assistant-client\nA lightweight JavaScript client for Maana-Q Assistant developers that wraps post-message communication between an embedded Maana-Q assistant and the Maana-Q UI.\n\n## Abstract\nThe Q-Assistant-Client is intented to be used in a web application being leveraged as a Maana Q assistant (embedded as an iframe).\nThis assistant client will facilitate communication between the assistant and the parent frame.\nThe client provides a rich, asynchronous experience over what would otherwise be 'fire-and-forget'-style messaging \nvia post-post message communication. \n\n## Requirements and Assumptions\n\n### Post-Robot Library\nThe Maana Knowledge Portal (KPortal) uses the kraken/post-robot library [kraken/post-robot](https://github.com/krakenjs/post-robot) to enrich the communication with the assistant. Post-robot allows for asynchronous, promise-based request/response style behavior between the assistant and the assistant API.\n\nThe API requires that the client use the post-robot library. This assistant-client library is the easiest way to achieve this, and also adds a fair amount of 'sugar' to the process to improve developer productivity. Developers could, however, use post-robot directly in their own client implementation. \n\n### Maana-Gateway Proxy Requirements\nThe Maana-Gateway service requires relative paths (paths relative to the root) in the assistant web application in order to proxy the application and its content. For create-react-apps, for instance, this means setting \"homepage\" to \".\" in the package.json file.\n\n## Singleton Instance\nThe client is exported as a singleton to avoid duplicate registration on event listeners.\nYou can import the instance like this:\n\n```js\nimport AssistantAPIClient from '@io-maana/q-assistant-client';\n```\n\nFunction calls can be made against the client instance like any other javascript object. They are all async.\n\n```js\nconst workspace = await AssistantAPIClient.getWorkspace(); \nconsole.log(\"Workspace:\", workspace)\n```\n\n## Dependencies\nPost-Robot\nhttps://github.com/krakenjs/post-robot\n\nPost-robot is used to provide a richer communication layer atop post-message.\n\n## Examples\n@TODO Logan\n\n## API Documentation\n\n### State management\n\n#### clearState = () =>\n\nThis will clear all ‘attached’ state between the assistant and the API. \n\nSpecifically, this will clear selection and inventory changed event listeners. \n\n```js\nawait AssistantAPIClient.clearState()\n```\n\n### User Info\nThe `UserInfo` object:\n```js\n{\n email: string,\n name: string\n}\n```\n\n#### getUserInfo = () => \n\nReturns a Userinfo object pertaining to the logged in user.\n\n```js\nconst userInfo = await AssistantAPIClient.getUserInfo()\n```\n### Selection\nThe `Selection` object:\n```js\n{\n  kindId: string\n  kindName: string\n  id: string\n}\n```\n\n#### getCurrentSelection = () => \n\nReturns an Array of `Selection` objects:\n\n```js\nconst {selection} = await AssistantAPIClient.getCurrentSelection();\n```\n\n#### addSelectionChangedListener = async cb =>\n\nAdds a callback function to be executed upon a valid workspace selection change.\n\nCallback value is an array of Selection objects:\n\n```js\n// Create the selection callback.\nconst selectionCB = ({selection})=>{\n  console.log('Workspace selection has changed.')\n  selection.forEach(i=>{\n    console.log('Kind: ',i.kindName)\n    console.log('Instance Id:',i.id)\n    console.log('Kind Id:',i.kindId)\n  })\n}\n\n// Add the listener.\nAssistantAPIClient.addSelectionChangedListener(selectionCB);\n```\n\nThis function only exists on the Q-Assistant-Client--only enableSelectionChangedNotification is called on the API. \n\n#### removeSelectionChangedListener = async cb =>\n\nThis will have to be called on a 1:1 basis with addSelectionChangedListener calls if supplying a callback.\n\n```js\nAssistantAPIClient.removeSelectionChangedListener(selectionCB)\n```\n\n**If NOT supplying a callback to this call, all selection changed listeners will be removed.\n\n```js\nAssistantAPIClient.removeSelectionChangedListener()\n```\n\nThis function only exists on the Q-Assistant-Client--only disableSelectionChangedNotification is called on the API. \n\n\n### Services\nThe `Service` object:\n```js\n{\n   id: string,\n   name: string\n   endpointUrl: string,\n   getKinds: () => // Returns [] of Kinds objects\n   getFunctions: () => // Returns [] of Function objects\n}\n```\n\n#### getServiceById = id =>\nThis will return a service that exists within the scope of the workspace. \n** Assistant services will return null. Services outside the scope of the workspace will cause an error to be returned as 'Unable to load a Service from outside of the workspace.'\n\n```js\nconst svc = await AssistantAPIClient.getServiceById(id)\n```\n\n### Workspace\nThe `Workspace` object:\n```js\n{\nid: string,\nname: string,\ngetKinds: () => {\n  // Returns an array of functions in the workspace (includes boilerplate).\n},\ngetFunctions: () =>\n  // Returns an array of functions in the workspace (includes boilerplate).\ngetActiveGraph: () => {\n  // Returns the active Graph object.\n  // Returns null if active graph is not of type 'Knowledge Graph', or if an\n  // active graph is deleted, thereby setting active graph to null.\n},\ngetKnowledgeGraphs: () => {\n  // Returns [Graph]\n},\ngetImportedServices: () => {\n  // Returns an service imported into the workspace\n  // as a array of Service object (this calls the function\n  // that underlies getServiceById.\n  // No assistant services will be returned.\n}\n}\n```\n\n#### getWorkspace = () =>\n\nReturns a Workspace object representing the workspace. \n\n```js\nconst ws = await AssistantAPIClient.getWorkspace()\n```\n\n### Graphs\nThe `Graph` object:\n```js\n{     \nid: string,\nname: string,\noffsetX: Number,\noffsetY: Number,\nzoom: Number,\ngetNodes: async () => {\n    // Returns [Node]\n},\n\naddNode: async (type, instance, changeSelection) => {\n    // Returns Node\n},\nremoveNode: async id => {\n    // Should return nothing or error.\n    // Currently returning [] in all cases.\n},\nupdateNodeLayout: async (nodeId, { x, y, collapsed }) => {\n},\nupdateGraphLayout: async ({ offsetX, offsetY, zoom }) => {\n}\n}\n```\n\n#### Getting a graph object:\nGraph objects are obtained through an instance of a Workspace \n\n```js\nconst ag = await ws.getActiveGraph()\n```\n\nor\n\n```js\nconst kgs = await ws.getKnowledgeGraphs()\n```\n\n#### Manipulating Graphs\n\n**Only the active graph may be manipulated.\n\nAll graph manipulations should be ‘visually’ verifiable on the graph itself, i.e., adds/removes/positioning, should all be reflected on the graph itself. \n\nThe `Node` object:\n```js\n{\nid: string\nx: number\ny: number\ncollapsed: boolean\nknowledgeGraphNode {\n  id: string\n  innerKind: Kind\n  innerFunction: Function\n}\n}\n```\n\n#### addNode(type, instance, changeSelection) =>\n\nTakes type (“Function” or “Kind”), instance (the Function or Kind object), and optionally a boolean to indicate whether the selection should be changed to this new node. \n\nReturns the newly created Node object.\n\n```js\nconst node = await ag.addNode('Kind',kind)\n```\n\n#### removeNode(id) =>\n\nTakes the id of Node to be deleted. Returns either undefined or an error. \n\n```js\nawait ag.removeNode(node.id)\n```\n\n#### getNodes() =>\nReturns an array of Node objects from the graph. \n\n```js\nconst nodes = await ag.getNodes()\n```\n\n#### updateNodeLayout: async (nodeId, { x, y, collapsed})=>\n\nUpdates a Node layout given a node ID and node coordinates (`x` and/or `y`) or a `collapsed` value. x/y values must be a number, and collapsed must be a boolean. Whatever is not specified will remain current.\n\n```js\nag.updateNodeLayout(id,{x:100,y:100,collapsed:true})\n```\n\n#### updateGraphLayout: async ({ offsetX, offsetY, zoom})=>\n\nUpdates a Graph layout given numerical values for x/y offsets and the zoom. \n\n```js\nag.updateGraphLayout({offsetX:50, offsetY:50, zoom: 70})\n```\n\n### Functions\n\nThe `Function` object:\n```js\n{\n    id: string\n    name: string\n    service {\n      id: string\n      name: string\n    }\n    arguments {\n      id: string\n      name: string\n      type: string\n      modifiers: Array[string]\n      typeKindId:: string\n      kind {\n        id: string\n        name: string\n      }\n    }\n    implementation {\n      id: string\n      entrypoint {\n        id: string\n      }\n      operations {\n        id: string\n        type: string\n        function {\n          id: string\n          name: string\n        }\n        argumentValues {\n          id: string\n          argument {\n            id: string\n          }\n          operation {\n            id: string\n          }\n          argumentRef: string\n        }\n      }\n    }\n    isGenerated: boolean\n    functionType: string\n    graphqlOperationType: string\n    outputType: string\n    outputKindId: string\n    outputModifiers: Array[string]\n    kind {\n      id: string\n      name: string\n    }\n}\n```\n\n`FunctionExecutionResult` object:\n```js\n{\n  id: string,\n  result: JSON\n}\n```\n\n#### executeFunction = ( {id, variables, resolve} ) =>\n\nExecutes a function based on its id, with optional inputs for variables and a resolve string (this specifies the fields to be returned, which must be valid based on the result).\n\nReturns : JSON matching shape of result , unless no sub-selection of fields is required in the execution.\n\nThis following piece of code will execute a Function given a function ID, and pass in variables for ‘example’, requesting back id and name fields. \n\n```js \nconst res = await AssistantAPIClient.executeFunction({functionId: func.id, variables: {\"variableName\": \"variableValue\"}, resolve: \"{ id name }\");\n```\n\n#### createFunction = input =>\n\nCreates a function based on the input provided. \n\nReturns: the created Function object.\n\n**Using create function will only place the function in the workspace’s inventory--it will not place the function as a node on the Graph. In order to do this, you must pass the created function into the addNode function on the active Graph, making sure to specify ‘Function' as the type.\n\n```js\nconst createFunctionInput = {\n  name:\"yourName\",\n  arguments:[],\n  outputType: \"STRING\",\n  graphqlOperationType:\"QUERY\",\n  functionType: \"CKG\"\n}\n  \nconst createdFunction = await AssistantAPIClient.createFunction(createFunctionInput)\n```\n\n#### updateFunction = input =>\n\nInput is the same for creating a function. It’s important to note that the arguments property will be replaced in it’s entirety with whatever is provided (if a value is provided.\n\nReturns the updated `Function` object.\n\n```js\nconst updatedFunction = await AssistantAPIClient.updateFunction(input);\n```\n\n#### deleteFunction = input =>\n\nInput is the id of the Function to be deleted. Returns the deleted function as a promise.\n\n```js\nconst deletedFunction = await AssistantAPIClient.deleteFunction('id...');\n```\n\n#### getFunctionById = id =>\n\nReturns a Function as a promise based on the ID provided.\n\n```js\nconst func = await AssistantAPIClient.getFunctionById('id...');\n```\n\n#### addFunctionExecutionListener = async (id, cb) =>\n\nAssociates a callback function with the execution of a particular Function. When the Function matching the id parameter is executed, its FunctionExecutionResult object passed to the callback. Returns undefined.\n\nExample function execution callback and listener registration:\n\n```js\nfunction exampleFunctionCB (result){\n  console.log(`Function executed with result:`, result)\n}\n\nAssistantAPIClient.addFunctionExecutionListener('id...', exampleFunctionCB)\n```\n\n#### removeFunctionExecutionListener = async (id, cb) =>\n\nRemoves a Function execution listener based on the function ID and a reference to the callback function. If no callback is supplied, all listeners associated with the Function ID will be removed. Returns undefined.\n\n```js\nAssistantAPIClient.removeFunctionExecutionListener('id..', exampleFunctionCB)\n```\n\n### Kinds\nThe `Kind` object:\n```js\n{\n    id: string\n    name: string\n    service: {\n      id\n      name\n    }\n    isGenerated: boolean\n    schema {\n      id: string\n      name: string\n      type: string\n      typeKindId: string\n      modifiers: Array[string]\n      kind {\n        id: string\n        name: string\n      }\n    }\n}\n```\n\n#### createKind = input =>\n\nCreates a Kind based on an input object. Returns a promise that resolves to the created Kind object.\n\n```js\nconst kindInput = {\n name: \"someKind\",\n schema:[\n  { name: \"someField1\", type: STRING },\n  { name: \"someField2\", type: STRING }\n ]\n}\n\nconst newKind = await AssistantAPIClient.createKind(kindInput)\n```\n\n#### updateKind = input =>\n\nUpdates a Kind based on an input object. \n\nUpdate Semantics: Only properties specified will be updated. If updating the schema, the entire schema must be specified as it will be replaced in its entirety. \n\nReturns the updated `Kind` object.\n\n```js\nconst updated = await AssistantAPIClient.updateKind(input)\n```\n\n#### deleteKind = input =>\n\nDeletes a Kind given a kind ID.\n\n```js\nconst deleted = await AssistantAPIClient.deleteKind(input)\n```\n\n#### getKindById = id =>\n\nReturns a promise that resolves to a Kind object given the specified kind ID. Only kinds in the workspace or those of imported services will be returned. \n\n```js\nconst kind = await AssistantAPIClient.getKindById(id)\n```\n\n### Inventory\n\nThe `InventoryChanged` object:\n```js\n{\n  kinds: {\n    adds: [DiffItem]\n    deletes: [DiffItem]\n    updates: [DiffItem]\n  }\n  functions:{\n    adds: [DiffItem]\n    deletes: [DiffItem]\n    updates: [DiffItem]\n  }\n  services: {\n    adds: [DiffItem]\n    deletes: [DiffItem]\n    updates: [DiffItem]\n  }\n}\n```\n\nThe `DiffItem` object:\n```js\n{\n  id: string,\n  name: string\n}\n```\n\n#### addInventoryChangedListener = async cb =>\n\nRegisters a callback function with the inventory changed event. When workspace inventory changes the callback function will be called with the InventoryChangedobject. Returns undefined.\n\n*Current limitations: Kind and Function updates only occur where the name property is changed. Updates to services outside of the workspace will not be detected. \n\n**Use-case note: an ‘update’ diff for inventory services is unlikely in general usage. \n\n```js\nconst inventoryCB = ({diff}) => {\n  if(diff.kinds) console.log('KINDS CHANGED',diff.kinds)\n  if(diff.functions) console.log('FUNCTIONS CHANGED', diff.functions)\n  if(diff.services) console.log('SERVICES CHANGED',diff.services)\n}\n\nAssistantAPIClient.addInventoryChangedListener(inventoryCB)\n```\n\nThis function exists on the Q-Assisant-Client only--only enableSelectionChangedNotification is used on the API side. \n\n#### removeInventoryChangedListener = async cb =>\n\nRemoves an inventory changed listener given the referenced callback. If no callback is specified, all listeners will be removed. Returns undefined.\n\n```js\nAssistantAPIClient.removeInventoryChangedListener(inventoryCB)\n```\n\nThis function exists on the Q-Assisant-Client only--only disableSelectionChangedNotification is used on the API side. \n\n## Troubleshooting Assistant Issues\n### Assistant root file has loaded, but not other content\nObserving in the browser's dev tools that some resources have loaded correctly (usually the root), but other's haven't (usually nested files or chunks), is indicative of a failure of Q Gateway to proxy due to not having a 'relative' path structure.\n\n### You are seeing post-robot `NO ACK` errors in the console.\nThese errors stem from a failed acknowledgement for a call either between the client and the API or vice-versa. Here, this means that the web app 'window' (the assistant) cannot communicate with, or access, the 'window.parent' (Maana K-Portal) object. Improper CORS configuration is a common culprit (also verify if using docker or nginx that your proxying and networking is configured correctly to allow communication and to accout for CORS).","readmeFilename":"README.md","gitHead":"3ff4fac02b4056dd6432436f135f999db4ed5c29","_id":"@io-maana/q-assistant-client@3.2.2-beta.29","_npmVersion":"6.4.1","_nodeVersion":"10.15.3","_npmUser":{"name":"teamcitymaana","email":"teamcity@maana.io"},"dist":{"integrity":"sha512-dXb/e/4uKMa2/8nCE4XMyrSd/0xYALkm87ztz84GVwO0VGOlrexrJUX6KtPTtbssg4VlFLmQioVdzXaUyAcxQA==","shasum":"6aa9d3664476a26897bd61fca01e18d94b2dc0a9","tarball":"https://registry.npmjs.org/@io-maana/q-assistant-client/-/q-assistant-client-3.2.2-beta.29.tgz","fileCount":10,"unpackedSize":48386,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJeg3GQCRA9TVsSAnZWagAAxIsP/2D7OfESZa+ulGyQ+4JJ\nTwSqdf3DZOvTIKAx/Tbm1Y6lDgeMxBcI7jRYVgpLHMmq/xf7TUkDQZuJnAf7\n1wY+fFCmKae8k9iiJLUiknWOTc96a03yV1GMScZBhUP3nLEU8a4sHn5KaYV4\nvHa8BeqiR5MHOc1hFTQmNslrk8oSmFcSGW2qurswm43fERNQ8kcieTI/j0BY\nVmgPrvIw8Umtj3bXKtmjtsyZumt3LnIbSsXlusIC5+kvRDU99DFQY46Cc8mg\nZJ/LGs1xG11oPZPw4vZOsRW9yfA2QtNPSlYZpwaa8czGKmeNIaJiu/pmC4cu\nxyEtWWM8xDdjw+mqEt3D6sM+4KxHG0qRA5xbcx1wEQhw89J11TU8nsRED+Vf\n8HR6NwiZObArXukjWmjKwTccWeShWlMFzLeqesT2PzcB+M8NTdT4d1/KKLAQ\n4BRIS8PiK6jLgjdM+T1XgrfURlYko4x0XJzS10RK1d8xT0cydwJnQB7AaxS5\nkhTvTqdMhoVKUJDu8vYo2HMETGV7olC3nGUHo6dgpy+eN8kip0ql9Y7ksFDX\np123Qx0pWlMpfsOvFEzyTPLtuAfJUoiQa2bC8m+j9DS0WS7utspcUs8ae/S4\nyqLTUtcZO6ZFijF+fd/5EzkXFcHNAlzUiNn6Bcub7K18B11YZmP9YU9PrJiS\neVvj\r\n=5dgR\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEQCIE+RvykGoBZDb0smum8A1uQeKurFuhiIygiJK0CA1X6sAiBzi7js/IvALgRmGowx9m+DigU6VGrxHbbzaufgG//qAA=="}]},"maintainers":[{"email":"andrey@maana.io","name":"abatyuk"},{"email":"bzvestey@gmail.com","name":"bzvetey"},{"email":"dlewissandy@maana.io","name":"dlsmaana"},{"email":"rob@maana.io","name":"rpovey"},{"email":"teamcity@maana.io","name":"teamcitymaana"},{"email":"witt3rd@witt3rd.com","name":"witt3rd"}],"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/q-assistant-client_3.2.2-beta.29_1585672591560_0.4181847770294258"},"_hasShrinkwrap":false},"3.2.2-beta.30":{"name":"@io-maana/q-assistant-client","version":"3.2.2-beta.30","description":"JavaScript package to streamline communication between an assistant and the Maana Q Assistant API.","main":"build/index.js","exports":{"./":"./build/"},"scripts":{"build":"babel src --out-dir build","prepack":"npm run build","test":"echo \"Error: no test specified\" && exit 1","format":"prettier --write \"src/**/*.js\""},"repository":{"type":"git","url":"git+https://github.com/maana-io/q-assistant-client.git"},"keywords":["Maana","Q"],"author":{"name":"Logan Gore @ Maana.io"},"license":"MIT","bugs":{"url":"https://github.com/maana-io/q-assistant-client/issues"},"homepage":"https://github.com/maana-io/q-assistant-client#readme","dependencies":{"core-js":"3.6.4","post-robot":"10.0.29"},"devDependencies":{"@babel/cli":"^7.5.5","@babel/core":"^7.5.5","@babel/plugin-proposal-class-properties":"^7.5.5","@babel/preset-env":"^7.5.5","prettier":"1.19.1"},"readme":"# q-assistant-client\nA lightweight JavaScript client for Maana-Q Assistant developers that wraps post-message communication between an embedded Maana-Q assistant and the Maana-Q UI.\n\n## Abstract\nThe Q-Assistant-Client is intented to be used in a web application being leveraged as a Maana Q assistant (embedded as an iframe).\nThis assistant client will facilitate communication between the assistant and the parent frame.\nThe client provides a rich, asynchronous experience over what would otherwise be 'fire-and-forget'-style messaging \nvia post-post message communication. \n\n## Requirements and Assumptions\n\n### Post-Robot Library\nThe Maana Knowledge Portal (KPortal) uses the kraken/post-robot library [kraken/post-robot](https://github.com/krakenjs/post-robot) to enrich the communication with the assistant. Post-robot allows for asynchronous, promise-based request/response style behavior between the assistant and the assistant API.\n\nThe API requires that the client use the post-robot library. This assistant-client library is the easiest way to achieve this, and also adds a fair amount of 'sugar' to the process to improve developer productivity. Developers could, however, use post-robot directly in their own client implementation. \n\n### Maana-Gateway Proxy Requirements\nThe Maana-Gateway service requires relative paths (paths relative to the root) in the assistant web application in order to proxy the application and its content. For create-react-apps, for instance, this means setting \"homepage\" to \".\" in the package.json file.\n\n## Singleton Instance\nThe client is exported as a singleton to avoid duplicate registration on event listeners.\nYou can import the instance like this:\n\n```js\nimport AssistantAPIClient from '@io-maana/q-assistant-client';\n```\n\nFunction calls can be made against the client instance like any other javascript object. They are all async.\n\n```js\nconst workspace = await AssistantAPIClient.getWorkspace(); \nconsole.log(\"Workspace:\", workspace)\n```\n\n## Dependencies\nPost-Robot\nhttps://github.com/krakenjs/post-robot\n\nPost-robot is used to provide a richer communication layer atop post-message.\n\n## Examples\n@TODO Logan\n\n## API Documentation\n\n### State management\n\n#### clearState = () =>\n\nThis will clear all ‘attached’ state between the assistant and the API. \n\nSpecifically, this will clear selection and inventory changed event listeners. \n\n```js\nawait AssistantAPIClient.clearState()\n```\n\n### User Info\nThe `UserInfo` object:\n```js\n{\n email: string,\n name: string\n}\n```\n\n#### getUserInfo = () => \n\nReturns a Userinfo object pertaining to the logged in user.\n\n```js\nconst userInfo = await AssistantAPIClient.getUserInfo()\n```\n### Selection\nThe `Selection` object:\n```js\n{\n  kindId: string\n  kindName: string\n  id: string\n}\n```\n\n#### getCurrentSelection = () => \n\nReturns an Array of `Selection` objects:\n\n```js\nconst {selection} = await AssistantAPIClient.getCurrentSelection();\n```\n\n#### addSelectionChangedListener = async cb =>\n\nAdds a callback function to be executed upon a valid workspace selection change.\n\nCallback value is an array of Selection objects:\n\n```js\n// Create the selection callback.\nconst selectionCB = ({selection})=>{\n  console.log('Workspace selection has changed.')\n  selection.forEach(i=>{\n    console.log('Kind: ',i.kindName)\n    console.log('Instance Id:',i.id)\n    console.log('Kind Id:',i.kindId)\n  })\n}\n\n// Add the listener.\nAssistantAPIClient.addSelectionChangedListener(selectionCB);\n```\n\nThis function only exists on the Q-Assistant-Client--only enableSelectionChangedNotification is called on the API. \n\n#### removeSelectionChangedListener = async cb =>\n\nThis will have to be called on a 1:1 basis with addSelectionChangedListener calls if supplying a callback.\n\n```js\nAssistantAPIClient.removeSelectionChangedListener(selectionCB)\n```\n\n**If NOT supplying a callback to this call, all selection changed listeners will be removed.\n\n```js\nAssistantAPIClient.removeSelectionChangedListener()\n```\n\nThis function only exists on the Q-Assistant-Client--only disableSelectionChangedNotification is called on the API. \n\n\n### Services\nThe `Service` object:\n```js\n{\n   id: string,\n   name: string\n   endpointUrl: string,\n   getKinds: () => // Returns [] of Kinds objects\n   getFunctions: () => // Returns [] of Function objects\n}\n```\n\n#### getServiceById = id =>\nThis will return a service that exists within the scope of the workspace. \n** Assistant services will return null. Services outside the scope of the workspace will cause an error to be returned as 'Unable to load a Service from outside of the workspace.'\n\n```js\nconst svc = await AssistantAPIClient.getServiceById(id)\n```\n\n### Workspace\nThe `Workspace` object:\n```js\n{\nid: string,\nname: string,\ngetKinds: () => {\n  // Returns an array of functions in the workspace (includes boilerplate).\n},\ngetFunctions: () =>\n  // Returns an array of functions in the workspace (includes boilerplate).\ngetActiveGraph: () => {\n  // Returns the active Graph object.\n  // Returns null if active graph is not of type 'Knowledge Graph', or if an\n  // active graph is deleted, thereby setting active graph to null.\n},\ngetKnowledgeGraphs: () => {\n  // Returns [Graph]\n},\ngetImportedServices: () => {\n  // Returns an service imported into the workspace\n  // as a array of Service object (this calls the function\n  // that underlies getServiceById.\n  // No assistant services will be returned.\n}\n}\n```\n\n#### getWorkspace = () =>\n\nReturns a Workspace object representing the workspace. \n\n```js\nconst ws = await AssistantAPIClient.getWorkspace()\n```\n\n### Graphs\nThe `Graph` object:\n```js\n{     \nid: string,\nname: string,\noffsetX: Number,\noffsetY: Number,\nzoom: Number,\ngetNodes: async () => {\n    // Returns [Node]\n},\n\naddNode: async (type, instance, changeSelection) => {\n    // Returns Node\n},\nremoveNode: async id => {\n    // Should return nothing or error.\n    // Currently returning [] in all cases.\n},\nupdateNodeLayout: async (nodeId, { x, y, collapsed }) => {\n},\nupdateGraphLayout: async ({ offsetX, offsetY, zoom }) => {\n}\n}\n```\n\n#### Getting a graph object:\nGraph objects are obtained through an instance of a Workspace \n\n```js\nconst ag = await ws.getActiveGraph()\n```\n\nor\n\n```js\nconst kgs = await ws.getKnowledgeGraphs()\n```\n\n#### Manipulating Graphs\n\n**Only the active graph may be manipulated.\n\nAll graph manipulations should be ‘visually’ verifiable on the graph itself, i.e., adds/removes/positioning, should all be reflected on the graph itself. \n\nThe `Node` object:\n```js\n{\nid: string\nx: number\ny: number\ncollapsed: boolean\nknowledgeGraphNode {\n  id: string\n  innerKind: Kind\n  innerFunction: Function\n}\n}\n```\n\n#### addNode(type, instance, changeSelection) =>\n\nTakes type (“Function” or “Kind”), instance (the Function or Kind object), and optionally a boolean to indicate whether the selection should be changed to this new node. \n\nReturns the newly created Node object.\n\n```js\nconst node = await ag.addNode('Kind',kind)\n```\n\n#### removeNode(id) =>\n\nTakes the id of Node to be deleted. Returns either undefined or an error. \n\n```js\nawait ag.removeNode(node.id)\n```\n\n#### getNodes() =>\nReturns an array of Node objects from the graph. \n\n```js\nconst nodes = await ag.getNodes()\n```\n\n#### updateNodeLayout: async (nodeId, { x, y, collapsed})=>\n\nUpdates a Node layout given a node ID and node coordinates (`x` and/or `y`) or a `collapsed` value. x/y values must be a number, and collapsed must be a boolean. Whatever is not specified will remain current.\n\n```js\nag.updateNodeLayout(id,{x:100,y:100,collapsed:true})\n```\n\n#### updateGraphLayout: async ({ offsetX, offsetY, zoom})=>\n\nUpdates a Graph layout given numerical values for x/y offsets and the zoom. \n\n```js\nag.updateGraphLayout({offsetX:50, offsetY:50, zoom: 70})\n```\n\n### Functions\n\nThe `Function` object:\n```js\n{\n    id: string\n    name: string\n    service {\n      id: string\n      name: string\n    }\n    arguments {\n      id: string\n      name: string\n      type: string\n      modifiers: Array[string]\n      typeKindId:: string\n      kind {\n        id: string\n        name: string\n      }\n    }\n    implementation {\n      id: string\n      entrypoint {\n        id: string\n      }\n      operations {\n        id: string\n        type: string\n        function {\n          id: string\n          name: string\n        }\n        argumentValues {\n          id: string\n          argument {\n            id: string\n          }\n          operation {\n            id: string\n          }\n          argumentRef: string\n        }\n      }\n    }\n    isGenerated: boolean\n    functionType: string\n    graphqlOperationType: string\n    outputType: string\n    outputKindId: string\n    outputModifiers: Array[string]\n    kind {\n      id: string\n      name: string\n    }\n}\n```\n\n`FunctionExecutionResult` object:\n```js\n{\n  id: string,\n  result: JSON\n}\n```\n\n#### executeFunction = ( {id, variables, resolve} ) =>\n\nExecutes a function based on its id, with optional inputs for variables and a resolve string (this specifies the fields to be returned, which must be valid based on the result).\n\nReturns : JSON matching shape of result , unless no sub-selection of fields is required in the execution.\n\nThis following piece of code will execute a Function given a function ID, and pass in variables for ‘example’, requesting back id and name fields. \n\n```js \nconst res = await AssistantAPIClient.executeFunction({functionId: func.id, variables: {\"variableName\": \"variableValue\"}, resolve: \"{ id name }\");\n```\n\n#### createFunction = input =>\n\nCreates a function based on the input provided. \n\nReturns: the created Function object.\n\n**Using create function will only place the function in the workspace’s inventory--it will not place the function as a node on the Graph. In order to do this, you must pass the created function into the addNode function on the active Graph, making sure to specify ‘Function' as the type.\n\n```js\nconst createFunctionInput = {\n  name:\"yourName\",\n  arguments:[],\n  outputType: \"STRING\",\n  graphqlOperationType:\"QUERY\",\n  functionType: \"CKG\"\n}\n  \nconst createdFunction = await AssistantAPIClient.createFunction(createFunctionInput)\n```\n\n#### updateFunction = input =>\n\nInput is the same for creating a function. It’s important to note that the arguments property will be replaced in it’s entirety with whatever is provided (if a value is provided.\n\nReturns the updated `Function` object.\n\n```js\nconst updatedFunction = await AssistantAPIClient.updateFunction(input);\n```\n\n#### deleteFunction = input =>\n\nInput is the id of the Function to be deleted. Returns the deleted function as a promise.\n\n```js\nconst deletedFunction = await AssistantAPIClient.deleteFunction('id...');\n```\n\n#### getFunctionById = id =>\n\nReturns a Function as a promise based on the ID provided.\n\n```js\nconst func = await AssistantAPIClient.getFunctionById('id...');\n```\n\n#### addFunctionExecutionListener = async (id, cb) =>\n\nAssociates a callback function with the execution of a particular Function. When the Function matching the id parameter is executed, its FunctionExecutionResult object passed to the callback. Returns undefined.\n\nExample function execution callback and listener registration:\n\n```js\nfunction exampleFunctionCB (result){\n  console.log(`Function executed with result:`, result)\n}\n\nAssistantAPIClient.addFunctionExecutionListener('id...', exampleFunctionCB)\n```\n\n#### removeFunctionExecutionListener = async (id, cb) =>\n\nRemoves a Function execution listener based on the function ID and a reference to the callback function. If no callback is supplied, all listeners associated with the Function ID will be removed. Returns undefined.\n\n```js\nAssistantAPIClient.removeFunctionExecutionListener('id..', exampleFunctionCB)\n```\n\n### Kinds\nThe `Kind` object:\n```js\n{\n    id: string\n    name: string\n    service: {\n      id\n      name\n    }\n    isGenerated: boolean\n    schema {\n      id: string\n      name: string\n      type: string\n      typeKindId: string\n      modifiers: Array[string]\n      kind {\n        id: string\n        name: string\n      }\n    }\n}\n```\n\n#### createKind = input =>\n\nCreates a Kind based on an input object. Returns a promise that resolves to the created Kind object.\n\n```js\nconst kindInput = {\n name: \"someKind\",\n schema:[\n  { name: \"someField1\", type: STRING },\n  { name: \"someField2\", type: STRING }\n ]\n}\n\nconst newKind = await AssistantAPIClient.createKind(kindInput)\n```\n\n#### updateKind = input =>\n\nUpdates a Kind based on an input object. \n\nUpdate Semantics: Only properties specified will be updated. If updating the schema, the entire schema must be specified as it will be replaced in its entirety. \n\nReturns the updated `Kind` object.\n\n```js\nconst updated = await AssistantAPIClient.updateKind(input)\n```\n\n#### deleteKind = input =>\n\nDeletes a Kind given a kind ID.\n\n```js\nconst deleted = await AssistantAPIClient.deleteKind(input)\n```\n\n#### getKindById = id =>\n\nReturns a promise that resolves to a Kind object given the specified kind ID. Only kinds in the workspace or those of imported services will be returned. \n\n```js\nconst kind = await AssistantAPIClient.getKindById(id)\n```\n\n### Inventory\n\nThe `InventoryChanged` object:\n```js\n{\n  kinds: {\n    adds: [DiffItem]\n    deletes: [DiffItem]\n    updates: [DiffItem]\n  }\n  functions:{\n    adds: [DiffItem]\n    deletes: [DiffItem]\n    updates: [DiffItem]\n  }\n  services: {\n    adds: [DiffItem]\n    deletes: [DiffItem]\n    updates: [DiffItem]\n  }\n}\n```\n\nThe `DiffItem` object:\n```js\n{\n  id: string,\n  name: string\n}\n```\n\n#### addInventoryChangedListener = async cb =>\n\nRegisters a callback function with the inventory changed event. When workspace inventory changes the callback function will be called with the InventoryChangedobject. Returns undefined.\n\n*Current limitations: Kind and Function updates only occur where the name property is changed. Updates to services outside of the workspace will not be detected. \n\n**Use-case note: an ‘update’ diff for inventory services is unlikely in general usage. \n\n```js\nconst inventoryCB = ({diff}) => {\n  if(diff.kinds) console.log('KINDS CHANGED',diff.kinds)\n  if(diff.functions) console.log('FUNCTIONS CHANGED', diff.functions)\n  if(diff.services) console.log('SERVICES CHANGED',diff.services)\n}\n\nAssistantAPIClient.addInventoryChangedListener(inventoryCB)\n```\n\nThis function exists on the Q-Assisant-Client only--only enableSelectionChangedNotification is used on the API side. \n\n#### removeInventoryChangedListener = async cb =>\n\nRemoves an inventory changed listener given the referenced callback. If no callback is specified, all listeners will be removed. Returns undefined.\n\n```js\nAssistantAPIClient.removeInventoryChangedListener(inventoryCB)\n```\n\nThis function exists on the Q-Assisant-Client only--only disableSelectionChangedNotification is used on the API side. \n\n## Troubleshooting Assistant Issues\n### Assistant root file has loaded, but not other content\nObserving in the browser's dev tools that some resources have loaded correctly (usually the root), but other's haven't (usually nested files or chunks), is indicative of a failure of Q Gateway to proxy due to not having a 'relative' path structure.\n\n### You are seeing post-robot `NO ACK` errors in the console.\nThese errors stem from a failed acknowledgement for a call either between the client and the API or vice-versa. Here, this means that the web app 'window' (the assistant) cannot communicate with, or access, the 'window.parent' (Maana K-Portal) object. Improper CORS configuration is a common culprit (also verify if using docker or nginx that your proxying and networking is configured correctly to allow communication and to accout for CORS).","readmeFilename":"README.md","gitHead":"f263b85fa09f69e0cc5a30bf1a8f9d171f743812","_id":"@io-maana/q-assistant-client@3.2.2-beta.30","_npmVersion":"6.4.1","_nodeVersion":"10.15.3","_npmUser":{"name":"teamcitymaana","email":"teamcity@maana.io"},"dist":{"integrity":"sha512-HSf+kImIine+HAN5GZNdoJcHqn1bf3LAJ2oyCyzcsJ5ZxintnMe8xei4+O16VFNTRbP7nrsHcaFPrIfPkNKcSw==","shasum":"7a68318824831c8ae5b825002bb7a246cf36f2fd","tarball":"https://registry.npmjs.org/@io-maana/q-assistant-client/-/q-assistant-client-3.2.2-beta.30.tgz","fileCount":10,"unpackedSize":48081,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJel6GhCRA9TVsSAnZWagAAzYYP/1Y3idAPEPgoa/emQ7cZ\neaBmN2lgBC+s0LEKwsr+M+p6JtWLALNKYrIYisK+2ChoMhaovOcCXGrQd1U/\nOumKPO/I0T7Et4hjuoVmXTP6v+NBy0VlH79FVZSdbV/aW2YmBiCR7wIL+qlw\nlua1WXplniviCQmIgdHMSxllq2phZKeNksT+F99mDrpNl03lveLOluiXxTf3\n3NjSXqj50SQ3ujnXzhwdjs76T3872ApBL3SI56dx/5zN9PvWNRhVTjN3p2J9\nIKOhLJpPM0p+0LBjrts9PUxtSHEvfdUwhcRr4oi0T9cvZu+hSAJYUQD6PhF8\nHdXKYbaLDqelTLAl9cLoJHSDPqGOX+TdEosX7CGrHyFotmTn4NLGNsldma65\n8xalcC4CjO4q5VED8+4wafdENTYTzhMx3mQaLnepkcUuepXrRDwKxSGhf2t6\nzg4ChJSNDA/B7uGPZgHFtlxYgNDidc2hBjfbZiJNraHQyXbQ2eHCOO2p0Lvh\n6J1aBnVmOP3cYPHvRe4R0ZevFldnsnc5bH2EpBSvD+xUDggeeskK1KMkO6jm\nYLHDy98IJBQg8ySaZjN5OSJcfbiwg5qlL7PlgErDODkmOXCA56ofXicN/vIo\nzA+JdfgHF6qjBc67boxfMrb/uCeQGhobp9p0r+zPQQOYdN+eEVC0j7thnOYu\n6C50\r\n=kkaX\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIQDTjyVojhBVK59dZfL7IMEtkz9OzZNOQO1ErqNdaKN1cAIgfPC0F59wSSE89DqJ13Uu0YQ1dCyfIHDS2w8UNjimvCk="}]},"maintainers":[{"email":"andrey@maana.io","name":"abatyuk"},{"email":"bzvestey@gmail.com","name":"bzvetey"},{"email":"dlewissandy@maana.io","name":"dlsmaana"},{"email":"rob@maana.io","name":"rpovey"},{"email":"teamcity@maana.io","name":"teamcitymaana"},{"email":"witt3rd@witt3rd.com","name":"witt3rd"}],"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/q-assistant-client_3.2.2-beta.30_1586995616680_0.5632861325380705"},"_hasShrinkwrap":false},"3.2.2-beta.31":{"name":"@io-maana/q-assistant-client","version":"3.2.2-beta.31","description":"JavaScript package to streamline communication between an assistant and the Maana Q Assistant API.","main":"build/index.js","exports":{"./":"./build/"},"scripts":{"build":"babel src --out-dir build","prepack":"npm run build","test":"echo \"Error: no test specified\" && exit 1","format":"prettier --write \"src/**/*.js\""},"repository":{"type":"git","url":"git+https://github.com/maana-io/q-assistant-client.git"},"keywords":["Maana","Q"],"author":{"name":"Logan Gore @ Maana.io"},"license":"MIT","bugs":{"url":"https://github.com/maana-io/q-assistant-client/issues"},"homepage":"https://github.com/maana-io/q-assistant-client#readme","dependencies":{"core-js":"3.6.4","post-robot":"10.0.29"},"devDependencies":{"@babel/cli":"^7.5.5","@babel/core":"^7.5.5","@babel/plugin-proposal-class-properties":"^7.5.5","@babel/preset-env":"^7.5.5","prettier":"1.19.1"},"readme":"# q-assistant-client\nA lightweight JavaScript client for Maana-Q Assistant developers that wraps post-message communication between an embedded Maana-Q assistant and the Maana-Q UI.\n\n## Abstract\nThe Q-Assistant-Client is intented to be used in a web application being leveraged as a Maana Q assistant (embedded as an iframe).\nThis assistant client will facilitate communication between the assistant and the parent frame.\nThe client provides a rich, asynchronous experience over what would otherwise be 'fire-and-forget'-style messaging \nvia post-post message communication. \n\n## Requirements and Assumptions\n\n### Post-Robot Library\nThe Maana Knowledge Portal (KPortal) uses the kraken/post-robot library [kraken/post-robot](https://github.com/krakenjs/post-robot) to enrich the communication with the assistant. Post-robot allows for asynchronous, promise-based request/response style behavior between the assistant and the assistant API.\n\nThe API requires that the client use the post-robot library. This assistant-client library is the easiest way to achieve this, and also adds a fair amount of 'sugar' to the process to improve developer productivity. Developers could, however, use post-robot directly in their own client implementation. \n\n### Maana-Gateway Proxy Requirements\nThe Maana-Gateway service requires relative paths (paths relative to the root) in the assistant web application in order to proxy the application and its content. For create-react-apps, for instance, this means setting \"homepage\" to \".\" in the package.json file.\n\n## Singleton Instance\nThe client is exported as a singleton to avoid duplicate registration on event listeners.\nYou can import the instance like this:\n\n```js\nimport AssistantAPIClient from '@io-maana/q-assistant-client';\n```\n\nFunction calls can be made against the client instance like any other javascript object. They are all async.\n\n```js\nconst workspace = await AssistantAPIClient.getWorkspace(); \nconsole.log(\"Workspace:\", workspace)\n```\n\n## Dependencies\nPost-Robot\nhttps://github.com/krakenjs/post-robot\n\nPost-robot is used to provide a richer communication layer atop post-message.\n\n## Examples\n@TODO Logan\n\n## API Documentation\n\n### State management\n\n#### clearState = () =>\n\nThis will clear all ‘attached’ state between the assistant and the API. \n\nSpecifically, this will clear selection and inventory changed event listeners. \n\n```js\nawait AssistantAPIClient.clearState()\n```\n\n### User Info\nThe `UserInfo` object:\n```js\n{\n email: string,\n name: string\n}\n```\n\n#### getUserInfo = () => \n\nReturns a Userinfo object pertaining to the logged in user.\n\n```js\nconst userInfo = await AssistantAPIClient.getUserInfo()\n```\n### Selection\nThe `Selection` object:\n```js\n{\n  kindId: string\n  kindName: string\n  id: string\n}\n```\n\n#### getCurrentSelection = () => \n\nReturns an Array of `Selection` objects:\n\n```js\nconst {selection} = await AssistantAPIClient.getCurrentSelection();\n```\n\n#### addSelectionChangedListener = async cb =>\n\nAdds a callback function to be executed upon a valid workspace selection change.\n\nCallback value is an array of Selection objects:\n\n```js\n// Create the selection callback.\nconst selectionCB = ({selection})=>{\n  console.log('Workspace selection has changed.')\n  selection.forEach(i=>{\n    console.log('Kind: ',i.kindName)\n    console.log('Instance Id:',i.id)\n    console.log('Kind Id:',i.kindId)\n  })\n}\n\n// Add the listener.\nAssistantAPIClient.addSelectionChangedListener(selectionCB);\n```\n\nThis function only exists on the Q-Assistant-Client--only enableSelectionChangedNotification is called on the API. \n\n#### removeSelectionChangedListener = async cb =>\n\nThis will have to be called on a 1:1 basis with addSelectionChangedListener calls if supplying a callback.\n\n```js\nAssistantAPIClient.removeSelectionChangedListener(selectionCB)\n```\n\n**If NOT supplying a callback to this call, all selection changed listeners will be removed.\n\n```js\nAssistantAPIClient.removeSelectionChangedListener()\n```\n\nThis function only exists on the Q-Assistant-Client--only disableSelectionChangedNotification is called on the API. \n\n\n### Services\nThe `Service` object:\n```js\n{\n   id: string,\n   name: string\n   endpointUrl: string,\n   getKinds: () => // Returns [] of Kinds objects\n   getFunctions: () => // Returns [] of Function objects\n}\n```\n\n#### getServiceById = id =>\nThis will return a service that exists within the scope of the workspace. \n** Assistant services will return null. Services outside the scope of the workspace will cause an error to be returned as 'Unable to load a Service from outside of the workspace.'\n\n```js\nconst svc = await AssistantAPIClient.getServiceById(id)\n```\n\n### Workspace\nThe `Workspace` object:\n```js\n{\nid: string,\nname: string,\ngetKinds: () => {\n  // Returns an array of functions in the workspace (includes boilerplate).\n},\ngetFunctions: () =>\n  // Returns an array of functions in the workspace (includes boilerplate).\ngetActiveGraph: () => {\n  // Returns the active Graph object.\n  // Returns null if active graph is not of type 'Knowledge Graph', or if an\n  // active graph is deleted, thereby setting active graph to null.\n},\ngetKnowledgeGraphs: () => {\n  // Returns [Graph]\n},\ngetImportedServices: () => {\n  // Returns an service imported into the workspace\n  // as a array of Service object (this calls the function\n  // that underlies getServiceById.\n  // No assistant services will be returned.\n}\n}\n```\n\n#### getWorkspace = () =>\n\nReturns a Workspace object representing the workspace. \n\n```js\nconst ws = await AssistantAPIClient.getWorkspace()\n```\n\n### Graphs\nThe `Graph` object:\n```js\n{     \nid: string,\nname: string,\noffsetX: Number,\noffsetY: Number,\nzoom: Number,\ngetNodes: async () => {\n    // Returns [Node]\n},\n\naddNode: async (type, instance, changeSelection) => {\n    // Returns Node\n},\nremoveNode: async id => {\n    // Should return nothing or error.\n    // Currently returning [] in all cases.\n},\nupdateNodeLayout: async (nodeId, { x, y, collapsed }) => {\n},\nupdateGraphLayout: async ({ offsetX, offsetY, zoom }) => {\n}\n}\n```\n\n#### Getting a graph object:\nGraph objects are obtained through an instance of a Workspace \n\n```js\nconst ag = await ws.getActiveGraph()\n```\n\nor\n\n```js\nconst kgs = await ws.getKnowledgeGraphs()\n```\n\n#### Manipulating Graphs\n\n**Only the active graph may be manipulated.\n\nAll graph manipulations should be ‘visually’ verifiable on the graph itself, i.e., adds/removes/positioning, should all be reflected on the graph itself. \n\nThe `Node` object:\n```js\n{\nid: string\nx: number\ny: number\ncollapsed: boolean\nknowledgeGraphNode {\n  id: string\n  innerKind: Kind\n  innerFunction: Function\n}\n}\n```\n\n#### addNode(type, instance, changeSelection) =>\n\nTakes type (“Function” or “Kind”), instance (the Function or Kind object), and optionally a boolean to indicate whether the selection should be changed to this new node. \n\nReturns the newly created Node object.\n\n```js\nconst node = await ag.addNode('Kind',kind)\n```\n\n#### removeNode(id) =>\n\nTakes the id of Node to be deleted. Returns either undefined or an error. \n\n```js\nawait ag.removeNode(node.id)\n```\n\n#### getNodes() =>\nReturns an array of Node objects from the graph. \n\n```js\nconst nodes = await ag.getNodes()\n```\n\n#### updateNodeLayout: async (nodeId, { x, y, collapsed})=>\n\nUpdates a Node layout given a node ID and node coordinates (`x` and/or `y`) or a `collapsed` value. x/y values must be a number, and collapsed must be a boolean. Whatever is not specified will remain current.\n\n```js\nag.updateNodeLayout(id,{x:100,y:100,collapsed:true})\n```\n\n#### updateGraphLayout: async ({ offsetX, offsetY, zoom})=>\n\nUpdates a Graph layout given numerical values for x/y offsets and the zoom. \n\n```js\nag.updateGraphLayout({offsetX:50, offsetY:50, zoom: 70})\n```\n\n### Functions\n\nThe `Function` object:\n```js\n{\n    id: string\n    name: string\n    service {\n      id: string\n      name: string\n    }\n    arguments {\n      id: string\n      name: string\n      type: string\n      modifiers: Array[string]\n      typeKindId:: string\n      kind {\n        id: string\n        name: string\n      }\n    }\n    implementation {\n      id: string\n      entrypoint {\n        id: string\n      }\n      operations {\n        id: string\n        type: string\n        function {\n          id: string\n          name: string\n        }\n        argumentValues {\n          id: string\n          argument {\n            id: string\n          }\n          operation {\n            id: string\n          }\n          argumentRef: string\n        }\n      }\n    }\n    isGenerated: boolean\n    functionType: string\n    graphqlOperationType: string\n    outputType: string\n    outputKindId: string\n    outputModifiers: Array[string]\n    kind {\n      id: string\n      name: string\n    }\n}\n```\n\n`FunctionExecutionResult` object:\n```js\n{\n  id: string,\n  result: JSON\n}\n```\n\n#### executeFunction = ( {id, variables, resolve} ) =>\n\nExecutes a function based on its id, with optional inputs for variables and a resolve string (this specifies the fields to be returned, which must be valid based on the result).\n\nReturns : JSON matching shape of result , unless no sub-selection of fields is required in the execution.\n\nThis following piece of code will execute a Function given a function ID, and pass in variables for ‘example’, requesting back id and name fields. \n\n```js \nconst res = await AssistantAPIClient.executeFunction({functionId: func.id, variables: {\"variableName\": \"variableValue\"}, resolve: \"{ id name }\");\n```\n\n#### createFunction = input =>\n\nCreates a function based on the input provided. \n\nReturns: the created Function object.\n\n**Using create function will only place the function in the workspace’s inventory--it will not place the function as a node on the Graph. In order to do this, you must pass the created function into the addNode function on the active Graph, making sure to specify ‘Function' as the type.\n\n```js\nconst createFunctionInput = {\n  name:\"yourName\",\n  arguments:[],\n  outputType: \"STRING\",\n  graphqlOperationType:\"QUERY\",\n  functionType: \"CKG\"\n}\n  \nconst createdFunction = await AssistantAPIClient.createFunction(createFunctionInput)\n```\n\n#### updateFunction = input =>\n\nInput is the same for creating a function. It’s important to note that the arguments property will be replaced in it’s entirety with whatever is provided (if a value is provided.\n\nReturns the updated `Function` object.\n\n```js\nconst updatedFunction = await AssistantAPIClient.updateFunction(input);\n```\n\n#### deleteFunction = input =>\n\nInput is the id of the Function to be deleted. Returns the deleted function as a promise.\n\n```js\nconst deletedFunction = await AssistantAPIClient.deleteFunction('id...');\n```\n\n#### getFunctionById = id =>\n\nReturns a Function as a promise based on the ID provided.\n\n```js\nconst func = await AssistantAPIClient.getFunctionById('id...');\n```\n\n#### addFunctionExecutionListener = async (id, cb) =>\n\nAssociates a callback function with the execution of a particular Function. When the Function matching the id parameter is executed, its FunctionExecutionResult object passed to the callback. Returns undefined.\n\nExample function execution callback and listener registration:\n\n```js\nfunction exampleFunctionCB (result){\n  console.log(`Function executed with result:`, result)\n}\n\nAssistantAPIClient.addFunctionExecutionListener('id...', exampleFunctionCB)\n```\n\n#### removeFunctionExecutionListener = async (id, cb) =>\n\nRemoves a Function execution listener based on the function ID and a reference to the callback function. If no callback is supplied, all listeners associated with the Function ID will be removed. Returns undefined.\n\n```js\nAssistantAPIClient.removeFunctionExecutionListener('id..', exampleFunctionCB)\n```\n\n### Kinds\nThe `Kind` object:\n```js\n{\n    id: string\n    name: string\n    service: {\n      id\n      name\n    }\n    isGenerated: boolean\n    schema {\n      id: string\n      name: string\n      type: string\n      typeKindId: string\n      modifiers: Array[string]\n      kind {\n        id: string\n        name: string\n      }\n    }\n}\n```\n\n#### createKind = input =>\n\nCreates a Kind based on an input object. Returns a promise that resolves to the created Kind object.\n\n```js\nconst kindInput = {\n name: \"someKind\",\n schema:[\n  { name: \"someField1\", type: STRING },\n  { name: \"someField2\", type: STRING }\n ]\n}\n\nconst newKind = await AssistantAPIClient.createKind(kindInput)\n```\n\n#### updateKind = input =>\n\nUpdates a Kind based on an input object. \n\nUpdate Semantics: Only properties specified will be updated. If updating the schema, the entire schema must be specified as it will be replaced in its entirety. \n\nReturns the updated `Kind` object.\n\n```js\nconst updated = await AssistantAPIClient.updateKind(input)\n```\n\n#### deleteKind = input =>\n\nDeletes a Kind given a kind ID.\n\n```js\nconst deleted = await AssistantAPIClient.deleteKind(input)\n```\n\n#### getKindById = id =>\n\nReturns a promise that resolves to a Kind object given the specified kind ID. Only kinds in the workspace or those of imported services will be returned. \n\n```js\nconst kind = await AssistantAPIClient.getKindById(id)\n```\n\n### Inventory\n\nThe `InventoryChanged` object:\n```js\n{\n  kinds: {\n    adds: [DiffItem]\n    deletes: [DiffItem]\n    updates: [DiffItem]\n  }\n  functions:{\n    adds: [DiffItem]\n    deletes: [DiffItem]\n    updates: [DiffItem]\n  }\n  services: {\n    adds: [DiffItem]\n    deletes: [DiffItem]\n    updates: [DiffItem]\n  }\n}\n```\n\nThe `DiffItem` object:\n```js\n{\n  id: string,\n  name: string\n}\n```\n\n#### addInventoryChangedListener = async cb =>\n\nRegisters a callback function with the inventory changed event. When workspace inventory changes the callback function will be called with the InventoryChangedobject. Returns undefined.\n\n*Current limitations: Kind and Function updates only occur where the name property is changed. Updates to services outside of the workspace will not be detected. \n\n**Use-case note: an ‘update’ diff for inventory services is unlikely in general usage. \n\n```js\nconst inventoryCB = ({diff}) => {\n  if(diff.kinds) console.log('KINDS CHANGED',diff.kinds)\n  if(diff.functions) console.log('FUNCTIONS CHANGED', diff.functions)\n  if(diff.services) console.log('SERVICES CHANGED',diff.services)\n}\n\nAssistantAPIClient.addInventoryChangedListener(inventoryCB)\n```\n\nThis function exists on the Q-Assisant-Client only--only enableSelectionChangedNotification is used on the API side. \n\n#### removeInventoryChangedListener = async cb =>\n\nRemoves an inventory changed listener given the referenced callback. If no callback is specified, all listeners will be removed. Returns undefined.\n\n```js\nAssistantAPIClient.removeInventoryChangedListener(inventoryCB)\n```\n\nThis function exists on the Q-Assisant-Client only--only disableSelectionChangedNotification is used on the API side. \n\n## Troubleshooting Assistant Issues\n### Assistant root file has loaded, but not other content\nObserving in the browser's dev tools that some resources have loaded correctly (usually the root), but other's haven't (usually nested files or chunks), is indicative of a failure of Q Gateway to proxy due to not having a 'relative' path structure.\n\n### You are seeing post-robot `NO ACK` errors in the console.\nThese errors stem from a failed acknowledgement for a call either between the client and the API or vice-versa. Here, this means that the web app 'window' (the assistant) cannot communicate with, or access, the 'window.parent' (Maana K-Portal) object. Improper CORS configuration is a common culprit (also verify if using docker or nginx that your proxying and networking is configured correctly to allow communication and to accout for CORS).","readmeFilename":"README.md","gitHead":"d2dd6f9b8e5a9a9163f48274bbaa2894a7d37209","_id":"@io-maana/q-assistant-client@3.2.2-beta.31","_npmVersion":"6.4.1","_nodeVersion":"10.15.3","_npmUser":{"name":"teamcitymaana","email":"teamcity@maana.io"},"dist":{"integrity":"sha512-13mFEwS+/ysN5zEB7FkaZ9QLfLPxc5PVtLyoWOEaIicWFVgeA6LCjY/8ShsPFl/2PjbHHEGnQELvXrww7PVqzA==","shasum":"3a4514b82c897c9b6ef99863e3979bb879e67c80","tarball":"https://registry.npmjs.org/@io-maana/q-assistant-client/-/q-assistant-client-3.2.2-beta.31.tgz","fileCount":10,"unpackedSize":48290,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJeuL+RCRA9TVsSAnZWagAAPG4P/Aw9GoNNEH28xQRICKSf\nA9sbSEpIET4zP17Gc2hgvyw2BlLO2N/HL3xlcXiADg9JunF3LbKkSPI15uLN\n78HYNEV7SCz5cNCyhP0Au/3ZWRwOX55NB/5l+rW+DF97mlbMrPqrJZqY7jhZ\nl7n6+NEjG7Wb5bdZBfyienmaP8QNqhPprjAeVviyvFSFIWYmtphb1mdH7g58\nUATywmLlq9ZcCiKRnsxODc8TFtqbRWzWFNHZiuEzEHa949NgxAEiZeDolQHX\n4vPbaOCGIe7870Sr5ZfQiZS/ymYQ18f5btAec/6uOMVfNGJWwwX5md3XIHrJ\nhv/auT0Jxs/6J4vHFe0Y03nKFBtrBWxhHbgpiauu3kJ9svLsvQpmm6zYzhry\nfprALSXjbODADbjtFNj1Dc1aNmS3sp+M30kC4KsgGQ6Rl6Q+cJv41JsoyaIS\ndjg+TXv3hixTIu403Lt86Zr4ObtsnI0hy/32kQaRsdGNicVtIyX8LnNUfvNn\nkx7fNe3QhyD5Oc2iuFMjoCQUG/IwX1SYzadNFi+mIgMETIHCbFN7IeHZRXSD\n/yHMGr7RYEOIu6ZrQ5g66MXCde27XRqGiV/IWNGCFzQc3doqLadtyurs7kFu\npWyxDHY2fQkoblp8QBa7UutIW8owAF0lk/ZdRKM3b9UXEiTySuQR3SIghrbj\nrRe/\r\n=Qj8e\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEYCIQDElEK6IzBGEhQNelHDH5vOpCysgDokwlKIAAqjnQuxAQIhAKHnVIGTImhCGbqvL5kxlqBqK7MBwvasXlCkO/2meDyv"}]},"maintainers":[{"email":"andrey@maana.io","name":"abatyuk"},{"email":"bzvestey@gmail.com","name":"bzvetey"},{"email":"dlewissandy@maana.io","name":"dlsmaana"},{"email":"rob@maana.io","name":"rpovey"},{"email":"teamcity@maana.io","name":"teamcitymaana"},{"email":"witt3rd@witt3rd.com","name":"witt3rd"}],"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/q-assistant-client_3.2.2-beta.31_1589165968929_0.6353247944976685"},"_hasShrinkwrap":false},"3.2.2-beta.32":{"name":"@io-maana/q-assistant-client","version":"3.2.2-beta.32","description":"JavaScript package to streamline communication between an assistant and the Maana Q Assistant API.","main":"build/index.js","exports":{"./":"./build/"},"scripts":{"build":"babel src --out-dir build","prepack":"npm run build","test":"echo \"Error: no test specified\" && exit 1","format":"prettier --write \"src/**/*.js\""},"repository":{"type":"git","url":"git+https://github.com/maana-io/q-assistant-client.git"},"keywords":["Maana","Q"],"author":{"name":"Logan Gore @ Maana.io"},"license":"MIT","bugs":{"url":"https://github.com/maana-io/q-assistant-client/issues"},"homepage":"https://github.com/maana-io/q-assistant-client#readme","dependencies":{"core-js":"3.6.4","post-robot":"10.0.29"},"devDependencies":{"@babel/cli":"^7.5.5","@babel/core":"^7.5.5","@babel/plugin-proposal-class-properties":"^7.5.5","@babel/preset-env":"^7.5.5","prettier":"1.19.1"},"readme":"# q-assistant-client\nA lightweight JavaScript client for Maana-Q Assistant developers that wraps post-message communication between an embedded Maana-Q assistant and the Maana-Q UI.\n\n## Abstract\nThe Q-Assistant-Client is intented to be used in a web application being leveraged as a Maana Q assistant (embedded as an iframe).\nThis assistant client will facilitate communication between the assistant and the parent frame.\nThe client provides a rich, asynchronous experience over what would otherwise be 'fire-and-forget'-style messaging \nvia post-post message communication. \n\n## Requirements and Assumptions\n\n### Post-Robot Library\nThe Maana Knowledge Portal (KPortal) uses the kraken/post-robot library [kraken/post-robot](https://github.com/krakenjs/post-robot) to enrich the communication with the assistant. Post-robot allows for asynchronous, promise-based request/response style behavior between the assistant and the assistant API.\n\nThe API requires that the client use the post-robot library. This assistant-client library is the easiest way to achieve this, and also adds a fair amount of 'sugar' to the process to improve developer productivity. Developers could, however, use post-robot directly in their own client implementation. \n\n### Maana-Gateway Proxy Requirements\nThe Maana-Gateway service requires relative paths (paths relative to the root) in the assistant web application in order to proxy the application and its content. For create-react-apps, for instance, this means setting \"homepage\" to \".\" in the package.json file.\n\n## Singleton Instance\nThe client is exported as a singleton to avoid duplicate registration on event listeners.\nYou can import the instance like this:\n\n```js\nimport AssistantAPIClient from '@io-maana/q-assistant-client';\n```\n\nFunction calls can be made against the client instance like any other javascript object. They are all async.\n\n```js\nconst workspace = await AssistantAPIClient.getWorkspace(); \nconsole.log(\"Workspace:\", workspace)\n```\n\n## Dependencies\nPost-Robot\nhttps://github.com/krakenjs/post-robot\n\nPost-robot is used to provide a richer communication layer atop post-message.\n\n## Examples\n@TODO Logan\n\n## API Documentation\n\n### State management\n\n#### clearState = () =>\n\nThis will clear all ‘attached’ state between the assistant and the API. \n\nSpecifically, this will clear selection and inventory changed event listeners. \n\n```js\nawait AssistantAPIClient.clearState()\n```\n\n### User Info\nThe `UserInfo` object:\n```js\n{\n email: string,\n name: string\n}\n```\n\n#### getUserInfo = () => \n\nReturns a Userinfo object pertaining to the logged in user.\n\n```js\nconst userInfo = await AssistantAPIClient.getUserInfo()\n```\n### Selection\nThe `Selection` object:\n```js\n{\n  kindId: string\n  kindName: string\n  id: string\n}\n```\n\n#### getCurrentSelection = () => \n\nReturns an Array of `Selection` objects:\n\n```js\nconst {selection} = await AssistantAPIClient.getCurrentSelection();\n```\n\n#### addSelectionChangedListener = async cb =>\n\nAdds a callback function to be executed upon a valid workspace selection change.\n\nCallback value is an array of Selection objects:\n\n```js\n// Create the selection callback.\nconst selectionCB = ({selection})=>{\n  console.log('Workspace selection has changed.')\n  selection.forEach(i=>{\n    console.log('Kind: ',i.kindName)\n    console.log('Instance Id:',i.id)\n    console.log('Kind Id:',i.kindId)\n  })\n}\n\n// Add the listener.\nAssistantAPIClient.addSelectionChangedListener(selectionCB);\n```\n\nThis function only exists on the Q-Assistant-Client--only enableSelectionChangedNotification is called on the API. \n\n#### removeSelectionChangedListener = async cb =>\n\nThis will have to be called on a 1:1 basis with addSelectionChangedListener calls if supplying a callback.\n\n```js\nAssistantAPIClient.removeSelectionChangedListener(selectionCB)\n```\n\n**If NOT supplying a callback to this call, all selection changed listeners will be removed.\n\n```js\nAssistantAPIClient.removeSelectionChangedListener()\n```\n\nThis function only exists on the Q-Assistant-Client--only disableSelectionChangedNotification is called on the API. \n\n\n### Services\nThe `Service` object:\n```js\n{\n   id: string,\n   name: string\n   endpointUrl: string,\n   getKinds: () => // Returns [] of Kinds objects\n   getFunctions: () => // Returns [] of Function objects\n}\n```\n\n#### getServiceById = id =>\nThis will return a service that exists within the scope of the workspace. \n** Assistant services will return null. Services outside the scope of the workspace will cause an error to be returned as 'Unable to load a Service from outside of the workspace.'\n\n```js\nconst svc = await AssistantAPIClient.getServiceById(id)\n```\n\n### Workspace\nThe `Workspace` object:\n```js\n{\nid: string,\nname: string,\ngetKinds: () => {\n  // Returns an array of functions in the workspace (includes boilerplate).\n},\ngetFunctions: () =>\n  // Returns an array of functions in the workspace (includes boilerplate).\ngetActiveGraph: () => {\n  // Returns the active Graph object.\n  // Returns null if active graph is not of type 'Knowledge Graph', or if an\n  // active graph is deleted, thereby setting active graph to null.\n},\ngetKnowledgeGraphs: () => {\n  // Returns [Graph]\n},\ngetImportedServices: () => {\n  // Returns an service imported into the workspace\n  // as a array of Service object (this calls the function\n  // that underlies getServiceById.\n  // No assistant services will be returned.\n}\n}\n```\n\n#### getWorkspace = () =>\n\nReturns a Workspace object representing the workspace. \n\n```js\nconst ws = await AssistantAPIClient.getWorkspace()\n```\n\n### Graphs\nThe `Graph` object:\n```js\n{     \nid: string,\nname: string,\noffsetX: Number,\noffsetY: Number,\nzoom: Number,\ngetNodes: async () => {\n    // Returns [Node]\n},\n\naddNode: async (type, instance, changeSelection) => {\n    // Returns Node\n},\nremoveNode: async id => {\n    // Should return nothing or error.\n    // Currently returning [] in all cases.\n},\nupdateNodeLayout: async (nodeId, { x, y, collapsed }) => {\n},\nupdateGraphLayout: async ({ offsetX, offsetY, zoom }) => {\n}\n}\n```\n\n#### Getting a graph object:\nGraph objects are obtained through an instance of a Workspace \n\n```js\nconst ag = await ws.getActiveGraph()\n```\n\nor\n\n```js\nconst kgs = await ws.getKnowledgeGraphs()\n```\n\n#### Manipulating Graphs\n\n**Only the active graph may be manipulated.\n\nAll graph manipulations should be ‘visually’ verifiable on the graph itself, i.e., adds/removes/positioning, should all be reflected on the graph itself. \n\nThe `Node` object:\n```js\n{\nid: string\nx: number\ny: number\ncollapsed: boolean\nknowledgeGraphNode {\n  id: string\n  innerKind: Kind\n  innerFunction: Function\n}\n}\n```\n\n#### addNode(type, instance, changeSelection) =>\n\nTakes type (“Function” or “Kind”), instance (the Function or Kind object), and optionally a boolean to indicate whether the selection should be changed to this new node. \n\nReturns the newly created Node object.\n\n```js\nconst node = await ag.addNode('Kind',kind)\n```\n\n#### removeNode(id) =>\n\nTakes the id of Node to be deleted. Returns either undefined or an error. \n\n```js\nawait ag.removeNode(node.id)\n```\n\n#### getNodes() =>\nReturns an array of Node objects from the graph. \n\n```js\nconst nodes = await ag.getNodes()\n```\n\n#### updateNodeLayout: async (nodeId, { x, y, collapsed})=>\n\nUpdates a Node layout given a node ID and node coordinates (`x` and/or `y`) or a `collapsed` value. x/y values must be a number, and collapsed must be a boolean. Whatever is not specified will remain current.\n\n```js\nag.updateNodeLayout(id,{x:100,y:100,collapsed:true})\n```\n\n#### updateGraphLayout: async ({ offsetX, offsetY, zoom})=>\n\nUpdates a Graph layout given numerical values for x/y offsets and the zoom. \n\n```js\nag.updateGraphLayout({offsetX:50, offsetY:50, zoom: 70})\n```\n\n### Functions\n\nThe `Function` object:\n```js\n{\n    id: string\n    name: string\n    service {\n      id: string\n      name: string\n    }\n    arguments {\n      id: string\n      name: string\n      type: string\n      modifiers: Array[string]\n      typeKindId:: string\n      kind {\n        id: string\n        name: string\n      }\n    }\n    implementation {\n      id: string\n      entrypoint {\n        id: string\n      }\n      operations {\n        id: string\n        type: string\n        function {\n          id: string\n          name: string\n        }\n        argumentValues {\n          id: string\n          argument {\n            id: string\n          }\n          operation {\n            id: string\n          }\n          argumentRef: string\n        }\n      }\n    }\n    isGenerated: boolean\n    functionType: string\n    graphqlOperationType: string\n    outputType: string\n    outputKindId: string\n    outputModifiers: Array[string]\n    kind {\n      id: string\n      name: string\n    }\n}\n```\n\n`FunctionExecutionResult` object:\n```js\n{\n  id: string,\n  result: JSON\n}\n```\n\n#### executeFunction = ( {id, variables, resolve} ) =>\n\nExecutes a function based on its id, with optional inputs for variables and a resolve string (this specifies the fields to be returned, which must be valid based on the result).\n\nReturns : JSON matching shape of result , unless no sub-selection of fields is required in the execution.\n\nThis following piece of code will execute a Function given a function ID, and pass in variables for ‘example’, requesting back id and name fields. \n\n```js \nconst res = await AssistantAPIClient.executeFunction({functionId: func.id, variables: {\"variableName\": \"variableValue\"}, resolve: \"{ id name }\");\n```\n\n#### createFunction = input =>\n\nCreates a function based on the input provided. \n\nReturns: the created Function object.\n\n**Using create function will only place the function in the workspace’s inventory--it will not place the function as a node on the Graph. In order to do this, you must pass the created function into the addNode function on the active Graph, making sure to specify ‘Function' as the type.\n\n```js\nconst createFunctionInput = {\n  name:\"yourName\",\n  arguments:[],\n  outputType: \"STRING\",\n  graphqlOperationType:\"QUERY\",\n  functionType: \"CKG\"\n}\n  \nconst createdFunction = await AssistantAPIClient.createFunction(createFunctionInput)\n```\n\n#### updateFunction = input =>\n\nInput is the same for creating a function. It’s important to note that the arguments property will be replaced in it’s entirety with whatever is provided (if a value is provided.\n\nReturns the updated `Function` object.\n\n```js\nconst updatedFunction = await AssistantAPIClient.updateFunction(input);\n```\n\n#### deleteFunction = input =>\n\nInput is the id of the Function to be deleted. Returns the deleted function as a promise.\n\n```js\nconst deletedFunction = await AssistantAPIClient.deleteFunction('id...');\n```\n\n#### getFunctionById = id =>\n\nReturns a Function as a promise based on the ID provided.\n\n```js\nconst func = await AssistantAPIClient.getFunctionById('id...');\n```\n\n#### addFunctionExecutionListener = async (id, cb) =>\n\nAssociates a callback function with the execution of a particular Function. When the Function matching the id parameter is executed, its FunctionExecutionResult object passed to the callback. Returns undefined.\n\nExample function execution callback and listener registration:\n\n```js\nfunction exampleFunctionCB (result){\n  console.log(`Function executed with result:`, result)\n}\n\nAssistantAPIClient.addFunctionExecutionListener('id...', exampleFunctionCB)\n```\n\n#### removeFunctionExecutionListener = async (id, cb) =>\n\nRemoves a Function execution listener based on the function ID and a reference to the callback function. If no callback is supplied, all listeners associated with the Function ID will be removed. Returns undefined.\n\n```js\nAssistantAPIClient.removeFunctionExecutionListener('id..', exampleFunctionCB)\n```\n\n### Kinds\nThe `Kind` object:\n```js\n{\n    id: string\n    name: string\n    service: {\n      id\n      name\n    }\n    isGenerated: boolean\n    schema {\n      id: string\n      name: string\n      type: string\n      typeKindId: string\n      modifiers: Array[string]\n      kind {\n        id: string\n        name: string\n      }\n    }\n}\n```\n\n#### createKind = input =>\n\nCreates a Kind based on an input object. Returns a promise that resolves to the created Kind object.\n\n```js\nconst kindInput = {\n name: \"someKind\",\n schema:[\n  { name: \"someField1\", type: STRING },\n  { name: \"someField2\", type: STRING }\n ]\n}\n\nconst newKind = await AssistantAPIClient.createKind(kindInput)\n```\n\n#### updateKind = input =>\n\nUpdates a Kind based on an input object. \n\nUpdate Semantics: Only properties specified will be updated. If updating the schema, the entire schema must be specified as it will be replaced in its entirety. \n\nReturns the updated `Kind` object.\n\n```js\nconst updated = await AssistantAPIClient.updateKind(input)\n```\n\n#### deleteKind = input =>\n\nDeletes a Kind given a kind ID.\n\n```js\nconst deleted = await AssistantAPIClient.deleteKind(input)\n```\n\n#### getKindById = id =>\n\nReturns a promise that resolves to a Kind object given the specified kind ID. Only kinds in the workspace or those of imported services will be returned. \n\n```js\nconst kind = await AssistantAPIClient.getKindById(id)\n```\n\n### Inventory\n\nThe `InventoryChanged` object:\n```js\n{\n  kinds: {\n    adds: [DiffItem]\n    deletes: [DiffItem]\n    updates: [DiffItem]\n  }\n  functions:{\n    adds: [DiffItem]\n    deletes: [DiffItem]\n    updates: [DiffItem]\n  }\n  services: {\n    adds: [DiffItem]\n    deletes: [DiffItem]\n    updates: [DiffItem]\n  }\n}\n```\n\nThe `DiffItem` object:\n```js\n{\n  id: string,\n  name: string\n}\n```\n\n#### addInventoryChangedListener = async cb =>\n\nRegisters a callback function with the inventory changed event. When workspace inventory changes the callback function will be called with the InventoryChangedobject. Returns undefined.\n\n*Current limitations: Kind and Function updates only occur where the name property is changed. Updates to services outside of the workspace will not be detected. \n\n**Use-case note: an ‘update’ diff for inventory services is unlikely in general usage. \n\n```js\nconst inventoryCB = ({diff}) => {\n  if(diff.kinds) console.log('KINDS CHANGED',diff.kinds)\n  if(diff.functions) console.log('FUNCTIONS CHANGED', diff.functions)\n  if(diff.services) console.log('SERVICES CHANGED',diff.services)\n}\n\nAssistantAPIClient.addInventoryChangedListener(inventoryCB)\n```\n\nThis function exists on the Q-Assisant-Client only--only enableSelectionChangedNotification is used on the API side. \n\n#### removeInventoryChangedListener = async cb =>\n\nRemoves an inventory changed listener given the referenced callback. If no callback is specified, all listeners will be removed. Returns undefined.\n\n```js\nAssistantAPIClient.removeInventoryChangedListener(inventoryCB)\n```\n\nThis function exists on the Q-Assisant-Client only--only disableSelectionChangedNotification is used on the API side. \n\n## Troubleshooting Assistant Issues\n### Assistant root file has loaded, but not other content\nObserving in the browser's dev tools that some resources have loaded correctly (usually the root), but other's haven't (usually nested files or chunks), is indicative of a failure of Q Gateway to proxy due to not having a 'relative' path structure.\n\n### You are seeing post-robot `NO ACK` errors in the console.\nThese errors stem from a failed acknowledgement for a call either between the client and the API or vice-versa. Here, this means that the web app 'window' (the assistant) cannot communicate with, or access, the 'window.parent' (Maana K-Portal) object. Improper CORS configuration is a common culprit (also verify if using docker or nginx that your proxying and networking is configured correctly to allow communication and to accout for CORS).","readmeFilename":"README.md","gitHead":"4f0cd67395003e322b988b6ab1959466462e988d","_id":"@io-maana/q-assistant-client@3.2.2-beta.32","_npmVersion":"6.4.1","_nodeVersion":"10.15.3","_npmUser":{"name":"teamcitymaana","email":"teamcity@maana.io"},"dist":{"integrity":"sha512-Gbq9QC8CicqsEw1qZKt3jmvH/32tO90sXdBBpFTg+ypl/hlRN/UrMd1SgKHv27lI9jACJCy5NX1e3Oz7QrtIRw==","shasum":"f42c9df50dec2a349fe78080371bb8da1f009117","tarball":"https://registry.npmjs.org/@io-maana/q-assistant-client/-/q-assistant-client-3.2.2-beta.32.tgz","fileCount":10,"unpackedSize":47401,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJe2R0qCRA9TVsSAnZWagAAPRwP/2ZSLa9CfQbcL2jiEGLf\nTxFepo9QY2rPqC4L0K4trypjeCZTU5AQ3nVYUNiuyEAdJ0/9bIu1zPjFYiwn\nS1zeVkGCpPhHDi/wcdpbNfV6tLwdXzlZ2lGqwiLGSkwa1F34s9GfodsxjeEq\nnJHm8Go77YtyX2qEDU20eHiZ/i4JJDvb5n0XuaSM06a9SZlqJQ14EXdgqQPt\nsqNMO3ANrZWytscTmw4IAMs8vvfn7pQ2SO8D98wjxKrwD7cp+Vg5/QqrOsma\ntA+ofwovo+xhD9ZhgbGpscgX7uYfdRQY+meK712ehTeOzthfMMGth73QeMaN\n7nYdaxyu4kHhTGvov1kkCvTrUomOQk5nUN0qhV3gT8VhKc0bXy93EX0VQ8gb\nUz9lO0YPMjjILHx36A9Rb6aeJBhyMT36/dYBWX6l03VCLZ5TCU4JuoYFulfX\nmi+k/DpqUICSEyDYW98Fv8F1dbLL5FKdP+eeCqjhxjrTd5JxRFQm0oo8xTAv\nrgOSv3mXJ/Xz/PyzyGb+/a1q4C5YxGqDnwJLnm5leY+1peKg+aCIZzNFMCsQ\ntwbUTYYwabHvAn4XdVngIngGk5+oCxxt1RMk6GbeLuUODCQbsjp32P5CoFlL\nTboiLHHWo9ZwSwQ9dNLqB5JRZoBBk6QZUkXTVVvFRVjGQIWFHDaEST7+y7zf\nc/NS\r\n=6hcV\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEYCIQDRBkknGZajJs7BI0a1iTPQvBjCAUuXQjU5ADdcYNJQigIhALxfOzM5DvA4cre05mvjFOH7NFMRLKcvybxQZO5dxu/p"}]},"maintainers":[{"email":"andrey@maana.io","name":"abatyuk"},{"email":"bzvestey@gmail.com","name":"bzvetey"},{"email":"dlewissandy@maana.io","name":"dlsmaana"},{"email":"rob@maana.io","name":"rpovey"},{"email":"teamcity@maana.io","name":"teamcitymaana"},{"email":"witt3rd@witt3rd.com","name":"witt3rd"}],"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/q-assistant-client_3.2.2-beta.32_1591287081656_0.7307156965186288"},"_hasShrinkwrap":false},"3.2.2-beta.33":{"name":"@io-maana/q-assistant-client","version":"3.2.2-beta.33","description":"JavaScript package to streamline communication between an assistant and the Maana Q Assistant API.","main":"build/index.js","exports":{"./":"./build/"},"scripts":{"build":"babel src --out-dir build","prepack":"npm run build","test":"echo \"Error: no test specified\" && exit 1","format":"prettier --write \"src/**/*.js\""},"repository":{"type":"git","url":"git+https://github.com/maana-io/q-assistant-client.git"},"keywords":["Maana","Q"],"author":{"name":"Logan Gore @ Maana.io"},"license":"MIT","bugs":{"url":"https://github.com/maana-io/q-assistant-client/issues"},"homepage":"https://github.com/maana-io/q-assistant-client#readme","dependencies":{"core-js":"3.6.4","post-robot":"10.0.29"},"devDependencies":{"@babel/cli":"^7.5.5","@babel/core":"^7.5.5","@babel/plugin-proposal-class-properties":"^7.5.5","@babel/preset-env":"^7.5.5","prettier":"1.19.1"},"readme":"# q-assistant-client\nA lightweight JavaScript client for Maana-Q Assistant developers that wraps post-message communication between an embedded Maana-Q assistant and the Maana-Q UI.\n\n## Abstract\nThe Q-Assistant-Client is intented to be used in a web application being leveraged as a Maana Q assistant (embedded as an iframe).\nThis assistant client will facilitate communication between the assistant and the parent frame.\nThe client provides a rich, asynchronous experience over what would otherwise be 'fire-and-forget'-style messaging \nvia post-post message communication. \n\n## Requirements and Assumptions\n\n### Post-Robot Library\nThe Maana Knowledge Portal (KPortal) uses the kraken/post-robot library [kraken/post-robot](https://github.com/krakenjs/post-robot) to enrich the communication with the assistant. Post-robot allows for asynchronous, promise-based request/response style behavior between the assistant and the assistant API.\n\nThe API requires that the client use the post-robot library. This assistant-client library is the easiest way to achieve this, and also adds a fair amount of 'sugar' to the process to improve developer productivity. Developers could, however, use post-robot directly in their own client implementation. \n\n### Maana-Gateway Proxy Requirements\nThe Maana-Gateway service requires relative paths (paths relative to the root) in the assistant web application in order to proxy the application and its content. For create-react-apps, for instance, this means setting \"homepage\" to \".\" in the package.json file.\n\n## Singleton Instance\nThe client is exported as a singleton to avoid duplicate registration on event listeners.\nYou can import the instance like this:\n\n```js\nimport AssistantAPIClient from '@io-maana/q-assistant-client';\n```\n\nFunction calls can be made against the client instance like any other javascript object. They are all async.\n\n```js\nconst workspace = await AssistantAPIClient.getWorkspace(); \nconsole.log(\"Workspace:\", workspace)\n```\n\n## Dependencies\nPost-Robot\nhttps://github.com/krakenjs/post-robot\n\nPost-robot is used to provide a richer communication layer atop post-message.\n\n## Versioning\nThe Maana Q Assistant Client does not follow semantic versioning. Its versions\ntrack the releases of the Maana Q platform.\n\n## Examples\n@TODO Logan\n\n\n## Changes in v3.2.2\nImprovements in v3.2.2\n-Assistant State Management: WORKING, IDLE\n-Background Messaging/Eventing\n-Render Modes: BACKGROUND, DISPLAY\n-Expansion of Workspace object capabilities\n-Error Reporting\n-Repair Event\n-Plural versions of calls such as updateKind(s) to improve performance\nand developer experience. \n\nThe following surface area IS removed from the \nclient in v3.2.2, and IS deprecated in the API:\n-AssistantAPIClient.enableSelectionChangedNotification\n-AssistantAPIClient.disableSelectionChangedNotification\n-AssistantAPIClient.enableInventoryChangedNotification\n-AssistantAPIClient.disableInventoryChangedNotification\n\nThe following surface area WILL BE removed from\nthe client in v3.2.4, and WILL BE deprecated in the API:\n-AssistantAPIClient.updateFunction (expected move to Workspace object)\n-AssistantAPIClient.updateKind (expected move to Workspace object)\n-AssistantAPIClient.deleteKind (expected move to Workspace object)\n-AssistantAPIClient.deleteFunction (expected move to Workspace object)\n\n## API Documentation\n\n### Assistant Render Mode\nAn assistant's render mode refers to whether it is being displayed in a visible manner to the user. As of v3.2.2, assistants are not closed when they are out of view.\nAll assistants will be loaded and kept in `BACKGROUND` render mode until they are \nplaced in the assistant panel, at which point the `DISPLAY` render mode event will be fired. \n\nNote: Assistants will receive all notifications/events while in BACKGROUND mode.\n\nDesign Consideration: It will be up to the developer to determine how state and resource use will be managed while an assistant is operating between BACKGROUND and DISPLAY modes.\n\n#### addRenderModeChangedListener = (cb) =>\nA listener to receive push events as to the assitant's render mode being changed. \n\n```js\nfunction handleRenderModeChanged(renderMode){\n  if (renderMode === 'DISPLAY'){\n    // Assistant is visible\n  } else {\n    // Assistant is not visible and running in background.\n  }\n}\n\nAssistantAPIClient.addRenderModeChangedListener(handleRenderModeChanged)\n\n```\n\n#### removeRenderModeChangedListener = (cb) =>\nRemoves the renderModeChanged listener by reference, or if no callback function reference is provided, it removes all listeners.\n\n#### getRenderMode = () =>\nReturns the current assistant render mode.\n\n```js\nconst renderMode = await AssistantAPIClient.getRenderMode()\n\nif (renderMode === 'DISPLAY'){\n  // Assistant is visible\n} else {\n  // Assistant is not visible and running in background.\n}\n\n```\n\n### Repair\nAssistants may get into situations where they are either out of sync with the Maana Q UI, or in a failure state. Assistants should be able to recover from these states. \n\nThe repair event functionality added in v3.2.2 is designed to notify the assistant that it must repair itself. This could mean a resync with its resources on the workspace or externally or, for some assistants, nothing at all. \n\nWhen is repair triggered? \nEither manually by a user clicking 'repair workspace' under the\nassistant inventory panel, or upon a workspace clone event. An assistant will be expected to handle either scenario. \n\nPerformance Consideration: \nFor some assistants, repair might involve 'introspecting' \nand processing the current workspace or Q system resources. This could be very resource intensive. Make sure you review this API guide to have an idea of what tools are\navailable to get the best results. It's always a good idea to check performance of repair on a large workspace and ensure necessary optimizations have been made. \n\nDesign Consideration: \nMake your workflows modular enough to be reused between repair and normal usage if possible. \n\n#### addRepairListener (cb) =>\n```js\n\nAssistantAPIClient.addRepairListener(()=>{\n  // Self-heal\n})\n\n```\n\nRecommended Usage: A repair process should be wrapped in the try/catch/finally flow shown in the `setAssistantState` API call to provide the user assistant-state and error updates as well as pause `inventoryChanged` notifications during repair (if the assistant has subscribed).\n\n#### removeRepairListener = (cb) =>\nRemoves the repair listener by reference, or if no callback function reference is provided, it removes all listeners.\n\n### User-facing Error Handling\n\n#### reportError (error) =>\nReports an error to the UI to be displayed in the assistant's error log in the \ninventory panel. This call is not disruptive and designed to operated independently of other assistant operations, such as state management. See `setAssistantState` in the next section.\n\nRecommended usage: use this functionality where it would futher the user experience\nto show the user an error and it's cause. Do not use this where things will be retried, \ncleaned up automatically, or are not relevant to the user. \n\n```js\ntry{\n  // Do work\n} catch(e) {\n  AssistantAPIClient.reportError(e)\n}\n```\n\n### State management\n\n#### clearState = () =>\nThis will remove all callbacks from all listeners. \n\n```js\nawait AssistantAPIClient.clearState()\n```\n\n#### setAssistantState = (state) =>\nThis sets the current state of the assistant using the \n`AssistantState` enum. Setting a state of `WORKING` will \ncreate the 'working' status spinner in the Assistant \nInventory Panel in the Maana Q UI. Conversely, setting an `IDLE` state will \nremove the spinner. This adds to user experience by informing users of the \nstatus of operations.\n\n```js\nimport {\n  default as AssistantAPIClient,\n  AssistantState\n} from '@io-maana/q-assistant-client'\n\n...\n\nAssistantAPIClient.setAssistantState(AssistantState.WORKING)\n\n...\n\nAssistantAPIClient.setAssistantState(AssistantState.IDLE)\n\n```\nUI User Prompt: If the assistant is in a `WORKING` state, the Maana Q UI will\nwarn the user before leaving the workspace. \n\nNOTE: while an assistant is in a working state, it will\nnot receive `inventoryChanged` events--an aggregated inventory diff\nwill be sent once the assistant is set back to `IDLE`.\n\nRecommended usage: Control states at a high level using try/catch/finally\nflow incorporating the `reportError` API call.\n\n```js\ntry{\n  AssistantAPIClient.setAssistantState(AssistantState.WORKING)\n  // Do work, await high-level tasks, etc.\n} catch(e) {\n  AssistantAPIClient.reportError(e)\n} finally{\n  AssistantAPIClient.setAssistantState(AssistantState.IDLE)\n}\n```\n\n#### AssistantState (enum)\nContains the valid assistant states: `IDLE` or `WORKING`.\n\nMust be imported in addition to the AssistantAPIClient:\n\n```js\nimport {\n  default as AssistantAPIClient,\n  AssistantState\n} from '@io-maana/q-assistant-client'\n```\n\n\n### User Info\nThe `UserInfo` object:\n```js\n{\n email: string,\n name: string\n}\n```\n\n#### getUserInfo = () => \nReturns a Userinfo object pertaining to the logged in user.\n\n```js\nconst userInfo = await AssistantAPIClient.getUserInfo()\n```\n### Selection\nThe `Selection` object:\n```js\n{\n  kindId: string\n  kindName: string\n  id: string\n}\n```\n\n#### getCurrentSelection = () => \nReturns an Array of `Selection` objects:\n\n```js\nconst {selection} = await AssistantAPIClient.getCurrentSelection();\n```\n\n#### addSelectionChangedListener = async cb =>\nAdds a callback function to be executed upon a valid workspace selection change.\n\nCallback value is an array of Selection objects:\n\n```js\n// Create the selection callback.\nconst selectionCB = ({selection})=>{\n  console.log('Workspace selection has changed.')\n  selection.forEach(i=>{\n    console.log('Kind: ',i.kindName)\n    console.log('Instance Id:',i.id)\n    console.log('Kind Id:',i.kindId)\n  })\n}\n\n// Add the listener.\nAssistantAPIClient.addSelectionChangedListener(selectionCB);\n```\n\nThis function only exists on the Q-Assistant-Client--only enableSelectionChangedNotification is called on the API. \n\n#### removeSelectionChangedListener = async cb =>\nThis will have to be called on a 1:1 basis with addSelectionChangedListener calls if supplying a callback.\n\n```js\nAssistantAPIClient.removeSelectionChangedListener(selectionCB)\n```\n\n**If NOT supplying a callback to this call, all selection changed listeners will be removed.\n\n```js\nAssistantAPIClient.removeSelectionChangedListener()\n```\n\nThis function only exists on the Q-Assistant-Client--only disableSelectionChangedNotification is called on the API. \n\n\n### Services\nThe `Service` object:\n```js\n{\n   id: string,\n   name: string\n   endpointUrl: string,\n   getKinds: () => // Returns [] of Kinds objects\n   getFunctions: () => // Returns [] of Function objects\n}\n```\n\n#### getServiceById = id =>\nThis will return a service that exists within the scope of the workspace. \n** Assistant services will return null. Services outside the scope of the workspace will cause an error to be returned as 'Unable to load a Service from outside of the workspace.'\n\n```js\nconst svc = await AssistantAPIClient.getServiceById(id)\n```\n\n#### createService = id => \nCreates a service in Q.\n\nNote: This will create the service, but does NOT import it into the workspace.\nYou will need to use `importService` on the Workspace object to import it.\nReturns a promise that resolves\n\n```js\n    const service = {\n      id: ...,\n      name: ...,\n      endpointUrl: ...,\n      serviceType: ...\n    }\n    \n    await AssistantAPIClient.createService(service)\n```\n\n#### deleteService = id =>\nDeletes a service from Q.\n\n```js\n    await AssistantAPIClient.deleteService(id)\n```\n\n#### refreshServiceSchema = id =>\nRefreshes a service by fetching its schema. This will also\nreload the service inventory in the currently visible workspace.\n\n```js\nawait AssistantAPIClient.refreshServiceSchema(\"id\")\n```\n\n#### reloadService = id =>\nReloads a service in the inventory in the currently visible workspace.\n\n```js\nawait AssistantAPIClient.reloadService(\"id\")\n```\n\n### Workspace\n\n#### getWorkspace = () =>\nReturns a Workspace object representing the workspace. \n\n```js\nconst ws = await AssistantAPIClient.getWorkspace(id)\n```\n\nNote: The `id` parameter is optional. If it is not supplied, the query\nwill return the current/visible workspace. \n\nThe `Workspace` object:\n\n```js\n\n{\n    id: string,\n    name: string,\n    endpointUrl: string,\n    workspaceServiceId: string,\n    modelServiceId: string,\n    logicServiceId: string,\n\n    //\n    // Knowledge Graphs\n    //\n    getActiveGraph: async () => {\n      // Returns the active Graph object.\n      // Returns null if active graph is not of type 'Knowledge Graph', or if an\n      // active graph is deleted, thereby setting active graph to null.\n    },\n    getKnowledgeGraphs: async () => {\n      // Returns [Graph]\n    },\n    // TODO: define input\n    createKnowledgeGraph: input =>\n    // TODO: define input\n    createKnowledgeGraphs: input =>\n\n    //\n    // Services\n    //\n    getImportedServices: async () => {\n      // Returns an array of Service objects that have \n      // been imported into the workspace.\n      // No assistant services will be returned.\n    },\n    getImportedAssistants: async () => {\n      // Returns a list of imported assistants.\n    },\n    importService: serviceId => {\n      // Imports a service by it's ID. \n    },\n    importServices: serviceIds => {\n      // Imports services by their IDs.\n    },\n    removeServices: serviceIds => {\n      // Removes a list of services from the workspace.\n    },\n    removeService: serviceId => {\n      // Removes a service from the workspace.\n    },\n\n    //\n    // Functions\n    //\n    getFunctions: async () => {\n      // Returns an array of functions in the workspace (includes boilerplate).\n    },\n    createFunction: funcData => {\n      // Creates a function and adds it to the graph. \n    }\n    createFunctions: funcData =>{\n      // Creates several functions and adds them to the graph. \n    }\n    updateFunction: funcData => {\n      // Updates a function.\n    },\n    updateFunctions: funcData =>{\n      // Updates functions based on input array.\n    },\n    deleteFunction: funcId => {\n      // Deletes a function by its ID.\n    },\n    getFunctionGraph: funcId => {\n      // Returns a function graph by its ID.\n    }\n\n    //\n    // Kinds\n    //\n    getKinds: async () => {\n      // Returns an array of functions in the workspace (includes boilerplate).\n    },\n    createKind: kindData => {\n      // Currently same input as AssistantAPIClient call.\n    },\n    createKinds: kindData => {\n      // Currently same input as AssistantAPIClient call.\n    },\n    updateKind: kindData => {\n      // Currently same input as AssistantAPIClient call.\n    },\n    updateKinds: kindData => {\n      // Currently same input as AssistantAPIClient call.\n    },\n    deleteKind: kindId => {\n      // Currently same input as AssistantAPIClient call.\n    }\n    // Event Triggers\n    triggerRepairEvent: () => {\n      // Triggers the repair event on a workspace. \n    }\n  };\n}\n```\n\n\n### Graphs\nThe `Graph` object:\n```js\n{     \nid: string,\nname: string,\noffsetX: Number,\noffsetY: Number,\nzoom: Number,\ngetNodes: async () => {\n    // Returns [Node]\n},\n\naddNode: async (type, instance, changeSelection) => {\n    // Returns Node\n},\nremoveNode: async id => {\n    // Should return nothing or error.\n    // Currently returning [] in all cases.\n},\nupdateNodeLayout: async (nodeId, { x, y, collapsed }) => {\n},\nupdateGraphLayout: async ({ offsetX, offsetY, zoom }) => {\n}\n}\n```\n\n#### Getting a graph object:\nGraph objects are obtained through an instance of a Workspace \n\n```js\nconst ag = await ws.getActiveGraph()\n```\n\nor\n\n```js\nconst kgs = await ws.getKnowledgeGraphs()\n```\n\n#### Manipulating Graphs\n\n**Only the active graph may be manipulated.\n\nAll graph manipulations should be ‘visually’ verifiable on the graph itself, i.e., adds/removes/positioning, should all be reflected on the graph itself. \n\nThe `Node` object:\n```js\n{\nid: string\nx: number\ny: number\ncollapsed: boolean\nknowledgeGraphNode {\n  id: string\n  innerKind: Kind\n  innerFunction: Function\n}\n}\n```\n\n#### addNode(type, instance, changeSelection) =>\n\nTakes type (“Function” or “Kind”), instance (the Function or Kind object), and optionally a boolean to indicate whether the selection should be changed to this new node. \n\nReturns the newly created Node object.\n\n```js\nconst node = await ag.addNode('Kind',kind)\n```\n\n#### removeNode(id) =>\n\nTakes the id of Node to be deleted. Returns either undefined or an error. \n\n```js\nawait ag.removeNode(node.id)\n```\n\n#### getNodes() =>\nReturns an array of Node objects from the graph. \n\n```js\nconst nodes = await ag.getNodes()\n```\n\n#### updateNodeLayout: async (nodeId, { x, y, collapsed})=>\nUpdates a Node layout given a node ID and node coordinates (`x` and/or `y`) or a `collapsed` value. x/y values must be a number, and collapsed must be a boolean. Whatever is not specified will remain current.\n\n```js\nag.updateNodeLayout(id,{x:100,y:100,collapsed:true})\n```\n\n#### updateGraphLayout: async ({ offsetX, offsetY, zoom})=>\nUpdates a Graph layout given numerical values for x/y offsets and the zoom. \n\n```js\nag.updateGraphLayout({offsetX:50, offsetY:50, zoom: 70})\n```\n\n### Functions\n\nThe `Function` object:\n```js\n{\n    id: string\n    name: string\n    service {\n      id: string\n      name: string\n    }\n    arguments {\n      id: string\n      name: string\n      type: string\n      modifiers: Array[string]\n      typeKindId:: string\n      kind {\n        id: string\n        name: string\n      }\n    }\n    implementation {\n      id: string\n      entrypoint {\n        id: string\n      }\n      operations {\n        id: string\n        type: string\n        function {\n          id: string\n          name: string\n        }\n        argumentValues {\n          id: string\n          argument {\n            id: string\n          }\n          operation {\n            id: string\n          }\n          argumentRef: string\n        }\n      }\n    }\n    isGenerated: boolean\n    functionType: string\n    graphqlOperationType: string\n    outputType: string\n    outputKindId: string\n    outputModifiers: Array[string]\n    kind {\n      id: string\n      name: string\n    }\n}\n```\n\n`FunctionExecutionResult` object:\n```js\n{\n  id: string,\n  result: JSON\n}\n```\n\n#### executeFunction = ( {id, variables, resolve} ) =>\nExecutes a function based on its id, with optional inputs for variables and a resolve string (this specifies the fields to be returned, which must be valid based on the result).\n\nReturns : JSON matching shape of result , unless no sub-selection of fields is required in the execution.\n\nThis following piece of code will execute a Function given a function ID, and pass in variables for ‘example’, requesting back id and name fields. \n\n```js \nconst res = await AssistantAPIClient.executeFunction({functionId: func.id, variables: {\"variableName\": \"variableValue\"}, resolve: \"{ id name }\");\n```\n\n#### createFunction = input =>\nCreates a function based on the input provided. \n\nReturns: the created Function object.\n\n**Using create function will only place the function in the workspace’s inventory--it will not place the function as a node on the Graph. In order to do this, you must pass the created function into the addNode function on the active Graph, making sure to specify ‘Function' as the type.\n\n```js\nconst createFunctionInput = {\n  name:\"yourName\",\n  arguments:[],\n  outputType: \"STRING\",\n  graphqlOperationType:\"QUERY\",\n  functionType: \"CKG\"\n}\n  \nconst createdFunction = await AssistantAPIClient.createFunction(createFunctionInput)\n```\n\n#### updateFunction = input =>\nInput is the same for creating a function. It’s important to note that the arguments property will be replaced in it’s entirety with whatever is provided (if a value is provided.\n\nReturns the updated `Function` object.\n\n```js\nconst updatedFunction = await AssistantAPIClient.updateFunction(input);\n```\n\n#### deleteFunction = input =>\nInput is the id of the Function to be deleted. Returns the deleted function as a promise.\n\n```js\nconst deletedFunction = await AssistantAPIClient.deleteFunction('id...');\n```\n\n#### getFunctionById = id =>\nReturns a Function as a promise based on the ID provided.\n\n```js\nconst func = await AssistantAPIClient.getFunctionById('id...');\n```\n\n#### addFunctionExecutionListener = async (id, cb) =>\nAssociates a callback function with the execution of a particular Function. When the Function matching the id parameter is executed, its FunctionExecutionResult object passed to the callback. Returns undefined.\n\nExample function execution callback and listener registration:\n\n```js\nfunction exampleFunctionCB (result){\n  console.log(`Function executed with result:`, result)\n}\n\nAssistantAPIClient.addFunctionExecutionListener('id...', exampleFunctionCB)\n```\n\n#### removeFunctionExecutionListener = async (id, cb) =>\nRemoves a Function execution listener based on the function ID and a reference to the callback function. If no callback is supplied, all listeners associated with the Function ID will be removed. Returns undefined.\n\n```js\nAssistantAPIClient.removeFunctionExecutionListener('id..', exampleFunctionCB)\n```\n\n### Kinds\nThe `Kind` object:\n```js\n{\n    id: string\n    name: string\n    service: {\n      id\n      name\n    }\n    isGenerated: boolean\n    schema {\n      id: string\n      name: string\n      type: string\n      typeKindId: string\n      modifiers: Array[string]\n      kind {\n        id: string\n        name: string\n      }\n    }\n}\n```\n\n#### createKind = input =>\nCreates a Kind based on an input object. Returns a promise that resolves to the created Kind object.\n\n```js\nconst kindInput = {\n name: \"someKind\",\n schema:[\n  { name: \"someField1\", type: STRING },\n  { name: \"someField2\", type: STRING }\n ]\n}\n\nconst newKind = await AssistantAPIClient.createKind(kindInput)\n```\n\n#### createKinds = input =>\nA plural version of `createKind` accepting an array of input objects.\nReturns a promise that resolves to an array of created Kind objects.\n\n```js\nconst kindsInput = [{\n name: \"someKind\",\n schema:[\n  { name: \"someField1\", type: STRING },\n  { name: \"someField2\", type: STRING }\n ]\n}, ...]\n\nconst newKinds = await AssistantAPIClient.createKinds(kindsInput)\n```\n\n\n#### updateKind = input =>\nUpdates a Kind based on an input object. \n\nUpdate Semantics: Only properties specified will be updated. If updating the schema, the entire schema must be specified as it will be replaced in its entirety. \n\nReturns a promise that resolves to the updated `Kind` object.\n\n```js\nconst updated = await AssistantAPIClient.updateKind(input)\n```\n\n#### deleteKind = input =>\nDeletes a Kind given a kind ID.\n\n```js\nconst deleted = await AssistantAPIClient.deleteKind(input)\n```\n\n#### getKindById = id =>\nReturns a promise that resolves to a Kind object given the specified kind ID. \n\nIn v3.2.2, any requested non-system kinds will be returned. \nIn v3.2.1, only kinds in the workspace or those of imported services will be returned. \n\n```js\nconst kind = await AssistantAPIClient.getKindById(id)\n```\n\n#### getKindsById = ids =>\nReturns a promise that resolves to an array of Kind objects given an array of kind IDs. Only kinds in the workspace or those of imported services will be returned. \n\n```js\nconst ids = [\"...\",\"...\",...]\nconst kind = await AssistantAPIClient.getKindsById(ids)\n```\n\n#### getAllReferencedKinds = input =>\nRecursively collects all kinds that are referenced in a kind's schema, starting\nwith a kind ID. For example if the ID of kind A is supplied as an input, and Kind `A` contains a field of type Kind `B`, and `B` contains a field of type Kind `C`, \nan array containing the kinds objects for `A`, `B`, `C` will be returned (as a promise).\n\n```js\nconst initialId = [\"...\"]\nconst kinds = await AssistantAPIClient.getAllReferencedKinds({\n          ids: initialId\n        })\n```\n\n\n### Inventory\n\nThe `InventoryChanged` object:\n```js\n{\n  kinds: {\n    adds: [DiffItem]\n    deletes: [DiffItem]\n    updates: [DiffItem]\n  }\n  functions:{\n    adds: [DiffItem]\n    deletes: [DiffItem]\n    updates: [DiffItem]\n  }\n  services: {\n    adds: [DiffItem]\n    deletes: [DiffItem]\n    updates: [DiffItem]\n  }\n}\n```\n\nThe `DiffItem` object:\n```js\n{\n  id: string,\n  name: string\n}\n```\n\n#### addInventoryChangedListener = async cb =>\nRegisters a callback function with the inventory changed event. When workspace inventory changes the callback function will be called with the InventoryChangedobject. Returns undefined.\n\n*Current limitations: Kind and Function updates only occur where the name property is changed. Updates to services outside of the workspace will not be detected. \n\n**Use-case note: an ‘update’ diff for inventory services is unlikely in general usage. \n\n```js\nconst inventoryCB = ({diff}) => {\n  if(diff.kinds) console.log('KINDS CHANGED',diff.kinds)\n  if(diff.functions) console.log('FUNCTIONS CHANGED', diff.functions)\n  if(diff.services) console.log('SERVICES CHANGED',diff.services)\n}\n\nAssistantAPIClient.addInventoryChangedListener(inventoryCB)\n```\n\nThis function exists on the Q-Assisant-Client only--only enableSelectionChangedNotification is used on the API side. \n\n#### removeInventoryChangedListener = async cb =>\nRemoves an inventory changed listener given the referenced callback. If no callback is specified, all listeners will be removed. Returns undefined.\n\n```js\nAssistantAPIClient.removeInventoryChangedListener(inventoryCB)\n```\n\nThis function exists on the Q-Assisant-Client only--only disableSelectionChangedNotification is used on the API side. \n\n#### moveKindsAndFunctions = (originId, targetId, kindIds, functionIds) =>\nMoves a collection of Kinds and Functions from the origin Workspace to the target Workspace.\n \n```js\n  await AssistantAPIClient.moveKindsAndFunctions(\n    originWorkspaceId,\n    targetId,\n    kindIds,\n    functionIds\n  );\n```\n\n\n## Troubleshooting Assistant Issues\n### Assistant root file has loaded, but not other content\nObserving in the browser's dev tools that some resources have loaded correctly (usually the root), but other's haven't (usually nested files or chunks), is indicative of a failure of Q Gateway to proxy due to not having a 'relative' path structure.\n\n### You are seeing post-robot `NO ACK` errors in the console.\nThese errors stem from a failed acknowledgement for a call either between the client and the API or vice-versa. Here, this means that the web app 'window' (the assistant) cannot communicate with, or access, the 'window.parent' (Maana K-Portal) object. \n\nCommonly, these will stem from the 'window' (the assistant) not being loaded or in a loadable state, which means the API will not receive an acknowledgement when it fires an event. \n\nImproper CORS configuration is also a common culprit (also verify if using docker or nginx that your proxying and networking is configured correctly to allow communication and to accout for CORS).","readmeFilename":"README.md","gitHead":"3928c6e521aabf7f839346eaff23629f06be8461","_id":"@io-maana/q-assistant-client@3.2.2-beta.33","_npmVersion":"6.4.1","_nodeVersion":"10.15.3","_npmUser":{"name":"teamcitymaana","email":"teamcity@maana.io"},"dist":{"integrity":"sha512-2iC+kLu68mHBNdWgca5Cu9drzyEOAmpA6CZmw2dP9cotEZ2BnwSAFq0t/EoWo9+y6Q3e7RH1XcfBHfBHExr3pg==","shasum":"2625d29501a90fb02fc0ecfa1deeb13485e4c521","tarball":"https://registry.npmjs.org/@io-maana/q-assistant-client/-/q-assistant-client-3.2.2-beta.33.tgz","fileCount":10,"unpackedSize":58596,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJe2oSrCRA9TVsSAnZWagAAYB0P/3BC/UriXsenhqlTF0xD\nwBEUxG6G2fRZwCjE3OQBxiRnSXUpa+Lu/zfT/0NQtD657M46GKUzVukSyenF\npPRJu3yb9jSGivs7prho/SpHTqYC2JjTBxr1ZIwBcuS4Ulby0PKiUV7ZmCU1\nZ6Udy2uHgM2ALBTD1mq0m+VlzvYDl1nhJqrYws+KxlOzV/HbTfS7OqbPRy8O\nir9FrnUAp4k8PaPzy/vtJ/UrRl/a3dX96ljYFRQjl0pjha/voG206tfzA2FQ\nP5xcaV10SOLeqVPkTGI2wpiYq/Fm2r3zryip4hfdfYFXnClKWIob19EidlX/\n52viRt8Y5sP44Z+qRpgfQPBdklkLLu6tYpZZaiS5flPqrlULDA/OWLyq6rZj\nhi1Y3EXc7UCzrLsXMxzKaRDF4QvSfMAXGaMm+O9r15f+C2SbAKCQh31YjTvk\nFZ/uzj5awcXu0FaEsAezAsX50AVLJYo/u4VlAtyglSCNv4vYZ60TZPYchBiN\n+eB1JRVHZveCnHW813R1LONU0DqVSzCI/LQJKi8mNbhUQaRymazbZjfaysbB\n1qWoVTYYgiJWwL5rfvD6kXSyBCTr8R0ZFvrFBl3uDShyYYx6XmJRi1NiI+Gr\ne1y4aYLoIjzp6j79BTu5a+rJ/s0QoRaRt67xUhv3vAjE+teWaiCLcQslgxDM\nHk1q\r\n=Ia2A\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIAd1LUVQnDh/ejwXYVgM2YtSut0QnGvM5TgCGlZBh6/QAiEA/+V4sUk1jq75KlJRHDDc9dssrLP1uGN/+njuAHLXlIY="}]},"maintainers":[{"email":"andrey@maana.io","name":"abatyuk"},{"email":"bzvestey@gmail.com","name":"bzvetey"},{"email":"dlewissandy@maana.io","name":"dlsmaana"},{"email":"rob@maana.io","name":"rpovey"},{"email":"teamcity@maana.io","name":"teamcitymaana"},{"email":"witt3rd@witt3rd.com","name":"witt3rd"}],"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/q-assistant-client_3.2.2-beta.33_1591379115113_0.5959230204785084"},"_hasShrinkwrap":false},"3.2.2-beta.34":{"name":"@io-maana/q-assistant-client","version":"3.2.2-beta.34","description":"JavaScript package to streamline communication between an assistant and the Maana Q Assistant API.","main":"build/index.js","exports":{"./":"./build/"},"scripts":{"build":"babel src --out-dir build","prepack":"npm run build","test":"echo \"Error: no test specified\" && exit 1","format":"prettier --write \"src/**/*.js\""},"repository":{"type":"git","url":"git+https://github.com/maana-io/q-assistant-client.git"},"keywords":["Maana","Q"],"author":{"name":"Logan Gore @ Maana.io"},"license":"MIT","bugs":{"url":"https://github.com/maana-io/q-assistant-client/issues"},"homepage":"https://github.com/maana-io/q-assistant-client#readme","dependencies":{"core-js":"3.6.4","post-robot":"10.0.29"},"devDependencies":{"@babel/cli":"^7.5.5","@babel/core":"^7.5.5","@babel/plugin-proposal-class-properties":"^7.5.5","@babel/preset-env":"^7.5.5","prettier":"1.19.1"},"readme":"# q-assistant-client\nA lightweight JavaScript client for Maana-Q Assistant developers that wraps post-message communication between an embedded Maana-Q assistant and the Maana-Q UI.\n\n## Abstract\nThe Q-Assistant-Client is intented to be used in a web application being leveraged as a Maana Q assistant (embedded as an iframe).\nThis assistant client will facilitate communication between the assistant and the parent frame.\nThe client provides a rich, asynchronous experience over what would otherwise be 'fire-and-forget'-style messaging \nvia post-post message communication. \n\n## Requirements and Assumptions\n\n### Post-Robot Library\nThe Maana Knowledge Portal (KPortal) uses the kraken/post-robot library [kraken/post-robot](https://github.com/krakenjs/post-robot) to enrich the communication with the assistant. Post-robot allows for asynchronous, promise-based request/response style behavior between the assistant and the assistant API.\n\nThe API requires that the client use the post-robot library. This assistant-client library is the easiest way to achieve this, and also adds a fair amount of 'sugar' to the process to improve developer productivity. Developers could, however, use post-robot directly in their own client implementation. \n\n### Maana-Gateway Proxy Requirements\nThe Maana-Gateway service requires relative paths (paths relative to the root) in the assistant web application in order to proxy the application and its content. For create-react-apps, for instance, this means setting \"homepage\" to \".\" in the package.json file.\n\n## Singleton Instance\nThe client is exported as a singleton to avoid duplicate registration on event listeners.\nYou can import the instance like this:\n\n```js\nimport AssistantAPIClient from '@io-maana/q-assistant-client';\n```\n\nFunction calls can be made against the client instance like any other javascript object. They are all async.\n\n```js\nconst workspace = await AssistantAPIClient.getWorkspace(); \nconsole.log(\"Workspace:\", workspace)\n```\n\n## Dependencies\nPost-Robot\nhttps://github.com/krakenjs/post-robot\n\nPost-robot is used to provide a richer communication layer atop post-message.\n\n## Versioning\nThe Maana Q Assistant Client does not follow semantic versioning. Its versions\ntrack the releases of the Maana Q platform.\n\n## Examples\n@TODO Logan\n\n\n## Changes in v3.2.2\nImprovements in v3.2.2\n- Assistant State Management: WORKING, IDLE\n- Background Messaging/Eventing\n- Render Modes: BACKGROUND, DISPLAY\n- Expansion of Workspace object capabilities\n- Error Reporting\n- Repair Event\n- Plural versions of calls such as updateKind(s) to improve performance and developer experience.\n- InventoryChanged diffing is fully granular in v3.2.2--limitations\nin v3.2.1 only fired the Function diff for changes in Function name.\n\n### Deprecation\nThe following surface area IS removed from the \nclient in v3.2.2, and IS deprecated in the API:\n- AssistantAPIClient.enableSelectionChangedNotification\n- AssistantAPIClient.disableSelectionChangedNotification\n- AssistantAPIClient.enableInventoryChangedNotification\n- AssistantAPIClient.disableInventoryChangedNotification\n\nThe following surface area WILL BE removed from\nthe client in v3.2.4, and WILL BE deprecated in the API:\n- AssistantAPIClient.updateFunction (expected move to Workspace object)\n- AssistantAPIClient.updateKind (expected move to Workspace object)\n- AssistantAPIClient.deleteKind (expected move to Workspace object)\n- AssistantAPIClient.deleteFunction (expected move to Workspace object)\n\n## API Documentation\n\n### Assistant Render Mode\nAn assistant's render mode refers to whether it is being displayed in a visible manner to the user. As of v3.2.2, assistants are not closed when they are out of view.\nAll assistants will be loaded and kept in `BACKGROUND` render mode until they are \nplaced in the assistant panel, at which point the `DISPLAY` render mode event will be fired. \n\nNote: Assistants will receive all notifications/events while in BACKGROUND mode.\n\nDesign Consideration: It will be up to the developer to determine how state and resource use will be managed while an assistant is operating between BACKGROUND and DISPLAY modes.\n\n#### addRenderModeChangedListener = (cb) =>\nA listener to receive push events as to the assitant's render mode being changed. \n\n```js\nfunction handleRenderModeChanged(renderMode){\n  if (renderMode === 'DISPLAY'){\n    // Assistant is visible\n  } else {\n    // Assistant is not visible and running in background.\n  }\n}\n\nAssistantAPIClient.addRenderModeChangedListener(handleRenderModeChanged)\n\n```\n\n#### removeRenderModeChangedListener = (cb) =>\nRemoves the renderModeChanged listener by reference, or if no callback function reference is provided, it removes all listeners.\n\n#### getRenderMode = () =>\nReturns the current assistant render mode.\n\n```js\nconst renderMode = await AssistantAPIClient.getRenderMode()\n\nif (renderMode === 'DISPLAY'){\n  // Assistant is visible\n} else {\n  // Assistant is not visible and running in background.\n}\n\n```\n\n### Repair\nAssistants may get into situations where they are either out of sync with the Maana Q UI, or in a failure state. Assistants should be able to recover from these states. \n\nThe repair event functionality added in v3.2.2 is designed to notify the assistant that it must repair itself. This could mean a resync with its resources on the workspace or externally or, for some assistants, nothing at all. \n\nWhen is repair triggered? \nEither manually by a user clicking 'repair workspace' under the\nassistant inventory panel, or upon a workspace clone event. An assistant will be expected to handle either scenario. \n\nPerformance Consideration: \nFor some assistants, repair might involve 'introspecting' \nand processing the current workspace or Q system resources. This could be very resource intensive. Make sure you review this API guide to have an idea of what tools are\navailable to get the best results. It's always a good idea to check performance of repair on a large workspace and ensure necessary optimizations have been made. \n\nDesign Consideration: \nMake your workflows modular enough to be reused between repair and normal usage if possible. \n\n#### addRepairListener (cb) =>\n```js\n\nAssistantAPIClient.addRepairListener(()=>{\n  // Self-heal\n})\n\n```\n\nRecommended Usage: A repair process should be wrapped in the try/catch/finally flow shown in the `setAssistantState` API call to provide the user assistant-state and error updates as well as pause `inventoryChanged` notifications during repair (if the assistant has subscribed).\n\n#### removeRepairListener = (cb) =>\nRemoves the repair listener by reference, or if no callback function reference is provided, it removes all listeners.\n\n### User-facing Error Handling\n\n#### reportError (error) =>\nReports an error to the UI to be displayed in the assistant's error log in the \ninventory panel. This call is not disruptive and designed to operated independently of other assistant operations, such as state management. See `setAssistantState` in the next section.\n\nRecommended usage: use this functionality where it would futher the user experience\nto show the user an error and it's cause. Do not use this where things will be retried, \ncleaned up automatically, or are not relevant to the user. \n\n```js\ntry{\n  // Do work\n} catch(e) {\n  AssistantAPIClient.reportError(e)\n}\n```\n\n### State management\n\n#### clearState = () =>\nThis will remove all callbacks from all listeners. \n\n```js\nawait AssistantAPIClient.clearState()\n```\n\n#### setAssistantState = (state) =>\nThis sets the current state of the assistant using the \n`AssistantState` enum. Setting a state of `WORKING` will \ncreate the 'working' status spinner in the Assistant \nInventory Panel in the Maana Q UI. Conversely, setting an `IDLE` state will \nremove the spinner. This adds to user experience by informing users of the \nstatus of operations.\n\n```js\nimport {\n  default as AssistantAPIClient,\n  AssistantState\n} from '@io-maana/q-assistant-client'\n\n...\n\nAssistantAPIClient.setAssistantState(AssistantState.WORKING)\n\n...\n\nAssistantAPIClient.setAssistantState(AssistantState.IDLE)\n\n```\nUI User Prompt: If the assistant is in a `WORKING` state, the Maana Q UI will\nwarn the user before leaving the workspace. \n\nNOTE: while an assistant is in a working state, it will\nnot receive `inventoryChanged` events--an aggregated inventory diff\nwill be sent once the assistant is set back to `IDLE`.\n\nRecommended usage: Control states at a high level using try/catch/finally\nflow incorporating the `reportError` API call.\n\n```js\ntry{\n  AssistantAPIClient.setAssistantState(AssistantState.WORKING)\n  // Do work, await high-level tasks, etc.\n} catch(e) {\n  AssistantAPIClient.reportError(e)\n} finally{\n  AssistantAPIClient.setAssistantState(AssistantState.IDLE)\n}\n```\n\n#### AssistantState (enum)\nContains the valid assistant states: `IDLE` or `WORKING`.\n\nMust be imported in addition to the AssistantAPIClient:\n\n```js\nimport {\n  default as AssistantAPIClient,\n  AssistantState\n} from '@io-maana/q-assistant-client'\n```\n\n\n### User Info\nThe `UserInfo` object:\n```js\n{\n email: string,\n name: string\n}\n```\n\n#### getUserInfo = () => \nReturns a Userinfo object pertaining to the logged in user.\n\n```js\nconst userInfo = await AssistantAPIClient.getUserInfo()\n```\n### Selection\nThe `Selection` object:\n```js\n{\n  kindId: string\n  kindName: string\n  id: string\n}\n```\n\n#### getCurrentSelection = () => \nReturns an Array of `Selection` objects:\n\n```js\nconst {selection} = await AssistantAPIClient.getCurrentSelection();\n```\n\n#### addSelectionChangedListener = async cb =>\nAdds a callback function to be executed upon a valid workspace selection change.\n\nCallback value is an array of Selection objects:\n\n```js\n// Create the selection callback.\nconst selectionCB = ({selection})=>{\n  console.log('Workspace selection has changed.')\n  selection.forEach(i=>{\n    console.log('Kind: ',i.kindName)\n    console.log('Instance Id:',i.id)\n    console.log('Kind Id:',i.kindId)\n  })\n}\n\n// Add the listener.\nAssistantAPIClient.addSelectionChangedListener(selectionCB);\n```\n\nThis function only exists on the Q-Assistant-Client--only enableSelectionChangedNotification is called on the API. \n\n#### removeSelectionChangedListener = async cb =>\nThis will have to be called on a 1:1 basis with addSelectionChangedListener calls if supplying a callback.\n\n```js\nAssistantAPIClient.removeSelectionChangedListener(selectionCB)\n```\n\n**If NOT supplying a callback to this call, all selection changed listeners will be removed.\n\n```js\nAssistantAPIClient.removeSelectionChangedListener()\n```\n\nThis function only exists on the Q-Assistant-Client--only disableSelectionChangedNotification is called on the API. \n\n\n### Services\nThe `Service` object:\n```js\n{\n   id: string,\n   name: string\n   endpointUrl: string,\n   getKinds: () => // Returns [] of Kinds objects\n   getFunctions: () => // Returns [] of Function objects\n}\n```\n\n#### getServiceById = id =>\nThis will return a service that exists within the scope of the workspace. \n** Assistant services will return null. Services outside the scope of the workspace will cause an error to be returned as 'Unable to load a Service from outside of the workspace.'\n\n```js\nconst svc = await AssistantAPIClient.getServiceById(id)\n```\n\n#### createService = id => \nCreates a service in Q.\n\nNote: This will create the service, but does NOT import it into the workspace.\nYou will need to use `importService` on the Workspace object to import it.\nReturns a promise that resolves\n\n```js\n    const service = {\n      id: ...,\n      name: ...,\n      endpointUrl: ...,\n      serviceType: ...\n    }\n    \n    await AssistantAPIClient.createService(service)\n```\n\n#### deleteService = id =>\nDeletes a service from Q.\n\n```js\n    await AssistantAPIClient.deleteService(id)\n```\n\n#### refreshServiceSchema = id =>\nRefreshes a service by fetching its schema. This will also\nreload the service inventory in the currently visible workspace.\n\n```js\nawait AssistantAPIClient.refreshServiceSchema(\"id\")\n```\n\n#### reloadService = id =>\nReloads a service in the inventory in the currently visible workspace.\n\n```js\nawait AssistantAPIClient.reloadService(\"id\")\n```\n\n### Workspace\n\n#### getWorkspace = () =>\nReturns a Workspace object representing the workspace. \n\n```js\nconst ws = await AssistantAPIClient.getWorkspace(id)\n```\n\nNote: The `id` parameter is optional. If it is not supplied, the query\nwill return the current/visible workspace. \n\nThe `Workspace` object:\n\n```js\n\n{\n    id: string,\n    name: string,\n    endpointUrl: string,\n    workspaceServiceId: string,\n    modelServiceId: string,\n    logicServiceId: string,\n\n    //\n    // Knowledge Graphs\n    //\n    getActiveGraph: async () => {\n      // Returns the active Graph object.\n      // Returns null if active graph is not of type 'Knowledge Graph', or if an\n      // active graph is deleted, thereby setting active graph to null.\n    },\n    getKnowledgeGraphs: async () => {\n      // Returns [Graph]\n    },\n    // TODO: define input\n    createKnowledgeGraph: input =>\n    // TODO: define input\n    createKnowledgeGraphs: input =>\n\n    //\n    // Services\n    //\n    getImportedServices: async () => {\n      // Returns an array of Service objects that have \n      // been imported into the workspace.\n      // No assistant services will be returned.\n    },\n    getImportedAssistants: async () => {\n      // Returns a list of imported assistants.\n    },\n    importService: serviceId => {\n      // Imports a service by it's ID. \n    },\n    importServices: serviceIds => {\n      // Imports services by their IDs.\n    },\n    removeServices: serviceIds => {\n      // Removes a list of services from the workspace.\n    },\n    removeService: serviceId => {\n      // Removes a service from the workspace.\n    },\n\n    //\n    // Functions\n    //\n    getFunctions: async () => {\n      // Returns an array of functions in the workspace (includes boilerplate).\n    },\n    createFunction: funcData => {\n      // Creates a function and adds it to the graph. \n    }\n    createFunctions: funcData =>{\n      // Creates several functions and adds them to the graph. \n    }\n    updateFunction: funcData => {\n      // Updates a function.\n    },\n    updateFunctions: funcData =>{\n      // Updates functions based on input array.\n    },\n    deleteFunction: funcId => {\n      // Deletes a function by its ID.\n    },\n    getFunctionGraph: funcId => {\n      // Returns a function graph by its ID.\n    }\n\n    //\n    // Kinds\n    //\n    getKinds: async () => {\n      // Returns an array of functions in the workspace (includes boilerplate).\n    },\n    createKind: kindData => {\n      // Currently same input as AssistantAPIClient call.\n    },\n    createKinds: kindData => {\n      // Currently same input as AssistantAPIClient call.\n    },\n    updateKind: kindData => {\n      // Currently same input as AssistantAPIClient call.\n    },\n    updateKinds: kindData => {\n      // Currently same input as AssistantAPIClient call.\n    },\n    deleteKind: kindId => {\n      // Currently same input as AssistantAPIClient call.\n    }\n    // Event Triggers\n    triggerRepairEvent: () => {\n      // Triggers the repair event on a workspace. \n    }\n  };\n}\n```\n\n\n### Graphs\nThe `Graph` object:\n```js\n{     \nid: string,\nname: string,\noffsetX: Number,\noffsetY: Number,\nzoom: Number,\ngetNodes: async () => {\n    // Returns [Node]\n},\n\naddNode: async (type, instance, changeSelection) => {\n    // Returns Node\n},\nremoveNode: async id => {\n    // Should return nothing or error.\n    // Currently returning [] in all cases.\n},\nupdateNodeLayout: async (nodeId, { x, y, collapsed }) => {\n},\nupdateGraphLayout: async ({ offsetX, offsetY, zoom }) => {\n}\n}\n```\n\n#### Getting a graph object:\nGraph objects are obtained through an instance of a Workspace \n\n```js\nconst ag = await ws.getActiveGraph()\n```\n\nor\n\n```js\nconst kgs = await ws.getKnowledgeGraphs()\n```\n\n#### Manipulating Graphs\n\n**Only the active graph may be manipulated.\n\nAll graph manipulations should be ‘visually’ verifiable on the graph itself, i.e., adds/removes/positioning, should all be reflected on the graph itself. \n\nThe `Node` object:\n```js\n{\nid: string\nx: number\ny: number\ncollapsed: boolean\nknowledgeGraphNode {\n  id: string\n  innerKind: Kind\n  innerFunction: Function\n}\n}\n```\n\n#### addNode(type, instance, changeSelection) =>\n\nTakes type (“Function” or “Kind”), instance (the Function or Kind object), and optionally a boolean to indicate whether the selection should be changed to this new node. \n\nReturns the newly created Node object.\n\n```js\nconst node = await ag.addNode('Kind',kind)\n```\n\n#### removeNode(id) =>\n\nTakes the id of Node to be deleted. Returns either undefined or an error. \n\n```js\nawait ag.removeNode(node.id)\n```\n\n#### getNodes() =>\nReturns an array of Node objects from the graph. \n\n```js\nconst nodes = await ag.getNodes()\n```\n\n#### updateNodeLayout: async (nodeId, { x, y, collapsed})=>\nUpdates a Node layout given a node ID and node coordinates (`x` and/or `y`) or a `collapsed` value. x/y values must be a number, and collapsed must be a boolean. Whatever is not specified will remain current.\n\n```js\nag.updateNodeLayout(id,{x:100,y:100,collapsed:true})\n```\n\n#### updateGraphLayout: async ({ offsetX, offsetY, zoom})=>\nUpdates a Graph layout given numerical values for x/y offsets and the zoom. \n\n```js\nag.updateGraphLayout({offsetX:50, offsetY:50, zoom: 70})\n```\n\n### Functions\n\nThe `Function` object:\n```js\n{\n    id: string\n    name: string\n    service {\n      id: string\n      name: string\n    }\n    arguments {\n      id: string\n      name: string\n      type: string\n      modifiers: Array[string]\n      typeKindId:: string\n      kind {\n        id: string\n        name: string\n      }\n    }\n    implementation {\n      id: string\n      entrypoint {\n        id: string\n      }\n      operations {\n        id: string\n        type: string\n        function {\n          id: string\n          name: string\n        }\n        argumentValues {\n          id: string\n          argument {\n            id: string\n          }\n          operation {\n            id: string\n          }\n          argumentRef: string\n        }\n      }\n    }\n    isGenerated: boolean\n    functionType: string\n    graphqlOperationType: string\n    outputType: string\n    outputKindId: string\n    outputModifiers: Array[string]\n    kind {\n      id: string\n      name: string\n    }\n}\n```\n\n`FunctionExecutionResult` object:\n```js\n{\n  id: string,\n  result: JSON\n}\n```\n\n#### executeFunction = ( {id, variables, resolve} ) =>\nExecutes a function based on its id, with optional inputs for variables and a resolve string (this specifies the fields to be returned, which must be valid based on the result).\n\nReturns : JSON matching shape of result , unless no sub-selection of fields is required in the execution.\n\nThis following piece of code will execute a Function given a function ID, and pass in variables for ‘example’, requesting back id and name fields. \n\n```js \nconst res = await AssistantAPIClient.executeFunction({functionId: func.id, variables: {\"variableName\": \"variableValue\"}, resolve: \"{ id name }\");\n```\n\n#### createFunction = input =>\nCreates a function based on the input provided. \n\nReturns: the created Function object.\n\n**Using create function will only place the function in the workspace’s inventory--it will not place the function as a node on the Graph. In order to do this, you must pass the created function into the addNode function on the active Graph, making sure to specify ‘Function' as the type.\n\n```js\nconst createFunctionInput = {\n  name:\"yourName\",\n  arguments:[],\n  outputType: \"STRING\",\n  graphqlOperationType:\"QUERY\",\n  functionType: \"CKG\"\n}\n  \nconst createdFunction = await AssistantAPIClient.createFunction(createFunctionInput)\n```\n\n#### updateFunction = input =>\nInput is the same for creating a function. It’s important to note that the arguments property will be replaced in it’s entirety with whatever is provided (if a value is provided.\n\nReturns the updated `Function` object.\n\n```js\nconst updatedFunction = await AssistantAPIClient.updateFunction(input);\n```\n\n#### deleteFunction = input =>\nInput is the id of the Function to be deleted. Returns the deleted function as a promise.\n\n```js\nconst deletedFunction = await AssistantAPIClient.deleteFunction('id...');\n```\n\n#### getFunctionById = id =>\nReturns a Function as a promise based on the ID provided.\n\n```js\nconst func = await AssistantAPIClient.getFunctionById('id...');\n```\n\n#### addFunctionExecutionListener = async (id, cb) =>\nAssociates a callback function with the execution of a particular Function. When the Function matching the id parameter is executed, its FunctionExecutionResult object passed to the callback. Returns undefined.\n\nExample function execution callback and listener registration:\n\n```js\nfunction exampleFunctionCB (result){\n  console.log(`Function executed with result:`, result)\n}\n\nAssistantAPIClient.addFunctionExecutionListener('id...', exampleFunctionCB)\n```\n\n#### removeFunctionExecutionListener = async (id, cb) =>\nRemoves a Function execution listener based on the function ID and a reference to the callback function. If no callback is supplied, all listeners associated with the Function ID will be removed. Returns undefined.\n\n```js\nAssistantAPIClient.removeFunctionExecutionListener('id..', exampleFunctionCB)\n```\n\n### Kinds\nThe `Kind` object:\n```js\n{\n    id: string\n    name: string\n    service: {\n      id\n      name\n    }\n    isGenerated: boolean\n    schema {\n      id: string\n      name: string\n      type: string\n      typeKindId: string\n      modifiers: Array[string]\n      kind {\n        id: string\n        name: string\n      }\n    }\n}\n```\n\n#### createKind = input =>\nCreates a Kind based on an input object. Returns a promise that resolves to the created Kind object.\n\n```js\nconst kindInput = {\n name: \"someKind\",\n schema:[\n  { name: \"someField1\", type: STRING },\n  { name: \"someField2\", type: STRING }\n ]\n}\n\nconst newKind = await AssistantAPIClient.createKind(kindInput)\n```\n\n#### createKinds = input =>\nA plural version of `createKind` accepting an array of input objects.\nReturns a promise that resolves to an array of created Kind objects.\n\n```js\nconst kindsInput = [{\n name: \"someKind\",\n schema:[\n  { name: \"someField1\", type: STRING },\n  { name: \"someField2\", type: STRING }\n ]\n}, ...]\n\nconst newKinds = await AssistantAPIClient.createKinds(kindsInput)\n```\n\n\n#### updateKind = input =>\nUpdates a Kind based on an input object. \n\nUpdate Semantics: Only properties specified will be updated. If updating the schema, the entire schema must be specified as it will be replaced in its entirety. \n\nReturns a promise that resolves to the updated `Kind` object.\n\n```js\nconst updated = await AssistantAPIClient.updateKind(input)\n```\n\n#### deleteKind = input =>\nDeletes a Kind given a kind ID.\n\n```js\nconst deleted = await AssistantAPIClient.deleteKind(input)\n```\n\n#### getKindById = id =>\nReturns a promise that resolves to a Kind object given the specified kind ID. \n\nIn v3.2.2, any requested non-system kinds will be returned. \nIn v3.2.1, only kinds in the workspace or those of imported services will be returned. \n\n```js\nconst kind = await AssistantAPIClient.getKindById(id)\n```\n\n#### getKindsById = ids =>\nReturns a promise that resolves to an array of Kind objects given an array of kind IDs. Only kinds in the workspace or those of imported services will be returned. \n\n```js\nconst ids = [\"...\",\"...\",...]\nconst kind = await AssistantAPIClient.getKindsById(ids)\n```\n\n#### getAllReferencedKinds = input =>\nRecursively collects all kinds that are referenced in a kind's schema, starting\nwith a kind ID. For example if the ID of kind A is supplied as an input, and Kind `A` contains a field of type Kind `B`, and `B` contains a field of type Kind `C`, \nan array containing the kinds objects for `A`, `B`, `C` will be returned (as a promise).\n\n```js\nconst initialId = [\"...\"]\nconst kinds = await AssistantAPIClient.getAllReferencedKinds({\n          ids: initialId\n        })\n```\n\n\n### Inventory\n\nThe `InventoryChanged` object:\n```js\n{\n  kinds: {\n    adds: [DiffItem]\n    deletes: [DiffItem]\n    updates: [DiffItem]\n  }\n  functions:{\n    adds: [DiffItem]\n    deletes: [DiffItem]\n    updates: [DiffItem]\n  }\n  services: {\n    adds: [DiffItem]\n    deletes: [DiffItem]\n    updates: [DiffItem]\n  }\n}\n```\n\nThe `DiffItem` object:\n```js\n{\n  id: string,\n  name: string\n}\n```\n\n#### addInventoryChangedListener = async cb =>\nRegisters a callback function with the inventory changed event. When workspace inventory changes the callback function will be called with the InventoryChangedobject. Returns undefined.\n\n**Use-case note: an ‘update’ diff for inventory services is unlikely in general usage. \n\n```js\nconst inventoryCB = ({diff}) => {\n  if(diff.kinds) console.log('KINDS CHANGED',diff.kinds)\n  if(diff.functions) console.log('FUNCTIONS CHANGED', diff.functions)\n  if(diff.services) console.log('SERVICES CHANGED',diff.services)\n}\n\nAssistantAPIClient.addInventoryChangedListener(inventoryCB)\n```\n\nThis function exists on the Q-Assisant-Client only--only enableSelectionChangedNotification is used on the API side. \n\n#### removeInventoryChangedListener = async cb =>\nRemoves an inventory changed listener given the referenced callback. If no callback is specified, all listeners will be removed. Returns undefined.\n\n```js\nAssistantAPIClient.removeInventoryChangedListener(inventoryCB)\n```\n\nThis function exists on the Q-Assisant-Client only--only disableSelectionChangedNotification is used on the API side. \n\n#### moveKindsAndFunctions = (originId, targetId, kindIds, functionIds) =>\nMoves a collection of Kinds and Functions from the origin Workspace to the target Workspace.\n \n```js\n  await AssistantAPIClient.moveKindsAndFunctions(\n    originWorkspaceId,\n    targetId,\n    kindIds,\n    functionIds\n  );\n```\n\n\n## Troubleshooting Assistant Issues\n### Assistant root file has loaded, but not other content\nObserving in the browser's dev tools that some resources have loaded correctly (usually the root), but other's haven't (usually nested files or chunks), is indicative of a failure of Q Gateway to proxy due to not having a 'relative' path structure.\n\n### You are seeing post-robot `NO ACK` errors in the console.\nThese errors stem from a failed acknowledgement for a call either between the client and the API or vice-versa. Here, this means that the web app 'window' (the assistant) cannot communicate with, or access, the 'window.parent' (Maana K-Portal) object. \n\nCommonly, these will stem from the 'window' (the assistant) not being loaded or in a loadable state, which means the API will not receive an acknowledgement when it fires an event. \n\nImproper CORS configuration is also a common culprit (also verify if using docker or nginx that your proxying and networking is configured correctly to allow communication and to accout for CORS).","readmeFilename":"README.md","gitHead":"90c869b003628e223b5d0d73a351fa883958bfd2","_id":"@io-maana/q-assistant-client@3.2.2-beta.34","_npmVersion":"6.4.1","_nodeVersion":"10.15.3","_npmUser":{"name":"teamcitymaana","email":"teamcity@maana.io"},"dist":{"integrity":"sha512-ujKCx+Crw2dMpcgIpe+24rF5/saNXKO3e48a9B8J5PMUH69UMxFcFxpw30TK52uRew7ymOcZemXtpjQoxkHo9w==","shasum":"ff3cdea7f80ced6d9576b827531a7f7ddbf7e82c","tarball":"https://registry.npmjs.org/@io-maana/q-assistant-client/-/q-assistant-client-3.2.2-beta.34.tgz","fileCount":10,"unpackedSize":58599,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJe2oplCRA9TVsSAnZWagAAd2cP/1OFS+iMs2ZBn1oTGQNI\nW0xvvMwhH6X8UK/aYEc2o7SXxSMXpDuP1WzukGwVR/o4dq93TITOO09PYmO6\nEuWHOSNntPyhOh3qIdylWlQ2U4b4ZM2+YYZpPhSeXyY3t2fjw/TnWpZmhbPh\nYqnQSqAkkL2SNiGHU2ner0kEPu5FGIVxypjISMEhLdIDe/p37Ei5NiJsngMB\n+r2xmDTOgVYMnkUnj1mJa64qqf5tN+pQPz7gzQRVMwxNffcr8AnI0fXCGFYr\nv9Noxcl1OuSTeBK/dNcWmHSCFTg5m2vWfWA3YbosxpMsmKlsTRZGtIoaLqmo\n4X1KOeLv69/4Ly44a1a1+nFdcX8TByzB6RJ1dLVCSm1jSHP1z/ldpI/vXqLy\nFZ8vEYyz3PendBuwXFAJtn33pDZ+55FWI/9B6elDNrAy2skFoCNyq/jtb4XU\nbI0LlFaBpjSUcoo8ZZo/vOYACcSWsAdDFu7J9LymPbRUyTB00kpillTmOKvP\nzAChMPCYRDWiQ0zI1ARV58pEIApoYZYdTBkJM+EcVOh62pUDy40BnpeuSDoM\nTH0dNqaaPcl7kBtYKLdLvMGGPjTcH49F9g/b56nPSFgBCQ3k8TQ2EqkNuxw7\ndq+HQlVwxtu2rHmejYZnp32E7kdHedHWoI6Xj0mf3Wa2S4Vj4YRfcyzqo5MM\nl+vL\r\n=rNqS\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEYCIQDojz0DljA414wzBhpjtQ53UTtYrqHRcdTMKK4XRr2+FgIhAL8SgMW1C5D4KbmfCwhR+uTOa0SMQpKm4TvoHBHCnaB4"}]},"maintainers":[{"email":"andrey@maana.io","name":"abatyuk"},{"email":"bzvestey@gmail.com","name":"bzvetey"},{"email":"dlewissandy@maana.io","name":"dlsmaana"},{"email":"rob@maana.io","name":"rpovey"},{"email":"teamcity@maana.io","name":"teamcitymaana"},{"email":"witt3rd@witt3rd.com","name":"witt3rd"}],"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/q-assistant-client_3.2.2-beta.34_1591380580828_0.40074287281196286"},"_hasShrinkwrap":false},"3.2.2":{"name":"@io-maana/q-assistant-client","version":"3.2.2","description":"JavaScript package to streamline communication between an assistant and the Maana Q Assistant API.","main":"build/index.js","exports":{"./":"./build/"},"scripts":{"build":"babel src --out-dir build","prepack":"npm run build","test":"echo \"Error: no test specified\" && exit 1","format":"prettier --write \"src/**/*.js\""},"repository":{"type":"git","url":"git+https://github.com/maana-io/q-assistant-client.git"},"keywords":["Maana","Q"],"author":{"name":"Logan Gore @ Maana.io"},"license":"MIT","bugs":{"url":"https://github.com/maana-io/q-assistant-client/issues"},"homepage":"https://github.com/maana-io/q-assistant-client#readme","dependencies":{"core-js":"3.6.4","post-robot":"10.0.29"},"devDependencies":{"@babel/cli":"^7.5.5","@babel/core":"^7.5.5","@babel/plugin-proposal-class-properties":"^7.5.5","@babel/preset-env":"^7.5.5","prettier":"1.19.1"},"gitHead":"ced1f798390bbd7b3b75f78d64627e67e9d6d2d4","_id":"@io-maana/q-assistant-client@3.2.2","_npmVersion":"6.4.1","_nodeVersion":"10.15.3","_npmUser":{"name":"teamcitymaana","email":"teamcity@maana.io"},"dist":{"integrity":"sha512-cNTLCH5YrLhhNo/zuZzMgHCoP2H8UKQd2xbwLwixB8nGJQr0+AgsOjpQKIBluV+anmH2AGRjjdh3HasyCMCGOg==","shasum":"eb4b628b73957064df020c45928f3fe5a5096506","tarball":"https://registry.npmjs.org/@io-maana/q-assistant-client/-/q-assistant-client-3.2.2.tgz","fileCount":10,"unpackedSize":58591,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJe2p25CRA9TVsSAnZWagAAvEcP/jWvenCd3H4WR+iup+/Q\nMA8TQWjuMdxBokT5eoyeO+kr14udgpd9fC0iUgm5ipn85CPmwxdN4TfmvGC8\nzKHFfD3/wps6GIcb2RnvsnTqYCv8QnAAU3SMFibYwa1GiJrWU66bEZ6PyE4Z\netYO9CYvzih6P1D25PMUaXgQ3/STGstmmhcyAhtogDGdH/PknmyS6GPo4PIv\nAz0789+Gzy99KzvbocZzg/F67NmjPy8P6GE107GOiB5o9qgAoWdyEAYnXIes\nG6GqGh4zrzscL5/cz5QHk570V/f/guB+/YTeWVtPrCO/bLq1WXRH8PyDBgOK\n996r5LogCB8qiSy40HcEvAWIoNb96cOwOwjeEWLw2+zmcdqhF1AMM0iE6d7z\niHxDO5T5/ktpfRXeq7GiJ53Tw9aB5l6l5mVJqAoxKnKfdIaFYygjMNrFincX\na7JCCw93IBApUKCtomwkH1W7WWuNyYb0/M1LQeIK3kKnj4iX08krLq2U6Y/l\nAuk2kUGwNK3K+HVOBpmTlXi3Cp+jOJJCbOuEH0Dok7sssiwvmR/tgZ5hrj7a\nAlx6n2HheIbF4ROIs4S59WxspD4zBYiAQ45vXTAVFWRJYmWhM5y3OwuQwfZs\n476LVGc/78nWK2qhMb/dEe/88pb7Fuy55VwZKZxPmzMc+f0kTV5oGOYPih8w\nC+8M\r\n=xCGm\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIFC6Pp44aQQy5ZwKCkGdhQb6p1CdfBNVMxNpHYP+qSYyAiEAmojMdNhUTHeSPC4gkh6ooI7MciPr4+V2Bu1s6Ol8gjA="}]},"maintainers":[{"email":"andrey@maana.io","name":"abatyuk"},{"email":"bzvestey@gmail.com","name":"bzvetey"},{"email":"dlewissandy@maana.io","name":"dlsmaana"},{"email":"rob@maana.io","name":"rpovey"},{"email":"teamcity@maana.io","name":"teamcitymaana"},{"email":"witt3rd@witt3rd.com","name":"witt3rd"}],"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/q-assistant-client_3.2.2_1591385528368_0.45842193043514423"},"_hasShrinkwrap":false},"3.2.3-beta.35":{"name":"@io-maana/q-assistant-client","version":"3.2.3-beta.35","description":"JavaScript package to streamline communication between an assistant and the Maana Q Assistant API.","main":"build/index.js","exports":{"./":"./build/"},"scripts":{"build":"babel src --out-dir build","prepack":"npm run build","test":"echo \"Error: no test specified\" && exit 1","format":"prettier --write \"src/**/*.js\""},"repository":{"type":"git","url":"git+https://github.com/maana-io/q-assistant-client.git"},"keywords":["Maana","Q"],"author":{"name":"Logan Gore @ Maana.io"},"license":"MIT","bugs":{"url":"https://github.com/maana-io/q-assistant-client/issues"},"homepage":"https://github.com/maana-io/q-assistant-client#readme","dependencies":{"core-js":"3.6.4","post-robot":"10.0.29"},"devDependencies":{"@babel/cli":"^7.5.5","@babel/core":"^7.5.5","@babel/plugin-proposal-class-properties":"^7.5.5","@babel/preset-env":"^7.5.5","prettier":"1.19.1"},"readme":"# q-assistant-client\nA lightweight JavaScript client for Maana-Q Assistant developers that wraps post-message communication between an embedded Maana-Q assistant and the Maana-Q UI.\n\n## Abstract\nThe Q-Assistant-Client is intented to be used in a web application being leveraged as a Maana Q assistant (embedded as an iframe).\nThis assistant client will facilitate communication between the assistant and the parent frame.\nThe client provides a rich, asynchronous experience over what would otherwise be 'fire-and-forget'-style messaging \nvia post-post message communication. \n\n## Requirements and Assumptions\n\n### Post-Robot Library\nThe Maana Knowledge Portal (KPortal) uses the kraken/post-robot library [kraken/post-robot](https://github.com/krakenjs/post-robot) to enrich the communication with the assistant. Post-robot allows for asynchronous, promise-based request/response style behavior between the assistant and the assistant API.\n\nThe API requires that the client use the post-robot library. This assistant-client library is the easiest way to achieve this, and also adds a fair amount of 'sugar' to the process to improve developer productivity. Developers could, however, use post-robot directly in their own client implementation. \n\n### Maana-Gateway Proxy Requirements\nThe Maana-Gateway service requires relative paths (paths relative to the root) in the assistant web application in order to proxy the application and its content. For create-react-apps, for instance, this means setting \"homepage\" to \".\" in the package.json file.\n\n## Singleton Instance\nThe client is exported as a singleton to avoid duplicate registration on event listeners.\nYou can import the instance like this:\n\n```js\nimport AssistantAPIClient from '@io-maana/q-assistant-client';\n```\n\nFunction calls can be made against the client instance like any other javascript object. They are all async.\n\n```js\nconst workspace = await AssistantAPIClient.getWorkspace(); \nconsole.log(\"Workspace:\", workspace)\n```\n\n## Dependencies\nPost-Robot\nhttps://github.com/krakenjs/post-robot\n\nPost-robot is used to provide a richer communication layer atop post-message.\n\n## Versioning\nThe Maana Q Assistant Client does not follow semantic versioning. Its versions\ntrack the releases of the Maana Q platform.\n\n## Examples\n@TODO Logan\n\n\n## Changes in v3.2.2\nImprovements in v3.2.2\n- Assistant State Management: WORKING, IDLE\n- Background Messaging/Eventing\n- Render Modes: BACKGROUND, DISPLAY\n- Expansion of Workspace object capabilities\n- Error Reporting\n- Repair Event\n- Plural versions of calls such as updateKind(s) to improve performance and developer experience.\n- InventoryChanged diffing is fully granular in v3.2.2--limitations\nin v3.2.1 only fired the Function diff for changes in Function name.\n\n### Deprecation\nThe following surface area IS removed from the \nclient in v3.2.2, and IS deprecated in the API:\n- AssistantAPIClient.enableSelectionChangedNotification\n- AssistantAPIClient.disableSelectionChangedNotification\n- AssistantAPIClient.enableInventoryChangedNotification\n- AssistantAPIClient.disableInventoryChangedNotification\n\nThe following surface area WILL BE removed from\nthe client in v3.2.4, and WILL BE deprecated in the API:\n- AssistantAPIClient.updateFunction (expected move to Workspace object)\n- AssistantAPIClient.updateKind (expected move to Workspace object)\n- AssistantAPIClient.deleteKind (expected move to Workspace object)\n- AssistantAPIClient.deleteFunction (expected move to Workspace object)\n\n## API Documentation\n\n### Assistant Render Mode\nAn assistant's render mode refers to whether it is being displayed in a visible manner to the user. As of v3.2.2, assistants are not closed when they are out of view.\nAll assistants will be loaded and kept in `BACKGROUND` render mode until they are \nplaced in the assistant panel, at which point the `DISPLAY` render mode event will be fired. \n\nNote: Assistants will receive all notifications/events while in BACKGROUND mode.\n\nDesign Consideration: It will be up to the developer to determine how state and resource use will be managed while an assistant is operating between BACKGROUND and DISPLAY modes.\n\n#### addRenderModeChangedListener = (cb) =>\nA listener to receive push events as to the assitant's render mode being changed. \n\n```js\nfunction handleRenderModeChanged(renderMode){\n  if (renderMode === 'DISPLAY'){\n    // Assistant is visible\n  } else {\n    // Assistant is not visible and running in background.\n  }\n}\n\nAssistantAPIClient.addRenderModeChangedListener(handleRenderModeChanged)\n\n```\n\n#### removeRenderModeChangedListener = (cb) =>\nRemoves the renderModeChanged listener by reference, or if no callback function reference is provided, it removes all listeners.\n\n#### getRenderMode = () =>\nReturns the current assistant render mode.\n\n```js\nconst renderMode = await AssistantAPIClient.getRenderMode()\n\nif (renderMode === 'DISPLAY'){\n  // Assistant is visible\n} else {\n  // Assistant is not visible and running in background.\n}\n\n```\n\n### Repair\nAssistants may get into situations where they are either out of sync with the Maana Q UI, or in a failure state. Assistants should be able to recover from these states. \n\nThe repair event functionality added in v3.2.2 is designed to notify the assistant that it must repair itself. This could mean a resync with its resources on the workspace or externally or, for some assistants, nothing at all. \n\nWhen is repair triggered? \nEither manually by a user clicking 'repair workspace' under the\nassistant inventory panel, or upon a workspace clone event. An assistant will be expected to handle either scenario. \n\nPerformance Consideration: \nFor some assistants, repair might involve 'introspecting' \nand processing the current workspace or Q system resources. This could be very resource intensive. Make sure you review this API guide to have an idea of what tools are\navailable to get the best results. It's always a good idea to check performance of repair on a large workspace and ensure necessary optimizations have been made. \n\nDesign Consideration: \nMake your workflows modular enough to be reused between repair and normal usage if possible. \n\n#### addRepairListener (cb) =>\n```js\n\nAssistantAPIClient.addRepairListener(()=>{\n  // Self-heal\n})\n\n```\n\nRecommended Usage: A repair process should be wrapped in the try/catch/finally flow shown in the `setAssistantState` API call to provide the user assistant-state and error updates as well as pause `inventoryChanged` notifications during repair (if the assistant has subscribed).\n\n#### removeRepairListener = (cb) =>\nRemoves the repair listener by reference, or if no callback function reference is provided, it removes all listeners.\n\n### User-facing Error Handling\n\n#### reportError (error) =>\nReports an error to the UI to be displayed in the assistant's error log in the \ninventory panel. This call is not disruptive and designed to operated independently of other assistant operations, such as state management. See `setAssistantState` in the next section.\n\nRecommended usage: use this functionality where it would futher the user experience\nto show the user an error and it's cause. Do not use this where things will be retried, \ncleaned up automatically, or are not relevant to the user. \n\n```js\ntry{\n  // Do work\n} catch(e) {\n  AssistantAPIClient.reportError(e)\n}\n```\n\n### State management\n\n#### clearState = () =>\nThis will remove all callbacks from all listeners. \n\n```js\nawait AssistantAPIClient.clearState()\n```\n\n#### setAssistantState = (state) =>\nThis sets the current state of the assistant using the \n`AssistantState` enum. Setting a state of `WORKING` will \ncreate the 'working' status spinner in the Assistant \nInventory Panel in the Maana Q UI. Conversely, setting an `IDLE` state will \nremove the spinner. This adds to user experience by informing users of the \nstatus of operations.\n\n```js\nimport {\n  default as AssistantAPIClient,\n  AssistantState\n} from '@io-maana/q-assistant-client'\n\n...\n\nAssistantAPIClient.setAssistantState(AssistantState.WORKING)\n\n...\n\nAssistantAPIClient.setAssistantState(AssistantState.IDLE)\n\n```\nUI User Prompt: If the assistant is in a `WORKING` state, the Maana Q UI will\nwarn the user before leaving the workspace. \n\nNOTE: while an assistant is in a working state, it will\nnot receive `inventoryChanged` events--an aggregated inventory diff\nwill be sent once the assistant is set back to `IDLE`.\n\nRecommended usage: Control states at a high level using try/catch/finally\nflow incorporating the `reportError` API call.\n\n```js\ntry{\n  AssistantAPIClient.setAssistantState(AssistantState.WORKING)\n  // Do work, await high-level tasks, etc.\n} catch(e) {\n  AssistantAPIClient.reportError(e)\n} finally{\n  AssistantAPIClient.setAssistantState(AssistantState.IDLE)\n}\n```\n\n#### AssistantState (enum)\nContains the valid assistant states: `IDLE` or `WORKING`.\n\nMust be imported in addition to the AssistantAPIClient:\n\n```js\nimport {\n  default as AssistantAPIClient,\n  AssistantState\n} from '@io-maana/q-assistant-client'\n```\n\n\n### User Info\nThe `UserInfo` object:\n```js\n{\n email: string,\n name: string\n}\n```\n\n#### getUserInfo = () => \nReturns a Userinfo object pertaining to the logged in user.\n\n```js\nconst userInfo = await AssistantAPIClient.getUserInfo()\n```\n### Selection\nThe `Selection` object:\n```js\n{\n  kindId: string\n  kindName: string\n  id: string\n}\n```\n\n#### getCurrentSelection = () => \nReturns an Array of `Selection` objects:\n\n```js\nconst {selection} = await AssistantAPIClient.getCurrentSelection();\n```\n\n#### addSelectionChangedListener = async cb =>\nAdds a callback function to be executed upon a valid workspace selection change.\n\nCallback value is an array of Selection objects:\n\n```js\n// Create the selection callback.\nconst selectionCB = ({selection})=>{\n  console.log('Workspace selection has changed.')\n  selection.forEach(i=>{\n    console.log('Kind: ',i.kindName)\n    console.log('Instance Id:',i.id)\n    console.log('Kind Id:',i.kindId)\n  })\n}\n\n// Add the listener.\nAssistantAPIClient.addSelectionChangedListener(selectionCB);\n```\n\nThis function only exists on the Q-Assistant-Client--only enableSelectionChangedNotification is called on the API. \n\n#### removeSelectionChangedListener = async cb =>\nThis will have to be called on a 1:1 basis with addSelectionChangedListener calls if supplying a callback.\n\n```js\nAssistantAPIClient.removeSelectionChangedListener(selectionCB)\n```\n\n**If NOT supplying a callback to this call, all selection changed listeners will be removed.\n\n```js\nAssistantAPIClient.removeSelectionChangedListener()\n```\n\nThis function only exists on the Q-Assistant-Client--only disableSelectionChangedNotification is called on the API. \n\n\n### Services\nThe `Service` object:\n```js\n{\n   id: string,\n   name: string\n   endpointUrl: string,\n   getKinds: () => // Returns [] of Kinds objects\n   getFunctions: () => // Returns [] of Function objects\n}\n```\n\n#### getServiceById = id =>\nThis will return a service that exists within the scope of the workspace. \n** Assistant services will return null. Services outside the scope of the workspace will cause an error to be returned as 'Unable to load a Service from outside of the workspace.'\n\n```js\nconst svc = await AssistantAPIClient.getServiceById(id)\n```\n\n#### createService = id => \nCreates a service in Q.\n\nNote: This will create the service, but does NOT import it into the workspace.\nYou will need to use `importService` on the Workspace object to import it.\nReturns a promise that resolves\n\n```js\n    const service = {\n      id: ...,\n      name: ...,\n      endpointUrl: ...,\n      serviceType: ...\n    }\n    \n    await AssistantAPIClient.createService(service)\n```\n\n#### deleteService = id =>\nDeletes a service from Q.\n\n```js\n    await AssistantAPIClient.deleteService(id)\n```\n\n#### refreshServiceSchema = id =>\nRefreshes a service by fetching its schema. This will also\nreload the service inventory in the currently visible workspace.\n\n```js\nawait AssistantAPIClient.refreshServiceSchema(\"id\")\n```\n\n#### reloadService = id =>\nReloads a service in the inventory in the currently visible workspace.\n\n```js\nawait AssistantAPIClient.reloadService(\"id\")\n```\n\n### Workspace\n\n#### getWorkspace = () =>\nReturns a Workspace object representing the workspace. \n\n```js\nconst ws = await AssistantAPIClient.getWorkspace(id)\n```\n\nNote: The `id` parameter is optional. If it is not supplied, the query\nwill return the current/visible workspace. \n\nThe `Workspace` object:\n\n```js\n\n{\n    id: string,\n    name: string,\n    endpointUrl: string,\n    workspaceServiceId: string,\n    modelServiceId: string,\n    logicServiceId: string,\n\n    //\n    // Knowledge Graphs\n    //\n    getActiveGraph: async () => {\n      // Returns the active Graph object.\n      // Returns null if active graph is not of type 'Knowledge Graph', or if an\n      // active graph is deleted, thereby setting active graph to null.\n    },\n    getKnowledgeGraphs: async () => {\n      // Returns [Graph]\n    },\n    // TODO: define input\n    createKnowledgeGraph: input =>\n    // TODO: define input\n    createKnowledgeGraphs: input =>\n\n    //\n    // Services\n    //\n    getImportedServices: async () => {\n      // Returns an array of Service objects that have \n      // been imported into the workspace.\n      // No assistant services will be returned.\n    },\n    getImportedAssistants: async () => {\n      // Returns a list of imported assistants.\n    },\n    importService: serviceId => {\n      // Imports a service by it's ID. \n    },\n    importServices: serviceIds => {\n      // Imports services by their IDs.\n    },\n    removeServices: serviceIds => {\n      // Removes a list of services from the workspace.\n    },\n    removeService: serviceId => {\n      // Removes a service from the workspace.\n    },\n\n    //\n    // Functions\n    //\n    getFunctions: async () => {\n      // Returns an array of functions in the workspace (includes boilerplate).\n    },\n    createFunction: funcData => {\n      // Creates a function and adds it to the graph. \n    }\n    createFunctions: funcData =>{\n      // Creates several functions and adds them to the graph. \n    }\n    updateFunction: funcData => {\n      // Updates a function.\n    },\n    updateFunctions: funcData =>{\n      // Updates functions based on input array.\n    },\n    deleteFunction: funcId => {\n      // Deletes a function by its ID.\n    },\n    getFunctionGraph: funcId => {\n      // Returns a function graph by its ID.\n    }\n\n    //\n    // Kinds\n    //\n    getKinds: async () => {\n      // Returns an array of functions in the workspace (includes boilerplate).\n    },\n    createKind: kindData => {\n      // Currently same input as AssistantAPIClient call.\n    },\n    createKinds: kindData => {\n      // Currently same input as AssistantAPIClient call.\n    },\n    updateKind: kindData => {\n      // Currently same input as AssistantAPIClient call.\n    },\n    updateKinds: kindData => {\n      // Currently same input as AssistantAPIClient call.\n    },\n    deleteKind: kindId => {\n      // Currently same input as AssistantAPIClient call.\n    }\n    // Event Triggers\n    triggerRepairEvent: () => {\n      // Triggers the repair event on a workspace. \n    }\n  };\n}\n```\n\n\n### Graphs\nThe `Graph` object:\n```js\n{     \nid: string,\nname: string,\noffsetX: Number,\noffsetY: Number,\nzoom: Number,\ngetNodes: async () => {\n    // Returns [Node]\n},\n\naddNode: async (type, instance, changeSelection) => {\n    // Returns Node\n},\nremoveNode: async id => {\n    // Should return nothing or error.\n    // Currently returning [] in all cases.\n},\nupdateNodeLayout: async (nodeId, { x, y, collapsed }) => {\n},\nupdateGraphLayout: async ({ offsetX, offsetY, zoom }) => {\n}\n}\n```\n\n#### Getting a graph object:\nGraph objects are obtained through an instance of a Workspace \n\n```js\nconst ag = await ws.getActiveGraph()\n```\n\nor\n\n```js\nconst kgs = await ws.getKnowledgeGraphs()\n```\n\n#### Manipulating Graphs\n\n**Only the active graph may be manipulated.\n\nAll graph manipulations should be ‘visually’ verifiable on the graph itself, i.e., adds/removes/positioning, should all be reflected on the graph itself. \n\nThe `Node` object:\n```js\n{\nid: string\nx: number\ny: number\ncollapsed: boolean\nknowledgeGraphNode {\n  id: string\n  innerKind: Kind\n  innerFunction: Function\n}\n}\n```\n\n#### addNode(type, instance, changeSelection) =>\n\nTakes type (“Function” or “Kind”), instance (the Function or Kind object), and optionally a boolean to indicate whether the selection should be changed to this new node. \n\nReturns the newly created Node object.\n\n```js\nconst node = await ag.addNode('Kind',kind)\n```\n\n#### removeNode(id) =>\n\nTakes the id of Node to be deleted. Returns either undefined or an error. \n\n```js\nawait ag.removeNode(node.id)\n```\n\n#### getNodes() =>\nReturns an array of Node objects from the graph. \n\n```js\nconst nodes = await ag.getNodes()\n```\n\n#### updateNodeLayout: async (nodeId, { x, y, collapsed})=>\nUpdates a Node layout given a node ID and node coordinates (`x` and/or `y`) or a `collapsed` value. x/y values must be a number, and collapsed must be a boolean. Whatever is not specified will remain current.\n\n```js\nag.updateNodeLayout(id,{x:100,y:100,collapsed:true})\n```\n\n#### updateGraphLayout: async ({ offsetX, offsetY, zoom})=>\nUpdates a Graph layout given numerical values for x/y offsets and the zoom. \n\n```js\nag.updateGraphLayout({offsetX:50, offsetY:50, zoom: 70})\n```\n\n### Functions\n\nThe `Function` object:\n```js\n{\n    id: string\n    name: string\n    service {\n      id: string\n      name: string\n    }\n    arguments {\n      id: string\n      name: string\n      type: string\n      modifiers: Array[string]\n      typeKindId:: string\n      kind {\n        id: string\n        name: string\n      }\n    }\n    implementation {\n      id: string\n      entrypoint {\n        id: string\n      }\n      operations {\n        id: string\n        type: string\n        function {\n          id: string\n          name: string\n        }\n        argumentValues {\n          id: string\n          argument {\n            id: string\n          }\n          operation {\n            id: string\n          }\n          argumentRef: string\n        }\n      }\n    }\n    isGenerated: boolean\n    functionType: string\n    graphqlOperationType: string\n    outputType: string\n    outputKindId: string\n    outputModifiers: Array[string]\n    kind {\n      id: string\n      name: string\n    }\n}\n```\n\n`FunctionExecutionResult` object:\n```js\n{\n  id: string,\n  result: JSON\n}\n```\n\n#### executeFunction = ( {id, variables, resolve} ) =>\nExecutes a function based on its id, with optional inputs for variables and a resolve string (this specifies the fields to be returned, which must be valid based on the result).\n\nReturns : JSON matching shape of result , unless no sub-selection of fields is required in the execution.\n\nThis following piece of code will execute a Function given a function ID, and pass in variables for ‘example’, requesting back id and name fields. \n\n```js \nconst res = await AssistantAPIClient.executeFunction({functionId: func.id, variables: {\"variableName\": \"variableValue\"}, resolve: \"{ id name }\");\n```\n\n#### createFunction = input =>\nCreates a function based on the input provided. \n\nReturns: the created Function object.\n\n**Using create function will only place the function in the workspace’s inventory--it will not place the function as a node on the Graph. In order to do this, you must pass the created function into the addNode function on the active Graph, making sure to specify ‘Function' as the type.\n\n```js\nconst createFunctionInput = {\n  name:\"yourName\",\n  arguments:[],\n  outputType: \"STRING\",\n  graphqlOperationType:\"QUERY\",\n  functionType: \"CKG\"\n}\n  \nconst createdFunction = await AssistantAPIClient.createFunction(createFunctionInput)\n```\n\n#### updateFunction = input =>\nInput is the same for creating a function. It’s important to note that the arguments property will be replaced in it’s entirety with whatever is provided (if a value is provided.\n\nReturns the updated `Function` object.\n\n```js\nconst updatedFunction = await AssistantAPIClient.updateFunction(input);\n```\n\n#### deleteFunction = input =>\nInput is the id of the Function to be deleted. Returns the deleted function as a promise.\n\n```js\nconst deletedFunction = await AssistantAPIClient.deleteFunction('id...');\n```\n\n#### getFunctionById = id =>\nReturns a Function as a promise based on the ID provided.\n\n```js\nconst func = await AssistantAPIClient.getFunctionById('id...');\n```\n\n#### addFunctionExecutionListener = async (id, cb) =>\nAssociates a callback function with the execution of a particular Function. When the Function matching the id parameter is executed, its FunctionExecutionResult object passed to the callback. Returns undefined.\n\nExample function execution callback and listener registration:\n\n```js\nfunction exampleFunctionCB (result){\n  console.log(`Function executed with result:`, result)\n}\n\nAssistantAPIClient.addFunctionExecutionListener('id...', exampleFunctionCB)\n```\n\n#### removeFunctionExecutionListener = async (id, cb) =>\nRemoves a Function execution listener based on the function ID and a reference to the callback function. If no callback is supplied, all listeners associated with the Function ID will be removed. Returns undefined.\n\n```js\nAssistantAPIClient.removeFunctionExecutionListener('id..', exampleFunctionCB)\n```\n\n### Kinds\nThe `Kind` object:\n```js\n{\n    id: string\n    name: string\n    service: {\n      id\n      name\n    }\n    isGenerated: boolean\n    schema {\n      id: string\n      name: string\n      type: string\n      typeKindId: string\n      modifiers: Array[string]\n      kind {\n        id: string\n        name: string\n      }\n    }\n}\n```\n\n#### createKind = input =>\nCreates a Kind based on an input object. Returns a promise that resolves to the created Kind object.\n\n```js\nconst kindInput = {\n name: \"someKind\",\n schema:[\n  { name: \"someField1\", type: STRING },\n  { name: \"someField2\", type: STRING }\n ]\n}\n\nconst newKind = await AssistantAPIClient.createKind(kindInput)\n```\n\n#### createKinds = input =>\nA plural version of `createKind` accepting an array of input objects.\nReturns a promise that resolves to an array of created Kind objects.\n\n```js\nconst kindsInput = [{\n name: \"someKind\",\n schema:[\n  { name: \"someField1\", type: STRING },\n  { name: \"someField2\", type: STRING }\n ]\n}, ...]\n\nconst newKinds = await AssistantAPIClient.createKinds(kindsInput)\n```\n\n\n#### updateKind = input =>\nUpdates a Kind based on an input object. \n\nUpdate Semantics: Only properties specified will be updated. If updating the schema, the entire schema must be specified as it will be replaced in its entirety. \n\nReturns a promise that resolves to the updated `Kind` object.\n\n```js\nconst updated = await AssistantAPIClient.updateKind(input)\n```\n\n#### deleteKind = input =>\nDeletes a Kind given a kind ID.\n\n```js\nconst deleted = await AssistantAPIClient.deleteKind(input)\n```\n\n#### getKindById = id =>\nReturns a promise that resolves to a Kind object given the specified kind ID. \n\nIn v3.2.2, any requested non-system kinds will be returned. \nIn v3.2.1, only kinds in the workspace or those of imported services will be returned. \n\n```js\nconst kind = await AssistantAPIClient.getKindById(id)\n```\n\n#### getKindsById = ids =>\nReturns a promise that resolves to an array of Kind objects given an array of kind IDs. Only kinds in the workspace or those of imported services will be returned. \n\n```js\nconst ids = [\"...\",\"...\",...]\nconst kind = await AssistantAPIClient.getKindsById(ids)\n```\n\n#### getAllReferencedKinds = input =>\nRecursively collects all kinds that are referenced in a kind's schema, starting\nwith a kind ID. For example if the ID of kind A is supplied as an input, and Kind `A` contains a field of type Kind `B`, and `B` contains a field of type Kind `C`, \nan array containing the kinds objects for `A`, `B`, `C` will be returned (as a promise).\n\n```js\nconst initialId = [\"...\"]\nconst kinds = await AssistantAPIClient.getAllReferencedKinds({\n          ids: initialId\n        })\n```\n\n\n### Inventory\n\nThe `InventoryChanged` object:\n```js\n{\n  kinds: {\n    adds: [DiffItem]\n    deletes: [DiffItem]\n    updates: [DiffItem]\n  }\n  functions:{\n    adds: [DiffItem]\n    deletes: [DiffItem]\n    updates: [DiffItem]\n  }\n  services: {\n    adds: [DiffItem]\n    deletes: [DiffItem]\n    updates: [DiffItem]\n  }\n}\n```\n\nThe `DiffItem` object:\n```js\n{\n  id: string,\n  name: string\n}\n```\n\n#### addInventoryChangedListener = async cb =>\nRegisters a callback function with the inventory changed event. When workspace inventory changes the callback function will be called with the InventoryChangedobject. Returns undefined.\n\n**Use-case note: an ‘update’ diff for inventory services is unlikely in general usage. \n\n```js\nconst inventoryCB = ({diff}) => {\n  if(diff.kinds) console.log('KINDS CHANGED',diff.kinds)\n  if(diff.functions) console.log('FUNCTIONS CHANGED', diff.functions)\n  if(diff.services) console.log('SERVICES CHANGED',diff.services)\n}\n\nAssistantAPIClient.addInventoryChangedListener(inventoryCB)\n```\n\nThis function exists on the Q-Assisant-Client only--only enableSelectionChangedNotification is used on the API side. \n\n#### removeInventoryChangedListener = async cb =>\nRemoves an inventory changed listener given the referenced callback. If no callback is specified, all listeners will be removed. Returns undefined.\n\n```js\nAssistantAPIClient.removeInventoryChangedListener(inventoryCB)\n```\n\nThis function exists on the Q-Assisant-Client only--only disableSelectionChangedNotification is used on the API side. \n\n#### moveKindsAndFunctions = (originId, targetId, kindIds, functionIds) =>\nMoves a collection of Kinds and Functions from the origin Workspace to the target Workspace.\n \n```js\n  await AssistantAPIClient.moveKindsAndFunctions(\n    originWorkspaceId,\n    targetId,\n    kindIds,\n    functionIds\n  );\n```\n\n\n## Troubleshooting Assistant Issues\n### Assistant root file has loaded, but not other content\nObserving in the browser's dev tools that some resources have loaded correctly (usually the root), but other's haven't (usually nested files or chunks), is indicative of a failure of Q Gateway to proxy due to not having a 'relative' path structure.\n\n### You are seeing post-robot `NO ACK` errors in the console.\nThese errors stem from a failed acknowledgement for a call either between the client and the API or vice-versa. Here, this means that the web app 'window' (the assistant) cannot communicate with, or access, the 'window.parent' (Maana K-Portal) object. \n\nCommonly, these will stem from the 'window' (the assistant) not being loaded or in a loadable state, which means the API will not receive an acknowledgement when it fires an event. \n\nImproper CORS configuration is also a common culprit (also verify if using docker or nginx that your proxying and networking is configured correctly to allow communication and to accout for CORS).","readmeFilename":"README.md","gitHead":"8afc2d6028cad4c97a3f79783516dd1a5d4d8a8a","_id":"@io-maana/q-assistant-client@3.2.3-beta.35","_npmVersion":"6.4.1","_nodeVersion":"10.15.3","_npmUser":{"name":"teamcitymaana","email":"teamcity@maana.io"},"dist":{"integrity":"sha512-KIJlNd7Dd8e1lSM7/p0eoS7OSNdckHmP12/xoZPgm7twEdRGM6lMMy3zZ5SdENmpsth4zX81jUShseSiea7pBA==","shasum":"843f50b9f36a0a8b35e45823a955fe6af01bc11a","tarball":"https://registry.npmjs.org/@io-maana/q-assistant-client/-/q-assistant-client-3.2.3-beta.35.tgz","fileCount":10,"unpackedSize":58599,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJe2rf3CRA9TVsSAnZWagAAk5QP/3Y7hRjuuDh8oumHEEh4\nJaTlGbYGq9WqRkbxqzCA9hlwyad28W00e3WRlHEDln5K+b/k008Fu1eVVF7o\numvKLRqWuCwJnRejFnx1XijNAVYTzZqM9Wq4fkyRcY+NqUg1roYy0CWZt6yV\nyQwkuRYWWVwLS1lGH2gWUz9jC5dXvKo+TQNU4CM6THA+C8ydkKd7ltcmoTos\neDnZK8ksZS3vrph5x8QSR6UwRPp9iLstuFS/J/MoESk7AzVkMwqm60T2vwpi\nYIEKtoIQzU/aZPq5wiGtL1Q6EPt8WIzYXibtNRk5TAgX2Ez/5bzyzBppKHF8\n+jwL84Gq3/oNCpzK4HkvSLFfJyJcpNS1hsII6x26VxSkyrqifCRjoR0ziT3E\nTq+uXgGhp9eznLuBAsMJpybnAE4HHaWRzVe5pvyadoFLJYiYUbXoEVQpP5h/\n8XXnBJI4QkrN4Lkgsbk8PphPXxmbv32KDtQlv4oS+H2Q5JzvymgMaml1Lzzf\nBftE/qek7sozhLiZCQTIJYOMLuoFR0PsxPCPlX0eJxqnBFbu4+7k/J2zkvFF\n7uElpjxXfva0kz3VjT61pXupqK261EptV17BmSa0dg+5ftqkrkSPooZhV5aC\n0HjAqhOf5enZpwj+bFvxZsMAKbZSNStUysR0Q+MAsJKQB21RR1i3CaZYMrhm\nMHZm\r\n=ZIyA\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIQDFTgJsC89A/aXi7VgqHw0QlCSosHaIS/84u3H5LU29TgIgNBtDi05Q1jz0O+8b0UW1verenBwFzA3pJyendjr0uWQ="}]},"maintainers":[{"email":"andrey@maana.io","name":"abatyuk"},{"email":"bzvestey@gmail.com","name":"bzvetey"},{"email":"dlewissandy@maana.io","name":"dlsmaana"},{"email":"rob@maana.io","name":"rpovey"},{"email":"teamcity@maana.io","name":"teamcitymaana"},{"email":"witt3rd@witt3rd.com","name":"witt3rd"}],"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/q-assistant-client_3.2.3-beta.35_1591392246881_0.4592395825275022"},"_hasShrinkwrap":false},"3.2.3-beta.36":{"name":"@io-maana/q-assistant-client","version":"3.2.3-beta.36","description":"JavaScript package to streamline communication between an assistant and the Maana Q Assistant API.","main":"build/index.js","exports":{"./":"./build/"},"scripts":{"build":"babel src --out-dir build","prepack":"npm run build","test":"echo \"Error: no test specified\" && exit 1","format":"prettier --write \"src/**/*.js\""},"repository":{"type":"git","url":"git+https://github.com/maana-io/q-assistant-client.git"},"keywords":["Maana","Q"],"author":{"name":"Logan Gore @ Maana.io"},"license":"MIT","bugs":{"url":"https://github.com/maana-io/q-assistant-client/issues"},"homepage":"https://github.com/maana-io/q-assistant-client#readme","dependencies":{"core-js":"3.6.4","post-robot":"10.0.29"},"devDependencies":{"@babel/cli":"^7.5.5","@babel/core":"^7.5.5","@babel/plugin-proposal-class-properties":"^7.5.5","@babel/preset-env":"^7.5.5","prettier":"1.19.1"},"readme":"# q-assistant-client\nA lightweight JavaScript client for Maana-Q Assistant developers that wraps post-message communication between an embedded Maana-Q assistant and the Maana-Q UI.\n\n## Abstract\nThe Q-Assistant-Client is intented to be used in a web application being leveraged as a Maana Q assistant (embedded as an iframe).\nThis assistant client will facilitate communication between the assistant and the parent frame.\nThe client provides a rich, asynchronous experience over what would otherwise be 'fire-and-forget'-style messaging \nvia post-post message communication. \n\n## Requirements and Assumptions\n\n### Post-Robot Library\nThe Maana Knowledge Portal (KPortal) uses the kraken/post-robot library [kraken/post-robot](https://github.com/krakenjs/post-robot) to enrich the communication with the assistant. Post-robot allows for asynchronous, promise-based request/response style behavior between the assistant and the assistant API.\n\nThe API requires that the client use the post-robot library. This assistant-client library is the easiest way to achieve this, and also adds a fair amount of 'sugar' to the process to improve developer productivity. Developers could, however, use post-robot directly in their own client implementation. \n\n### Maana-Gateway Proxy Requirements\nThe Maana-Gateway service requires relative paths (paths relative to the root) in the assistant web application in order to proxy the application and its content. For create-react-apps, for instance, this means setting \"homepage\" to \".\" in the package.json file.\n\n## Singleton Instance\nThe client is exported as a singleton to avoid duplicate registration on event listeners.\nYou can import the instance like this:\n\n```js\nimport AssistantAPIClient from '@io-maana/q-assistant-client';\n```\n\nFunction calls can be made against the client instance like any other javascript object. They are all async.\n\n```js\nconst workspace = await AssistantAPIClient.getWorkspace(); \nconsole.log(\"Workspace:\", workspace)\n```\n\n## Dependencies\nPost-Robot\nhttps://github.com/krakenjs/post-robot\n\nPost-robot is used to provide a richer communication layer atop post-message.\n\n## Versioning\nThe Maana Q Assistant Client does not follow semantic versioning. Its versions\ntrack the releases of the Maana Q platform.\n\n## Examples\n@TODO Logan\n\n\n## Changes in v3.2.2\nImprovements in v3.2.2\n- Assistant State Management: WORKING, IDLE\n- Background Messaging/Eventing\n- Render Modes: BACKGROUND, DISPLAY\n- Expansion of Workspace object capabilities\n- Error Reporting\n- Repair Event\n- Plural versions of calls such as updateKind(s) to improve performance and developer experience.\n- InventoryChanged diffing is fully granular in v3.2.2--limitations\nin v3.2.1 only fired the Function diff for changes in Function name.\n\n### Deprecation\nThe following surface area IS removed from the \nclient in v3.2.2, and IS deprecated in the API:\n- AssistantAPIClient.enableSelectionChangedNotification\n- AssistantAPIClient.disableSelectionChangedNotification\n- AssistantAPIClient.enableInventoryChangedNotification\n- AssistantAPIClient.disableInventoryChangedNotification\n\nThe following surface area WILL BE removed from\nthe client in v3.2.4, and WILL BE deprecated in the API:\n- AssistantAPIClient.updateFunction (expected move to Workspace object)\n- AssistantAPIClient.updateKind (expected move to Workspace object)\n- AssistantAPIClient.deleteKind (expected move to Workspace object)\n- AssistantAPIClient.deleteFunction (expected move to Workspace object)\n\n## API Documentation\n\n### Assistant Render Mode\nAn assistant's render mode refers to whether it is being displayed in a visible manner to the user. As of v3.2.2, assistants are not closed when they are out of view.\nAll assistants will be loaded and kept in `BACKGROUND` render mode until they are \nplaced in the assistant panel, at which point the `DISPLAY` render mode event will be fired. \n\nNote: Assistants will receive all notifications/events while in BACKGROUND mode.\n\nDesign Consideration: It will be up to the developer to determine how state and resource use will be managed while an assistant is operating between BACKGROUND and DISPLAY modes.\n\n#### addRenderModeChangedListener = (cb) =>\nA listener to receive push events as to the assitant's render mode being changed. \n\n```js\nfunction handleRenderModeChanged(renderMode){\n  if (renderMode === 'DISPLAY'){\n    // Assistant is visible\n  } else {\n    // Assistant is not visible and running in background.\n  }\n}\n\nAssistantAPIClient.addRenderModeChangedListener(handleRenderModeChanged)\n\n```\n\n#### removeRenderModeChangedListener = (cb) =>\nRemoves the renderModeChanged listener by reference, or if no callback function reference is provided, it removes all listeners.\n\n#### getRenderMode = () =>\nReturns the current assistant render mode.\n\n```js\nconst renderMode = await AssistantAPIClient.getRenderMode()\n\nif (renderMode === 'DISPLAY'){\n  // Assistant is visible\n} else {\n  // Assistant is not visible and running in background.\n}\n\n```\n\n### Repair\nAssistants may get into situations where they are either out of sync with the Maana Q UI, or in a failure state. Assistants should be able to recover from these states. \n\nThe repair event functionality added in v3.2.2 is designed to notify the assistant that it must repair itself. This could mean a resync with its resources on the workspace or externally or, for some assistants, nothing at all. \n\nWhen is repair triggered? \nEither manually by a user clicking 'repair workspace' under the\nassistant inventory panel, or upon a workspace clone event. An assistant will be expected to handle either scenario. \n\nPerformance Consideration: \nFor some assistants, repair might involve 'introspecting' \nand processing the current workspace or Q system resources. This could be very resource intensive. Make sure you review this API guide to have an idea of what tools are\navailable to get the best results. It's always a good idea to check performance of repair on a large workspace and ensure necessary optimizations have been made. \n\nDesign Consideration: \nMake your workflows modular enough to be reused between repair and normal usage if possible. \n\n#### addRepairListener (cb) =>\n```js\n\nAssistantAPIClient.addRepairListener(()=>{\n  // Self-heal\n})\n\n```\n\nRecommended Usage: A repair process should be wrapped in the try/catch/finally flow shown in the `setAssistantState` API call to provide the user assistant-state and error updates as well as pause `inventoryChanged` notifications during repair (if the assistant has subscribed).\n\n#### removeRepairListener = (cb) =>\nRemoves the repair listener by reference, or if no callback function reference is provided, it removes all listeners.\n\n### User-facing Error Handling\n\n#### reportError (error) =>\nReports an error to the UI to be displayed in the assistant's error log in the \ninventory panel. This call is not disruptive and designed to operated independently of other assistant operations, such as state management. See `setAssistantState` in the next section.\n\nRecommended usage: use this functionality where it would futher the user experience\nto show the user an error and it's cause. Do not use this where things will be retried, \ncleaned up automatically, or are not relevant to the user. \n\n```js\ntry{\n  // Do work\n} catch(e) {\n  AssistantAPIClient.reportError(e)\n}\n```\n\n### State management\n\n#### clearState = () =>\nThis will remove all callbacks from all listeners. \n\n```js\nawait AssistantAPIClient.clearState()\n```\n\n#### setAssistantState = (state) =>\nThis sets the current state of the assistant using the \n`AssistantState` enum. Setting a state of `WORKING` will \ncreate the 'working' status spinner in the Assistant \nInventory Panel in the Maana Q UI. Conversely, setting an `IDLE` state will \nremove the spinner. This adds to user experience by informing users of the \nstatus of operations.\n\n```js\nimport {\n  default as AssistantAPIClient,\n  AssistantState\n} from '@io-maana/q-assistant-client'\n\n...\n\nAssistantAPIClient.setAssistantState(AssistantState.WORKING)\n\n...\n\nAssistantAPIClient.setAssistantState(AssistantState.IDLE)\n\n```\nUI User Prompt: If the assistant is in a `WORKING` state, the Maana Q UI will\nwarn the user before leaving the workspace. \n\nNOTE: while an assistant is in a working state, it will\nnot receive `inventoryChanged` events--an aggregated inventory diff\nwill be sent once the assistant is set back to `IDLE`.\n\nRecommended usage: Control states at a high level using try/catch/finally\nflow incorporating the `reportError` API call.\n\n```js\ntry{\n  AssistantAPIClient.setAssistantState(AssistantState.WORKING)\n  // Do work, await high-level tasks, etc.\n} catch(e) {\n  AssistantAPIClient.reportError(e)\n} finally{\n  AssistantAPIClient.setAssistantState(AssistantState.IDLE)\n}\n```\n\n#### AssistantState (enum)\nContains the valid assistant states: `IDLE` or `WORKING`.\n\nMust be imported in addition to the AssistantAPIClient:\n\n```js\nimport {\n  default as AssistantAPIClient,\n  AssistantState\n} from '@io-maana/q-assistant-client'\n```\n\n\n### User Info\nThe `UserInfo` object:\n```js\n{\n email: string,\n name: string\n}\n```\n\n#### getUserInfo = () => \nReturns a Userinfo object pertaining to the logged in user.\n\n```js\nconst userInfo = await AssistantAPIClient.getUserInfo()\n```\n### Selection\nThe `Selection` object:\n```js\n{\n  kindId: string\n  kindName: string\n  id: string\n}\n```\n\n#### getCurrentSelection = () => \nReturns an Array of `Selection` objects:\n\n```js\nconst {selection} = await AssistantAPIClient.getCurrentSelection();\n```\n\n#### addSelectionChangedListener = async cb =>\nAdds a callback function to be executed upon a valid workspace selection change.\n\nCallback value is an array of Selection objects:\n\n```js\n// Create the selection callback.\nconst selectionCB = ({selection})=>{\n  console.log('Workspace selection has changed.')\n  selection.forEach(i=>{\n    console.log('Kind: ',i.kindName)\n    console.log('Instance Id:',i.id)\n    console.log('Kind Id:',i.kindId)\n  })\n}\n\n// Add the listener.\nAssistantAPIClient.addSelectionChangedListener(selectionCB);\n```\n\nThis function only exists on the Q-Assistant-Client--only enableSelectionChangedNotification is called on the API. \n\n#### removeSelectionChangedListener = async cb =>\nThis will have to be called on a 1:1 basis with addSelectionChangedListener calls if supplying a callback.\n\n```js\nAssistantAPIClient.removeSelectionChangedListener(selectionCB)\n```\n\n**If NOT supplying a callback to this call, all selection changed listeners will be removed.\n\n```js\nAssistantAPIClient.removeSelectionChangedListener()\n```\n\nThis function only exists on the Q-Assistant-Client--only disableSelectionChangedNotification is called on the API. \n\n\n### Services\nThe `Service` object:\n```js\n{\n   id: string,\n   name: string\n   endpointUrl: string,\n   getKinds: () => // Returns [] of Kinds objects\n   getFunctions: () => // Returns [] of Function objects\n}\n```\n\n#### getServiceById = id =>\nThis will return a service that exists within the scope of the workspace. \n** Assistant services will return null. Services outside the scope of the workspace will cause an error to be returned as 'Unable to load a Service from outside of the workspace.'\n\n```js\nconst svc = await AssistantAPIClient.getServiceById(id)\n```\n\n#### createService = id => \nCreates a service in Q.\n\nNote: This will create the service, but does NOT import it into the workspace.\nYou will need to use `importService` on the Workspace object to import it.\nReturns a promise that resolves\n\n```js\n    const service = {\n      id: ...,\n      name: ...,\n      endpointUrl: ...,\n      serviceType: ...\n    }\n    \n    await AssistantAPIClient.createService(service)\n```\n\n#### deleteService = id =>\nDeletes a service from Q.\n\n```js\n    await AssistantAPIClient.deleteService(id)\n```\n\n#### refreshServiceSchema = id =>\nRefreshes a service by fetching its schema. This will also\nreload the service inventory in the currently visible workspace.\n\n```js\nawait AssistantAPIClient.refreshServiceSchema(\"id\")\n```\n\n#### reloadService = id =>\nReloads a service in the inventory in the currently visible workspace.\n\n```js\nawait AssistantAPIClient.reloadService(\"id\")\n```\n\n### Workspace\n\n#### getWorkspace = () =>\nReturns a Workspace object representing the workspace. \n\n```js\nconst ws = await AssistantAPIClient.getWorkspace(id)\n```\n\nNote: The `id` parameter is optional. If it is not supplied, the query\nwill return the current/visible workspace. \n\nThe `Workspace` object:\n\n```js\n\n{\n    id: string,\n    name: string,\n    endpointUrl: string,\n    workspaceServiceId: string,\n    modelServiceId: string,\n    logicServiceId: string,\n\n    //\n    // Knowledge Graphs\n    //\n    getActiveGraph: async () => {\n      // Returns the active Graph object.\n      // Returns null if active graph is not of type 'Knowledge Graph', or if an\n      // active graph is deleted, thereby setting active graph to null.\n    },\n    getKnowledgeGraphs: async () => {\n      // Returns [Graph]\n    },\n    // TODO: define input\n    createKnowledgeGraph: input =>\n    // TODO: define input\n    createKnowledgeGraphs: input =>\n\n    //\n    // Services\n    //\n    getImportedServices: async () => {\n      // Returns an array of Service objects that have \n      // been imported into the workspace.\n      // No assistant services will be returned.\n    },\n    getImportedAssistants: async () => {\n      // Returns a list of imported assistants.\n    },\n    importService: serviceId => {\n      // Imports a service by it's ID. \n    },\n    importServices: serviceIds => {\n      // Imports services by their IDs.\n    },\n    removeServices: serviceIds => {\n      // Removes a list of services from the workspace.\n    },\n    removeService: serviceId => {\n      // Removes a service from the workspace.\n    },\n\n    //\n    // Functions\n    //\n    getFunctions: async () => {\n      // Returns an array of functions in the workspace (includes boilerplate).\n    },\n    createFunction: funcData => {\n      // Creates a function and adds it to the graph. \n    }\n    createFunctions: funcData =>{\n      // Creates several functions and adds them to the graph. \n    }\n    updateFunction: funcData => {\n      // Updates a function.\n    },\n    updateFunctions: funcData =>{\n      // Updates functions based on input array.\n    },\n    deleteFunction: funcId => {\n      // Deletes a function by its ID.\n    },\n    getFunctionGraph: funcId => {\n      // Returns a function graph by its ID.\n    }\n\n    //\n    // Kinds\n    //\n    getKinds: async () => {\n      // Returns an array of functions in the workspace (includes boilerplate).\n    },\n    createKind: kindData => {\n      // Currently same input as AssistantAPIClient call.\n    },\n    createKinds: kindData => {\n      // Currently same input as AssistantAPIClient call.\n    },\n    updateKind: kindData => {\n      // Currently same input as AssistantAPIClient call.\n    },\n    updateKinds: kindData => {\n      // Currently same input as AssistantAPIClient call.\n    },\n    deleteKind: kindId => {\n      // Currently same input as AssistantAPIClient call.\n    }\n    // Event Triggers\n    triggerRepairEvent: () => {\n      // Triggers the repair event on a workspace. \n    }\n  };\n}\n```\n\n\n### Graphs\nThe `Graph` object:\n```js\n{     \nid: string,\nname: string,\noffsetX: Number,\noffsetY: Number,\nzoom: Number,\ngetNodes: async () => {\n    // Returns [Node]\n},\n\naddNode: async (type, instance, changeSelection) => {\n    // Returns Node\n},\nremoveNode: async id => {\n    // Should return nothing or error.\n    // Currently returning [] in all cases.\n},\nupdateNodeLayout: async (nodeId, { x, y, collapsed }) => {\n},\nupdateGraphLayout: async ({ offsetX, offsetY, zoom }) => {\n}\n}\n```\n\n#### Getting a graph object:\nGraph objects are obtained through an instance of a Workspace \n\n```js\nconst ag = await ws.getActiveGraph()\n```\n\nor\n\n```js\nconst kgs = await ws.getKnowledgeGraphs()\n```\n\n#### Manipulating Graphs\n\n**Only the active graph may be manipulated.\n\nAll graph manipulations should be ‘visually’ verifiable on the graph itself, i.e., adds/removes/positioning, should all be reflected on the graph itself. \n\nThe `Node` object:\n```js\n{\nid: string\nx: number\ny: number\ncollapsed: boolean\nknowledgeGraphNode {\n  id: string\n  innerKind: Kind\n  innerFunction: Function\n}\n}\n```\n\n#### addNode(type, instance, changeSelection) =>\n\nTakes type (“Function” or “Kind”), instance (the Function or Kind object), and optionally a boolean to indicate whether the selection should be changed to this new node. \n\nReturns the newly created Node object.\n\n```js\nconst node = await ag.addNode('Kind',kind)\n```\n\n#### removeNode(id) =>\n\nTakes the id of Node to be deleted. Returns either undefined or an error. \n\n```js\nawait ag.removeNode(node.id)\n```\n\n#### getNodes() =>\nReturns an array of Node objects from the graph. \n\n```js\nconst nodes = await ag.getNodes()\n```\n\n#### updateNodeLayout: async (nodeId, { x, y, collapsed})=>\nUpdates a Node layout given a node ID and node coordinates (`x` and/or `y`) or a `collapsed` value. x/y values must be a number, and collapsed must be a boolean. Whatever is not specified will remain current.\n\n```js\nag.updateNodeLayout(id,{x:100,y:100,collapsed:true})\n```\n\n#### updateGraphLayout: async ({ offsetX, offsetY, zoom})=>\nUpdates a Graph layout given numerical values for x/y offsets and the zoom. \n\n```js\nag.updateGraphLayout({offsetX:50, offsetY:50, zoom: 70})\n```\n\n### Functions\n\nThe `Function` object:\n```js\n{\n    id: string\n    name: string\n    service {\n      id: string\n      name: string\n    }\n    arguments {\n      id: string\n      name: string\n      type: string\n      modifiers: Array[string]\n      typeKindId:: string\n      kind {\n        id: string\n        name: string\n      }\n    }\n    implementation {\n      id: string\n      entrypoint {\n        id: string\n      }\n      operations {\n        id: string\n        type: string\n        function {\n          id: string\n          name: string\n        }\n        argumentValues {\n          id: string\n          argument {\n            id: string\n          }\n          operation {\n            id: string\n          }\n          argumentRef: string\n        }\n      }\n    }\n    isGenerated: boolean\n    functionType: string\n    graphqlOperationType: string\n    outputType: string\n    outputKindId: string\n    outputModifiers: Array[string]\n    kind {\n      id: string\n      name: string\n    }\n}\n```\n\n`FunctionExecutionResult` object:\n```js\n{\n  id: string,\n  result: JSON\n}\n```\n\n#### executeFunction = ( {id, variables, resolve} ) =>\nExecutes a function based on its id, with optional inputs for variables and a resolve string (this specifies the fields to be returned, which must be valid based on the result).\n\nReturns : JSON matching shape of result , unless no sub-selection of fields is required in the execution.\n\nThis following piece of code will execute a Function given a function ID, and pass in variables for ‘example’, requesting back id and name fields. \n\n```js \nconst res = await AssistantAPIClient.executeFunction({functionId: func.id, variables: {\"variableName\": \"variableValue\"}, resolve: \"{ id name }\");\n```\n\n#### createFunction = input =>\nCreates a function based on the input provided. \n\nReturns: the created Function object.\n\n**Using create function will only place the function in the workspace’s inventory--it will not place the function as a node on the Graph. In order to do this, you must pass the created function into the addNode function on the active Graph, making sure to specify ‘Function' as the type.\n\n```js\nconst createFunctionInput = {\n  name:\"yourName\",\n  arguments:[],\n  outputType: \"STRING\",\n  graphqlOperationType:\"QUERY\",\n  functionType: \"CKG\"\n}\n  \nconst createdFunction = await AssistantAPIClient.createFunction(createFunctionInput)\n```\n\n#### updateFunction = input =>\nInput is the same for creating a function. It’s important to note that the arguments property will be replaced in it’s entirety with whatever is provided (if a value is provided.\n\nReturns the updated `Function` object.\n\n```js\nconst updatedFunction = await AssistantAPIClient.updateFunction(input);\n```\n\n#### deleteFunction = input =>\nInput is the id of the Function to be deleted. Returns the deleted function as a promise.\n\n```js\nconst deletedFunction = await AssistantAPIClient.deleteFunction('id...');\n```\n\n#### getFunctionById = id =>\nReturns a Function as a promise based on the ID provided.\n\n```js\nconst func = await AssistantAPIClient.getFunctionById('id...');\n```\n\n#### addFunctionExecutionListener = async (id, cb) =>\nAssociates a callback function with the execution of a particular Function. When the Function matching the id parameter is executed, its FunctionExecutionResult object passed to the callback. Returns undefined.\n\nExample function execution callback and listener registration:\n\n```js\nfunction exampleFunctionCB (result){\n  console.log(`Function executed with result:`, result)\n}\n\nAssistantAPIClient.addFunctionExecutionListener('id...', exampleFunctionCB)\n```\n\n#### removeFunctionExecutionListener = async (id, cb) =>\nRemoves a Function execution listener based on the function ID and a reference to the callback function. If no callback is supplied, all listeners associated with the Function ID will be removed. Returns undefined.\n\n```js\nAssistantAPIClient.removeFunctionExecutionListener('id..', exampleFunctionCB)\n```\n\n### Kinds\nThe `Kind` object:\n```js\n{\n    id: string\n    name: string\n    service: {\n      id\n      name\n    }\n    isGenerated: boolean\n    schema {\n      id: string\n      name: string\n      type: string\n      typeKindId: string\n      modifiers: Array[string]\n      kind {\n        id: string\n        name: string\n      }\n    }\n}\n```\n\n#### createKind = input =>\nCreates a Kind based on an input object. Returns a promise that resolves to the created Kind object.\n\n```js\nconst kindInput = {\n name: \"someKind\",\n schema:[\n  { name: \"someField1\", type: STRING },\n  { name: \"someField2\", type: STRING }\n ]\n}\n\nconst newKind = await AssistantAPIClient.createKind(kindInput)\n```\n\n#### createKinds = input =>\nA plural version of `createKind` accepting an array of input objects.\nReturns a promise that resolves to an array of created Kind objects.\n\n```js\nconst kindsInput = [{\n name: \"someKind\",\n schema:[\n  { name: \"someField1\", type: STRING },\n  { name: \"someField2\", type: STRING }\n ]\n}, ...]\n\nconst newKinds = await AssistantAPIClient.createKinds(kindsInput)\n```\n\n\n#### updateKind = input =>\nUpdates a Kind based on an input object. \n\nUpdate Semantics: Only properties specified will be updated. If updating the schema, the entire schema must be specified as it will be replaced in its entirety. \n\nReturns a promise that resolves to the updated `Kind` object.\n\n```js\nconst updated = await AssistantAPIClient.updateKind(input)\n```\n\n#### deleteKind = input =>\nDeletes a Kind given a kind ID.\n\n```js\nconst deleted = await AssistantAPIClient.deleteKind(input)\n```\n\n#### getKindById = id =>\nReturns a promise that resolves to a Kind object given the specified kind ID. \n\nIn v3.2.2, any requested non-system kinds will be returned. \nIn v3.2.1, only kinds in the workspace or those of imported services will be returned. \n\n```js\nconst kind = await AssistantAPIClient.getKindById(id)\n```\n\n#### getKindsById = ids =>\nReturns a promise that resolves to an array of Kind objects given an array of kind IDs. Only kinds in the workspace or those of imported services will be returned. \n\n```js\nconst ids = [\"...\",\"...\",...]\nconst kind = await AssistantAPIClient.getKindsById(ids)\n```\n\n#### getAllReferencedKinds = input =>\nRecursively collects all kinds that are referenced in a kind's schema, starting\nwith a kind ID. For example if the ID of kind A is supplied as an input, and Kind `A` contains a field of type Kind `B`, and `B` contains a field of type Kind `C`, \nan array containing the kinds objects for `A`, `B`, `C` will be returned (as a promise).\n\n```js\nconst initialId = [\"...\"]\nconst kinds = await AssistantAPIClient.getAllReferencedKinds({\n          ids: initialId\n        })\n```\n\n\n### Inventory\n\nThe `InventoryChanged` object:\n```js\n{\n  kinds: {\n    adds: [DiffItem]\n    deletes: [DiffItem]\n    updates: [DiffItem]\n  }\n  functions:{\n    adds: [DiffItem]\n    deletes: [DiffItem]\n    updates: [DiffItem]\n  }\n  services: {\n    adds: [DiffItem]\n    deletes: [DiffItem]\n    updates: [DiffItem]\n  }\n}\n```\n\nThe `DiffItem` object:\n```js\n{\n  id: string,\n  name: string\n}\n```\n\n#### addInventoryChangedListener = async cb =>\nRegisters a callback function with the inventory changed event. When workspace inventory changes the callback function will be called with the InventoryChangedobject. Returns undefined.\n\n**Use-case note: an ‘update’ diff for inventory services is unlikely in general usage. \n\n```js\nconst inventoryCB = ({diff}) => {\n  if(diff.kinds) console.log('KINDS CHANGED',diff.kinds)\n  if(diff.functions) console.log('FUNCTIONS CHANGED', diff.functions)\n  if(diff.services) console.log('SERVICES CHANGED',diff.services)\n}\n\nAssistantAPIClient.addInventoryChangedListener(inventoryCB)\n```\n\nThis function exists on the Q-Assisant-Client only--only enableSelectionChangedNotification is used on the API side. \n\n#### removeInventoryChangedListener = async cb =>\nRemoves an inventory changed listener given the referenced callback. If no callback is specified, all listeners will be removed. Returns undefined.\n\n```js\nAssistantAPIClient.removeInventoryChangedListener(inventoryCB)\n```\n\nThis function exists on the Q-Assisant-Client only--only disableSelectionChangedNotification is used on the API side. \n\n#### moveKindsAndFunctions = (originId, targetId, kindIds, functionIds) =>\nMoves a collection of Kinds and Functions from the origin Workspace to the target Workspace.\n \n```js\n  await AssistantAPIClient.moveKindsAndFunctions(\n    originWorkspaceId,\n    targetId,\n    kindIds,\n    functionIds\n  );\n```\n\n\n## Troubleshooting Assistant Issues\n### Assistant root file has loaded, but not other content\nObserving in the browser's dev tools that some resources have loaded correctly (usually the root), but other's haven't (usually nested files or chunks), is indicative of a failure of Q Gateway to proxy due to not having a 'relative' path structure.\n\n### You are seeing post-robot `NO ACK` errors in the console.\nThese errors stem from a failed acknowledgement for a call either between the client and the API or vice-versa. Here, this means that the web app 'window' (the assistant) cannot communicate with, or access, the 'window.parent' (Maana K-Portal) object. \n\nCommonly, these will stem from the 'window' (the assistant) not being loaded or in a loadable state, which means the API will not receive an acknowledgement when it fires an event. \n\nImproper CORS configuration is also a common culprit (also verify if using docker or nginx that your proxying and networking is configured correctly to allow communication and to accout for CORS).","readmeFilename":"README.md","gitHead":"399e41bc6c49f35b7fb1620867a6e0a2d68a5d04","_id":"@io-maana/q-assistant-client@3.2.3-beta.36","_npmVersion":"6.4.1","_nodeVersion":"10.15.3","_npmUser":{"name":"teamcitymaana","email":"teamcity@maana.io"},"dist":{"integrity":"sha512-ZHGU7dmoSWxtW8QcZHir5c87r4wp/H0sgStLduE3aZZUj0cwi/wun+/SEu6CDlsD1QH5AnPwf3dOGBKsItQpeQ==","shasum":"70500cd7cfa88a92116021aad52de06c071c4916","tarball":"https://registry.npmjs.org/@io-maana/q-assistant-client/-/q-assistant-client-3.2.3-beta.36.tgz","fileCount":10,"unpackedSize":60293,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJe/PdVCRA9TVsSAnZWagAAxBgP/jJijOhs3ZP87wP9bWJV\n9yoboGT4/kgGfKfYg9PUIpUuC6f0R8I29/xGQonGUMlgpHXJn16DZ+IiEcKF\ndo9AInGWj1gxhblq0QaUoB/MEdKTrDm7RcyD0PcH57+5WeSjIKZ4Ke9fn/KZ\nLziVPhjgmTrsWJX8Hd2snM0np29+QnPb9Ys+9pP7pKIZtZiditkaQU58FrA1\nL7RiJ5YKGLydelmOs9lN3PgHjCbFPsQm7PCE3k592+bdPkbtatmxpGh2hIqa\n2FT2DmPfBd0+plxvFbZ9F70nHoqCuB58q5lnduJy1kZCdloEGcD5CWP8wT4L\nfjHqVPuZaQiUc1YcHPOdjnDblUj/B+ww7hoHzaX9yklTwXnkyZj39PFDoGCx\nTS3JczbtLM2aJVlxURQaBbEHhMwKqiWoBUar551xkzk4R6OQxCFl9seLaO0m\n/w3KqeKCvqbwm/qIYRWl9sYMlDLk5sqfgdJYREQ15ncYiIQm/b9yHY6JifGQ\np1ROLgaGYGLMy4M+9tfBOLeEPdqKzOhDIxqckN2XhwH915D24y+d1u3b7XnP\nAJxADCWXQftqRGdRsfuAlzB2mj0L5v+LJlTVuRh0q4tEzR+Li2TFjzFHBvJb\ngK7+BbG7EHKE0vXC+81YZOxKPmZ8emTRwDv6+6D2TcJc1GW+dcY5l3LrUNY6\nXvfU\r\n=5jSy\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEYCIQCxwE2L5jQyTKq0CEv/J37cdvQnsS6rf1bcNIqgAQgaiQIhAKvzqNz8Kv3EKuKuCD/CIgsLl5xHaVQnO5PpZRyv8GPm"}]},"maintainers":[{"email":"andrey@maana.io","name":"abatyuk"},{"email":"bzvestey@gmail.com","name":"bzvetey"},{"email":"dlewissandy@maana.io","name":"dlsmaana"},{"email":"rob@maana.io","name":"rpovey"},{"email":"teamcity@maana.io","name":"teamcitymaana"},{"email":"witt3rd@witt3rd.com","name":"witt3rd"}],"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/q-assistant-client_3.2.3-beta.36_1593636693130_0.7653311959252855"},"_hasShrinkwrap":false},"3.2.3-beta.37":{"name":"@io-maana/q-assistant-client","version":"3.2.3-beta.37","description":"JavaScript package to streamline communication between an assistant and the Maana Q Assistant API.","main":"build/index.js","exports":{"./":"./build/"},"scripts":{"build":"babel src --out-dir build","prepack":"npm run build","test":"echo \"Error: no test specified\" && exit 1","format":"prettier --write \"src/**/*.js\""},"repository":{"type":"git","url":"git+https://github.com/maana-io/q-assistant-client.git"},"keywords":["Maana","Q"],"author":{"name":"Logan Gore @ Maana.io"},"license":"MIT","bugs":{"url":"https://github.com/maana-io/q-assistant-client/issues"},"homepage":"https://github.com/maana-io/q-assistant-client#readme","dependencies":{"core-js":"3.6.4","post-robot":"10.0.29"},"devDependencies":{"@babel/cli":"^7.5.5","@babel/core":"^7.5.5","@babel/plugin-proposal-class-properties":"^7.5.5","@babel/preset-env":"^7.5.5","prettier":"1.19.1"},"readme":"# q-assistant-client\nA lightweight JavaScript client for Maana-Q Assistant developers that wraps post-message communication between an embedded Maana-Q assistant and the Maana-Q UI.\n\n## Abstract\nThe Q-Assistant-Client is intented to be used in a web application being leveraged as a Maana Q assistant (embedded as an iframe).\nThis assistant client will facilitate communication between the assistant and the parent frame.\nThe client provides a rich, asynchronous experience over what would otherwise be 'fire-and-forget'-style messaging \nvia post-post message communication. \n\n## Requirements and Assumptions\n\n### Post-Robot Library\nThe Maana Knowledge Portal (KPortal) uses the kraken/post-robot library [kraken/post-robot](https://github.com/krakenjs/post-robot) to enrich the communication with the assistant. Post-robot allows for asynchronous, promise-based request/response style behavior between the assistant and the assistant API.\n\nThe API requires that the client use the post-robot library. This assistant-client library is the easiest way to achieve this, and also adds a fair amount of 'sugar' to the process to improve developer productivity. Developers could, however, use post-robot directly in their own client implementation. \n\n### Maana-Gateway Proxy Requirements\nThe Maana-Gateway service requires relative paths (paths relative to the root) in the assistant web application in order to proxy the application and its content. For create-react-apps, for instance, this means setting \"homepage\" to \".\" in the package.json file.\n\n## Singleton Instance\nThe client is exported as a singleton to avoid duplicate registration on event listeners.\nYou can import the instance like this:\n\n```js\nimport AssistantAPIClient from '@io-maana/q-assistant-client';\n```\n\nFunction calls can be made against the client instance like any other javascript object. They are all async.\n\n```js\nconst workspace = await AssistantAPIClient.getWorkspace(); \nconsole.log(\"Workspace:\", workspace)\n```\n\n## Dependencies\nPost-Robot\nhttps://github.com/krakenjs/post-robot\n\nPost-robot is used to provide a richer communication layer atop post-message.\n\n## Versioning\nThe Maana Q Assistant Client does not follow semantic versioning. Its versions\ntrack the releases of the Maana Q platform.\n\n## Examples\n@TODO Logan\n\n\n## Changes in v3.2.2\nImprovements in v3.2.2\n- Assistant State Management: WORKING, IDLE\n- Background Messaging/Eventing\n- Render Modes: BACKGROUND, DISPLAY\n- Expansion of Workspace object capabilities\n- Error Reporting\n- Repair Event\n- Plural versions of calls such as updateKind(s) to improve performance and developer experience.\n- InventoryChanged diffing is fully granular in v3.2.2--limitations\nin v3.2.1 only fired the Function diff for changes in Function name.\n\n### Deprecation\nThe following surface area IS removed from the \nclient in v3.2.2, and IS deprecated in the API:\n- AssistantAPIClient.enableSelectionChangedNotification\n- AssistantAPIClient.disableSelectionChangedNotification\n- AssistantAPIClient.enableInventoryChangedNotification\n- AssistantAPIClient.disableInventoryChangedNotification\n\nThe following surface area WILL BE removed from\nthe client in v3.2.4, and WILL BE deprecated in the API:\n- AssistantAPIClient.updateFunction (expected move to Workspace object)\n- AssistantAPIClient.updateKind (expected move to Workspace object)\n- AssistantAPIClient.deleteKind (expected move to Workspace object)\n- AssistantAPIClient.deleteFunction (expected move to Workspace object)\n\n## API Documentation\n\n### Assistant Render Mode\nAn assistant's render mode refers to whether it is being displayed in a visible manner to the user. As of v3.2.2, assistants are not closed when they are out of view.\nAll assistants will be loaded and kept in `BACKGROUND` render mode until they are \nplaced in the assistant panel, at which point the `DISPLAY` render mode event will be fired. \n\nNote: Assistants will receive all notifications/events while in BACKGROUND mode.\n\nDesign Consideration: It will be up to the developer to determine how state and resource use will be managed while an assistant is operating between BACKGROUND and DISPLAY modes.\n\n#### addRenderModeChangedListener = (cb) =>\nA listener to receive push events as to the assitant's render mode being changed. \n\n```js\nfunction handleRenderModeChanged(renderMode){\n  if (renderMode === 'DISPLAY'){\n    // Assistant is visible\n  } else {\n    // Assistant is not visible and running in background.\n  }\n}\n\nAssistantAPIClient.addRenderModeChangedListener(handleRenderModeChanged)\n\n```\n\n#### removeRenderModeChangedListener = (cb) =>\nRemoves the renderModeChanged listener by reference, or if no callback function reference is provided, it removes all listeners.\n\n#### getRenderMode = () =>\nReturns the current assistant render mode.\n\n```js\nconst renderMode = await AssistantAPIClient.getRenderMode()\n\nif (renderMode === 'DISPLAY'){\n  // Assistant is visible\n} else {\n  // Assistant is not visible and running in background.\n}\n\n```\n\n### Repair\nAssistants may get into situations where they are either out of sync with the Maana Q UI, or in a failure state. Assistants should be able to recover from these states. \n\nThe repair event functionality added in v3.2.2 is designed to notify the assistant that it must repair itself. This could mean a resync with its resources on the workspace or externally or, for some assistants, nothing at all. \n\nWhen is repair triggered? \nEither manually by a user clicking 'repair workspace' under the\nassistant inventory panel, or upon a workspace clone event. An assistant will be expected to handle either scenario. \n\nPerformance Consideration: \nFor some assistants, repair might involve 'introspecting' \nand processing the current workspace or Q system resources. This could be very resource intensive. Make sure you review this API guide to have an idea of what tools are\navailable to get the best results. It's always a good idea to check performance of repair on a large workspace and ensure necessary optimizations have been made. \n\nDesign Consideration: \nMake your workflows modular enough to be reused between repair and normal usage if possible. \n\n#### addRepairListener (cb) =>\n```js\n\nAssistantAPIClient.addRepairListener(()=>{\n  // Self-heal\n})\n\n```\n\nRecommended Usage: A repair process should be wrapped in the try/catch/finally flow shown in the `setAssistantState` API call to provide the user assistant-state and error updates as well as pause `inventoryChanged` notifications during repair (if the assistant has subscribed).\n\n#### removeRepairListener = (cb) =>\nRemoves the repair listener by reference, or if no callback function reference is provided, it removes all listeners.\n\n### User-facing Error Handling\n\n#### reportError (error) =>\nReports an error to the UI to be displayed in the assistant's error log in the \ninventory panel. This call is not disruptive and designed to operated independently of other assistant operations, such as state management. See `setAssistantState` in the next section.\n\nRecommended usage: use this functionality where it would futher the user experience\nto show the user an error and it's cause. Do not use this where things will be retried, \ncleaned up automatically, or are not relevant to the user. \n\n```js\ntry{\n  // Do work\n} catch(e) {\n  AssistantAPIClient.reportError(e)\n}\n```\n\n### State management\n\n#### clearState = () =>\nThis will remove all callbacks from all listeners. \n\n```js\nawait AssistantAPIClient.clearState()\n```\n\n#### setAssistantState = (state) =>\nThis sets the current state of the assistant using the \n`AssistantState` enum. Setting a state of `WORKING` will \ncreate the 'working' status spinner in the Assistant \nInventory Panel in the Maana Q UI. Conversely, setting an `IDLE` state will \nremove the spinner. This adds to user experience by informing users of the \nstatus of operations.\n\n```js\nimport {\n  default as AssistantAPIClient,\n  AssistantState\n} from '@io-maana/q-assistant-client'\n\n...\n\nAssistantAPIClient.setAssistantState(AssistantState.WORKING)\n\n...\n\nAssistantAPIClient.setAssistantState(AssistantState.IDLE)\n\n```\nUI User Prompt: If the assistant is in a `WORKING` state, the Maana Q UI will\nwarn the user before leaving the workspace. \n\nNOTE: while an assistant is in a working state, it will\nnot receive `inventoryChanged` events--an aggregated inventory diff\nwill be sent once the assistant is set back to `IDLE`.\n\nRecommended usage: Control states at a high level using try/catch/finally\nflow incorporating the `reportError` API call.\n\n```js\ntry{\n  AssistantAPIClient.setAssistantState(AssistantState.WORKING)\n  // Do work, await high-level tasks, etc.\n} catch(e) {\n  AssistantAPIClient.reportError(e)\n} finally{\n  AssistantAPIClient.setAssistantState(AssistantState.IDLE)\n}\n```\n\n#### AssistantState (enum)\nContains the valid assistant states: `IDLE` or `WORKING`.\n\nMust be imported in addition to the AssistantAPIClient:\n\n```js\nimport {\n  default as AssistantAPIClient,\n  AssistantState\n} from '@io-maana/q-assistant-client'\n```\n\n\n### User Info\nThe `UserInfo` object:\n```js\n{\n email: string,\n name: string\n}\n```\n\n#### getUserInfo = () => \nReturns a Userinfo object pertaining to the logged in user.\n\n```js\nconst userInfo = await AssistantAPIClient.getUserInfo()\n```\n### Selection\nThe `Selection` object:\n```js\n{\n  kindId: string\n  kindName: string\n  id: string\n}\n```\n\n#### getCurrentSelection = () => \nReturns an Array of `Selection` objects:\n\n```js\nconst {selection} = await AssistantAPIClient.getCurrentSelection();\n```\n\n#### addSelectionChangedListener = async cb =>\nAdds a callback function to be executed upon a valid workspace selection change.\n\nCallback value is an array of Selection objects:\n\n```js\n// Create the selection callback.\nconst selectionCB = ({selection})=>{\n  console.log('Workspace selection has changed.')\n  selection.forEach(i=>{\n    console.log('Kind: ',i.kindName)\n    console.log('Instance Id:',i.id)\n    console.log('Kind Id:',i.kindId)\n  })\n}\n\n// Add the listener.\nAssistantAPIClient.addSelectionChangedListener(selectionCB);\n```\n\nThis function only exists on the Q-Assistant-Client--only enableSelectionChangedNotification is called on the API. \n\n#### removeSelectionChangedListener = async cb =>\nThis will have to be called on a 1:1 basis with addSelectionChangedListener calls if supplying a callback.\n\n```js\nAssistantAPIClient.removeSelectionChangedListener(selectionCB)\n```\n\n**If NOT supplying a callback to this call, all selection changed listeners will be removed.\n\n```js\nAssistantAPIClient.removeSelectionChangedListener()\n```\n\nThis function only exists on the Q-Assistant-Client--only disableSelectionChangedNotification is called on the API. \n\n\n### Services\nThe `Service` object:\n```js\n{\n   id: string,\n   name: string\n   endpointUrl: string,\n   getKinds: () => // Returns [] of Kinds objects\n   getFunctions: () => // Returns [] of Function objects\n}\n```\n\n#### getServiceById = id =>\nThis will return a service that exists within the scope of the workspace. \n** Assistant services will return null. Services outside the scope of the workspace will cause an error to be returned as 'Unable to load a Service from outside of the workspace.'\n\n```js\nconst svc = await AssistantAPIClient.getServiceById(id)\n```\n\n#### createService = id => \nCreates a service in Q.\n\nNote: This will create the service, but does NOT import it into the workspace.\nYou will need to use `importService` on the Workspace object to import it.\nReturns a promise that resolves\n\n```js\n    const service = {\n      id: ...,\n      name: ...,\n      endpointUrl: ...,\n      serviceType: ...\n    }\n    \n    await AssistantAPIClient.createService(service)\n```\n\n#### deleteService = id =>\nDeletes a service from Q.\n\n```js\n    await AssistantAPIClient.deleteService(id)\n```\n\n#### refreshServiceSchema = id =>\nRefreshes a service by fetching its schema. This will also\nreload the service inventory in the currently visible workspace.\n\n```js\nawait AssistantAPIClient.refreshServiceSchema(\"id\")\n```\n\n#### reloadService = id =>\nReloads a service in the inventory in the currently visible workspace.\n\n```js\nawait AssistantAPIClient.reloadService(\"id\")\n```\n\n### Workspace\n\n#### getWorkspace = () =>\nReturns a Workspace object representing the workspace. \n\n```js\nconst ws = await AssistantAPIClient.getWorkspace(id)\n```\n\nNote: The `id` parameter is optional. If it is not supplied, the query\nwill return the current/visible workspace. \n\nThe `Workspace` object:\n\n```js\n\n{\n    id: string,\n    name: string,\n    endpointUrl: string,\n    workspaceServiceId: string,\n    modelServiceId: string,\n    logicServiceId: string,\n\n    //\n    // Knowledge Graphs\n    //\n    getActiveGraph: async () => {\n      // Returns the active Graph object.\n      // Returns null if active graph is not of type 'Knowledge Graph', or if an\n      // active graph is deleted, thereby setting active graph to null.\n    },\n    getKnowledgeGraphs: async () => {\n      // Returns [Graph]\n    },\n    // TODO: define input\n    createKnowledgeGraph: input =>\n    // TODO: define input\n    createKnowledgeGraphs: input =>\n\n    //\n    // Services\n    //\n    getImportedServices: async () => {\n      // Returns an array of Service objects that have \n      // been imported into the workspace.\n      // No assistant services will be returned.\n    },\n    getImportedAssistants: async () => {\n      // Returns a list of imported assistants.\n    },\n    importService: serviceId => {\n      // Imports a service by it's ID. \n    },\n    importServices: serviceIds => {\n      // Imports services by their IDs.\n    },\n    removeServices: serviceIds => {\n      // Removes a list of services from the workspace.\n    },\n    removeService: serviceId => {\n      // Removes a service from the workspace.\n    },\n\n    //\n    // Functions\n    //\n    getFunctions: async () => {\n      // Returns an array of functions in the workspace (includes boilerplate).\n    },\n    createFunction: funcData => {\n      // Creates a function and adds it to the graph. \n    }\n    createFunctions: funcData =>{\n      // Creates several functions and adds them to the graph. \n    }\n    updateFunction: funcData => {\n      // Updates a function.\n    },\n    updateFunctions: funcData =>{\n      // Updates functions based on input array.\n    },\n    deleteFunction: funcId => {\n      // Deletes a function by its ID.\n    },\n    getFunctionGraph: funcId => {\n      // Returns a function graph by its ID.\n    }\n\n    //\n    // Kinds\n    //\n    getKinds: async () => {\n      // Returns an array of functions in the workspace (includes boilerplate).\n    },\n    createKind: kindData => {\n      // Currently same input as AssistantAPIClient call.\n    },\n    createKinds: kindData => {\n      // Currently same input as AssistantAPIClient call.\n    },\n    updateKind: kindData => {\n      // Currently same input as AssistantAPIClient call.\n    },\n    updateKinds: kindData => {\n      // Currently same input as AssistantAPIClient call.\n    },\n    deleteKind: kindId => {\n      // Currently same input as AssistantAPIClient call.\n    }\n    // Event Triggers\n    triggerRepairEvent: () => {\n      // Triggers the repair event on a workspace. \n    }\n  };\n}\n```\n\n\n### Graphs\nThe `Graph` object:\n```js\n{     \nid: string,\nname: string,\noffsetX: Number,\noffsetY: Number,\nzoom: Number,\ngetNodes: async () => {\n    // Returns [Node]\n},\n\naddNode: async (type, instance, changeSelection) => {\n    // Returns Node\n},\nremoveNode: async id => {\n    // Should return nothing or error.\n    // Currently returning [] in all cases.\n},\nupdateNodeLayout: async (nodeId, { x, y, collapsed }) => {\n},\nupdateGraphLayout: async ({ offsetX, offsetY, zoom }) => {\n}\n}\n```\n\n#### Getting a graph object:\nGraph objects are obtained through an instance of a Workspace \n\n```js\nconst ag = await ws.getActiveGraph()\n```\n\nor\n\n```js\nconst kgs = await ws.getKnowledgeGraphs()\n```\n\n#### Manipulating Graphs\n\n**Only the active graph may be manipulated.\n\nAll graph manipulations should be ‘visually’ verifiable on the graph itself, i.e., adds/removes/positioning, should all be reflected on the graph itself. \n\nThe `Node` object:\n```js\n{\nid: string\nx: number\ny: number\ncollapsed: boolean\nknowledgeGraphNode {\n  id: string\n  innerKind: Kind\n  innerFunction: Function\n}\n}\n```\n\n#### addNode(type, instance, changeSelection) =>\n\nTakes type (“Function” or “Kind”), instance (the Function or Kind object), and optionally a boolean to indicate whether the selection should be changed to this new node. \n\nReturns the newly created Node object.\n\n```js\nconst node = await ag.addNode('Kind',kind)\n```\n\n#### removeNode(id) =>\n\nTakes the id of Node to be deleted. Returns either undefined or an error. \n\n```js\nawait ag.removeNode(node.id)\n```\n\n#### getNodes() =>\nReturns an array of Node objects from the graph. \n\n```js\nconst nodes = await ag.getNodes()\n```\n\n#### updateNodeLayout: async (nodeId, { x, y, collapsed})=>\nUpdates a Node layout given a node ID and node coordinates (`x` and/or `y`) or a `collapsed` value. x/y values must be a number, and collapsed must be a boolean. Whatever is not specified will remain current.\n\n```js\nag.updateNodeLayout(id,{x:100,y:100,collapsed:true})\n```\n\n#### updateGraphLayout: async ({ offsetX, offsetY, zoom})=>\nUpdates a Graph layout given numerical values for x/y offsets and the zoom. \n\n```js\nag.updateGraphLayout({offsetX:50, offsetY:50, zoom: 70})\n```\n\n### Functions\n\nThe `Function` object:\n```js\n{\n    id: string\n    name: string\n    service {\n      id: string\n      name: string\n    }\n    arguments {\n      id: string\n      name: string\n      type: string\n      modifiers: Array[string]\n      typeKindId:: string\n      kind {\n        id: string\n        name: string\n      }\n    }\n    implementation {\n      id: string\n      entrypoint {\n        id: string\n      }\n      operations {\n        id: string\n        type: string\n        function {\n          id: string\n          name: string\n        }\n        argumentValues {\n          id: string\n          argument {\n            id: string\n          }\n          operation {\n            id: string\n          }\n          argumentRef: string\n        }\n      }\n    }\n    isGenerated: boolean\n    functionType: string\n    graphqlOperationType: string\n    outputType: string\n    outputKindId: string\n    outputModifiers: Array[string]\n    kind {\n      id: string\n      name: string\n    }\n}\n```\n\n`FunctionExecutionResult` object:\n```js\n{\n  id: string,\n  result: JSON\n}\n```\n\n#### executeFunction = ( {id, variables, resolve} ) =>\nExecutes a function based on its id, with optional inputs for variables and a resolve string (this specifies the fields to be returned, which must be valid based on the result).\n\nReturns : JSON matching shape of result , unless no sub-selection of fields is required in the execution.\n\nThis following piece of code will execute a Function given a function ID, and pass in variables for ‘example’, requesting back id and name fields. \n\n```js \nconst res = await AssistantAPIClient.executeFunction({functionId: func.id, variables: {\"variableName\": \"variableValue\"}, resolve: \"{ id name }\");\n```\n\n#### createFunction = input =>\nCreates a function based on the input provided. \n\nReturns: the created Function object.\n\n**Using create function will only place the function in the workspace’s inventory--it will not place the function as a node on the Graph. In order to do this, you must pass the created function into the addNode function on the active Graph, making sure to specify ‘Function' as the type.\n\n```js\nconst createFunctionInput = {\n  name:\"yourName\",\n  arguments:[],\n  outputType: \"STRING\",\n  graphqlOperationType:\"QUERY\",\n  functionType: \"CKG\"\n}\n  \nconst createdFunction = await AssistantAPIClient.createFunction(createFunctionInput)\n```\n\n#### updateFunction = input =>\nInput is the same for creating a function. It’s important to note that the arguments property will be replaced in it’s entirety with whatever is provided (if a value is provided.\n\nReturns the updated `Function` object.\n\n```js\nconst updatedFunction = await AssistantAPIClient.updateFunction(input);\n```\n\n#### deleteFunction = input =>\nInput is the id of the Function to be deleted. Returns the deleted function as a promise.\n\n```js\nconst deletedFunction = await AssistantAPIClient.deleteFunction('id...');\n```\n\n#### getFunctionById = id =>\nReturns a Function as a promise based on the ID provided.\n\n```js\nconst func = await AssistantAPIClient.getFunctionById('id...');\n```\n\n#### addFunctionExecutionListener = async (id, cb) =>\nAssociates a callback function with the execution of a particular Function. When the Function matching the id parameter is executed, its FunctionExecutionResult object passed to the callback. Returns undefined.\n\nExample function execution callback and listener registration:\n\n```js\nfunction exampleFunctionCB (result){\n  console.log(`Function executed with result:`, result)\n}\n\nAssistantAPIClient.addFunctionExecutionListener('id...', exampleFunctionCB)\n```\n\n#### removeFunctionExecutionListener = async (id, cb) =>\nRemoves a Function execution listener based on the function ID and a reference to the callback function. If no callback is supplied, all listeners associated with the Function ID will be removed. Returns undefined.\n\n```js\nAssistantAPIClient.removeFunctionExecutionListener('id..', exampleFunctionCB)\n```\n\n### Kinds\nThe `Kind` object:\n```js\n{\n    id: string\n    name: string\n    service: {\n      id\n      name\n    }\n    isGenerated: boolean\n    schema {\n      id: string\n      name: string\n      type: string\n      typeKindId: string\n      modifiers: Array[string]\n      kind {\n        id: string\n        name: string\n      }\n    }\n}\n```\n\n#### createKind = input =>\nCreates a Kind based on an input object. Returns a promise that resolves to the created Kind object.\n\n```js\nconst kindInput = {\n name: \"someKind\",\n schema:[\n  { name: \"someField1\", type: STRING },\n  { name: \"someField2\", type: STRING }\n ]\n}\n\nconst newKind = await AssistantAPIClient.createKind(kindInput)\n```\n\n#### createKinds = input =>\nA plural version of `createKind` accepting an array of input objects.\nReturns a promise that resolves to an array of created Kind objects.\n\n```js\nconst kindsInput = [{\n name: \"someKind\",\n schema:[\n  { name: \"someField1\", type: STRING },\n  { name: \"someField2\", type: STRING }\n ]\n}, ...]\n\nconst newKinds = await AssistantAPIClient.createKinds(kindsInput)\n```\n\n\n#### updateKind = input =>\nUpdates a Kind based on an input object. \n\nUpdate Semantics: Only properties specified will be updated. If updating the schema, the entire schema must be specified as it will be replaced in its entirety. \n\nReturns a promise that resolves to the updated `Kind` object.\n\n```js\nconst updated = await AssistantAPIClient.updateKind(input)\n```\n\n#### deleteKind = input =>\nDeletes a Kind given a kind ID.\n\n```js\nconst deleted = await AssistantAPIClient.deleteKind(input)\n```\n\n#### getKindById = id =>\nReturns a promise that resolves to a Kind object given the specified kind ID. \n\nIn v3.2.2, any requested non-system kinds will be returned. \nIn v3.2.1, only kinds in the workspace or those of imported services will be returned. \n\n```js\nconst kind = await AssistantAPIClient.getKindById(id)\n```\n\n#### getKindsById = ids =>\nReturns a promise that resolves to an array of Kind objects given an array of kind IDs. Only kinds in the workspace or those of imported services will be returned. \n\n```js\nconst ids = [\"...\",\"...\",...]\nconst kind = await AssistantAPIClient.getKindsById(ids)\n```\n\n#### getAllReferencedKinds = input =>\nRecursively collects all kinds that are referenced in a kind's schema, starting\nwith a kind ID. For example if the ID of kind A is supplied as an input, and Kind `A` contains a field of type Kind `B`, and `B` contains a field of type Kind `C`, \nan array containing the kinds objects for `A`, `B`, `C` will be returned (as a promise).\n\n```js\nconst initialId = [\"...\"]\nconst kinds = await AssistantAPIClient.getAllReferencedKinds({\n          ids: initialId\n        })\n```\n\n\n### Inventory\n\nThe `InventoryChanged` object:\n```js\n{\n  kinds: {\n    adds: [DiffItem]\n    deletes: [DiffItem]\n    updates: [DiffItem]\n  }\n  functions:{\n    adds: [DiffItem]\n    deletes: [DiffItem]\n    updates: [DiffItem]\n  }\n  services: {\n    adds: [DiffItem]\n    deletes: [DiffItem]\n    updates: [DiffItem]\n  }\n}\n```\n\nThe `DiffItem` object:\n```js\n{\n  id: string,\n  name: string\n}\n```\n\n#### addInventoryChangedListener = async cb =>\nRegisters a callback function with the inventory changed event. When workspace inventory changes the callback function will be called with the InventoryChangedobject. Returns undefined.\n\n**Use-case note: an ‘update’ diff for inventory services is unlikely in general usage. \n\n```js\nconst inventoryCB = ({diff}) => {\n  if(diff.kinds) console.log('KINDS CHANGED',diff.kinds)\n  if(diff.functions) console.log('FUNCTIONS CHANGED', diff.functions)\n  if(diff.services) console.log('SERVICES CHANGED',diff.services)\n}\n\nAssistantAPIClient.addInventoryChangedListener(inventoryCB)\n```\n\nThis function exists on the Q-Assisant-Client only--only enableSelectionChangedNotification is used on the API side. \n\n#### removeInventoryChangedListener = async cb =>\nRemoves an inventory changed listener given the referenced callback. If no callback is specified, all listeners will be removed. Returns undefined.\n\n```js\nAssistantAPIClient.removeInventoryChangedListener(inventoryCB)\n```\n\nThis function exists on the Q-Assisant-Client only--only disableSelectionChangedNotification is used on the API side. \n\n#### moveKindsAndFunctions = (originId, targetId, kindIds, functionIds) =>\nMoves a collection of Kinds and Functions from the origin Workspace to the target Workspace.\n \n```js\n  await AssistantAPIClient.moveKindsAndFunctions(\n    originWorkspaceId,\n    targetId,\n    kindIds,\n    functionIds\n  );\n```\n\n\n## Troubleshooting Assistant Issues\n### Assistant root file has loaded, but not other content\nObserving in the browser's dev tools that some resources have loaded correctly (usually the root), but other's haven't (usually nested files or chunks), is indicative of a failure of Q Gateway to proxy due to not having a 'relative' path structure.\n\n### You are seeing post-robot `NO ACK` errors in the console.\nThese errors stem from a failed acknowledgement for a call either between the client and the API or vice-versa. Here, this means that the web app 'window' (the assistant) cannot communicate with, or access, the 'window.parent' (Maana K-Portal) object. \n\nCommonly, these will stem from the 'window' (the assistant) not being loaded or in a loadable state, which means the API will not receive an acknowledgement when it fires an event. \n\nImproper CORS configuration is also a common culprit (also verify if using docker or nginx that your proxying and networking is configured correctly to allow communication and to accout for CORS).","readmeFilename":"README.md","gitHead":"c840499ccca266a0050234f6c5b70551ee5e5ae4","_id":"@io-maana/q-assistant-client@3.2.3-beta.37","_npmVersion":"6.4.1","_nodeVersion":"10.15.3","_npmUser":{"name":"teamcitymaana","email":"teamcity@maana.io"},"dist":{"integrity":"sha512-c1mC011H+aW3q9OH8WFerUdL1bQgTAou3MP2SwaggrtYQQ/Ygj2uL6kzCfWfZYChLxcxpoyI+Ua1Ch/9XVKHlA==","shasum":"a9c63d910a5c7a39b9e3f6c65b283509e68b3083","tarball":"https://registry.npmjs.org/@io-maana/q-assistant-client/-/q-assistant-client-3.2.3-beta.37.tgz","fileCount":10,"unpackedSize":61783,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJfBP+cCRA9TVsSAnZWagAAE+kP/1nT/dcDkphOHr6uPwdy\nBWUhQ0WQHyyIurlwf4usCZPV/3x9vkadr0YdtRzZ/rA7lO69oysurO5P4aob\nOQ/pfjbPlrH0liy6zeBw3EnBH+hQ2+ZAYoJC+byUem8lgq+58iaY3VTU/myu\ntQ5e4Zx+0mmv6/kXAVtu05197eVhoBzEQca9E7idA7Lfh0WukxEiZWX2APi6\nu+82Ouk7yYLkS4rSZPpL+zTtyzjkrsloLvkyfXIrll6XR2EPQsJR2Ni194DH\n5kjcv+hLqiI2qwvtmYCxGWqx2RFsXLC3U5GDcdn07V0tEmeEsjD6K064aHoI\ncgiV3fwgsDV80X7BfOKWTJbcKegDN5wNUdw2otGCIk9j+zqi9ghq65mmYF4j\ncGdjCEU+CYPmRVwXYcfzRF90+CF0A/Q9G+J1gFZEjmjKmK4NQGa5a++iHEPm\ntCPB79sj4yXRGG59qaR9hhRCLYVLkYdNRx6Ndj37OZkf8xh5DE2YyA2G4Q/F\nnhxjSCEGit2FQe7f773vvMEsokW77AeWnIUDdheleLx83j7IRJb8KjXBO0vC\n3hjmhIpo2Zto2bMSlioFntUox71GrshDWdmVpiLtMi/aGS3KQsDWwySNy1Zz\nnvilKhWkt3zu8yey3Hx/43aHIJRcLc9ldMk+/ObG8PgsbY8Nh+ioX+3pDOqY\nUtT7\r\n=stHc\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEQCIGoQ4Y5f/z8zlWoHcGI8u2b4ftnHXAeKHxSWdulQNsNwAiBNQCc5cNfOixic+jE2Reb1Cr/ZoF+k1Ty5Sw1LTzt0tA=="}]},"maintainers":[{"email":"andrey@maana.io","name":"abatyuk"},{"email":"bzvestey@gmail.com","name":"bzvetey"},{"email":"dlewissandy@maana.io","name":"dlsmaana"},{"email":"rob@maana.io","name":"rpovey"},{"email":"teamcity@maana.io","name":"teamcitymaana"},{"email":"witt3rd@witt3rd.com","name":"witt3rd"}],"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/q-assistant-client_3.2.3-beta.37_1594163099906_0.9827104571741765"},"_hasShrinkwrap":false},"3.2.3-beta.38":{"name":"@io-maana/q-assistant-client","version":"3.2.3-beta.38","description":"JavaScript package to streamline communication between an assistant and the Maana Q Assistant API.","main":"build/index.js","exports":{"./":"./build/"},"scripts":{"build":"babel src --out-dir build","prepack":"npm run build","test":"echo \"Error: no test specified\" && exit 1","format":"prettier --write \"src/**/*.js\""},"repository":{"type":"git","url":"git+https://github.com/maana-io/q-assistant-client.git"},"keywords":["Maana","Q"],"author":{"name":"Logan Gore @ Maana.io"},"license":"MIT","bugs":{"url":"https://github.com/maana-io/q-assistant-client/issues"},"homepage":"https://github.com/maana-io/q-assistant-client#readme","dependencies":{"core-js":"3.6.4","post-robot":"10.0.29"},"devDependencies":{"@babel/cli":"^7.5.5","@babel/core":"^7.5.5","@babel/plugin-proposal-class-properties":"^7.5.5","@babel/preset-env":"^7.5.5","prettier":"1.19.1"},"gitHead":"87ae9e54855ce60d60362e9bfcd3d1a784252544","readme":"# q-assistant-client\nA lightweight JavaScript client for Maana-Q Assistant developers that wraps post-message communication between an embedded Maana-Q assistant and the Maana-Q UI.\n\n## Abstract\nThe Q-Assistant-Client is intented to be used in a web application being leveraged as a Maana Q assistant (embedded as an iframe).\nThis assistant client will facilitate communication between the assistant and the parent frame.\nThe client provides a rich, asynchronous experience over what would otherwise be 'fire-and-forget'-style messaging\nvia post-post message communication.\n\n## Requirements and Assumptions\n\n### Post-Robot Library\nThe Maana Knowledge Portal (KPortal) uses the kraken/post-robot library [kraken/post-robot](https://github.com/krakenjs/post-robot) to enrich the communication with the assistant. Post-robot allows for asynchronous, promise-based request/response style behavior between the assistant and the assistant API.\n\nThe API requires that the client use the post-robot library. This assistant-client library is the easiest way to achieve this, and also adds a fair amount of 'sugar' to the process to improve developer productivity. Developers could, however, use post-robot directly in their own client implementation.\n\n### Maana-Gateway Proxy Requirements\nThe Maana-Gateway service requires relative paths (paths relative to the root) in the assistant web application in order to proxy the application and its content. For create-react-apps, for instance, this means setting \"homepage\" to \".\" in the package.json file.\n\n## Singleton Instance\nThe client is exported as a singleton to avoid duplicate registration on event listeners.\nYou can import the instance like this:\n\n```js\nimport AssistantAPIClient from '@io-maana/q-assistant-client';\n```\n\nFunction calls can be made against the client instance like any other javascript object. They are all async.\n\n```js\nconst workspace = await AssistantAPIClient.getWorkspace();\nconsole.log(\"Workspace:\", workspace)\n```\n\n## Dependencies\nPost-Robot\nhttps://github.com/krakenjs/post-robot\n\nPost-robot is used to provide a richer communication layer atop post-message.\n\n## Versioning\nThe Maana Q Assistant Client does not follow semantic versioning. Its versions\ntrack the releases of the Maana Q platform.\n\n## Examples\n@TODO Logan\n\n\n## Changes in v3.2.2\nImprovements in v3.2.2\n- Assistant State Management: WORKING, IDLE\n- Background Messaging/Eventing\n- Render Modes: BACKGROUND, DISPLAY\n- Expansion of Workspace object capabilities\n- Error Reporting\n- Repair Event\n- Plural versions of calls such as updateKind(s) to improve performance and developer experience.\n- InventoryChanged diffing is fully granular in v3.2.2--limitations\nin v3.2.1 only fired the Function diff for changes in Function name.\n\n### Deprecation\nThe following surface area IS removed from the\nclient in v3.2.2, and IS deprecated in the API:\n- AssistantAPIClient.enableSelectionChangedNotification\n- AssistantAPIClient.disableSelectionChangedNotification\n- AssistantAPIClient.enableInventoryChangedNotification\n- AssistantAPIClient.disableInventoryChangedNotification\n\nThe following surface area WILL BE removed from\nthe client in v3.2.4, and WILL BE deprecated in the API:\n- AssistantAPIClient.updateFunction (expected move to Workspace object)\n- AssistantAPIClient.updateKind (expected move to Workspace object)\n- AssistantAPIClient.deleteKind (expected move to Workspace object)\n- AssistantAPIClient.deleteFunction (expected move to Workspace object)\n\n## API Documentation\n\n### Assistant Render Mode\nAn assistant's render mode refers to whether it is being displayed in a visible manner to the user. As of v3.2.2, assistants are not closed when they are out of view.\nAll assistants will be loaded and kept in `BACKGROUND` render mode until they are\nplaced in the assistant panel, at which point the `DISPLAY` render mode event will be fired.\n\nNote: Assistants will receive all notifications/events while in BACKGROUND mode.\n\nDesign Consideration: It will be up to the developer to determine how state and resource use will be managed while an assistant is operating between BACKGROUND and DISPLAY modes.\n\n#### addRenderModeChangedListener = (cb) =>\nA listener to receive push events as to the assitant's render mode being changed.\n\n```js\nfunction handleRenderModeChanged(renderMode){\n  if (renderMode === 'DISPLAY'){\n    // Assistant is visible\n  } else {\n    // Assistant is not visible and running in background.\n  }\n}\n\nAssistantAPIClient.addRenderModeChangedListener(handleRenderModeChanged)\n\n```\n\n#### removeRenderModeChangedListener = (cb) =>\nRemoves the renderModeChanged listener by reference, or if no callback function reference is provided, it removes all listeners.\n\n#### getRenderMode = () =>\nReturns the current assistant render mode.\n\n```js\nconst renderMode = await AssistantAPIClient.getRenderMode()\n\nif (renderMode === 'DISPLAY'){\n  // Assistant is visible\n} else {\n  // Assistant is not visible and running in background.\n}\n\n```\n\n### Repair\nAssistants may get into situations where they are either out of sync with the Maana Q UI, or in a failure state. Assistants should be able to recover from these states.\n\nThe repair event functionality added in v3.2.2 is designed to notify the assistant that it must repair itself. This could mean a resync with its resources on the workspace or externally or, for some assistants, nothing at all.\n\nWhen is repair triggered?\nEither manually by a user clicking 'repair workspace' under the\nassistant inventory panel, or upon a workspace clone event. An assistant will be expected to handle either scenario.\n\nPerformance Consideration:\nFor some assistants, repair might involve 'introspecting'\nand processing the current workspace or Q system resources. This could be very resource intensive. Make sure you review this API guide to have an idea of what tools are\navailable to get the best results. It's always a good idea to check performance of repair on a large workspace and ensure necessary optimizations have been made.\n\nDesign Consideration:\nMake your workflows modular enough to be reused between repair and normal usage if possible.\n\n#### addRepairListener (cb) =>\n```js\n\nAssistantAPIClient.addRepairListener(()=>{\n  // Self-heal\n})\n\n```\n\nRecommended Usage: A repair process should be wrapped in the try/catch/finally flow shown in the `setAssistantState` API call to provide the user assistant-state and error updates as well as pause `inventoryChanged` notifications during repair (if the assistant has subscribed).\n\n#### removeRepairListener = (cb) =>\nRemoves the repair listener by reference, or if no callback function reference is provided, it removes all listeners.\n\n### User-facing Error Handling\n\n#### reportError (error) =>\nReports an error to the UI to be displayed in the assistant's error log in the\ninventory panel. This call is not disruptive and designed to operated independently of other assistant operations, such as state management. See `setAssistantState` in the next section.\n\nRecommended usage: use this functionality where it would futher the user experience\nto show the user an error and it's cause. Do not use this where things will be retried,\ncleaned up automatically, or are not relevant to the user.\n\n```js\ntry{\n  // Do work\n} catch(e) {\n  AssistantAPIClient.reportError(e)\n}\n```\n\n### State management\n\n#### clearState = () =>\nThis will remove all callbacks from all listeners.\n\n```js\nawait AssistantAPIClient.clearState()\n```\n\n#### setAssistantState = (state) =>\nThis sets the current state of the assistant using the\n`AssistantState` enum. Setting a state of `WORKING` will\ncreate the 'working' status spinner in the Assistant\nInventory Panel in the Maana Q UI. Conversely, setting an `IDLE` state will\nremove the spinner. This adds to user experience by informing users of the\nstatus of operations.\n\n```js\nimport {\n  default as AssistantAPIClient,\n  AssistantState\n} from '@io-maana/q-assistant-client'\n\n...\n\nAssistantAPIClient.setAssistantState(AssistantState.WORKING)\n\n...\n\nAssistantAPIClient.setAssistantState(AssistantState.IDLE)\n\n```\nUI User Prompt: If the assistant is in a `WORKING` state, the Maana Q UI will\nwarn the user before leaving the workspace.\n\nNOTE: while an assistant is in a working state, it will\nnot receive `inventoryChanged` events--an aggregated inventory diff\nwill be sent once the assistant is set back to `IDLE`.\n\nRecommended usage: Control states at a high level using try/catch/finally\nflow incorporating the `reportError` API call.\n\n```js\ntry{\n  AssistantAPIClient.setAssistantState(AssistantState.WORKING)\n  // Do work, await high-level tasks, etc.\n} catch(e) {\n  AssistantAPIClient.reportError(e)\n} finally{\n  AssistantAPIClient.setAssistantState(AssistantState.IDLE)\n}\n```\n\n#### AssistantState (enum)\nContains the valid assistant states: `IDLE` or `WORKING`.\n\nMust be imported in addition to the AssistantAPIClient:\n\n```js\nimport {\n  default as AssistantAPIClient,\n  AssistantState\n} from '@io-maana/q-assistant-client'\n```\n\n\n### User Info\nThe `UserInfo` object:\n```js\n{\n email: string,\n name: string\n}\n```\n\n#### getUserInfo = () =>\nReturns a Userinfo object pertaining to the logged in user.\n\n```js\nconst userInfo = await AssistantAPIClient.getUserInfo()\n```\n### Selection\nThe `Selection` object:\n```js\n{\n  kindId: string\n  kindName: string\n  id: string\n}\n```\n\n#### getCurrentSelection = () =>\nReturns an Array of `Selection` objects:\n\n```js\nconst {selection} = await AssistantAPIClient.getCurrentSelection();\n```\n\n#### addSelectionChangedListener = async cb =>\nAdds a callback function to be executed upon a valid workspace selection change.\n\nCallback value is an array of Selection objects:\n\n```js\n// Create the selection callback.\nconst selectionCB = ({selection})=>{\n  console.log('Workspace selection has changed.')\n  selection.forEach(i=>{\n    console.log('Kind: ',i.kindName)\n    console.log('Instance Id:',i.id)\n    console.log('Kind Id:',i.kindId)\n  })\n}\n\n// Add the listener.\nAssistantAPIClient.addSelectionChangedListener(selectionCB);\n```\n\nThis function only exists on the Q-Assistant-Client--only enableSelectionChangedNotification is called on the API.\n\n#### removeSelectionChangedListener = async cb =>\nThis will have to be called on a 1:1 basis with addSelectionChangedListener calls if supplying a callback.\n\n```js\nAssistantAPIClient.removeSelectionChangedListener(selectionCB)\n```\n\n**If NOT supplying a callback to this call, all selection changed listeners will be removed.\n\n```js\nAssistantAPIClient.removeSelectionChangedListener()\n```\n\nThis function only exists on the Q-Assistant-Client--only disableSelectionChangedNotification is called on the API.\n\n\n### Services\nThe `Service` object:\n```js\n{\n   id: string,\n   name: string\n   endpointUrl: string,\n   getKinds: () => // Returns [] of Kinds objects\n   getFunctions: () => // Returns [] of Function objects\n}\n```\n\n#### getServiceById = id =>\nThis will return a service that exists within the scope of the workspace.\n** Assistant services will return null. Services outside the scope of the workspace will cause an error to be returned as 'Unable to load a Service from outside of the workspace.'\n\n```js\nconst svc = await AssistantAPIClient.getServiceById(id)\n```\n\n#### createService = id =>\nCreates a service in Q.\n\nNote: This will create the service, but does NOT import it into the workspace.\nYou will need to use `importService` on the Workspace object to import it.\nReturns a promise that resolves\n\n```js\n    const service = {\n      id: ...,\n      name: ...,\n      endpointUrl: ...,\n      serviceType: ...\n    }\n\n    await AssistantAPIClient.createService(service)\n```\n\n#### deleteService = id =>\nDeletes a service from Q.\n\n```js\n    await AssistantAPIClient.deleteService(id)\n```\n\n#### refreshServiceSchema = id =>\nRefreshes a service by fetching its schema. This will also\nreload the service inventory in the currently visible workspace.\n\n```js\nawait AssistantAPIClient.refreshServiceSchema(\"id\")\n```\n\n#### reloadService = id =>\nReloads a service in the inventory in the currently visible workspace.\n\n```js\nawait AssistantAPIClient.reloadService(\"id\")\n```\n\n### Workspace\n\n#### getWorkspace = () =>\nReturns a Workspace object representing the workspace.\n\n```js\nconst ws = await AssistantAPIClient.getWorkspace(id)\n```\n\nNote: The `id` parameter is optional. If it is not supplied, the query\nwill return the current/visible workspace.\n\nThe `Workspace` object:\n\n```js\n\n{\n    id: string,\n    name: string,\n    endpointUrl: string,\n    workspaceServiceId: string,\n    modelServiceId: string,\n    logicServiceId: string,\n\n    //\n    // Locking information\n    //\n    async lockedBy() {\n      // Returns the e-mail address of the user who locked the Workspace, or\n      // null if the Workspace is not currently locked.\n    }\n    async canEdit() {\n      // Returns `true` when the Workspace is not locked, or the current user\n      // owns the lock.\n      // Returns 'false' when the Workspace is locked by a different user.\n    }\n    async setLocked(isLocked) {\n      // Takes a boolean or undefined for `isLocked`.\n      //  `true` locks the Workspace as the current User.\n      //  `false` unlocks the Workspace\n      //  `undefined` causes it to toggle the current locked state.\n      // Returns a Promise that will resolve or reject when the task is done.\n    }\n\n    //\n    // Knowledge Graphs\n    //\n    getActiveGraph: async () => {\n      // Returns the active Graph object.\n      // Returns null if active graph is not of type 'Knowledge Graph', or if an\n      // active graph is deleted, thereby setting active graph to null.\n    },\n    getKnowledgeGraphs: async () => {\n      // Returns [Graph]\n    },\n    // TODO: define input\n    createKnowledgeGraph: input =>\n    // TODO: define input\n    createKnowledgeGraphs: input =>\n\n    //\n    // Services\n    //\n    getImportedServices: async () => {\n      // Returns an array of Service objects that have\n      // been imported into the workspace.\n      // No assistant services will be returned.\n    },\n    getImportedAssistants: async () => {\n      // Returns a list of imported assistants.\n    },\n    importService: serviceId => {\n      // Imports a service by it's ID.\n    },\n    importServices: serviceIds => {\n      // Imports services by their IDs.\n    },\n    removeServices: serviceIds => {\n      // Removes a list of services from the workspace.\n    },\n    removeService: serviceId => {\n      // Removes a service from the workspace.\n    },\n\n    //\n    // Functions\n    //\n    getFunctions: async () => {\n      // Returns an array of functions in the workspace (includes boilerplate).\n    },\n    createFunction: funcData => {\n      // Creates a function and adds it to the graph.\n    }\n    createFunctions: funcData =>{\n      // Creates several functions and adds them to the graph.\n    }\n    updateFunction: funcData => {\n      // Updates a function.\n    },\n    updateFunctions: funcData =>{\n      // Updates functions based on input array.\n    },\n    deleteFunction: funcId => {\n      // Deletes a function by its ID.\n    },\n    getFunctionGraph: funcId => {\n      // Returns a function graph by its ID.\n    }\n\n    //\n    // Kinds\n    //\n    getKinds: async () => {\n      // Returns an array of functions in the workspace (includes boilerplate).\n    },\n    createKind: kindData => {\n      // Currently same input as AssistantAPIClient call.\n    },\n    createKinds: kindData => {\n      // Currently same input as AssistantAPIClient call.\n    },\n    updateKind: kindData => {\n      // Currently same input as AssistantAPIClient call.\n    },\n    updateKinds: kindData => {\n      // Currently same input as AssistantAPIClient call.\n    },\n    deleteKind: kindId => {\n      // Currently same input as AssistantAPIClient call.\n    }\n    // Event Triggers\n    triggerRepairEvent: () => {\n      // Triggers the repair event on a workspace.\n    }\n  };\n}\n```\n\n\n### Graphs\nThe `Graph` object:\n```js\n{\n  id: string,\n  name: string,\n  offsetX: Number,\n  offsetY: Number,\n  zoom: Number,\n  getNodes: async () => {\n      // Returns [Node]\n  },\n\n  addNode: async (type, instance, changeSelection) => {\n      // Returns Node\n  },\n  removeNode: async id => {\n      // Should return nothing or error.\n      // Currently returning [] in all cases.\n  },\n  updateNodeLayout: async (nodeId, { x, y, collapsed }) => {\n  },\n  updateGraphLayout: async ({ offsetX, offsetY, zoom }) => {\n  }\n\n  //\n  // Locking information\n  //\n  async lockedBy() {\n    // Returns the e-mail address of the user who locked the Graph, or null if\n    // the Graph is not currently locked.\n  }\n  async canEdit() {\n    // Returns `true` when the Graph is not locked, or the current user owns the\n    // lock.\n    // Returns 'false' when the Graph is locked by a different user.\n  }\n  async setLocked(isLocked) {\n    // Takes a boolean or undefined for `isLocked`.\n    //  `true` locks the Graph as the current User.\n    //  `false` unlocks the Graph\n    //  `undefined` causes it to toggle the current locked state.\n    // Returns a Promise that will resolve or reject when the task is done.\n  }\n}\n```\n\n#### Getting a graph object:\nGraph objects are obtained through an instance of a Workspace\n\n```js\nconst ag = await ws.getActiveGraph()\n```\n\nor\n\n```js\nconst kgs = await ws.getKnowledgeGraphs()\n```\n\n#### Manipulating Graphs\n\n**Only the active graph may be manipulated.\n\nAll graph manipulations should be ‘visually’ verifiable on the graph itself, i.e., adds/removes/positioning, should all be reflected on the graph itself.\n\nThe `Node` object:\n```js\n{\nid: string\nx: number\ny: number\ncollapsed: boolean\nknowledgeGraphNode {\n  id: string\n  innerKind: Kind\n  innerFunction: Function\n}\n}\n```\n\n#### addNode(type, instance, changeSelection) =>\n\nTakes type (“Function” or “Kind”), instance (the Function or Kind object), and optionally a boolean to indicate whether the selection should be changed to this new node.\n\nReturns the newly created Node object.\n\n```js\nconst node = await ag.addNode('Kind',kind)\n```\n\n#### removeNode(id) =>\n\nTakes the id of Node to be deleted. Returns either undefined or an error.\n\n```js\nawait ag.removeNode(node.id)\n```\n\n#### getNodes() =>\nReturns an array of Node objects from the graph.\n\n```js\nconst nodes = await ag.getNodes()\n```\n\n#### updateNodeLayout: async (nodeId, { x, y, collapsed})=>\nUpdates a Node layout given a node ID and node coordinates (`x` and/or `y`) or a `collapsed` value. x/y values must be a number, and collapsed must be a boolean. Whatever is not specified will remain current.\n\n```js\nag.updateNodeLayout(id,{x:100,y:100,collapsed:true})\n```\n\n#### updateGraphLayout: async ({ offsetX, offsetY, zoom})=>\nUpdates a Graph layout given numerical values for x/y offsets and the zoom.\n\n```js\nag.updateGraphLayout({offsetX:50, offsetY:50, zoom: 70})\n```\n\n### Functions\n\nThe `Function` object:\n```js\n{\n    id: string\n    name: string\n    service {\n      id: string\n      name: string\n    }\n    arguments {\n      id: string\n      name: string\n      type: string\n      modifiers: Array[string]\n      typeKindId:: string\n      kind {\n        id: string\n        name: string\n      }\n    }\n    implementation {\n      id: string\n      entrypoint {\n        id: string\n      }\n      operations {\n        id: string\n        type: string\n        function {\n          id: string\n          name: string\n        }\n        argumentValues {\n          id: string\n          argument {\n            id: string\n          }\n          operation {\n            id: string\n          }\n          argumentRef: string\n        }\n      }\n    }\n    isGenerated: boolean\n    functionType: string\n    graphqlOperationType: string\n    outputType: string\n    outputKindId: string\n    outputModifiers: Array[string]\n    kind {\n      id: string\n      name: string\n    }\n\n    //\n    // Locking information\n    //\n    async lockedBy() {\n      // Returns the e-mail address of the user who locked the Function, or null\n      // if the Function is not currently locked.\n    }\n    async canEdit() {\n      // Returns `true` when the Function is not locked, or the current user\n      // owns the lock.\n      // Returns 'false' when the Function is locked by a different user.\n    }\n    async setLocked(isLocked) {\n      // Takes a boolean or undefined for `isLocked`.\n      //  `true` locks the Function as the current User.\n      //  `false` unlocks the Function\n      //  `undefined` causes it to toggle the current locked state.\n      // Returns a Promise that will resolve or reject when the task is done.\n    }\n}\n```\n\n`FunctionExecutionResult` object:\n```js\n{\n  id: string,\n  result: JSON\n}\n```\n\n#### executeFunction = ( {id, variables, resolve} ) =>\nExecutes a function based on its id, with optional inputs for variables and a resolve string (this specifies the fields to be returned, which must be valid based on the result).\n\nReturns : JSON matching shape of result , unless no sub-selection of fields is required in the execution.\n\nThis following piece of code will execute a Function given a function ID, and pass in variables for ‘example’, requesting back id and name fields.\n\n```js\nconst res = await AssistantAPIClient.executeFunction({functionId: func.id, variables: {\"variableName\": \"variableValue\"}, resolve: \"{ id name }\");\n```\n\n#### createFunction = input =>\nCreates a function based on the input provided.\n\nReturns: the created Function object.\n\n**Using create function will only place the function in the workspace’s inventory--it will not place the function as a node on the Graph. In order to do this, you must pass the created function into the addNode function on the active Graph, making sure to specify ‘Function' as the type.\n\n```js\nconst createFunctionInput = {\n  name:\"yourName\",\n  arguments:[],\n  outputType: \"STRING\",\n  graphqlOperationType:\"QUERY\",\n  functionType: \"CKG\"\n}\n\nconst createdFunction = await AssistantAPIClient.createFunction(createFunctionInput)\n```\n\n#### updateFunction = input =>\nInput is the same for creating a function. It’s important to note that the arguments property will be replaced in it’s entirety with whatever is provided (if a value is provided.\n\nReturns the updated `Function` object.\n\n```js\nconst updatedFunction = await AssistantAPIClient.updateFunction(input);\n```\n\n#### deleteFunction = input =>\nInput is the id of the Function to be deleted. Returns the deleted function as a promise.\n\n```js\nconst deletedFunction = await AssistantAPIClient.deleteFunction('id...');\n```\n\n#### getFunctionById = id =>\nReturns a Function as a promise based on the ID provided.\n\n```js\nconst func = await AssistantAPIClient.getFunctionById('id...');\n```\n\n#### addFunctionExecutionListener = async (id, cb) =>\nAssociates a callback function with the execution of a particular Function. When the Function matching the id parameter is executed, its FunctionExecutionResult object passed to the callback. Returns undefined.\n\nExample function execution callback and listener registration:\n\n```js\nfunction exampleFunctionCB (result){\n  console.log(`Function executed with result:`, result)\n}\n\nAssistantAPIClient.addFunctionExecutionListener('id...', exampleFunctionCB)\n```\n\n#### removeFunctionExecutionListener = async (id, cb) =>\nRemoves a Function execution listener based on the function ID and a reference to the callback function. If no callback is supplied, all listeners associated with the Function ID will be removed. Returns undefined.\n\n```js\nAssistantAPIClient.removeFunctionExecutionListener('id..', exampleFunctionCB)\n```\n\n### Kinds\nThe `Kind` object:\n```js\n{\n    id: string\n    name: string\n    service: {\n      id\n      name\n    }\n    isGenerated: boolean\n    schema {\n      id: string\n      name: string\n      type: string\n      typeKindId: string\n      modifiers: Array[string]\n      kind {\n        id: string\n        name: string\n      }\n    }\n}\n```\n\n#### createKind = input =>\nCreates a Kind based on an input object. Returns a promise that resolves to the created Kind object.\n\n```js\nconst kindInput = {\n name: \"someKind\",\n schema:[\n  { name: \"someField1\", type: STRING },\n  { name: \"someField2\", type: STRING }\n ]\n}\n\nconst newKind = await AssistantAPIClient.createKind(kindInput)\n```\n\n#### createKinds = input =>\nA plural version of `createKind` accepting an array of input objects.\nReturns a promise that resolves to an array of created Kind objects.\n\n```js\nconst kindsInput = [{\n name: \"someKind\",\n schema:[\n  { name: \"someField1\", type: STRING },\n  { name: \"someField2\", type: STRING }\n ]\n}, ...]\n\nconst newKinds = await AssistantAPIClient.createKinds(kindsInput)\n```\n\n\n#### updateKind = input =>\nUpdates a Kind based on an input object.\n\nUpdate Semantics: Only properties specified will be updated. If updating the schema, the entire schema must be specified as it will be replaced in its entirety.\n\nReturns a promise that resolves to the updated `Kind` object.\n\n```js\nconst updated = await AssistantAPIClient.updateKind(input)\n```\n\n#### deleteKind = input =>\nDeletes a Kind given a kind ID.\n\n```js\nconst deleted = await AssistantAPIClient.deleteKind(input)\n```\n\n#### getKindById = id =>\nReturns a promise that resolves to a Kind object given the specified kind ID.\n\nIn v3.2.2, any requested non-system kinds will be returned.\nIn v3.2.1, only kinds in the workspace or those of imported services will be returned.\n\n```js\nconst kind = await AssistantAPIClient.getKindById(id)\n```\n\n#### getKindsById = ids =>\nReturns a promise that resolves to an array of Kind objects given an array of kind IDs. Only kinds in the workspace or those of imported services will be returned.\n\n```js\nconst ids = [\"...\",\"...\",...]\nconst kind = await AssistantAPIClient.getKindsById(ids)\n```\n\n#### getAllReferencedKinds = input =>\nRecursively collects all kinds that are referenced in a kind's schema, starting\nwith a kind ID. For example if the ID of kind A is supplied as an input, and Kind `A` contains a field of type Kind `B`, and `B` contains a field of type Kind `C`,\nan array containing the kinds objects for `A`, `B`, `C` will be returned (as a promise).\n\n```js\nconst initialId = [\"...\"]\nconst kinds = await AssistantAPIClient.getAllReferencedKinds({\n          ids: initialId\n        })\n```\n\n\n### Inventory\n\nThe `InventoryChanged` object:\n```js\n{\n  kinds: {\n    adds: [DiffItem]\n    deletes: [DiffItem]\n    updates: [DiffItem]\n  }\n  functions:{\n    adds: [DiffItem]\n    deletes: [DiffItem]\n    updates: [DiffItem]\n  }\n  services: {\n    adds: [DiffItem]\n    deletes: [DiffItem]\n    updates: [DiffItem]\n  }\n}\n```\n\nThe `DiffItem` object:\n```js\n{\n  id: string,\n  name: string\n}\n```\n\n#### addInventoryChangedListener = async cb =>\nRegisters a callback function with the inventory changed event. When workspace inventory changes the callback function will be called with the InventoryChangedobject. Returns undefined.\n\n**Use-case note: an ‘update’ diff for inventory services is unlikely in general usage.\n\n```js\nconst inventoryCB = ({diff}) => {\n  if(diff.kinds) console.log('KINDS CHANGED',diff.kinds)\n  if(diff.functions) console.log('FUNCTIONS CHANGED', diff.functions)\n  if(diff.services) console.log('SERVICES CHANGED',diff.services)\n}\n\nAssistantAPIClient.addInventoryChangedListener(inventoryCB)\n```\n\nThis function exists on the Q-Assisant-Client only--only enableSelectionChangedNotification is used on the API side.\n\n#### removeInventoryChangedListener = async cb =>\nRemoves an inventory changed listener given the referenced callback. If no callback is specified, all listeners will be removed. Returns undefined.\n\n```js\nAssistantAPIClient.removeInventoryChangedListener(inventoryCB)\n```\n\nThis function exists on the Q-Assisant-Client only--only disableSelectionChangedNotification is used on the API side.\n\n#### moveKindsAndFunctions = (originId, targetId, kindIds, functionIds) =>\nMoves a collection of Kinds and Functions from the origin Workspace to the target Workspace.\n\n```js\n  await AssistantAPIClient.moveKindsAndFunctions(\n    originWorkspaceId,\n    targetId,\n    kindIds,\n    functionIds\n  );\n```\n\n### Locking Changed Event\n\nAn event is triggered when the locked state of the currently active Workspace or\nits Knowledge Graphs and Functions change.\n\nThe `LockingChanged` object:\n```js\n{\n  workspaces: [LockItem],\n  knowledgeGraphs: [LockItem],\n  functions: [LockItem]\n}\n```\n\nThe `LockItem` object:\n```js\n{\n  id: string\n  lockedBy: string\n}\n```\n\n#### addLockingChangedListener = cb =>\n\nRegisters a callback function with the locking changed event. When the currently\nactive Workspace or its Knowledge Graphs and Functions change the callback\nfunction will be called with the `LockingChanged` object. Returns undefined.\n\n```js\nconst lockingChangedCB = ({ locks }) => {\n  if(locks.workspace) console.log('WORKSPACES CHANGED', locks.workspace);\n  if(locks.knowledgeGraphs) console.log('KNOWLEDGE GRAPHS CHANGED', locks.knowledgeGraphs);\n  if(locks.functions) console.log('FUNCTIONS CHANGED', locks.functions);\n}\n\nAssistantAPIClient.addLockingChangedListener(lockingChangedCB);\n```\n\n#### removeLockingChangedListener = cb =>\n\nRemoves an locking changed listener given the referenced callback. If no\ncallback is specified, all listeners will be removed. Returns undefined.\n\n```js\nAssistantAPIClient.removeLockingChangedListener(lockingChangedCB)\n```\n\n## Troubleshooting Assistant Issues\n### Assistant root file has loaded, but not other content\nObserving in the browser's dev tools that some resources have loaded correctly (usually the root), but other's haven't (usually nested files or chunks), is indicative of a failure of Q Gateway to proxy due to not having a 'relative' path structure.\n\n### You are seeing post-robot `NO ACK` errors in the console.\nThese errors stem from a failed acknowledgement for a call either between the client and the API or vice-versa. Here, this means that the web app 'window' (the assistant) cannot communicate with, or access, the 'window.parent' (Maana K-Portal) object.\n\nCommonly, these will stem from the 'window' (the assistant) not being loaded or in a loadable state, which means the API will not receive an acknowledgement when it fires an event.\n\nImproper CORS configuration is also a common culprit (also verify if using docker or nginx that your proxying and networking is configured correctly to allow communication and to accout for CORS).","readmeFilename":"README.md","_id":"@io-maana/q-assistant-client@3.2.3-beta.38","_npmVersion":"6.4.1","_nodeVersion":"10.15.3","_npmUser":{"name":"teamcitymaana","email":"teamcity@maana.io"},"dist":{"integrity":"sha512-/YV57zEuhnntUAuI0pQEK+xTna00+z0k2TP/Vw8cbFa9F+ARwiQOwjnk1Xsf0DuVFFhFM94NfwSw4UTflaqMAA==","shasum":"88ce8c74b798acf64303c58306e65e64e02a075b","tarball":"https://registry.npmjs.org/@io-maana/q-assistant-client/-/q-assistant-client-3.2.3-beta.38.tgz","fileCount":10,"unpackedSize":65161,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJfB3qFCRA9TVsSAnZWagAAEoMP/203/NKhUc2twk8fITo3\nTqNKNTM0uxxYWam7Jyna1uKk1jE5BF1YxCVC2oqLWluggU9fNhqkE5+76Ksu\ng00ltDH9gvoozv4l8kGZyAPWgrfOqGlQOtV/Nm+NNGIiYeTOceNA3FvymBfZ\nJtTYMGoKVPx+Bdw066Qm34r+0bzQZUXGOoJ0nIVOvphta6P4dFaZ6rpCkb8k\nXpd0QQLK3ttoZQIhDTBwzMk8Qp3iSJL5pkLOfJOis077euc8Xa6qQuYyqlMK\nuXaPvyW7UuJzG7HMmZ4/Ei9ld5hbUpiR5ZkxWZCEFeRxTyflgvePK2kWRoac\nB7EwQrdq6tQxDnHQIcGS0N1dhVbRLHSujnHs7Cv5KZWLJIkF3K6qFeDUEPz0\nxxgmXbgG0MZT+OzwTklL83zSrVkqXpPYDJQp3KJxAGiixWVWjpq67bVOaPto\nChbE6GCWXRNX5SvYly1cE28vg7Lgo0YXEyCBg9P53fi7UI0hv3MCpEhCluaX\nb1DIDOP236Yj2Ff25Wl9+7EMYbC0hVTjI/7TOxDIfmP4LxaZFfwlkSIzNdiN\nQn5KVfXgnjJaWMOss86teZtBbUkfZdciWKERxZ/gaofBBCm7srBqJBjFc1Q9\n2Q2QtNVNEAb0PTVL6fWrGSxOgS5d1GgaGs1kJ67vVABFMdJO6jf5CGRJ99KO\nsds/\r\n=Tqxl\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEQCIB/QQ3WSMmL7p2QkTsuWD4qmXcIUIEH7IieKh+EcM1chAiA8Z3mb6dSf5iw8QYiZ72yW0C1HMEFXvgqkdgPjFsNYEA=="}]},"maintainers":[{"email":"andrey@maana.io","name":"abatyuk"},{"email":"bzvestey@gmail.com","name":"bzvetey"},{"email":"dlewissandy@maana.io","name":"dlsmaana"},{"email":"rob@maana.io","name":"rpovey"},{"email":"teamcity@maana.io","name":"teamcitymaana"},{"email":"witt3rd@witt3rd.com","name":"witt3rd"}],"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/q-assistant-client_3.2.3-beta.38_1594325636714_0.9395532180382242"},"_hasShrinkwrap":false},"3.2.3":{"name":"@io-maana/q-assistant-client","version":"3.2.3","description":"JavaScript package to streamline communication between an assistant and the Maana Q Assistant API.","main":"build/index.js","exports":{"./":"./build/"},"scripts":{"build":"babel src --out-dir build","prepack":"npm run build","test":"echo \"Error: no test specified\" && exit 1","format":"prettier --write \"src/**/*.js\""},"repository":{"type":"git","url":"git+https://github.com/maana-io/q-assistant-client.git"},"keywords":["Maana","Q"],"author":{"name":"Logan Gore @ Maana.io"},"license":"MIT","bugs":{"url":"https://github.com/maana-io/q-assistant-client/issues"},"homepage":"https://github.com/maana-io/q-assistant-client#readme","dependencies":{"core-js":"3.6.4","post-robot":"10.0.29"},"devDependencies":{"@babel/cli":"^7.5.5","@babel/core":"^7.5.5","@babel/plugin-proposal-class-properties":"^7.5.5","@babel/preset-env":"^7.5.5","prettier":"1.19.1"},"gitHead":"3a37fced485908e29b8008e457790db90cc4a4dc","_id":"@io-maana/q-assistant-client@3.2.3","_npmVersion":"6.4.1","_nodeVersion":"10.15.3","_npmUser":{"name":"teamcitymaana","email":"teamcity@maana.io"},"dist":{"integrity":"sha512-i+oPFOoEtVwZQDdl52/v5ABeKXJ15RN3re2CE1usPEOfZS+RsUNExlq1EICKDbFYEabP8BCv5inevn8n9iVBaA==","shasum":"b5b659d1e01380e784d116ad7259eb15362c8dc5","tarball":"https://registry.npmjs.org/@io-maana/q-assistant-client/-/q-assistant-client-3.2.3.tgz","fileCount":10,"unpackedSize":65153,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJfB4+yCRA9TVsSAnZWagAAf/wP/jfIRrdEUq3TFHy/O+23\ncEKfI+qga+p33SIG3y+hXcpCZ20zCsaP688eF4reVCjzZ3ufuBnrdfA7ZV/P\ndyXH1dIpov+d0dEkE0ROhshrX4Uo6PGs99vWeT+TeaCH7ynNF0hILSJpslRk\nUi2tdZ0k1N714bpc7CyESHtrVZkkkGaXamq9librZg2mhsHyjy0iJj/gS+eg\nhhYI8DEhaXt4yj0LQ1SVznhrtP6T9+V2EXcI/Z8JNB1fL20ubHz2BtzU7BUV\n1eaYxYDI4rT1rjkUHO3ez6chFkX25mEWjoy4TCUpvlr+GdEkoptv585rGAIV\nXYvXV9z5Gt8ceBDoZtJIsLZwPuw2hTHOUzz9KlTmkp/Dx/qBkPfY11dZTGUI\nXVXcaMLKkDHiUg6YwU5GcYAVak3ZR8s8jcYLRyIQd5d9zT0ZGKM4gF4HQM7r\nQloTUXhUQq7d74EPRpc7RYoxBuB8Q+fIhCYzXd7JVh9+EQlwaLKW+4tlxshp\nArpnx5PuD4T2plm6av9uY1XCThj9R2RgGok65vn4sJWhMUdkRiaRaaD3XVhQ\nY1fuduVdQfo3qFc2x/bmvZj04C4CIOJE1nnoh9knnKE6cdjfhr6DHsxMLSK5\n74v+/A1hEQ6Go3fj1p3JpAKimjqR31OJILZd8J5Kgs3eas2mW9PdLYIYbrmp\nE3nN\r\n=7/Pw\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEQCIF1oppOqi7+AZnW+T/102O9hnCT4ce26j4D5tw/bD9ZdAiAYheXs0/TVyYdm1D8FDw2cwkKQPnwhWOljabnDu9geIA=="}]},"maintainers":[{"email":"andrey@maana.io","name":"abatyuk"},{"email":"bzvestey@gmail.com","name":"bzvetey"},{"email":"dlewissandy@maana.io","name":"dlsmaana"},{"email":"rob@maana.io","name":"rpovey"},{"email":"teamcity@maana.io","name":"teamcitymaana"},{"email":"witt3rd@witt3rd.com","name":"witt3rd"}],"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/q-assistant-client_3.2.3_1594331058353_0.6752805200738023"},"_hasShrinkwrap":false},"3.2.4-beta.39":{"name":"@io-maana/q-assistant-client","version":"3.2.4-beta.39","description":"JavaScript package to streamline communication between an assistant and the Maana Q Assistant API.","main":"build/index.js","exports":{"./":"./build/"},"scripts":{"build":"babel src --out-dir build","prepack":"npm run build","test":"echo \"Error: no test specified\" && exit 1","format":"prettier --write \"src/**/*.js\""},"repository":{"type":"git","url":"git+https://github.com/maana-io/q-assistant-client.git"},"keywords":["Maana","Q"],"author":{"name":"Logan Gore @ Maana.io"},"license":"MIT","bugs":{"url":"https://github.com/maana-io/q-assistant-client/issues"},"homepage":"https://github.com/maana-io/q-assistant-client#readme","dependencies":{"core-js":"3.6.4","post-robot":"10.0.29"},"devDependencies":{"@babel/cli":"^7.5.5","@babel/core":"^7.5.5","@babel/plugin-proposal-class-properties":"^7.5.5","@babel/preset-env":"^7.5.5","prettier":"1.19.1"},"readme":"# q-assistant-client\nA lightweight JavaScript client for Maana-Q Assistant developers that wraps post-message communication between an embedded Maana-Q assistant and the Maana-Q UI.\n\n## Abstract\nThe Q-Assistant-Client is intented to be used in a web application being leveraged as a Maana Q assistant (embedded as an iframe).\nThis assistant client will facilitate communication between the assistant and the parent frame.\nThe client provides a rich, asynchronous experience over what would otherwise be 'fire-and-forget'-style messaging\nvia post-post message communication.\n\n## Requirements and Assumptions\n\n### Post-Robot Library\nThe Maana Knowledge Portal (KPortal) uses the kraken/post-robot library [kraken/post-robot](https://github.com/krakenjs/post-robot) to enrich the communication with the assistant. Post-robot allows for asynchronous, promise-based request/response style behavior between the assistant and the assistant API.\n\nThe API requires that the client use the post-robot library. This assistant-client library is the easiest way to achieve this, and also adds a fair amount of 'sugar' to the process to improve developer productivity. Developers could, however, use post-robot directly in their own client implementation.\n\n### Maana-Gateway Proxy Requirements\nThe Maana-Gateway service requires relative paths (paths relative to the root) in the assistant web application in order to proxy the application and its content. For create-react-apps, for instance, this means setting \"homepage\" to \".\" in the package.json file.\n\n## Singleton Instance\nThe client is exported as a singleton to avoid duplicate registration on event listeners.\nYou can import the instance like this:\n\n```js\nimport AssistantAPIClient from '@io-maana/q-assistant-client';\n```\n\nFunction calls can be made against the client instance like any other javascript object. They are all async.\n\n```js\nconst workspace = await AssistantAPIClient.getWorkspace();\nconsole.log(\"Workspace:\", workspace)\n```\n\n## Dependencies\nPost-Robot\nhttps://github.com/krakenjs/post-robot\n\nPost-robot is used to provide a richer communication layer atop post-message.\n\n## Versioning\nThe Maana Q Assistant Client does not follow semantic versioning. Its versions\ntrack the releases of the Maana Q platform.\n\n## Examples\n@TODO Logan\n\n\n## Changes in v3.2.2\nImprovements in v3.2.2\n- Assistant State Management: WORKING, IDLE\n- Background Messaging/Eventing\n- Render Modes: BACKGROUND, DISPLAY\n- Expansion of Workspace object capabilities\n- Error Reporting\n- Repair Event\n- Plural versions of calls such as updateKind(s) to improve performance and developer experience.\n- InventoryChanged diffing is fully granular in v3.2.2--limitations\nin v3.2.1 only fired the Function diff for changes in Function name.\n\n### Deprecation\nThe following surface area IS removed from the\nclient in v3.2.2, and IS deprecated in the API:\n- AssistantAPIClient.enableSelectionChangedNotification\n- AssistantAPIClient.disableSelectionChangedNotification\n- AssistantAPIClient.enableInventoryChangedNotification\n- AssistantAPIClient.disableInventoryChangedNotification\n\nThe following surface area WILL BE removed from\nthe client in v3.2.4, and WILL BE deprecated in the API:\n- AssistantAPIClient.updateFunction (expected move to Workspace object)\n- AssistantAPIClient.updateKind (expected move to Workspace object)\n- AssistantAPIClient.deleteKind (expected move to Workspace object)\n- AssistantAPIClient.deleteFunction (expected move to Workspace object)\n\n## API Documentation\n\n### Assistant Render Mode\nAn assistant's render mode refers to whether it is being displayed in a visible manner to the user. As of v3.2.2, assistants are not closed when they are out of view.\nAll assistants will be loaded and kept in `BACKGROUND` render mode until they are\nplaced in the assistant panel, at which point the `DISPLAY` render mode event will be fired.\n\nNote: Assistants will receive all notifications/events while in BACKGROUND mode.\n\nDesign Consideration: It will be up to the developer to determine how state and resource use will be managed while an assistant is operating between BACKGROUND and DISPLAY modes.\n\n#### addRenderModeChangedListener = (cb) =>\nA listener to receive push events as to the assitant's render mode being changed.\n\n```js\nfunction handleRenderModeChanged(renderMode){\n  if (renderMode === 'DISPLAY'){\n    // Assistant is visible\n  } else {\n    // Assistant is not visible and running in background.\n  }\n}\n\nAssistantAPIClient.addRenderModeChangedListener(handleRenderModeChanged)\n\n```\n\n#### removeRenderModeChangedListener = (cb) =>\nRemoves the renderModeChanged listener by reference, or if no callback function reference is provided, it removes all listeners.\n\n#### getRenderMode = () =>\nReturns the current assistant render mode.\n\n```js\nconst renderMode = await AssistantAPIClient.getRenderMode()\n\nif (renderMode === 'DISPLAY'){\n  // Assistant is visible\n} else {\n  // Assistant is not visible and running in background.\n}\n\n```\n\n### Repair\nAssistants may get into situations where they are either out of sync with the Maana Q UI, or in a failure state. Assistants should be able to recover from these states.\n\nThe repair event functionality added in v3.2.2 is designed to notify the assistant that it must repair itself. This could mean a resync with its resources on the workspace or externally or, for some assistants, nothing at all.\n\nWhen is repair triggered?\nEither manually by a user clicking 'repair workspace' under the\nassistant inventory panel, or upon a workspace clone event. An assistant will be expected to handle either scenario.\n\nPerformance Consideration:\nFor some assistants, repair might involve 'introspecting'\nand processing the current workspace or Q system resources. This could be very resource intensive. Make sure you review this API guide to have an idea of what tools are\navailable to get the best results. It's always a good idea to check performance of repair on a large workspace and ensure necessary optimizations have been made.\n\nDesign Consideration:\nMake your workflows modular enough to be reused between repair and normal usage if possible.\n\n#### addRepairListener (cb) =>\n```js\n\nAssistantAPIClient.addRepairListener(()=>{\n  // Self-heal\n})\n\n```\n\nRecommended Usage: A repair process should be wrapped in the try/catch/finally flow shown in the `setAssistantState` API call to provide the user assistant-state and error updates as well as pause `inventoryChanged` notifications during repair (if the assistant has subscribed).\n\n#### removeRepairListener = (cb) =>\nRemoves the repair listener by reference, or if no callback function reference is provided, it removes all listeners.\n\n### User-facing Error Handling\n\n#### reportError (error) =>\nReports an error to the UI to be displayed in the assistant's error log in the\ninventory panel. This call is not disruptive and designed to operated independently of other assistant operations, such as state management. See `setAssistantState` in the next section.\n\nRecommended usage: use this functionality where it would futher the user experience\nto show the user an error and it's cause. Do not use this where things will be retried,\ncleaned up automatically, or are not relevant to the user.\n\n```js\ntry{\n  // Do work\n} catch(e) {\n  AssistantAPIClient.reportError(e)\n}\n```\n\n### State management\n\n#### clearState = () =>\nThis will remove all callbacks from all listeners.\n\n```js\nawait AssistantAPIClient.clearState()\n```\n\n#### setAssistantState = (state) =>\nThis sets the current state of the assistant using the\n`AssistantState` enum. Setting a state of `WORKING` will\ncreate the 'working' status spinner in the Assistant\nInventory Panel in the Maana Q UI. Conversely, setting an `IDLE` state will\nremove the spinner. This adds to user experience by informing users of the\nstatus of operations.\n\n```js\nimport {\n  default as AssistantAPIClient,\n  AssistantState\n} from '@io-maana/q-assistant-client'\n\n...\n\nAssistantAPIClient.setAssistantState(AssistantState.WORKING)\n\n...\n\nAssistantAPIClient.setAssistantState(AssistantState.IDLE)\n\n```\nUI User Prompt: If the assistant is in a `WORKING` state, the Maana Q UI will\nwarn the user before leaving the workspace.\n\nNOTE: while an assistant is in a working state, it will\nnot receive `inventoryChanged` events--an aggregated inventory diff\nwill be sent once the assistant is set back to `IDLE`.\n\nRecommended usage: Control states at a high level using try/catch/finally\nflow incorporating the `reportError` API call.\n\n```js\ntry{\n  AssistantAPIClient.setAssistantState(AssistantState.WORKING)\n  // Do work, await high-level tasks, etc.\n} catch(e) {\n  AssistantAPIClient.reportError(e)\n} finally{\n  AssistantAPIClient.setAssistantState(AssistantState.IDLE)\n}\n```\n\n#### AssistantState (enum)\nContains the valid assistant states: `IDLE` or `WORKING`.\n\nMust be imported in addition to the AssistantAPIClient:\n\n```js\nimport {\n  default as AssistantAPIClient,\n  AssistantState\n} from '@io-maana/q-assistant-client'\n```\n\n\n### User Info\nThe `UserInfo` object:\n```js\n{\n email: string,\n name: string\n}\n```\n\n#### getUserInfo = () =>\nReturns a Userinfo object pertaining to the logged in user.\n\n```js\nconst userInfo = await AssistantAPIClient.getUserInfo()\n```\n### Selection\nThe `Selection` object:\n```js\n{\n  kindId: string\n  kindName: string\n  id: string\n}\n```\n\n#### getCurrentSelection = () =>\nReturns an Array of `Selection` objects:\n\n```js\nconst {selection} = await AssistantAPIClient.getCurrentSelection();\n```\n\n#### addSelectionChangedListener = async cb =>\nAdds a callback function to be executed upon a valid workspace selection change.\n\nCallback value is an array of Selection objects:\n\n```js\n// Create the selection callback.\nconst selectionCB = ({selection})=>{\n  console.log('Workspace selection has changed.')\n  selection.forEach(i=>{\n    console.log('Kind: ',i.kindName)\n    console.log('Instance Id:',i.id)\n    console.log('Kind Id:',i.kindId)\n  })\n}\n\n// Add the listener.\nAssistantAPIClient.addSelectionChangedListener(selectionCB);\n```\n\nThis function only exists on the Q-Assistant-Client--only enableSelectionChangedNotification is called on the API.\n\n#### removeSelectionChangedListener = async cb =>\nThis will have to be called on a 1:1 basis with addSelectionChangedListener calls if supplying a callback.\n\n```js\nAssistantAPIClient.removeSelectionChangedListener(selectionCB)\n```\n\n**If NOT supplying a callback to this call, all selection changed listeners will be removed.\n\n```js\nAssistantAPIClient.removeSelectionChangedListener()\n```\n\nThis function only exists on the Q-Assistant-Client--only disableSelectionChangedNotification is called on the API.\n\n\n### Services\nThe `Service` object:\n```js\n{\n   id: string,\n   name: string\n   endpointUrl: string,\n   getKinds: () => // Returns [] of Kinds objects\n   getFunctions: () => // Returns [] of Function objects\n}\n```\n\n#### getServiceById = id =>\nThis will return a service that exists within the scope of the workspace.\n** Assistant services will return null. Services outside the scope of the workspace will cause an error to be returned as 'Unable to load a Service from outside of the workspace.'\n\n```js\nconst svc = await AssistantAPIClient.getServiceById(id)\n```\n\n#### createService = id =>\nCreates a service in Q.\n\nNote: This will create the service, but does NOT import it into the workspace.\nYou will need to use `importService` on the Workspace object to import it.\nReturns a promise that resolves\n\n```js\n    const service = {\n      id: ...,\n      name: ...,\n      endpointUrl: ...,\n      serviceType: ...\n    }\n\n    await AssistantAPIClient.createService(service)\n```\n\n#### deleteService = id =>\nDeletes a service from Q.\n\n```js\n    await AssistantAPIClient.deleteService(id)\n```\n\n#### refreshServiceSchema = id =>\nRefreshes a service by fetching its schema. This will also\nreload the service inventory in the currently visible workspace.\n\n```js\nawait AssistantAPIClient.refreshServiceSchema(\"id\")\n```\n\n#### reloadService = id =>\nReloads a service in the inventory in the currently visible workspace.\n\n```js\nawait AssistantAPIClient.reloadService(\"id\")\n```\n\n### Workspace\n\n#### getWorkspace = () =>\nReturns a Workspace object representing the workspace.\n\n```js\nconst ws = await AssistantAPIClient.getWorkspace(id)\n```\n\nNote: The `id` parameter is optional. If it is not supplied, the query\nwill return the current/visible workspace.\n\nThe `Workspace` object:\n\n```js\n\n{\n    id: string,\n    name: string,\n    endpointUrl: string,\n    workspaceServiceId: string,\n    modelServiceId: string,\n    logicServiceId: string,\n\n    //\n    // Locking information\n    //\n    async lockedBy() {\n      // Returns the e-mail address of the user who locked the Workspace, or\n      // null if the Workspace is not currently locked.\n    }\n    async canEdit() {\n      // Returns `true` when the Workspace is not locked, or the current user\n      // owns the lock.\n      // Returns 'false' when the Workspace is locked by a different user.\n    }\n    async setLocked(isLocked) {\n      // Takes a boolean or undefined for `isLocked`.\n      //  `true` locks the Workspace as the current User.\n      //  `false` unlocks the Workspace\n      //  `undefined` causes it to toggle the current locked state.\n      // Returns a Promise that will resolve or reject when the task is done.\n    }\n\n    //\n    // Knowledge Graphs\n    //\n    getActiveGraph: async () => {\n      // Returns the active Graph object.\n      // Returns null if active graph is not of type 'Knowledge Graph', or if an\n      // active graph is deleted, thereby setting active graph to null.\n    },\n    getKnowledgeGraphs: async () => {\n      // Returns [Graph]\n    },\n    // TODO: define input\n    createKnowledgeGraph: input =>\n    // TODO: define input\n    createKnowledgeGraphs: input =>\n\n    //\n    // Services\n    //\n    getImportedServices: async () => {\n      // Returns an array of Service objects that have\n      // been imported into the workspace.\n      // No assistant services will be returned.\n    },\n    getImportedAssistants: async () => {\n      // Returns a list of imported assistants.\n    },\n    importService: serviceId => {\n      // Imports a service by it's ID.\n    },\n    importServices: serviceIds => {\n      // Imports services by their IDs.\n    },\n    removeServices: serviceIds => {\n      // Removes a list of services from the workspace.\n    },\n    removeService: serviceId => {\n      // Removes a service from the workspace.\n    },\n\n    //\n    // Functions\n    //\n    getFunctions: async () => {\n      // Returns an array of functions in the workspace (includes boilerplate).\n    },\n    createFunction: funcData => {\n      // Creates a function and adds it to the graph.\n    }\n    createFunctions: funcData =>{\n      // Creates several functions and adds them to the graph.\n    }\n    updateFunction: funcData => {\n      // Updates a function.\n    },\n    updateFunctions: funcData =>{\n      // Updates functions based on input array.\n    },\n    deleteFunction: funcId => {\n      // Deletes a function by its ID.\n    },\n    getFunctionGraph: funcId => {\n      // Returns a function graph by its ID.\n    }\n\n    //\n    // Kinds\n    //\n    getKinds: async () => {\n      // Returns an array of functions in the workspace (includes boilerplate).\n    },\n    createKind: kindData => {\n      // Currently same input as AssistantAPIClient call.\n    },\n    createKinds: kindData => {\n      // Currently same input as AssistantAPIClient call.\n    },\n    updateKind: kindData => {\n      // Currently same input as AssistantAPIClient call.\n    },\n    updateKinds: kindData => {\n      // Currently same input as AssistantAPIClient call.\n    },\n    deleteKind: kindId => {\n      // Currently same input as AssistantAPIClient call.\n    }\n    // Event Triggers\n    triggerRepairEvent: () => {\n      // Triggers the repair event on a workspace.\n    }\n  };\n}\n```\n\n\n### Graphs\nThe `Graph` object:\n```js\n{\n  id: string,\n  name: string,\n  offsetX: Number,\n  offsetY: Number,\n  zoom: Number,\n  getNodes: async () => {\n      // Returns [Node]\n  },\n\n  addNode: async (type, instance, changeSelection) => {\n      // Returns Node\n  },\n  removeNode: async id => {\n      // Should return nothing or error.\n      // Currently returning [] in all cases.\n  },\n  updateNodeLayout: async (nodeId, { x, y, collapsed }) => {\n  },\n  updateGraphLayout: async ({ offsetX, offsetY, zoom }) => {\n  }\n\n  //\n  // Locking information\n  //\n  async lockedBy() {\n    // Returns the e-mail address of the user who locked the Graph, or null if\n    // the Graph is not currently locked.\n  }\n  async canEdit() {\n    // Returns `true` when the Graph is not locked, or the current user owns the\n    // lock.\n    // Returns 'false' when the Graph is locked by a different user.\n  }\n  async setLocked(isLocked) {\n    // Takes a boolean or undefined for `isLocked`.\n    //  `true` locks the Graph as the current User.\n    //  `false` unlocks the Graph\n    //  `undefined` causes it to toggle the current locked state.\n    // Returns a Promise that will resolve or reject when the task is done.\n  }\n}\n```\n\n#### Getting a graph object:\nGraph objects are obtained through an instance of a Workspace\n\n```js\nconst ag = await ws.getActiveGraph()\n```\n\nor\n\n```js\nconst kgs = await ws.getKnowledgeGraphs()\n```\n\n#### Manipulating Graphs\n\n**Only the active graph may be manipulated.\n\nAll graph manipulations should be ‘visually’ verifiable on the graph itself, i.e., adds/removes/positioning, should all be reflected on the graph itself.\n\nThe `Node` object:\n```js\n{\nid: string\nx: number\ny: number\ncollapsed: boolean\nknowledgeGraphNode {\n  id: string\n  innerKind: Kind\n  innerFunction: Function\n}\n}\n```\n\n#### addNode(type, instance, changeSelection) =>\n\nTakes type (“Function” or “Kind”), instance (the Function or Kind object), and optionally a boolean to indicate whether the selection should be changed to this new node.\n\nReturns the newly created Node object.\n\n```js\nconst node = await ag.addNode('Kind',kind)\n```\n\n#### removeNode(id) =>\n\nTakes the id of Node to be deleted. Returns either undefined or an error.\n\n```js\nawait ag.removeNode(node.id)\n```\n\n#### getNodes() =>\nReturns an array of Node objects from the graph.\n\n```js\nconst nodes = await ag.getNodes()\n```\n\n#### updateNodeLayout: async (nodeId, { x, y, collapsed})=>\nUpdates a Node layout given a node ID and node coordinates (`x` and/or `y`) or a `collapsed` value. x/y values must be a number, and collapsed must be a boolean. Whatever is not specified will remain current.\n\n```js\nag.updateNodeLayout(id,{x:100,y:100,collapsed:true})\n```\n\n#### updateGraphLayout: async ({ offsetX, offsetY, zoom})=>\nUpdates a Graph layout given numerical values for x/y offsets and the zoom.\n\n```js\nag.updateGraphLayout({offsetX:50, offsetY:50, zoom: 70})\n```\n\n### Functions\n\nThe `Function` object:\n```js\n{\n    id: string\n    name: string\n    service {\n      id: string\n      name: string\n    }\n    arguments {\n      id: string\n      name: string\n      type: string\n      modifiers: Array[string]\n      typeKindId:: string\n      kind {\n        id: string\n        name: string\n      }\n    }\n    implementation {\n      id: string\n      entrypoint {\n        id: string\n      }\n      operations {\n        id: string\n        type: string\n        function {\n          id: string\n          name: string\n        }\n        argumentValues {\n          id: string\n          argument {\n            id: string\n          }\n          operation {\n            id: string\n          }\n          argumentRef: string\n        }\n      }\n    }\n    isGenerated: boolean\n    functionType: string\n    graphqlOperationType: string\n    outputType: string\n    outputKindId: string\n    outputModifiers: Array[string]\n    kind {\n      id: string\n      name: string\n    }\n\n    //\n    // Locking information\n    //\n    async lockedBy() {\n      // Returns the e-mail address of the user who locked the Function, or null\n      // if the Function is not currently locked.\n    }\n    async canEdit() {\n      // Returns `true` when the Function is not locked, or the current user\n      // owns the lock.\n      // Returns 'false' when the Function is locked by a different user.\n    }\n    async setLocked(isLocked) {\n      // Takes a boolean or undefined for `isLocked`.\n      //  `true` locks the Function as the current User.\n      //  `false` unlocks the Function\n      //  `undefined` causes it to toggle the current locked state.\n      // Returns a Promise that will resolve or reject when the task is done.\n    }\n}\n```\n\n`FunctionExecutionResult` object:\n```js\n{\n  id: string,\n  result: JSON\n}\n```\n\n#### executeFunction = ( {id, variables, resolve} ) =>\nExecutes a function based on its id, with optional inputs for variables and a resolve string (this specifies the fields to be returned, which must be valid based on the result).\n\nReturns : JSON matching shape of result , unless no sub-selection of fields is required in the execution.\n\nThis following piece of code will execute a Function given a function ID, and pass in variables for ‘example’, requesting back id and name fields.\n\n```js\nconst res = await AssistantAPIClient.executeFunction({functionId: func.id, variables: {\"variableName\": \"variableValue\"}, resolve: \"{ id name }\");\n```\n\n#### createFunction = input =>\nCreates a function based on the input provided.\n\nReturns: the created Function object.\n\n**Using create function will only place the function in the workspace’s inventory--it will not place the function as a node on the Graph. In order to do this, you must pass the created function into the addNode function on the active Graph, making sure to specify ‘Function' as the type.\n\n```js\nconst createFunctionInput = {\n  name:\"yourName\",\n  arguments:[],\n  outputType: \"STRING\",\n  graphqlOperationType:\"QUERY\",\n  functionType: \"CKG\"\n}\n\nconst createdFunction = await AssistantAPIClient.createFunction(createFunctionInput)\n```\n\n#### updateFunction = input =>\nInput is the same for creating a function. It’s important to note that the arguments property will be replaced in it’s entirety with whatever is provided (if a value is provided.\n\nReturns the updated `Function` object.\n\n```js\nconst updatedFunction = await AssistantAPIClient.updateFunction(input);\n```\n\n#### deleteFunction = input =>\nInput is the id of the Function to be deleted. Returns the deleted function as a promise.\n\n```js\nconst deletedFunction = await AssistantAPIClient.deleteFunction('id...');\n```\n\n#### getFunctionById = id =>\nReturns a Function as a promise based on the ID provided.\n\n```js\nconst func = await AssistantAPIClient.getFunctionById('id...');\n```\n\n#### addFunctionExecutionListener = async (id, cb) =>\nAssociates a callback function with the execution of a particular Function. When the Function matching the id parameter is executed, its FunctionExecutionResult object passed to the callback. Returns undefined.\n\nExample function execution callback and listener registration:\n\n```js\nfunction exampleFunctionCB (result){\n  console.log(`Function executed with result:`, result)\n}\n\nAssistantAPIClient.addFunctionExecutionListener('id...', exampleFunctionCB)\n```\n\n#### removeFunctionExecutionListener = async (id, cb) =>\nRemoves a Function execution listener based on the function ID and a reference to the callback function. If no callback is supplied, all listeners associated with the Function ID will be removed. Returns undefined.\n\n```js\nAssistantAPIClient.removeFunctionExecutionListener('id..', exampleFunctionCB)\n```\n\n### Kinds\nThe `Kind` object:\n```js\n{\n    id: string\n    name: string\n    service: {\n      id\n      name\n    }\n    isGenerated: boolean\n    schema {\n      id: string\n      name: string\n      type: string\n      typeKindId: string\n      modifiers: Array[string]\n      kind {\n        id: string\n        name: string\n      }\n    }\n}\n```\n\n#### createKind = input =>\nCreates a Kind based on an input object. Returns a promise that resolves to the created Kind object.\n\n```js\nconst kindInput = {\n name: \"someKind\",\n schema:[\n  { name: \"someField1\", type: STRING },\n  { name: \"someField2\", type: STRING }\n ]\n}\n\nconst newKind = await AssistantAPIClient.createKind(kindInput)\n```\n\n#### createKinds = input =>\nA plural version of `createKind` accepting an array of input objects.\nReturns a promise that resolves to an array of created Kind objects.\n\n```js\nconst kindsInput = [{\n name: \"someKind\",\n schema:[\n  { name: \"someField1\", type: STRING },\n  { name: \"someField2\", type: STRING }\n ]\n}, ...]\n\nconst newKinds = await AssistantAPIClient.createKinds(kindsInput)\n```\n\n\n#### updateKind = input =>\nUpdates a Kind based on an input object.\n\nUpdate Semantics: Only properties specified will be updated. If updating the schema, the entire schema must be specified as it will be replaced in its entirety.\n\nReturns a promise that resolves to the updated `Kind` object.\n\n```js\nconst updated = await AssistantAPIClient.updateKind(input)\n```\n\n#### deleteKind = input =>\nDeletes a Kind given a kind ID.\n\n```js\nconst deleted = await AssistantAPIClient.deleteKind(input)\n```\n\n#### getKindById = id =>\nReturns a promise that resolves to a Kind object given the specified kind ID.\n\nIn v3.2.2, any requested non-system kinds will be returned.\nIn v3.2.1, only kinds in the workspace or those of imported services will be returned.\n\n```js\nconst kind = await AssistantAPIClient.getKindById(id)\n```\n\n#### getKindsById = ids =>\nReturns a promise that resolves to an array of Kind objects given an array of kind IDs. Only kinds in the workspace or those of imported services will be returned.\n\n```js\nconst ids = [\"...\",\"...\",...]\nconst kind = await AssistantAPIClient.getKindsById(ids)\n```\n\n#### getAllReferencedKinds = input =>\nRecursively collects all kinds that are referenced in a kind's schema, starting\nwith a kind ID. For example if the ID of kind A is supplied as an input, and Kind `A` contains a field of type Kind `B`, and `B` contains a field of type Kind `C`,\nan array containing the kinds objects for `A`, `B`, `C` will be returned (as a promise).\n\n```js\nconst initialId = [\"...\"]\nconst kinds = await AssistantAPIClient.getAllReferencedKinds({\n          ids: initialId\n        })\n```\n\n\n### Inventory\n\nThe `InventoryChanged` object:\n```js\n{\n  kinds: {\n    adds: [DiffItem]\n    deletes: [DiffItem]\n    updates: [DiffItem]\n  }\n  functions:{\n    adds: [DiffItem]\n    deletes: [DiffItem]\n    updates: [DiffItem]\n  }\n  services: {\n    adds: [DiffItem]\n    deletes: [DiffItem]\n    updates: [DiffItem]\n  }\n}\n```\n\nThe `DiffItem` object:\n```js\n{\n  id: string,\n  name: string\n}\n```\n\n#### addInventoryChangedListener = async cb =>\nRegisters a callback function with the inventory changed event. When workspace inventory changes the callback function will be called with the InventoryChangedobject. Returns undefined.\n\n**Use-case note: an ‘update’ diff for inventory services is unlikely in general usage.\n\n```js\nconst inventoryCB = ({diff}) => {\n  if(diff.kinds) console.log('KINDS CHANGED',diff.kinds)\n  if(diff.functions) console.log('FUNCTIONS CHANGED', diff.functions)\n  if(diff.services) console.log('SERVICES CHANGED',diff.services)\n}\n\nAssistantAPIClient.addInventoryChangedListener(inventoryCB)\n```\n\nThis function exists on the Q-Assisant-Client only--only enableSelectionChangedNotification is used on the API side.\n\n#### removeInventoryChangedListener = async cb =>\nRemoves an inventory changed listener given the referenced callback. If no callback is specified, all listeners will be removed. Returns undefined.\n\n```js\nAssistantAPIClient.removeInventoryChangedListener(inventoryCB)\n```\n\nThis function exists on the Q-Assisant-Client only--only disableSelectionChangedNotification is used on the API side.\n\n#### moveKindsAndFunctions = (originId, targetId, kindIds, functionIds) =>\nMoves a collection of Kinds and Functions from the origin Workspace to the target Workspace.\n\n```js\n  await AssistantAPIClient.moveKindsAndFunctions(\n    originWorkspaceId,\n    targetId,\n    kindIds,\n    functionIds\n  );\n```\n\n### Locking Changed Event\n\nAn event is triggered when the locked state of the currently active Workspace or\nits Knowledge Graphs and Functions change.\n\nThe `LockingChanged` object:\n```js\n{\n  workspaces: [LockItem],\n  knowledgeGraphs: [LockItem],\n  functions: [LockItem]\n}\n```\n\nThe `LockItem` object:\n```js\n{\n  id: string\n  lockedBy: string\n}\n```\n\n#### addLockingChangedListener = cb =>\n\nRegisters a callback function with the locking changed event. When the currently\nactive Workspace or its Knowledge Graphs and Functions change the callback\nfunction will be called with the `LockingChanged` object. Returns undefined.\n\n```js\nconst lockingChangedCB = ({ locks }) => {\n  if(locks.workspace) console.log('WORKSPACES CHANGED', locks.workspace);\n  if(locks.knowledgeGraphs) console.log('KNOWLEDGE GRAPHS CHANGED', locks.knowledgeGraphs);\n  if(locks.functions) console.log('FUNCTIONS CHANGED', locks.functions);\n}\n\nAssistantAPIClient.addLockingChangedListener(lockingChangedCB);\n```\n\n#### removeLockingChangedListener = cb =>\n\nRemoves an locking changed listener given the referenced callback. If no\ncallback is specified, all listeners will be removed. Returns undefined.\n\n```js\nAssistantAPIClient.removeLockingChangedListener(lockingChangedCB)\n```\n\n## Troubleshooting Assistant Issues\n### Assistant root file has loaded, but not other content\nObserving in the browser's dev tools that some resources have loaded correctly (usually the root), but other's haven't (usually nested files or chunks), is indicative of a failure of Q Gateway to proxy due to not having a 'relative' path structure.\n\n### You are seeing post-robot `NO ACK` errors in the console.\nThese errors stem from a failed acknowledgement for a call either between the client and the API or vice-versa. Here, this means that the web app 'window' (the assistant) cannot communicate with, or access, the 'window.parent' (Maana K-Portal) object.\n\nCommonly, these will stem from the 'window' (the assistant) not being loaded or in a loadable state, which means the API will not receive an acknowledgement when it fires an event.\n\nImproper CORS configuration is also a common culprit (also verify if using docker or nginx that your proxying and networking is configured correctly to allow communication and to accout for CORS).","readmeFilename":"README.md","gitHead":"2e4fdef50e14cbf687f5809c0edfef26d67fab56","_id":"@io-maana/q-assistant-client@3.2.4-beta.39","_npmVersion":"6.4.1","_nodeVersion":"10.15.3","_npmUser":{"name":"teamcitymaana","email":"teamcity@maana.io"},"dist":{"integrity":"sha512-1bhPwDPTMzMDQ8vgQfxWlayN1M8l2rHkmFZslTt8YyUWMQWtlopQMSpYVl8iaHmEtAAjXEcjp33GrYlRRYEBdw==","shasum":"a36b0bab92a4320eed341505c6abae0dc4937724","tarball":"https://registry.npmjs.org/@io-maana/q-assistant-client/-/q-assistant-client-3.2.4-beta.39.tgz","fileCount":10,"unpackedSize":65161,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJfB5tTCRA9TVsSAnZWagAA3ZIP/2mCcNDs0Q+FCv9xeMRt\nkINuDIwKllyhypxqUkL7oemVNQaCnAS2OangGNWAMDn+B8+ozef0L8AaMLjc\nE6Bu+OuQvn76ZV+Gfw6KTDgSlCYJsBadyI8ZYTiY3rLL5qUdx7TIFHtoOmv4\ndBySfNrhNYRpehVzBNUraCGE9XqP1U7FYfl8enRKD9B3D2DYk7bJVDCzC4BU\nC6zQOtvWNS5dWZD0VkCljITfKoPIoedZswnW7m2byyGT4bg5SeVasi/Yp+7C\nv2CueP2vXl7TTBhfRKETWTFN9OEUWYMiMEmuIH+uCHfFvzYAO8xHZvQR4if3\n2a6LFxFJQ0kuOXV8bOan1Wwc9xLdpviwKpx2o1MksDDf8nXq07cwWqbhr8MA\ndMMIi1DquMtdx8/rYjp+iR4J2x4GS8WL00MXYBnfqVVeYbwMN8IOYz3lBqKk\nnLf06t5az+dgYZV1RGPZy0zoqK8C8PIjE8UTJkfYv6E9Dzxv5qFDHwRjMD7A\nF56n7yeAgsFEGJYz4hv8zzUI6XT1WHoEpu1jY7R5ip/n1MuS1PylCL6oojhY\nH73yG2LISEEVoZYL8PzWQ0SsmaSNAhM3HBY8AP6QvPXD/4POqmRy0orwNYFI\nYb+xa/FrG5ugovyLXq+os98PiXz9/TNfjT81Ac7FNrpCBk53wMEWsFCarIAd\nnSAi\r\n=1Jdu\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEQCIHmyjxJcv1eJ663Q8DTa1CoXdWUiWcCqOn7SEJmNBvmRAiAxwBammSRhIlYMUwHTmETFwOf3eapcweSjD8G0vBVf3w=="}]},"maintainers":[{"email":"andrey@maana.io","name":"abatyuk"},{"email":"bzvestey@gmail.com","name":"bzvetey"},{"email":"dlewissandy@maana.io","name":"dlsmaana"},{"email":"rob@maana.io","name":"rpovey"},{"email":"teamcity@maana.io","name":"teamcitymaana"},{"email":"witt3rd@witt3rd.com","name":"witt3rd"}],"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/q-assistant-client_3.2.4-beta.39_1594334034650_0.9531484021695158"},"_hasShrinkwrap":false},"3.3.0-beta.2":{"name":"@io-maana/q-assistant-client","version":"3.3.0-beta.2","description":"JavaScript package to streamline communication between an assistant and the Maana Q Assistant API.","main":"build/index.js","types":"build/index.d.ts","exports":{"./":"./build/"},"scripts":{"build":"npm run build:js && npm run build:tsd","build:js":"babel src --out-dir build","build:tsd":"tsc --build tsconfig.json","prepack":"npm run build","test":"echo \"Error: no test specified\" && exit 1","format":"prettier --write \"src/**/*.js\""},"repository":{"type":"git","url":"git+https://github.com/maana-io/q-assistant-client.git"},"keywords":["Maana","Q"],"author":{"name":"Logan Gore @ Maana.io"},"license":"MIT","bugs":{"url":"https://github.com/maana-io/q-assistant-client/issues"},"homepage":"https://github.com/maana-io/q-assistant-client#readme","dependencies":{"core-js":"3.6.4","post-robot":"10.0.29"},"devDependencies":{"@babel/cli":"^7.10.1","@babel/core":"^7.10.2","@babel/plugin-proposal-class-properties":"^7.10.1","@babel/preset-env":"^7.10.2","prettier":"2.0.5","typescript":"^3.9.5"},"readme":"# q-assistant-client\nA lightweight JavaScript client for Maana-Q Assistant developers that wraps post-message communication between an embedded Maana-Q assistant and the Maana-Q UI.\n\n## Abstract\nThe Q-Assistant-Client is intented to be used in a web application being leveraged as a Maana Q assistant (embedded as an iframe).\nThis assistant client will facilitate communication between the assistant and the parent frame.\nThe client provides a rich, asynchronous experience over what would otherwise be 'fire-and-forget'-style messaging\nvia post-post message communication.\n\n## Requirements and Assumptions\n\n### Post-Robot Library\nThe Maana Knowledge Portal (KPortal) uses the kraken/post-robot library [kraken/post-robot](https://github.com/krakenjs/post-robot) to enrich the communication with the assistant. Post-robot allows for asynchronous, promise-based request/response style behavior between the assistant and the assistant API.\n\nThe API requires that the client use the post-robot library. This assistant-client library is the easiest way to achieve this, and also adds a fair amount of 'sugar' to the process to improve developer productivity. Developers could, however, use post-robot directly in their own client implementation.\n\n### Maana-Gateway Proxy Requirements\nThe Maana-Gateway service requires relative paths (paths relative to the root) in the assistant web application in order to proxy the application and its content. For create-react-apps, for instance, this means setting \"homepage\" to \".\" in the package.json file.\n\n## Singleton Instance\nThe client is exported as a singleton to avoid duplicate registration on event listeners.\nYou can import the instance like this:\n\n```js\nimport AssistantAPIClient from '@io-maana/q-assistant-client';\n```\n\nFunction calls can be made against the client instance like any other javascript object. They are all async.\n\n```js\nconst workspace = await AssistantAPIClient.getWorkspace();\nconsole.log(\"Workspace:\", workspace)\n```\n\n## Dependencies\nPost-Robot\nhttps://github.com/krakenjs/post-robot\n\nPost-robot is used to provide a richer communication layer atop post-message.\n\n## Versioning\nThe Maana Q Assistant Client does not follow semantic versioning. Its versions\ntrack the releases of the Maana Q platform.\n\n## Examples\n@TODO Logan\n\n\n## Changes in v3.2.2\nImprovements in v3.2.2\n- Assistant State Management: WORKING, IDLE\n- Background Messaging/Eventing\n- Render Modes: BACKGROUND, DISPLAY\n- Expansion of Workspace object capabilities\n- Error Reporting\n- Repair Event\n- Plural versions of calls such as updateKind(s) to improve performance and developer experience.\n- InventoryChanged diffing is fully granular in v3.2.2--limitations\nin v3.2.1 only fired the Function diff for changes in Function name.\n\n### Deprecation\nThe following surface area IS removed from the\nclient in v3.2.2, and IS deprecated in the API:\n- AssistantAPIClient.enableSelectionChangedNotification\n- AssistantAPIClient.disableSelectionChangedNotification\n- AssistantAPIClient.enableInventoryChangedNotification\n- AssistantAPIClient.disableInventoryChangedNotification\n\nThe following surface area WILL BE removed from\nthe client in v3.2.4, and WILL BE deprecated in the API:\n- AssistantAPIClient.updateFunction (expected move to Workspace object)\n- AssistantAPIClient.updateKind (expected move to Workspace object)\n- AssistantAPIClient.deleteKind (expected move to Workspace object)\n- AssistantAPIClient.deleteFunction (expected move to Workspace object)\n\n## API Documentation\n\n### Assistant Render Mode\nAn assistant's render mode refers to whether it is being displayed in a visible manner to the user. As of v3.2.2, assistants are not closed when they are out of view.\nAll assistants will be loaded and kept in `BACKGROUND` render mode until they are\nplaced in the assistant panel, at which point the `DISPLAY` render mode event will be fired.\n\nNote: Assistants will receive all notifications/events while in BACKGROUND mode.\n\nDesign Consideration: It will be up to the developer to determine how state and resource use will be managed while an assistant is operating between BACKGROUND and DISPLAY modes.\n\n#### addRenderModeChangedListener = (cb) =>\nA listener to receive push events as to the assitant's render mode being changed.\n\n```js\nfunction handleRenderModeChanged(renderMode){\n  if (renderMode === 'DISPLAY'){\n    // Assistant is visible\n  } else {\n    // Assistant is not visible and running in background.\n  }\n}\n\nAssistantAPIClient.addRenderModeChangedListener(handleRenderModeChanged)\n\n```\n\n#### removeRenderModeChangedListener = (cb) =>\nRemoves the renderModeChanged listener by reference, or if no callback function reference is provided, it removes all listeners.\n\n#### getRenderMode = () =>\nReturns the current assistant render mode.\n\n```js\nconst renderMode = await AssistantAPIClient.getRenderMode()\n\nif (renderMode === 'DISPLAY'){\n  // Assistant is visible\n} else {\n  // Assistant is not visible and running in background.\n}\n\n```\n\n### Repair\nAssistants may get into situations where they are either out of sync with the Maana Q UI, or in a failure state. Assistants should be able to recover from these states.\n\nThe repair event functionality added in v3.2.2 is designed to notify the assistant that it must repair itself. This could mean a resync with its resources on the workspace or externally or, for some assistants, nothing at all.\n\nWhen is repair triggered?\nEither manually by a user clicking 'repair workspace' under the\nassistant inventory panel, or upon a workspace clone event. An assistant will be expected to handle either scenario.\n\nPerformance Consideration:\nFor some assistants, repair might involve 'introspecting'\nand processing the current workspace or Q system resources. This could be very resource intensive. Make sure you review this API guide to have an idea of what tools are\navailable to get the best results. It's always a good idea to check performance of repair on a large workspace and ensure necessary optimizations have been made.\n\nDesign Consideration:\nMake your workflows modular enough to be reused between repair and normal usage if possible.\n\n#### addRepairListener (cb) =>\n```js\n\nAssistantAPIClient.addRepairListener(()=>{\n  // Self-heal\n})\n\n```\n\nRecommended Usage: A repair process should be wrapped in the try/catch/finally flow shown in the `setAssistantState` API call to provide the user assistant-state and error updates as well as pause `inventoryChanged` notifications during repair (if the assistant has subscribed).\n\n#### removeRepairListener = (cb) =>\nRemoves the repair listener by reference, or if no callback function reference is provided, it removes all listeners.\n\n### User-facing Error Handling\n\n#### reportError (error) =>\nReports an error to the UI to be displayed in the assistant's error log in the\ninventory panel. This call is not disruptive and designed to operated independently of other assistant operations, such as state management. See `setAssistantState` in the next section.\n\nRecommended usage: use this functionality where it would futher the user experience\nto show the user an error and it's cause. Do not use this where things will be retried,\ncleaned up automatically, or are not relevant to the user.\n\n```js\ntry{\n  // Do work\n} catch(e) {\n  AssistantAPIClient.reportError(e)\n}\n```\n\n### State management\n\n#### clearState = () =>\nThis will remove all callbacks from all listeners.\n\n```js\nawait AssistantAPIClient.clearState()\n```\n\n#### setAssistantState = (state) =>\nThis sets the current state of the assistant using the\n`AssistantState` enum. Setting a state of `WORKING` will\ncreate the 'working' status spinner in the Assistant\nInventory Panel in the Maana Q UI. Conversely, setting an `IDLE` state will\nremove the spinner. This adds to user experience by informing users of the\nstatus of operations.\n\n```js\nimport {\n  default as AssistantAPIClient,\n  AssistantState\n} from '@io-maana/q-assistant-client'\n\n...\n\nAssistantAPIClient.setAssistantState(AssistantState.WORKING)\n\n...\n\nAssistantAPIClient.setAssistantState(AssistantState.IDLE)\n\n```\nUI User Prompt: If the assistant is in a `WORKING` state, the Maana Q UI will\nwarn the user before leaving the workspace.\n\nNOTE: while an assistant is in a working state, it will\nnot receive `inventoryChanged` events--an aggregated inventory diff\nwill be sent once the assistant is set back to `IDLE`.\n\nRecommended usage: Control states at a high level using try/catch/finally\nflow incorporating the `reportError` API call.\n\n```js\ntry{\n  AssistantAPIClient.setAssistantState(AssistantState.WORKING)\n  // Do work, await high-level tasks, etc.\n} catch(e) {\n  AssistantAPIClient.reportError(e)\n} finally{\n  AssistantAPIClient.setAssistantState(AssistantState.IDLE)\n}\n```\n\n#### AssistantState (enum)\nContains the valid assistant states: `IDLE` or `WORKING`.\n\nMust be imported in addition to the AssistantAPIClient:\n\n```js\nimport {\n  default as AssistantAPIClient,\n  AssistantState\n} from '@io-maana/q-assistant-client'\n```\n\n\n### User Info\nThe `UserInfo` object:\n```js\n{\n email: string,\n name: string\n}\n```\n\n#### getUserInfo = () =>\nReturns a Userinfo object pertaining to the logged in user.\n\n```js\nconst userInfo = await AssistantAPIClient.getUserInfo()\n```\n### Selection\nThe `Selection` object:\n```js\n{\n  kindId: string\n  kindName: string\n  id: string\n}\n```\n\n#### getCurrentSelection = () =>\nReturns an Array of `Selection` objects:\n\n```js\nconst {selection} = await AssistantAPIClient.getCurrentSelection();\n```\n\n#### addSelectionChangedListener = async cb =>\nAdds a callback function to be executed upon a valid workspace selection change.\n\nCallback value is an array of Selection objects:\n\n```js\n// Create the selection callback.\nconst selectionCB = ({selection})=>{\n  console.log('Workspace selection has changed.')\n  selection.forEach(i=>{\n    console.log('Kind: ',i.kindName)\n    console.log('Instance Id:',i.id)\n    console.log('Kind Id:',i.kindId)\n  })\n}\n\n// Add the listener.\nAssistantAPIClient.addSelectionChangedListener(selectionCB);\n```\n\nThis function only exists on the Q-Assistant-Client--only enableSelectionChangedNotification is called on the API.\n\n#### removeSelectionChangedListener = async cb =>\nThis will have to be called on a 1:1 basis with addSelectionChangedListener calls if supplying a callback.\n\n```js\nAssistantAPIClient.removeSelectionChangedListener(selectionCB)\n```\n\n**If NOT supplying a callback to this call, all selection changed listeners will be removed.\n\n```js\nAssistantAPIClient.removeSelectionChangedListener()\n```\n\nThis function only exists on the Q-Assistant-Client--only disableSelectionChangedNotification is called on the API.\n\n\n### Services\nThe `Service` object:\n```js\n{\n   id: string,\n   name: string\n   endpointUrl: string,\n   getKinds: () => // Returns [] of Kinds objects\n   getFunctions: () => // Returns [] of Function objects\n}\n```\n\n#### getServiceById = id =>\nThis will return a service that exists within the scope of the workspace.\n** Assistant services will return null. Services outside the scope of the workspace will cause an error to be returned as 'Unable to load a Service from outside of the workspace.'\n\n```js\nconst svc = await AssistantAPIClient.getServiceById(id)\n```\n\n#### createService = id =>\nCreates a service in Q.\n\nNote: This will create the service, but does NOT import it into the workspace.\nYou will need to use `importService` on the Workspace object to import it.\nReturns a promise that resolves\n\n```js\n    const service = {\n      id: ...,\n      name: ...,\n      endpointUrl: ...,\n      serviceType: ...\n    }\n\n    await AssistantAPIClient.createService(service)\n```\n\n#### deleteService = id =>\nDeletes a service from Q.\n\n```js\n    await AssistantAPIClient.deleteService(id)\n```\n\n#### refreshServiceSchema = id =>\nRefreshes a service by fetching its schema. This will also\nreload the service inventory in the currently visible workspace.\n\n```js\nawait AssistantAPIClient.refreshServiceSchema(\"id\")\n```\n\n#### reloadService = id =>\nReloads a service in the inventory in the currently visible workspace.\n\n```js\nawait AssistantAPIClient.reloadService(\"id\")\n```\n\n### Workspace\n\n#### getWorkspace = () =>\nReturns a Workspace object representing the workspace.\n\n```js\nconst ws = await AssistantAPIClient.getWorkspace(id)\n```\n\nNote: The `id` parameter is optional. If it is not supplied, the query\nwill return the current/visible workspace.\n\nThe `Workspace` object:\n\n```js\n\n{\n    id: string,\n    name: string,\n    endpointUrl: string,\n    workspaceServiceId: string,\n    modelServiceId: string,\n    logicServiceId: string,\n\n    //\n    // Locking information\n    //\n    async lockedBy() {\n      // Returns the e-mail address of the user who locked the Workspace, or\n      // null if the Workspace is not currently locked.\n    }\n    async canEdit() {\n      // Returns `true` when the Workspace is not locked, or the current user\n      // owns the lock.\n      // Returns 'false' when the Workspace is locked by a different user.\n    }\n    async setLocked(isLocked) {\n      // Takes a boolean or undefined for `isLocked`.\n      //  `true` locks the Workspace as the current User.\n      //  `false` unlocks the Workspace\n      //  `undefined` causes it to toggle the current locked state.\n      // Returns a Promise that will resolve or reject when the task is done.\n    }\n\n    //\n    // Knowledge Graphs\n    //\n    getActiveGraph: async () => {\n      // Returns the active Graph object.\n      // Returns null if active graph is not of type 'Knowledge Graph', or if an\n      // active graph is deleted, thereby setting active graph to null.\n    },\n    getKnowledgeGraphs: async () => {\n      // Returns [Graph]\n    },\n    // TODO: define input\n    createKnowledgeGraph: input =>\n    // TODO: define input\n    createKnowledgeGraphs: input =>\n\n    //\n    // Services\n    //\n    getImportedServices: async () => {\n      // Returns an array of Service objects that have\n      // been imported into the workspace.\n      // No assistant services will be returned.\n    },\n    getImportedAssistants: async () => {\n      // Returns a list of imported assistants.\n    },\n    importService: serviceId => {\n      // Imports a service by it's ID.\n    },\n    importServices: serviceIds => {\n      // Imports services by their IDs.\n    },\n    removeServices: serviceIds => {\n      // Removes a list of services from the workspace.\n    },\n    removeService: serviceId => {\n      // Removes a service from the workspace.\n    },\n\n    //\n    // Functions\n    //\n    getFunctions: async () => {\n      // Returns an array of functions in the workspace (includes boilerplate).\n    },\n    createFunction: funcData => {\n      // Creates a function and adds it to the graph.\n    }\n    createFunctions: funcData =>{\n      // Creates several functions and adds them to the graph.\n    }\n    updateFunction: funcData => {\n      // Updates a function.\n    },\n    updateFunctions: funcData =>{\n      // Updates functions based on input array.\n    },\n    deleteFunction: funcId => {\n      // Deletes a function by its ID.\n    },\n    getFunctionGraph: funcId => {\n      // Returns a function graph by its ID.\n    }\n\n    //\n    // Kinds\n    //\n    getKinds: async () => {\n      // Returns an array of functions in the workspace (includes boilerplate).\n    },\n    createKind: kindData => {\n      // Currently same input as AssistantAPIClient call.\n    },\n    createKinds: kindData => {\n      // Currently same input as AssistantAPIClient call.\n    },\n    updateKind: kindData => {\n      // Currently same input as AssistantAPIClient call.\n    },\n    updateKinds: kindData => {\n      // Currently same input as AssistantAPIClient call.\n    },\n    deleteKind: kindId => {\n      // Currently same input as AssistantAPIClient call.\n    }\n    // Event Triggers\n    triggerRepairEvent: () => {\n      // Triggers the repair event on a workspace.\n    }\n  };\n}\n```\n\n\n### Graphs\nThe `Graph` object:\n```js\n{\n  id: string,\n  name: string,\n  offsetX: Number,\n  offsetY: Number,\n  zoom: Number,\n  getNodes: async () => {\n      // Returns [Node]\n  },\n\n  addNode: async (type, instance, changeSelection) => {\n      // Returns Node\n  },\n  removeNode: async id => {\n      // Should return nothing or error.\n      // Currently returning [] in all cases.\n  },\n  updateNodeLayout: async (nodeId, { x, y, collapsed }) => {\n  },\n  updateGraphLayout: async ({ offsetX, offsetY, zoom }) => {\n  }\n\n  //\n  // Locking information\n  //\n  async lockedBy() {\n    // Returns the e-mail address of the user who locked the Graph, or null if\n    // the Graph is not currently locked.\n  }\n  async canEdit() {\n    // Returns `true` when the Graph is not locked, or the current user owns the\n    // lock.\n    // Returns 'false' when the Graph is locked by a different user.\n  }\n  async setLocked(isLocked) {\n    // Takes a boolean or undefined for `isLocked`.\n    //  `true` locks the Graph as the current User.\n    //  `false` unlocks the Graph\n    //  `undefined` causes it to toggle the current locked state.\n    // Returns a Promise that will resolve or reject when the task is done.\n  }\n}\n```\n\n#### Getting a graph object:\nGraph objects are obtained through an instance of a Workspace\n\n```js\nconst ag = await ws.getActiveGraph()\n```\n\nor\n\n```js\nconst kgs = await ws.getKnowledgeGraphs()\n```\n\n#### Manipulating Graphs\n\n**Only the active graph may be manipulated.\n\nAll graph manipulations should be ‘visually’ verifiable on the graph itself, i.e., adds/removes/positioning, should all be reflected on the graph itself.\n\nThe `Node` object:\n```js\n{\nid: string\nx: number\ny: number\ncollapsed: boolean\nknowledgeGraphNode {\n  id: string\n  innerKind: Kind\n  innerFunction: Function\n}\n}\n```\n\n#### addNode(type, instance, changeSelection) =>\n\nTakes type (“Function” or “Kind”), instance (the Function or Kind object), and optionally a boolean to indicate whether the selection should be changed to this new node.\n\nReturns the newly created Node object.\n\n```js\nconst node = await ag.addNode('Kind',kind)\n```\n\n#### removeNode(id) =>\n\nTakes the id of Node to be deleted. Returns either undefined or an error.\n\n```js\nawait ag.removeNode(node.id)\n```\n\n#### getNodes() =>\nReturns an array of Node objects from the graph.\n\n```js\nconst nodes = await ag.getNodes()\n```\n\n#### updateNodeLayout: async (nodeId, { x, y, collapsed})=>\nUpdates a Node layout given a node ID and node coordinates (`x` and/or `y`) or a `collapsed` value. x/y values must be a number, and collapsed must be a boolean. Whatever is not specified will remain current.\n\n```js\nag.updateNodeLayout(id,{x:100,y:100,collapsed:true})\n```\n\n#### updateGraphLayout: async ({ offsetX, offsetY, zoom})=>\nUpdates a Graph layout given numerical values for x/y offsets and the zoom.\n\n```js\nag.updateGraphLayout({offsetX:50, offsetY:50, zoom: 70})\n```\n\n### Functions\n\nThe `Function` object:\n```js\n{\n    id: string\n    name: string\n    service {\n      id: string\n      name: string\n    }\n    arguments {\n      id: string\n      name: string\n      type: string\n      modifiers: Array[string]\n      typeKindId:: string\n      kind {\n        id: string\n        name: string\n      }\n    }\n    implementation {\n      id: string\n      entrypoint {\n        id: string\n      }\n      operations {\n        id: string\n        type: string\n        function {\n          id: string\n          name: string\n        }\n        argumentValues {\n          id: string\n          argument {\n            id: string\n          }\n          operation {\n            id: string\n          }\n          argumentRef: string\n        }\n      }\n    }\n    isGenerated: boolean\n    functionType: string\n    graphqlOperationType: string\n    outputType: string\n    outputKindId: string\n    outputModifiers: Array[string]\n    kind {\n      id: string\n      name: string\n    }\n\n    //\n    // Locking information\n    //\n    async lockedBy() {\n      // Returns the e-mail address of the user who locked the Function, or null\n      // if the Function is not currently locked.\n    }\n    async canEdit() {\n      // Returns `true` when the Function is not locked, or the current user\n      // owns the lock.\n      // Returns 'false' when the Function is locked by a different user.\n    }\n    async setLocked(isLocked) {\n      // Takes a boolean or undefined for `isLocked`.\n      //  `true` locks the Function as the current User.\n      //  `false` unlocks the Function\n      //  `undefined` causes it to toggle the current locked state.\n      // Returns a Promise that will resolve or reject when the task is done.\n    }\n}\n```\n\n`FunctionExecutionResult` object:\n```js\n{\n  id: string,\n  result: JSON\n}\n```\n\n#### executeFunction = ( {id, variables, resolve} ) =>\nExecutes a function based on its id, with optional inputs for variables and a resolve string (this specifies the fields to be returned, which must be valid based on the result).\n\nReturns : JSON matching shape of result , unless no sub-selection of fields is required in the execution.\n\nThis following piece of code will execute a Function given a function ID, and pass in variables for ‘example’, requesting back id and name fields.\n\n```js\nconst res = await AssistantAPIClient.executeFunction({functionId: func.id, variables: {\"variableName\": \"variableValue\"}, resolve: \"{ id name }\");\n```\n\n#### createFunction = input =>\nCreates a function based on the input provided.\n\nReturns: the created Function object.\n\n**Using create function will only place the function in the workspace’s inventory--it will not place the function as a node on the Graph. In order to do this, you must pass the created function into the addNode function on the active Graph, making sure to specify ‘Function' as the type.\n\n```js\nconst createFunctionInput = {\n  name:\"yourName\",\n  arguments:[],\n  outputType: \"STRING\",\n  graphqlOperationType:\"QUERY\",\n  functionType: \"CKG\"\n}\n\nconst createdFunction = await AssistantAPIClient.createFunction(createFunctionInput)\n```\n\n#### updateFunction = input =>\nInput is the same for creating a function. It’s important to note that the arguments property will be replaced in it’s entirety with whatever is provided (if a value is provided.\n\nReturns the updated `Function` object.\n\n```js\nconst updatedFunction = await AssistantAPIClient.updateFunction(input);\n```\n\n#### deleteFunction = input =>\nInput is the id of the Function to be deleted. Returns the deleted function as a promise.\n\n```js\nconst deletedFunction = await AssistantAPIClient.deleteFunction('id...');\n```\n\n#### getFunctionById = id =>\nReturns a Function as a promise based on the ID provided.\n\n```js\nconst func = await AssistantAPIClient.getFunctionById('id...');\n```\n\n#### addFunctionExecutionListener = async (id, cb) =>\nAssociates a callback function with the execution of a particular Function. When the Function matching the id parameter is executed, its FunctionExecutionResult object passed to the callback. Returns undefined.\n\nExample function execution callback and listener registration:\n\n```js\nfunction exampleFunctionCB (result){\n  console.log(`Function executed with result:`, result)\n}\n\nAssistantAPIClient.addFunctionExecutionListener('id...', exampleFunctionCB)\n```\n\n#### removeFunctionExecutionListener = async (id, cb) =>\nRemoves a Function execution listener based on the function ID and a reference to the callback function. If no callback is supplied, all listeners associated with the Function ID will be removed. Returns undefined.\n\n```js\nAssistantAPIClient.removeFunctionExecutionListener('id..', exampleFunctionCB)\n```\n\n### Kinds\nThe `Kind` object:\n```js\n{\n    id: string\n    name: string\n    service: {\n      id\n      name\n    }\n    isGenerated: boolean\n    schema {\n      id: string\n      name: string\n      type: string\n      typeKindId: string\n      modifiers: Array[string]\n      kind {\n        id: string\n        name: string\n      }\n    }\n}\n```\n\n#### createKind = input =>\nCreates a Kind based on an input object. Returns a promise that resolves to the created Kind object.\n\n```js\nconst kindInput = {\n name: \"someKind\",\n schema:[\n  { name: \"someField1\", type: STRING },\n  { name: \"someField2\", type: STRING }\n ]\n}\n\nconst newKind = await AssistantAPIClient.createKind(kindInput)\n```\n\n#### createKinds = input =>\nA plural version of `createKind` accepting an array of input objects.\nReturns a promise that resolves to an array of created Kind objects.\n\n```js\nconst kindsInput = [{\n name: \"someKind\",\n schema:[\n  { name: \"someField1\", type: STRING },\n  { name: \"someField2\", type: STRING }\n ]\n}, ...]\n\nconst newKinds = await AssistantAPIClient.createKinds(kindsInput)\n```\n\n\n#### updateKind = input =>\nUpdates a Kind based on an input object.\n\nUpdate Semantics: Only properties specified will be updated. If updating the schema, the entire schema must be specified as it will be replaced in its entirety.\n\nReturns a promise that resolves to the updated `Kind` object.\n\n```js\nconst updated = await AssistantAPIClient.updateKind(input)\n```\n\n#### deleteKind = input =>\nDeletes a Kind given a kind ID.\n\n```js\nconst deleted = await AssistantAPIClient.deleteKind(input)\n```\n\n#### getKindById = id =>\nReturns a promise that resolves to a Kind object given the specified kind ID.\n\nIn v3.2.2, any requested non-system kinds will be returned.\nIn v3.2.1, only kinds in the workspace or those of imported services will be returned.\n\n```js\nconst kind = await AssistantAPIClient.getKindById(id)\n```\n\n#### getKindsById = ids =>\nReturns a promise that resolves to an array of Kind objects given an array of kind IDs. Only kinds in the workspace or those of imported services will be returned.\n\n```js\nconst ids = [\"...\",\"...\",...]\nconst kind = await AssistantAPIClient.getKindsById(ids)\n```\n\n#### getAllReferencedKinds = input =>\nRecursively collects all kinds that are referenced in a kind's schema, starting\nwith a kind ID. For example if the ID of kind A is supplied as an input, and Kind `A` contains a field of type Kind `B`, and `B` contains a field of type Kind `C`,\nan array containing the kinds objects for `A`, `B`, `C` will be returned (as a promise).\n\n```js\nconst initialId = [\"...\"]\nconst kinds = await AssistantAPIClient.getAllReferencedKinds({\n          ids: initialId\n        })\n```\n\n\n### Inventory\n\nThe `InventoryChanged` object:\n```js\n{\n  kinds: {\n    adds: [DiffItem]\n    deletes: [DiffItem]\n    updates: [DiffItem]\n  }\n  functions:{\n    adds: [DiffItem]\n    deletes: [DiffItem]\n    updates: [DiffItem]\n  }\n  services: {\n    adds: [DiffItem]\n    deletes: [DiffItem]\n    updates: [DiffItem]\n  }\n}\n```\n\nThe `DiffItem` object:\n```js\n{\n  id: string,\n  name: string\n}\n```\n\n#### addInventoryChangedListener = async cb =>\nRegisters a callback function with the inventory changed event. When workspace inventory changes the callback function will be called with the InventoryChangedobject. Returns undefined.\n\n**Use-case note: an ‘update’ diff for inventory services is unlikely in general usage.\n\n```js\nconst inventoryCB = ({diff}) => {\n  if(diff.kinds) console.log('KINDS CHANGED',diff.kinds)\n  if(diff.functions) console.log('FUNCTIONS CHANGED', diff.functions)\n  if(diff.services) console.log('SERVICES CHANGED',diff.services)\n}\n\nAssistantAPIClient.addInventoryChangedListener(inventoryCB)\n```\n\nThis function exists on the Q-Assisant-Client only--only enableSelectionChangedNotification is used on the API side.\n\n#### removeInventoryChangedListener = async cb =>\nRemoves an inventory changed listener given the referenced callback. If no callback is specified, all listeners will be removed. Returns undefined.\n\n```js\nAssistantAPIClient.removeInventoryChangedListener(inventoryCB)\n```\n\nThis function exists on the Q-Assisant-Client only--only disableSelectionChangedNotification is used on the API side.\n\n#### moveKindsAndFunctions = (originId, targetId, kindIds, functionIds) =>\nMoves a collection of Kinds and Functions from the origin Workspace to the target Workspace.\n\n```js\n  await AssistantAPIClient.moveKindsAndFunctions(\n    originWorkspaceId,\n    targetId,\n    kindIds,\n    functionIds\n  );\n```\n\n### Locking Changed Event\n\nAn event is triggered when the locked state of the currently active Workspace or\nits Knowledge Graphs and Functions change.\n\nThe `LockingChanged` object:\n```js\n{\n  workspaces: [LockItem],\n  knowledgeGraphs: [LockItem],\n  functions: [LockItem]\n}\n```\n\nThe `LockItem` object:\n```js\n{\n  id: string\n  lockedBy: string\n}\n```\n\n#### addLockingChangedListener = cb =>\n\nRegisters a callback function with the locking changed event. When the currently\nactive Workspace or its Knowledge Graphs and Functions change the callback\nfunction will be called with the `LockingChanged` object. Returns undefined.\n\n```js\nconst lockingChangedCB = ({ locks }) => {\n  if(locks.workspace) console.log('WORKSPACES CHANGED', locks.workspace);\n  if(locks.knowledgeGraphs) console.log('KNOWLEDGE GRAPHS CHANGED', locks.knowledgeGraphs);\n  if(locks.functions) console.log('FUNCTIONS CHANGED', locks.functions);\n}\n\nAssistantAPIClient.addLockingChangedListener(lockingChangedCB);\n```\n\n#### removeLockingChangedListener = cb =>\n\nRemoves an locking changed listener given the referenced callback. If no\ncallback is specified, all listeners will be removed. Returns undefined.\n\n```js\nAssistantAPIClient.removeLockingChangedListener(lockingChangedCB)\n```\n\n## Troubleshooting Assistant Issues\n### Assistant root file has loaded, but not other content\nObserving in the browser's dev tools that some resources have loaded correctly (usually the root), but other's haven't (usually nested files or chunks), is indicative of a failure of Q Gateway to proxy due to not having a 'relative' path structure.\n\n### You are seeing post-robot `NO ACK` errors in the console.\nThese errors stem from a failed acknowledgement for a call either between the client and the API or vice-versa. Here, this means that the web app 'window' (the assistant) cannot communicate with, or access, the 'window.parent' (Maana K-Portal) object.\n\nCommonly, these will stem from the 'window' (the assistant) not being loaded or in a loadable state, which means the API will not receive an acknowledgement when it fires an event.\n\nImproper CORS configuration is also a common culprit (also verify if using docker or nginx that your proxying and networking is configured correctly to allow communication and to accout for CORS).","readmeFilename":"README.md","gitHead":"a91c22f754cf6cb0b0961f45070b6ac6d849e2b8","_id":"@io-maana/q-assistant-client@3.3.0-beta.2","_nodeVersion":"12.18.4","_npmVersion":"6.14.6","dist":{"integrity":"sha512-lGx1HCDDHLH5LwzBrgnqN94pOd77ESnqz734/KQ/oSuWPeMq/QbrBzvREGaTiBcR8HMc5dZL+YG+JGG9xj3ZDA==","shasum":"ce2fab15a9478cd24b41d3e4c39457da4f2177f0","tarball":"https://registry.npmjs.org/@io-maana/q-assistant-client/-/q-assistant-client-3.3.0-beta.2.tgz","fileCount":16,"unpackedSize":113804,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJff5saCRA9TVsSAnZWagAAUZUP/isdVS0fmLSYutMG9PJS\ntB9RbB+9V2PxqlnayDDkATXIkf/JiQu10okQX/aPxwHqhF8VsUXI6q5kPRvA\neUIMMLof55m5NYUsPrJpFOOV69le1Yt2qVKyKf8bsbbsFQxyYV8jsEJJvwp/\n1SwJM8SDSaw7Aq/dpaMC2cz9snOnlUOhHPrBlwV65i3PKEkBnptrs3S95VIg\ne0/WcUcKSBPsFWoqaA3/JTgWVn+CS8zc/WvJgd1pXaoTgzNpV4eO7WTaUn0N\nbd9sMnvXKshxJTpTKyO0BxwnbCW/WasxFFf+GnCQnPFvOid3unLfZSllkRog\nnI6JSVMhZx0JLctq0CW8QSF95p/60gA0Rr34ifqSDlXbGxV8+Q8ZJaBJdCcq\n3g7JX66gV+ltk9L6o4IaYI8ok2LFcwT9NCd9DJvG0i0crcRNc3QRPUgWc13q\nFfKk2Bz3+YKOPf5upvuTivccmTS2m76bYewv5IKmdhuKpTlWnPFfQVvxVpPR\nFcuCkym7wfDcfrLdaNVt1MoAx4OL7uHXdS7uJgjuDguoRpJ64Kw4dImzMm2t\nX1phs6NYkNB5NvsQE2iU3slwLaj3BIdN87V/kzY7GU+/QCESOTpv7eKWfOnh\nE93ja4Mv9fhozxWL554uXe1ynVrDrvd3CLy1gqJbGa4Au1ckFLSlmn/S/wb2\nI5VN\r\n=7Ox0\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEQCIHvhNJkm10V8h+4kv6VM13Z5XfIxXgHNdqzN/SVLqAGuAiAfnQ+dY/wGSAkBw7si7cgLory30GZeU5pfbzamF9Lx7g=="}]},"maintainers":[{"name":"dlsmaana","email":"dlewissandy@maana.io"},{"name":"witt3rd","email":"witt3rd@witt3rd.com"},{"name":"bzvetey","email":"bzvestey@gmail.com"},{"name":"abatyuk","email":"andrey@maana.io"},{"name":"rpovey","email":"rob@maana.io"},{"name":"teamcitymaana","email":"teamcity@maana.io"}],"_npmUser":{"name":"teamcitymaana","email":"teamcity@maana.io"},"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/q-assistant-client_3.3.0-beta.2_1602198298156_0.705411691603919"},"_hasShrinkwrap":false},"3.3.0-beta.4":{"name":"@io-maana/q-assistant-client","version":"3.3.0-beta.4","description":"JavaScript package to streamline communication between an assistant and the Maana Q Assistant API.","main":"build/index.js","types":"build/index.d.ts","exports":{"./":"./build/"},"scripts":{"build":"npm run build:js && npm run build:tsd && npm run build:doc","build:js":"babel src --out-dir build","build:tsd":"tsc --build tsconfig.json","build:doc":"jsdoc2md > API.md","prepack":"npm run build","test":"echo \"Error: no test specified\" && exit 1","format":"prettier --write \"src/**/*.js\""},"repository":{"type":"git","url":"git+https://github.com/maana-io/q-assistant-client.git"},"keywords":["Maana","Q"],"author":{"name":"Logan Gore @ Maana.io"},"license":"MIT","bugs":{"url":"https://github.com/maana-io/q-assistant-client/issues"},"homepage":"https://github.com/maana-io/q-assistant-client#readme","dependencies":{"core-js":"3.6.4","post-robot":"10.0.29"},"devDependencies":{"@babel/cli":"^7.10.1","@babel/core":"^7.10.2","@babel/plugin-proposal-class-properties":"^7.10.1","@babel/preset-env":"^7.10.2","jsdoc-to-markdown":"^6.0.1","prettier":"2.0.5","typescript":"^3.9.5"},"readme":"# q-assistant-client\nA lightweight JavaScript client for Maana-Q Assistant developers that wraps post-message communication between an embedded Maana-Q assistant and the Maana-Q UI.\n\n## Abstract\nThe Q-Assistant-Client is intented to be used in a web application being leveraged as a Maana Q assistant (embedded as an iframe).\nThis assistant client will facilitate communication between the assistant and the parent frame.\nThe client provides a rich, asynchronous experience over what would otherwise be 'fire-and-forget'-style messaging\nvia post-post message communication.\n\n## Requirements and Assumptions\n\n### Post-Robot Library\nThe Maana Knowledge Portal (KPortal) uses the kraken/post-robot library [kraken/post-robot](https://github.com/krakenjs/post-robot) to enrich the communication with the assistant. Post-robot allows for asynchronous, promise-based request/response style behavior between the assistant and the assistant API.\n\nThe API requires that the client use the post-robot library. This assistant-client library is the easiest way to achieve this, and also adds a fair amount of 'sugar' to the process to improve developer productivity. Developers could, however, use post-robot directly in their own client implementation.\n\n### Maana-Gateway Proxy Requirements\nThe Maana-Gateway service requires relative paths (paths relative to the root) in the assistant web application in order to proxy the application and its content. For create-react-apps, for instance, this means setting \"homepage\" to \".\" in the package.json file.\n\n## Singleton Instance\nThe client is exported as a singleton to avoid duplicate registration on event listeners.\nYou can import the instance like this:\n\n```js\nimport AssistantAPIClient from '@io-maana/q-assistant-client';\n```\n\nFunction calls can be made against the client instance like any other javascript object. They are all async.\n\n```js\nconst workspace = await AssistantAPIClient.getWorkspace();\nconsole.log(\"Workspace:\", workspace)\n```\n\n## Dependencies\nPost-Robot\nhttps://github.com/krakenjs/post-robot\n\nPost-robot is used to provide a richer communication layer atop post-message.\n\n## Versioning\nThe Maana Q Assistant Client does not follow semantic versioning. Its versions\ntrack the releases of the Maana Q platform.\n\n## Examples\n@TODO Logan\n\n\n## Changes in v3.2.2\nImprovements in v3.2.2\n- Assistant State Management: WORKING, IDLE\n- Background Messaging/Eventing\n- Render Modes: BACKGROUND, DISPLAY\n- Expansion of Workspace object capabilities\n- Error Reporting\n- Repair Event\n- Plural versions of calls such as updateKind(s) to improve performance and developer experience.\n- InventoryChanged diffing is fully granular in v3.2.2--limitations\nin v3.2.1 only fired the Function diff for changes in Function name.\n\n### Deprecation\nThe following surface area IS removed from the\nclient in v3.2.2, and IS deprecated in the API:\n- AssistantAPIClient.enableSelectionChangedNotification\n- AssistantAPIClient.disableSelectionChangedNotification\n- AssistantAPIClient.enableInventoryChangedNotification\n- AssistantAPIClient.disableInventoryChangedNotification\n\nThe following surface area WILL BE removed from\nthe client in v3.2.4, and WILL BE deprecated in the API:\n- AssistantAPIClient.updateFunction (expected move to Workspace object)\n- AssistantAPIClient.updateKind (expected move to Workspace object)\n- AssistantAPIClient.deleteKind (expected move to Workspace object)\n- AssistantAPIClient.deleteFunction (expected move to Workspace object)\n\n## API Documentation\nMore information in the [API File](./API.md)\n\n### Assistant Render Mode\nAn assistant's render mode refers to whether it is being displayed in a visible manner to the user. As of v3.2.2, assistants are not closed when they are out of view.\nAll assistants will be loaded and kept in `BACKGROUND` render mode until they are\nplaced in the assistant panel, at which point the `DISPLAY` render mode event will be fired.\n\nNote: Assistants will receive all notifications/events while in BACKGROUND mode.\n\nDesign Consideration: It will be up to the developer to determine how state and resource use will be managed while an assistant is operating between BACKGROUND and DISPLAY modes.\n\n#### addRenderModeChangedListener = (cb) =>\nA listener to receive push events as to the assitant's render mode being changed.\n\n```js\nfunction handleRenderModeChanged(renderMode){\n  if (renderMode === 'DISPLAY'){\n    // Assistant is visible\n  } else {\n    // Assistant is not visible and running in background.\n  }\n}\n\nAssistantAPIClient.addRenderModeChangedListener(handleRenderModeChanged)\n\n```\n\n#### removeRenderModeChangedListener = (cb) =>\nRemoves the renderModeChanged listener by reference, or if no callback function reference is provided, it removes all listeners.\n\n#### getRenderMode = () =>\nReturns the current assistant render mode.\n\n```js\nconst renderMode = await AssistantAPIClient.getRenderMode()\n\nif (renderMode === 'DISPLAY'){\n  // Assistant is visible\n} else {\n  // Assistant is not visible and running in background.\n}\n\n```\n\n### Repair\nAssistants may get into situations where they are either out of sync with the Maana Q UI, or in a failure state. Assistants should be able to recover from these states.\n\nThe repair event functionality added in v3.2.2 is designed to notify the assistant that it must repair itself. This could mean a resync with its resources on the workspace or externally or, for some assistants, nothing at all.\n\nWhen is repair triggered?\nEither manually by a user clicking 'repair workspace' under the\nassistant inventory panel, or upon a workspace clone event. An assistant will be expected to handle either scenario.\n\nPerformance Consideration:\nFor some assistants, repair might involve 'introspecting'\nand processing the current workspace or Q system resources. This could be very resource intensive. Make sure you review this API guide to have an idea of what tools are\navailable to get the best results. It's always a good idea to check performance of repair on a large workspace and ensure necessary optimizations have been made.\n\nDesign Consideration:\nMake your workflows modular enough to be reused between repair and normal usage if possible.\n\n#### addRepairListener (cb) =>\n```js\n\nAssistantAPIClient.addRepairListener(()=>{\n  // Self-heal\n})\n\n```\n\nRecommended Usage: A repair process should be wrapped in the try/catch/finally flow shown in the `setAssistantState` API call to provide the user assistant-state and error updates as well as pause `inventoryChanged` notifications during repair (if the assistant has subscribed).\n\n#### removeRepairListener = (cb) =>\nRemoves the repair listener by reference, or if no callback function reference is provided, it removes all listeners.\n\n### User-facing Error Handling\n\n#### reportError (error) =>\nReports an error to the UI to be displayed in the assistant's error log in the\ninventory panel. This call is not disruptive and designed to operated independently of other assistant operations, such as state management. See `setAssistantState` in the next section.\n\nRecommended usage: use this functionality where it would futher the user experience\nto show the user an error and it's cause. Do not use this where things will be retried,\ncleaned up automatically, or are not relevant to the user.\n\n```js\ntry{\n  // Do work\n} catch(e) {\n  AssistantAPIClient.reportError(e)\n}\n```\n\n### State management\n\n#### clearState = () =>\nThis will remove all callbacks from all listeners.\n\n```js\nawait AssistantAPIClient.clearState()\n```\n\n#### setAssistantState = (state) =>\nThis sets the current state of the assistant using the\n`AssistantState` enum. Setting a state of `WORKING` will\ncreate the 'working' status spinner in the Assistant\nInventory Panel in the Maana Q UI. Conversely, setting an `IDLE` state will\nremove the spinner. This adds to user experience by informing users of the\nstatus of operations.\n\n```js\nimport {\n  default as AssistantAPIClient,\n  AssistantState\n} from '@io-maana/q-assistant-client'\n\n...\n\nAssistantAPIClient.setAssistantState(AssistantState.WORKING)\n\n...\n\nAssistantAPIClient.setAssistantState(AssistantState.IDLE)\n\n```\nUI User Prompt: If the assistant is in a `WORKING` state, the Maana Q UI will\nwarn the user before leaving the workspace.\n\nNOTE: while an assistant is in a working state, it will\nnot receive `inventoryChanged` events--an aggregated inventory diff\nwill be sent once the assistant is set back to `IDLE`.\n\nRecommended usage: Control states at a high level using try/catch/finally\nflow incorporating the `reportError` API call.\n\n```js\ntry{\n  AssistantAPIClient.setAssistantState(AssistantState.WORKING)\n  // Do work, await high-level tasks, etc.\n} catch(e) {\n  AssistantAPIClient.reportError(e)\n} finally{\n  AssistantAPIClient.setAssistantState(AssistantState.IDLE)\n}\n```\n\n#### AssistantState (enum)\nContains the valid assistant states: `IDLE` or `WORKING`.\n\nMust be imported in addition to the AssistantAPIClient:\n\n```js\nimport {\n  default as AssistantAPIClient,\n  AssistantState\n} from '@io-maana/q-assistant-client'\n```\n\n\n### User Info\nThe `UserInfo` object:\n```js\n{\n email: string,\n name: string\n}\n```\n\n#### getUserInfo = () =>\nReturns a Userinfo object pertaining to the logged in user.\n\n```js\nconst userInfo = await AssistantAPIClient.getUserInfo()\n```\n### Selection\nThe `Selection` object:\n```js\n{\n  kindId: string\n  kindName: string\n  id: string\n}\n```\n\n#### getCurrentSelection = () =>\nReturns an Array of `Selection` objects:\n\n```js\nconst {selection} = await AssistantAPIClient.getCurrentSelection();\n```\n\n#### addSelectionChangedListener = async cb =>\nAdds a callback function to be executed upon a valid workspace selection change.\n\nCallback value is an array of Selection objects:\n\n```js\n// Create the selection callback.\nconst selectionCB = ({selection})=>{\n  console.log('Workspace selection has changed.')\n  selection.forEach(i=>{\n    console.log('Kind: ',i.kindName)\n    console.log('Instance Id:',i.id)\n    console.log('Kind Id:',i.kindId)\n  })\n}\n\n// Add the listener.\nAssistantAPIClient.addSelectionChangedListener(selectionCB);\n```\n\nThis function only exists on the Q-Assistant-Client--only enableSelectionChangedNotification is called on the API.\n\n#### removeSelectionChangedListener = async cb =>\nThis will have to be called on a 1:1 basis with addSelectionChangedListener calls if supplying a callback.\n\n```js\nAssistantAPIClient.removeSelectionChangedListener(selectionCB)\n```\n\n**If NOT supplying a callback to this call, all selection changed listeners will be removed.\n\n```js\nAssistantAPIClient.removeSelectionChangedListener()\n```\n\nThis function only exists on the Q-Assistant-Client--only disableSelectionChangedNotification is called on the API.\n\n\n### Services\nThe `Service` object:\n```js\n{\n   id: string,\n   name: string\n   endpointUrl: string,\n   getKinds: () => // Returns [] of Kinds objects\n   getFunctions: () => // Returns [] of Function objects\n}\n```\n\n#### getServiceById = id =>\nThis will return a service that exists within the scope of the workspace.\n** Assistant services will return null. Services outside the scope of the workspace will cause an error to be returned as 'Unable to load a Service from outside of the workspace.'\n\n```js\nconst svc = await AssistantAPIClient.getServiceById(id)\n```\n\n#### createService = id =>\nCreates a service in Q.\n\nNote: This will create the service, but does NOT import it into the workspace.\nYou will need to use `importService` on the Workspace object to import it.\nReturns a promise that resolves\n\n```js\n    const service = {\n      id: ...,\n      name: ...,\n      endpointUrl: ...,\n      serviceType: ...\n    }\n\n    await AssistantAPIClient.createService(service)\n```\n\n#### deleteService = id =>\nDeletes a service from Q.\n\n```js\n    await AssistantAPIClient.deleteService(id)\n```\n\n#### refreshServiceSchema = id =>\nRefreshes a service by fetching its schema. This will also\nreload the service inventory in the currently visible workspace.\n\n```js\nawait AssistantAPIClient.refreshServiceSchema(\"id\")\n```\n\n#### reloadService = id =>\nReloads a service in the inventory in the currently visible workspace.\n\n```js\nawait AssistantAPIClient.reloadService(\"id\")\n```\n\n### Workspace\n\n#### getWorkspace = () =>\nReturns a Workspace object representing the workspace.\n\n```js\nconst ws = await AssistantAPIClient.getWorkspace(id)\n```\n\nNote: The `id` parameter is optional. If it is not supplied, the query\nwill return the current/visible workspace.\n\nThe `Workspace` object:\n\n```js\n\n{\n    id: string,\n    name: string,\n    endpointUrl: string,\n    workspaceServiceId: string,\n    modelServiceId: string,\n    logicServiceId: string,\n\n    //\n    // Locking information\n    //\n    async lockedBy() {\n      // Returns the e-mail address of the user who locked the Workspace, or\n      // null if the Workspace is not currently locked.\n    }\n    async canEdit() {\n      // Returns `true` when the Workspace is not locked, or the current user\n      // owns the lock.\n      // Returns 'false' when the Workspace is locked by a different user.\n    }\n    async setLocked(isLocked) {\n      // Takes a boolean or undefined for `isLocked`.\n      //  `true` locks the Workspace as the current User.\n      //  `false` unlocks the Workspace\n      //  `undefined` causes it to toggle the current locked state.\n      // Returns a Promise that will resolve or reject when the task is done.\n    }\n\n    //\n    // Knowledge Graphs\n    //\n    getActiveGraph: async () => {\n      // Returns the active Graph object.\n      // Returns null if active graph is not of type 'Knowledge Graph', or if an\n      // active graph is deleted, thereby setting active graph to null.\n    },\n    getKnowledgeGraphs: async () => {\n      // Returns [Graph]\n    },\n    // TODO: define input\n    createKnowledgeGraph: input =>\n    // TODO: define input\n    createKnowledgeGraphs: input =>\n\n    //\n    // Services\n    //\n    getImportedServices: async () => {\n      // Returns an array of Service objects that have\n      // been imported into the workspace.\n      // No assistant services will be returned.\n    },\n    getImportedAssistants: async () => {\n      // Returns a list of imported assistants.\n    },\n    importService: serviceId => {\n      // Imports a service by it's ID.\n    },\n    importServices: serviceIds => {\n      // Imports services by their IDs.\n    },\n    removeServices: serviceIds => {\n      // Removes a list of services from the workspace.\n    },\n    removeService: serviceId => {\n      // Removes a service from the workspace.\n    },\n\n    //\n    // Functions\n    //\n    getFunctions: async () => {\n      // Returns an array of functions in the workspace (includes boilerplate).\n    },\n    createFunction: funcData => {\n      // Creates a function and adds it to the graph.\n    }\n    createFunctions: funcData =>{\n      // Creates several functions and adds them to the graph.\n    }\n    updateFunction: funcData => {\n      // Updates a function.\n    },\n    updateFunctions: funcData =>{\n      // Updates functions based on input array.\n    },\n    deleteFunction: funcId => {\n      // Deletes a function by its ID.\n    },\n    getFunctionGraph: funcId => {\n      // Returns a function graph by its ID.\n    }\n\n    //\n    // Kinds\n    //\n    getKinds: async () => {\n      // Returns an array of functions in the workspace (includes boilerplate).\n    },\n    createKind: kindData => {\n      // Currently same input as AssistantAPIClient call.\n    },\n    createKinds: kindData => {\n      // Currently same input as AssistantAPIClient call.\n    },\n    updateKind: kindData => {\n      // Currently same input as AssistantAPIClient call.\n    },\n    updateKinds: kindData => {\n      // Currently same input as AssistantAPIClient call.\n    },\n    deleteKind: kindId => {\n      // Currently same input as AssistantAPIClient call.\n    }\n    // Event Triggers\n    triggerRepairEvent: () => {\n      // Triggers the repair event on a workspace.\n    }\n  };\n}\n```\n\n\n### Graphs\nThe `Graph` object:\n```js\n{\n  id: string,\n  name: string,\n  offsetX: Number,\n  offsetY: Number,\n  zoom: Number,\n  getNodes: async () => {\n      // Returns [Node]\n  },\n\n  addNode: async (type, instance, changeSelection) => {\n      // Returns Node\n  },\n  removeNode: async id => {\n      // Should return nothing or error.\n      // Currently returning [] in all cases.\n  },\n  updateNodeLayout: async (nodeId, { x, y, collapsed }) => {\n  },\n  updateGraphLayout: async ({ offsetX, offsetY, zoom }) => {\n  }\n\n  //\n  // Locking information\n  //\n  async lockedBy() {\n    // Returns the e-mail address of the user who locked the Graph, or null if\n    // the Graph is not currently locked.\n  }\n  async canEdit() {\n    // Returns `true` when the Graph is not locked, or the current user owns the\n    // lock.\n    // Returns 'false' when the Graph is locked by a different user.\n  }\n  async setLocked(isLocked) {\n    // Takes a boolean or undefined for `isLocked`.\n    //  `true` locks the Graph as the current User.\n    //  `false` unlocks the Graph\n    //  `undefined` causes it to toggle the current locked state.\n    // Returns a Promise that will resolve or reject when the task is done.\n  }\n}\n```\n\n#### Getting a graph object:\nGraph objects are obtained through an instance of a Workspace\n\n```js\nconst ag = await ws.getActiveGraph()\n```\n\nor\n\n```js\nconst kgs = await ws.getKnowledgeGraphs()\n```\n\n#### Manipulating Graphs\n\n**Only the active graph may be manipulated.\n\nAll graph manipulations should be ‘visually’ verifiable on the graph itself, i.e., adds/removes/positioning, should all be reflected on the graph itself.\n\nThe `Node` object:\n```js\n{\nid: string\nx: number\ny: number\ncollapsed: boolean\nknowledgeGraphNode {\n  id: string\n  innerKind: Kind\n  innerFunction: Function\n}\n}\n```\n\n#### addNode(type, instance, changeSelection) =>\n\nTakes type (“Function” or “Kind”), instance (the Function or Kind object), and optionally a boolean to indicate whether the selection should be changed to this new node.\n\nReturns the newly created Node object.\n\n```js\nconst node = await ag.addNode('Kind',kind)\n```\n\n#### removeNode(id) =>\n\nTakes the id of Node to be deleted. Returns either undefined or an error.\n\n```js\nawait ag.removeNode(node.id)\n```\n\n#### getNodes() =>\nReturns an array of Node objects from the graph.\n\n```js\nconst nodes = await ag.getNodes()\n```\n\n#### updateNodeLayout: async (nodeId, { x, y, collapsed})=>\nUpdates a Node layout given a node ID and node coordinates (`x` and/or `y`) or a `collapsed` value. x/y values must be a number, and collapsed must be a boolean. Whatever is not specified will remain current.\n\n```js\nag.updateNodeLayout(id,{x:100,y:100,collapsed:true})\n```\n\n#### updateGraphLayout: async ({ offsetX, offsetY, zoom})=>\nUpdates a Graph layout given numerical values for x/y offsets and the zoom.\n\n```js\nag.updateGraphLayout({offsetX:50, offsetY:50, zoom: 70})\n```\n\n### Functions\n\nThe `Function` object:\n```js\n{\n    id: string\n    name: string\n    service {\n      id: string\n      name: string\n    }\n    arguments {\n      id: string\n      name: string\n      type: string\n      modifiers: Array[string]\n      typeKindId:: string\n      kind {\n        id: string\n        name: string\n      }\n    }\n    implementation {\n      id: string\n      entrypoint {\n        id: string\n      }\n      operations {\n        id: string\n        type: string\n        function {\n          id: string\n          name: string\n        }\n        argumentValues {\n          id: string\n          argument {\n            id: string\n          }\n          operation {\n            id: string\n          }\n          argumentRef: string\n        }\n      }\n    }\n    isGenerated: boolean\n    functionType: string\n    graphqlOperationType: string\n    outputType: string\n    outputKindId: string\n    outputModifiers: Array[string]\n    kind {\n      id: string\n      name: string\n    }\n\n    //\n    // Locking information\n    //\n    async lockedBy() {\n      // Returns the e-mail address of the user who locked the Function, or null\n      // if the Function is not currently locked.\n    }\n    async canEdit() {\n      // Returns `true` when the Function is not locked, or the current user\n      // owns the lock.\n      // Returns 'false' when the Function is locked by a different user.\n    }\n    async setLocked(isLocked) {\n      // Takes a boolean or undefined for `isLocked`.\n      //  `true` locks the Function as the current User.\n      //  `false` unlocks the Function\n      //  `undefined` causes it to toggle the current locked state.\n      // Returns a Promise that will resolve or reject when the task is done.\n    }\n}\n```\n\n`FunctionExecutionResult` object:\n```js\n{\n  id: string,\n  result: JSON\n}\n```\n\n#### executeFunction = ( {id, variables, resolve} ) =>\nExecutes a function based on its id, with optional inputs for variables and a resolve string (this specifies the fields to be returned, which must be valid based on the result).\n\nReturns : JSON matching shape of result , unless no sub-selection of fields is required in the execution.\n\nThis following piece of code will execute a Function given a function ID, and pass in variables for ‘example’, requesting back id and name fields.\n\n```js\nconst res = await AssistantAPIClient.executeFunction({functionId: func.id, variables: {\"variableName\": \"variableValue\"}, resolve: \"{ id name }\");\n```\n\n#### createFunction = input =>\nCreates a function based on the input provided.\n\nReturns: the created Function object.\n\n**Using create function will only place the function in the workspace’s inventory--it will not place the function as a node on the Graph. In order to do this, you must pass the created function into the addNode function on the active Graph, making sure to specify ‘Function' as the type.\n\n```js\nconst createFunctionInput = {\n  name:\"yourName\",\n  arguments:[],\n  outputType: \"STRING\",\n  graphqlOperationType:\"QUERY\",\n  functionType: \"CKG\"\n}\n\nconst createdFunction = await AssistantAPIClient.createFunction(createFunctionInput)\n```\n\n#### updateFunction = input =>\nInput is the same for creating a function. It’s important to note that the arguments property will be replaced in it’s entirety with whatever is provided (if a value is provided.\n\nReturns the updated `Function` object.\n\n```js\nconst updatedFunction = await AssistantAPIClient.updateFunction(input);\n```\n\n#### deleteFunction = input =>\nInput is the id of the Function to be deleted. Returns the deleted function as a promise.\n\n```js\nconst deletedFunction = await AssistantAPIClient.deleteFunction('id...');\n```\n\n#### getFunctionById = id =>\nReturns a Function as a promise based on the ID provided.\n\n```js\nconst func = await AssistantAPIClient.getFunctionById('id...');\n```\n\n#### addFunctionExecutionListener = async (id, cb) =>\nAssociates a callback function with the execution of a particular Function. When the Function matching the id parameter is executed, its FunctionExecutionResult object passed to the callback. Returns undefined.\n\nExample function execution callback and listener registration:\n\n```js\nfunction exampleFunctionCB (result){\n  console.log(`Function executed with result:`, result)\n}\n\nAssistantAPIClient.addFunctionExecutionListener('id...', exampleFunctionCB)\n```\n\n#### removeFunctionExecutionListener = async (id, cb) =>\nRemoves a Function execution listener based on the function ID and a reference to the callback function. If no callback is supplied, all listeners associated with the Function ID will be removed. Returns undefined.\n\n```js\nAssistantAPIClient.removeFunctionExecutionListener('id..', exampleFunctionCB)\n```\n\n### Kinds\nThe `Kind` object:\n```js\n{\n    id: string\n    name: string\n    service: {\n      id\n      name\n    }\n    isGenerated: boolean\n    schema {\n      id: string\n      name: string\n      type: string\n      typeKindId: string\n      modifiers: Array[string]\n      kind {\n        id: string\n        name: string\n      }\n    }\n}\n```\n\n#### createKind = input =>\nCreates a Kind based on an input object. Returns a promise that resolves to the created Kind object.\n\n```js\nconst kindInput = {\n name: \"someKind\",\n schema:[\n  { name: \"someField1\", type: STRING },\n  { name: \"someField2\", type: STRING }\n ]\n}\n\nconst newKind = await AssistantAPIClient.createKind(kindInput)\n```\n\n#### createKinds = input =>\nA plural version of `createKind` accepting an array of input objects.\nReturns a promise that resolves to an array of created Kind objects.\n\n```js\nconst kindsInput = [{\n name: \"someKind\",\n schema:[\n  { name: \"someField1\", type: STRING },\n  { name: \"someField2\", type: STRING }\n ]\n}, ...]\n\nconst newKinds = await AssistantAPIClient.createKinds(kindsInput)\n```\n\n\n#### updateKind = input =>\nUpdates a Kind based on an input object.\n\nUpdate Semantics: Only properties specified will be updated. If updating the schema, the entire schema must be specified as it will be replaced in its entirety.\n\nReturns a promise that resolves to the updated `Kind` object.\n\n```js\nconst updated = await AssistantAPIClient.updateKind(input)\n```\n\n#### deleteKind = input =>\nDeletes a Kind given a kind ID.\n\n```js\nconst deleted = await AssistantAPIClient.deleteKind(input)\n```\n\n#### getKindById = id =>\nReturns a promise that resolves to a Kind object given the specified kind ID.\n\nIn v3.2.2, any requested non-system kinds will be returned.\nIn v3.2.1, only kinds in the workspace or those of imported services will be returned.\n\n```js\nconst kind = await AssistantAPIClient.getKindById(id)\n```\n\n#### getKindsById = ids =>\nReturns a promise that resolves to an array of Kind objects given an array of kind IDs. Only kinds in the workspace or those of imported services will be returned.\n\n```js\nconst ids = [\"...\",\"...\",...]\nconst kind = await AssistantAPIClient.getKindsById(ids)\n```\n\n#### getAllReferencedKinds = input =>\nRecursively collects all kinds that are referenced in a kind's schema, starting\nwith a kind ID. For example if the ID of kind A is supplied as an input, and Kind `A` contains a field of type Kind `B`, and `B` contains a field of type Kind `C`,\nan array containing the kinds objects for `A`, `B`, `C` will be returned (as a promise).\n\n```js\nconst initialId = [\"...\"]\nconst kinds = await AssistantAPIClient.getAllReferencedKinds({\n          ids: initialId\n        })\n```\n\n\n### Inventory\n\nThe `InventoryChanged` object:\n```js\n{\n  kinds: {\n    adds: [DiffItem]\n    deletes: [DiffItem]\n    updates: [DiffItem]\n  }\n  functions:{\n    adds: [DiffItem]\n    deletes: [DiffItem]\n    updates: [DiffItem]\n  }\n  services: {\n    adds: [DiffItem]\n    deletes: [DiffItem]\n    updates: [DiffItem]\n  }\n}\n```\n\nThe `DiffItem` object:\n```js\n{\n  id: string,\n  name: string\n}\n```\n\n#### addInventoryChangedListener = async cb =>\nRegisters a callback function with the inventory changed event. When workspace inventory changes the callback function will be called with the InventoryChangedobject. Returns undefined.\n\n**Use-case note: an ‘update’ diff for inventory services is unlikely in general usage.\n\n```js\nconst inventoryCB = ({diff}) => {\n  if(diff.kinds) console.log('KINDS CHANGED',diff.kinds)\n  if(diff.functions) console.log('FUNCTIONS CHANGED', diff.functions)\n  if(diff.services) console.log('SERVICES CHANGED',diff.services)\n}\n\nAssistantAPIClient.addInventoryChangedListener(inventoryCB)\n```\n\nThis function exists on the Q-Assisant-Client only--only enableSelectionChangedNotification is used on the API side.\n\n#### removeInventoryChangedListener = async cb =>\nRemoves an inventory changed listener given the referenced callback. If no callback is specified, all listeners will be removed. Returns undefined.\n\n```js\nAssistantAPIClient.removeInventoryChangedListener(inventoryCB)\n```\n\nThis function exists on the Q-Assisant-Client only--only disableSelectionChangedNotification is used on the API side.\n\n#### moveKindsAndFunctions = (originId, targetId, kindIds, functionIds) =>\nMoves a collection of Kinds and Functions from the origin Workspace to the target Workspace.\n\n```js\n  await AssistantAPIClient.moveKindsAndFunctions(\n    originWorkspaceId,\n    targetId,\n    kindIds,\n    functionIds\n  );\n```\n\n### Locking Changed Event\n\nAn event is triggered when the locked state of the currently active Workspace or\nits Knowledge Graphs and Functions change.\n\nThe `LockingChanged` object:\n```js\n{\n  workspaces: [LockItem],\n  knowledgeGraphs: [LockItem],\n  functions: [LockItem]\n}\n```\n\nThe `LockItem` object:\n```js\n{\n  id: string\n  lockedBy: string\n}\n```\n\n#### addLockingChangedListener = cb =>\n\nRegisters a callback function with the locking changed event. When the currently\nactive Workspace or its Knowledge Graphs and Functions change the callback\nfunction will be called with the `LockingChanged` object. Returns undefined.\n\n```js\nconst lockingChangedCB = ({ locks }) => {\n  if(locks.workspace) console.log('WORKSPACES CHANGED', locks.workspace);\n  if(locks.knowledgeGraphs) console.log('KNOWLEDGE GRAPHS CHANGED', locks.knowledgeGraphs);\n  if(locks.functions) console.log('FUNCTIONS CHANGED', locks.functions);\n}\n\nAssistantAPIClient.addLockingChangedListener(lockingChangedCB);\n```\n\n#### removeLockingChangedListener = cb =>\n\nRemoves an locking changed listener given the referenced callback. If no\ncallback is specified, all listeners will be removed. Returns undefined.\n\n```js\nAssistantAPIClient.removeLockingChangedListener(lockingChangedCB)\n```\n\n## Troubleshooting Assistant Issues\n### Assistant root file has loaded, but not other content\nObserving in the browser's dev tools that some resources have loaded correctly (usually the root), but other's haven't (usually nested files or chunks), is indicative of a failure of Q Gateway to proxy due to not having a 'relative' path structure.\n\n### You are seeing post-robot `NO ACK` errors in the console.\nThese errors stem from a failed acknowledgement for a call either between the client and the API or vice-versa. Here, this means that the web app 'window' (the assistant) cannot communicate with, or access, the 'window.parent' (Maana K-Portal) object.\n\nCommonly, these will stem from the 'window' (the assistant) not being loaded or in a loadable state, which means the API will not receive an acknowledgement when it fires an event.\n\nImproper CORS configuration is also a common culprit (also verify if using docker or nginx that your proxying and networking is configured correctly to allow communication and to accout for CORS).","readmeFilename":"README.md","gitHead":"b0243f84143d0f45878ec2ef5176ea0cdefa9b1c","_id":"@io-maana/q-assistant-client@3.3.0-beta.4","_nodeVersion":"12.19.0","_npmVersion":"6.14.8","dist":{"integrity":"sha512-jsCGbSZx2ahipTF5irZDqxaRtLhcv5TQq4sssVlfQg0w1Rz6ItS0lwD4APPXrp5DsdbBrfdQ9cg7HJS0cfkaZA==","shasum":"4cea6b1b00f480e6ee1dbf86f8f60d9750e94b7e","tarball":"https://registry.npmjs.org/@io-maana/q-assistant-client/-/q-assistant-client-3.3.0-beta.4.tgz","fileCount":18,"unpackedSize":251605,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJficmVCRA9TVsSAnZWagAAb9oP/inSYyT+7/0Xk6WnKZLy\n1f8OaNOVps+sH/w0btkoED55e47Xgy9OEfADs4CkOKeaWgW3GMwYBBCzs82L\newoBSPhYgy66GeD4jUbKCcBPoYomcQkkA27l/SKdOis3+31q56SGHE6v5gsT\nYgRI4+HRYvcE6NsdtSyXPLDNAY/v6Jps09mi5Yu/GidsULbWimAf29eVsgPj\nMgOJnbRPO6jncVi8GEP/bzSy/ebD7p+T4N+2zGt9P7Tp4T1TVKX8hWwQVNtK\n6JDVgh1xBlmeeT4RrEb51FZLOAkfe6qHDgILtvW6A6r14rCzEbYEFNUMR416\nKNp7SEvVZ+q76MwnH8vVHs2ppRFQpTreE/g/DFP8qMLuX0iyo0Z20ntWzroI\nwGV5wPOViRzRuFzjjOh87c/xhT1B57+TrA6A1augznrJiXbR52Z5L/GEaRTU\nxlN5uKlWRu/oOSeOaZSPpUKX9qwGRh7qcuHGA7x2lpDHYyYD0FWb7EqwvC7j\nmeTmzKrHt6Ntli0JmnWtDIodI1eMyZFDoR2aujc5JMeWDT4gV6//61fv2iPR\naewwI7vBAiZChHNGTJoeOhlG+OEEwv93UdQx1ZGTCbZqTHeesztBAK3phkSq\nAqVbG5pIYjs0nax6YIl+eWF+/TrT0gzTYO7ctkc9M6v7AYRdb3KA0o6HmFOE\ndhTX\r\n=2VUg\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIQDErFM+IpOCBjSFlmQUI67XEXO91R7EEQYWaksGNh+5+AIgFq5R780UyV61fkYrw70uOhOThpnXpDvvFoZ/zg4Vl/A="}]},"maintainers":[{"name":"dlsmaana","email":"dlewissandy@maana.io"},{"name":"witt3rd","email":"witt3rd@witt3rd.com"},{"name":"bzvetey","email":"bzvestey@gmail.com"},{"name":"abatyuk","email":"andrey@maana.io"},{"name":"rpovey","email":"rob@maana.io"},{"name":"teamcitymaana","email":"teamcity@maana.io"}],"_npmUser":{"name":"teamcitymaana","email":"teamcity@maana.io"},"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/q-assistant-client_3.3.0-beta.4_1602865557277_0.6743811544005502"},"_hasShrinkwrap":false},"3.3.0-beta.5":{"name":"@io-maana/q-assistant-client","version":"3.3.0-beta.5","description":"JavaScript package to streamline communication between an assistant and the Maana Q Assistant API.","main":"build/index.js","types":"build/index.d.ts","exports":{"./":"./build/"},"scripts":{"build":"npm run build:ts && npm run build:doc","build:ts":"tsc --build tsconfig.json","build:doc":"typedoc","prepack":"npm run build","test":"echo \"Error: no test specified\" && exit 1","format":"prettier --write \"src/**/*.js\""},"repository":{"type":"git","url":"git+https://github.com/maana-io/q-assistant-client.git"},"keywords":["Maana","Q"],"author":{"name":"Logan Gore @ Maana.io"},"license":"MIT","bugs":{"url":"https://github.com/maana-io/q-assistant-client/issues"},"homepage":"https://github.com/maana-io/q-assistant-client#readme","dependencies":{"core-js":"3.6.4","post-robot":"10.0.29"},"devDependencies":{"@types/node":"^14.14.2","@types/post-robot":"^10.0.0","prettier":"2.0.5","typedoc":"^0.19.2","typedoc-plugin-markdown":"^3.0.11","typescript":"^3.9.5"},"readme":"# q-assistant-client\nA lightweight JavaScript client for Maana-Q Assistant developers that wraps post-message communication between an embedded Maana-Q assistant and the Maana-Q UI.\n\nYou can find the [API Documentation here](docs/README.md).\n\n## Abstract\nThe Q-Assistant-Client is intented to be used in a web application being leveraged as a Maana Q assistant (embedded as an iframe).\nThis assistant client will facilitate communication between the assistant and the parent frame.\nThe client provides a rich, asynchronous experience over what would otherwise be 'fire-and-forget'-style messaging\nvia post-post message communication.\n\n## Requirements and Assumptions\n\n### Post-Robot Library\nThe Maana Knowledge Portal (KPortal) uses the kraken/post-robot library [kraken/post-robot](https://github.com/krakenjs/post-robot) to enrich the communication with the assistant. Post-robot allows for asynchronous, promise-based request/response style behavior between the assistant and the assistant API.\n\nThe API requires that the client use the post-robot library. This assistant-client library is the easiest way to achieve this, and also adds a fair amount of 'sugar' to the process to improve developer productivity. Developers could, however, use post-robot directly in their own client implementation.\n\n### Maana-Gateway Proxy Requirements\nThe Maana-Gateway service requires relative paths (paths relative to the root) in the assistant web application in order to proxy the application and its content. For create-react-apps, for instance, this means setting \"homepage\" to \".\" in the package.json file.\n\n## Singleton Instance\nThe client is exported as a singleton to avoid duplicate registration on event listeners.\nYou can import the instance like this:\n\n```js\nimport AssistantAPIClient from '@io-maana/q-assistant-client';\n```\n\nFunction calls can be made against the client instance like any other javascript object. They are all async.\n\n```js\nconst workspace = await AssistantAPIClient.getWorkspace();\nconsole.log(\"Workspace:\", workspace)\n```\n\n## Dependencies\nPost-Robot\nhttps://github.com/krakenjs/post-robot\n\nPost-robot is used to provide a richer communication layer atop post-message.\n\n## Versioning\nThe Maana Q Assistant Client does not follow semantic versioning. Its versions\ntrack the releases of the Maana Q platform.\n\n## Examples\n@TODO Logan\n\n\n## Changes in v3.2.2\nImprovements in v3.2.2\n- Assistant State Management: WORKING, IDLE\n- Background Messaging/Eventing\n- Render Modes: BACKGROUND, DISPLAY\n- Expansion of Workspace object capabilities\n- Error Reporting\n- Repair Event\n- Plural versions of calls such as updateKind(s) to improve performance and developer experience.\n- InventoryChanged diffing is fully granular in v3.2.2--limitations\nin v3.2.1 only fired the Function diff for changes in Function name.\n\n### Deprecation\nThe following surface area IS removed from the\nclient in v3.2.2, and IS deprecated in the API:\n- AssistantAPIClient.enableSelectionChangedNotification\n- AssistantAPIClient.disableSelectionChangedNotification\n- AssistantAPIClient.enableInventoryChangedNotification\n- AssistantAPIClient.disableInventoryChangedNotification\n\nThe following surface area WILL BE removed from\nthe client in v3.2.4, and WILL BE deprecated in the API:\n- AssistantAPIClient.updateFunction (expected move to Workspace object)\n- AssistantAPIClient.updateKind (expected move to Workspace object)\n- AssistantAPIClient.deleteKind (expected move to Workspace object)\n- AssistantAPIClient.deleteFunction (expected move to Workspace object)\n\n## API Documentation\nMore information in the [API File](./API.md)\n\n### Assistant Render Mode\nAn assistant's render mode refers to whether it is being displayed in a visible manner to the user. As of v3.2.2, assistants are not closed when they are out of view.\nAll assistants will be loaded and kept in `BACKGROUND` render mode until they are\nplaced in the assistant panel, at which point the `DISPLAY` render mode event will be fired.\n\nNote: Assistants will receive all notifications/events while in BACKGROUND mode.\n\nDesign Consideration: It will be up to the developer to determine how state and resource use will be managed while an assistant is operating between BACKGROUND and DISPLAY modes.\n\n#### addRenderModeChangedListener = (cb) =>\nA listener to receive push events as to the assitant's render mode being changed.\n\n```js\nfunction handleRenderModeChanged(renderMode){\n  if (renderMode === 'DISPLAY'){\n    // Assistant is visible\n  } else {\n    // Assistant is not visible and running in background.\n  }\n}\n\nAssistantAPIClient.addRenderModeChangedListener(handleRenderModeChanged)\n\n```\n\n#### removeRenderModeChangedListener = (cb) =>\nRemoves the renderModeChanged listener by reference, or if no callback function reference is provided, it removes all listeners.\n\n#### getRenderMode = () =>\nReturns the current assistant render mode.\n\n```js\nconst renderMode = await AssistantAPIClient.getRenderMode()\n\nif (renderMode === 'DISPLAY'){\n  // Assistant is visible\n} else {\n  // Assistant is not visible and running in background.\n}\n\n```\n\n### Repair\nAssistants may get into situations where they are either out of sync with the Maana Q UI, or in a failure state. Assistants should be able to recover from these states.\n\nThe repair event functionality added in v3.2.2 is designed to notify the assistant that it must repair itself. This could mean a resync with its resources on the workspace or externally or, for some assistants, nothing at all.\n\nWhen is repair triggered?\nEither manually by a user clicking 'repair workspace' under the\nassistant inventory panel, or upon a workspace clone event. An assistant will be expected to handle either scenario.\n\nPerformance Consideration:\nFor some assistants, repair might involve 'introspecting'\nand processing the current workspace or Q system resources. This could be very resource intensive. Make sure you review this API guide to have an idea of what tools are\navailable to get the best results. It's always a good idea to check performance of repair on a large workspace and ensure necessary optimizations have been made.\n\nDesign Consideration:\nMake your workflows modular enough to be reused between repair and normal usage if possible.\n\n#### addRepairListener (cb) =>\n```js\n\nAssistantAPIClient.addRepairListener(()=>{\n  // Self-heal\n})\n\n```\n\nRecommended Usage: A repair process should be wrapped in the try/catch/finally flow shown in the `setAssistantState` API call to provide the user assistant-state and error updates as well as pause `inventoryChanged` notifications during repair (if the assistant has subscribed).\n\n#### removeRepairListener = (cb) =>\nRemoves the repair listener by reference, or if no callback function reference is provided, it removes all listeners.\n\n### User-facing Error Handling\n\n#### reportError (error) =>\nReports an error to the UI to be displayed in the assistant's error log in the\ninventory panel. This call is not disruptive and designed to operated independently of other assistant operations, such as state management. See `setAssistantState` in the next section.\n\nRecommended usage: use this functionality where it would futher the user experience\nto show the user an error and it's cause. Do not use this where things will be retried,\ncleaned up automatically, or are not relevant to the user.\n\n```js\ntry{\n  // Do work\n} catch(e) {\n  AssistantAPIClient.reportError(e)\n}\n```\n\n### State management\n\n#### clearState = () =>\nThis will remove all callbacks from all listeners.\n\n```js\nawait AssistantAPIClient.clearState()\n```\n\n#### setAssistantState = (state) =>\nThis sets the current state of the assistant using the\n`AssistantState` enum. Setting a state of `WORKING` will\ncreate the 'working' status spinner in the Assistant\nInventory Panel in the Maana Q UI. Conversely, setting an `IDLE` state will\nremove the spinner. This adds to user experience by informing users of the\nstatus of operations.\n\n```js\nimport {\n  default as AssistantAPIClient,\n  AssistantState\n} from '@io-maana/q-assistant-client'\n\n...\n\nAssistantAPIClient.setAssistantState(AssistantState.WORKING)\n\n...\n\nAssistantAPIClient.setAssistantState(AssistantState.IDLE)\n\n```\nUI User Prompt: If the assistant is in a `WORKING` state, the Maana Q UI will\nwarn the user before leaving the workspace.\n\nNOTE: while an assistant is in a working state, it will\nnot receive `inventoryChanged` events--an aggregated inventory diff\nwill be sent once the assistant is set back to `IDLE`.\n\nRecommended usage: Control states at a high level using try/catch/finally\nflow incorporating the `reportError` API call.\n\n```js\ntry{\n  AssistantAPIClient.setAssistantState(AssistantState.WORKING)\n  // Do work, await high-level tasks, etc.\n} catch(e) {\n  AssistantAPIClient.reportError(e)\n} finally{\n  AssistantAPIClient.setAssistantState(AssistantState.IDLE)\n}\n```\n\n#### AssistantState (enum)\nContains the valid assistant states: `IDLE` or `WORKING`.\n\nMust be imported in addition to the AssistantAPIClient:\n\n```js\nimport {\n  default as AssistantAPIClient,\n  AssistantState\n} from '@io-maana/q-assistant-client'\n```\n\n\n### User Info\nThe `UserInfo` object:\n```js\n{\n email: string,\n name: string\n}\n```\n\n#### getUserInfo = () =>\nReturns a Userinfo object pertaining to the logged in user.\n\n```js\nconst userInfo = await AssistantAPIClient.getUserInfo()\n```\n### Selection\nThe `Selection` object:\n```js\n{\n  kindId: string\n  kindName: string\n  id: string\n}\n```\n\n#### getCurrentSelection = () =>\nReturns an Array of `Selection` objects:\n\n```js\nconst {selection} = await AssistantAPIClient.getCurrentSelection();\n```\n\n#### addSelectionChangedListener = async cb =>\nAdds a callback function to be executed upon a valid workspace selection change.\n\nCallback value is an array of Selection objects:\n\n```js\n// Create the selection callback.\nconst selectionCB = ({selection})=>{\n  console.log('Workspace selection has changed.')\n  selection.forEach(i=>{\n    console.log('Kind: ',i.kindName)\n    console.log('Instance Id:',i.id)\n    console.log('Kind Id:',i.kindId)\n  })\n}\n\n// Add the listener.\nAssistantAPIClient.addSelectionChangedListener(selectionCB);\n```\n\nThis function only exists on the Q-Assistant-Client--only enableSelectionChangedNotification is called on the API.\n\n#### removeSelectionChangedListener = async cb =>\nThis will have to be called on a 1:1 basis with addSelectionChangedListener calls if supplying a callback.\n\n```js\nAssistantAPIClient.removeSelectionChangedListener(selectionCB)\n```\n\n**If NOT supplying a callback to this call, all selection changed listeners will be removed.\n\n```js\nAssistantAPIClient.removeSelectionChangedListener()\n```\n\nThis function only exists on the Q-Assistant-Client--only disableSelectionChangedNotification is called on the API.\n\n\n### Services\nThe `Service` object:\n```js\n{\n   id: string,\n   name: string\n   endpointUrl: string,\n   getKinds: () => // Returns [] of Kinds objects\n   getFunctions: () => // Returns [] of Function objects\n}\n```\n\n#### getServiceById = id =>\nThis will return a service that exists within the scope of the workspace.\n** Assistant services will return null. Services outside the scope of the workspace will cause an error to be returned as 'Unable to load a Service from outside of the workspace.'\n\n```js\nconst svc = await AssistantAPIClient.getServiceById(id)\n```\n\n#### createService = id =>\nCreates a service in Q.\n\nNote: This will create the service, but does NOT import it into the workspace.\nYou will need to use `importService` on the Workspace object to import it.\nReturns a promise that resolves\n\n```js\n    const service = {\n      id: ...,\n      name: ...,\n      endpointUrl: ...,\n      serviceType: ...\n    }\n\n    await AssistantAPIClient.createService(service)\n```\n\n#### deleteService = id =>\nDeletes a service from Q.\n\n```js\n    await AssistantAPIClient.deleteService(id)\n```\n\n#### refreshServiceSchema = id =>\nRefreshes a service by fetching its schema. This will also\nreload the service inventory in the currently visible workspace.\n\n```js\nawait AssistantAPIClient.refreshServiceSchema(\"id\")\n```\n\n#### reloadService = id =>\nReloads a service in the inventory in the currently visible workspace.\n\n```js\nawait AssistantAPIClient.reloadService(\"id\")\n```\n\n### Workspace\n\n#### getWorkspace = () =>\nReturns a Workspace object representing the workspace.\n\n```js\nconst ws = await AssistantAPIClient.getWorkspace(id)\n```\n\nNote: The `id` parameter is optional. If it is not supplied, the query\nwill return the current/visible workspace.\n\nThe `Workspace` object:\n\n```js\n\n{\n    id: string,\n    name: string,\n    endpointUrl: string,\n    workspaceServiceId: string,\n    modelServiceId: string,\n    logicServiceId: string,\n\n    //\n    // Locking information\n    //\n    async lockedBy() {\n      // Returns the e-mail address of the user who locked the Workspace, or\n      // null if the Workspace is not currently locked.\n    }\n    async canEdit() {\n      // Returns `true` when the Workspace is not locked, or the current user\n      // owns the lock.\n      // Returns 'false' when the Workspace is locked by a different user.\n    }\n    async setLocked(isLocked) {\n      // Takes a boolean or undefined for `isLocked`.\n      //  `true` locks the Workspace as the current User.\n      //  `false` unlocks the Workspace\n      //  `undefined` causes it to toggle the current locked state.\n      // Returns a Promise that will resolve or reject when the task is done.\n    }\n\n    //\n    // Knowledge Graphs\n    //\n    getActiveGraph: async () => {\n      // Returns the active Graph object.\n      // Returns null if active graph is not of type 'Knowledge Graph', or if an\n      // active graph is deleted, thereby setting active graph to null.\n    },\n    getKnowledgeGraphs: async () => {\n      // Returns [Graph]\n    },\n    // TODO: define input\n    createKnowledgeGraph: input =>\n    // TODO: define input\n    createKnowledgeGraphs: input =>\n\n    //\n    // Services\n    //\n    getImportedServices: async () => {\n      // Returns an array of Service objects that have\n      // been imported into the workspace.\n      // No assistant services will be returned.\n    },\n    getImportedAssistants: async () => {\n      // Returns a list of imported assistants.\n    },\n    importService: serviceId => {\n      // Imports a service by it's ID.\n    },\n    importServices: serviceIds => {\n      // Imports services by their IDs.\n    },\n    removeServices: serviceIds => {\n      // Removes a list of services from the workspace.\n    },\n    removeService: serviceId => {\n      // Removes a service from the workspace.\n    },\n\n    //\n    // Functions\n    //\n    getFunctions: async () => {\n      // Returns an array of functions in the workspace (includes boilerplate).\n    },\n    createFunction: funcData => {\n      // Creates a function and adds it to the graph.\n    }\n    createFunctions: funcData =>{\n      // Creates several functions and adds them to the graph.\n    }\n    updateFunction: funcData => {\n      // Updates a function.\n    },\n    updateFunctions: funcData =>{\n      // Updates functions based on input array.\n    },\n    deleteFunction: funcId => {\n      // Deletes a function by its ID.\n    },\n    getFunctionGraph: funcId => {\n      // Returns a function graph by its ID.\n    }\n\n    //\n    // Kinds\n    //\n    getKinds: async () => {\n      // Returns an array of functions in the workspace (includes boilerplate).\n    },\n    createKind: kindData => {\n      // Currently same input as AssistantAPIClient call.\n    },\n    createKinds: kindData => {\n      // Currently same input as AssistantAPIClient call.\n    },\n    updateKind: kindData => {\n      // Currently same input as AssistantAPIClient call.\n    },\n    updateKinds: kindData => {\n      // Currently same input as AssistantAPIClient call.\n    },\n    deleteKind: kindId => {\n      // Currently same input as AssistantAPIClient call.\n    }\n    // Event Triggers\n    triggerRepairEvent: () => {\n      // Triggers the repair event on a workspace.\n    }\n  };\n}\n```\n\n\n### Graphs\nThe `Graph` object:\n```js\n{\n  id: string,\n  name: string,\n  offsetX: Number,\n  offsetY: Number,\n  zoom: Number,\n  getNodes: async () => {\n      // Returns [Node]\n  },\n\n  addNode: async (type, instance, changeSelection) => {\n      // Returns Node\n  },\n  removeNode: async id => {\n      // Should return nothing or error.\n      // Currently returning [] in all cases.\n  },\n  updateNodeLayout: async (nodeId, { x, y, collapsed }) => {\n  },\n  updateGraphLayout: async ({ offsetX, offsetY, zoom }) => {\n  }\n\n  //\n  // Locking information\n  //\n  async lockedBy() {\n    // Returns the e-mail address of the user who locked the Graph, or null if\n    // the Graph is not currently locked.\n  }\n  async canEdit() {\n    // Returns `true` when the Graph is not locked, or the current user owns the\n    // lock.\n    // Returns 'false' when the Graph is locked by a different user.\n  }\n  async setLocked(isLocked) {\n    // Takes a boolean or undefined for `isLocked`.\n    //  `true` locks the Graph as the current User.\n    //  `false` unlocks the Graph\n    //  `undefined` causes it to toggle the current locked state.\n    // Returns a Promise that will resolve or reject when the task is done.\n  }\n}\n```\n\n#### Getting a graph object:\nGraph objects are obtained through an instance of a Workspace\n\n```js\nconst ag = await ws.getActiveGraph()\n```\n\nor\n\n```js\nconst kgs = await ws.getKnowledgeGraphs()\n```\n\n#### Manipulating Graphs\n\n**Only the active graph may be manipulated.\n\nAll graph manipulations should be ‘visually’ verifiable on the graph itself, i.e., adds/removes/positioning, should all be reflected on the graph itself.\n\nThe `Node` object:\n```js\n{\nid: string\nx: number\ny: number\ncollapsed: boolean\nknowledgeGraphNode {\n  id: string\n  innerKind: Kind\n  innerFunction: Function\n}\n}\n```\n\n#### addNode(type, instance, changeSelection) =>\n\nTakes type (“Function” or “Kind”), instance (the Function or Kind object), and optionally a boolean to indicate whether the selection should be changed to this new node.\n\nReturns the newly created Node object.\n\n```js\nconst node = await ag.addNode('Kind',kind)\n```\n\n#### removeNode(id) =>\n\nTakes the id of Node to be deleted. Returns either undefined or an error.\n\n```js\nawait ag.removeNode(node.id)\n```\n\n#### getNodes() =>\nReturns an array of Node objects from the graph.\n\n```js\nconst nodes = await ag.getNodes()\n```\n\n#### updateNodeLayout: async (nodeId, { x, y, collapsed})=>\nUpdates a Node layout given a node ID and node coordinates (`x` and/or `y`) or a `collapsed` value. x/y values must be a number, and collapsed must be a boolean. Whatever is not specified will remain current.\n\n```js\nag.updateNodeLayout(id,{x:100,y:100,collapsed:true})\n```\n\n#### updateGraphLayout: async ({ offsetX, offsetY, zoom})=>\nUpdates a Graph layout given numerical values for x/y offsets and the zoom.\n\n```js\nag.updateGraphLayout({offsetX:50, offsetY:50, zoom: 70})\n```\n\n### Functions\n\nThe `Function` object:\n```js\n{\n    id: string\n    name: string\n    service {\n      id: string\n      name: string\n    }\n    arguments {\n      id: string\n      name: string\n      type: string\n      modifiers: Array[string]\n      typeKindId:: string\n      kind {\n        id: string\n        name: string\n      }\n    }\n    implementation {\n      id: string\n      entrypoint {\n        id: string\n      }\n      operations {\n        id: string\n        type: string\n        function {\n          id: string\n          name: string\n        }\n        argumentValues {\n          id: string\n          argument {\n            id: string\n          }\n          operation {\n            id: string\n          }\n          argumentRef: string\n        }\n      }\n    }\n    isGenerated: boolean\n    functionType: string\n    graphqlOperationType: string\n    outputType: string\n    outputKindId: string\n    outputModifiers: Array[string]\n    kind {\n      id: string\n      name: string\n    }\n\n    //\n    // Locking information\n    //\n    async lockedBy() {\n      // Returns the e-mail address of the user who locked the Function, or null\n      // if the Function is not currently locked.\n    }\n    async canEdit() {\n      // Returns `true` when the Function is not locked, or the current user\n      // owns the lock.\n      // Returns 'false' when the Function is locked by a different user.\n    }\n    async setLocked(isLocked) {\n      // Takes a boolean or undefined for `isLocked`.\n      //  `true` locks the Function as the current User.\n      //  `false` unlocks the Function\n      //  `undefined` causes it to toggle the current locked state.\n      // Returns a Promise that will resolve or reject when the task is done.\n    }\n}\n```\n\n`FunctionExecutionResult` object:\n```js\n{\n  id: string,\n  result: JSON\n}\n```\n\n#### executeFunction = ( {id, variables, resolve} ) =>\nExecutes a function based on its id, with optional inputs for variables and a resolve string (this specifies the fields to be returned, which must be valid based on the result).\n\nReturns : JSON matching shape of result , unless no sub-selection of fields is required in the execution.\n\nThis following piece of code will execute a Function given a function ID, and pass in variables for ‘example’, requesting back id and name fields.\n\n```js\nconst res = await AssistantAPIClient.executeFunction({functionId: func.id, variables: {\"variableName\": \"variableValue\"}, resolve: \"{ id name }\");\n```\n\n#### createFunction = input =>\nCreates a function based on the input provided.\n\nReturns: the created Function object.\n\n**Using create function will only place the function in the workspace’s inventory--it will not place the function as a node on the Graph. In order to do this, you must pass the created function into the addNode function on the active Graph, making sure to specify ‘Function' as the type.\n\n```js\nconst createFunctionInput = {\n  name:\"yourName\",\n  arguments:[],\n  outputType: \"STRING\",\n  graphqlOperationType:\"QUERY\",\n  functionType: \"CKG\"\n}\n\nconst createdFunction = await AssistantAPIClient.createFunction(createFunctionInput)\n```\n\n#### updateFunction = input =>\nInput is the same for creating a function. It’s important to note that the arguments property will be replaced in it’s entirety with whatever is provided (if a value is provided.\n\nReturns the updated `Function` object.\n\n```js\nconst updatedFunction = await AssistantAPIClient.updateFunction(input);\n```\n\n#### deleteFunction = input =>\nInput is the id of the Function to be deleted. Returns the deleted function as a promise.\n\n```js\nconst deletedFunction = await AssistantAPIClient.deleteFunction('id...');\n```\n\n#### getFunctionById = id =>\nReturns a Function as a promise based on the ID provided.\n\n```js\nconst func = await AssistantAPIClient.getFunctionById('id...');\n```\n\n#### addFunctionExecutionListener = async (id, cb) =>\nAssociates a callback function with the execution of a particular Function. When the Function matching the id parameter is executed, its FunctionExecutionResult object passed to the callback. Returns undefined.\n\nExample function execution callback and listener registration:\n\n```js\nfunction exampleFunctionCB (result){\n  console.log(`Function executed with result:`, result)\n}\n\nAssistantAPIClient.addFunctionExecutionListener('id...', exampleFunctionCB)\n```\n\n#### removeFunctionExecutionListener = async (id, cb) =>\nRemoves a Function execution listener based on the function ID and a reference to the callback function. If no callback is supplied, all listeners associated with the Function ID will be removed. Returns undefined.\n\n```js\nAssistantAPIClient.removeFunctionExecutionListener('id..', exampleFunctionCB)\n```\n\n### Kinds\nThe `Kind` object:\n```js\n{\n    id: string\n    name: string\n    service: {\n      id\n      name\n    }\n    isGenerated: boolean\n    schema {\n      id: string\n      name: string\n      type: string\n      typeKindId: string\n      modifiers: Array[string]\n      kind {\n        id: string\n        name: string\n      }\n    }\n}\n```\n\n#### createKind = input =>\nCreates a Kind based on an input object. Returns a promise that resolves to the created Kind object.\n\n```js\nconst kindInput = {\n name: \"someKind\",\n schema:[\n  { name: \"someField1\", type: STRING },\n  { name: \"someField2\", type: STRING }\n ]\n}\n\nconst newKind = await AssistantAPIClient.createKind(kindInput)\n```\n\n#### createKinds = input =>\nA plural version of `createKind` accepting an array of input objects.\nReturns a promise that resolves to an array of created Kind objects.\n\n```js\nconst kindsInput = [{\n name: \"someKind\",\n schema:[\n  { name: \"someField1\", type: STRING },\n  { name: \"someField2\", type: STRING }\n ]\n}, ...]\n\nconst newKinds = await AssistantAPIClient.createKinds(kindsInput)\n```\n\n\n#### updateKind = input =>\nUpdates a Kind based on an input object.\n\nUpdate Semantics: Only properties specified will be updated. If updating the schema, the entire schema must be specified as it will be replaced in its entirety.\n\nReturns a promise that resolves to the updated `Kind` object.\n\n```js\nconst updated = await AssistantAPIClient.updateKind(input)\n```\n\n#### deleteKind = input =>\nDeletes a Kind given a kind ID.\n\n```js\nconst deleted = await AssistantAPIClient.deleteKind(input)\n```\n\n#### getKindById = id =>\nReturns a promise that resolves to a Kind object given the specified kind ID.\n\nIn v3.2.2, any requested non-system kinds will be returned.\nIn v3.2.1, only kinds in the workspace or those of imported services will be returned.\n\n```js\nconst kind = await AssistantAPIClient.getKindById(id)\n```\n\n#### getKindsById = ids =>\nReturns a promise that resolves to an array of Kind objects given an array of kind IDs. Only kinds in the workspace or those of imported services will be returned.\n\n```js\nconst ids = [\"...\",\"...\",...]\nconst kind = await AssistantAPIClient.getKindsById(ids)\n```\n\n#### getAllReferencedKinds = input =>\nRecursively collects all kinds that are referenced in a kind's schema, starting\nwith a kind ID. For example if the ID of kind A is supplied as an input, and Kind `A` contains a field of type Kind `B`, and `B` contains a field of type Kind `C`,\nan array containing the kinds objects for `A`, `B`, `C` will be returned (as a promise).\n\n```js\nconst initialId = [\"...\"]\nconst kinds = await AssistantAPIClient.getAllReferencedKinds({\n          ids: initialId\n        })\n```\n\n\n### Inventory\n\nThe `InventoryChanged` object:\n```js\n{\n  kinds: {\n    adds: [DiffItem]\n    deletes: [DiffItem]\n    updates: [DiffItem]\n  }\n  functions:{\n    adds: [DiffItem]\n    deletes: [DiffItem]\n    updates: [DiffItem]\n  }\n  services: {\n    adds: [DiffItem]\n    deletes: [DiffItem]\n    updates: [DiffItem]\n  }\n}\n```\n\nThe `DiffItem` object:\n```js\n{\n  id: string,\n  name: string\n}\n```\n\n#### addInventoryChangedListener = async cb =>\nRegisters a callback function with the inventory changed event. When workspace inventory changes the callback function will be called with the InventoryChangedobject. Returns undefined.\n\n**Use-case note: an ‘update’ diff for inventory services is unlikely in general usage.\n\n```js\nconst inventoryCB = ({diff}) => {\n  if(diff.kinds) console.log('KINDS CHANGED',diff.kinds)\n  if(diff.functions) console.log('FUNCTIONS CHANGED', diff.functions)\n  if(diff.services) console.log('SERVICES CHANGED',diff.services)\n}\n\nAssistantAPIClient.addInventoryChangedListener(inventoryCB)\n```\n\nThis function exists on the Q-Assisant-Client only--only enableSelectionChangedNotification is used on the API side.\n\n#### removeInventoryChangedListener = async cb =>\nRemoves an inventory changed listener given the referenced callback. If no callback is specified, all listeners will be removed. Returns undefined.\n\n```js\nAssistantAPIClient.removeInventoryChangedListener(inventoryCB)\n```\n\nThis function exists on the Q-Assisant-Client only--only disableSelectionChangedNotification is used on the API side.\n\n#### moveKindsAndFunctions = (originId, targetId, kindIds, functionIds) =>\nMoves a collection of Kinds and Functions from the origin Workspace to the target Workspace.\n\n```js\n  await AssistantAPIClient.moveKindsAndFunctions(\n    originWorkspaceId,\n    targetId,\n    kindIds,\n    functionIds\n  );\n```\n\n### Locking Changed Event\n\nAn event is triggered when the locked state of the currently active Workspace or\nits Knowledge Graphs and Functions change.\n\nThe `LockingChanged` object:\n```js\n{\n  workspaces: [LockItem],\n  knowledgeGraphs: [LockItem],\n  functions: [LockItem]\n}\n```\n\nThe `LockItem` object:\n```js\n{\n  id: string\n  lockedBy: string\n}\n```\n\n#### addLockingChangedListener = cb =>\n\nRegisters a callback function with the locking changed event. When the currently\nactive Workspace or its Knowledge Graphs and Functions change the callback\nfunction will be called with the `LockingChanged` object. Returns undefined.\n\n```js\nconst lockingChangedCB = ({ locks }) => {\n  if(locks.workspace) console.log('WORKSPACES CHANGED', locks.workspace);\n  if(locks.knowledgeGraphs) console.log('KNOWLEDGE GRAPHS CHANGED', locks.knowledgeGraphs);\n  if(locks.functions) console.log('FUNCTIONS CHANGED', locks.functions);\n}\n\nAssistantAPIClient.addLockingChangedListener(lockingChangedCB);\n```\n\n#### removeLockingChangedListener = cb =>\n\nRemoves an locking changed listener given the referenced callback. If no\ncallback is specified, all listeners will be removed. Returns undefined.\n\n```js\nAssistantAPIClient.removeLockingChangedListener(lockingChangedCB)\n```\n\n## Troubleshooting Assistant Issues\n### Assistant root file has loaded, but not other content\nObserving in the browser's dev tools that some resources have loaded correctly (usually the root), but other's haven't (usually nested files or chunks), is indicative of a failure of Q Gateway to proxy due to not having a 'relative' path structure.\n\n### You are seeing post-robot `NO ACK` errors in the console.\nThese errors stem from a failed acknowledgement for a call either between the client and the API or vice-versa. Here, this means that the web app 'window' (the assistant) cannot communicate with, or access, the 'window.parent' (Maana K-Portal) object.\n\nCommonly, these will stem from the 'window' (the assistant) not being loaded or in a loadable state, which means the API will not receive an acknowledgement when it fires an event.\n\nImproper CORS configuration is also a common culprit (also verify if using docker or nginx that your proxying and networking is configured correctly to allow communication and to accout for CORS).","readmeFilename":"README.md","gitHead":"2b2b176f070534a46dd9e002d8ee8052bf2bfc90","_id":"@io-maana/q-assistant-client@3.3.0-beta.5","_nodeVersion":"12.19.0","_npmVersion":"6.14.8","dist":{"integrity":"sha512-RuES0SRu2PcFAiuZP8QcxW5XeLScMVjiC27R8eYNk5AW7w47LOUrVLiw0fpVZHjYYdcdw5sAE3weluer8gP+Vw==","shasum":"db95bc6666220f03cc23d5ce9e7c1d7bc210e12b","tarball":"https://registry.npmjs.org/@io-maana/q-assistant-client/-/q-assistant-client-3.3.0-beta.5.tgz","fileCount":38,"unpackedSize":244845,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJfvZerCRA9TVsSAnZWagAAzI8QAIDOReJ1AX1I/t2TrxVw\nM299qgvSWlBUdNOielpfPY7bhmahJkn5bTlbQ8d2T6hAtBTIJn8Mpl2223g8\nxDG751eCEeeFI/u/IaB0NX1kmN5d7CLhsaQdfqkn/TeOwWTxuty9vkrfn3lr\ni9O/MSKg3iCstfZLqYTx7t/SfUdBHPD2Mgkl7YIE7QWZYiWzxEEYXKSDVFta\nNMRsJxKe+hF5MJiyxERCZnkBFfoEQhsTXswAMEJ0NLVkxtjuJ7Qc3qp/jwoN\nJqCwBSXiJ8bAkzxiJ3TyHoYKBqE3ObqAn4V8OUnQfJ2Rif1hn942JgZGdeUF\nlJCzlyEjLQynbd3Q6h0HzfkGIQjSYsZva1PcH9Gbhwv+EHvpI2h4E9EbOG6O\nDX9jV78wEVNuMiaOzM8AG3KUcLfR0AnstnxwoG/+a2vK9FwWBLzb0zlFmmXS\nFgcty3kx40E4Ju8l69u5MrkH2ROL9poFriGltdb3Mdm/9T+Z67Vp80u/5oaw\nwlH2V0+fCs3T3jsZgbzgGnWxIxlzQYpX36hK6Wyc4NqG9A1UDntYiysxBm9Q\n95MHt8vcAGCVSI40eVusOw5Zo7O2iWbN4LdD2yxUd3/DtNo9pmqCSmQEs7jX\n0tzxH9DrZ8Cfny5kWeJ3u55N/rzciKQvtHlElpSs30AeXsbFO5sxtGK78Hks\naE70\r\n=Xowh\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIGklDhDx0gMtbaNPSWLD5v7CtuESh+6/Hi9GralewZaTAiEA/1s54OJ4sKhIKrc9KUOk6SR17fj/r5oRkmanZZRb3uQ="}]},"_npmUser":{"name":"teamcitymaana","email":"teamcity@maana.io"},"directories":{},"maintainers":[{"name":"dlsmaana","email":"dlewissandy@maana.io"},{"name":"witt3rd","email":"witt3rd@witt3rd.com"},{"name":"bzvetey","email":"bzvestey@gmail.com"},{"name":"abatyuk","email":"andrey@maana.io"},{"name":"rpovey","email":"rob@maana.io"},{"name":"teamcitymaana","email":"teamcity@maana.io"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/q-assistant-client_3.3.0-beta.5_1606260650694_0.5444888432522212"},"_hasShrinkwrap":false},"3.3.0-beta.6":{"name":"@io-maana/q-assistant-client","version":"3.3.0-beta.6","description":"JavaScript package to streamline communication between an assistant and the Maana Q Assistant API.","main":"build/index.js","types":"build/index.d.ts","exports":{"./":"./build/"},"scripts":{"build":"npm run build:ts && npm run build:doc","build:ts":"tsc --build tsconfig.json","build:doc":"typedoc","prepack":"npm run build","test":"echo \"Error: no test specified\" && exit 1","format":"prettier --write \"src/**/*.js\""},"repository":{"type":"git","url":"git+https://github.com/maana-io/q-assistant-client.git"},"keywords":["Maana","Q"],"author":{"name":"Logan Gore @ Maana.io"},"license":"MIT","bugs":{"url":"https://github.com/maana-io/q-assistant-client/issues"},"homepage":"https://github.com/maana-io/q-assistant-client#readme","dependencies":{"core-js":"3.6.4","post-robot":"10.0.29"},"devDependencies":{"@types/node":"^14.14.2","@types/post-robot":"^10.0.0","prettier":"2.0.5","typedoc":"^0.19.2","typedoc-plugin-markdown":"^3.0.11","typescript":"^3.9.5"},"readme":"# q-assistant-client\nA lightweight JavaScript client for Maana-Q Assistant developers that wraps post-message communication between an embedded Maana-Q assistant and the Maana-Q UI.\n\nYou can find the [API Documentation here](docs/README.md).\n\n## Abstract\nThe Q-Assistant-Client is intented to be used in a web application being leveraged as a Maana Q assistant (embedded as an iframe).\nThis assistant client will facilitate communication between the assistant and the parent frame.\nThe client provides a rich, asynchronous experience over what would otherwise be 'fire-and-forget'-style messaging\nvia post-post message communication.\n\n## Requirements and Assumptions\n\n### Post-Robot Library\nThe Maana Knowledge Portal (KPortal) uses the kraken/post-robot library [kraken/post-robot](https://github.com/krakenjs/post-robot) to enrich the communication with the assistant. Post-robot allows for asynchronous, promise-based request/response style behavior between the assistant and the assistant API.\n\nThe API requires that the client use the post-robot library. This assistant-client library is the easiest way to achieve this, and also adds a fair amount of 'sugar' to the process to improve developer productivity. Developers could, however, use post-robot directly in their own client implementation.\n\n### Maana-Gateway Proxy Requirements\nThe Maana-Gateway service requires relative paths (paths relative to the root) in the assistant web application in order to proxy the application and its content. For create-react-apps, for instance, this means setting \"homepage\" to \".\" in the package.json file.\n\n## Singleton Instance\nThe client is exported as a singleton to avoid duplicate registration on event listeners.\nYou can import the instance like this:\n\n```js\nimport AssistantAPIClient from '@io-maana/q-assistant-client';\n```\n\nFunction calls can be made against the client instance like any other javascript object. They are all async.\n\n```js\nconst workspace = await AssistantAPIClient.getWorkspace();\nconsole.log(\"Workspace:\", workspace)\n```\n\n## Dependencies\nPost-Robot\nhttps://github.com/krakenjs/post-robot\n\nPost-robot is used to provide a richer communication layer atop post-message.\n\n## Versioning\nThe Maana Q Assistant Client does not follow semantic versioning. Its versions\ntrack the releases of the Maana Q platform.\n\n## Examples\n@TODO Logan\n\n\n## Changes in v3.2.2\nImprovements in v3.2.2\n- Assistant State Management: WORKING, IDLE\n- Background Messaging/Eventing\n- Render Modes: BACKGROUND, DISPLAY\n- Expansion of Workspace object capabilities\n- Error Reporting\n- Repair Event\n- Plural versions of calls such as updateKind(s) to improve performance and developer experience.\n- InventoryChanged diffing is fully granular in v3.2.2--limitations\nin v3.2.1 only fired the Function diff for changes in Function name.\n\n### Deprecation\nThe following surface area IS removed from the\nclient in v3.2.2, and IS deprecated in the API:\n- AssistantAPIClient.enableSelectionChangedNotification\n- AssistantAPIClient.disableSelectionChangedNotification\n- AssistantAPIClient.enableInventoryChangedNotification\n- AssistantAPIClient.disableInventoryChangedNotification\n\nThe following surface area WILL BE removed from\nthe client in v3.2.4, and WILL BE deprecated in the API:\n- AssistantAPIClient.updateFunction (expected move to Workspace object)\n- AssistantAPIClient.updateKind (expected move to Workspace object)\n- AssistantAPIClient.deleteKind (expected move to Workspace object)\n- AssistantAPIClient.deleteFunction (expected move to Workspace object)\n\n## API Documentation\nMore information in the [API File](./API.md)\n\n### Assistant Render Mode\nAn assistant's render mode refers to whether it is being displayed in a visible manner to the user. As of v3.2.2, assistants are not closed when they are out of view.\nAll assistants will be loaded and kept in `BACKGROUND` render mode until they are\nplaced in the assistant panel, at which point the `DISPLAY` render mode event will be fired.\n\nNote: Assistants will receive all notifications/events while in BACKGROUND mode.\n\nDesign Consideration: It will be up to the developer to determine how state and resource use will be managed while an assistant is operating between BACKGROUND and DISPLAY modes.\n\n#### addRenderModeChangedListener = (cb) =>\nA listener to receive push events as to the assitant's render mode being changed.\n\n```js\nfunction handleRenderModeChanged(renderMode){\n  if (renderMode === 'DISPLAY'){\n    // Assistant is visible\n  } else {\n    // Assistant is not visible and running in background.\n  }\n}\n\nAssistantAPIClient.addRenderModeChangedListener(handleRenderModeChanged)\n\n```\n\n#### removeRenderModeChangedListener = (cb) =>\nRemoves the renderModeChanged listener by reference, or if no callback function reference is provided, it removes all listeners.\n\n#### getRenderMode = () =>\nReturns the current assistant render mode.\n\n```js\nconst renderMode = await AssistantAPIClient.getRenderMode()\n\nif (renderMode === 'DISPLAY'){\n  // Assistant is visible\n} else {\n  // Assistant is not visible and running in background.\n}\n\n```\n\n### Repair\nAssistants may get into situations where they are either out of sync with the Maana Q UI, or in a failure state. Assistants should be able to recover from these states.\n\nThe repair event functionality added in v3.2.2 is designed to notify the assistant that it must repair itself. This could mean a resync with its resources on the workspace or externally or, for some assistants, nothing at all.\n\nWhen is repair triggered?\nEither manually by a user clicking 'repair workspace' under the\nassistant inventory panel, or upon a workspace clone event. An assistant will be expected to handle either scenario.\n\nPerformance Consideration:\nFor some assistants, repair might involve 'introspecting'\nand processing the current workspace or Q system resources. This could be very resource intensive. Make sure you review this API guide to have an idea of what tools are\navailable to get the best results. It's always a good idea to check performance of repair on a large workspace and ensure necessary optimizations have been made.\n\nDesign Consideration:\nMake your workflows modular enough to be reused between repair and normal usage if possible.\n\n#### addRepairListener (cb) =>\n```js\n\nAssistantAPIClient.addRepairListener(()=>{\n  // Self-heal\n})\n\n```\n\nRecommended Usage: A repair process should be wrapped in the try/catch/finally flow shown in the `setAssistantState` API call to provide the user assistant-state and error updates as well as pause `inventoryChanged` notifications during repair (if the assistant has subscribed).\n\n#### removeRepairListener = (cb) =>\nRemoves the repair listener by reference, or if no callback function reference is provided, it removes all listeners.\n\n### User-facing Error Handling\n\n#### reportError (error) =>\nReports an error to the UI to be displayed in the assistant's error log in the\ninventory panel. This call is not disruptive and designed to operated independently of other assistant operations, such as state management. See `setAssistantState` in the next section.\n\nRecommended usage: use this functionality where it would futher the user experience\nto show the user an error and it's cause. Do not use this where things will be retried,\ncleaned up automatically, or are not relevant to the user.\n\n```js\ntry{\n  // Do work\n} catch(e) {\n  AssistantAPIClient.reportError(e)\n}\n```\n\n### State management\n\n#### clearState = () =>\nThis will remove all callbacks from all listeners.\n\n```js\nawait AssistantAPIClient.clearState()\n```\n\n#### setAssistantState = (state) =>\nThis sets the current state of the assistant using the\n`AssistantState` enum. Setting a state of `WORKING` will\ncreate the 'working' status spinner in the Assistant\nInventory Panel in the Maana Q UI. Conversely, setting an `IDLE` state will\nremove the spinner. This adds to user experience by informing users of the\nstatus of operations.\n\n```js\nimport {\n  default as AssistantAPIClient,\n  AssistantState\n} from '@io-maana/q-assistant-client'\n\n...\n\nAssistantAPIClient.setAssistantState(AssistantState.WORKING)\n\n...\n\nAssistantAPIClient.setAssistantState(AssistantState.IDLE)\n\n```\nUI User Prompt: If the assistant is in a `WORKING` state, the Maana Q UI will\nwarn the user before leaving the workspace.\n\nNOTE: while an assistant is in a working state, it will\nnot receive `inventoryChanged` events--an aggregated inventory diff\nwill be sent once the assistant is set back to `IDLE`.\n\nRecommended usage: Control states at a high level using try/catch/finally\nflow incorporating the `reportError` API call.\n\n```js\ntry{\n  AssistantAPIClient.setAssistantState(AssistantState.WORKING)\n  // Do work, await high-level tasks, etc.\n} catch(e) {\n  AssistantAPIClient.reportError(e)\n} finally{\n  AssistantAPIClient.setAssistantState(AssistantState.IDLE)\n}\n```\n\n#### AssistantState (enum)\nContains the valid assistant states: `IDLE` or `WORKING`.\n\nMust be imported in addition to the AssistantAPIClient:\n\n```js\nimport {\n  default as AssistantAPIClient,\n  AssistantState\n} from '@io-maana/q-assistant-client'\n```\n\n\n### User Info\nThe `UserInfo` object:\n```js\n{\n email: string,\n name: string\n}\n```\n\n#### getUserInfo = () =>\nReturns a Userinfo object pertaining to the logged in user.\n\n```js\nconst userInfo = await AssistantAPIClient.getUserInfo()\n```\n### Selection\nThe `Selection` object:\n```js\n{\n  kindId: string\n  kindName: string\n  id: string\n}\n```\n\n#### getCurrentSelection = () =>\nReturns an Array of `Selection` objects:\n\n```js\nconst {selection} = await AssistantAPIClient.getCurrentSelection();\n```\n\n#### addSelectionChangedListener = async cb =>\nAdds a callback function to be executed upon a valid workspace selection change.\n\nCallback value is an array of Selection objects:\n\n```js\n// Create the selection callback.\nconst selectionCB = ({selection})=>{\n  console.log('Workspace selection has changed.')\n  selection.forEach(i=>{\n    console.log('Kind: ',i.kindName)\n    console.log('Instance Id:',i.id)\n    console.log('Kind Id:',i.kindId)\n  })\n}\n\n// Add the listener.\nAssistantAPIClient.addSelectionChangedListener(selectionCB);\n```\n\nThis function only exists on the Q-Assistant-Client--only enableSelectionChangedNotification is called on the API.\n\n#### removeSelectionChangedListener = async cb =>\nThis will have to be called on a 1:1 basis with addSelectionChangedListener calls if supplying a callback.\n\n```js\nAssistantAPIClient.removeSelectionChangedListener(selectionCB)\n```\n\n**If NOT supplying a callback to this call, all selection changed listeners will be removed.\n\n```js\nAssistantAPIClient.removeSelectionChangedListener()\n```\n\nThis function only exists on the Q-Assistant-Client--only disableSelectionChangedNotification is called on the API.\n\n\n### Services\nThe `Service` object:\n```js\n{\n   id: string,\n   name: string\n   endpointUrl: string,\n   getKinds: () => // Returns [] of Kinds objects\n   getFunctions: () => // Returns [] of Function objects\n}\n```\n\n#### getServiceById = id =>\nThis will return a service that exists within the scope of the workspace.\n** Assistant services will return null. Services outside the scope of the workspace will cause an error to be returned as 'Unable to load a Service from outside of the workspace.'\n\n```js\nconst svc = await AssistantAPIClient.getServiceById(id)\n```\n\n#### createService = id =>\nCreates a service in Q.\n\nNote: This will create the service, but does NOT import it into the workspace.\nYou will need to use `importService` on the Workspace object to import it.\nReturns a promise that resolves\n\n```js\n    const service = {\n      id: ...,\n      name: ...,\n      endpointUrl: ...,\n      serviceType: ...\n    }\n\n    await AssistantAPIClient.createService(service)\n```\n\n#### deleteService = id =>\nDeletes a service from Q.\n\n```js\n    await AssistantAPIClient.deleteService(id)\n```\n\n#### refreshServiceSchema = id =>\nRefreshes a service by fetching its schema. This will also\nreload the service inventory in the currently visible workspace.\n\n```js\nawait AssistantAPIClient.refreshServiceSchema(\"id\")\n```\n\n#### reloadService = id =>\nReloads a service in the inventory in the currently visible workspace.\n\n```js\nawait AssistantAPIClient.reloadService(\"id\")\n```\n\n### Workspace\n\n#### getWorkspace = () =>\nReturns a Workspace object representing the workspace.\n\n```js\nconst ws = await AssistantAPIClient.getWorkspace(id)\n```\n\nNote: The `id` parameter is optional. If it is not supplied, the query\nwill return the current/visible workspace.\n\nThe `Workspace` object:\n\n```js\n\n{\n    id: string,\n    name: string,\n    endpointUrl: string,\n    workspaceServiceId: string,\n    modelServiceId: string,\n    logicServiceId: string,\n\n    //\n    // Locking information\n    //\n    async lockedBy() {\n      // Returns the e-mail address of the user who locked the Workspace, or\n      // null if the Workspace is not currently locked.\n    }\n    async canEdit() {\n      // Returns `true` when the Workspace is not locked, or the current user\n      // owns the lock.\n      // Returns 'false' when the Workspace is locked by a different user.\n    }\n    async setLocked(isLocked) {\n      // Takes a boolean or undefined for `isLocked`.\n      //  `true` locks the Workspace as the current User.\n      //  `false` unlocks the Workspace\n      //  `undefined` causes it to toggle the current locked state.\n      // Returns a Promise that will resolve or reject when the task is done.\n    }\n\n    //\n    // Knowledge Graphs\n    //\n    getActiveGraph: async () => {\n      // Returns the active Graph object.\n      // Returns null if active graph is not of type 'Knowledge Graph', or if an\n      // active graph is deleted, thereby setting active graph to null.\n    },\n    getKnowledgeGraphs: async () => {\n      // Returns [Graph]\n    },\n    // TODO: define input\n    createKnowledgeGraph: input =>\n    // TODO: define input\n    createKnowledgeGraphs: input =>\n\n    //\n    // Services\n    //\n    getImportedServices: async () => {\n      // Returns an array of Service objects that have\n      // been imported into the workspace.\n      // No assistant services will be returned.\n    },\n    getImportedAssistants: async () => {\n      // Returns a list of imported assistants.\n    },\n    importService: serviceId => {\n      // Imports a service by it's ID.\n    },\n    importServices: serviceIds => {\n      // Imports services by their IDs.\n    },\n    removeServices: serviceIds => {\n      // Removes a list of services from the workspace.\n    },\n    removeService: serviceId => {\n      // Removes a service from the workspace.\n    },\n\n    //\n    // Functions\n    //\n    getFunctions: async () => {\n      // Returns an array of functions in the workspace (includes boilerplate).\n    },\n    createFunction: funcData => {\n      // Creates a function and adds it to the graph.\n    }\n    createFunctions: funcData =>{\n      // Creates several functions and adds them to the graph.\n    }\n    updateFunction: funcData => {\n      // Updates a function.\n    },\n    updateFunctions: funcData =>{\n      // Updates functions based on input array.\n    },\n    deleteFunction: funcId => {\n      // Deletes a function by its ID.\n    },\n    getFunctionGraph: funcId => {\n      // Returns a function graph by its ID.\n    }\n\n    //\n    // Kinds\n    //\n    getKinds: async () => {\n      // Returns an array of functions in the workspace (includes boilerplate).\n    },\n    createKind: kindData => {\n      // Currently same input as AssistantAPIClient call.\n    },\n    createKinds: kindData => {\n      // Currently same input as AssistantAPIClient call.\n    },\n    updateKind: kindData => {\n      // Currently same input as AssistantAPIClient call.\n    },\n    updateKinds: kindData => {\n      // Currently same input as AssistantAPIClient call.\n    },\n    deleteKind: kindId => {\n      // Currently same input as AssistantAPIClient call.\n    }\n    // Event Triggers\n    triggerRepairEvent: () => {\n      // Triggers the repair event on a workspace.\n    }\n  };\n}\n```\n\n\n### Graphs\nThe `Graph` object:\n```js\n{\n  id: string,\n  name: string,\n  offsetX: Number,\n  offsetY: Number,\n  zoom: Number,\n  getNodes: async () => {\n      // Returns [Node]\n  },\n\n  addNode: async (type, instance, changeSelection) => {\n      // Returns Node\n  },\n  removeNode: async id => {\n      // Should return nothing or error.\n      // Currently returning [] in all cases.\n  },\n  updateNodeLayout: async (nodeId, { x, y, collapsed }) => {\n  },\n  updateGraphLayout: async ({ offsetX, offsetY, zoom }) => {\n  }\n\n  //\n  // Locking information\n  //\n  async lockedBy() {\n    // Returns the e-mail address of the user who locked the Graph, or null if\n    // the Graph is not currently locked.\n  }\n  async canEdit() {\n    // Returns `true` when the Graph is not locked, or the current user owns the\n    // lock.\n    // Returns 'false' when the Graph is locked by a different user.\n  }\n  async setLocked(isLocked) {\n    // Takes a boolean or undefined for `isLocked`.\n    //  `true` locks the Graph as the current User.\n    //  `false` unlocks the Graph\n    //  `undefined` causes it to toggle the current locked state.\n    // Returns a Promise that will resolve or reject when the task is done.\n  }\n}\n```\n\n#### Getting a graph object:\nGraph objects are obtained through an instance of a Workspace\n\n```js\nconst ag = await ws.getActiveGraph()\n```\n\nor\n\n```js\nconst kgs = await ws.getKnowledgeGraphs()\n```\n\n#### Manipulating Graphs\n\n**Only the active graph may be manipulated.\n\nAll graph manipulations should be ‘visually’ verifiable on the graph itself, i.e., adds/removes/positioning, should all be reflected on the graph itself.\n\nThe `Node` object:\n```js\n{\nid: string\nx: number\ny: number\ncollapsed: boolean\nknowledgeGraphNode {\n  id: string\n  innerKind: Kind\n  innerFunction: Function\n}\n}\n```\n\n#### addNode(type, instance, changeSelection) =>\n\nTakes type (“Function” or “Kind”), instance (the Function or Kind object), and optionally a boolean to indicate whether the selection should be changed to this new node.\n\nReturns the newly created Node object.\n\n```js\nconst node = await ag.addNode('Kind',kind)\n```\n\n#### removeNode(id) =>\n\nTakes the id of Node to be deleted. Returns either undefined or an error.\n\n```js\nawait ag.removeNode(node.id)\n```\n\n#### getNodes() =>\nReturns an array of Node objects from the graph.\n\n```js\nconst nodes = await ag.getNodes()\n```\n\n#### updateNodeLayout: async (nodeId, { x, y, collapsed})=>\nUpdates a Node layout given a node ID and node coordinates (`x` and/or `y`) or a `collapsed` value. x/y values must be a number, and collapsed must be a boolean. Whatever is not specified will remain current.\n\n```js\nag.updateNodeLayout(id,{x:100,y:100,collapsed:true})\n```\n\n#### updateGraphLayout: async ({ offsetX, offsetY, zoom})=>\nUpdates a Graph layout given numerical values for x/y offsets and the zoom.\n\n```js\nag.updateGraphLayout({offsetX:50, offsetY:50, zoom: 70})\n```\n\n### Functions\n\nThe `Function` object:\n```js\n{\n    id: string\n    name: string\n    service {\n      id: string\n      name: string\n    }\n    arguments {\n      id: string\n      name: string\n      type: string\n      modifiers: Array[string]\n      typeKindId:: string\n      kind {\n        id: string\n        name: string\n      }\n    }\n    implementation {\n      id: string\n      entrypoint {\n        id: string\n      }\n      operations {\n        id: string\n        type: string\n        function {\n          id: string\n          name: string\n        }\n        argumentValues {\n          id: string\n          argument {\n            id: string\n          }\n          operation {\n            id: string\n          }\n          argumentRef: string\n        }\n      }\n    }\n    isGenerated: boolean\n    functionType: string\n    graphqlOperationType: string\n    outputType: string\n    outputKindId: string\n    outputModifiers: Array[string]\n    kind {\n      id: string\n      name: string\n    }\n\n    //\n    // Locking information\n    //\n    async lockedBy() {\n      // Returns the e-mail address of the user who locked the Function, or null\n      // if the Function is not currently locked.\n    }\n    async canEdit() {\n      // Returns `true` when the Function is not locked, or the current user\n      // owns the lock.\n      // Returns 'false' when the Function is locked by a different user.\n    }\n    async setLocked(isLocked) {\n      // Takes a boolean or undefined for `isLocked`.\n      //  `true` locks the Function as the current User.\n      //  `false` unlocks the Function\n      //  `undefined` causes it to toggle the current locked state.\n      // Returns a Promise that will resolve or reject when the task is done.\n    }\n}\n```\n\n`FunctionExecutionResult` object:\n```js\n{\n  id: string,\n  result: JSON\n}\n```\n\n#### executeFunction = ( {id, variables, resolve} ) =>\nExecutes a function based on its id, with optional inputs for variables and a resolve string (this specifies the fields to be returned, which must be valid based on the result).\n\nReturns : JSON matching shape of result , unless no sub-selection of fields is required in the execution.\n\nThis following piece of code will execute a Function given a function ID, and pass in variables for ‘example’, requesting back id and name fields.\n\n```js\nconst res = await AssistantAPIClient.executeFunction({functionId: func.id, variables: {\"variableName\": \"variableValue\"}, resolve: \"{ id name }\");\n```\n\n#### createFunction = input =>\nCreates a function based on the input provided.\n\nReturns: the created Function object.\n\n**Using create function will only place the function in the workspace’s inventory--it will not place the function as a node on the Graph. In order to do this, you must pass the created function into the addNode function on the active Graph, making sure to specify ‘Function' as the type.\n\n```js\nconst createFunctionInput = {\n  name:\"yourName\",\n  arguments:[],\n  outputType: \"STRING\",\n  graphqlOperationType:\"QUERY\",\n  functionType: \"CKG\"\n}\n\nconst createdFunction = await AssistantAPIClient.createFunction(createFunctionInput)\n```\n\n#### updateFunction = input =>\nInput is the same for creating a function. It’s important to note that the arguments property will be replaced in it’s entirety with whatever is provided (if a value is provided.\n\nReturns the updated `Function` object.\n\n```js\nconst updatedFunction = await AssistantAPIClient.updateFunction(input);\n```\n\n#### deleteFunction = input =>\nInput is the id of the Function to be deleted. Returns the deleted function as a promise.\n\n```js\nconst deletedFunction = await AssistantAPIClient.deleteFunction('id...');\n```\n\n#### getFunctionById = id =>\nReturns a Function as a promise based on the ID provided.\n\n```js\nconst func = await AssistantAPIClient.getFunctionById('id...');\n```\n\n#### addFunctionExecutionListener = async (id, cb) =>\nAssociates a callback function with the execution of a particular Function. When the Function matching the id parameter is executed, its FunctionExecutionResult object passed to the callback. Returns undefined.\n\nExample function execution callback and listener registration:\n\n```js\nfunction exampleFunctionCB (result){\n  console.log(`Function executed with result:`, result)\n}\n\nAssistantAPIClient.addFunctionExecutionListener('id...', exampleFunctionCB)\n```\n\n#### removeFunctionExecutionListener = async (id, cb) =>\nRemoves a Function execution listener based on the function ID and a reference to the callback function. If no callback is supplied, all listeners associated with the Function ID will be removed. Returns undefined.\n\n```js\nAssistantAPIClient.removeFunctionExecutionListener('id..', exampleFunctionCB)\n```\n\n### Kinds\nThe `Kind` object:\n```js\n{\n    id: string\n    name: string\n    service: {\n      id\n      name\n    }\n    isGenerated: boolean\n    schema {\n      id: string\n      name: string\n      type: string\n      typeKindId: string\n      modifiers: Array[string]\n      kind {\n        id: string\n        name: string\n      }\n    }\n}\n```\n\n#### createKind = input =>\nCreates a Kind based on an input object. Returns a promise that resolves to the created Kind object.\n\n```js\nconst kindInput = {\n name: \"someKind\",\n schema:[\n  { name: \"someField1\", type: STRING },\n  { name: \"someField2\", type: STRING }\n ]\n}\n\nconst newKind = await AssistantAPIClient.createKind(kindInput)\n```\n\n#### createKinds = input =>\nA plural version of `createKind` accepting an array of input objects.\nReturns a promise that resolves to an array of created Kind objects.\n\n```js\nconst kindsInput = [{\n name: \"someKind\",\n schema:[\n  { name: \"someField1\", type: STRING },\n  { name: \"someField2\", type: STRING }\n ]\n}, ...]\n\nconst newKinds = await AssistantAPIClient.createKinds(kindsInput)\n```\n\n\n#### updateKind = input =>\nUpdates a Kind based on an input object.\n\nUpdate Semantics: Only properties specified will be updated. If updating the schema, the entire schema must be specified as it will be replaced in its entirety.\n\nReturns a promise that resolves to the updated `Kind` object.\n\n```js\nconst updated = await AssistantAPIClient.updateKind(input)\n```\n\n#### deleteKind = input =>\nDeletes a Kind given a kind ID.\n\n```js\nconst deleted = await AssistantAPIClient.deleteKind(input)\n```\n\n#### getKindById = id =>\nReturns a promise that resolves to a Kind object given the specified kind ID.\n\nIn v3.2.2, any requested non-system kinds will be returned.\nIn v3.2.1, only kinds in the workspace or those of imported services will be returned.\n\n```js\nconst kind = await AssistantAPIClient.getKindById(id)\n```\n\n#### getKindsById = ids =>\nReturns a promise that resolves to an array of Kind objects given an array of kind IDs. Only kinds in the workspace or those of imported services will be returned.\n\n```js\nconst ids = [\"...\",\"...\",...]\nconst kind = await AssistantAPIClient.getKindsById(ids)\n```\n\n#### getAllReferencedKinds = input =>\nRecursively collects all kinds that are referenced in a kind's schema, starting\nwith a kind ID. For example if the ID of kind A is supplied as an input, and Kind `A` contains a field of type Kind `B`, and `B` contains a field of type Kind `C`,\nan array containing the kinds objects for `A`, `B`, `C` will be returned (as a promise).\n\n```js\nconst initialId = [\"...\"]\nconst kinds = await AssistantAPIClient.getAllReferencedKinds({\n          ids: initialId\n        })\n```\n\n\n### Inventory\n\nThe `InventoryChanged` object:\n```js\n{\n  kinds: {\n    adds: [DiffItem]\n    deletes: [DiffItem]\n    updates: [DiffItem]\n  }\n  functions:{\n    adds: [DiffItem]\n    deletes: [DiffItem]\n    updates: [DiffItem]\n  }\n  services: {\n    adds: [DiffItem]\n    deletes: [DiffItem]\n    updates: [DiffItem]\n  }\n}\n```\n\nThe `DiffItem` object:\n```js\n{\n  id: string,\n  name: string\n}\n```\n\n#### addInventoryChangedListener = async cb =>\nRegisters a callback function with the inventory changed event. When workspace inventory changes the callback function will be called with the InventoryChangedobject. Returns undefined.\n\n**Use-case note: an ‘update’ diff for inventory services is unlikely in general usage.\n\n```js\nconst inventoryCB = ({diff}) => {\n  if(diff.kinds) console.log('KINDS CHANGED',diff.kinds)\n  if(diff.functions) console.log('FUNCTIONS CHANGED', diff.functions)\n  if(diff.services) console.log('SERVICES CHANGED',diff.services)\n}\n\nAssistantAPIClient.addInventoryChangedListener(inventoryCB)\n```\n\nThis function exists on the Q-Assisant-Client only--only enableSelectionChangedNotification is used on the API side.\n\n#### removeInventoryChangedListener = async cb =>\nRemoves an inventory changed listener given the referenced callback. If no callback is specified, all listeners will be removed. Returns undefined.\n\n```js\nAssistantAPIClient.removeInventoryChangedListener(inventoryCB)\n```\n\nThis function exists on the Q-Assisant-Client only--only disableSelectionChangedNotification is used on the API side.\n\n#### moveKindsAndFunctions = (originId, targetId, kindIds, functionIds) =>\nMoves a collection of Kinds and Functions from the origin Workspace to the target Workspace.\n\n```js\n  await AssistantAPIClient.moveKindsAndFunctions(\n    originWorkspaceId,\n    targetId,\n    kindIds,\n    functionIds\n  );\n```\n\n### Locking Changed Event\n\nAn event is triggered when the locked state of the currently active Workspace or\nits Knowledge Graphs and Functions change.\n\nThe `LockingChanged` object:\n```js\n{\n  workspaces: [LockItem],\n  knowledgeGraphs: [LockItem],\n  functions: [LockItem]\n}\n```\n\nThe `LockItem` object:\n```js\n{\n  id: string\n  lockedBy: string\n}\n```\n\n#### addLockingChangedListener = cb =>\n\nRegisters a callback function with the locking changed event. When the currently\nactive Workspace or its Knowledge Graphs and Functions change the callback\nfunction will be called with the `LockingChanged` object. Returns undefined.\n\n```js\nconst lockingChangedCB = ({ locks }) => {\n  if(locks.workspace) console.log('WORKSPACES CHANGED', locks.workspace);\n  if(locks.knowledgeGraphs) console.log('KNOWLEDGE GRAPHS CHANGED', locks.knowledgeGraphs);\n  if(locks.functions) console.log('FUNCTIONS CHANGED', locks.functions);\n}\n\nAssistantAPIClient.addLockingChangedListener(lockingChangedCB);\n```\n\n#### removeLockingChangedListener = cb =>\n\nRemoves an locking changed listener given the referenced callback. If no\ncallback is specified, all listeners will be removed. Returns undefined.\n\n```js\nAssistantAPIClient.removeLockingChangedListener(lockingChangedCB)\n```\n\n## Troubleshooting Assistant Issues\n### Assistant root file has loaded, but not other content\nObserving in the browser's dev tools that some resources have loaded correctly (usually the root), but other's haven't (usually nested files or chunks), is indicative of a failure of Q Gateway to proxy due to not having a 'relative' path structure.\n\n### You are seeing post-robot `NO ACK` errors in the console.\nThese errors stem from a failed acknowledgement for a call either between the client and the API or vice-versa. Here, this means that the web app 'window' (the assistant) cannot communicate with, or access, the 'window.parent' (Maana K-Portal) object.\n\nCommonly, these will stem from the 'window' (the assistant) not being loaded or in a loadable state, which means the API will not receive an acknowledgement when it fires an event.\n\nImproper CORS configuration is also a common culprit (also verify if using docker or nginx that your proxying and networking is configured correctly to allow communication and to accout for CORS).","readmeFilename":"README.md","gitHead":"5637a49ab105b2d180097ec9713b400a18cfb63a","_id":"@io-maana/q-assistant-client@3.3.0-beta.6","_nodeVersion":"12.20.1","_npmVersion":"6.14.10","dist":{"integrity":"sha512-KFjqDxDark2BQZBLpbSYGJb3DywJXv1WVBeSAejIk/nbCKmIbXwnwt7oW1ztzwZGOSljliHPv5RXL4fN0nX79g==","shasum":"c573962f5ebe57e9e3a22e6c8470efb7a3565aa6","tarball":"https://registry.npmjs.org/@io-maana/q-assistant-client/-/q-assistant-client-3.3.0-beta.6.tgz","fileCount":81,"unpackedSize":347878,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJgFEEXCRA9TVsSAnZWagAAChUP+gLCywKBwZHvFzUf6c8M\nWjL5ZFoQHgN++GXvGp9sRbG/UWRokFphwiBqxEMqTtKdgJwCojQ1OnPyF1c7\njBYLinG9yWhwsOpml5/cnhFdraSFGn7Ut9rOWstTOhoafu2d9mh2Uum5avdh\nAlweIyIw5Pbx6UOijmLffTXf6GVJx6SyDoRBhYGh9cEJ3CjqVnJV8btcqsty\n7HxhK/FMkjQb4MGoRtHKOiDx2FzXlLIIe/sS19U9+UxEZ3qA79VLoJ1RhEfs\nV7+//KIbld6RYo5pHj4DATbjSFdeSx/Gkk0wuua5b319JtG0biFGLFgyV7Ih\nEzi4c7yUo667Q5gS080jFd5unZpp2C6A5FSNEOAuPSii00OIG0QYuBNgtfrg\nbLx8kVAlxrj7bHTqDUWRzLhXG5g8AehFYPDEMHjTyRzwJK0RVwWZS20eATzv\nbHgQhC7ljnENp3HNr8oKFCnu6erUa20jSSyRfHTxHPp44LS8+ZfHK08VMPSy\ntJkAsUswogb0dhm4I7mKowAPUDJD+ZlmqfQ4LDlcJXp4BLdC923jwerlnRwE\nxhG3DlDGb0wNHaMCYcLGlL48RhfJX2/geY/2nYgipZVtHK4328q3MgTsPRgS\n/QvNRQJ+1iijR1FBiXf42zIQN3K08Djykvpa5gArN47HsvaEwMOjEsZcwnys\n+giH\r\n=HFN3\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIQCUdPSdBVQ7OvdvFtwMdoMkABofHeWjoWJihdov19JK2QIgNv3I/2dM+K2VzJINxwYxFTyp8UK0AoapIIB+r1Zrzhc="}]},"_npmUser":{"name":"teamcitymaana","email":"teamcity@maana.io"},"directories":{},"maintainers":[{"name":"witt3rd","email":"witt3rd@witt3rd.com"},{"name":"bzvetey","email":"bzvestey@gmail.com"},{"name":"abatyuk","email":"andrey@maana.io"},{"name":"rpovey","email":"rob@maana.io"},{"name":"teamcitymaana","email":"teamcity@maana.io"},{"name":"dlsmaana","email":"dlewissandy@maana.io"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/q-assistant-client_3.3.0-beta.6_1611940119079_0.4688438222647815"},"_hasShrinkwrap":false},"3.3.0-beta.7":{"name":"@io-maana/q-assistant-client","version":"3.3.0-beta.7","description":"JavaScript package to streamline communication between an assistant and the Maana Q Assistant API.","main":"build/index.js","types":"build/index.d.ts","exports":{"./":"./build/"},"scripts":{"build":"npm run build:ts && npm run build:doc","build:ts":"tsc --build tsconfig.json","build:doc":"typedoc","prepack":"npm run build","test":"echo \"Error: no test specified\" && exit 1","format":"prettier --write \"src/**/*.js\""},"repository":{"type":"git","url":"git+https://github.com/maana-io/q-assistant-client.git"},"keywords":["Maana","Q"],"author":{"name":"Logan Gore @ Maana.io"},"license":"MIT","bugs":{"url":"https://github.com/maana-io/q-assistant-client/issues"},"homepage":"https://github.com/maana-io/q-assistant-client#readme","dependencies":{"core-js":"3.6.4","post-robot":"10.0.29"},"devDependencies":{"@types/node":"^14.14.2","@types/post-robot":"^10.0.0","prettier":"2.0.5","typedoc":"^0.19.2","typedoc-plugin-markdown":"^3.0.11","typescript":"^3.9.5"},"readme":"# q-assistant-client\nA lightweight JavaScript client for Maana-Q Assistant developers that wraps post-message communication between an embedded Maana-Q assistant and the Maana-Q UI.\n\nYou can find the [API Documentation here](docs/README.md).\n\n## Abstract\nThe Q-Assistant-Client is intented to be used in a web application being leveraged as a Maana Q assistant (embedded as an iframe).\nThis assistant client will facilitate communication between the assistant and the parent frame.\nThe client provides a rich, asynchronous experience over what would otherwise be 'fire-and-forget'-style messaging\nvia post-post message communication.\n\n## Requirements and Assumptions\n\n### Post-Robot Library\nThe Maana Knowledge Portal (KPortal) uses the kraken/post-robot library [kraken/post-robot](https://github.com/krakenjs/post-robot) to enrich the communication with the assistant. Post-robot allows for asynchronous, promise-based request/response style behavior between the assistant and the assistant API.\n\nThe API requires that the client use the post-robot library. This assistant-client library is the easiest way to achieve this, and also adds a fair amount of 'sugar' to the process to improve developer productivity. Developers could, however, use post-robot directly in their own client implementation.\n\n### Maana-Gateway Proxy Requirements\nThe Maana-Gateway service requires relative paths (paths relative to the root) in the assistant web application in order to proxy the application and its content. For create-react-apps, for instance, this means setting \"homepage\" to \".\" in the package.json file.\n\n## Singleton Instance\nThe client is exported as a singleton to avoid duplicate registration on event listeners.\nYou can import the instance like this:\n\n```js\nimport AssistantAPIClient from '@io-maana/q-assistant-client';\n```\n\nFunction calls can be made against the client instance like any other javascript object. They are all async.\n\n```js\nconst workspace = await AssistantAPIClient.getWorkspace();\nconsole.log(\"Workspace:\", workspace)\n```\n\n## Dependencies\nPost-Robot\nhttps://github.com/krakenjs/post-robot\n\nPost-robot is used to provide a richer communication layer atop post-message.\n\n## Versioning\nThe Maana Q Assistant Client does not follow semantic versioning. Its versions\ntrack the releases of the Maana Q platform.\n\n## Examples\n@TODO Logan\n\n\n## Changes in v3.2.2\nImprovements in v3.2.2\n- Assistant State Management: WORKING, IDLE\n- Background Messaging/Eventing\n- Render Modes: BACKGROUND, DISPLAY\n- Expansion of Workspace object capabilities\n- Error Reporting\n- Repair Event\n- Plural versions of calls such as updateKind(s) to improve performance and developer experience.\n- InventoryChanged diffing is fully granular in v3.2.2--limitations\nin v3.2.1 only fired the Function diff for changes in Function name.\n\n### Deprecation\nThe following surface area IS removed from the\nclient in v3.2.2, and IS deprecated in the API:\n- AssistantAPIClient.enableSelectionChangedNotification\n- AssistantAPIClient.disableSelectionChangedNotification\n- AssistantAPIClient.enableInventoryChangedNotification\n- AssistantAPIClient.disableInventoryChangedNotification\n\nThe following surface area WILL BE removed from\nthe client in v3.2.4, and WILL BE deprecated in the API:\n- AssistantAPIClient.updateFunction (expected move to Workspace object)\n- AssistantAPIClient.updateKind (expected move to Workspace object)\n- AssistantAPIClient.deleteKind (expected move to Workspace object)\n- AssistantAPIClient.deleteFunction (expected move to Workspace object)\n\n## API Documentation\nMore information in the [API File](./API.md)\n\n### Assistant Render Mode\nAn assistant's render mode refers to whether it is being displayed in a visible manner to the user. As of v3.2.2, assistants are not closed when they are out of view.\nAll assistants will be loaded and kept in `BACKGROUND` render mode until they are\nplaced in the assistant panel, at which point the `DISPLAY` render mode event will be fired.\n\nNote: Assistants will receive all notifications/events while in BACKGROUND mode.\n\nDesign Consideration: It will be up to the developer to determine how state and resource use will be managed while an assistant is operating between BACKGROUND and DISPLAY modes.\n\n#### addRenderModeChangedListener = (cb) =>\nA listener to receive push events as to the assitant's render mode being changed.\n\n```js\nfunction handleRenderModeChanged(renderMode){\n  if (renderMode === 'DISPLAY'){\n    // Assistant is visible\n  } else {\n    // Assistant is not visible and running in background.\n  }\n}\n\nAssistantAPIClient.addRenderModeChangedListener(handleRenderModeChanged)\n\n```\n\n#### removeRenderModeChangedListener = (cb) =>\nRemoves the renderModeChanged listener by reference, or if no callback function reference is provided, it removes all listeners.\n\n#### getRenderMode = () =>\nReturns the current assistant render mode.\n\n```js\nconst renderMode = await AssistantAPIClient.getRenderMode()\n\nif (renderMode === 'DISPLAY'){\n  // Assistant is visible\n} else {\n  // Assistant is not visible and running in background.\n}\n\n```\n\n### Repair\nAssistants may get into situations where they are either out of sync with the Maana Q UI, or in a failure state. Assistants should be able to recover from these states.\n\nThe repair event functionality added in v3.2.2 is designed to notify the assistant that it must repair itself. This could mean a resync with its resources on the workspace or externally or, for some assistants, nothing at all.\n\nWhen is repair triggered?\nEither manually by a user clicking 'repair workspace' under the\nassistant inventory panel, or upon a workspace clone event. An assistant will be expected to handle either scenario.\n\nPerformance Consideration:\nFor some assistants, repair might involve 'introspecting'\nand processing the current workspace or Q system resources. This could be very resource intensive. Make sure you review this API guide to have an idea of what tools are\navailable to get the best results. It's always a good idea to check performance of repair on a large workspace and ensure necessary optimizations have been made.\n\nDesign Consideration:\nMake your workflows modular enough to be reused between repair and normal usage if possible.\n\n#### addRepairListener (cb) =>\n```js\n\nAssistantAPIClient.addRepairListener(()=>{\n  // Self-heal\n})\n\n```\n\nRecommended Usage: A repair process should be wrapped in the try/catch/finally flow shown in the `setAssistantState` API call to provide the user assistant-state and error updates as well as pause `inventoryChanged` notifications during repair (if the assistant has subscribed).\n\n#### removeRepairListener = (cb) =>\nRemoves the repair listener by reference, or if no callback function reference is provided, it removes all listeners.\n\n### User-facing Error Handling\n\n#### reportError (error) =>\nReports an error to the UI to be displayed in the assistant's error log in the\ninventory panel. This call is not disruptive and designed to operated independently of other assistant operations, such as state management. See `setAssistantState` in the next section.\n\nRecommended usage: use this functionality where it would futher the user experience\nto show the user an error and it's cause. Do not use this where things will be retried,\ncleaned up automatically, or are not relevant to the user.\n\n```js\ntry{\n  // Do work\n} catch(e) {\n  AssistantAPIClient.reportError(e)\n}\n```\n\n### State management\n\n#### clearState = () =>\nThis will remove all callbacks from all listeners.\n\n```js\nawait AssistantAPIClient.clearState()\n```\n\n#### setAssistantState = (state) =>\nThis sets the current state of the assistant using the\n`AssistantState` enum. Setting a state of `WORKING` will\ncreate the 'working' status spinner in the Assistant\nInventory Panel in the Maana Q UI. Conversely, setting an `IDLE` state will\nremove the spinner. This adds to user experience by informing users of the\nstatus of operations.\n\n```js\nimport {\n  default as AssistantAPIClient,\n  AssistantState\n} from '@io-maana/q-assistant-client'\n\n...\n\nAssistantAPIClient.setAssistantState(AssistantState.WORKING)\n\n...\n\nAssistantAPIClient.setAssistantState(AssistantState.IDLE)\n\n```\nUI User Prompt: If the assistant is in a `WORKING` state, the Maana Q UI will\nwarn the user before leaving the workspace.\n\nNOTE: while an assistant is in a working state, it will\nnot receive `inventoryChanged` events--an aggregated inventory diff\nwill be sent once the assistant is set back to `IDLE`.\n\nRecommended usage: Control states at a high level using try/catch/finally\nflow incorporating the `reportError` API call.\n\n```js\ntry{\n  AssistantAPIClient.setAssistantState(AssistantState.WORKING)\n  // Do work, await high-level tasks, etc.\n} catch(e) {\n  AssistantAPIClient.reportError(e)\n} finally{\n  AssistantAPIClient.setAssistantState(AssistantState.IDLE)\n}\n```\n\n#### AssistantState (enum)\nContains the valid assistant states: `IDLE` or `WORKING`.\n\nMust be imported in addition to the AssistantAPIClient:\n\n```js\nimport {\n  default as AssistantAPIClient,\n  AssistantState\n} from '@io-maana/q-assistant-client'\n```\n\n\n### User Info\nThe `UserInfo` object:\n```js\n{\n email: string,\n name: string\n}\n```\n\n#### getUserInfo = () =>\nReturns a Userinfo object pertaining to the logged in user.\n\n```js\nconst userInfo = await AssistantAPIClient.getUserInfo()\n```\n### Selection\nThe `Selection` object:\n```js\n{\n  kindId: string\n  kindName: string\n  id: string\n}\n```\n\n#### getCurrentSelection = () =>\nReturns an Array of `Selection` objects:\n\n```js\nconst {selection} = await AssistantAPIClient.getCurrentSelection();\n```\n\n#### addSelectionChangedListener = async cb =>\nAdds a callback function to be executed upon a valid workspace selection change.\n\nCallback value is an array of Selection objects:\n\n```js\n// Create the selection callback.\nconst selectionCB = ({selection})=>{\n  console.log('Workspace selection has changed.')\n  selection.forEach(i=>{\n    console.log('Kind: ',i.kindName)\n    console.log('Instance Id:',i.id)\n    console.log('Kind Id:',i.kindId)\n  })\n}\n\n// Add the listener.\nAssistantAPIClient.addSelectionChangedListener(selectionCB);\n```\n\nThis function only exists on the Q-Assistant-Client--only enableSelectionChangedNotification is called on the API.\n\n#### removeSelectionChangedListener = async cb =>\nThis will have to be called on a 1:1 basis with addSelectionChangedListener calls if supplying a callback.\n\n```js\nAssistantAPIClient.removeSelectionChangedListener(selectionCB)\n```\n\n**If NOT supplying a callback to this call, all selection changed listeners will be removed.\n\n```js\nAssistantAPIClient.removeSelectionChangedListener()\n```\n\nThis function only exists on the Q-Assistant-Client--only disableSelectionChangedNotification is called on the API.\n\n\n### Services\nThe `Service` object:\n```js\n{\n   id: string,\n   name: string\n   endpointUrl: string,\n   getKinds: () => // Returns [] of Kinds objects\n   getFunctions: () => // Returns [] of Function objects\n}\n```\n\n#### getServiceById = id =>\nThis will return a service that exists within the scope of the workspace.\n** Assistant services will return null. Services outside the scope of the workspace will cause an error to be returned as 'Unable to load a Service from outside of the workspace.'\n\n```js\nconst svc = await AssistantAPIClient.getServiceById(id)\n```\n\n#### createService = id =>\nCreates a service in Q.\n\nNote: This will create the service, but does NOT import it into the workspace.\nYou will need to use `importService` on the Workspace object to import it.\nReturns a promise that resolves\n\n```js\n    const service = {\n      id: ...,\n      name: ...,\n      endpointUrl: ...,\n      serviceType: ...\n    }\n\n    await AssistantAPIClient.createService(service)\n```\n\n#### deleteService = id =>\nDeletes a service from Q.\n\n```js\n    await AssistantAPIClient.deleteService(id)\n```\n\n#### refreshServiceSchema = id =>\nRefreshes a service by fetching its schema. This will also\nreload the service inventory in the currently visible workspace.\n\n```js\nawait AssistantAPIClient.refreshServiceSchema(\"id\")\n```\n\n#### reloadService = id =>\nReloads a service in the inventory in the currently visible workspace.\n\n```js\nawait AssistantAPIClient.reloadService(\"id\")\n```\n\n### Workspace\n\n#### getWorkspace = () =>\nReturns a Workspace object representing the workspace.\n\n```js\nconst ws = await AssistantAPIClient.getWorkspace(id)\n```\n\nNote: The `id` parameter is optional. If it is not supplied, the query\nwill return the current/visible workspace.\n\nThe `Workspace` object:\n\n```js\n\n{\n    id: string,\n    name: string,\n    endpointUrl: string,\n    workspaceServiceId: string,\n    modelServiceId: string,\n    logicServiceId: string,\n\n    //\n    // Locking information\n    //\n    async lockedBy() {\n      // Returns the e-mail address of the user who locked the Workspace, or\n      // null if the Workspace is not currently locked.\n    }\n    async canEdit() {\n      // Returns `true` when the Workspace is not locked, or the current user\n      // owns the lock.\n      // Returns 'false' when the Workspace is locked by a different user.\n    }\n    async setLocked(isLocked) {\n      // Takes a boolean or undefined for `isLocked`.\n      //  `true` locks the Workspace as the current User.\n      //  `false` unlocks the Workspace\n      //  `undefined` causes it to toggle the current locked state.\n      // Returns a Promise that will resolve or reject when the task is done.\n    }\n\n    //\n    // Knowledge Graphs\n    //\n    getActiveGraph: async () => {\n      // Returns the active Graph object.\n      // Returns null if active graph is not of type 'Knowledge Graph', or if an\n      // active graph is deleted, thereby setting active graph to null.\n    },\n    getKnowledgeGraphs: async () => {\n      // Returns [Graph]\n    },\n    // TODO: define input\n    createKnowledgeGraph: input =>\n    // TODO: define input\n    createKnowledgeGraphs: input =>\n\n    //\n    // Services\n    //\n    getImportedServices: async () => {\n      // Returns an array of Service objects that have\n      // been imported into the workspace.\n      // No assistant services will be returned.\n    },\n    getImportedAssistants: async () => {\n      // Returns a list of imported assistants.\n    },\n    importService: serviceId => {\n      // Imports a service by it's ID.\n    },\n    importServices: serviceIds => {\n      // Imports services by their IDs.\n    },\n    removeServices: serviceIds => {\n      // Removes a list of services from the workspace.\n    },\n    removeService: serviceId => {\n      // Removes a service from the workspace.\n    },\n\n    //\n    // Functions\n    //\n    getFunctions: async () => {\n      // Returns an array of functions in the workspace (includes boilerplate).\n    },\n    createFunction: funcData => {\n      // Creates a function and adds it to the graph.\n    }\n    createFunctions: funcData =>{\n      // Creates several functions and adds them to the graph.\n    }\n    updateFunction: funcData => {\n      // Updates a function.\n    },\n    updateFunctions: funcData =>{\n      // Updates functions based on input array.\n    },\n    deleteFunction: funcId => {\n      // Deletes a function by its ID.\n    },\n    getFunctionGraph: funcId => {\n      // Returns a function graph by its ID.\n    }\n\n    //\n    // Kinds\n    //\n    getKinds: async () => {\n      // Returns an array of functions in the workspace (includes boilerplate).\n    },\n    createKind: kindData => {\n      // Currently same input as AssistantAPIClient call.\n    },\n    createKinds: kindData => {\n      // Currently same input as AssistantAPIClient call.\n    },\n    updateKind: kindData => {\n      // Currently same input as AssistantAPIClient call.\n    },\n    updateKinds: kindData => {\n      // Currently same input as AssistantAPIClient call.\n    },\n    deleteKind: kindId => {\n      // Currently same input as AssistantAPIClient call.\n    }\n    // Event Triggers\n    triggerRepairEvent: () => {\n      // Triggers the repair event on a workspace.\n    }\n  };\n}\n```\n\n\n### Graphs\nThe `Graph` object:\n```js\n{\n  id: string,\n  name: string,\n  offsetX: Number,\n  offsetY: Number,\n  zoom: Number,\n  getNodes: async () => {\n      // Returns [Node]\n  },\n\n  addNode: async (type, instance, changeSelection) => {\n      // Returns Node\n  },\n  removeNode: async id => {\n      // Should return nothing or error.\n      // Currently returning [] in all cases.\n  },\n  updateNodeLayout: async (nodeId, { x, y, collapsed }) => {\n  },\n  updateGraphLayout: async ({ offsetX, offsetY, zoom }) => {\n  }\n\n  //\n  // Locking information\n  //\n  async lockedBy() {\n    // Returns the e-mail address of the user who locked the Graph, or null if\n    // the Graph is not currently locked.\n  }\n  async canEdit() {\n    // Returns `true` when the Graph is not locked, or the current user owns the\n    // lock.\n    // Returns 'false' when the Graph is locked by a different user.\n  }\n  async setLocked(isLocked) {\n    // Takes a boolean or undefined for `isLocked`.\n    //  `true` locks the Graph as the current User.\n    //  `false` unlocks the Graph\n    //  `undefined` causes it to toggle the current locked state.\n    // Returns a Promise that will resolve or reject when the task is done.\n  }\n}\n```\n\n#### Getting a graph object:\nGraph objects are obtained through an instance of a Workspace\n\n```js\nconst ag = await ws.getActiveGraph()\n```\n\nor\n\n```js\nconst kgs = await ws.getKnowledgeGraphs()\n```\n\n#### Manipulating Graphs\n\n**Only the active graph may be manipulated.\n\nAll graph manipulations should be ‘visually’ verifiable on the graph itself, i.e., adds/removes/positioning, should all be reflected on the graph itself.\n\nThe `Node` object:\n```js\n{\nid: string\nx: number\ny: number\ncollapsed: boolean\nknowledgeGraphNode {\n  id: string\n  innerKind: Kind\n  innerFunction: Function\n}\n}\n```\n\n#### addNode(type, instance, changeSelection) =>\n\nTakes type (“Function” or “Kind”), instance (the Function or Kind object), and optionally a boolean to indicate whether the selection should be changed to this new node.\n\nReturns the newly created Node object.\n\n```js\nconst node = await ag.addNode('Kind',kind)\n```\n\n#### removeNode(id) =>\n\nTakes the id of Node to be deleted. Returns either undefined or an error.\n\n```js\nawait ag.removeNode(node.id)\n```\n\n#### getNodes() =>\nReturns an array of Node objects from the graph.\n\n```js\nconst nodes = await ag.getNodes()\n```\n\n#### updateNodeLayout: async (nodeId, { x, y, collapsed})=>\nUpdates a Node layout given a node ID and node coordinates (`x` and/or `y`) or a `collapsed` value. x/y values must be a number, and collapsed must be a boolean. Whatever is not specified will remain current.\n\n```js\nag.updateNodeLayout(id,{x:100,y:100,collapsed:true})\n```\n\n#### updateGraphLayout: async ({ offsetX, offsetY, zoom})=>\nUpdates a Graph layout given numerical values for x/y offsets and the zoom.\n\n```js\nag.updateGraphLayout({offsetX:50, offsetY:50, zoom: 70})\n```\n\n### Functions\n\nThe `Function` object:\n```js\n{\n    id: string\n    name: string\n    service {\n      id: string\n      name: string\n    }\n    arguments {\n      id: string\n      name: string\n      type: string\n      modifiers: Array[string]\n      typeKindId:: string\n      kind {\n        id: string\n        name: string\n      }\n    }\n    implementation {\n      id: string\n      entrypoint {\n        id: string\n      }\n      operations {\n        id: string\n        type: string\n        function {\n          id: string\n          name: string\n        }\n        argumentValues {\n          id: string\n          argument {\n            id: string\n          }\n          operation {\n            id: string\n          }\n          argumentRef: string\n        }\n      }\n    }\n    isGenerated: boolean\n    functionType: string\n    graphqlOperationType: string\n    outputType: string\n    outputKindId: string\n    outputModifiers: Array[string]\n    kind {\n      id: string\n      name: string\n    }\n\n    //\n    // Locking information\n    //\n    async lockedBy() {\n      // Returns the e-mail address of the user who locked the Function, or null\n      // if the Function is not currently locked.\n    }\n    async canEdit() {\n      // Returns `true` when the Function is not locked, or the current user\n      // owns the lock.\n      // Returns 'false' when the Function is locked by a different user.\n    }\n    async setLocked(isLocked) {\n      // Takes a boolean or undefined for `isLocked`.\n      //  `true` locks the Function as the current User.\n      //  `false` unlocks the Function\n      //  `undefined` causes it to toggle the current locked state.\n      // Returns a Promise that will resolve or reject when the task is done.\n    }\n}\n```\n\n`FunctionExecutionResult` object:\n```js\n{\n  id: string,\n  result: JSON\n}\n```\n\n#### executeFunction = ( {id, variables, resolve} ) =>\nExecutes a function based on its id, with optional inputs for variables and a resolve string (this specifies the fields to be returned, which must be valid based on the result).\n\nReturns : JSON matching shape of result , unless no sub-selection of fields is required in the execution.\n\nThis following piece of code will execute a Function given a function ID, and pass in variables for ‘example’, requesting back id and name fields.\n\n```js\nconst res = await AssistantAPIClient.executeFunction({functionId: func.id, variables: {\"variableName\": \"variableValue\"}, resolve: \"{ id name }\");\n```\n\n#### createFunction = input =>\nCreates a function based on the input provided.\n\nReturns: the created Function object.\n\n**Using create function will only place the function in the workspace’s inventory--it will not place the function as a node on the Graph. In order to do this, you must pass the created function into the addNode function on the active Graph, making sure to specify ‘Function' as the type.\n\n```js\nconst createFunctionInput = {\n  name:\"yourName\",\n  arguments:[],\n  outputType: \"STRING\",\n  graphqlOperationType:\"QUERY\",\n  functionType: \"CKG\"\n}\n\nconst createdFunction = await AssistantAPIClient.createFunction(createFunctionInput)\n```\n\n#### updateFunction = input =>\nInput is the same for creating a function. It’s important to note that the arguments property will be replaced in it’s entirety with whatever is provided (if a value is provided.\n\nReturns the updated `Function` object.\n\n```js\nconst updatedFunction = await AssistantAPIClient.updateFunction(input);\n```\n\n#### deleteFunction = input =>\nInput is the id of the Function to be deleted. Returns the deleted function as a promise.\n\n```js\nconst deletedFunction = await AssistantAPIClient.deleteFunction('id...');\n```\n\n#### getFunctionById = id =>\nReturns a Function as a promise based on the ID provided.\n\n```js\nconst func = await AssistantAPIClient.getFunctionById('id...');\n```\n\n#### addFunctionExecutionListener = async (id, cb) =>\nAssociates a callback function with the execution of a particular Function. When the Function matching the id parameter is executed, its FunctionExecutionResult object passed to the callback. Returns undefined.\n\nExample function execution callback and listener registration:\n\n```js\nfunction exampleFunctionCB (result){\n  console.log(`Function executed with result:`, result)\n}\n\nAssistantAPIClient.addFunctionExecutionListener('id...', exampleFunctionCB)\n```\n\n#### removeFunctionExecutionListener = async (id, cb) =>\nRemoves a Function execution listener based on the function ID and a reference to the callback function. If no callback is supplied, all listeners associated with the Function ID will be removed. Returns undefined.\n\n```js\nAssistantAPIClient.removeFunctionExecutionListener('id..', exampleFunctionCB)\n```\n\n### Kinds\nThe `Kind` object:\n```js\n{\n    id: string\n    name: string\n    service: {\n      id\n      name\n    }\n    isGenerated: boolean\n    schema {\n      id: string\n      name: string\n      type: string\n      typeKindId: string\n      modifiers: Array[string]\n      kind {\n        id: string\n        name: string\n      }\n    }\n}\n```\n\n#### createKind = input =>\nCreates a Kind based on an input object. Returns a promise that resolves to the created Kind object.\n\n```js\nconst kindInput = {\n name: \"someKind\",\n schema:[\n  { name: \"someField1\", type: STRING },\n  { name: \"someField2\", type: STRING }\n ]\n}\n\nconst newKind = await AssistantAPIClient.createKind(kindInput)\n```\n\n#### createKinds = input =>\nA plural version of `createKind` accepting an array of input objects.\nReturns a promise that resolves to an array of created Kind objects.\n\n```js\nconst kindsInput = [{\n name: \"someKind\",\n schema:[\n  { name: \"someField1\", type: STRING },\n  { name: \"someField2\", type: STRING }\n ]\n}, ...]\n\nconst newKinds = await AssistantAPIClient.createKinds(kindsInput)\n```\n\n\n#### updateKind = input =>\nUpdates a Kind based on an input object.\n\nUpdate Semantics: Only properties specified will be updated. If updating the schema, the entire schema must be specified as it will be replaced in its entirety.\n\nReturns a promise that resolves to the updated `Kind` object.\n\n```js\nconst updated = await AssistantAPIClient.updateKind(input)\n```\n\n#### deleteKind = input =>\nDeletes a Kind given a kind ID.\n\n```js\nconst deleted = await AssistantAPIClient.deleteKind(input)\n```\n\n#### getKindById = id =>\nReturns a promise that resolves to a Kind object given the specified kind ID.\n\nIn v3.2.2, any requested non-system kinds will be returned.\nIn v3.2.1, only kinds in the workspace or those of imported services will be returned.\n\n```js\nconst kind = await AssistantAPIClient.getKindById(id)\n```\n\n#### getKindsById = ids =>\nReturns a promise that resolves to an array of Kind objects given an array of kind IDs. Only kinds in the workspace or those of imported services will be returned.\n\n```js\nconst ids = [\"...\",\"...\",...]\nconst kind = await AssistantAPIClient.getKindsById(ids)\n```\n\n#### getAllReferencedKinds = input =>\nRecursively collects all kinds that are referenced in a kind's schema, starting\nwith a kind ID. For example if the ID of kind A is supplied as an input, and Kind `A` contains a field of type Kind `B`, and `B` contains a field of type Kind `C`,\nan array containing the kinds objects for `A`, `B`, `C` will be returned (as a promise).\n\n```js\nconst initialId = [\"...\"]\nconst kinds = await AssistantAPIClient.getAllReferencedKinds({\n          ids: initialId\n        })\n```\n\n\n### Inventory\n\nThe `InventoryChanged` object:\n```js\n{\n  kinds: {\n    adds: [DiffItem]\n    deletes: [DiffItem]\n    updates: [DiffItem]\n  }\n  functions:{\n    adds: [DiffItem]\n    deletes: [DiffItem]\n    updates: [DiffItem]\n  }\n  services: {\n    adds: [DiffItem]\n    deletes: [DiffItem]\n    updates: [DiffItem]\n  }\n}\n```\n\nThe `DiffItem` object:\n```js\n{\n  id: string,\n  name: string\n}\n```\n\n#### addInventoryChangedListener = async cb =>\nRegisters a callback function with the inventory changed event. When workspace inventory changes the callback function will be called with the InventoryChangedobject. Returns undefined.\n\n**Use-case note: an ‘update’ diff for inventory services is unlikely in general usage.\n\n```js\nconst inventoryCB = ({diff}) => {\n  if(diff.kinds) console.log('KINDS CHANGED',diff.kinds)\n  if(diff.functions) console.log('FUNCTIONS CHANGED', diff.functions)\n  if(diff.services) console.log('SERVICES CHANGED',diff.services)\n}\n\nAssistantAPIClient.addInventoryChangedListener(inventoryCB)\n```\n\nThis function exists on the Q-Assisant-Client only--only enableSelectionChangedNotification is used on the API side.\n\n#### removeInventoryChangedListener = async cb =>\nRemoves an inventory changed listener given the referenced callback. If no callback is specified, all listeners will be removed. Returns undefined.\n\n```js\nAssistantAPIClient.removeInventoryChangedListener(inventoryCB)\n```\n\nThis function exists on the Q-Assisant-Client only--only disableSelectionChangedNotification is used on the API side.\n\n#### moveKindsAndFunctions = (originId, targetId, kindIds, functionIds) =>\nMoves a collection of Kinds and Functions from the origin Workspace to the target Workspace.\n\n```js\n  await AssistantAPIClient.moveKindsAndFunctions(\n    originWorkspaceId,\n    targetId,\n    kindIds,\n    functionIds\n  );\n```\n\n### Locking Changed Event\n\nAn event is triggered when the locked state of the currently active Workspace or\nits Knowledge Graphs and Functions change.\n\nThe `LockingChanged` object:\n```js\n{\n  workspaces: [LockItem],\n  knowledgeGraphs: [LockItem],\n  functions: [LockItem]\n}\n```\n\nThe `LockItem` object:\n```js\n{\n  id: string\n  lockedBy: string\n}\n```\n\n#### addLockingChangedListener = cb =>\n\nRegisters a callback function with the locking changed event. When the currently\nactive Workspace or its Knowledge Graphs and Functions change the callback\nfunction will be called with the `LockingChanged` object. Returns undefined.\n\n```js\nconst lockingChangedCB = ({ locks }) => {\n  if(locks.workspace) console.log('WORKSPACES CHANGED', locks.workspace);\n  if(locks.knowledgeGraphs) console.log('KNOWLEDGE GRAPHS CHANGED', locks.knowledgeGraphs);\n  if(locks.functions) console.log('FUNCTIONS CHANGED', locks.functions);\n}\n\nAssistantAPIClient.addLockingChangedListener(lockingChangedCB);\n```\n\n#### removeLockingChangedListener = cb =>\n\nRemoves an locking changed listener given the referenced callback. If no\ncallback is specified, all listeners will be removed. Returns undefined.\n\n```js\nAssistantAPIClient.removeLockingChangedListener(lockingChangedCB)\n```\n\n## Troubleshooting Assistant Issues\n### Assistant root file has loaded, but not other content\nObserving in the browser's dev tools that some resources have loaded correctly (usually the root), but other's haven't (usually nested files or chunks), is indicative of a failure of Q Gateway to proxy due to not having a 'relative' path structure.\n\n### You are seeing post-robot `NO ACK` errors in the console.\nThese errors stem from a failed acknowledgement for a call either between the client and the API or vice-versa. Here, this means that the web app 'window' (the assistant) cannot communicate with, or access, the 'window.parent' (Maana K-Portal) object.\n\nCommonly, these will stem from the 'window' (the assistant) not being loaded or in a loadable state, which means the API will not receive an acknowledgement when it fires an event.\n\nImproper CORS configuration is also a common culprit (also verify if using docker or nginx that your proxying and networking is configured correctly to allow communication and to accout for CORS).","readmeFilename":"README.md","gitHead":"fc04a97c7418c70f5f40d8470bc17fcca9144ef3","_id":"@io-maana/q-assistant-client@3.3.0-beta.7","_nodeVersion":"12.20.1","_npmVersion":"6.14.10","dist":{"integrity":"sha512-Lvluaana6/3AOGpU/OlengjE59ie3oacVF7qPKrWx4secxJ5eqvf8IOG6XhX7nzTpxnf10wjtADny3qy0xIIsg==","shasum":"40140f49e5146556b9d4918013679ae877ceca53","tarball":"https://registry.npmjs.org/@io-maana/q-assistant-client/-/q-assistant-client-3.3.0-beta.7.tgz","fileCount":81,"unpackedSize":349907,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJgGfhRCRA9TVsSAnZWagAAaQEP/1J9jiwzzqOU0n4Cz3Pm\n0OMJS3RA4TasKOz62gwjM5B4wHNBZsp9k5yMLIrNiiLZfVFPTIwN1GRLw2zc\ngtP2hnPI1xQfdsoVFpYgCkHkSx/Rz7ngr41QxIfgO7xKpIaUmtQBL9wn55Mw\nJcuuShGoYQxwaUc30c6eUtM9hY0UmqTtK6tnPLBxr0VP5owCEh33g2BYVr3W\nZbOhXavKRWikKTUDJX5507mHDkdjgxulkchUspiRyRDdgZ4hYxzbCWXK7lS1\noqDnKbWm/sJsqnqwt8hMbtE3Ntak0NijRlytpXDWbPssHQQVVvgHGgkv6nkU\neCFr3o3ZVyi6gnPsgNmRWoJXjPWC0vgWY5gh4S89dKQW2ob9p5n4aA9mHzH5\nntxC/A9KrAEqeMhXKkBEg3OmfI8pYA9pUUtEiP3J7RgsEF2w5qlGdbSQ64LW\nZHVe1I6urMe+3c2FQlSqiBGj89iDmRw8iedy6mbXesNaFcuQfpnFJuJVLhuk\n9+sb6oP2bWVLznQu22RPIqErSUw6z7/Slsx99NQaU4QUnyVgttLLNVSvf7sN\nlYFXP3uUrXS6wdJdUC/kimnQI327t5S7Jvk3jyDENzG/md1QAYj6YO2F4/JC\nlRu8UyUMEETwpqUkIcxZ9d1n7uRXpQEfvv1s6AZS6XhZsDVhDwWD/Tx0mcQP\n57pA\r\n=yOO9\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEYCIQCKAaQ4JasHwv8F3lkIncmiGqX4oy/UfZs7f/GJAab5YwIhAJopPwUGv17t7kRonbOlg6tc28o0PL6UADfyD30RVWi9"}]},"_npmUser":{"name":"teamcitymaana","email":"teamcity@maana.io"},"directories":{},"maintainers":[{"name":"witt3rd","email":"witt3rd@witt3rd.com"},{"name":"bzvetey","email":"bzvestey@gmail.com"},{"name":"abatyuk","email":"andrey@maana.io"},{"name":"rpovey","email":"rob@maana.io"},{"name":"teamcitymaana","email":"teamcity@maana.io"},{"name":"dlsmaana","email":"dlewissandy@maana.io"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/q-assistant-client_3.3.0-beta.7_1612314704682_0.020913207848087367"},"_hasShrinkwrap":false},"3.3.0-beta.8":{"name":"@io-maana/q-assistant-client","version":"3.3.0-beta.8","description":"JavaScript package to streamline communication between an assistant and the Maana Q Assistant API.","main":"build/index.js","types":"build/index.d.ts","exports":{"./":"./build/"},"scripts":{"build":"npm run build:ts && npm run build:doc","build:ts":"tsc --build tsconfig.json","build:doc":"typedoc","prepack":"npm run build","test":"echo \"Error: no test specified\" && exit 1","format":"prettier --write \"src/**/*.js\""},"repository":{"type":"git","url":"git+https://github.com/maana-io/q-assistant-client.git"},"keywords":["Maana","Q"],"author":{"name":"Logan Gore @ Maana.io"},"license":"MIT","bugs":{"url":"https://github.com/maana-io/q-assistant-client/issues"},"homepage":"https://github.com/maana-io/q-assistant-client#readme","dependencies":{"core-js":"3.6.4","post-robot":"10.0.29"},"devDependencies":{"@types/node":"^14.14.2","@types/post-robot":"^10.0.0","prettier":"2.0.5","typedoc":"^0.19.2","typedoc-plugin-markdown":"^3.0.11","typescript":"^3.9.5"},"readme":"# q-assistant-client\nA lightweight JavaScript client for Maana-Q Assistant developers that wraps post-message communication between an embedded Maana-Q assistant and the Maana-Q UI.\n\nYou can find the [API Documentation here](docs/README.md).\n\n## Abstract\nThe Q-Assistant-Client is intented to be used in a web application being leveraged as a Maana Q assistant (embedded as an iframe).\nThis assistant client will facilitate communication between the assistant and the parent frame.\nThe client provides a rich, asynchronous experience over what would otherwise be 'fire-and-forget'-style messaging\nvia post-post message communication.\n\n## Requirements and Assumptions\n\n### Post-Robot Library\nThe Maana Knowledge Portal (KPortal) uses the kraken/post-robot library [kraken/post-robot](https://github.com/krakenjs/post-robot) to enrich the communication with the assistant. Post-robot allows for asynchronous, promise-based request/response style behavior between the assistant and the assistant API.\n\nThe API requires that the client use the post-robot library. This assistant-client library is the easiest way to achieve this, and also adds a fair amount of 'sugar' to the process to improve developer productivity. Developers could, however, use post-robot directly in their own client implementation.\n\n### Maana-Gateway Proxy Requirements\nThe Maana-Gateway service requires relative paths (paths relative to the root) in the assistant web application in order to proxy the application and its content. For create-react-apps, for instance, this means setting \"homepage\" to \".\" in the package.json file.\n\n## Singleton Instance\nThe client is exported as a singleton to avoid duplicate registration on event listeners.\nYou can import the instance like this:\n\n```js\nimport AssistantAPIClient from '@io-maana/q-assistant-client';\n```\n\nFunction calls can be made against the client instance like any other javascript object. They are all async.\n\n```js\nconst workspace = await AssistantAPIClient.getWorkspace();\nconsole.log(\"Workspace:\", workspace)\n```\n\n## Dependencies\nPost-Robot\nhttps://github.com/krakenjs/post-robot\n\nPost-robot is used to provide a richer communication layer atop post-message.\n\n## Versioning\nThe Maana Q Assistant Client does not follow semantic versioning. Its versions\ntrack the releases of the Maana Q platform.\n\n## Examples\n@TODO Logan\n\n\n## Changes in v3.2.2\nImprovements in v3.2.2\n- Assistant State Management: WORKING, IDLE\n- Background Messaging/Eventing\n- Render Modes: BACKGROUND, DISPLAY\n- Expansion of Workspace object capabilities\n- Error Reporting\n- Repair Event\n- Plural versions of calls such as updateKind(s) to improve performance and developer experience.\n- InventoryChanged diffing is fully granular in v3.2.2--limitations\nin v3.2.1 only fired the Function diff for changes in Function name.\n\n### Deprecation\nThe following surface area IS removed from the\nclient in v3.2.2, and IS deprecated in the API:\n- AssistantAPIClient.enableSelectionChangedNotification\n- AssistantAPIClient.disableSelectionChangedNotification\n- AssistantAPIClient.enableInventoryChangedNotification\n- AssistantAPIClient.disableInventoryChangedNotification\n\nThe following surface area WILL BE removed from\nthe client in v3.2.4, and WILL BE deprecated in the API:\n- AssistantAPIClient.updateFunction (expected move to Workspace object)\n- AssistantAPIClient.updateKind (expected move to Workspace object)\n- AssistantAPIClient.deleteKind (expected move to Workspace object)\n- AssistantAPIClient.deleteFunction (expected move to Workspace object)\n\n## API Documentation\nMore information in the [API File](./API.md)\n\n### Assistant Render Mode\nAn assistant's render mode refers to whether it is being displayed in a visible manner to the user. As of v3.2.2, assistants are not closed when they are out of view.\nAll assistants will be loaded and kept in `BACKGROUND` render mode until they are\nplaced in the assistant panel, at which point the `DISPLAY` render mode event will be fired.\n\nNote: Assistants will receive all notifications/events while in BACKGROUND mode.\n\nDesign Consideration: It will be up to the developer to determine how state and resource use will be managed while an assistant is operating between BACKGROUND and DISPLAY modes.\n\n#### addRenderModeChangedListener = (cb) =>\nA listener to receive push events as to the assitant's render mode being changed.\n\n```js\nfunction handleRenderModeChanged(renderMode){\n  if (renderMode === 'DISPLAY'){\n    // Assistant is visible\n  } else {\n    // Assistant is not visible and running in background.\n  }\n}\n\nAssistantAPIClient.addRenderModeChangedListener(handleRenderModeChanged)\n\n```\n\n#### removeRenderModeChangedListener = (cb) =>\nRemoves the renderModeChanged listener by reference, or if no callback function reference is provided, it removes all listeners.\n\n#### getRenderMode = () =>\nReturns the current assistant render mode.\n\n```js\nconst renderMode = await AssistantAPIClient.getRenderMode()\n\nif (renderMode === 'DISPLAY'){\n  // Assistant is visible\n} else {\n  // Assistant is not visible and running in background.\n}\n\n```\n\n### Repair\nAssistants may get into situations where they are either out of sync with the Maana Q UI, or in a failure state. Assistants should be able to recover from these states.\n\nThe repair event functionality added in v3.2.2 is designed to notify the assistant that it must repair itself. This could mean a resync with its resources on the workspace or externally or, for some assistants, nothing at all.\n\nWhen is repair triggered?\nEither manually by a user clicking 'repair workspace' under the\nassistant inventory panel, or upon a workspace clone event. An assistant will be expected to handle either scenario.\n\nPerformance Consideration:\nFor some assistants, repair might involve 'introspecting'\nand processing the current workspace or Q system resources. This could be very resource intensive. Make sure you review this API guide to have an idea of what tools are\navailable to get the best results. It's always a good idea to check performance of repair on a large workspace and ensure necessary optimizations have been made.\n\nDesign Consideration:\nMake your workflows modular enough to be reused between repair and normal usage if possible.\n\n#### addRepairListener (cb) =>\n```js\n\nAssistantAPIClient.addRepairListener(()=>{\n  // Self-heal\n})\n\n```\n\nRecommended Usage: A repair process should be wrapped in the try/catch/finally flow shown in the `setAssistantState` API call to provide the user assistant-state and error updates as well as pause `inventoryChanged` notifications during repair (if the assistant has subscribed).\n\n#### removeRepairListener = (cb) =>\nRemoves the repair listener by reference, or if no callback function reference is provided, it removes all listeners.\n\n### User-facing Error Handling\n\n#### reportError (error) =>\nReports an error to the UI to be displayed in the assistant's error log in the\ninventory panel. This call is not disruptive and designed to operated independently of other assistant operations, such as state management. See `setAssistantState` in the next section.\n\nRecommended usage: use this functionality where it would futher the user experience\nto show the user an error and it's cause. Do not use this where things will be retried,\ncleaned up automatically, or are not relevant to the user.\n\n```js\ntry{\n  // Do work\n} catch(e) {\n  AssistantAPIClient.reportError(e)\n}\n```\n\n### State management\n\n#### clearState = () =>\nThis will remove all callbacks from all listeners.\n\n```js\nawait AssistantAPIClient.clearState()\n```\n\n#### setAssistantState = (state) =>\nThis sets the current state of the assistant using the\n`AssistantState` enum. Setting a state of `WORKING` will\ncreate the 'working' status spinner in the Assistant\nInventory Panel in the Maana Q UI. Conversely, setting an `IDLE` state will\nremove the spinner. This adds to user experience by informing users of the\nstatus of operations.\n\n```js\nimport {\n  default as AssistantAPIClient,\n  AssistantState\n} from '@io-maana/q-assistant-client'\n\n...\n\nAssistantAPIClient.setAssistantState(AssistantState.WORKING)\n\n...\n\nAssistantAPIClient.setAssistantState(AssistantState.IDLE)\n\n```\nUI User Prompt: If the assistant is in a `WORKING` state, the Maana Q UI will\nwarn the user before leaving the workspace.\n\nNOTE: while an assistant is in a working state, it will\nnot receive `inventoryChanged` events--an aggregated inventory diff\nwill be sent once the assistant is set back to `IDLE`.\n\nRecommended usage: Control states at a high level using try/catch/finally\nflow incorporating the `reportError` API call.\n\n```js\ntry{\n  AssistantAPIClient.setAssistantState(AssistantState.WORKING)\n  // Do work, await high-level tasks, etc.\n} catch(e) {\n  AssistantAPIClient.reportError(e)\n} finally{\n  AssistantAPIClient.setAssistantState(AssistantState.IDLE)\n}\n```\n\n#### AssistantState (enum)\nContains the valid assistant states: `IDLE` or `WORKING`.\n\nMust be imported in addition to the AssistantAPIClient:\n\n```js\nimport {\n  default as AssistantAPIClient,\n  AssistantState\n} from '@io-maana/q-assistant-client'\n```\n\n\n### User Info\nThe `UserInfo` object:\n```js\n{\n email: string,\n name: string\n}\n```\n\n#### getUserInfo = () =>\nReturns a Userinfo object pertaining to the logged in user.\n\n```js\nconst userInfo = await AssistantAPIClient.getUserInfo()\n```\n### Selection\nThe `Selection` object:\n```js\n{\n  kindId: string\n  kindName: string\n  id: string\n}\n```\n\n#### getCurrentSelection = () =>\nReturns an Array of `Selection` objects:\n\n```js\nconst {selection} = await AssistantAPIClient.getCurrentSelection();\n```\n\n#### addSelectionChangedListener = async cb =>\nAdds a callback function to be executed upon a valid workspace selection change.\n\nCallback value is an array of Selection objects:\n\n```js\n// Create the selection callback.\nconst selectionCB = ({selection})=>{\n  console.log('Workspace selection has changed.')\n  selection.forEach(i=>{\n    console.log('Kind: ',i.kindName)\n    console.log('Instance Id:',i.id)\n    console.log('Kind Id:',i.kindId)\n  })\n}\n\n// Add the listener.\nAssistantAPIClient.addSelectionChangedListener(selectionCB);\n```\n\nThis function only exists on the Q-Assistant-Client--only enableSelectionChangedNotification is called on the API.\n\n#### removeSelectionChangedListener = async cb =>\nThis will have to be called on a 1:1 basis with addSelectionChangedListener calls if supplying a callback.\n\n```js\nAssistantAPIClient.removeSelectionChangedListener(selectionCB)\n```\n\n**If NOT supplying a callback to this call, all selection changed listeners will be removed.\n\n```js\nAssistantAPIClient.removeSelectionChangedListener()\n```\n\nThis function only exists on the Q-Assistant-Client--only disableSelectionChangedNotification is called on the API.\n\n\n### Services\nThe `Service` object:\n```js\n{\n   id: string,\n   name: string\n   endpointUrl: string,\n   getKinds: () => // Returns [] of Kinds objects\n   getFunctions: () => // Returns [] of Function objects\n}\n```\n\n#### getServiceById = id =>\nThis will return a service that exists within the scope of the workspace.\n** Assistant services will return null. Services outside the scope of the workspace will cause an error to be returned as 'Unable to load a Service from outside of the workspace.'\n\n```js\nconst svc = await AssistantAPIClient.getServiceById(id)\n```\n\n#### createService = id =>\nCreates a service in Q.\n\nNote: This will create the service, but does NOT import it into the workspace.\nYou will need to use `importService` on the Workspace object to import it.\nReturns a promise that resolves\n\n```js\n    const service = {\n      id: ...,\n      name: ...,\n      endpointUrl: ...,\n      serviceType: ...\n    }\n\n    await AssistantAPIClient.createService(service)\n```\n\n#### deleteService = id =>\nDeletes a service from Q.\n\n```js\n    await AssistantAPIClient.deleteService(id)\n```\n\n#### refreshServiceSchema = id =>\nRefreshes a service by fetching its schema. This will also\nreload the service inventory in the currently visible workspace.\n\n```js\nawait AssistantAPIClient.refreshServiceSchema(\"id\")\n```\n\n#### reloadService = id =>\nReloads a service in the inventory in the currently visible workspace.\n\n```js\nawait AssistantAPIClient.reloadService(\"id\")\n```\n\n### Workspace\n\n#### getWorkspace = () =>\nReturns a Workspace object representing the workspace.\n\n```js\nconst ws = await AssistantAPIClient.getWorkspace(id)\n```\n\nNote: The `id` parameter is optional. If it is not supplied, the query\nwill return the current/visible workspace.\n\nThe `Workspace` object:\n\n```js\n\n{\n    id: string,\n    name: string,\n    endpointUrl: string,\n    workspaceServiceId: string,\n    modelServiceId: string,\n    logicServiceId: string,\n\n    //\n    // Locking information\n    //\n    async lockedBy() {\n      // Returns the e-mail address of the user who locked the Workspace, or\n      // null if the Workspace is not currently locked.\n    }\n    async canEdit() {\n      // Returns `true` when the Workspace is not locked, or the current user\n      // owns the lock.\n      // Returns 'false' when the Workspace is locked by a different user.\n    }\n    async setLocked(isLocked) {\n      // Takes a boolean or undefined for `isLocked`.\n      //  `true` locks the Workspace as the current User.\n      //  `false` unlocks the Workspace\n      //  `undefined` causes it to toggle the current locked state.\n      // Returns a Promise that will resolve or reject when the task is done.\n    }\n\n    //\n    // Knowledge Graphs\n    //\n    getActiveGraph: async () => {\n      // Returns the active Graph object.\n      // Returns null if active graph is not of type 'Knowledge Graph', or if an\n      // active graph is deleted, thereby setting active graph to null.\n    },\n    getKnowledgeGraphs: async () => {\n      // Returns [Graph]\n    },\n    // TODO: define input\n    createKnowledgeGraph: input =>\n    // TODO: define input\n    createKnowledgeGraphs: input =>\n\n    //\n    // Services\n    //\n    getImportedServices: async () => {\n      // Returns an array of Service objects that have\n      // been imported into the workspace.\n      // No assistant services will be returned.\n    },\n    getImportedAssistants: async () => {\n      // Returns a list of imported assistants.\n    },\n    importService: serviceId => {\n      // Imports a service by it's ID.\n    },\n    importServices: serviceIds => {\n      // Imports services by their IDs.\n    },\n    removeServices: serviceIds => {\n      // Removes a list of services from the workspace.\n    },\n    removeService: serviceId => {\n      // Removes a service from the workspace.\n    },\n\n    //\n    // Functions\n    //\n    getFunctions: async () => {\n      // Returns an array of functions in the workspace (includes boilerplate).\n    },\n    createFunction: funcData => {\n      // Creates a function and adds it to the graph.\n    }\n    createFunctions: funcData =>{\n      // Creates several functions and adds them to the graph.\n    }\n    updateFunction: funcData => {\n      // Updates a function.\n    },\n    updateFunctions: funcData =>{\n      // Updates functions based on input array.\n    },\n    deleteFunction: funcId => {\n      // Deletes a function by its ID.\n    },\n    getFunctionGraph: funcId => {\n      // Returns a function graph by its ID.\n    }\n\n    //\n    // Kinds\n    //\n    getKinds: async () => {\n      // Returns an array of functions in the workspace (includes boilerplate).\n    },\n    createKind: kindData => {\n      // Currently same input as AssistantAPIClient call.\n    },\n    createKinds: kindData => {\n      // Currently same input as AssistantAPIClient call.\n    },\n    updateKind: kindData => {\n      // Currently same input as AssistantAPIClient call.\n    },\n    updateKinds: kindData => {\n      // Currently same input as AssistantAPIClient call.\n    },\n    deleteKind: kindId => {\n      // Currently same input as AssistantAPIClient call.\n    }\n    // Event Triggers\n    triggerRepairEvent: () => {\n      // Triggers the repair event on a workspace.\n    }\n  };\n}\n```\n\n\n### Graphs\nThe `Graph` object:\n```js\n{\n  id: string,\n  name: string,\n  offsetX: Number,\n  offsetY: Number,\n  zoom: Number,\n  getNodes: async () => {\n      // Returns [Node]\n  },\n\n  addNode: async (type, instance, changeSelection) => {\n      // Returns Node\n  },\n  removeNode: async id => {\n      // Should return nothing or error.\n      // Currently returning [] in all cases.\n  },\n  updateNodeLayout: async (nodeId, { x, y, collapsed }) => {\n  },\n  updateGraphLayout: async ({ offsetX, offsetY, zoom }) => {\n  }\n\n  //\n  // Locking information\n  //\n  async lockedBy() {\n    // Returns the e-mail address of the user who locked the Graph, or null if\n    // the Graph is not currently locked.\n  }\n  async canEdit() {\n    // Returns `true` when the Graph is not locked, or the current user owns the\n    // lock.\n    // Returns 'false' when the Graph is locked by a different user.\n  }\n  async setLocked(isLocked) {\n    // Takes a boolean or undefined for `isLocked`.\n    //  `true` locks the Graph as the current User.\n    //  `false` unlocks the Graph\n    //  `undefined` causes it to toggle the current locked state.\n    // Returns a Promise that will resolve or reject when the task is done.\n  }\n}\n```\n\n#### Getting a graph object:\nGraph objects are obtained through an instance of a Workspace\n\n```js\nconst ag = await ws.getActiveGraph()\n```\n\nor\n\n```js\nconst kgs = await ws.getKnowledgeGraphs()\n```\n\n#### Manipulating Graphs\n\n**Only the active graph may be manipulated.\n\nAll graph manipulations should be ‘visually’ verifiable on the graph itself, i.e., adds/removes/positioning, should all be reflected on the graph itself.\n\nThe `Node` object:\n```js\n{\nid: string\nx: number\ny: number\ncollapsed: boolean\nknowledgeGraphNode {\n  id: string\n  innerKind: Kind\n  innerFunction: Function\n}\n}\n```\n\n#### addNode(type, instance, changeSelection) =>\n\nTakes type (“Function” or “Kind”), instance (the Function or Kind object), and optionally a boolean to indicate whether the selection should be changed to this new node.\n\nReturns the newly created Node object.\n\n```js\nconst node = await ag.addNode('Kind',kind)\n```\n\n#### removeNode(id) =>\n\nTakes the id of Node to be deleted. Returns either undefined or an error.\n\n```js\nawait ag.removeNode(node.id)\n```\n\n#### getNodes() =>\nReturns an array of Node objects from the graph.\n\n```js\nconst nodes = await ag.getNodes()\n```\n\n#### updateNodeLayout: async (nodeId, { x, y, collapsed})=>\nUpdates a Node layout given a node ID and node coordinates (`x` and/or `y`) or a `collapsed` value. x/y values must be a number, and collapsed must be a boolean. Whatever is not specified will remain current.\n\n```js\nag.updateNodeLayout(id,{x:100,y:100,collapsed:true})\n```\n\n#### updateGraphLayout: async ({ offsetX, offsetY, zoom})=>\nUpdates a Graph layout given numerical values for x/y offsets and the zoom.\n\n```js\nag.updateGraphLayout({offsetX:50, offsetY:50, zoom: 70})\n```\n\n### Functions\n\nThe `Function` object:\n```js\n{\n    id: string\n    name: string\n    service {\n      id: string\n      name: string\n    }\n    arguments {\n      id: string\n      name: string\n      type: string\n      modifiers: Array[string]\n      typeKindId:: string\n      kind {\n        id: string\n        name: string\n      }\n    }\n    implementation {\n      id: string\n      entrypoint {\n        id: string\n      }\n      operations {\n        id: string\n        type: string\n        function {\n          id: string\n          name: string\n        }\n        argumentValues {\n          id: string\n          argument {\n            id: string\n          }\n          operation {\n            id: string\n          }\n          argumentRef: string\n        }\n      }\n    }\n    isGenerated: boolean\n    functionType: string\n    graphqlOperationType: string\n    outputType: string\n    outputKindId: string\n    outputModifiers: Array[string]\n    kind {\n      id: string\n      name: string\n    }\n\n    //\n    // Locking information\n    //\n    async lockedBy() {\n      // Returns the e-mail address of the user who locked the Function, or null\n      // if the Function is not currently locked.\n    }\n    async canEdit() {\n      // Returns `true` when the Function is not locked, or the current user\n      // owns the lock.\n      // Returns 'false' when the Function is locked by a different user.\n    }\n    async setLocked(isLocked) {\n      // Takes a boolean or undefined for `isLocked`.\n      //  `true` locks the Function as the current User.\n      //  `false` unlocks the Function\n      //  `undefined` causes it to toggle the current locked state.\n      // Returns a Promise that will resolve or reject when the task is done.\n    }\n}\n```\n\n`FunctionExecutionResult` object:\n```js\n{\n  id: string,\n  result: JSON\n}\n```\n\n#### executeFunction = ( {id, variables, resolve} ) =>\nExecutes a function based on its id, with optional inputs for variables and a resolve string (this specifies the fields to be returned, which must be valid based on the result).\n\nReturns : JSON matching shape of result , unless no sub-selection of fields is required in the execution.\n\nThis following piece of code will execute a Function given a function ID, and pass in variables for ‘example’, requesting back id and name fields.\n\n```js\nconst res = await AssistantAPIClient.executeFunction({functionId: func.id, variables: {\"variableName\": \"variableValue\"}, resolve: \"{ id name }\");\n```\n\n#### createFunction = input =>\nCreates a function based on the input provided.\n\nReturns: the created Function object.\n\n**Using create function will only place the function in the workspace’s inventory--it will not place the function as a node on the Graph. In order to do this, you must pass the created function into the addNode function on the active Graph, making sure to specify ‘Function' as the type.\n\n```js\nconst createFunctionInput = {\n  name:\"yourName\",\n  arguments:[],\n  outputType: \"STRING\",\n  graphqlOperationType:\"QUERY\",\n  functionType: \"CKG\"\n}\n\nconst createdFunction = await AssistantAPIClient.createFunction(createFunctionInput)\n```\n\n#### updateFunction = input =>\nInput is the same for creating a function. It’s important to note that the arguments property will be replaced in it’s entirety with whatever is provided (if a value is provided.\n\nReturns the updated `Function` object.\n\n```js\nconst updatedFunction = await AssistantAPIClient.updateFunction(input);\n```\n\n#### deleteFunction = input =>\nInput is the id of the Function to be deleted. Returns the deleted function as a promise.\n\n```js\nconst deletedFunction = await AssistantAPIClient.deleteFunction('id...');\n```\n\n#### getFunctionById = id =>\nReturns a Function as a promise based on the ID provided.\n\n```js\nconst func = await AssistantAPIClient.getFunctionById('id...');\n```\n\n#### addFunctionExecutionListener = async (id, cb) =>\nAssociates a callback function with the execution of a particular Function. When the Function matching the id parameter is executed, its FunctionExecutionResult object passed to the callback. Returns undefined.\n\nExample function execution callback and listener registration:\n\n```js\nfunction exampleFunctionCB (result){\n  console.log(`Function executed with result:`, result)\n}\n\nAssistantAPIClient.addFunctionExecutionListener('id...', exampleFunctionCB)\n```\n\n#### removeFunctionExecutionListener = async (id, cb) =>\nRemoves a Function execution listener based on the function ID and a reference to the callback function. If no callback is supplied, all listeners associated with the Function ID will be removed. Returns undefined.\n\n```js\nAssistantAPIClient.removeFunctionExecutionListener('id..', exampleFunctionCB)\n```\n\n### Kinds\nThe `Kind` object:\n```js\n{\n    id: string\n    name: string\n    service: {\n      id\n      name\n    }\n    isGenerated: boolean\n    schema {\n      id: string\n      name: string\n      type: string\n      typeKindId: string\n      modifiers: Array[string]\n      kind {\n        id: string\n        name: string\n      }\n    }\n}\n```\n\n#### createKind = input =>\nCreates a Kind based on an input object. Returns a promise that resolves to the created Kind object.\n\n```js\nconst kindInput = {\n name: \"someKind\",\n schema:[\n  { name: \"someField1\", type: STRING },\n  { name: \"someField2\", type: STRING }\n ]\n}\n\nconst newKind = await AssistantAPIClient.createKind(kindInput)\n```\n\n#### createKinds = input =>\nA plural version of `createKind` accepting an array of input objects.\nReturns a promise that resolves to an array of created Kind objects.\n\n```js\nconst kindsInput = [{\n name: \"someKind\",\n schema:[\n  { name: \"someField1\", type: STRING },\n  { name: \"someField2\", type: STRING }\n ]\n}, ...]\n\nconst newKinds = await AssistantAPIClient.createKinds(kindsInput)\n```\n\n\n#### updateKind = input =>\nUpdates a Kind based on an input object.\n\nUpdate Semantics: Only properties specified will be updated. If updating the schema, the entire schema must be specified as it will be replaced in its entirety.\n\nReturns a promise that resolves to the updated `Kind` object.\n\n```js\nconst updated = await AssistantAPIClient.updateKind(input)\n```\n\n#### deleteKind = input =>\nDeletes a Kind given a kind ID.\n\n```js\nconst deleted = await AssistantAPIClient.deleteKind(input)\n```\n\n#### getKindById = id =>\nReturns a promise that resolves to a Kind object given the specified kind ID.\n\nIn v3.2.2, any requested non-system kinds will be returned.\nIn v3.2.1, only kinds in the workspace or those of imported services will be returned.\n\n```js\nconst kind = await AssistantAPIClient.getKindById(id)\n```\n\n#### getKindsById = ids =>\nReturns a promise that resolves to an array of Kind objects given an array of kind IDs. Only kinds in the workspace or those of imported services will be returned.\n\n```js\nconst ids = [\"...\",\"...\",...]\nconst kind = await AssistantAPIClient.getKindsById(ids)\n```\n\n#### getAllReferencedKinds = input =>\nRecursively collects all kinds that are referenced in a kind's schema, starting\nwith a kind ID. For example if the ID of kind A is supplied as an input, and Kind `A` contains a field of type Kind `B`, and `B` contains a field of type Kind `C`,\nan array containing the kinds objects for `A`, `B`, `C` will be returned (as a promise).\n\n```js\nconst initialId = [\"...\"]\nconst kinds = await AssistantAPIClient.getAllReferencedKinds({\n          ids: initialId\n        })\n```\n\n\n### Inventory\n\nThe `InventoryChanged` object:\n```js\n{\n  kinds: {\n    adds: [DiffItem]\n    deletes: [DiffItem]\n    updates: [DiffItem]\n  }\n  functions:{\n    adds: [DiffItem]\n    deletes: [DiffItem]\n    updates: [DiffItem]\n  }\n  services: {\n    adds: [DiffItem]\n    deletes: [DiffItem]\n    updates: [DiffItem]\n  }\n}\n```\n\nThe `DiffItem` object:\n```js\n{\n  id: string,\n  name: string\n}\n```\n\n#### addInventoryChangedListener = async cb =>\nRegisters a callback function with the inventory changed event. When workspace inventory changes the callback function will be called with the InventoryChangedobject. Returns undefined.\n\n**Use-case note: an ‘update’ diff for inventory services is unlikely in general usage.\n\n```js\nconst inventoryCB = ({diff}) => {\n  if(diff.kinds) console.log('KINDS CHANGED',diff.kinds)\n  if(diff.functions) console.log('FUNCTIONS CHANGED', diff.functions)\n  if(diff.services) console.log('SERVICES CHANGED',diff.services)\n}\n\nAssistantAPIClient.addInventoryChangedListener(inventoryCB)\n```\n\nThis function exists on the Q-Assisant-Client only--only enableSelectionChangedNotification is used on the API side.\n\n#### removeInventoryChangedListener = async cb =>\nRemoves an inventory changed listener given the referenced callback. If no callback is specified, all listeners will be removed. Returns undefined.\n\n```js\nAssistantAPIClient.removeInventoryChangedListener(inventoryCB)\n```\n\nThis function exists on the Q-Assisant-Client only--only disableSelectionChangedNotification is used on the API side.\n\n#### moveKindsAndFunctions = (originId, targetId, kindIds, functionIds) =>\nMoves a collection of Kinds and Functions from the origin Workspace to the target Workspace.\n\n```js\n  await AssistantAPIClient.moveKindsAndFunctions(\n    originWorkspaceId,\n    targetId,\n    kindIds,\n    functionIds\n  );\n```\n\n### Locking Changed Event\n\nAn event is triggered when the locked state of the currently active Workspace or\nits Knowledge Graphs and Functions change.\n\nThe `LockingChanged` object:\n```js\n{\n  workspaces: [LockItem],\n  knowledgeGraphs: [LockItem],\n  functions: [LockItem]\n}\n```\n\nThe `LockItem` object:\n```js\n{\n  id: string\n  lockedBy: string\n}\n```\n\n#### addLockingChangedListener = cb =>\n\nRegisters a callback function with the locking changed event. When the currently\nactive Workspace or its Knowledge Graphs and Functions change the callback\nfunction will be called with the `LockingChanged` object. Returns undefined.\n\n```js\nconst lockingChangedCB = ({ locks }) => {\n  if(locks.workspace) console.log('WORKSPACES CHANGED', locks.workspace);\n  if(locks.knowledgeGraphs) console.log('KNOWLEDGE GRAPHS CHANGED', locks.knowledgeGraphs);\n  if(locks.functions) console.log('FUNCTIONS CHANGED', locks.functions);\n}\n\nAssistantAPIClient.addLockingChangedListener(lockingChangedCB);\n```\n\n#### removeLockingChangedListener = cb =>\n\nRemoves an locking changed listener given the referenced callback. If no\ncallback is specified, all listeners will be removed. Returns undefined.\n\n```js\nAssistantAPIClient.removeLockingChangedListener(lockingChangedCB)\n```\n\n## Troubleshooting Assistant Issues\n### Assistant root file has loaded, but not other content\nObserving in the browser's dev tools that some resources have loaded correctly (usually the root), but other's haven't (usually nested files or chunks), is indicative of a failure of Q Gateway to proxy due to not having a 'relative' path structure.\n\n### You are seeing post-robot `NO ACK` errors in the console.\nThese errors stem from a failed acknowledgement for a call either between the client and the API or vice-versa. Here, this means that the web app 'window' (the assistant) cannot communicate with, or access, the 'window.parent' (Maana K-Portal) object.\n\nCommonly, these will stem from the 'window' (the assistant) not being loaded or in a loadable state, which means the API will not receive an acknowledgement when it fires an event.\n\nImproper CORS configuration is also a common culprit (also verify if using docker or nginx that your proxying and networking is configured correctly to allow communication and to accout for CORS).","readmeFilename":"README.md","gitHead":"3e97ed1b67ac6aa36fe946be5ce16cabe72b3767","_id":"@io-maana/q-assistant-client@3.3.0-beta.8","_nodeVersion":"12.20.1","_npmVersion":"6.14.10","dist":{"integrity":"sha512-E2xK4V5exoKyHToaKwi3nqiFk0/+G6Tmyg+1t99g2sJshVlXb6/HDZpK8F59gFyPAafBgExtxy+rANn0DuEtkQ==","shasum":"630b268ec60960f8396866099a0800fff56a2138","tarball":"https://registry.npmjs.org/@io-maana/q-assistant-client/-/q-assistant-client-3.3.0-beta.8.tgz","fileCount":81,"unpackedSize":351112,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJgG0MHCRA9TVsSAnZWagAA6osP/2LwmaRZSIm2TcgiShj/\nlm+x2nMjlndymlepAXfpVrZjz/yF75+vmI1XxYcG3W8BcHAkr6BHTwNDme/C\neA+4SYZAW/SSX3s/H4JBg/dX3gCFgJzpinnr3Bt0Gz/fpVa2hJLUG4uyNiZR\nO6y6ZDnZR5Ln0t7xhKXw1iaVuJjVWsH+oFGpjl3hB920HdUAKI4ZCgXOSMsE\nv+yQJ8BNqDGOo01XFhgCjrJs8UfTSASMHHlDtZJMQuBs6IFDt7xoSoGsRLtX\nJgGkuKbzfs8gF5xLt7I6zwWLeHqx2qMLWO9zMTWxrTZIwNMPspahG5GNT2sA\nwXehN/p/1IuvaQrjpg1Cx1XgRg+1eIuqmeM8PuHsKgnm5TJ1cs2uhvT36G1H\nFh3c13dDsl8TcSdwRehaJ1O/4JqCNTAKD06JzjSCMmpp5uQGTsLszRQRF3u8\nXd4N7lBsIdNQ3wIORBPjr7UxvZ2aLpXhLi2J2vFbv8R1s5LlcnZsWId1dzNA\nWBizcQtJIoM/rs28oLPkQngT16GxEbTA8aZh7TXkTWDRxiAzKKpr55qCtfoX\nf0/W87JXAjTvbBPK1SfXeYCHoVEGQI5E5ou88oUITRMhf6wECEY+TZ7Fhylq\nVONFf5xP7kibMfHH8RbcDofq8lYdR81neJVkEdvmivpM43kc7ICQIgZ/PNVx\nUDlz\r\n=PGg2\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEYCIQD3tmcEF0ipIhGlrFzY46Dhsvk3oM2AKHs1hiTNrHb0EgIhAOOX5Jpa0oMtkN+3M92ynIYkYZmGIyEZY9+22syG9puR"}]},"_npmUser":{"name":"teamcitymaana","email":"teamcity@maana.io"},"directories":{},"maintainers":[{"name":"witt3rd","email":"witt3rd@witt3rd.com"},{"name":"bzvetey","email":"bzvestey@gmail.com"},{"name":"abatyuk","email":"andrey@maana.io"},{"name":"rpovey","email":"rob@maana.io"},{"name":"teamcitymaana","email":"teamcity@maana.io"},{"name":"dlsmaana","email":"dlewissandy@maana.io"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/q-assistant-client_3.3.0-beta.8_1612399366505_0.8081763341287724"},"_hasShrinkwrap":false},"3.3.0-beta.9":{"name":"@io-maana/q-assistant-client","version":"3.3.0-beta.9","description":"JavaScript package to streamline communication between an assistant and the Maana Q Assistant API.","main":"build/index.js","types":"build/index.d.ts","exports":{"./":"./build/"},"scripts":{"build":"npm run build:ts && npm run build:doc","build:ts":"tsc --build tsconfig.json","build:doc":"typedoc","prepack":"npm run build","test":"echo \"Error: no test specified\" && exit 1","format":"prettier --write \"src/**/*.js\""},"repository":{"type":"git","url":"git+https://github.com/maana-io/q-assistant-client.git"},"keywords":["Maana","Q"],"author":{"name":"Logan Gore @ Maana.io"},"license":"MIT","bugs":{"url":"https://github.com/maana-io/q-assistant-client/issues"},"homepage":"https://github.com/maana-io/q-assistant-client#readme","dependencies":{"core-js":"3.6.4","post-robot":"10.0.29"},"devDependencies":{"@types/node":"^14.14.2","@types/post-robot":"^10.0.0","prettier":"2.0.5","typedoc":"^0.19.2","typedoc-plugin-markdown":"^3.0.11","typescript":"^3.9.5"},"readme":"# q-assistant-client\nA lightweight JavaScript client for Maana-Q Assistant developers that wraps post-message communication between an embedded Maana-Q assistant and the Maana-Q UI.\n\nYou can find the [API Documentation here](docs/README.md).\n\n## Abstract\nThe Q-Assistant-Client is intented to be used in a web application being leveraged as a Maana Q assistant (embedded as an iframe).\nThis assistant client will facilitate communication between the assistant and the parent frame.\nThe client provides a rich, asynchronous experience over what would otherwise be 'fire-and-forget'-style messaging\nvia post-post message communication.\n\n## Requirements and Assumptions\n\n### Post-Robot Library\nThe Maana Knowledge Portal (KPortal) uses the kraken/post-robot library [kraken/post-robot](https://github.com/krakenjs/post-robot) to enrich the communication with the assistant. Post-robot allows for asynchronous, promise-based request/response style behavior between the assistant and the assistant API.\n\nThe API requires that the client use the post-robot library. This assistant-client library is the easiest way to achieve this, and also adds a fair amount of 'sugar' to the process to improve developer productivity. Developers could, however, use post-robot directly in their own client implementation.\n\n### Maana-Gateway Proxy Requirements\nThe Maana-Gateway service requires relative paths (paths relative to the root) in the assistant web application in order to proxy the application and its content. For create-react-apps, for instance, this means setting \"homepage\" to \".\" in the package.json file.\n\n## Singleton Instance\nThe client is exported as a singleton to avoid duplicate registration on event listeners.\nYou can import the instance like this:\n\n```js\nimport AssistantAPIClient from '@io-maana/q-assistant-client';\n```\n\nFunction calls can be made against the client instance like any other javascript object. They are all async.\n\n```js\nconst workspace = await AssistantAPIClient.getWorkspace();\nconsole.log(\"Workspace:\", workspace)\n```\n\n## Dependencies\nPost-Robot\nhttps://github.com/krakenjs/post-robot\n\nPost-robot is used to provide a richer communication layer atop post-message.\n\n## Versioning\nThe Maana Q Assistant Client does not follow semantic versioning. Its versions\ntrack the releases of the Maana Q platform.\n\n## Examples\n@TODO Logan\n\n\n## Changes in v3.2.2\nImprovements in v3.2.2\n- Assistant State Management: WORKING, IDLE\n- Background Messaging/Eventing\n- Render Modes: BACKGROUND, DISPLAY\n- Expansion of Workspace object capabilities\n- Error Reporting\n- Repair Event\n- Plural versions of calls such as updateKind(s) to improve performance and developer experience.\n- InventoryChanged diffing is fully granular in v3.2.2--limitations\nin v3.2.1 only fired the Function diff for changes in Function name.\n\n### Deprecation\nThe following surface area IS removed from the\nclient in v3.2.2, and IS deprecated in the API:\n- AssistantAPIClient.enableSelectionChangedNotification\n- AssistantAPIClient.disableSelectionChangedNotification\n- AssistantAPIClient.enableInventoryChangedNotification\n- AssistantAPIClient.disableInventoryChangedNotification\n\nThe following surface area WILL BE removed from\nthe client in v3.2.4, and WILL BE deprecated in the API:\n- AssistantAPIClient.updateFunction (expected move to Workspace object)\n- AssistantAPIClient.updateKind (expected move to Workspace object)\n- AssistantAPIClient.deleteKind (expected move to Workspace object)\n- AssistantAPIClient.deleteFunction (expected move to Workspace object)\n\n## API Documentation\nMore information in the [API File](./API.md)\n\n### Assistant Render Mode\nAn assistant's render mode refers to whether it is being displayed in a visible manner to the user. As of v3.2.2, assistants are not closed when they are out of view.\nAll assistants will be loaded and kept in `BACKGROUND` render mode until they are\nplaced in the assistant panel, at which point the `DISPLAY` render mode event will be fired.\n\nNote: Assistants will receive all notifications/events while in BACKGROUND mode.\n\nDesign Consideration: It will be up to the developer to determine how state and resource use will be managed while an assistant is operating between BACKGROUND and DISPLAY modes.\n\n#### addRenderModeChangedListener = (cb) =>\nA listener to receive push events as to the assitant's render mode being changed.\n\n```js\nfunction handleRenderModeChanged(renderMode){\n  if (renderMode === 'DISPLAY'){\n    // Assistant is visible\n  } else {\n    // Assistant is not visible and running in background.\n  }\n}\n\nAssistantAPIClient.addRenderModeChangedListener(handleRenderModeChanged)\n\n```\n\n#### removeRenderModeChangedListener = (cb) =>\nRemoves the renderModeChanged listener by reference, or if no callback function reference is provided, it removes all listeners.\n\n#### getRenderMode = () =>\nReturns the current assistant render mode.\n\n```js\nconst renderMode = await AssistantAPIClient.getRenderMode()\n\nif (renderMode === 'DISPLAY'){\n  // Assistant is visible\n} else {\n  // Assistant is not visible and running in background.\n}\n\n```\n\n### Repair\nAssistants may get into situations where they are either out of sync with the Maana Q UI, or in a failure state. Assistants should be able to recover from these states.\n\nThe repair event functionality added in v3.2.2 is designed to notify the assistant that it must repair itself. This could mean a resync with its resources on the workspace or externally or, for some assistants, nothing at all.\n\nWhen is repair triggered?\nEither manually by a user clicking 'repair workspace' under the\nassistant inventory panel, or upon a workspace clone event. An assistant will be expected to handle either scenario.\n\nPerformance Consideration:\nFor some assistants, repair might involve 'introspecting'\nand processing the current workspace or Q system resources. This could be very resource intensive. Make sure you review this API guide to have an idea of what tools are\navailable to get the best results. It's always a good idea to check performance of repair on a large workspace and ensure necessary optimizations have been made.\n\nDesign Consideration:\nMake your workflows modular enough to be reused between repair and normal usage if possible.\n\n#### addRepairListener (cb) =>\n```js\n\nAssistantAPIClient.addRepairListener(()=>{\n  // Self-heal\n})\n\n```\n\nRecommended Usage: A repair process should be wrapped in the try/catch/finally flow shown in the `setAssistantState` API call to provide the user assistant-state and error updates as well as pause `inventoryChanged` notifications during repair (if the assistant has subscribed).\n\n#### removeRepairListener = (cb) =>\nRemoves the repair listener by reference, or if no callback function reference is provided, it removes all listeners.\n\n### User-facing Error Handling\n\n#### reportError (error) =>\nReports an error to the UI to be displayed in the assistant's error log in the\ninventory panel. This call is not disruptive and designed to operated independently of other assistant operations, such as state management. See `setAssistantState` in the next section.\n\nRecommended usage: use this functionality where it would futher the user experience\nto show the user an error and it's cause. Do not use this where things will be retried,\ncleaned up automatically, or are not relevant to the user.\n\n```js\ntry{\n  // Do work\n} catch(e) {\n  AssistantAPIClient.reportError(e)\n}\n```\n\n### State management\n\n#### clearState = () =>\nThis will remove all callbacks from all listeners.\n\n```js\nawait AssistantAPIClient.clearState()\n```\n\n#### setAssistantState = (state) =>\nThis sets the current state of the assistant using the\n`AssistantState` enum. Setting a state of `WORKING` will\ncreate the 'working' status spinner in the Assistant\nInventory Panel in the Maana Q UI. Conversely, setting an `IDLE` state will\nremove the spinner. This adds to user experience by informing users of the\nstatus of operations.\n\n```js\nimport {\n  default as AssistantAPIClient,\n  AssistantState\n} from '@io-maana/q-assistant-client'\n\n...\n\nAssistantAPIClient.setAssistantState(AssistantState.WORKING)\n\n...\n\nAssistantAPIClient.setAssistantState(AssistantState.IDLE)\n\n```\nUI User Prompt: If the assistant is in a `WORKING` state, the Maana Q UI will\nwarn the user before leaving the workspace.\n\nNOTE: while an assistant is in a working state, it will\nnot receive `inventoryChanged` events--an aggregated inventory diff\nwill be sent once the assistant is set back to `IDLE`.\n\nRecommended usage: Control states at a high level using try/catch/finally\nflow incorporating the `reportError` API call.\n\n```js\ntry{\n  AssistantAPIClient.setAssistantState(AssistantState.WORKING)\n  // Do work, await high-level tasks, etc.\n} catch(e) {\n  AssistantAPIClient.reportError(e)\n} finally{\n  AssistantAPIClient.setAssistantState(AssistantState.IDLE)\n}\n```\n\n#### AssistantState (enum)\nContains the valid assistant states: `IDLE` or `WORKING`.\n\nMust be imported in addition to the AssistantAPIClient:\n\n```js\nimport {\n  default as AssistantAPIClient,\n  AssistantState\n} from '@io-maana/q-assistant-client'\n```\n\n\n### User Info\nThe `UserInfo` object:\n```js\n{\n email: string,\n name: string\n}\n```\n\n#### getUserInfo = () =>\nReturns a Userinfo object pertaining to the logged in user.\n\n```js\nconst userInfo = await AssistantAPIClient.getUserInfo()\n```\n### Selection\nThe `Selection` object:\n```js\n{\n  kindId: string\n  kindName: string\n  id: string\n}\n```\n\n#### getCurrentSelection = () =>\nReturns an Array of `Selection` objects:\n\n```js\nconst {selection} = await AssistantAPIClient.getCurrentSelection();\n```\n\n#### addSelectionChangedListener = async cb =>\nAdds a callback function to be executed upon a valid workspace selection change.\n\nCallback value is an array of Selection objects:\n\n```js\n// Create the selection callback.\nconst selectionCB = ({selection})=>{\n  console.log('Workspace selection has changed.')\n  selection.forEach(i=>{\n    console.log('Kind: ',i.kindName)\n    console.log('Instance Id:',i.id)\n    console.log('Kind Id:',i.kindId)\n  })\n}\n\n// Add the listener.\nAssistantAPIClient.addSelectionChangedListener(selectionCB);\n```\n\nThis function only exists on the Q-Assistant-Client--only enableSelectionChangedNotification is called on the API.\n\n#### removeSelectionChangedListener = async cb =>\nThis will have to be called on a 1:1 basis with addSelectionChangedListener calls if supplying a callback.\n\n```js\nAssistantAPIClient.removeSelectionChangedListener(selectionCB)\n```\n\n**If NOT supplying a callback to this call, all selection changed listeners will be removed.\n\n```js\nAssistantAPIClient.removeSelectionChangedListener()\n```\n\nThis function only exists on the Q-Assistant-Client--only disableSelectionChangedNotification is called on the API.\n\n\n### Services\nThe `Service` object:\n```js\n{\n   id: string,\n   name: string\n   endpointUrl: string,\n   getKinds: () => // Returns [] of Kinds objects\n   getFunctions: () => // Returns [] of Function objects\n}\n```\n\n#### getServiceById = id =>\nThis will return a service that exists within the scope of the workspace.\n** Assistant services will return null. Services outside the scope of the workspace will cause an error to be returned as 'Unable to load a Service from outside of the workspace.'\n\n```js\nconst svc = await AssistantAPIClient.getServiceById(id)\n```\n\n#### createService = id =>\nCreates a service in Q.\n\nNote: This will create the service, but does NOT import it into the workspace.\nYou will need to use `importService` on the Workspace object to import it.\nReturns a promise that resolves\n\n```js\n    const service = {\n      id: ...,\n      name: ...,\n      endpointUrl: ...,\n      serviceType: ...\n    }\n\n    await AssistantAPIClient.createService(service)\n```\n\n#### deleteService = id =>\nDeletes a service from Q.\n\n```js\n    await AssistantAPIClient.deleteService(id)\n```\n\n#### refreshServiceSchema = id =>\nRefreshes a service by fetching its schema. This will also\nreload the service inventory in the currently visible workspace.\n\n```js\nawait AssistantAPIClient.refreshServiceSchema(\"id\")\n```\n\n#### reloadService = id =>\nReloads a service in the inventory in the currently visible workspace.\n\n```js\nawait AssistantAPIClient.reloadService(\"id\")\n```\n\n### Workspace\n\n#### getWorkspace = () =>\nReturns a Workspace object representing the workspace.\n\n```js\nconst ws = await AssistantAPIClient.getWorkspace(id)\n```\n\nNote: The `id` parameter is optional. If it is not supplied, the query\nwill return the current/visible workspace.\n\nThe `Workspace` object:\n\n```js\n\n{\n    id: string,\n    name: string,\n    endpointUrl: string,\n    workspaceServiceId: string,\n    modelServiceId: string,\n    logicServiceId: string,\n\n    //\n    // Locking information\n    //\n    async lockedBy() {\n      // Returns the e-mail address of the user who locked the Workspace, or\n      // null if the Workspace is not currently locked.\n    }\n    async canEdit() {\n      // Returns `true` when the Workspace is not locked, or the current user\n      // owns the lock.\n      // Returns 'false' when the Workspace is locked by a different user.\n    }\n    async setLocked(isLocked) {\n      // Takes a boolean or undefined for `isLocked`.\n      //  `true` locks the Workspace as the current User.\n      //  `false` unlocks the Workspace\n      //  `undefined` causes it to toggle the current locked state.\n      // Returns a Promise that will resolve or reject when the task is done.\n    }\n\n    //\n    // Knowledge Graphs\n    //\n    getActiveGraph: async () => {\n      // Returns the active Graph object.\n      // Returns null if active graph is not of type 'Knowledge Graph', or if an\n      // active graph is deleted, thereby setting active graph to null.\n    },\n    getKnowledgeGraphs: async () => {\n      // Returns [Graph]\n    },\n    // TODO: define input\n    createKnowledgeGraph: input =>\n    // TODO: define input\n    createKnowledgeGraphs: input =>\n\n    //\n    // Services\n    //\n    getImportedServices: async () => {\n      // Returns an array of Service objects that have\n      // been imported into the workspace.\n      // No assistant services will be returned.\n    },\n    getImportedAssistants: async () => {\n      // Returns a list of imported assistants.\n    },\n    importService: serviceId => {\n      // Imports a service by it's ID.\n    },\n    importServices: serviceIds => {\n      // Imports services by their IDs.\n    },\n    removeServices: serviceIds => {\n      // Removes a list of services from the workspace.\n    },\n    removeService: serviceId => {\n      // Removes a service from the workspace.\n    },\n\n    //\n    // Functions\n    //\n    getFunctions: async () => {\n      // Returns an array of functions in the workspace (includes boilerplate).\n    },\n    createFunction: funcData => {\n      // Creates a function and adds it to the graph.\n    }\n    createFunctions: funcData =>{\n      // Creates several functions and adds them to the graph.\n    }\n    updateFunction: funcData => {\n      // Updates a function.\n    },\n    updateFunctions: funcData =>{\n      // Updates functions based on input array.\n    },\n    deleteFunction: funcId => {\n      // Deletes a function by its ID.\n    },\n    getFunctionGraph: funcId => {\n      // Returns a function graph by its ID.\n    }\n\n    //\n    // Kinds\n    //\n    getKinds: async () => {\n      // Returns an array of functions in the workspace (includes boilerplate).\n    },\n    createKind: kindData => {\n      // Currently same input as AssistantAPIClient call.\n    },\n    createKinds: kindData => {\n      // Currently same input as AssistantAPIClient call.\n    },\n    updateKind: kindData => {\n      // Currently same input as AssistantAPIClient call.\n    },\n    updateKinds: kindData => {\n      // Currently same input as AssistantAPIClient call.\n    },\n    deleteKind: kindId => {\n      // Currently same input as AssistantAPIClient call.\n    }\n    // Event Triggers\n    triggerRepairEvent: () => {\n      // Triggers the repair event on a workspace.\n    }\n  };\n}\n```\n\n\n### Graphs\nThe `Graph` object:\n```js\n{\n  id: string,\n  name: string,\n  offsetX: Number,\n  offsetY: Number,\n  zoom: Number,\n  getNodes: async () => {\n      // Returns [Node]\n  },\n\n  addNode: async (type, instance, changeSelection) => {\n      // Returns Node\n  },\n  removeNode: async id => {\n      // Should return nothing or error.\n      // Currently returning [] in all cases.\n  },\n  updateNodeLayout: async (nodeId, { x, y, collapsed }) => {\n  },\n  updateGraphLayout: async ({ offsetX, offsetY, zoom }) => {\n  }\n\n  //\n  // Locking information\n  //\n  async lockedBy() {\n    // Returns the e-mail address of the user who locked the Graph, or null if\n    // the Graph is not currently locked.\n  }\n  async canEdit() {\n    // Returns `true` when the Graph is not locked, or the current user owns the\n    // lock.\n    // Returns 'false' when the Graph is locked by a different user.\n  }\n  async setLocked(isLocked) {\n    // Takes a boolean or undefined for `isLocked`.\n    //  `true` locks the Graph as the current User.\n    //  `false` unlocks the Graph\n    //  `undefined` causes it to toggle the current locked state.\n    // Returns a Promise that will resolve or reject when the task is done.\n  }\n}\n```\n\n#### Getting a graph object:\nGraph objects are obtained through an instance of a Workspace\n\n```js\nconst ag = await ws.getActiveGraph()\n```\n\nor\n\n```js\nconst kgs = await ws.getKnowledgeGraphs()\n```\n\n#### Manipulating Graphs\n\n**Only the active graph may be manipulated.\n\nAll graph manipulations should be ‘visually’ verifiable on the graph itself, i.e., adds/removes/positioning, should all be reflected on the graph itself.\n\nThe `Node` object:\n```js\n{\nid: string\nx: number\ny: number\ncollapsed: boolean\nknowledgeGraphNode {\n  id: string\n  innerKind: Kind\n  innerFunction: Function\n}\n}\n```\n\n#### addNode(type, instance, changeSelection) =>\n\nTakes type (“Function” or “Kind”), instance (the Function or Kind object), and optionally a boolean to indicate whether the selection should be changed to this new node.\n\nReturns the newly created Node object.\n\n```js\nconst node = await ag.addNode('Kind',kind)\n```\n\n#### removeNode(id) =>\n\nTakes the id of Node to be deleted. Returns either undefined or an error.\n\n```js\nawait ag.removeNode(node.id)\n```\n\n#### getNodes() =>\nReturns an array of Node objects from the graph.\n\n```js\nconst nodes = await ag.getNodes()\n```\n\n#### updateNodeLayout: async (nodeId, { x, y, collapsed})=>\nUpdates a Node layout given a node ID and node coordinates (`x` and/or `y`) or a `collapsed` value. x/y values must be a number, and collapsed must be a boolean. Whatever is not specified will remain current.\n\n```js\nag.updateNodeLayout(id,{x:100,y:100,collapsed:true})\n```\n\n#### updateGraphLayout: async ({ offsetX, offsetY, zoom})=>\nUpdates a Graph layout given numerical values for x/y offsets and the zoom.\n\n```js\nag.updateGraphLayout({offsetX:50, offsetY:50, zoom: 70})\n```\n\n### Functions\n\nThe `Function` object:\n```js\n{\n    id: string\n    name: string\n    service {\n      id: string\n      name: string\n    }\n    arguments {\n      id: string\n      name: string\n      type: string\n      modifiers: Array[string]\n      typeKindId:: string\n      kind {\n        id: string\n        name: string\n      }\n    }\n    implementation {\n      id: string\n      entrypoint {\n        id: string\n      }\n      operations {\n        id: string\n        type: string\n        function {\n          id: string\n          name: string\n        }\n        argumentValues {\n          id: string\n          argument {\n            id: string\n          }\n          operation {\n            id: string\n          }\n          argumentRef: string\n        }\n      }\n    }\n    isGenerated: boolean\n    functionType: string\n    graphqlOperationType: string\n    outputType: string\n    outputKindId: string\n    outputModifiers: Array[string]\n    kind {\n      id: string\n      name: string\n    }\n\n    //\n    // Locking information\n    //\n    async lockedBy() {\n      // Returns the e-mail address of the user who locked the Function, or null\n      // if the Function is not currently locked.\n    }\n    async canEdit() {\n      // Returns `true` when the Function is not locked, or the current user\n      // owns the lock.\n      // Returns 'false' when the Function is locked by a different user.\n    }\n    async setLocked(isLocked) {\n      // Takes a boolean or undefined for `isLocked`.\n      //  `true` locks the Function as the current User.\n      //  `false` unlocks the Function\n      //  `undefined` causes it to toggle the current locked state.\n      // Returns a Promise that will resolve or reject when the task is done.\n    }\n}\n```\n\n`FunctionExecutionResult` object:\n```js\n{\n  id: string,\n  result: JSON\n}\n```\n\n#### executeFunction = ( {id, variables, resolve} ) =>\nExecutes a function based on its id, with optional inputs for variables and a resolve string (this specifies the fields to be returned, which must be valid based on the result).\n\nReturns : JSON matching shape of result , unless no sub-selection of fields is required in the execution.\n\nThis following piece of code will execute a Function given a function ID, and pass in variables for ‘example’, requesting back id and name fields.\n\n```js\nconst res = await AssistantAPIClient.executeFunction({functionId: func.id, variables: {\"variableName\": \"variableValue\"}, resolve: \"{ id name }\");\n```\n\n#### createFunction = input =>\nCreates a function based on the input provided.\n\nReturns: the created Function object.\n\n**Using create function will only place the function in the workspace’s inventory--it will not place the function as a node on the Graph. In order to do this, you must pass the created function into the addNode function on the active Graph, making sure to specify ‘Function' as the type.\n\n```js\nconst createFunctionInput = {\n  name:\"yourName\",\n  arguments:[],\n  outputType: \"STRING\",\n  graphqlOperationType:\"QUERY\",\n  functionType: \"CKG\"\n}\n\nconst createdFunction = await AssistantAPIClient.createFunction(createFunctionInput)\n```\n\n#### updateFunction = input =>\nInput is the same for creating a function. It’s important to note that the arguments property will be replaced in it’s entirety with whatever is provided (if a value is provided.\n\nReturns the updated `Function` object.\n\n```js\nconst updatedFunction = await AssistantAPIClient.updateFunction(input);\n```\n\n#### deleteFunction = input =>\nInput is the id of the Function to be deleted. Returns the deleted function as a promise.\n\n```js\nconst deletedFunction = await AssistantAPIClient.deleteFunction('id...');\n```\n\n#### getFunctionById = id =>\nReturns a Function as a promise based on the ID provided.\n\n```js\nconst func = await AssistantAPIClient.getFunctionById('id...');\n```\n\n#### addFunctionExecutionListener = async (id, cb) =>\nAssociates a callback function with the execution of a particular Function. When the Function matching the id parameter is executed, its FunctionExecutionResult object passed to the callback. Returns undefined.\n\nExample function execution callback and listener registration:\n\n```js\nfunction exampleFunctionCB (result){\n  console.log(`Function executed with result:`, result)\n}\n\nAssistantAPIClient.addFunctionExecutionListener('id...', exampleFunctionCB)\n```\n\n#### removeFunctionExecutionListener = async (id, cb) =>\nRemoves a Function execution listener based on the function ID and a reference to the callback function. If no callback is supplied, all listeners associated with the Function ID will be removed. Returns undefined.\n\n```js\nAssistantAPIClient.removeFunctionExecutionListener('id..', exampleFunctionCB)\n```\n\n### Kinds\nThe `Kind` object:\n```js\n{\n    id: string\n    name: string\n    service: {\n      id\n      name\n    }\n    isGenerated: boolean\n    schema {\n      id: string\n      name: string\n      type: string\n      typeKindId: string\n      modifiers: Array[string]\n      kind {\n        id: string\n        name: string\n      }\n    }\n}\n```\n\n#### createKind = input =>\nCreates a Kind based on an input object. Returns a promise that resolves to the created Kind object.\n\n```js\nconst kindInput = {\n name: \"someKind\",\n schema:[\n  { name: \"someField1\", type: STRING },\n  { name: \"someField2\", type: STRING }\n ]\n}\n\nconst newKind = await AssistantAPIClient.createKind(kindInput)\n```\n\n#### createKinds = input =>\nA plural version of `createKind` accepting an array of input objects.\nReturns a promise that resolves to an array of created Kind objects.\n\n```js\nconst kindsInput = [{\n name: \"someKind\",\n schema:[\n  { name: \"someField1\", type: STRING },\n  { name: \"someField2\", type: STRING }\n ]\n}, ...]\n\nconst newKinds = await AssistantAPIClient.createKinds(kindsInput)\n```\n\n\n#### updateKind = input =>\nUpdates a Kind based on an input object.\n\nUpdate Semantics: Only properties specified will be updated. If updating the schema, the entire schema must be specified as it will be replaced in its entirety.\n\nReturns a promise that resolves to the updated `Kind` object.\n\n```js\nconst updated = await AssistantAPIClient.updateKind(input)\n```\n\n#### deleteKind = input =>\nDeletes a Kind given a kind ID.\n\n```js\nconst deleted = await AssistantAPIClient.deleteKind(input)\n```\n\n#### getKindById = id =>\nReturns a promise that resolves to a Kind object given the specified kind ID.\n\nIn v3.2.2, any requested non-system kinds will be returned.\nIn v3.2.1, only kinds in the workspace or those of imported services will be returned.\n\n```js\nconst kind = await AssistantAPIClient.getKindById(id)\n```\n\n#### getKindsById = ids =>\nReturns a promise that resolves to an array of Kind objects given an array of kind IDs. Only kinds in the workspace or those of imported services will be returned.\n\n```js\nconst ids = [\"...\",\"...\",...]\nconst kind = await AssistantAPIClient.getKindsById(ids)\n```\n\n#### getAllReferencedKinds = input =>\nRecursively collects all kinds that are referenced in a kind's schema, starting\nwith a kind ID. For example if the ID of kind A is supplied as an input, and Kind `A` contains a field of type Kind `B`, and `B` contains a field of type Kind `C`,\nan array containing the kinds objects for `A`, `B`, `C` will be returned (as a promise).\n\n```js\nconst initialId = [\"...\"]\nconst kinds = await AssistantAPIClient.getAllReferencedKinds({\n          ids: initialId\n        })\n```\n\n\n### Inventory\n\nThe `InventoryChanged` object:\n```js\n{\n  kinds: {\n    adds: [DiffItem]\n    deletes: [DiffItem]\n    updates: [DiffItem]\n  }\n  functions:{\n    adds: [DiffItem]\n    deletes: [DiffItem]\n    updates: [DiffItem]\n  }\n  services: {\n    adds: [DiffItem]\n    deletes: [DiffItem]\n    updates: [DiffItem]\n  }\n}\n```\n\nThe `DiffItem` object:\n```js\n{\n  id: string,\n  name: string\n}\n```\n\n#### addInventoryChangedListener = async cb =>\nRegisters a callback function with the inventory changed event. When workspace inventory changes the callback function will be called with the InventoryChangedobject. Returns undefined.\n\n**Use-case note: an ‘update’ diff for inventory services is unlikely in general usage.\n\n```js\nconst inventoryCB = ({diff}) => {\n  if(diff.kinds) console.log('KINDS CHANGED',diff.kinds)\n  if(diff.functions) console.log('FUNCTIONS CHANGED', diff.functions)\n  if(diff.services) console.log('SERVICES CHANGED',diff.services)\n}\n\nAssistantAPIClient.addInventoryChangedListener(inventoryCB)\n```\n\nThis function exists on the Q-Assisant-Client only--only enableSelectionChangedNotification is used on the API side.\n\n#### removeInventoryChangedListener = async cb =>\nRemoves an inventory changed listener given the referenced callback. If no callback is specified, all listeners will be removed. Returns undefined.\n\n```js\nAssistantAPIClient.removeInventoryChangedListener(inventoryCB)\n```\n\nThis function exists on the Q-Assisant-Client only--only disableSelectionChangedNotification is used on the API side.\n\n#### moveKindsAndFunctions = (originId, targetId, kindIds, functionIds) =>\nMoves a collection of Kinds and Functions from the origin Workspace to the target Workspace.\n\n```js\n  await AssistantAPIClient.moveKindsAndFunctions(\n    originWorkspaceId,\n    targetId,\n    kindIds,\n    functionIds\n  );\n```\n\n### Locking Changed Event\n\nAn event is triggered when the locked state of the currently active Workspace or\nits Knowledge Graphs and Functions change.\n\nThe `LockingChanged` object:\n```js\n{\n  workspaces: [LockItem],\n  knowledgeGraphs: [LockItem],\n  functions: [LockItem]\n}\n```\n\nThe `LockItem` object:\n```js\n{\n  id: string\n  lockedBy: string\n}\n```\n\n#### addLockingChangedListener = cb =>\n\nRegisters a callback function with the locking changed event. When the currently\nactive Workspace or its Knowledge Graphs and Functions change the callback\nfunction will be called with the `LockingChanged` object. Returns undefined.\n\n```js\nconst lockingChangedCB = ({ locks }) => {\n  if(locks.workspace) console.log('WORKSPACES CHANGED', locks.workspace);\n  if(locks.knowledgeGraphs) console.log('KNOWLEDGE GRAPHS CHANGED', locks.knowledgeGraphs);\n  if(locks.functions) console.log('FUNCTIONS CHANGED', locks.functions);\n}\n\nAssistantAPIClient.addLockingChangedListener(lockingChangedCB);\n```\n\n#### removeLockingChangedListener = cb =>\n\nRemoves an locking changed listener given the referenced callback. If no\ncallback is specified, all listeners will be removed. Returns undefined.\n\n```js\nAssistantAPIClient.removeLockingChangedListener(lockingChangedCB)\n```\n\n## Troubleshooting Assistant Issues\n### Assistant root file has loaded, but not other content\nObserving in the browser's dev tools that some resources have loaded correctly (usually the root), but other's haven't (usually nested files or chunks), is indicative of a failure of Q Gateway to proxy due to not having a 'relative' path structure.\n\n### You are seeing post-robot `NO ACK` errors in the console.\nThese errors stem from a failed acknowledgement for a call either between the client and the API or vice-versa. Here, this means that the web app 'window' (the assistant) cannot communicate with, or access, the 'window.parent' (Maana K-Portal) object.\n\nCommonly, these will stem from the 'window' (the assistant) not being loaded or in a loadable state, which means the API will not receive an acknowledgement when it fires an event.\n\nImproper CORS configuration is also a common culprit (also verify if using docker or nginx that your proxying and networking is configured correctly to allow communication and to accout for CORS).","readmeFilename":"README.md","gitHead":"60e729aa783e163386c1cba79dd28d4b49ef2d74","_id":"@io-maana/q-assistant-client@3.3.0-beta.9","_nodeVersion":"12.21.0","_npmVersion":"6.14.11","dist":{"integrity":"sha512-9kjt0qojnb/Gg/Sd+rYj4ONQwWFEC7cFWYnEf2YVyfmwE5ibWzykMexEn36gqROHSAxnBfQHoLSExKm3MOiiyQ==","shasum":"b7082f875ed4fe3a55b88a1d568dbbf7102becfe","tarball":"https://registry.npmjs.org/@io-maana/q-assistant-client/-/q-assistant-client-3.3.0-beta.9.tgz","fileCount":81,"unpackedSize":352274,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJgSnhwCRA9TVsSAnZWagAAdFAP/2GbC2tp7BDxdvhZ7mQY\nMCeJMY/E3+3nO0bOjoqrLJMg5uVEEm5p0Z23duC/4+wohMRJJtiRduoArXkL\nU5z7npqMhM1SXVZefcsb/o77EYf0zUcxB7sBpsd73nuGksXWemDbrYfHxY5Z\nuJq4y5VJFmIpSlTGMYZN5s7DpR6S0tEKQqztfUF/TCAlCgVuvYFRCF3tA79z\nvObqvdEcKGYgQPr3zNo3hhOigR4I/2nv3MZJespyEFu/e0JtGSlJAadrMLyM\nNOulPv7+xMbI4QOK3O5FPwd4WitVIkZPTDtnwlWzwn4IAF1woGv74LsX9Hzn\nATq8oWHciiRFUbwwYVijjfi7f1s4HgwsGenMc5R29KC/pF7en+hZXRbt0yRM\nw07Pq3BrSwc4X8jyp8CPxYQA06AWjHOgzZyRuUe8fAy/r0o1k41xElNlWmfa\nDVOUwr0rClxXu4f/iLjpNpUgqVwAQNR5MdQy1/c9yB4q3WKJuqRjOe0755tc\njdTpGDtFYEraaP4aQvZXAFLSZ4Dhgcbqi42+auqJGTvZlguyH6fyWH6Zx2Mo\n28UDY8uJbrDVmxmTUEFadR2+0T7n0BYZHpPxtEGxZC9rDZ7Jp/em0evV2su9\nQdmRKghoVoPUEwXOzNmoNypU355bXUY03dVpJBmBCGPXmeOT04iJiVEx1Egh\nFtYw\r\n=uEme\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIFqfitfQXJ2/vOtSKv7fCYjSnNs10ZRpG/XW1L9nMY12AiEA7vuIDYoYNECqBr+AhjfYS0LfSLZjF9a/b0EdfGXRv68="}]},"_npmUser":{"name":"teamcitymaana","email":"teamcity@maana.io"},"directories":{},"maintainers":[{"name":"witt3rd","email":"witt3rd@witt3rd.com"},{"name":"bzvetey","email":"bzvestey@gmail.com"},{"name":"abatyuk","email":"andrey@maana.io"},{"name":"rpovey","email":"rob@maana.io"},{"name":"teamcitymaana","email":"teamcity@maana.io"},{"name":"dlsmaana","email":"dlewissandy@maana.io"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/q-assistant-client_3.3.0-beta.9_1615493232290_0.5308539187577375"},"_hasShrinkwrap":false},"3.3.0-beta.10":{"name":"@io-maana/q-assistant-client","version":"3.3.0-beta.10","description":"JavaScript package to streamline communication between an assistant and the Maana Q Assistant API.","main":"build/index.js","types":"build/index.d.ts","exports":{"./":"./build/"},"scripts":{"build":"npm run build:ts && npm run build:doc","build:ts":"tsc --build tsconfig.json","build:doc":"typedoc","prepack":"npm run build","test":"echo \"Error: no test specified\" && exit 1","format":"prettier --write \"src/**/*.js\""},"repository":{"type":"git","url":"git+https://github.com/maana-io/q-assistant-client.git"},"keywords":["Maana","Q"],"author":{"name":"Logan Gore @ Maana.io"},"license":"MIT","bugs":{"url":"https://github.com/maana-io/q-assistant-client/issues"},"homepage":"https://github.com/maana-io/q-assistant-client#readme","dependencies":{"core-js":"3.6.4","post-robot":"10.0.29"},"devDependencies":{"@types/node":"^14.14.2","@types/post-robot":"^10.0.0","prettier":"2.0.5","typedoc":"^0.19.2","typedoc-plugin-markdown":"^3.0.11","typescript":"^3.9.5"},"readme":"# q-assistant-client\nA lightweight JavaScript client for Maana-Q Assistant developers that wraps post-message communication between an embedded Maana-Q assistant and the Maana-Q UI.\n\nYou can find the [API Documentation here](docs/README.md).\n\n## Abstract\nThe Q-Assistant-Client is intented to be used in a web application being leveraged as a Maana Q assistant (embedded as an iframe).\nThis assistant client will facilitate communication between the assistant and the parent frame.\nThe client provides a rich, asynchronous experience over what would otherwise be 'fire-and-forget'-style messaging\nvia post-post message communication.\n\n## Requirements and Assumptions\n\n### Post-Robot Library\nThe Maana Knowledge Portal (KPortal) uses the kraken/post-robot library [kraken/post-robot](https://github.com/krakenjs/post-robot) to enrich the communication with the assistant. Post-robot allows for asynchronous, promise-based request/response style behavior between the assistant and the assistant API.\n\nThe API requires that the client use the post-robot library. This assistant-client library is the easiest way to achieve this, and also adds a fair amount of 'sugar' to the process to improve developer productivity. Developers could, however, use post-robot directly in their own client implementation.\n\n### Maana-Gateway Proxy Requirements\nThe Maana-Gateway service requires relative paths (paths relative to the root) in the assistant web application in order to proxy the application and its content. For create-react-apps, for instance, this means setting \"homepage\" to \".\" in the package.json file.\n\n## Singleton Instance\nThe client is exported as a singleton to avoid duplicate registration on event listeners.\nYou can import the instance like this:\n\n```js\nimport AssistantAPIClient from '@io-maana/q-assistant-client';\n```\n\nFunction calls can be made against the client instance like any other javascript object. They are all async.\n\n```js\nconst workspace = await AssistantAPIClient.getWorkspace();\nconsole.log(\"Workspace:\", workspace)\n```\n\n## Dependencies\nPost-Robot\nhttps://github.com/krakenjs/post-robot\n\nPost-robot is used to provide a richer communication layer atop post-message.\n\n## Versioning\nThe Maana Q Assistant Client does not follow semantic versioning. Its versions\ntrack the releases of the Maana Q platform.\n\n## Examples\n@TODO Logan\n\n\n## Changes in v3.2.2\nImprovements in v3.2.2\n- Assistant State Management: WORKING, IDLE\n- Background Messaging/Eventing\n- Render Modes: BACKGROUND, DISPLAY\n- Expansion of Workspace object capabilities\n- Error Reporting\n- Repair Event\n- Plural versions of calls such as updateKind(s) to improve performance and developer experience.\n- InventoryChanged diffing is fully granular in v3.2.2--limitations\nin v3.2.1 only fired the Function diff for changes in Function name.\n\n### Deprecation\nThe following surface area IS removed from the\nclient in v3.2.2, and IS deprecated in the API:\n- AssistantAPIClient.enableSelectionChangedNotification\n- AssistantAPIClient.disableSelectionChangedNotification\n- AssistantAPIClient.enableInventoryChangedNotification\n- AssistantAPIClient.disableInventoryChangedNotification\n\nThe following surface area WILL BE removed from\nthe client in v3.2.4, and WILL BE deprecated in the API:\n- AssistantAPIClient.updateFunction (expected move to Workspace object)\n- AssistantAPIClient.updateKind (expected move to Workspace object)\n- AssistantAPIClient.deleteKind (expected move to Workspace object)\n- AssistantAPIClient.deleteFunction (expected move to Workspace object)\n\n## API Documentation\nMore information in the [API File](./API.md)\n\n### Assistant Render Mode\nAn assistant's render mode refers to whether it is being displayed in a visible manner to the user. As of v3.2.2, assistants are not closed when they are out of view.\nAll assistants will be loaded and kept in `BACKGROUND` render mode until they are\nplaced in the assistant panel, at which point the `DISPLAY` render mode event will be fired.\n\nNote: Assistants will receive all notifications/events while in BACKGROUND mode.\n\nDesign Consideration: It will be up to the developer to determine how state and resource use will be managed while an assistant is operating between BACKGROUND and DISPLAY modes.\n\n#### addRenderModeChangedListener = (cb) =>\nA listener to receive push events as to the assitant's render mode being changed.\n\n```js\nfunction handleRenderModeChanged(renderMode){\n  if (renderMode === 'DISPLAY'){\n    // Assistant is visible\n  } else {\n    // Assistant is not visible and running in background.\n  }\n}\n\nAssistantAPIClient.addRenderModeChangedListener(handleRenderModeChanged)\n\n```\n\n#### removeRenderModeChangedListener = (cb) =>\nRemoves the renderModeChanged listener by reference, or if no callback function reference is provided, it removes all listeners.\n\n#### getRenderMode = () =>\nReturns the current assistant render mode.\n\n```js\nconst renderMode = await AssistantAPIClient.getRenderMode()\n\nif (renderMode === 'DISPLAY'){\n  // Assistant is visible\n} else {\n  // Assistant is not visible and running in background.\n}\n\n```\n\n### Repair\nAssistants may get into situations where they are either out of sync with the Maana Q UI, or in a failure state. Assistants should be able to recover from these states.\n\nThe repair event functionality added in v3.2.2 is designed to notify the assistant that it must repair itself. This could mean a resync with its resources on the workspace or externally or, for some assistants, nothing at all.\n\nWhen is repair triggered?\nEither manually by a user clicking 'repair workspace' under the\nassistant inventory panel, or upon a workspace clone event. An assistant will be expected to handle either scenario.\n\nPerformance Consideration:\nFor some assistants, repair might involve 'introspecting'\nand processing the current workspace or Q system resources. This could be very resource intensive. Make sure you review this API guide to have an idea of what tools are\navailable to get the best results. It's always a good idea to check performance of repair on a large workspace and ensure necessary optimizations have been made.\n\nDesign Consideration:\nMake your workflows modular enough to be reused between repair and normal usage if possible.\n\n#### addRepairListener (cb) =>\n```js\n\nAssistantAPIClient.addRepairListener(()=>{\n  // Self-heal\n})\n\n```\n\nRecommended Usage: A repair process should be wrapped in the try/catch/finally flow shown in the `setAssistantState` API call to provide the user assistant-state and error updates as well as pause `inventoryChanged` notifications during repair (if the assistant has subscribed).\n\n#### removeRepairListener = (cb) =>\nRemoves the repair listener by reference, or if no callback function reference is provided, it removes all listeners.\n\n### User-facing Error Handling\n\n#### reportError (error) =>\nReports an error to the UI to be displayed in the assistant's error log in the\ninventory panel. This call is not disruptive and designed to operated independently of other assistant operations, such as state management. See `setAssistantState` in the next section.\n\nRecommended usage: use this functionality where it would futher the user experience\nto show the user an error and it's cause. Do not use this where things will be retried,\ncleaned up automatically, or are not relevant to the user.\n\n```js\ntry{\n  // Do work\n} catch(e) {\n  AssistantAPIClient.reportError(e)\n}\n```\n\n### State management\n\n#### clearState = () =>\nThis will remove all callbacks from all listeners.\n\n```js\nawait AssistantAPIClient.clearState()\n```\n\n#### setAssistantState = (state) =>\nThis sets the current state of the assistant using the\n`AssistantState` enum. Setting a state of `WORKING` will\ncreate the 'working' status spinner in the Assistant\nInventory Panel in the Maana Q UI. Conversely, setting an `IDLE` state will\nremove the spinner. This adds to user experience by informing users of the\nstatus of operations.\n\n```js\nimport {\n  default as AssistantAPIClient,\n  AssistantState\n} from '@io-maana/q-assistant-client'\n\n...\n\nAssistantAPIClient.setAssistantState(AssistantState.WORKING)\n\n...\n\nAssistantAPIClient.setAssistantState(AssistantState.IDLE)\n\n```\nUI User Prompt: If the assistant is in a `WORKING` state, the Maana Q UI will\nwarn the user before leaving the workspace.\n\nNOTE: while an assistant is in a working state, it will\nnot receive `inventoryChanged` events--an aggregated inventory diff\nwill be sent once the assistant is set back to `IDLE`.\n\nRecommended usage: Control states at a high level using try/catch/finally\nflow incorporating the `reportError` API call.\n\n```js\ntry{\n  AssistantAPIClient.setAssistantState(AssistantState.WORKING)\n  // Do work, await high-level tasks, etc.\n} catch(e) {\n  AssistantAPIClient.reportError(e)\n} finally{\n  AssistantAPIClient.setAssistantState(AssistantState.IDLE)\n}\n```\n\n#### AssistantState (enum)\nContains the valid assistant states: `IDLE` or `WORKING`.\n\nMust be imported in addition to the AssistantAPIClient:\n\n```js\nimport {\n  default as AssistantAPIClient,\n  AssistantState\n} from '@io-maana/q-assistant-client'\n```\n\n\n### User Info\nThe `UserInfo` object:\n```js\n{\n email: string,\n name: string\n}\n```\n\n#### getUserInfo = () =>\nReturns a Userinfo object pertaining to the logged in user.\n\n```js\nconst userInfo = await AssistantAPIClient.getUserInfo()\n```\n### Selection\nThe `Selection` object:\n```js\n{\n  kindId: string\n  kindName: string\n  id: string\n}\n```\n\n#### getCurrentSelection = () =>\nReturns an Array of `Selection` objects:\n\n```js\nconst {selection} = await AssistantAPIClient.getCurrentSelection();\n```\n\n#### addSelectionChangedListener = async cb =>\nAdds a callback function to be executed upon a valid workspace selection change.\n\nCallback value is an array of Selection objects:\n\n```js\n// Create the selection callback.\nconst selectionCB = ({selection})=>{\n  console.log('Workspace selection has changed.')\n  selection.forEach(i=>{\n    console.log('Kind: ',i.kindName)\n    console.log('Instance Id:',i.id)\n    console.log('Kind Id:',i.kindId)\n  })\n}\n\n// Add the listener.\nAssistantAPIClient.addSelectionChangedListener(selectionCB);\n```\n\nThis function only exists on the Q-Assistant-Client--only enableSelectionChangedNotification is called on the API.\n\n#### removeSelectionChangedListener = async cb =>\nThis will have to be called on a 1:1 basis with addSelectionChangedListener calls if supplying a callback.\n\n```js\nAssistantAPIClient.removeSelectionChangedListener(selectionCB)\n```\n\n**If NOT supplying a callback to this call, all selection changed listeners will be removed.\n\n```js\nAssistantAPIClient.removeSelectionChangedListener()\n```\n\nThis function only exists on the Q-Assistant-Client--only disableSelectionChangedNotification is called on the API.\n\n\n### Services\nThe `Service` object:\n```js\n{\n   id: string,\n   name: string\n   endpointUrl: string,\n   getKinds: () => // Returns [] of Kinds objects\n   getFunctions: () => // Returns [] of Function objects\n}\n```\n\n#### getServiceById = id =>\nThis will return a service that exists within the scope of the workspace.\n** Assistant services will return null. Services outside the scope of the workspace will cause an error to be returned as 'Unable to load a Service from outside of the workspace.'\n\n```js\nconst svc = await AssistantAPIClient.getServiceById(id)\n```\n\n#### createService = id =>\nCreates a service in Q.\n\nNote: This will create the service, but does NOT import it into the workspace.\nYou will need to use `importService` on the Workspace object to import it.\nReturns a promise that resolves\n\n```js\n    const service = {\n      id: ...,\n      name: ...,\n      endpointUrl: ...,\n      serviceType: ...\n    }\n\n    await AssistantAPIClient.createService(service)\n```\n\n#### deleteService = id =>\nDeletes a service from Q.\n\n```js\n    await AssistantAPIClient.deleteService(id)\n```\n\n#### refreshServiceSchema = id =>\nRefreshes a service by fetching its schema. This will also\nreload the service inventory in the currently visible workspace.\n\n```js\nawait AssistantAPIClient.refreshServiceSchema(\"id\")\n```\n\n#### reloadService = id =>\nReloads a service in the inventory in the currently visible workspace.\n\n```js\nawait AssistantAPIClient.reloadService(\"id\")\n```\n\n### Workspace\n\n#### getWorkspace = () =>\nReturns a Workspace object representing the workspace.\n\n```js\nconst ws = await AssistantAPIClient.getWorkspace(id)\n```\n\nNote: The `id` parameter is optional. If it is not supplied, the query\nwill return the current/visible workspace.\n\nThe `Workspace` object:\n\n```js\n\n{\n    id: string,\n    name: string,\n    endpointUrl: string,\n    workspaceServiceId: string,\n    modelServiceId: string,\n    logicServiceId: string,\n\n    //\n    // Locking information\n    //\n    async lockedBy() {\n      // Returns the e-mail address of the user who locked the Workspace, or\n      // null if the Workspace is not currently locked.\n    }\n    async canEdit() {\n      // Returns `true` when the Workspace is not locked, or the current user\n      // owns the lock.\n      // Returns 'false' when the Workspace is locked by a different user.\n    }\n    async setLocked(isLocked) {\n      // Takes a boolean or undefined for `isLocked`.\n      //  `true` locks the Workspace as the current User.\n      //  `false` unlocks the Workspace\n      //  `undefined` causes it to toggle the current locked state.\n      // Returns a Promise that will resolve or reject when the task is done.\n    }\n\n    //\n    // Knowledge Graphs\n    //\n    getActiveGraph: async () => {\n      // Returns the active Graph object.\n      // Returns null if active graph is not of type 'Knowledge Graph', or if an\n      // active graph is deleted, thereby setting active graph to null.\n    },\n    getKnowledgeGraphs: async () => {\n      // Returns [Graph]\n    },\n    // TODO: define input\n    createKnowledgeGraph: input =>\n    // TODO: define input\n    createKnowledgeGraphs: input =>\n\n    //\n    // Services\n    //\n    getImportedServices: async () => {\n      // Returns an array of Service objects that have\n      // been imported into the workspace.\n      // No assistant services will be returned.\n    },\n    getImportedAssistants: async () => {\n      // Returns a list of imported assistants.\n    },\n    importService: serviceId => {\n      // Imports a service by it's ID.\n    },\n    importServices: serviceIds => {\n      // Imports services by their IDs.\n    },\n    removeServices: serviceIds => {\n      // Removes a list of services from the workspace.\n    },\n    removeService: serviceId => {\n      // Removes a service from the workspace.\n    },\n\n    //\n    // Functions\n    //\n    getFunctions: async () => {\n      // Returns an array of functions in the workspace (includes boilerplate).\n    },\n    createFunction: funcData => {\n      // Creates a function and adds it to the graph.\n    }\n    createFunctions: funcData =>{\n      // Creates several functions and adds them to the graph.\n    }\n    updateFunction: funcData => {\n      // Updates a function.\n    },\n    updateFunctions: funcData =>{\n      // Updates functions based on input array.\n    },\n    deleteFunction: funcId => {\n      // Deletes a function by its ID.\n    },\n    getFunctionGraph: funcId => {\n      // Returns a function graph by its ID.\n    }\n\n    //\n    // Kinds\n    //\n    getKinds: async () => {\n      // Returns an array of functions in the workspace (includes boilerplate).\n    },\n    createKind: kindData => {\n      // Currently same input as AssistantAPIClient call.\n    },\n    createKinds: kindData => {\n      // Currently same input as AssistantAPIClient call.\n    },\n    updateKind: kindData => {\n      // Currently same input as AssistantAPIClient call.\n    },\n    updateKinds: kindData => {\n      // Currently same input as AssistantAPIClient call.\n    },\n    deleteKind: kindId => {\n      // Currently same input as AssistantAPIClient call.\n    }\n    // Event Triggers\n    triggerRepairEvent: () => {\n      // Triggers the repair event on a workspace.\n    }\n  };\n}\n```\n\n\n### Graphs\nThe `Graph` object:\n```js\n{\n  id: string,\n  name: string,\n  offsetX: Number,\n  offsetY: Number,\n  zoom: Number,\n  getNodes: async () => {\n      // Returns [Node]\n  },\n\n  addNode: async (type, instance, changeSelection) => {\n      // Returns Node\n  },\n  removeNode: async id => {\n      // Should return nothing or error.\n      // Currently returning [] in all cases.\n  },\n  updateNodeLayout: async (nodeId, { x, y, collapsed }) => {\n  },\n  updateGraphLayout: async ({ offsetX, offsetY, zoom }) => {\n  }\n\n  //\n  // Locking information\n  //\n  async lockedBy() {\n    // Returns the e-mail address of the user who locked the Graph, or null if\n    // the Graph is not currently locked.\n  }\n  async canEdit() {\n    // Returns `true` when the Graph is not locked, or the current user owns the\n    // lock.\n    // Returns 'false' when the Graph is locked by a different user.\n  }\n  async setLocked(isLocked) {\n    // Takes a boolean or undefined for `isLocked`.\n    //  `true` locks the Graph as the current User.\n    //  `false` unlocks the Graph\n    //  `undefined` causes it to toggle the current locked state.\n    // Returns a Promise that will resolve or reject when the task is done.\n  }\n}\n```\n\n#### Getting a graph object:\nGraph objects are obtained through an instance of a Workspace\n\n```js\nconst ag = await ws.getActiveGraph()\n```\n\nor\n\n```js\nconst kgs = await ws.getKnowledgeGraphs()\n```\n\n#### Manipulating Graphs\n\n**Only the active graph may be manipulated.\n\nAll graph manipulations should be ‘visually’ verifiable on the graph itself, i.e., adds/removes/positioning, should all be reflected on the graph itself.\n\nThe `Node` object:\n```js\n{\nid: string\nx: number\ny: number\ncollapsed: boolean\nknowledgeGraphNode {\n  id: string\n  innerKind: Kind\n  innerFunction: Function\n}\n}\n```\n\n#### addNode(type, instance, changeSelection) =>\n\nTakes type (“Function” or “Kind”), instance (the Function or Kind object), and optionally a boolean to indicate whether the selection should be changed to this new node.\n\nReturns the newly created Node object.\n\n```js\nconst node = await ag.addNode('Kind',kind)\n```\n\n#### removeNode(id) =>\n\nTakes the id of Node to be deleted. Returns either undefined or an error.\n\n```js\nawait ag.removeNode(node.id)\n```\n\n#### getNodes() =>\nReturns an array of Node objects from the graph.\n\n```js\nconst nodes = await ag.getNodes()\n```\n\n#### updateNodeLayout: async (nodeId, { x, y, collapsed})=>\nUpdates a Node layout given a node ID and node coordinates (`x` and/or `y`) or a `collapsed` value. x/y values must be a number, and collapsed must be a boolean. Whatever is not specified will remain current.\n\n```js\nag.updateNodeLayout(id,{x:100,y:100,collapsed:true})\n```\n\n#### updateGraphLayout: async ({ offsetX, offsetY, zoom})=>\nUpdates a Graph layout given numerical values for x/y offsets and the zoom.\n\n```js\nag.updateGraphLayout({offsetX:50, offsetY:50, zoom: 70})\n```\n\n### Functions\n\nThe `Function` object:\n```js\n{\n    id: string\n    name: string\n    service {\n      id: string\n      name: string\n    }\n    arguments {\n      id: string\n      name: string\n      type: string\n      modifiers: Array[string]\n      typeKindId:: string\n      kind {\n        id: string\n        name: string\n      }\n    }\n    implementation {\n      id: string\n      entrypoint {\n        id: string\n      }\n      operations {\n        id: string\n        type: string\n        function {\n          id: string\n          name: string\n        }\n        argumentValues {\n          id: string\n          argument {\n            id: string\n          }\n          operation {\n            id: string\n          }\n          argumentRef: string\n        }\n      }\n    }\n    isGenerated: boolean\n    functionType: string\n    graphqlOperationType: string\n    outputType: string\n    outputKindId: string\n    outputModifiers: Array[string]\n    kind {\n      id: string\n      name: string\n    }\n\n    //\n    // Locking information\n    //\n    async lockedBy() {\n      // Returns the e-mail address of the user who locked the Function, or null\n      // if the Function is not currently locked.\n    }\n    async canEdit() {\n      // Returns `true` when the Function is not locked, or the current user\n      // owns the lock.\n      // Returns 'false' when the Function is locked by a different user.\n    }\n    async setLocked(isLocked) {\n      // Takes a boolean or undefined for `isLocked`.\n      //  `true` locks the Function as the current User.\n      //  `false` unlocks the Function\n      //  `undefined` causes it to toggle the current locked state.\n      // Returns a Promise that will resolve or reject when the task is done.\n    }\n}\n```\n\n`FunctionExecutionResult` object:\n```js\n{\n  id: string,\n  result: JSON\n}\n```\n\n#### executeFunction = ( {id, variables, resolve} ) =>\nExecutes a function based on its id, with optional inputs for variables and a resolve string (this specifies the fields to be returned, which must be valid based on the result).\n\nReturns : JSON matching shape of result , unless no sub-selection of fields is required in the execution.\n\nThis following piece of code will execute a Function given a function ID, and pass in variables for ‘example’, requesting back id and name fields.\n\n```js\nconst res = await AssistantAPIClient.executeFunction({functionId: func.id, variables: {\"variableName\": \"variableValue\"}, resolve: \"{ id name }\");\n```\n\n#### createFunction = input =>\nCreates a function based on the input provided.\n\nReturns: the created Function object.\n\n**Using create function will only place the function in the workspace’s inventory--it will not place the function as a node on the Graph. In order to do this, you must pass the created function into the addNode function on the active Graph, making sure to specify ‘Function' as the type.\n\n```js\nconst createFunctionInput = {\n  name:\"yourName\",\n  arguments:[],\n  outputType: \"STRING\",\n  graphqlOperationType:\"QUERY\",\n  functionType: \"CKG\"\n}\n\nconst createdFunction = await AssistantAPIClient.createFunction(createFunctionInput)\n```\n\n#### updateFunction = input =>\nInput is the same for creating a function. It’s important to note that the arguments property will be replaced in it’s entirety with whatever is provided (if a value is provided.\n\nReturns the updated `Function` object.\n\n```js\nconst updatedFunction = await AssistantAPIClient.updateFunction(input);\n```\n\n#### deleteFunction = input =>\nInput is the id of the Function to be deleted. Returns the deleted function as a promise.\n\n```js\nconst deletedFunction = await AssistantAPIClient.deleteFunction('id...');\n```\n\n#### getFunctionById = id =>\nReturns a Function as a promise based on the ID provided.\n\n```js\nconst func = await AssistantAPIClient.getFunctionById('id...');\n```\n\n#### addFunctionExecutionListener = async (id, cb) =>\nAssociates a callback function with the execution of a particular Function. When the Function matching the id parameter is executed, its FunctionExecutionResult object passed to the callback. Returns undefined.\n\nExample function execution callback and listener registration:\n\n```js\nfunction exampleFunctionCB (result){\n  console.log(`Function executed with result:`, result)\n}\n\nAssistantAPIClient.addFunctionExecutionListener('id...', exampleFunctionCB)\n```\n\n#### removeFunctionExecutionListener = async (id, cb) =>\nRemoves a Function execution listener based on the function ID and a reference to the callback function. If no callback is supplied, all listeners associated with the Function ID will be removed. Returns undefined.\n\n```js\nAssistantAPIClient.removeFunctionExecutionListener('id..', exampleFunctionCB)\n```\n\n### Kinds\nThe `Kind` object:\n```js\n{\n    id: string\n    name: string\n    service: {\n      id\n      name\n    }\n    isGenerated: boolean\n    schema {\n      id: string\n      name: string\n      type: string\n      typeKindId: string\n      modifiers: Array[string]\n      kind {\n        id: string\n        name: string\n      }\n    }\n}\n```\n\n#### createKind = input =>\nCreates a Kind based on an input object. Returns a promise that resolves to the created Kind object.\n\n```js\nconst kindInput = {\n name: \"someKind\",\n schema:[\n  { name: \"someField1\", type: STRING },\n  { name: \"someField2\", type: STRING }\n ]\n}\n\nconst newKind = await AssistantAPIClient.createKind(kindInput)\n```\n\n#### createKinds = input =>\nA plural version of `createKind` accepting an array of input objects.\nReturns a promise that resolves to an array of created Kind objects.\n\n```js\nconst kindsInput = [{\n name: \"someKind\",\n schema:[\n  { name: \"someField1\", type: STRING },\n  { name: \"someField2\", type: STRING }\n ]\n}, ...]\n\nconst newKinds = await AssistantAPIClient.createKinds(kindsInput)\n```\n\n\n#### updateKind = input =>\nUpdates a Kind based on an input object.\n\nUpdate Semantics: Only properties specified will be updated. If updating the schema, the entire schema must be specified as it will be replaced in its entirety.\n\nReturns a promise that resolves to the updated `Kind` object.\n\n```js\nconst updated = await AssistantAPIClient.updateKind(input)\n```\n\n#### deleteKind = input =>\nDeletes a Kind given a kind ID.\n\n```js\nconst deleted = await AssistantAPIClient.deleteKind(input)\n```\n\n#### getKindById = id =>\nReturns a promise that resolves to a Kind object given the specified kind ID.\n\nIn v3.2.2, any requested non-system kinds will be returned.\nIn v3.2.1, only kinds in the workspace or those of imported services will be returned.\n\n```js\nconst kind = await AssistantAPIClient.getKindById(id)\n```\n\n#### getKindsById = ids =>\nReturns a promise that resolves to an array of Kind objects given an array of kind IDs. Only kinds in the workspace or those of imported services will be returned.\n\n```js\nconst ids = [\"...\",\"...\",...]\nconst kind = await AssistantAPIClient.getKindsById(ids)\n```\n\n#### getAllReferencedKinds = input =>\nRecursively collects all kinds that are referenced in a kind's schema, starting\nwith a kind ID. For example if the ID of kind A is supplied as an input, and Kind `A` contains a field of type Kind `B`, and `B` contains a field of type Kind `C`,\nan array containing the kinds objects for `A`, `B`, `C` will be returned (as a promise).\n\n```js\nconst initialId = [\"...\"]\nconst kinds = await AssistantAPIClient.getAllReferencedKinds({\n          ids: initialId\n        })\n```\n\n\n### Inventory\n\nThe `InventoryChanged` object:\n```js\n{\n  kinds: {\n    adds: [DiffItem]\n    deletes: [DiffItem]\n    updates: [DiffItem]\n  }\n  functions:{\n    adds: [DiffItem]\n    deletes: [DiffItem]\n    updates: [DiffItem]\n  }\n  services: {\n    adds: [DiffItem]\n    deletes: [DiffItem]\n    updates: [DiffItem]\n  }\n}\n```\n\nThe `DiffItem` object:\n```js\n{\n  id: string,\n  name: string\n}\n```\n\n#### addInventoryChangedListener = async cb =>\nRegisters a callback function with the inventory changed event. When workspace inventory changes the callback function will be called with the InventoryChangedobject. Returns undefined.\n\n**Use-case note: an ‘update’ diff for inventory services is unlikely in general usage.\n\n```js\nconst inventoryCB = ({diff}) => {\n  if(diff.kinds) console.log('KINDS CHANGED',diff.kinds)\n  if(diff.functions) console.log('FUNCTIONS CHANGED', diff.functions)\n  if(diff.services) console.log('SERVICES CHANGED',diff.services)\n}\n\nAssistantAPIClient.addInventoryChangedListener(inventoryCB)\n```\n\nThis function exists on the Q-Assisant-Client only--only enableSelectionChangedNotification is used on the API side.\n\n#### removeInventoryChangedListener = async cb =>\nRemoves an inventory changed listener given the referenced callback. If no callback is specified, all listeners will be removed. Returns undefined.\n\n```js\nAssistantAPIClient.removeInventoryChangedListener(inventoryCB)\n```\n\nThis function exists on the Q-Assisant-Client only--only disableSelectionChangedNotification is used on the API side.\n\n#### moveKindsAndFunctions = (originId, targetId, kindIds, functionIds) =>\nMoves a collection of Kinds and Functions from the origin Workspace to the target Workspace.\n\n```js\n  await AssistantAPIClient.moveKindsAndFunctions(\n    originWorkspaceId,\n    targetId,\n    kindIds,\n    functionIds\n  );\n```\n\n### Locking Changed Event\n\nAn event is triggered when the locked state of the currently active Workspace or\nits Knowledge Graphs and Functions change.\n\nThe `LockingChanged` object:\n```js\n{\n  workspaces: [LockItem],\n  knowledgeGraphs: [LockItem],\n  functions: [LockItem]\n}\n```\n\nThe `LockItem` object:\n```js\n{\n  id: string\n  lockedBy: string\n}\n```\n\n#### addLockingChangedListener = cb =>\n\nRegisters a callback function with the locking changed event. When the currently\nactive Workspace or its Knowledge Graphs and Functions change the callback\nfunction will be called with the `LockingChanged` object. Returns undefined.\n\n```js\nconst lockingChangedCB = ({ locks }) => {\n  if(locks.workspace) console.log('WORKSPACES CHANGED', locks.workspace);\n  if(locks.knowledgeGraphs) console.log('KNOWLEDGE GRAPHS CHANGED', locks.knowledgeGraphs);\n  if(locks.functions) console.log('FUNCTIONS CHANGED', locks.functions);\n}\n\nAssistantAPIClient.addLockingChangedListener(lockingChangedCB);\n```\n\n#### removeLockingChangedListener = cb =>\n\nRemoves an locking changed listener given the referenced callback. If no\ncallback is specified, all listeners will be removed. Returns undefined.\n\n```js\nAssistantAPIClient.removeLockingChangedListener(lockingChangedCB)\n```\n\n## Troubleshooting Assistant Issues\n### Assistant root file has loaded, but not other content\nObserving in the browser's dev tools that some resources have loaded correctly (usually the root), but other's haven't (usually nested files or chunks), is indicative of a failure of Q Gateway to proxy due to not having a 'relative' path structure.\n\n### You are seeing post-robot `NO ACK` errors in the console.\nThese errors stem from a failed acknowledgement for a call either between the client and the API or vice-versa. Here, this means that the web app 'window' (the assistant) cannot communicate with, or access, the 'window.parent' (Maana K-Portal) object.\n\nCommonly, these will stem from the 'window' (the assistant) not being loaded or in a loadable state, which means the API will not receive an acknowledgement when it fires an event.\n\nImproper CORS configuration is also a common culprit (also verify if using docker or nginx that your proxying and networking is configured correctly to allow communication and to accout for CORS).","readmeFilename":"README.md","gitHead":"b6e482c59e66d81bff0485c80678cbbace88b35a","_id":"@io-maana/q-assistant-client@3.3.0-beta.10","_nodeVersion":"12.21.0","_npmVersion":"6.14.11","dist":{"integrity":"sha512-wrSX4kNIvgXNde5/nLunwWEgEL5EIH7Ch34We8tsdhiJsc6gqYHCix63zqwZdANw7Ulzh7cDTHzMBAX+1sBRsQ==","shasum":"44c0b4441ddb888f5c6c7c97b4441f3d81d7427c","tarball":"https://registry.npmjs.org/@io-maana/q-assistant-client/-/q-assistant-client-3.3.0-beta.10.tgz","fileCount":83,"unpackedSize":356108,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJgWnz2CRA9TVsSAnZWagAASPUP/RDjhN8JwHNKJn3X5ISJ\nAPa8R4cTCJqZcocouXWISkYG4ic1t3HYzVx/tkJmbONRQHdF/cDWvOsoR2/s\n2+p1WM/6whOTH4GckU6J3UNQyRenvzvXe0hVcmkTaITNX7vhenhuanFHtBMZ\n7xXiZgybK+2PoO5NTN3Lrd5EYs3Q4eBOr0YvAU2oB0SJELg9x4B+LRQ4S2MP\n6xCNxPtYcqgBC6QMeyhCtVHMdaATZfX+SV8M5FD2xhWD9zrUCR2oOBZaeIGA\nHBGErD8lTANvUppD2rrb8OlojROPAG5uQp1wPEsOSR5TjH3nkWm/vk2S+X45\nIJJYyYE635tQEb+kpYHv9EMT/bzvuEsh9zm2ToTnLmGYdOsOciQxRoVjlk0M\n7VlGHIAqtEX8X+g4pGofuUC0o025ElTAUw/zZZUz4HLaBG65acRGG4bd3EH4\nLY5r02vDaThE+C9IbJ5VP9MRbh+sdUFM0GIrpAXcpA5U9I66j2+LH3n63ZCv\nZzhBROT4JQzeb3XKNFEPKol0IeF5KXcNK9l5ggq0NbS+y5u1nDUIvo/CmzZW\nI7QbHelaYh7EwwikIfWkUoZaDKrm5CMbaAfJB1TAeVeMhl0emLxkspgFTYGC\nU5upafg+I/+Bed6NCd1wHtBzeacGtbFLVkQ52JfFxYA602NDDpoMaaCB2Ri9\nTfAf\r\n=2Z3e\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIQCRqxLHnBF57yeGlxJFMBWbNzkJ+19NBCbZcD0HRt86xAIgKl5ps05gvoJXVESb5jnJCP6dRIwzoy6rSICegY6N7MU="}]},"_npmUser":{"name":"teamcitymaana","email":"teamcity@maana.io"},"directories":{},"maintainers":[{"name":"witt3rd","email":"witt3rd@witt3rd.com"},{"name":"bzvetey","email":"bzvestey@gmail.com"},{"name":"abatyuk","email":"andrey@maana.io"},{"name":"rpovey","email":"rob@maana.io"},{"name":"teamcitymaana","email":"teamcity@maana.io"},{"name":"dlsmaana","email":"dlewissandy@maana.io"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/q-assistant-client_3.3.0-beta.10_1616542965706_0.7451008038922697"},"_hasShrinkwrap":false},"3.3.0-beta.11":{"name":"@io-maana/q-assistant-client","version":"3.3.0-beta.11","description":"JavaScript package to streamline communication between an assistant and the Maana Q Assistant API.","main":"build/index.js","types":"build/index.d.ts","exports":{"./":"./build/"},"scripts":{"build":"npm run build:ts && npm run build:doc","build:ts":"tsc --build tsconfig.json","build:doc":"typedoc","prepack":"npm run build","test":"echo \"Error: no test specified\" && exit 1","format":"prettier --write \"src/**/*.js\""},"repository":{"type":"git","url":"git+https://github.com/maana-io/q-assistant-client.git"},"keywords":["Maana","Q"],"author":{"name":"Logan Gore @ Maana.io"},"license":"MIT","bugs":{"url":"https://github.com/maana-io/q-assistant-client/issues"},"homepage":"https://github.com/maana-io/q-assistant-client#readme","dependencies":{"core-js":"3.6.4","post-robot":"10.0.29"},"devDependencies":{"@types/node":"^14.14.2","@types/post-robot":"^10.0.0","prettier":"2.0.5","typedoc":"^0.19.2","typedoc-plugin-markdown":"^3.0.11","typescript":"^3.9.5"},"readme":"# q-assistant-client\nA lightweight JavaScript client for Maana-Q Assistant developers that wraps post-message communication between an embedded Maana-Q assistant and the Maana-Q UI.\n\nYou can find the [API Documentation here](docs/README.md).\n\n## Abstract\nThe Q-Assistant-Client is intented to be used in a web application being leveraged as a Maana Q assistant (embedded as an iframe).\nThis assistant client will facilitate communication between the assistant and the parent frame.\nThe client provides a rich, asynchronous experience over what would otherwise be 'fire-and-forget'-style messaging\nvia post-post message communication.\n\n## Requirements and Assumptions\n\n### Post-Robot Library\nThe Maana Knowledge Portal (KPortal) uses the kraken/post-robot library [kraken/post-robot](https://github.com/krakenjs/post-robot) to enrich the communication with the assistant. Post-robot allows for asynchronous, promise-based request/response style behavior between the assistant and the assistant API.\n\nThe API requires that the client use the post-robot library. This assistant-client library is the easiest way to achieve this, and also adds a fair amount of 'sugar' to the process to improve developer productivity. Developers could, however, use post-robot directly in their own client implementation.\n\n### Maana-Gateway Proxy Requirements\nThe Maana-Gateway service requires relative paths (paths relative to the root) in the assistant web application in order to proxy the application and its content. For create-react-apps, for instance, this means setting \"homepage\" to \".\" in the package.json file.\n\n## Singleton Instance\nThe client is exported as a singleton to avoid duplicate registration on event listeners.\nYou can import the instance like this:\n\n```js\nimport AssistantAPIClient from '@io-maana/q-assistant-client';\n```\n\nFunction calls can be made against the client instance like any other javascript object. They are all async.\n\n```js\nconst workspace = await AssistantAPIClient.getWorkspace();\nconsole.log(\"Workspace:\", workspace)\n```\n\n## Dependencies\nPost-Robot\nhttps://github.com/krakenjs/post-robot\n\nPost-robot is used to provide a richer communication layer atop post-message.\n\n## Versioning\nThe Maana Q Assistant Client does not follow semantic versioning. Its versions\ntrack the releases of the Maana Q platform.\n\n## Examples\n@TODO Logan\n\n\n## Changes in v3.2.2\nImprovements in v3.2.2\n- Assistant State Management: WORKING, IDLE\n- Background Messaging/Eventing\n- Render Modes: BACKGROUND, DISPLAY\n- Expansion of Workspace object capabilities\n- Error Reporting\n- Repair Event\n- Plural versions of calls such as updateKind(s) to improve performance and developer experience.\n- InventoryChanged diffing is fully granular in v3.2.2--limitations\nin v3.2.1 only fired the Function diff for changes in Function name.\n\n### Deprecation\nThe following surface area IS removed from the\nclient in v3.2.2, and IS deprecated in the API:\n- AssistantAPIClient.enableSelectionChangedNotification\n- AssistantAPIClient.disableSelectionChangedNotification\n- AssistantAPIClient.enableInventoryChangedNotification\n- AssistantAPIClient.disableInventoryChangedNotification\n\nThe following surface area WILL BE removed from\nthe client in v3.2.4, and WILL BE deprecated in the API:\n- AssistantAPIClient.updateFunction (expected move to Workspace object)\n- AssistantAPIClient.updateKind (expected move to Workspace object)\n- AssistantAPIClient.deleteKind (expected move to Workspace object)\n- AssistantAPIClient.deleteFunction (expected move to Workspace object)\n\n## API Documentation\nMore information in the [API File](./API.md)\n\n### Assistant Render Mode\nAn assistant's render mode refers to whether it is being displayed in a visible manner to the user. As of v3.2.2, assistants are not closed when they are out of view.\nAll assistants will be loaded and kept in `BACKGROUND` render mode until they are\nplaced in the assistant panel, at which point the `DISPLAY` render mode event will be fired.\n\nNote: Assistants will receive all notifications/events while in BACKGROUND mode.\n\nDesign Consideration: It will be up to the developer to determine how state and resource use will be managed while an assistant is operating between BACKGROUND and DISPLAY modes.\n\n#### addRenderModeChangedListener = (cb) =>\nA listener to receive push events as to the assitant's render mode being changed.\n\n```js\nfunction handleRenderModeChanged(renderMode){\n  if (renderMode === 'DISPLAY'){\n    // Assistant is visible\n  } else {\n    // Assistant is not visible and running in background.\n  }\n}\n\nAssistantAPIClient.addRenderModeChangedListener(handleRenderModeChanged)\n\n```\n\n#### removeRenderModeChangedListener = (cb) =>\nRemoves the renderModeChanged listener by reference, or if no callback function reference is provided, it removes all listeners.\n\n#### getRenderMode = () =>\nReturns the current assistant render mode.\n\n```js\nconst renderMode = await AssistantAPIClient.getRenderMode()\n\nif (renderMode === 'DISPLAY'){\n  // Assistant is visible\n} else {\n  // Assistant is not visible and running in background.\n}\n\n```\n\n### Repair\nAssistants may get into situations where they are either out of sync with the Maana Q UI, or in a failure state. Assistants should be able to recover from these states.\n\nThe repair event functionality added in v3.2.2 is designed to notify the assistant that it must repair itself. This could mean a resync with its resources on the workspace or externally or, for some assistants, nothing at all.\n\nWhen is repair triggered?\nEither manually by a user clicking 'repair workspace' under the\nassistant inventory panel, or upon a workspace clone event. An assistant will be expected to handle either scenario.\n\nPerformance Consideration:\nFor some assistants, repair might involve 'introspecting'\nand processing the current workspace or Q system resources. This could be very resource intensive. Make sure you review this API guide to have an idea of what tools are\navailable to get the best results. It's always a good idea to check performance of repair on a large workspace and ensure necessary optimizations have been made.\n\nDesign Consideration:\nMake your workflows modular enough to be reused between repair and normal usage if possible.\n\n#### addRepairListener (cb) =>\n```js\n\nAssistantAPIClient.addRepairListener(()=>{\n  // Self-heal\n})\n\n```\n\nRecommended Usage: A repair process should be wrapped in the try/catch/finally flow shown in the `setAssistantState` API call to provide the user assistant-state and error updates as well as pause `inventoryChanged` notifications during repair (if the assistant has subscribed).\n\n#### removeRepairListener = (cb) =>\nRemoves the repair listener by reference, or if no callback function reference is provided, it removes all listeners.\n\n### User-facing Error Handling\n\n#### reportError (error) =>\nReports an error to the UI to be displayed in the assistant's error log in the\ninventory panel. This call is not disruptive and designed to operated independently of other assistant operations, such as state management. See `setAssistantState` in the next section.\n\nRecommended usage: use this functionality where it would futher the user experience\nto show the user an error and it's cause. Do not use this where things will be retried,\ncleaned up automatically, or are not relevant to the user.\n\n```js\ntry{\n  // Do work\n} catch(e) {\n  AssistantAPIClient.reportError(e)\n}\n```\n\n### State management\n\n#### clearState = () =>\nThis will remove all callbacks from all listeners.\n\n```js\nawait AssistantAPIClient.clearState()\n```\n\n#### setAssistantState = (state) =>\nThis sets the current state of the assistant using the\n`AssistantState` enum. Setting a state of `WORKING` will\ncreate the 'working' status spinner in the Assistant\nInventory Panel in the Maana Q UI. Conversely, setting an `IDLE` state will\nremove the spinner. This adds to user experience by informing users of the\nstatus of operations.\n\n```js\nimport {\n  default as AssistantAPIClient,\n  AssistantState\n} from '@io-maana/q-assistant-client'\n\n...\n\nAssistantAPIClient.setAssistantState(AssistantState.WORKING)\n\n...\n\nAssistantAPIClient.setAssistantState(AssistantState.IDLE)\n\n```\nUI User Prompt: If the assistant is in a `WORKING` state, the Maana Q UI will\nwarn the user before leaving the workspace.\n\nNOTE: while an assistant is in a working state, it will\nnot receive `inventoryChanged` events--an aggregated inventory diff\nwill be sent once the assistant is set back to `IDLE`.\n\nRecommended usage: Control states at a high level using try/catch/finally\nflow incorporating the `reportError` API call.\n\n```js\ntry{\n  AssistantAPIClient.setAssistantState(AssistantState.WORKING)\n  // Do work, await high-level tasks, etc.\n} catch(e) {\n  AssistantAPIClient.reportError(e)\n} finally{\n  AssistantAPIClient.setAssistantState(AssistantState.IDLE)\n}\n```\n\n#### AssistantState (enum)\nContains the valid assistant states: `IDLE` or `WORKING`.\n\nMust be imported in addition to the AssistantAPIClient:\n\n```js\nimport {\n  default as AssistantAPIClient,\n  AssistantState\n} from '@io-maana/q-assistant-client'\n```\n\n\n### User Info\nThe `UserInfo` object:\n```js\n{\n email: string,\n name: string\n}\n```\n\n#### getUserInfo = () =>\nReturns a Userinfo object pertaining to the logged in user.\n\n```js\nconst userInfo = await AssistantAPIClient.getUserInfo()\n```\n### Selection\nThe `Selection` object:\n```js\n{\n  kindId: string\n  kindName: string\n  id: string\n}\n```\n\n#### getCurrentSelection = () =>\nReturns an Array of `Selection` objects:\n\n```js\nconst {selection} = await AssistantAPIClient.getCurrentSelection();\n```\n\n#### addSelectionChangedListener = async cb =>\nAdds a callback function to be executed upon a valid workspace selection change.\n\nCallback value is an array of Selection objects:\n\n```js\n// Create the selection callback.\nconst selectionCB = ({selection})=>{\n  console.log('Workspace selection has changed.')\n  selection.forEach(i=>{\n    console.log('Kind: ',i.kindName)\n    console.log('Instance Id:',i.id)\n    console.log('Kind Id:',i.kindId)\n  })\n}\n\n// Add the listener.\nAssistantAPIClient.addSelectionChangedListener(selectionCB);\n```\n\nThis function only exists on the Q-Assistant-Client--only enableSelectionChangedNotification is called on the API.\n\n#### removeSelectionChangedListener = async cb =>\nThis will have to be called on a 1:1 basis with addSelectionChangedListener calls if supplying a callback.\n\n```js\nAssistantAPIClient.removeSelectionChangedListener(selectionCB)\n```\n\n**If NOT supplying a callback to this call, all selection changed listeners will be removed.\n\n```js\nAssistantAPIClient.removeSelectionChangedListener()\n```\n\nThis function only exists on the Q-Assistant-Client--only disableSelectionChangedNotification is called on the API.\n\n\n### Services\nThe `Service` object:\n```js\n{\n   id: string,\n   name: string\n   endpointUrl: string,\n   getKinds: () => // Returns [] of Kinds objects\n   getFunctions: () => // Returns [] of Function objects\n}\n```\n\n#### getServiceById = id =>\nThis will return a service that exists within the scope of the workspace.\n** Assistant services will return null. Services outside the scope of the workspace will cause an error to be returned as 'Unable to load a Service from outside of the workspace.'\n\n```js\nconst svc = await AssistantAPIClient.getServiceById(id)\n```\n\n#### createService = id =>\nCreates a service in Q.\n\nNote: This will create the service, but does NOT import it into the workspace.\nYou will need to use `importService` on the Workspace object to import it.\nReturns a promise that resolves\n\n```js\n    const service = {\n      id: ...,\n      name: ...,\n      endpointUrl: ...,\n      serviceType: ...\n    }\n\n    await AssistantAPIClient.createService(service)\n```\n\n#### deleteService = id =>\nDeletes a service from Q.\n\n```js\n    await AssistantAPIClient.deleteService(id)\n```\n\n#### refreshServiceSchema = id =>\nRefreshes a service by fetching its schema. This will also\nreload the service inventory in the currently visible workspace.\n\n```js\nawait AssistantAPIClient.refreshServiceSchema(\"id\")\n```\n\n#### reloadService = id =>\nReloads a service in the inventory in the currently visible workspace.\n\n```js\nawait AssistantAPIClient.reloadService(\"id\")\n```\n\n### Workspace\n\n#### getWorkspace = () =>\nReturns a Workspace object representing the workspace.\n\n```js\nconst ws = await AssistantAPIClient.getWorkspace(id)\n```\n\nNote: The `id` parameter is optional. If it is not supplied, the query\nwill return the current/visible workspace.\n\nThe `Workspace` object:\n\n```js\n\n{\n    id: string,\n    name: string,\n    endpointUrl: string,\n    workspaceServiceId: string,\n    modelServiceId: string,\n    logicServiceId: string,\n\n    //\n    // Locking information\n    //\n    async lockedBy() {\n      // Returns the e-mail address of the user who locked the Workspace, or\n      // null if the Workspace is not currently locked.\n    }\n    async canEdit() {\n      // Returns `true` when the Workspace is not locked, or the current user\n      // owns the lock.\n      // Returns 'false' when the Workspace is locked by a different user.\n    }\n    async setLocked(isLocked) {\n      // Takes a boolean or undefined for `isLocked`.\n      //  `true` locks the Workspace as the current User.\n      //  `false` unlocks the Workspace\n      //  `undefined` causes it to toggle the current locked state.\n      // Returns a Promise that will resolve or reject when the task is done.\n    }\n\n    //\n    // Knowledge Graphs\n    //\n    getActiveGraph: async () => {\n      // Returns the active Graph object.\n      // Returns null if active graph is not of type 'Knowledge Graph', or if an\n      // active graph is deleted, thereby setting active graph to null.\n    },\n    getKnowledgeGraphs: async () => {\n      // Returns [Graph]\n    },\n    // TODO: define input\n    createKnowledgeGraph: input =>\n    // TODO: define input\n    createKnowledgeGraphs: input =>\n\n    //\n    // Services\n    //\n    getImportedServices: async () => {\n      // Returns an array of Service objects that have\n      // been imported into the workspace.\n      // No assistant services will be returned.\n    },\n    getImportedAssistants: async () => {\n      // Returns a list of imported assistants.\n    },\n    importService: serviceId => {\n      // Imports a service by it's ID.\n    },\n    importServices: serviceIds => {\n      // Imports services by their IDs.\n    },\n    removeServices: serviceIds => {\n      // Removes a list of services from the workspace.\n    },\n    removeService: serviceId => {\n      // Removes a service from the workspace.\n    },\n\n    //\n    // Functions\n    //\n    getFunctions: async () => {\n      // Returns an array of functions in the workspace (includes boilerplate).\n    },\n    createFunction: funcData => {\n      // Creates a function and adds it to the graph.\n    }\n    createFunctions: funcData =>{\n      // Creates several functions and adds them to the graph.\n    }\n    updateFunction: funcData => {\n      // Updates a function.\n    },\n    updateFunctions: funcData =>{\n      // Updates functions based on input array.\n    },\n    deleteFunction: funcId => {\n      // Deletes a function by its ID.\n    },\n    getFunctionGraph: funcId => {\n      // Returns a function graph by its ID.\n    }\n\n    //\n    // Kinds\n    //\n    getKinds: async () => {\n      // Returns an array of functions in the workspace (includes boilerplate).\n    },\n    createKind: kindData => {\n      // Currently same input as AssistantAPIClient call.\n    },\n    createKinds: kindData => {\n      // Currently same input as AssistantAPIClient call.\n    },\n    updateKind: kindData => {\n      // Currently same input as AssistantAPIClient call.\n    },\n    updateKinds: kindData => {\n      // Currently same input as AssistantAPIClient call.\n    },\n    deleteKind: kindId => {\n      // Currently same input as AssistantAPIClient call.\n    }\n    // Event Triggers\n    triggerRepairEvent: () => {\n      // Triggers the repair event on a workspace.\n    }\n  };\n}\n```\n\n\n### Graphs\nThe `Graph` object:\n```js\n{\n  id: string,\n  name: string,\n  offsetX: Number,\n  offsetY: Number,\n  zoom: Number,\n  getNodes: async () => {\n      // Returns [Node]\n  },\n\n  addNode: async (type, instance, changeSelection) => {\n      // Returns Node\n  },\n  removeNode: async id => {\n      // Should return nothing or error.\n      // Currently returning [] in all cases.\n  },\n  updateNodeLayout: async (nodeId, { x, y, collapsed }) => {\n  },\n  updateGraphLayout: async ({ offsetX, offsetY, zoom }) => {\n  }\n\n  //\n  // Locking information\n  //\n  async lockedBy() {\n    // Returns the e-mail address of the user who locked the Graph, or null if\n    // the Graph is not currently locked.\n  }\n  async canEdit() {\n    // Returns `true` when the Graph is not locked, or the current user owns the\n    // lock.\n    // Returns 'false' when the Graph is locked by a different user.\n  }\n  async setLocked(isLocked) {\n    // Takes a boolean or undefined for `isLocked`.\n    //  `true` locks the Graph as the current User.\n    //  `false` unlocks the Graph\n    //  `undefined` causes it to toggle the current locked state.\n    // Returns a Promise that will resolve or reject when the task is done.\n  }\n}\n```\n\n#### Getting a graph object:\nGraph objects are obtained through an instance of a Workspace\n\n```js\nconst ag = await ws.getActiveGraph()\n```\n\nor\n\n```js\nconst kgs = await ws.getKnowledgeGraphs()\n```\n\n#### Manipulating Graphs\n\n**Only the active graph may be manipulated.\n\nAll graph manipulations should be ‘visually’ verifiable on the graph itself, i.e., adds/removes/positioning, should all be reflected on the graph itself.\n\nThe `Node` object:\n```js\n{\nid: string\nx: number\ny: number\ncollapsed: boolean\nknowledgeGraphNode {\n  id: string\n  innerKind: Kind\n  innerFunction: Function\n}\n}\n```\n\n#### addNode(type, instance, changeSelection) =>\n\nTakes type (“Function” or “Kind”), instance (the Function or Kind object), and optionally a boolean to indicate whether the selection should be changed to this new node.\n\nReturns the newly created Node object.\n\n```js\nconst node = await ag.addNode('Kind',kind)\n```\n\n#### removeNode(id) =>\n\nTakes the id of Node to be deleted. Returns either undefined or an error.\n\n```js\nawait ag.removeNode(node.id)\n```\n\n#### getNodes() =>\nReturns an array of Node objects from the graph.\n\n```js\nconst nodes = await ag.getNodes()\n```\n\n#### updateNodeLayout: async (nodeId, { x, y, collapsed})=>\nUpdates a Node layout given a node ID and node coordinates (`x` and/or `y`) or a `collapsed` value. x/y values must be a number, and collapsed must be a boolean. Whatever is not specified will remain current.\n\n```js\nag.updateNodeLayout(id,{x:100,y:100,collapsed:true})\n```\n\n#### updateGraphLayout: async ({ offsetX, offsetY, zoom})=>\nUpdates a Graph layout given numerical values for x/y offsets and the zoom.\n\n```js\nag.updateGraphLayout({offsetX:50, offsetY:50, zoom: 70})\n```\n\n### Functions\n\nThe `Function` object:\n```js\n{\n    id: string\n    name: string\n    service {\n      id: string\n      name: string\n    }\n    arguments {\n      id: string\n      name: string\n      type: string\n      modifiers: Array[string]\n      typeKindId:: string\n      kind {\n        id: string\n        name: string\n      }\n    }\n    implementation {\n      id: string\n      entrypoint {\n        id: string\n      }\n      operations {\n        id: string\n        type: string\n        function {\n          id: string\n          name: string\n        }\n        argumentValues {\n          id: string\n          argument {\n            id: string\n          }\n          operation {\n            id: string\n          }\n          argumentRef: string\n        }\n      }\n    }\n    isGenerated: boolean\n    functionType: string\n    graphqlOperationType: string\n    outputType: string\n    outputKindId: string\n    outputModifiers: Array[string]\n    kind {\n      id: string\n      name: string\n    }\n\n    //\n    // Locking information\n    //\n    async lockedBy() {\n      // Returns the e-mail address of the user who locked the Function, or null\n      // if the Function is not currently locked.\n    }\n    async canEdit() {\n      // Returns `true` when the Function is not locked, or the current user\n      // owns the lock.\n      // Returns 'false' when the Function is locked by a different user.\n    }\n    async setLocked(isLocked) {\n      // Takes a boolean or undefined for `isLocked`.\n      //  `true` locks the Function as the current User.\n      //  `false` unlocks the Function\n      //  `undefined` causes it to toggle the current locked state.\n      // Returns a Promise that will resolve or reject when the task is done.\n    }\n}\n```\n\n`FunctionExecutionResult` object:\n```js\n{\n  id: string,\n  result: JSON\n}\n```\n\n#### executeFunction = ( {id, variables, resolve} ) =>\nExecutes a function based on its id, with optional inputs for variables and a resolve string (this specifies the fields to be returned, which must be valid based on the result).\n\nReturns : JSON matching shape of result , unless no sub-selection of fields is required in the execution.\n\nThis following piece of code will execute a Function given a function ID, and pass in variables for ‘example’, requesting back id and name fields.\n\n```js\nconst res = await AssistantAPIClient.executeFunction({functionId: func.id, variables: {\"variableName\": \"variableValue\"}, resolve: \"{ id name }\");\n```\n\n#### createFunction = input =>\nCreates a function based on the input provided.\n\nReturns: the created Function object.\n\n**Using create function will only place the function in the workspace’s inventory--it will not place the function as a node on the Graph. In order to do this, you must pass the created function into the addNode function on the active Graph, making sure to specify ‘Function' as the type.\n\n```js\nconst createFunctionInput = {\n  name:\"yourName\",\n  arguments:[],\n  outputType: \"STRING\",\n  graphqlOperationType:\"QUERY\",\n  functionType: \"CKG\"\n}\n\nconst createdFunction = await AssistantAPIClient.createFunction(createFunctionInput)\n```\n\n#### updateFunction = input =>\nInput is the same for creating a function. It’s important to note that the arguments property will be replaced in it’s entirety with whatever is provided (if a value is provided.\n\nReturns the updated `Function` object.\n\n```js\nconst updatedFunction = await AssistantAPIClient.updateFunction(input);\n```\n\n#### deleteFunction = input =>\nInput is the id of the Function to be deleted. Returns the deleted function as a promise.\n\n```js\nconst deletedFunction = await AssistantAPIClient.deleteFunction('id...');\n```\n\n#### getFunctionById = id =>\nReturns a Function as a promise based on the ID provided.\n\n```js\nconst func = await AssistantAPIClient.getFunctionById('id...');\n```\n\n#### addFunctionExecutionListener = async (id, cb) =>\nAssociates a callback function with the execution of a particular Function. When the Function matching the id parameter is executed, its FunctionExecutionResult object passed to the callback. Returns undefined.\n\nExample function execution callback and listener registration:\n\n```js\nfunction exampleFunctionCB (result){\n  console.log(`Function executed with result:`, result)\n}\n\nAssistantAPIClient.addFunctionExecutionListener('id...', exampleFunctionCB)\n```\n\n#### removeFunctionExecutionListener = async (id, cb) =>\nRemoves a Function execution listener based on the function ID and a reference to the callback function. If no callback is supplied, all listeners associated with the Function ID will be removed. Returns undefined.\n\n```js\nAssistantAPIClient.removeFunctionExecutionListener('id..', exampleFunctionCB)\n```\n\n### Kinds\nThe `Kind` object:\n```js\n{\n    id: string\n    name: string\n    service: {\n      id\n      name\n    }\n    isGenerated: boolean\n    schema {\n      id: string\n      name: string\n      type: string\n      typeKindId: string\n      modifiers: Array[string]\n      kind {\n        id: string\n        name: string\n      }\n    }\n}\n```\n\n#### createKind = input =>\nCreates a Kind based on an input object. Returns a promise that resolves to the created Kind object.\n\n```js\nconst kindInput = {\n name: \"someKind\",\n schema:[\n  { name: \"someField1\", type: STRING },\n  { name: \"someField2\", type: STRING }\n ]\n}\n\nconst newKind = await AssistantAPIClient.createKind(kindInput)\n```\n\n#### createKinds = input =>\nA plural version of `createKind` accepting an array of input objects.\nReturns a promise that resolves to an array of created Kind objects.\n\n```js\nconst kindsInput = [{\n name: \"someKind\",\n schema:[\n  { name: \"someField1\", type: STRING },\n  { name: \"someField2\", type: STRING }\n ]\n}, ...]\n\nconst newKinds = await AssistantAPIClient.createKinds(kindsInput)\n```\n\n\n#### updateKind = input =>\nUpdates a Kind based on an input object.\n\nUpdate Semantics: Only properties specified will be updated. If updating the schema, the entire schema must be specified as it will be replaced in its entirety.\n\nReturns a promise that resolves to the updated `Kind` object.\n\n```js\nconst updated = await AssistantAPIClient.updateKind(input)\n```\n\n#### deleteKind = input =>\nDeletes a Kind given a kind ID.\n\n```js\nconst deleted = await AssistantAPIClient.deleteKind(input)\n```\n\n#### getKindById = id =>\nReturns a promise that resolves to a Kind object given the specified kind ID.\n\nIn v3.2.2, any requested non-system kinds will be returned.\nIn v3.2.1, only kinds in the workspace or those of imported services will be returned.\n\n```js\nconst kind = await AssistantAPIClient.getKindById(id)\n```\n\n#### getKindsById = ids =>\nReturns a promise that resolves to an array of Kind objects given an array of kind IDs. Only kinds in the workspace or those of imported services will be returned.\n\n```js\nconst ids = [\"...\",\"...\",...]\nconst kind = await AssistantAPIClient.getKindsById(ids)\n```\n\n#### getAllReferencedKinds = input =>\nRecursively collects all kinds that are referenced in a kind's schema, starting\nwith a kind ID. For example if the ID of kind A is supplied as an input, and Kind `A` contains a field of type Kind `B`, and `B` contains a field of type Kind `C`,\nan array containing the kinds objects for `A`, `B`, `C` will be returned (as a promise).\n\n```js\nconst initialId = [\"...\"]\nconst kinds = await AssistantAPIClient.getAllReferencedKinds({\n          ids: initialId\n        })\n```\n\n\n### Inventory\n\nThe `InventoryChanged` object:\n```js\n{\n  kinds: {\n    adds: [DiffItem]\n    deletes: [DiffItem]\n    updates: [DiffItem]\n  }\n  functions:{\n    adds: [DiffItem]\n    deletes: [DiffItem]\n    updates: [DiffItem]\n  }\n  services: {\n    adds: [DiffItem]\n    deletes: [DiffItem]\n    updates: [DiffItem]\n  }\n}\n```\n\nThe `DiffItem` object:\n```js\n{\n  id: string,\n  name: string\n}\n```\n\n#### addInventoryChangedListener = async cb =>\nRegisters a callback function with the inventory changed event. When workspace inventory changes the callback function will be called with the InventoryChangedobject. Returns undefined.\n\n**Use-case note: an ‘update’ diff for inventory services is unlikely in general usage.\n\n```js\nconst inventoryCB = ({diff}) => {\n  if(diff.kinds) console.log('KINDS CHANGED',diff.kinds)\n  if(diff.functions) console.log('FUNCTIONS CHANGED', diff.functions)\n  if(diff.services) console.log('SERVICES CHANGED',diff.services)\n}\n\nAssistantAPIClient.addInventoryChangedListener(inventoryCB)\n```\n\nThis function exists on the Q-Assisant-Client only--only enableSelectionChangedNotification is used on the API side.\n\n#### removeInventoryChangedListener = async cb =>\nRemoves an inventory changed listener given the referenced callback. If no callback is specified, all listeners will be removed. Returns undefined.\n\n```js\nAssistantAPIClient.removeInventoryChangedListener(inventoryCB)\n```\n\nThis function exists on the Q-Assisant-Client only--only disableSelectionChangedNotification is used on the API side.\n\n#### moveKindsAndFunctions = (originId, targetId, kindIds, functionIds) =>\nMoves a collection of Kinds and Functions from the origin Workspace to the target Workspace.\n\n```js\n  await AssistantAPIClient.moveKindsAndFunctions(\n    originWorkspaceId,\n    targetId,\n    kindIds,\n    functionIds\n  );\n```\n\n### Locking Changed Event\n\nAn event is triggered when the locked state of the currently active Workspace or\nits Knowledge Graphs and Functions change.\n\nThe `LockingChanged` object:\n```js\n{\n  workspaces: [LockItem],\n  knowledgeGraphs: [LockItem],\n  functions: [LockItem]\n}\n```\n\nThe `LockItem` object:\n```js\n{\n  id: string\n  lockedBy: string\n}\n```\n\n#### addLockingChangedListener = cb =>\n\nRegisters a callback function with the locking changed event. When the currently\nactive Workspace or its Knowledge Graphs and Functions change the callback\nfunction will be called with the `LockingChanged` object. Returns undefined.\n\n```js\nconst lockingChangedCB = ({ locks }) => {\n  if(locks.workspace) console.log('WORKSPACES CHANGED', locks.workspace);\n  if(locks.knowledgeGraphs) console.log('KNOWLEDGE GRAPHS CHANGED', locks.knowledgeGraphs);\n  if(locks.functions) console.log('FUNCTIONS CHANGED', locks.functions);\n}\n\nAssistantAPIClient.addLockingChangedListener(lockingChangedCB);\n```\n\n#### removeLockingChangedListener = cb =>\n\nRemoves an locking changed listener given the referenced callback. If no\ncallback is specified, all listeners will be removed. Returns undefined.\n\n```js\nAssistantAPIClient.removeLockingChangedListener(lockingChangedCB)\n```\n\n## Troubleshooting Assistant Issues\n### Assistant root file has loaded, but not other content\nObserving in the browser's dev tools that some resources have loaded correctly (usually the root), but other's haven't (usually nested files or chunks), is indicative of a failure of Q Gateway to proxy due to not having a 'relative' path structure.\n\n### You are seeing post-robot `NO ACK` errors in the console.\nThese errors stem from a failed acknowledgement for a call either between the client and the API or vice-versa. Here, this means that the web app 'window' (the assistant) cannot communicate with, or access, the 'window.parent' (Maana K-Portal) object.\n\nCommonly, these will stem from the 'window' (the assistant) not being loaded or in a loadable state, which means the API will not receive an acknowledgement when it fires an event.\n\nImproper CORS configuration is also a common culprit (also verify if using docker or nginx that your proxying and networking is configured correctly to allow communication and to accout for CORS).","readmeFilename":"README.md","gitHead":"9eae85f35ea75ac5c76c7b5c50bc2d655dec6b0b","_id":"@io-maana/q-assistant-client@3.3.0-beta.11","_nodeVersion":"12.21.0","_npmVersion":"6.14.11","dist":{"integrity":"sha512-OfoFU735S3ieAruSwkicdDqcSIFZs6+dEzRo6H3gbxGcP4staDXS+7+i+KkmokA4TlLf2eUR86G1/kbRJbi+Og==","shasum":"e3eed193b8f17e2db2b5bc845fdcf184104e5fd5","tarball":"https://registry.npmjs.org/@io-maana/q-assistant-client/-/q-assistant-client-3.3.0-beta.11.tgz","fileCount":83,"unpackedSize":356435,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJgXgo9CRA9TVsSAnZWagAAiGcQAKApVCHZasplJu7B2iqk\n2cdRIroI4eKQGMfHFSOw4EOkzDgCUT67h2OrPE7WbQwTqzhQhaOvUWZDCvvZ\nh7WJ3OU9p2S0hZpS6zES66RwAtNyiTdlRk6BEqFUceF+/yUpLO0C8FGaw5Fs\nZENr2U0Ljnon/6dGPZcPgSEtUQyEc6DUuRmoOqZhiugwdoktUM5fGSokyGZ4\nmd5JdcXv5sKp7OHRhDqeOlLmrPTMxFJWPp277PGudUyxJ6DwiKi0DNYZ6nUm\nnCmPaE+9LdrGUiSBWUKP8LcZxha2r/+5c4RojnBatvXBNBsvtV+xADxuA3+p\nteIix1ot8loA8C5xQ8YUMuBoqYjrBLRWyQy71xwzi/jtAzeNA3MdTn/eSD+k\nliI3oVL/Ck3JR8shQmCl+1aAz284eGg6uPSnJ0DbGNWmFSqECfAGQIWQ5d8d\naVVJIofKvl0w8eKQ4f66jzSIIyLjY5DzjgWxEg2eiMOdRES3ky5VrCD3XUAB\n+46PzZaERWZwAcehUq8nIEthr8LnpwF64fa1n2xtXq0WQ2P34MkxqWYqbebL\nCbDmKd5clXLre+1curBbs1Li9HnS6DzxgYoZwpC3K/aGWfzgzdU9HlpoicRK\neEc6xRU8LyB6ij2A7HZ55r6pEjyZt7r9pSuVeoqeWmkbpLYezUxnVHz8e5gw\nulYr\r\n=oLdy\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEYCIQCx+JqxDU2tQq9sveQ/cGRIIV3toQHDwj0qcTWFKdAElQIhAPPFeLjS/gnrrZ+vRiG02vvefTINkzQonJlSGepW6up8"}]},"_npmUser":{"name":"teamcitymaana","email":"teamcity@maana.io"},"directories":{},"maintainers":[{"name":"witt3rd","email":"witt3rd@witt3rd.com"},{"name":"bzvetey","email":"bzvestey@gmail.com"},{"name":"abatyuk","email":"andrey@maana.io"},{"name":"rpovey","email":"rob@maana.io"},{"name":"teamcitymaana","email":"teamcity@maana.io"},{"name":"dlsmaana","email":"dlewissandy@maana.io"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/q-assistant-client_3.3.0-beta.11_1616775741430_0.4100843088542283"},"_hasShrinkwrap":false},"3.3.0-beta.13":{"name":"@io-maana/q-assistant-client","version":"3.3.0-beta.13","description":"JavaScript package to streamline communication between an assistant and the Maana Q Assistant API.","main":"build/index.js","types":"build/index.d.ts","exports":{"./":"./build/"},"scripts":{"build":"npm run build:ts && npm run build:doc","build:ts":"tsc --build tsconfig.json","build:doc":"typedoc","prepack":"npm run build","test":"echo \"Error: no test specified\" && exit 1","format":"prettier --write \"src/**/*.js\""},"repository":{"type":"git","url":"git+https://github.com/maana-io/q-assistant-client.git"},"keywords":["Maana","Q"],"author":{"name":"Logan Gore @ Maana.io"},"license":"MIT","bugs":{"url":"https://github.com/maana-io/q-assistant-client/issues"},"homepage":"https://github.com/maana-io/q-assistant-client#readme","dependencies":{"core-js":"3.6.4","post-robot":"10.0.29"},"devDependencies":{"@types/node":"^14.14.2","@types/post-robot":"^10.0.0","prettier":"2.0.5","typedoc":"^0.19.2","typedoc-plugin-markdown":"^3.0.11","typescript":"^3.9.5"},"readme":"# q-assistant-client\nA lightweight JavaScript client for Maana-Q Assistant developers that wraps post-message communication between an embedded Maana-Q assistant and the Maana-Q UI.\n\nYou can find the [API Documentation here](docs/README.md).\n\n## Abstract\nThe Q-Assistant-Client is intented to be used in a web application being leveraged as a Maana Q assistant (embedded as an iframe).\nThis assistant client will facilitate communication between the assistant and the parent frame.\nThe client provides a rich, asynchronous experience over what would otherwise be 'fire-and-forget'-style messaging\nvia post-post message communication.\n\n## Requirements and Assumptions\n\n### Post-Robot Library\nThe Maana Knowledge Portal (KPortal) uses the kraken/post-robot library [kraken/post-robot](https://github.com/krakenjs/post-robot) to enrich the communication with the assistant. Post-robot allows for asynchronous, promise-based request/response style behavior between the assistant and the assistant API.\n\nThe API requires that the client use the post-robot library. This assistant-client library is the easiest way to achieve this, and also adds a fair amount of 'sugar' to the process to improve developer productivity. Developers could, however, use post-robot directly in their own client implementation.\n\n### Maana-Gateway Proxy Requirements\nThe Maana-Gateway service requires relative paths (paths relative to the root) in the assistant web application in order to proxy the application and its content. For create-react-apps, for instance, this means setting \"homepage\" to \".\" in the package.json file.\n\n## Singleton Instance\nThe client is exported as a singleton to avoid duplicate registration on event listeners.\nYou can import the instance like this:\n\n```js\nimport AssistantAPIClient from '@io-maana/q-assistant-client';\n```\n\nFunction calls can be made against the client instance like any other javascript object. They are all async.\n\n```js\nconst workspace = await AssistantAPIClient.getWorkspace();\nconsole.log(\"Workspace:\", workspace)\n```\n\n## Dependencies\nPost-Robot\nhttps://github.com/krakenjs/post-robot\n\nPost-robot is used to provide a richer communication layer atop post-message.\n\n## Versioning\nThe Maana Q Assistant Client does not follow semantic versioning. Its versions\ntrack the releases of the Maana Q platform.\n\n## Examples\n@TODO Logan\n\n\n## Changes in v3.2.2\nImprovements in v3.2.2\n- Assistant State Management: WORKING, IDLE\n- Background Messaging/Eventing\n- Render Modes: BACKGROUND, DISPLAY\n- Expansion of Workspace object capabilities\n- Error Reporting\n- Repair Event\n- Plural versions of calls such as updateKind(s) to improve performance and developer experience.\n- InventoryChanged diffing is fully granular in v3.2.2--limitations\nin v3.2.1 only fired the Function diff for changes in Function name.\n\n### Deprecation\nThe following surface area IS removed from the\nclient in v3.2.2, and IS deprecated in the API:\n- AssistantAPIClient.enableSelectionChangedNotification\n- AssistantAPIClient.disableSelectionChangedNotification\n- AssistantAPIClient.enableInventoryChangedNotification\n- AssistantAPIClient.disableInventoryChangedNotification\n\nThe following surface area WILL BE removed from\nthe client in v3.2.4, and WILL BE deprecated in the API:\n- AssistantAPIClient.updateFunction (expected move to Workspace object)\n- AssistantAPIClient.updateKind (expected move to Workspace object)\n- AssistantAPIClient.deleteKind (expected move to Workspace object)\n- AssistantAPIClient.deleteFunction (expected move to Workspace object)\n\n## API Documentation\nMore information in the [API File](./API.md)\n\n### Assistant Render Mode\nAn assistant's render mode refers to whether it is being displayed in a visible manner to the user. As of v3.2.2, assistants are not closed when they are out of view.\nAll assistants will be loaded and kept in `BACKGROUND` render mode until they are\nplaced in the assistant panel, at which point the `DISPLAY` render mode event will be fired.\n\nNote: Assistants will receive all notifications/events while in BACKGROUND mode.\n\nDesign Consideration: It will be up to the developer to determine how state and resource use will be managed while an assistant is operating between BACKGROUND and DISPLAY modes.\n\n#### addRenderModeChangedListener = (cb) =>\nA listener to receive push events as to the assitant's render mode being changed.\n\n```js\nfunction handleRenderModeChanged(renderMode){\n  if (renderMode === 'DISPLAY'){\n    // Assistant is visible\n  } else {\n    // Assistant is not visible and running in background.\n  }\n}\n\nAssistantAPIClient.addRenderModeChangedListener(handleRenderModeChanged)\n\n```\n\n#### removeRenderModeChangedListener = (cb) =>\nRemoves the renderModeChanged listener by reference, or if no callback function reference is provided, it removes all listeners.\n\n#### getRenderMode = () =>\nReturns the current assistant render mode.\n\n```js\nconst renderMode = await AssistantAPIClient.getRenderMode()\n\nif (renderMode === 'DISPLAY'){\n  // Assistant is visible\n} else {\n  // Assistant is not visible and running in background.\n}\n\n```\n\n### Repair\nAssistants may get into situations where they are either out of sync with the Maana Q UI, or in a failure state. Assistants should be able to recover from these states.\n\nThe repair event functionality added in v3.2.2 is designed to notify the assistant that it must repair itself. This could mean a resync with its resources on the workspace or externally or, for some assistants, nothing at all.\n\nWhen is repair triggered?\nEither manually by a user clicking 'repair workspace' under the\nassistant inventory panel, or upon a workspace clone event. An assistant will be expected to handle either scenario.\n\nPerformance Consideration:\nFor some assistants, repair might involve 'introspecting'\nand processing the current workspace or Q system resources. This could be very resource intensive. Make sure you review this API guide to have an idea of what tools are\navailable to get the best results. It's always a good idea to check performance of repair on a large workspace and ensure necessary optimizations have been made.\n\nDesign Consideration:\nMake your workflows modular enough to be reused between repair and normal usage if possible.\n\n#### addRepairListener (cb) =>\n```js\n\nAssistantAPIClient.addRepairListener(()=>{\n  // Self-heal\n})\n\n```\n\nRecommended Usage: A repair process should be wrapped in the try/catch/finally flow shown in the `setAssistantState` API call to provide the user assistant-state and error updates as well as pause `inventoryChanged` notifications during repair (if the assistant has subscribed).\n\n#### removeRepairListener = (cb) =>\nRemoves the repair listener by reference, or if no callback function reference is provided, it removes all listeners.\n\n### User-facing Error Handling\n\n#### reportError (error) =>\nReports an error to the UI to be displayed in the assistant's error log in the\ninventory panel. This call is not disruptive and designed to operated independently of other assistant operations, such as state management. See `setAssistantState` in the next section.\n\nRecommended usage: use this functionality where it would futher the user experience\nto show the user an error and it's cause. Do not use this where things will be retried,\ncleaned up automatically, or are not relevant to the user.\n\n```js\ntry{\n  // Do work\n} catch(e) {\n  AssistantAPIClient.reportError(e)\n}\n```\n\n### State management\n\n#### clearState = () =>\nThis will remove all callbacks from all listeners.\n\n```js\nawait AssistantAPIClient.clearState()\n```\n\n#### setAssistantState = (state) =>\nThis sets the current state of the assistant using the\n`AssistantState` enum. Setting a state of `WORKING` will\ncreate the 'working' status spinner in the Assistant\nInventory Panel in the Maana Q UI. Conversely, setting an `IDLE` state will\nremove the spinner. This adds to user experience by informing users of the\nstatus of operations.\n\n```js\nimport {\n  default as AssistantAPIClient,\n  AssistantState\n} from '@io-maana/q-assistant-client'\n\n...\n\nAssistantAPIClient.setAssistantState(AssistantState.WORKING)\n\n...\n\nAssistantAPIClient.setAssistantState(AssistantState.IDLE)\n\n```\nUI User Prompt: If the assistant is in a `WORKING` state, the Maana Q UI will\nwarn the user before leaving the workspace.\n\nNOTE: while an assistant is in a working state, it will\nnot receive `inventoryChanged` events--an aggregated inventory diff\nwill be sent once the assistant is set back to `IDLE`.\n\nRecommended usage: Control states at a high level using try/catch/finally\nflow incorporating the `reportError` API call.\n\n```js\ntry{\n  AssistantAPIClient.setAssistantState(AssistantState.WORKING)\n  // Do work, await high-level tasks, etc.\n} catch(e) {\n  AssistantAPIClient.reportError(e)\n} finally{\n  AssistantAPIClient.setAssistantState(AssistantState.IDLE)\n}\n```\n\n#### AssistantState (enum)\nContains the valid assistant states: `IDLE` or `WORKING`.\n\nMust be imported in addition to the AssistantAPIClient:\n\n```js\nimport {\n  default as AssistantAPIClient,\n  AssistantState\n} from '@io-maana/q-assistant-client'\n```\n\n\n### User Info\nThe `UserInfo` object:\n```js\n{\n email: string,\n name: string\n}\n```\n\n#### getUserInfo = () =>\nReturns a Userinfo object pertaining to the logged in user.\n\n```js\nconst userInfo = await AssistantAPIClient.getUserInfo()\n```\n### Selection\nThe `Selection` object:\n```js\n{\n  kindId: string\n  kindName: string\n  id: string\n}\n```\n\n#### getCurrentSelection = () =>\nReturns an Array of `Selection` objects:\n\n```js\nconst {selection} = await AssistantAPIClient.getCurrentSelection();\n```\n\n#### addSelectionChangedListener = async cb =>\nAdds a callback function to be executed upon a valid workspace selection change.\n\nCallback value is an array of Selection objects:\n\n```js\n// Create the selection callback.\nconst selectionCB = ({selection})=>{\n  console.log('Workspace selection has changed.')\n  selection.forEach(i=>{\n    console.log('Kind: ',i.kindName)\n    console.log('Instance Id:',i.id)\n    console.log('Kind Id:',i.kindId)\n  })\n}\n\n// Add the listener.\nAssistantAPIClient.addSelectionChangedListener(selectionCB);\n```\n\nThis function only exists on the Q-Assistant-Client--only enableSelectionChangedNotification is called on the API.\n\n#### removeSelectionChangedListener = async cb =>\nThis will have to be called on a 1:1 basis with addSelectionChangedListener calls if supplying a callback.\n\n```js\nAssistantAPIClient.removeSelectionChangedListener(selectionCB)\n```\n\n**If NOT supplying a callback to this call, all selection changed listeners will be removed.\n\n```js\nAssistantAPIClient.removeSelectionChangedListener()\n```\n\nThis function only exists on the Q-Assistant-Client--only disableSelectionChangedNotification is called on the API.\n\n\n### Services\nThe `Service` object:\n```js\n{\n   id: string,\n   name: string\n   endpointUrl: string,\n   getKinds: () => // Returns [] of Kinds objects\n   getFunctions: () => // Returns [] of Function objects\n}\n```\n\n#### getServiceById = id =>\nThis will return a service that exists within the scope of the workspace.\n** Assistant services will return null. Services outside the scope of the workspace will cause an error to be returned as 'Unable to load a Service from outside of the workspace.'\n\n```js\nconst svc = await AssistantAPIClient.getServiceById(id)\n```\n\n#### createService = id =>\nCreates a service in Q.\n\nNote: This will create the service, but does NOT import it into the workspace.\nYou will need to use `importService` on the Workspace object to import it.\nReturns a promise that resolves\n\n```js\n    const service = {\n      id: ...,\n      name: ...,\n      endpointUrl: ...,\n      serviceType: ...\n    }\n\n    await AssistantAPIClient.createService(service)\n```\n\n#### deleteService = id =>\nDeletes a service from Q.\n\n```js\n    await AssistantAPIClient.deleteService(id)\n```\n\n#### refreshServiceSchema = id =>\nRefreshes a service by fetching its schema. This will also\nreload the service inventory in the currently visible workspace.\n\n```js\nawait AssistantAPIClient.refreshServiceSchema(\"id\")\n```\n\n#### reloadService = id =>\nReloads a service in the inventory in the currently visible workspace.\n\n```js\nawait AssistantAPIClient.reloadService(\"id\")\n```\n\n### Workspace\n\n#### getWorkspace = () =>\nReturns a Workspace object representing the workspace.\n\n```js\nconst ws = await AssistantAPIClient.getWorkspace(id)\n```\n\nNote: The `id` parameter is optional. If it is not supplied, the query\nwill return the current/visible workspace.\n\nThe `Workspace` object:\n\n```js\n\n{\n    id: string,\n    name: string,\n    endpointUrl: string,\n    workspaceServiceId: string,\n    modelServiceId: string,\n    logicServiceId: string,\n\n    //\n    // Locking information\n    //\n    async lockedBy() {\n      // Returns the e-mail address of the user who locked the Workspace, or\n      // null if the Workspace is not currently locked.\n    }\n    async canEdit() {\n      // Returns `true` when the Workspace is not locked, or the current user\n      // owns the lock.\n      // Returns 'false' when the Workspace is locked by a different user.\n    }\n    async setLocked(isLocked) {\n      // Takes a boolean or undefined for `isLocked`.\n      //  `true` locks the Workspace as the current User.\n      //  `false` unlocks the Workspace\n      //  `undefined` causes it to toggle the current locked state.\n      // Returns a Promise that will resolve or reject when the task is done.\n    }\n\n    //\n    // Knowledge Graphs\n    //\n    getActiveGraph: async () => {\n      // Returns the active Graph object.\n      // Returns null if active graph is not of type 'Knowledge Graph', or if an\n      // active graph is deleted, thereby setting active graph to null.\n    },\n    getKnowledgeGraphs: async () => {\n      // Returns [Graph]\n    },\n    // TODO: define input\n    createKnowledgeGraph: input =>\n    // TODO: define input\n    createKnowledgeGraphs: input =>\n\n    //\n    // Services\n    //\n    getImportedServices: async () => {\n      // Returns an array of Service objects that have\n      // been imported into the workspace.\n      // No assistant services will be returned.\n    },\n    getImportedAssistants: async () => {\n      // Returns a list of imported assistants.\n    },\n    importService: serviceId => {\n      // Imports a service by it's ID.\n    },\n    importServices: serviceIds => {\n      // Imports services by their IDs.\n    },\n    removeServices: serviceIds => {\n      // Removes a list of services from the workspace.\n    },\n    removeService: serviceId => {\n      // Removes a service from the workspace.\n    },\n\n    //\n    // Functions\n    //\n    getFunctions: async () => {\n      // Returns an array of functions in the workspace (includes boilerplate).\n    },\n    createFunction: funcData => {\n      // Creates a function and adds it to the graph.\n    }\n    createFunctions: funcData =>{\n      // Creates several functions and adds them to the graph.\n    }\n    updateFunction: funcData => {\n      // Updates a function.\n    },\n    updateFunctions: funcData =>{\n      // Updates functions based on input array.\n    },\n    deleteFunction: funcId => {\n      // Deletes a function by its ID.\n    },\n    getFunctionGraph: funcId => {\n      // Returns a function graph by its ID.\n    }\n\n    //\n    // Kinds\n    //\n    getKinds: async () => {\n      // Returns an array of functions in the workspace (includes boilerplate).\n    },\n    createKind: kindData => {\n      // Currently same input as AssistantAPIClient call.\n    },\n    createKinds: kindData => {\n      // Currently same input as AssistantAPIClient call.\n    },\n    updateKind: kindData => {\n      // Currently same input as AssistantAPIClient call.\n    },\n    updateKinds: kindData => {\n      // Currently same input as AssistantAPIClient call.\n    },\n    deleteKind: kindId => {\n      // Currently same input as AssistantAPIClient call.\n    }\n    // Event Triggers\n    triggerRepairEvent: () => {\n      // Triggers the repair event on a workspace.\n    }\n  };\n}\n```\n\n\n### Graphs\nThe `Graph` object:\n```js\n{\n  id: string,\n  name: string,\n  offsetX: Number,\n  offsetY: Number,\n  zoom: Number,\n  getNodes: async () => {\n      // Returns [Node]\n  },\n\n  addNode: async (type, instance, changeSelection) => {\n      // Returns Node\n  },\n  removeNode: async id => {\n      // Should return nothing or error.\n      // Currently returning [] in all cases.\n  },\n  updateNodeLayout: async (nodeId, { x, y, collapsed }) => {\n  },\n  updateGraphLayout: async ({ offsetX, offsetY, zoom }) => {\n  }\n\n  //\n  // Locking information\n  //\n  async lockedBy() {\n    // Returns the e-mail address of the user who locked the Graph, or null if\n    // the Graph is not currently locked.\n  }\n  async canEdit() {\n    // Returns `true` when the Graph is not locked, or the current user owns the\n    // lock.\n    // Returns 'false' when the Graph is locked by a different user.\n  }\n  async setLocked(isLocked) {\n    // Takes a boolean or undefined for `isLocked`.\n    //  `true` locks the Graph as the current User.\n    //  `false` unlocks the Graph\n    //  `undefined` causes it to toggle the current locked state.\n    // Returns a Promise that will resolve or reject when the task is done.\n  }\n}\n```\n\n#### Getting a graph object:\nGraph objects are obtained through an instance of a Workspace\n\n```js\nconst ag = await ws.getActiveGraph()\n```\n\nor\n\n```js\nconst kgs = await ws.getKnowledgeGraphs()\n```\n\n#### Manipulating Graphs\n\n**Only the active graph may be manipulated.\n\nAll graph manipulations should be ‘visually’ verifiable on the graph itself, i.e., adds/removes/positioning, should all be reflected on the graph itself.\n\nThe `Node` object:\n```js\n{\nid: string\nx: number\ny: number\ncollapsed: boolean\nknowledgeGraphNode {\n  id: string\n  innerKind: Kind\n  innerFunction: Function\n}\n}\n```\n\n#### addNode(type, instance, changeSelection) =>\n\nTakes type (“Function” or “Kind”), instance (the Function or Kind object), and optionally a boolean to indicate whether the selection should be changed to this new node.\n\nReturns the newly created Node object.\n\n```js\nconst node = await ag.addNode('Kind',kind)\n```\n\n#### removeNode(id) =>\n\nTakes the id of Node to be deleted. Returns either undefined or an error.\n\n```js\nawait ag.removeNode(node.id)\n```\n\n#### getNodes() =>\nReturns an array of Node objects from the graph.\n\n```js\nconst nodes = await ag.getNodes()\n```\n\n#### updateNodeLayout: async (nodeId, { x, y, collapsed})=>\nUpdates a Node layout given a node ID and node coordinates (`x` and/or `y`) or a `collapsed` value. x/y values must be a number, and collapsed must be a boolean. Whatever is not specified will remain current.\n\n```js\nag.updateNodeLayout(id,{x:100,y:100,collapsed:true})\n```\n\n#### updateGraphLayout: async ({ offsetX, offsetY, zoom})=>\nUpdates a Graph layout given numerical values for x/y offsets and the zoom.\n\n```js\nag.updateGraphLayout({offsetX:50, offsetY:50, zoom: 70})\n```\n\n### Functions\n\nThe `Function` object:\n```js\n{\n    id: string\n    name: string\n    service {\n      id: string\n      name: string\n    }\n    arguments {\n      id: string\n      name: string\n      type: string\n      modifiers: Array[string]\n      typeKindId:: string\n      kind {\n        id: string\n        name: string\n      }\n    }\n    implementation {\n      id: string\n      entrypoint {\n        id: string\n      }\n      operations {\n        id: string\n        type: string\n        function {\n          id: string\n          name: string\n        }\n        argumentValues {\n          id: string\n          argument {\n            id: string\n          }\n          operation {\n            id: string\n          }\n          argumentRef: string\n        }\n      }\n    }\n    isGenerated: boolean\n    functionType: string\n    graphqlOperationType: string\n    outputType: string\n    outputKindId: string\n    outputModifiers: Array[string]\n    kind {\n      id: string\n      name: string\n    }\n\n    //\n    // Locking information\n    //\n    async lockedBy() {\n      // Returns the e-mail address of the user who locked the Function, or null\n      // if the Function is not currently locked.\n    }\n    async canEdit() {\n      // Returns `true` when the Function is not locked, or the current user\n      // owns the lock.\n      // Returns 'false' when the Function is locked by a different user.\n    }\n    async setLocked(isLocked) {\n      // Takes a boolean or undefined for `isLocked`.\n      //  `true` locks the Function as the current User.\n      //  `false` unlocks the Function\n      //  `undefined` causes it to toggle the current locked state.\n      // Returns a Promise that will resolve or reject when the task is done.\n    }\n}\n```\n\n`FunctionExecutionResult` object:\n```js\n{\n  id: string,\n  result: JSON\n}\n```\n\n#### executeFunction = ( {id, variables, resolve} ) =>\nExecutes a function based on its id, with optional inputs for variables and a resolve string (this specifies the fields to be returned, which must be valid based on the result).\n\nReturns : JSON matching shape of result , unless no sub-selection of fields is required in the execution.\n\nThis following piece of code will execute a Function given a function ID, and pass in variables for ‘example’, requesting back id and name fields.\n\n```js\nconst res = await AssistantAPIClient.executeFunction({functionId: func.id, variables: {\"variableName\": \"variableValue\"}, resolve: \"{ id name }\");\n```\n\n#### createFunction = input =>\nCreates a function based on the input provided.\n\nReturns: the created Function object.\n\n**Using create function will only place the function in the workspace’s inventory--it will not place the function as a node on the Graph. In order to do this, you must pass the created function into the addNode function on the active Graph, making sure to specify ‘Function' as the type.\n\n```js\nconst createFunctionInput = {\n  name:\"yourName\",\n  arguments:[],\n  outputType: \"STRING\",\n  graphqlOperationType:\"QUERY\",\n  functionType: \"CKG\"\n}\n\nconst createdFunction = await AssistantAPIClient.createFunction(createFunctionInput)\n```\n\n#### updateFunction = input =>\nInput is the same for creating a function. It’s important to note that the arguments property will be replaced in it’s entirety with whatever is provided (if a value is provided.\n\nReturns the updated `Function` object.\n\n```js\nconst updatedFunction = await AssistantAPIClient.updateFunction(input);\n```\n\n#### deleteFunction = input =>\nInput is the id of the Function to be deleted. Returns the deleted function as a promise.\n\n```js\nconst deletedFunction = await AssistantAPIClient.deleteFunction('id...');\n```\n\n#### getFunctionById = id =>\nReturns a Function as a promise based on the ID provided.\n\n```js\nconst func = await AssistantAPIClient.getFunctionById('id...');\n```\n\n#### addFunctionExecutionListener = async (id, cb) =>\nAssociates a callback function with the execution of a particular Function. When the Function matching the id parameter is executed, its FunctionExecutionResult object passed to the callback. Returns undefined.\n\nExample function execution callback and listener registration:\n\n```js\nfunction exampleFunctionCB (result){\n  console.log(`Function executed with result:`, result)\n}\n\nAssistantAPIClient.addFunctionExecutionListener('id...', exampleFunctionCB)\n```\n\n#### removeFunctionExecutionListener = async (id, cb) =>\nRemoves a Function execution listener based on the function ID and a reference to the callback function. If no callback is supplied, all listeners associated with the Function ID will be removed. Returns undefined.\n\n```js\nAssistantAPIClient.removeFunctionExecutionListener('id..', exampleFunctionCB)\n```\n\n### Kinds\nThe `Kind` object:\n```js\n{\n    id: string\n    name: string\n    service: {\n      id\n      name\n    }\n    isGenerated: boolean\n    schema {\n      id: string\n      name: string\n      type: string\n      typeKindId: string\n      modifiers: Array[string]\n      kind {\n        id: string\n        name: string\n      }\n    }\n}\n```\n\n#### createKind = input =>\nCreates a Kind based on an input object. Returns a promise that resolves to the created Kind object.\n\n```js\nconst kindInput = {\n name: \"someKind\",\n schema:[\n  { name: \"someField1\", type: STRING },\n  { name: \"someField2\", type: STRING }\n ]\n}\n\nconst newKind = await AssistantAPIClient.createKind(kindInput)\n```\n\n#### createKinds = input =>\nA plural version of `createKind` accepting an array of input objects.\nReturns a promise that resolves to an array of created Kind objects.\n\n```js\nconst kindsInput = [{\n name: \"someKind\",\n schema:[\n  { name: \"someField1\", type: STRING },\n  { name: \"someField2\", type: STRING }\n ]\n}, ...]\n\nconst newKinds = await AssistantAPIClient.createKinds(kindsInput)\n```\n\n\n#### updateKind = input =>\nUpdates a Kind based on an input object.\n\nUpdate Semantics: Only properties specified will be updated. If updating the schema, the entire schema must be specified as it will be replaced in its entirety.\n\nReturns a promise that resolves to the updated `Kind` object.\n\n```js\nconst updated = await AssistantAPIClient.updateKind(input)\n```\n\n#### deleteKind = input =>\nDeletes a Kind given a kind ID.\n\n```js\nconst deleted = await AssistantAPIClient.deleteKind(input)\n```\n\n#### getKindById = id =>\nReturns a promise that resolves to a Kind object given the specified kind ID.\n\nIn v3.2.2, any requested non-system kinds will be returned.\nIn v3.2.1, only kinds in the workspace or those of imported services will be returned.\n\n```js\nconst kind = await AssistantAPIClient.getKindById(id)\n```\n\n#### getKindsById = ids =>\nReturns a promise that resolves to an array of Kind objects given an array of kind IDs. Only kinds in the workspace or those of imported services will be returned.\n\n```js\nconst ids = [\"...\",\"...\",...]\nconst kind = await AssistantAPIClient.getKindsById(ids)\n```\n\n#### getAllReferencedKinds = input =>\nRecursively collects all kinds that are referenced in a kind's schema, starting\nwith a kind ID. For example if the ID of kind A is supplied as an input, and Kind `A` contains a field of type Kind `B`, and `B` contains a field of type Kind `C`,\nan array containing the kinds objects for `A`, `B`, `C` will be returned (as a promise).\n\n```js\nconst initialId = [\"...\"]\nconst kinds = await AssistantAPIClient.getAllReferencedKinds({\n          ids: initialId\n        })\n```\n\n\n### Inventory\n\nThe `InventoryChanged` object:\n```js\n{\n  kinds: {\n    adds: [DiffItem]\n    deletes: [DiffItem]\n    updates: [DiffItem]\n  }\n  functions:{\n    adds: [DiffItem]\n    deletes: [DiffItem]\n    updates: [DiffItem]\n  }\n  services: {\n    adds: [DiffItem]\n    deletes: [DiffItem]\n    updates: [DiffItem]\n  }\n}\n```\n\nThe `DiffItem` object:\n```js\n{\n  id: string,\n  name: string\n}\n```\n\n#### addInventoryChangedListener = async cb =>\nRegisters a callback function with the inventory changed event. When workspace inventory changes the callback function will be called with the InventoryChangedobject. Returns undefined.\n\n**Use-case note: an ‘update’ diff for inventory services is unlikely in general usage.\n\n```js\nconst inventoryCB = ({diff}) => {\n  if(diff.kinds) console.log('KINDS CHANGED',diff.kinds)\n  if(diff.functions) console.log('FUNCTIONS CHANGED', diff.functions)\n  if(diff.services) console.log('SERVICES CHANGED',diff.services)\n}\n\nAssistantAPIClient.addInventoryChangedListener(inventoryCB)\n```\n\nThis function exists on the Q-Assisant-Client only--only enableSelectionChangedNotification is used on the API side.\n\n#### removeInventoryChangedListener = async cb =>\nRemoves an inventory changed listener given the referenced callback. If no callback is specified, all listeners will be removed. Returns undefined.\n\n```js\nAssistantAPIClient.removeInventoryChangedListener(inventoryCB)\n```\n\nThis function exists on the Q-Assisant-Client only--only disableSelectionChangedNotification is used on the API side.\n\n#### moveKindsAndFunctions = (originId, targetId, kindIds, functionIds) =>\nMoves a collection of Kinds and Functions from the origin Workspace to the target Workspace.\n\n```js\n  await AssistantAPIClient.moveKindsAndFunctions(\n    originWorkspaceId,\n    targetId,\n    kindIds,\n    functionIds\n  );\n```\n\n### Locking Changed Event\n\nAn event is triggered when the locked state of the currently active Workspace or\nits Knowledge Graphs and Functions change.\n\nThe `LockingChanged` object:\n```js\n{\n  workspaces: [LockItem],\n  knowledgeGraphs: [LockItem],\n  functions: [LockItem]\n}\n```\n\nThe `LockItem` object:\n```js\n{\n  id: string\n  lockedBy: string\n}\n```\n\n#### addLockingChangedListener = cb =>\n\nRegisters a callback function with the locking changed event. When the currently\nactive Workspace or its Knowledge Graphs and Functions change the callback\nfunction will be called with the `LockingChanged` object. Returns undefined.\n\n```js\nconst lockingChangedCB = ({ locks }) => {\n  if(locks.workspace) console.log('WORKSPACES CHANGED', locks.workspace);\n  if(locks.knowledgeGraphs) console.log('KNOWLEDGE GRAPHS CHANGED', locks.knowledgeGraphs);\n  if(locks.functions) console.log('FUNCTIONS CHANGED', locks.functions);\n}\n\nAssistantAPIClient.addLockingChangedListener(lockingChangedCB);\n```\n\n#### removeLockingChangedListener = cb =>\n\nRemoves an locking changed listener given the referenced callback. If no\ncallback is specified, all listeners will be removed. Returns undefined.\n\n```js\nAssistantAPIClient.removeLockingChangedListener(lockingChangedCB)\n```\n\n## Troubleshooting Assistant Issues\n### Assistant root file has loaded, but not other content\nObserving in the browser's dev tools that some resources have loaded correctly (usually the root), but other's haven't (usually nested files or chunks), is indicative of a failure of Q Gateway to proxy due to not having a 'relative' path structure.\n\n### You are seeing post-robot `NO ACK` errors in the console.\nThese errors stem from a failed acknowledgement for a call either between the client and the API or vice-versa. Here, this means that the web app 'window' (the assistant) cannot communicate with, or access, the 'window.parent' (Maana K-Portal) object.\n\nCommonly, these will stem from the 'window' (the assistant) not being loaded or in a loadable state, which means the API will not receive an acknowledgement when it fires an event.\n\nImproper CORS configuration is also a common culprit (also verify if using docker or nginx that your proxying and networking is configured correctly to allow communication and to accout for CORS).","readmeFilename":"README.md","gitHead":"1edf512933a2443bd3800846a02b1c356ab6eae1","_id":"@io-maana/q-assistant-client@3.3.0-beta.13","_nodeVersion":"12.22.1","_npmVersion":"6.14.12","dist":{"integrity":"sha512-DyeOMwBLdI9dZUx+tGngWtbfQrvmFUTJY7kAA4ngxWhOYqJF+cRzygQoxi+X0z9PhHXjC8U6G26rsAoW8g7atA==","shasum":"83687a2cc96521b9dc176345620c7c7148984952","tarball":"https://registry.npmjs.org/@io-maana/q-assistant-client/-/q-assistant-client-3.3.0-beta.13.tgz","fileCount":83,"unpackedSize":355798,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJgecVOCRA9TVsSAnZWagAAGn0QAKHep1sy2AE1+LEpAmtG\nseOSsHlCzCHk9RYLjSJKhnkxxjdRrU5dyUx4lITKrW2dHglb5LHG2no1J5fP\nmSvnArQM5qosxUlOleJYd/YRF5ie1j5tisk4kc+79AqVU3FhqyXuTwr4Afey\nntvJlqIrWFasukXm59QJTMI6aGvRWXBuWj/lZoAK/wAYK43SlENA7hWZyYb9\ndZ+l+qNKhz8wGzvyRSCA0bLrDqq9jWJF+GfKZ5E7jxIGzqBP2FVNN5kXKSj7\nHxtD2HOpmCk6Dm+iTjEy4OvNgnEOR62Ax/HrqLT2OEPrcXgmzx12/VPDS51b\nOSih+Ug7+Gz9Hf6KY7FmNS3t6tPn52Bvk7XxHFplU2FT+QdM6WDRvOF9M4wI\nykwaoHWqm3TJy/WM2/G1nnaurj6Zg/eTk3/C0nZ/Ok4ZMYiR72UAxGyrKWHh\nYKgeKBHnrd4ZC9UNrn89cc/LFKScsdzMcZo674ud8+1pLlemDFj2PVv2SMef\nsXEtW374Z3XjpfqdlTaKi+fJfyr+U6URPJ1pS4pB98g41xqRXrPZj1eZYgQx\n1QZpIHLhuk6pH70rqpmIflzf5Y0XvLQVO79jbHyPR6Ps6zkdiHbUBW8qJq/W\nZwq5vWtUAW+Y2XTDkiKvXzDcrBuI0Pp8f6XNQAnVUqTJz6xFYyWxLAmsruZZ\nAtqe\r\n=g3qQ\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIQDOidQ17acm2a/meyjeREBGIGhiUHqq8hkU4Ij7akODbgIgBK4tcmiaXEygVjE3zshLyAMh7SMv/WnLmLFJSrKluQI="}]},"_npmUser":{"name":"teamcitymaana","email":"teamcity@maana.io"},"directories":{},"maintainers":[{"name":"witt3rd","email":"witt3rd@witt3rd.com"},{"name":"bzvetey","email":"bzvestey@gmail.com"},{"name":"abatyuk","email":"andrey@maana.io"},{"name":"rpovey","email":"rob@maana.io"},{"name":"teamcitymaana","email":"teamcity@maana.io"},{"name":"dlsmaana","email":"dlewissandy@maana.io"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/q-assistant-client_3.3.0-beta.13_1618593101838_0.19799606776553746"},"_hasShrinkwrap":false},"3.3.0-beta.15":{"name":"@io-maana/q-assistant-client","version":"3.3.0-beta.15","description":"JavaScript package to streamline communication between an assistant and the Maana Q Assistant API.","main":"build/index.js","types":"build/index.d.ts","exports":{"./":"./build/"},"scripts":{"build":"npm run build:ts && npm run build:doc","build:ts":"tsc --build tsconfig.json","build:doc":"typedoc","prepack":"npm run build","test":"echo \"Error: no test specified\" && exit 1","format":"prettier --write \"src/**/*.js\""},"repository":{"type":"git","url":"git+https://github.com/maana-io/q-assistant-client.git"},"keywords":["Maana","Q"],"author":{"name":"Logan Gore @ Maana.io"},"license":"MIT","bugs":{"url":"https://github.com/maana-io/q-assistant-client/issues"},"homepage":"https://github.com/maana-io/q-assistant-client#readme","dependencies":{"core-js":"3.6.4","post-robot":"10.0.29"},"devDependencies":{"@types/node":"^14.14.2","@types/post-robot":"^10.0.0","prettier":"2.0.5","typedoc":"^0.19.2","typedoc-plugin-markdown":"^3.0.11","typescript":"^3.9.5"},"readme":"# q-assistant-client\nA lightweight JavaScript client for Maana-Q Assistant developers that wraps post-message communication between an embedded Maana-Q assistant and the Maana-Q UI.\n\nYou can find the [API Documentation here](docs/README.md).\n\n## Abstract\nThe Q-Assistant-Client is intented to be used in a web application being leveraged as a Maana Q assistant (embedded as an iframe).\nThis assistant client will facilitate communication between the assistant and the parent frame.\nThe client provides a rich, asynchronous experience over what would otherwise be 'fire-and-forget'-style messaging\nvia post-post message communication.\n\n## Requirements and Assumptions\n\n### Post-Robot Library\nThe Maana Knowledge Portal (KPortal) uses the kraken/post-robot library [kraken/post-robot](https://github.com/krakenjs/post-robot) to enrich the communication with the assistant. Post-robot allows for asynchronous, promise-based request/response style behavior between the assistant and the assistant API.\n\nThe API requires that the client use the post-robot library. This assistant-client library is the easiest way to achieve this, and also adds a fair amount of 'sugar' to the process to improve developer productivity. Developers could, however, use post-robot directly in their own client implementation.\n\n### Maana-Gateway Proxy Requirements\nThe Maana-Gateway service requires relative paths (paths relative to the root) in the assistant web application in order to proxy the application and its content. For create-react-apps, for instance, this means setting \"homepage\" to \".\" in the package.json file.\n\n## Singleton Instance\nThe client is exported as a singleton to avoid duplicate registration on event listeners.\nYou can import the instance like this:\n\n```js\nimport AssistantAPIClient from '@io-maana/q-assistant-client';\n```\n\nFunction calls can be made against the client instance like any other javascript object. They are all async.\n\n```js\nconst workspace = await AssistantAPIClient.getWorkspace();\nconsole.log(\"Workspace:\", workspace)\n```\n\n## Dependencies\nPost-Robot\nhttps://github.com/krakenjs/post-robot\n\nPost-robot is used to provide a richer communication layer atop post-message.\n\n## Versioning\nThe Maana Q Assistant Client does not follow semantic versioning. Its versions\ntrack the releases of the Maana Q platform.\n\n## Examples\n@TODO Logan\n\n\n## Changes in v3.2.2\nImprovements in v3.2.2\n- Assistant State Management: WORKING, IDLE\n- Background Messaging/Eventing\n- Render Modes: BACKGROUND, DISPLAY\n- Expansion of Workspace object capabilities\n- Error Reporting\n- Repair Event\n- Plural versions of calls such as updateKind(s) to improve performance and developer experience.\n- InventoryChanged diffing is fully granular in v3.2.2--limitations\nin v3.2.1 only fired the Function diff for changes in Function name.\n\n### Deprecation\nThe following surface area IS removed from the\nclient in v3.2.2, and IS deprecated in the API:\n- AssistantAPIClient.enableSelectionChangedNotification\n- AssistantAPIClient.disableSelectionChangedNotification\n- AssistantAPIClient.enableInventoryChangedNotification\n- AssistantAPIClient.disableInventoryChangedNotification\n\nThe following surface area WILL BE removed from\nthe client in v3.2.4, and WILL BE deprecated in the API:\n- AssistantAPIClient.updateFunction (expected move to Workspace object)\n- AssistantAPIClient.updateKind (expected move to Workspace object)\n- AssistantAPIClient.deleteKind (expected move to Workspace object)\n- AssistantAPIClient.deleteFunction (expected move to Workspace object)\n\n## API Documentation\nMore information in the [API File](./API.md)\n\n### Assistant Render Mode\nAn assistant's render mode refers to whether it is being displayed in a visible manner to the user. As of v3.2.2, assistants are not closed when they are out of view.\nAll assistants will be loaded and kept in `BACKGROUND` render mode until they are\nplaced in the assistant panel, at which point the `DISPLAY` render mode event will be fired.\n\nNote: Assistants will receive all notifications/events while in BACKGROUND mode.\n\nDesign Consideration: It will be up to the developer to determine how state and resource use will be managed while an assistant is operating between BACKGROUND and DISPLAY modes.\n\n#### addRenderModeChangedListener = (cb) =>\nA listener to receive push events as to the assitant's render mode being changed.\n\n```js\nfunction handleRenderModeChanged(renderMode){\n  if (renderMode === 'DISPLAY'){\n    // Assistant is visible\n  } else {\n    // Assistant is not visible and running in background.\n  }\n}\n\nAssistantAPIClient.addRenderModeChangedListener(handleRenderModeChanged)\n\n```\n\n#### removeRenderModeChangedListener = (cb) =>\nRemoves the renderModeChanged listener by reference, or if no callback function reference is provided, it removes all listeners.\n\n#### getRenderMode = () =>\nReturns the current assistant render mode.\n\n```js\nconst renderMode = await AssistantAPIClient.getRenderMode()\n\nif (renderMode === 'DISPLAY'){\n  // Assistant is visible\n} else {\n  // Assistant is not visible and running in background.\n}\n\n```\n\n### Repair\nAssistants may get into situations where they are either out of sync with the Maana Q UI, or in a failure state. Assistants should be able to recover from these states.\n\nThe repair event functionality added in v3.2.2 is designed to notify the assistant that it must repair itself. This could mean a resync with its resources on the workspace or externally or, for some assistants, nothing at all.\n\nWhen is repair triggered?\nEither manually by a user clicking 'repair workspace' under the\nassistant inventory panel, or upon a workspace clone event. An assistant will be expected to handle either scenario.\n\nPerformance Consideration:\nFor some assistants, repair might involve 'introspecting'\nand processing the current workspace or Q system resources. This could be very resource intensive. Make sure you review this API guide to have an idea of what tools are\navailable to get the best results. It's always a good idea to check performance of repair on a large workspace and ensure necessary optimizations have been made.\n\nDesign Consideration:\nMake your workflows modular enough to be reused between repair and normal usage if possible.\n\n#### addRepairListener (cb) =>\n```js\n\nAssistantAPIClient.addRepairListener(()=>{\n  // Self-heal\n})\n\n```\n\nRecommended Usage: A repair process should be wrapped in the try/catch/finally flow shown in the `setAssistantState` API call to provide the user assistant-state and error updates as well as pause `inventoryChanged` notifications during repair (if the assistant has subscribed).\n\n#### removeRepairListener = (cb) =>\nRemoves the repair listener by reference, or if no callback function reference is provided, it removes all listeners.\n\n### User-facing Error Handling\n\n#### reportError (error) =>\nReports an error to the UI to be displayed in the assistant's error log in the\ninventory panel. This call is not disruptive and designed to operated independently of other assistant operations, such as state management. See `setAssistantState` in the next section.\n\nRecommended usage: use this functionality where it would futher the user experience\nto show the user an error and it's cause. Do not use this where things will be retried,\ncleaned up automatically, or are not relevant to the user.\n\n```js\ntry{\n  // Do work\n} catch(e) {\n  AssistantAPIClient.reportError(e)\n}\n```\n\n### State management\n\n#### clearState = () =>\nThis will remove all callbacks from all listeners.\n\n```js\nawait AssistantAPIClient.clearState()\n```\n\n#### setAssistantState = (state) =>\nThis sets the current state of the assistant using the\n`AssistantState` enum. Setting a state of `WORKING` will\ncreate the 'working' status spinner in the Assistant\nInventory Panel in the Maana Q UI. Conversely, setting an `IDLE` state will\nremove the spinner. This adds to user experience by informing users of the\nstatus of operations.\n\n```js\nimport {\n  default as AssistantAPIClient,\n  AssistantState\n} from '@io-maana/q-assistant-client'\n\n...\n\nAssistantAPIClient.setAssistantState(AssistantState.WORKING)\n\n...\n\nAssistantAPIClient.setAssistantState(AssistantState.IDLE)\n\n```\nUI User Prompt: If the assistant is in a `WORKING` state, the Maana Q UI will\nwarn the user before leaving the workspace.\n\nNOTE: while an assistant is in a working state, it will\nnot receive `inventoryChanged` events--an aggregated inventory diff\nwill be sent once the assistant is set back to `IDLE`.\n\nRecommended usage: Control states at a high level using try/catch/finally\nflow incorporating the `reportError` API call.\n\n```js\ntry{\n  AssistantAPIClient.setAssistantState(AssistantState.WORKING)\n  // Do work, await high-level tasks, etc.\n} catch(e) {\n  AssistantAPIClient.reportError(e)\n} finally{\n  AssistantAPIClient.setAssistantState(AssistantState.IDLE)\n}\n```\n\n#### AssistantState (enum)\nContains the valid assistant states: `IDLE` or `WORKING`.\n\nMust be imported in addition to the AssistantAPIClient:\n\n```js\nimport {\n  default as AssistantAPIClient,\n  AssistantState\n} from '@io-maana/q-assistant-client'\n```\n\n\n### User Info\nThe `UserInfo` object:\n```js\n{\n email: string,\n name: string\n}\n```\n\n#### getUserInfo = () =>\nReturns a Userinfo object pertaining to the logged in user.\n\n```js\nconst userInfo = await AssistantAPIClient.getUserInfo()\n```\n### Selection\nThe `Selection` object:\n```js\n{\n  kindId: string\n  kindName: string\n  id: string\n}\n```\n\n#### getCurrentSelection = () =>\nReturns an Array of `Selection` objects:\n\n```js\nconst {selection} = await AssistantAPIClient.getCurrentSelection();\n```\n\n#### addSelectionChangedListener = async cb =>\nAdds a callback function to be executed upon a valid workspace selection change.\n\nCallback value is an array of Selection objects:\n\n```js\n// Create the selection callback.\nconst selectionCB = ({selection})=>{\n  console.log('Workspace selection has changed.')\n  selection.forEach(i=>{\n    console.log('Kind: ',i.kindName)\n    console.log('Instance Id:',i.id)\n    console.log('Kind Id:',i.kindId)\n  })\n}\n\n// Add the listener.\nAssistantAPIClient.addSelectionChangedListener(selectionCB);\n```\n\nThis function only exists on the Q-Assistant-Client--only enableSelectionChangedNotification is called on the API.\n\n#### removeSelectionChangedListener = async cb =>\nThis will have to be called on a 1:1 basis with addSelectionChangedListener calls if supplying a callback.\n\n```js\nAssistantAPIClient.removeSelectionChangedListener(selectionCB)\n```\n\n**If NOT supplying a callback to this call, all selection changed listeners will be removed.\n\n```js\nAssistantAPIClient.removeSelectionChangedListener()\n```\n\nThis function only exists on the Q-Assistant-Client--only disableSelectionChangedNotification is called on the API.\n\n\n### Services\nThe `Service` object:\n```js\n{\n   id: string,\n   name: string\n   endpointUrl: string,\n   getKinds: () => // Returns [] of Kinds objects\n   getFunctions: () => // Returns [] of Function objects\n}\n```\n\n#### getServiceById = id =>\nThis will return a service that exists within the scope of the workspace.\n** Assistant services will return null. Services outside the scope of the workspace will cause an error to be returned as 'Unable to load a Service from outside of the workspace.'\n\n```js\nconst svc = await AssistantAPIClient.getServiceById(id)\n```\n\n#### createService = id =>\nCreates a service in Q.\n\nNote: This will create the service, but does NOT import it into the workspace.\nYou will need to use `importService` on the Workspace object to import it.\nReturns a promise that resolves\n\n```js\n    const service = {\n      id: ...,\n      name: ...,\n      endpointUrl: ...,\n      serviceType: ...\n    }\n\n    await AssistantAPIClient.createService(service)\n```\n\n#### deleteService = id =>\nDeletes a service from Q.\n\n```js\n    await AssistantAPIClient.deleteService(id)\n```\n\n#### refreshServiceSchema = id =>\nRefreshes a service by fetching its schema. This will also\nreload the service inventory in the currently visible workspace.\n\n```js\nawait AssistantAPIClient.refreshServiceSchema(\"id\")\n```\n\n#### reloadService = id =>\nReloads a service in the inventory in the currently visible workspace.\n\n```js\nawait AssistantAPIClient.reloadService(\"id\")\n```\n\n### Workspace\n\n#### getWorkspace = () =>\nReturns a Workspace object representing the workspace.\n\n```js\nconst ws = await AssistantAPIClient.getWorkspace(id)\n```\n\nNote: The `id` parameter is optional. If it is not supplied, the query\nwill return the current/visible workspace.\n\nThe `Workspace` object:\n\n```js\n\n{\n    id: string,\n    name: string,\n    endpointUrl: string,\n    workspaceServiceId: string,\n    modelServiceId: string,\n    logicServiceId: string,\n\n    //\n    // Locking information\n    //\n    async lockedBy() {\n      // Returns the e-mail address of the user who locked the Workspace, or\n      // null if the Workspace is not currently locked.\n    }\n    async canEdit() {\n      // Returns `true` when the Workspace is not locked, or the current user\n      // owns the lock.\n      // Returns 'false' when the Workspace is locked by a different user.\n    }\n    async setLocked(isLocked) {\n      // Takes a boolean or undefined for `isLocked`.\n      //  `true` locks the Workspace as the current User.\n      //  `false` unlocks the Workspace\n      //  `undefined` causes it to toggle the current locked state.\n      // Returns a Promise that will resolve or reject when the task is done.\n    }\n\n    //\n    // Knowledge Graphs\n    //\n    getActiveGraph: async () => {\n      // Returns the active Graph object.\n      // Returns null if active graph is not of type 'Knowledge Graph', or if an\n      // active graph is deleted, thereby setting active graph to null.\n    },\n    getKnowledgeGraphs: async () => {\n      // Returns [Graph]\n    },\n    // TODO: define input\n    createKnowledgeGraph: input =>\n    // TODO: define input\n    createKnowledgeGraphs: input =>\n\n    //\n    // Services\n    //\n    getImportedServices: async () => {\n      // Returns an array of Service objects that have\n      // been imported into the workspace.\n      // No assistant services will be returned.\n    },\n    getImportedAssistants: async () => {\n      // Returns a list of imported assistants.\n    },\n    importService: serviceId => {\n      // Imports a service by it's ID.\n    },\n    importServices: serviceIds => {\n      // Imports services by their IDs.\n    },\n    removeServices: serviceIds => {\n      // Removes a list of services from the workspace.\n    },\n    removeService: serviceId => {\n      // Removes a service from the workspace.\n    },\n\n    //\n    // Functions\n    //\n    getFunctions: async () => {\n      // Returns an array of functions in the workspace (includes boilerplate).\n    },\n    createFunction: funcData => {\n      // Creates a function and adds it to the graph.\n    }\n    createFunctions: funcData =>{\n      // Creates several functions and adds them to the graph.\n    }\n    updateFunction: funcData => {\n      // Updates a function.\n    },\n    updateFunctions: funcData =>{\n      // Updates functions based on input array.\n    },\n    deleteFunction: funcId => {\n      // Deletes a function by its ID.\n    },\n    getFunctionGraph: funcId => {\n      // Returns a function graph by its ID.\n    }\n\n    //\n    // Kinds\n    //\n    getKinds: async () => {\n      // Returns an array of functions in the workspace (includes boilerplate).\n    },\n    createKind: kindData => {\n      // Currently same input as AssistantAPIClient call.\n    },\n    createKinds: kindData => {\n      // Currently same input as AssistantAPIClient call.\n    },\n    updateKind: kindData => {\n      // Currently same input as AssistantAPIClient call.\n    },\n    updateKinds: kindData => {\n      // Currently same input as AssistantAPIClient call.\n    },\n    deleteKind: kindId => {\n      // Currently same input as AssistantAPIClient call.\n    }\n    // Event Triggers\n    triggerRepairEvent: () => {\n      // Triggers the repair event on a workspace.\n    }\n  };\n}\n```\n\n\n### Graphs\nThe `Graph` object:\n```js\n{\n  id: string,\n  name: string,\n  offsetX: Number,\n  offsetY: Number,\n  zoom: Number,\n  getNodes: async () => {\n      // Returns [Node]\n  },\n\n  addNode: async (type, instance, changeSelection) => {\n      // Returns Node\n  },\n  removeNode: async id => {\n      // Should return nothing or error.\n      // Currently returning [] in all cases.\n  },\n  updateNodeLayout: async (nodeId, { x, y, collapsed }) => {\n  },\n  updateGraphLayout: async ({ offsetX, offsetY, zoom }) => {\n  }\n\n  //\n  // Locking information\n  //\n  async lockedBy() {\n    // Returns the e-mail address of the user who locked the Graph, or null if\n    // the Graph is not currently locked.\n  }\n  async canEdit() {\n    // Returns `true` when the Graph is not locked, or the current user owns the\n    // lock.\n    // Returns 'false' when the Graph is locked by a different user.\n  }\n  async setLocked(isLocked) {\n    // Takes a boolean or undefined for `isLocked`.\n    //  `true` locks the Graph as the current User.\n    //  `false` unlocks the Graph\n    //  `undefined` causes it to toggle the current locked state.\n    // Returns a Promise that will resolve or reject when the task is done.\n  }\n}\n```\n\n#### Getting a graph object:\nGraph objects are obtained through an instance of a Workspace\n\n```js\nconst ag = await ws.getActiveGraph()\n```\n\nor\n\n```js\nconst kgs = await ws.getKnowledgeGraphs()\n```\n\n#### Manipulating Graphs\n\n**Only the active graph may be manipulated.\n\nAll graph manipulations should be ‘visually’ verifiable on the graph itself, i.e., adds/removes/positioning, should all be reflected on the graph itself.\n\nThe `Node` object:\n```js\n{\nid: string\nx: number\ny: number\ncollapsed: boolean\nknowledgeGraphNode {\n  id: string\n  innerKind: Kind\n  innerFunction: Function\n}\n}\n```\n\n#### addNode(type, instance, changeSelection) =>\n\nTakes type (“Function” or “Kind”), instance (the Function or Kind object), and optionally a boolean to indicate whether the selection should be changed to this new node.\n\nReturns the newly created Node object.\n\n```js\nconst node = await ag.addNode('Kind',kind)\n```\n\n#### removeNode(id) =>\n\nTakes the id of Node to be deleted. Returns either undefined or an error.\n\n```js\nawait ag.removeNode(node.id)\n```\n\n#### getNodes() =>\nReturns an array of Node objects from the graph.\n\n```js\nconst nodes = await ag.getNodes()\n```\n\n#### updateNodeLayout: async (nodeId, { x, y, collapsed})=>\nUpdates a Node layout given a node ID and node coordinates (`x` and/or `y`) or a `collapsed` value. x/y values must be a number, and collapsed must be a boolean. Whatever is not specified will remain current.\n\n```js\nag.updateNodeLayout(id,{x:100,y:100,collapsed:true})\n```\n\n#### updateGraphLayout: async ({ offsetX, offsetY, zoom})=>\nUpdates a Graph layout given numerical values for x/y offsets and the zoom.\n\n```js\nag.updateGraphLayout({offsetX:50, offsetY:50, zoom: 70})\n```\n\n### Functions\n\nThe `Function` object:\n```js\n{\n    id: string\n    name: string\n    service {\n      id: string\n      name: string\n    }\n    arguments {\n      id: string\n      name: string\n      type: string\n      modifiers: Array[string]\n      typeKindId:: string\n      kind {\n        id: string\n        name: string\n      }\n    }\n    implementation {\n      id: string\n      entrypoint {\n        id: string\n      }\n      operations {\n        id: string\n        type: string\n        function {\n          id: string\n          name: string\n        }\n        argumentValues {\n          id: string\n          argument {\n            id: string\n          }\n          operation {\n            id: string\n          }\n          argumentRef: string\n        }\n      }\n    }\n    isGenerated: boolean\n    functionType: string\n    graphqlOperationType: string\n    outputType: string\n    outputKindId: string\n    outputModifiers: Array[string]\n    kind {\n      id: string\n      name: string\n    }\n\n    //\n    // Locking information\n    //\n    async lockedBy() {\n      // Returns the e-mail address of the user who locked the Function, or null\n      // if the Function is not currently locked.\n    }\n    async canEdit() {\n      // Returns `true` when the Function is not locked, or the current user\n      // owns the lock.\n      // Returns 'false' when the Function is locked by a different user.\n    }\n    async setLocked(isLocked) {\n      // Takes a boolean or undefined for `isLocked`.\n      //  `true` locks the Function as the current User.\n      //  `false` unlocks the Function\n      //  `undefined` causes it to toggle the current locked state.\n      // Returns a Promise that will resolve or reject when the task is done.\n    }\n}\n```\n\n`FunctionExecutionResult` object:\n```js\n{\n  id: string,\n  result: JSON\n}\n```\n\n#### executeFunction = ( {id, variables, resolve} ) =>\nExecutes a function based on its id, with optional inputs for variables and a resolve string (this specifies the fields to be returned, which must be valid based on the result).\n\nReturns : JSON matching shape of result , unless no sub-selection of fields is required in the execution.\n\nThis following piece of code will execute a Function given a function ID, and pass in variables for ‘example’, requesting back id and name fields.\n\n```js\nconst res = await AssistantAPIClient.executeFunction({functionId: func.id, variables: {\"variableName\": \"variableValue\"}, resolve: \"{ id name }\");\n```\n\n#### createFunction = input =>\nCreates a function based on the input provided.\n\nReturns: the created Function object.\n\n**Using create function will only place the function in the workspace’s inventory--it will not place the function as a node on the Graph. In order to do this, you must pass the created function into the addNode function on the active Graph, making sure to specify ‘Function' as the type.\n\n```js\nconst createFunctionInput = {\n  name:\"yourName\",\n  arguments:[],\n  outputType: \"STRING\",\n  graphqlOperationType:\"QUERY\",\n  functionType: \"CKG\"\n}\n\nconst createdFunction = await AssistantAPIClient.createFunction(createFunctionInput)\n```\n\n#### updateFunction = input =>\nInput is the same for creating a function. It’s important to note that the arguments property will be replaced in it’s entirety with whatever is provided (if a value is provided.\n\nReturns the updated `Function` object.\n\n```js\nconst updatedFunction = await AssistantAPIClient.updateFunction(input);\n```\n\n#### deleteFunction = input =>\nInput is the id of the Function to be deleted. Returns the deleted function as a promise.\n\n```js\nconst deletedFunction = await AssistantAPIClient.deleteFunction('id...');\n```\n\n#### getFunctionById = id =>\nReturns a Function as a promise based on the ID provided.\n\n```js\nconst func = await AssistantAPIClient.getFunctionById('id...');\n```\n\n#### addFunctionExecutionListener = async (id, cb) =>\nAssociates a callback function with the execution of a particular Function. When the Function matching the id parameter is executed, its FunctionExecutionResult object passed to the callback. Returns undefined.\n\nExample function execution callback and listener registration:\n\n```js\nfunction exampleFunctionCB (result){\n  console.log(`Function executed with result:`, result)\n}\n\nAssistantAPIClient.addFunctionExecutionListener('id...', exampleFunctionCB)\n```\n\n#### removeFunctionExecutionListener = async (id, cb) =>\nRemoves a Function execution listener based on the function ID and a reference to the callback function. If no callback is supplied, all listeners associated with the Function ID will be removed. Returns undefined.\n\n```js\nAssistantAPIClient.removeFunctionExecutionListener('id..', exampleFunctionCB)\n```\n\n### Kinds\nThe `Kind` object:\n```js\n{\n    id: string\n    name: string\n    service: {\n      id\n      name\n    }\n    isGenerated: boolean\n    schema {\n      id: string\n      name: string\n      type: string\n      typeKindId: string\n      modifiers: Array[string]\n      kind {\n        id: string\n        name: string\n      }\n    }\n}\n```\n\n#### createKind = input =>\nCreates a Kind based on an input object. Returns a promise that resolves to the created Kind object.\n\n```js\nconst kindInput = {\n name: \"someKind\",\n schema:[\n  { name: \"someField1\", type: STRING },\n  { name: \"someField2\", type: STRING }\n ]\n}\n\nconst newKind = await AssistantAPIClient.createKind(kindInput)\n```\n\n#### createKinds = input =>\nA plural version of `createKind` accepting an array of input objects.\nReturns a promise that resolves to an array of created Kind objects.\n\n```js\nconst kindsInput = [{\n name: \"someKind\",\n schema:[\n  { name: \"someField1\", type: STRING },\n  { name: \"someField2\", type: STRING }\n ]\n}, ...]\n\nconst newKinds = await AssistantAPIClient.createKinds(kindsInput)\n```\n\n\n#### updateKind = input =>\nUpdates a Kind based on an input object.\n\nUpdate Semantics: Only properties specified will be updated. If updating the schema, the entire schema must be specified as it will be replaced in its entirety.\n\nReturns a promise that resolves to the updated `Kind` object.\n\n```js\nconst updated = await AssistantAPIClient.updateKind(input)\n```\n\n#### deleteKind = input =>\nDeletes a Kind given a kind ID.\n\n```js\nconst deleted = await AssistantAPIClient.deleteKind(input)\n```\n\n#### getKindById = id =>\nReturns a promise that resolves to a Kind object given the specified kind ID.\n\nIn v3.2.2, any requested non-system kinds will be returned.\nIn v3.2.1, only kinds in the workspace or those of imported services will be returned.\n\n```js\nconst kind = await AssistantAPIClient.getKindById(id)\n```\n\n#### getKindsById = ids =>\nReturns a promise that resolves to an array of Kind objects given an array of kind IDs. Only kinds in the workspace or those of imported services will be returned.\n\n```js\nconst ids = [\"...\",\"...\",...]\nconst kind = await AssistantAPIClient.getKindsById(ids)\n```\n\n#### getAllReferencedKinds = input =>\nRecursively collects all kinds that are referenced in a kind's schema, starting\nwith a kind ID. For example if the ID of kind A is supplied as an input, and Kind `A` contains a field of type Kind `B`, and `B` contains a field of type Kind `C`,\nan array containing the kinds objects for `A`, `B`, `C` will be returned (as a promise).\n\n```js\nconst initialId = [\"...\"]\nconst kinds = await AssistantAPIClient.getAllReferencedKinds({\n          ids: initialId\n        })\n```\n\n\n### Inventory\n\nThe `InventoryChanged` object:\n```js\n{\n  kinds: {\n    adds: [DiffItem]\n    deletes: [DiffItem]\n    updates: [DiffItem]\n  }\n  functions:{\n    adds: [DiffItem]\n    deletes: [DiffItem]\n    updates: [DiffItem]\n  }\n  services: {\n    adds: [DiffItem]\n    deletes: [DiffItem]\n    updates: [DiffItem]\n  }\n}\n```\n\nThe `DiffItem` object:\n```js\n{\n  id: string,\n  name: string\n}\n```\n\n#### addInventoryChangedListener = async cb =>\nRegisters a callback function with the inventory changed event. When workspace inventory changes the callback function will be called with the InventoryChangedobject. Returns undefined.\n\n**Use-case note: an ‘update’ diff for inventory services is unlikely in general usage.\n\n```js\nconst inventoryCB = ({diff}) => {\n  if(diff.kinds) console.log('KINDS CHANGED',diff.kinds)\n  if(diff.functions) console.log('FUNCTIONS CHANGED', diff.functions)\n  if(diff.services) console.log('SERVICES CHANGED',diff.services)\n}\n\nAssistantAPIClient.addInventoryChangedListener(inventoryCB)\n```\n\nThis function exists on the Q-Assisant-Client only--only enableSelectionChangedNotification is used on the API side.\n\n#### removeInventoryChangedListener = async cb =>\nRemoves an inventory changed listener given the referenced callback. If no callback is specified, all listeners will be removed. Returns undefined.\n\n```js\nAssistantAPIClient.removeInventoryChangedListener(inventoryCB)\n```\n\nThis function exists on the Q-Assisant-Client only--only disableSelectionChangedNotification is used on the API side.\n\n#### moveKindsAndFunctions = (originId, targetId, kindIds, functionIds) =>\nMoves a collection of Kinds and Functions from the origin Workspace to the target Workspace.\n\n```js\n  await AssistantAPIClient.moveKindsAndFunctions(\n    originWorkspaceId,\n    targetId,\n    kindIds,\n    functionIds\n  );\n```\n\n### Locking Changed Event\n\nAn event is triggered when the locked state of the currently active Workspace or\nits Knowledge Graphs and Functions change.\n\nThe `LockingChanged` object:\n```js\n{\n  workspaces: [LockItem],\n  knowledgeGraphs: [LockItem],\n  functions: [LockItem]\n}\n```\n\nThe `LockItem` object:\n```js\n{\n  id: string\n  lockedBy: string\n}\n```\n\n#### addLockingChangedListener = cb =>\n\nRegisters a callback function with the locking changed event. When the currently\nactive Workspace or its Knowledge Graphs and Functions change the callback\nfunction will be called with the `LockingChanged` object. Returns undefined.\n\n```js\nconst lockingChangedCB = ({ locks }) => {\n  if(locks.workspace) console.log('WORKSPACES CHANGED', locks.workspace);\n  if(locks.knowledgeGraphs) console.log('KNOWLEDGE GRAPHS CHANGED', locks.knowledgeGraphs);\n  if(locks.functions) console.log('FUNCTIONS CHANGED', locks.functions);\n}\n\nAssistantAPIClient.addLockingChangedListener(lockingChangedCB);\n```\n\n#### removeLockingChangedListener = cb =>\n\nRemoves an locking changed listener given the referenced callback. If no\ncallback is specified, all listeners will be removed. Returns undefined.\n\n```js\nAssistantAPIClient.removeLockingChangedListener(lockingChangedCB)\n```\n\n## Troubleshooting Assistant Issues\n### Assistant root file has loaded, but not other content\nObserving in the browser's dev tools that some resources have loaded correctly (usually the root), but other's haven't (usually nested files or chunks), is indicative of a failure of Q Gateway to proxy due to not having a 'relative' path structure.\n\n### You are seeing post-robot `NO ACK` errors in the console.\nThese errors stem from a failed acknowledgement for a call either between the client and the API or vice-versa. Here, this means that the web app 'window' (the assistant) cannot communicate with, or access, the 'window.parent' (Maana K-Portal) object.\n\nCommonly, these will stem from the 'window' (the assistant) not being loaded or in a loadable state, which means the API will not receive an acknowledgement when it fires an event.\n\nImproper CORS configuration is also a common culprit (also verify if using docker or nginx that your proxying and networking is configured correctly to allow communication and to accout for CORS).","readmeFilename":"README.md","gitHead":"705da49e512681716cc029d9f37b688d7634ba66","_id":"@io-maana/q-assistant-client@3.3.0-beta.15","_nodeVersion":"12.22.1","_npmVersion":"6.14.12","dist":{"integrity":"sha512-Vu/yZSEfPPYcml9lOEdVT8Ow5t8QFR2XMeiWjUYHvJAf7yMVBPGUuC6oWUxynZgGH6Yc70DTDeofWDyAkAIVTg==","shasum":"03f874142508936f15149bc1e629d36c4ef40287","tarball":"https://registry.npmjs.org/@io-maana/q-assistant-client/-/q-assistant-client-3.3.0-beta.15.tgz","fileCount":84,"unpackedSize":361128,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJggwJGCRA9TVsSAnZWagAA5lEP/3au3pyX8CvxQhGn0jkc\n5fqSwKozZNTI4ATe1O0nuS6Yn8MVae5NZBrfpcGlVBQwcj5RimIYlY2Xuzhf\nh3eh4rbUb82Zopc4Ga2311/t7vLM2NMjrGP0QPBb70EOWXMApYmDNTC7rOhO\nzdrsKoIwqbgiPozJ9bPX/jp52BcZb8U8UCxjPPYN5f39ENqZw/Y/vZbZDofW\nepIMwy0ecerlUgfM0X0q47Xnrwlt/N+AYvuGCS2igJ6ovR/jLEOf/cbDteQi\nmKnvIs7jumykXXUukiunHhCKpHl3En/uSBni3wc/crAWNCOPj0RQu/mXMiEj\nPDoCFU92Y5sk8u8nV1MCsnUIKUtcuOz1y9GDLgXAxegqIzpDBOorvfskwoiS\ni4rkkLGWiZawnacSGnew1mkWqshPo20u2ycb/TtgjR6B95CZNzBortixhRnW\nEKSiPofSHiLOpghUHqBYjJFsxzYrcQzXTEAnTWBwmqZias9MnkZSJbsrTc1/\nS0T4RQsml4AT7FiAsMZZ4mhoLDv+JzuyCcbaJreCMSrAwAIGOVcuYTDbIeM5\nmrf69yceNGEU+h2nOgV0mDblZEUMx/POinSo6h9MeWi8cDBneNeoD/NfQdnD\n7gG1H4jrDdVYb+ICF6zV95PyxzSN+lYbPs383cfvkpX3MYlBEFvKpAznUdjF\nUMe9\r\n=Oq7t\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEQCIDJPitX7TlJg+nUqyTBhC5M4J4lF8X+W0uab+ylxhLl3AiAUIcvEkenwtSvk6KAGVKrA/1w6t4xRNJSOdoDQe3RT1g=="}]},"_npmUser":{"name":"teamcitymaana","email":"teamcity@maana.io"},"directories":{},"maintainers":[{"name":"witt3rd","email":"witt3rd@witt3rd.com"},{"name":"bzvetey","email":"bzvestey@gmail.com"},{"name":"abatyuk","email":"andrey@maana.io"},{"name":"rpovey","email":"rob@maana.io"},{"name":"teamcitymaana","email":"teamcity@maana.io"},{"name":"dlsmaana","email":"dlewissandy@maana.io"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/q-assistant-client_3.3.0-beta.15_1619198534246_0.14959972022584167"},"_hasShrinkwrap":false},"3.3.0-beta.16":{"name":"@io-maana/q-assistant-client","version":"3.3.0-beta.16","description":"JavaScript package to streamline communication between an assistant and the Maana Q Assistant API.","main":"build/index.js","types":"build/index.d.ts","exports":{"./":"./build/"},"scripts":{"build":"npm run build:ts && npm run build:doc","build:ts":"tsc --build tsconfig.json","build:doc":"typedoc","prepack":"npm run build","test":"echo \"Error: no test specified\" && exit 1","format":"prettier --write \"src/**/*.js\""},"repository":{"type":"git","url":"git+https://github.com/maana-io/q-assistant-client.git"},"keywords":["Maana","Q"],"author":{"name":"Logan Gore @ Maana.io"},"license":"MIT","bugs":{"url":"https://github.com/maana-io/q-assistant-client/issues"},"homepage":"https://github.com/maana-io/q-assistant-client#readme","dependencies":{"core-js":"3.6.4","post-robot":"10.0.29"},"devDependencies":{"@types/node":"^14.14.2","@types/post-robot":"^10.0.0","prettier":"2.0.5","typedoc":"^0.19.2","typedoc-plugin-markdown":"^3.0.11","typescript":"^3.9.5"},"readme":"# q-assistant-client\n\nA lightweight JavaScript client for Maana-Q Assistant developers that wraps\npost-message communication between an embedded Maana-Q assistant and the Maana-Q\nUI.\n\nYou can find the [API Documentation here](./docs/README.md).\n\n## Abstract\n\nThe Q-Assistant-Client is intended to be used in a web application being\nleveraged as a Maana Q assistant (embedded as an iframe). This assistant client\nwill facilitate communication between the assistant and the parent frame. The\nclient provides a rich, asynchronous experience over what would otherwise be\n'fire-and-forget'-style messaging via post-post message communication.\n\n## Requirements and Assumptions\n\n### Post-Robot Library\n\nThe Maana Knowledge Portal (KPortal) uses the\n[kraken/post-robot library](https://github.com/krakenjs/post-robot) to enrich\nthe communication with the assistant. Post-robot allows for asynchronous,\npromise-based request/response style behavior between the assistant and the\nassistant API.\n\nThe API requires that the client use the post-robot library. This\nassistant-client library is the easiest way to achieve this, and also adds a\nfair amount of 'sugar' to the process to improve developer productivity.\nDevelopers could, however, use post-robot directly in their own client\nimplementation.\n\n### Maana-Gateway Proxy Requirements\n\nThe Maana-Gateway service requires relative paths (paths relative to the root)\nin the assistant web application in order to proxy the application and its\ncontent. For create-react-apps, for instance, this means setting `\"homepage\"` to\n`\".\"` in the package.json file.\n\n## Singleton Instance\n\nThe client is exported as a singleton to avoid duplicate registration on event\nlisteners. You can import the instance like this:\n\n```js\nimport { AssistantAPIClient } from '@io-maana/q-assistant-client';\n```\n\nFunction calls can be made against the client instance like any other javascript\nobject. They are all async.\n\n```js\nconst workspace = await AssistantAPIClient.getWorkspace();\nconsole.log(\"Workspace:\", workspace)\n```\n\n## Dependencies\n\nPost-Robot\nhttps://github.com/krakenjs/post-robot\n\nPost-robot is used to provide a richer communication layer atop post-message.\n\n## Versioning\n\nThe Maana Q Assistant Client does not follow semantic versioning. Its versions\ntrack the releases of the Maana Q platform.\n\n## Changes in v3.3.0\n\n### Improvements\n\n- Full Typescript support with interfaces for all types used.\n- More comprehensive documentation.\n- Support for the Maana Q 3.3.0 data types.\n- More control over updating the Workspaces and other entities.\n- A collection of enums and constants for places where the API expects or\nreturns enumerated information.\n- Improved information returned to the Assistant when there is an error in an\nAPI call.\n\n### Deprecation\n\nThe following surface area is deprecated and should be updated as described.\n\n- AssistantAPIClient.moveKindsAndFunctions has been deprecated in favor of\ncalling update on the target Workspace to move the entities.\n- AssistantAPIClient.createFunction has been deprecated in favor of calling\ncreateFunction or update on the Workspace it belongs to.\n- AssistantAPIClient.updateFunction has been deprecated in favor of calling\nupdate on the Function object or the Workspace it belongs to.\n- AssistantAPIClient.deleteFunction has been deprecated in favor of calling\ndeleteFunction or update on the Workspace it belongs to.\n- AssistantAPIClient.getFunctionById has been deprecated in favor of calling\nAssistantAPIClient.getFunctionOfServiceByName.\n- AssistantAPIClient.getFunctionsById has been deprecated in favor of calling\nAssistantAPIClient.getFunctionsOfServiceByName.\n- AssistantAPIClient.getFunctionGraph and workspace.getFunctionGraph have been\ndeprecated in favor of calling workspace.getFunctionsByName.\n- AssistantAPIClient.createKind has been deprecated in favor of calling\ncreateKind or update on the Workspace it belongs to.\n- AssistantAPIClient.updateKind has been deprecated in favor of calling\nupdate on the Kind object or the Workspace it belongs to.\n- AssistantAPIClient.deleteKind has been deprecated in favor of calling\ndeleteKind or update on the Workspace it belongs to.\n- AssistantAPIClient.getKindById has been deprecated in favor of calling\nAssistantAPIClient.getKindOfServiceByName.\n- AssistantAPIClient.getKindsById has been deprecated in favor of calling\nAssistantAPIClient.getKindsOfServiceByName.\n- knowledgeGraph.offsetX, knowledgeGraph.offsetY, knowledgeGraph.zoom and\nknowledgeGraph.getNodes have been deprecated in favor of getting the information\noff of knowledgeGraph.graph.\n- knowledgeGraph.addNode and knowledgeGraph.removeNode have been deprecated in\nfavor of knowledgeGraph.update that gives you much more fine grained control.\n\n\n## Changes in v3.2.2\n\n### Improvements\n\n- Assistant State Management: WORKING, IDLE\n- Background Messaging/Eventing\n- Render Modes: BACKGROUND, DISPLAY\n- Expansion of Workspace object capabilities\n- Error Reporting\n- Repair Event\n- Plural versions of calls such as updateKind(s) to improve performance and\ndeveloper experience.\n- InventoryChanged diffing is fully granular in v3.2.2--limitations\nin v3.2.1 only fired the Function diff for changes in Function name.\n\n### Deprecation\n\nThe following surface area IS removed from the client in v3.2.2, and IS\ndeprecated in the API:\n\n- AssistantAPIClient.enableSelectionChangedNotification\n- AssistantAPIClient.disableSelectionChangedNotification\n- AssistantAPIClient.enableInventoryChangedNotification\n- AssistantAPIClient.disableInventoryChangedNotification\n\n## API Documentation\nMore information in the [Docs Folder](./docs/README.md)\n\n### Assistant Render Mode\n\nAn assistant's render mode refers to whether it is being displayed in a visible\nmanner to the user. As of v3.2.2, assistants are not closed when they are out of\nview. All assistants will be loaded and kept in `BACKGROUND` render mode until\nthey are placed in the assistant panel, at which point the `DISPLAY` render mode\nevent will be fired.\n\nNote: Assistants will receive all notifications/events while in BACKGROUND mode.\n\nDesign Consideration: It will be up to the developer to determine how state and\nresource use will be managed while an assistant is operating between BACKGROUND\nand DISPLAY modes.\n\n### Repair\nAssistants may get into situations where they are either out of sync with the\nMaana Q UI, or in a failure state. Assistants should be able to recover from\nthese states.\n\nThe repair event functionality added in v3.2.2 is designed to notify the\nassistant that it must repair itself. This could mean a resync with its\nresources on the workspace or externally or, for some assistants, nothing at\nall.\n\nWhen is repair triggered?\nEither manually by a user clicking 'repair workspace' under the assistant\ninventory panel, or upon a workspace clone event. An assistant will be expected\nto handle either scenario.\n\nPerformance Consideration:\nFor some assistants, repair might involve 'introspecting' and processing the\ncurrent workspace or Q system resources. This could be very resource intensive.\nMake sure you review this API guide to have an idea of what tools are available\nto get the best results. It's always a good idea to check performance of repair\non a large workspace and ensure necessary optimizations have been made.\n\nDesign Consideration:\nMake your workflows modular enough to be reused between repair and normal usage\nif possible.\n\nRecommended Usage: A repair process should be wrapped in the try/catch/finally flow shown in the `setAssistantState` API call to provide the user assistant-state and error updates as well as pause `inventoryChanged` notifications during repair (if the assistant has subscribed).\n\n## Troubleshooting Assistant Issues\n### Assistant root file has loaded, but not other content\n\nObserving in the browser's dev tools that some resources have loaded correctly\n(usually the root), but other's haven't (usually nested files or chunks), is\nindicative of a failure of Q Gateway to proxy due to not having a 'relative'\npath structure.\n\n### You are seeing post-robot `NO ACK` errors in the console.\n\nThese errors stem from a failed acknowledgement for a call either between the\nclient and the API or vice-versa. Here, this means that the web app 'window'\n(the assistant) cannot communicate with, or access, the 'window.parent'\n(Maana K-Portal) object.\n\nCommonly, these will stem from the 'window' (the assistant) not being loaded or\nin a loadable state, which means the API will not receive an acknowledgement\nwhen it fires an event.\n\nImproper CORS configuration is also a common culprit (also verify if using\ndocker or nginx that your proxying and networking is configured correctly to\nallow communication and to account for CORS).\n","readmeFilename":"README.md","gitHead":"1299d37d4dc4ac1f0c503a367a2d796e5e4347a0","_id":"@io-maana/q-assistant-client@3.3.0-beta.16","_nodeVersion":"12.22.1","_npmVersion":"6.14.12","dist":{"integrity":"sha512-5oqUMxYcCaq/+QKnip58EBeM8pdAUadcQlsm+L13xmvvBAbg0cySb5YsJsl72EBWRTdyh+ad30qjye7bDWIVgQ==","shasum":"433b0515f006da69b043e88f1cbc36f816205aa1","tarball":"https://registry.npmjs.org/@io-maana/q-assistant-client/-/q-assistant-client-3.3.0-beta.16.tgz","fileCount":87,"unpackedSize":376679,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJgiJm7CRA9TVsSAnZWagAAnjcP/jzF3ydEPXO7VeTwQ/j1\nRoin5NDPy8+8iAsT3CrxrRfMMuqJ+Vlwn59Ir5+mESty9f4YIlXAoD0AvKwj\nPeU9ljMPJy461yqyBysnZsTjj7sTCAS+l8qPsxV/BTvIvrAzQVk2+p2OtaeJ\nmU/teRrC+RXZkdTrJlWLieI6DCSl5ayUfPXARFFUPGsWCjzRbnR1NNL9Zy1b\n7XlS4wMZURsUU7hs7WynKo6AWLDE1BlqCjItUBQf2xhF3B71IimlG952SkO3\nGCXoHCIUSkvTqODPzZpFma7UYof2RkAQP8SE/9LragXgY9SK3AsLMy4Ivx5f\nFIIJ5a3YpESt3GEW7m3RC+sn/nKZSxyI4lKSvANxMSpJx2k+96/MSvE6qdgr\n/MLIN8twcdIHW3My1+pb8f9hzKmz+F0QawJpXYQ8Rz2pYrZcno2JbaixqF1F\nxQmQD0LuqY/mQFhTMo3M8vvvkeQxhDmeOBVacsE+tTBAf7/ahp2AyVJ2KlHb\nEJZF1NZCOV+MqHQjOhWQG/AQddDkDoAdjPptviztEgF2qD56k9ySnpb8jymW\nXKRbCk3Xl4SjmqgDSitztzvDLnfiOgeb2gnGB59pXM0RQzXXZ0mEMBp7pJhB\nEJJN3sgbWMHynRSUpgK3QnlZplaS9Mrd485EdFBMpn+5/GRDx3Ms4Sx5f7+Z\natun\r\n=jYwh\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIFdrQgbSaOrsSKyVe/vN/cxBFufihAvqfnGjkjrvB65tAiEAvNDZ+AfVV9Qu/KTJk5ZeddTIaOLsxjljDS7JYkyHHlc="}]},"_npmUser":{"name":"teamcitymaana","email":"teamcity@maana.io"},"directories":{},"maintainers":[{"name":"witt3rd","email":"witt3rd@witt3rd.com"},{"name":"bzvetey","email":"bzvestey@gmail.com"},{"name":"abatyuk","email":"andrey@maana.io"},{"name":"rpovey","email":"rob@maana.io"},{"name":"teamcitymaana","email":"teamcity@maana.io"},{"name":"dlsmaana","email":"dlewissandy@maana.io"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/q-assistant-client_3.3.0-beta.16_1619564985540_0.050492718587912266"},"_hasShrinkwrap":false},"3.3.0-beta.17":{"name":"@io-maana/q-assistant-client","version":"3.3.0-beta.17","description":"JavaScript package to streamline communication between an assistant and the Maana Q Assistant API.","main":"build/index.js","types":"build/index.d.ts","exports":{"./":"./build/"},"scripts":{"build":"npm run build:ts && npm run build:doc","build:ts":"tsc --build tsconfig.json","build:doc":"typedoc","prepack":"npm run build","test":"echo \"Error: no test specified\" && exit 1","format":"prettier --write \"src/**/*.js\""},"repository":{"type":"git","url":"git+https://github.com/maana-io/q-assistant-client.git"},"keywords":["Maana","Q"],"author":{"name":"Logan Gore @ Maana.io"},"license":"MIT","bugs":{"url":"https://github.com/maana-io/q-assistant-client/issues"},"homepage":"https://github.com/maana-io/q-assistant-client#readme","dependencies":{"core-js":"3.6.4","post-robot":"10.0.29"},"devDependencies":{"@types/node":"^14.14.2","@types/post-robot":"^10.0.0","prettier":"2.0.5","typedoc":"^0.19.2","typedoc-plugin-markdown":"^3.0.11","typescript":"^3.9.5"},"readme":"# q-assistant-client\n\nA lightweight JavaScript client for Maana-Q Assistant developers that wraps\npost-message communication between an embedded Maana-Q assistant and the Maana-Q\nUI.\n\nYou can find the [API Documentation here](./docs/README.md).\n\n## Abstract\n\nThe Q-Assistant-Client is intended to be used in a web application being\nleveraged as a Maana Q assistant (embedded as an iframe). This assistant client\nwill facilitate communication between the assistant and the parent frame. The\nclient provides a rich, asynchronous experience over what would otherwise be\n'fire-and-forget'-style messaging via post-post message communication.\n\n## Requirements and Assumptions\n\n### Post-Robot Library\n\nThe Maana Knowledge Portal (KPortal) uses the\n[kraken/post-robot library](https://github.com/krakenjs/post-robot) to enrich\nthe communication with the assistant. Post-robot allows for asynchronous,\npromise-based request/response style behavior between the assistant and the\nassistant API.\n\nThe API requires that the client use the post-robot library. This\nassistant-client library is the easiest way to achieve this, and also adds a\nfair amount of 'sugar' to the process to improve developer productivity.\nDevelopers could, however, use post-robot directly in their own client\nimplementation.\n\n### Maana-Gateway Proxy Requirements\n\nThe Maana-Gateway service requires relative paths (paths relative to the root)\nin the assistant web application in order to proxy the application and its\ncontent. For create-react-apps, for instance, this means setting `\"homepage\"` to\n`\".\"` in the package.json file.\n\n## Singleton Instance\n\nThe client is exported as a singleton to avoid duplicate registration on event\nlisteners. You can import the instance like this:\n\n```js\nimport { AssistantAPIClient } from '@io-maana/q-assistant-client';\n```\n\nFunction calls can be made against the client instance like any other javascript\nobject. They are all async.\n\n```js\nconst workspace = await AssistantAPIClient.getWorkspace();\nconsole.log(\"Workspace:\", workspace)\n```\n\n## Dependencies\n\nPost-Robot\nhttps://github.com/krakenjs/post-robot\n\nPost-robot is used to provide a richer communication layer atop post-message.\n\n## Versioning\n\nThe Maana Q Assistant Client does not follow semantic versioning. Its versions\ntrack the releases of the Maana Q platform.\n\n## Changes in v3.3.0\n\n### Improvements\n\n- Full Typescript support with interfaces for all types used.\n- More comprehensive documentation.\n- Support for the Maana Q 3.3.0 data types.\n- More control over updating the Workspaces and other entities.\n- A collection of enums and constants for places where the API expects or\nreturns enumerated information.\n- Improved information returned to the Assistant when there is an error in an\nAPI call.\n\n### Deprecation\n\nThe following surface area is deprecated and should be updated as described.\n\n- AssistantAPIClient.moveKindsAndFunctions has been deprecated in favor of\ncalling update on the target Workspace to move the entities.\n- AssistantAPIClient.createFunction has been deprecated in favor of calling\ncreateFunction or update on the Workspace it belongs to.\n- AssistantAPIClient.updateFunction has been deprecated in favor of calling\nupdate on the Function object or the Workspace it belongs to.\n- AssistantAPIClient.deleteFunction has been deprecated in favor of calling\ndeleteFunction or update on the Workspace it belongs to.\n- AssistantAPIClient.getFunctionById has been deprecated in favor of calling\nAssistantAPIClient.getFunctionOfServiceByName.\n- AssistantAPIClient.getFunctionsById has been deprecated in favor of calling\nAssistantAPIClient.getFunctionsOfServiceByName.\n- AssistantAPIClient.getFunctionGraph and workspace.getFunctionGraph have been\ndeprecated in favor of calling workspace.getFunctionsByName.\n- AssistantAPIClient.createKind has been deprecated in favor of calling\ncreateKind or update on the Workspace it belongs to.\n- AssistantAPIClient.updateKind has been deprecated in favor of calling\nupdate on the Kind object or the Workspace it belongs to.\n- AssistantAPIClient.deleteKind has been deprecated in favor of calling\ndeleteKind or update on the Workspace it belongs to.\n- AssistantAPIClient.getKindById has been deprecated in favor of calling\nAssistantAPIClient.getKindOfServiceByName.\n- AssistantAPIClient.getKindsById has been deprecated in favor of calling\nAssistantAPIClient.getKindsOfServiceByName.\n- knowledgeGraph.offsetX, knowledgeGraph.offsetY, knowledgeGraph.zoom and\nknowledgeGraph.getNodes have been deprecated in favor of getting the information\noff of knowledgeGraph.graph.\n- knowledgeGraph.addNode and knowledgeGraph.removeNode have been deprecated in\nfavor of knowledgeGraph.update that gives you much more fine grained control.\n\n\n## Changes in v3.2.2\n\n### Improvements\n\n- Assistant State Management: WORKING, IDLE\n- Background Messaging/Eventing\n- Render Modes: BACKGROUND, DISPLAY\n- Expansion of Workspace object capabilities\n- Error Reporting\n- Repair Event\n- Plural versions of calls such as updateKind(s) to improve performance and\ndeveloper experience.\n- InventoryChanged diffing is fully granular in v3.2.2--limitations\nin v3.2.1 only fired the Function diff for changes in Function name.\n\n### Deprecation\n\nThe following surface area IS removed from the client in v3.2.2, and IS\ndeprecated in the API:\n\n- AssistantAPIClient.enableSelectionChangedNotification\n- AssistantAPIClient.disableSelectionChangedNotification\n- AssistantAPIClient.enableInventoryChangedNotification\n- AssistantAPIClient.disableInventoryChangedNotification\n\n## API Documentation\nMore information in the [Docs Folder](./docs/README.md)\n\n### Assistant Render Mode\n\nAn assistant's render mode refers to whether it is being displayed in a visible\nmanner to the user. As of v3.2.2, assistants are not closed when they are out of\nview. All assistants will be loaded and kept in `BACKGROUND` render mode until\nthey are placed in the assistant panel, at which point the `DISPLAY` render mode\nevent will be fired.\n\nNote: Assistants will receive all notifications/events while in BACKGROUND mode.\n\nDesign Consideration: It will be up to the developer to determine how state and\nresource use will be managed while an assistant is operating between BACKGROUND\nand DISPLAY modes.\n\n### Repair\nAssistants may get into situations where they are either out of sync with the\nMaana Q UI, or in a failure state. Assistants should be able to recover from\nthese states.\n\nThe repair event functionality added in v3.2.2 is designed to notify the\nassistant that it must repair itself. This could mean a resync with its\nresources on the workspace or externally or, for some assistants, nothing at\nall.\n\nWhen is repair triggered?\nEither manually by a user clicking 'repair workspace' under the assistant\ninventory panel, or upon a workspace clone event. An assistant will be expected\nto handle either scenario.\n\nPerformance Consideration:\nFor some assistants, repair might involve 'introspecting' and processing the\ncurrent workspace or Q system resources. This could be very resource intensive.\nMake sure you review this API guide to have an idea of what tools are available\nto get the best results. It's always a good idea to check performance of repair\non a large workspace and ensure necessary optimizations have been made.\n\nDesign Consideration:\nMake your workflows modular enough to be reused between repair and normal usage\nif possible.\n\nRecommended Usage: A repair process should be wrapped in the try/catch/finally flow shown in the `setAssistantState` API call to provide the user assistant-state and error updates as well as pause `inventoryChanged` notifications during repair (if the assistant has subscribed).\n\n## Troubleshooting Assistant Issues\n### Assistant root file has loaded, but not other content\n\nObserving in the browser's dev tools that some resources have loaded correctly\n(usually the root), but other's haven't (usually nested files or chunks), is\nindicative of a failure of Q Gateway to proxy due to not having a 'relative'\npath structure.\n\n### You are seeing post-robot `NO ACK` errors in the console.\n\nThese errors stem from a failed acknowledgement for a call either between the\nclient and the API or vice-versa. Here, this means that the web app 'window'\n(the assistant) cannot communicate with, or access, the 'window.parent'\n(Maana K-Portal) object.\n\nCommonly, these will stem from the 'window' (the assistant) not being loaded or\nin a loadable state, which means the API will not receive an acknowledgement\nwhen it fires an event.\n\nImproper CORS configuration is also a common culprit (also verify if using\ndocker or nginx that your proxying and networking is configured correctly to\nallow communication and to account for CORS).\n","readmeFilename":"README.md","gitHead":"1e78fc6bafed36e7a927800b9fa8dda1fe8d1265","_id":"@io-maana/q-assistant-client@3.3.0-beta.17","_nodeVersion":"12.22.1","_npmVersion":"6.14.12","dist":{"integrity":"sha512-PiXGvqAaHZLN16Xif5T7cpXqMBs7G1078S/b1eQenrge+YHvcm1iaKNrm3GlHHcM2ssfTEUnfUY4jMkTNpBohQ==","shasum":"35380a07c56ae8f4a84d1c9672164af8f665085a","tarball":"https://registry.npmjs.org/@io-maana/q-assistant-client/-/q-assistant-client-3.3.0-beta.17.tgz","fileCount":87,"unpackedSize":377826,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJg1gsQCRA9TVsSAnZWagAAMpUP/RLRBZE+IZRQRjBCGhrt\nRHyPYuoTPeblpvwuxCGBSa8r1/Hv4ArellZZnazS4VYCebkDrwdm5+NLrBqT\ndlHPyMdVM17CEbUrifQELUy33YWLFNZsWtPVqPjmDceWp5ODW2mmIZUUKwRo\nxKkoXo1IrC5HH5a7+GToAuf/UhRs1TGdt8iSbxtshkjYje981qf9XdCT6iW9\nkd+INsY1hWbLQKaLydSmDOeBtefel+qq2fWVILSKLMQ5fBp0xedEjodIyuS/\ndQ1Pmvml9KiHtuxQEUvZ6rk2xOOmJOl1Dw7jt0XjhYIw4RAG21/7iQnlFxNp\nvifzkEza6T/d2vhwVUSTyCzmBevfTm6z+Cqoks1gIjWUvrVQdWy/zw9qB3UE\nvYj4R/llVhXpz26C4BkLBonPotxYK6vegYqBbKHr0uzImfVwZkiZolf+AXSj\nG79fEyGyYzWv7lP8RgpgTSJlTIcS/EOTyh40P8zJ0Z5IYFt3UyTQmVOAMGAS\nm2oHkjNsrrg6kH2dyxqMT4iSJKqYvcgWj0WUp8NbDpNNhM9pg08lFCcWBqbk\nzd9JrXeKqDk36z7D9mopMNOEsJgsz39cmCs5/yKn0IgO5W2YCYaBm+b3Qtgi\nqJI4xZyihny+tWwOn5cHzSkpLqhOusOPA44gnfMnA/904iFTyGSkfoPGk162\nmC+m\r\n=ZUhL\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCICkkW/AymeJQ1SsjoPgCpSVwARnygP/U0gW7Yba4Gvd1AiEAt/ynfYwwwsJzi79q8hmkz2YsAJosYbba4QptWm61h98="}]},"_npmUser":{"name":"teamcitymaana","email":"teamcity@maana.io"},"directories":{},"maintainers":[{"name":"witt3rd","email":"witt3rd@witt3rd.com"},{"name":"bzvetey","email":"bzvestey@gmail.com"},{"name":"abatyuk","email":"andrey@maana.io"},{"name":"rpovey","email":"rob@maana.io"},{"name":"teamcitymaana","email":"teamcity@maana.io"},{"name":"dlsmaana","email":"dlewissandy@maana.io"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/q-assistant-client_3.3.0-beta.17_1624640272098_0.7051940552962419"},"_hasShrinkwrap":false},"3.3.0-beta.18":{"name":"@io-maana/q-assistant-client","version":"3.3.0-beta.18","description":"JavaScript package to streamline communication between an assistant and the Maana Q Assistant API.","main":"build/index.js","types":"build/index.d.ts","exports":{"./":"./build/"},"scripts":{"build":"npm run build:ts && npm run build:doc","build:ts":"tsc --build tsconfig.json","build:doc":"typedoc","prepack":"npm run build","test":"echo \"Error: no test specified\" && exit 1","format":"prettier --write \"src/**/*.js\""},"repository":{"type":"git","url":"git+https://github.com/maana-io/q-assistant-client.git"},"keywords":["Maana","Q"],"author":{"name":"Logan Gore @ Maana.io"},"license":"MIT","bugs":{"url":"https://github.com/maana-io/q-assistant-client/issues"},"homepage":"https://github.com/maana-io/q-assistant-client#readme","dependencies":{"core-js":"3.6.4","post-robot":"10.0.29"},"devDependencies":{"@types/node":"^14.14.2","@types/post-robot":"^10.0.0","prettier":"2.0.5","typedoc":"^0.19.2","typedoc-plugin-markdown":"^3.0.11","typescript":"^3.9.5"},"readme":"# q-assistant-client\n\nA lightweight JavaScript client for Maana-Q Assistant developers that wraps\npost-message communication between an embedded Maana-Q assistant and the Maana-Q\nUI.\n\nYou can find the [API Documentation here](./docs/README.md).\n\n## Abstract\n\nThe Q-Assistant-Client is intended to be used in a web application being\nleveraged as a Maana Q assistant (embedded as an iframe). This assistant client\nwill facilitate communication between the assistant and the parent frame. The\nclient provides a rich, asynchronous experience over what would otherwise be\n'fire-and-forget'-style messaging via post-post message communication.\n\n## Requirements and Assumptions\n\n### Post-Robot Library\n\nThe Maana Knowledge Portal (KPortal) uses the\n[kraken/post-robot library](https://github.com/krakenjs/post-robot) to enrich\nthe communication with the assistant. Post-robot allows for asynchronous,\npromise-based request/response style behavior between the assistant and the\nassistant API.\n\nThe API requires that the client use the post-robot library. This\nassistant-client library is the easiest way to achieve this, and also adds a\nfair amount of 'sugar' to the process to improve developer productivity.\nDevelopers could, however, use post-robot directly in their own client\nimplementation.\n\n### Maana-Gateway Proxy Requirements\n\nThe Maana-Gateway service requires relative paths (paths relative to the root)\nin the assistant web application in order to proxy the application and its\ncontent. For create-react-apps, for instance, this means setting `\"homepage\"` to\n`\".\"` in the package.json file.\n\n## Singleton Instance\n\nThe client is exported as a singleton to avoid duplicate registration on event\nlisteners. You can import the instance like this:\n\n```js\nimport { AssistantAPIClient } from '@io-maana/q-assistant-client';\n```\n\nFunction calls can be made against the client instance like any other javascript\nobject. They are all async.\n\n```js\nconst workspace = await AssistantAPIClient.getWorkspace();\nconsole.log(\"Workspace:\", workspace)\n```\n\n## Dependencies\n\nPost-Robot\nhttps://github.com/krakenjs/post-robot\n\nPost-robot is used to provide a richer communication layer atop post-message.\n\n## Versioning\n\nThe Maana Q Assistant Client does not follow semantic versioning. Its versions\ntrack the releases of the Maana Q platform.\n\n## Changes in v3.3.0\n\n### Improvements\n\n- Full Typescript support with interfaces for all types used.\n- More comprehensive documentation.\n- Support for the Maana Q 3.3.0 data types.\n- More control over updating the Workspaces and other entities.\n- A collection of enums and constants for places where the API expects or\nreturns enumerated information.\n- Improved information returned to the Assistant when there is an error in an\nAPI call.\n\n### Deprecation\n\nThe following surface area is deprecated and should be updated as described.\n\n- AssistantAPIClient.moveKindsAndFunctions has been deprecated in favor of\ncalling update on the target Workspace to move the entities.\n- AssistantAPIClient.createFunction has been deprecated in favor of calling\ncreateFunction or update on the Workspace it belongs to.\n- AssistantAPIClient.updateFunction has been deprecated in favor of calling\nupdate on the Function object or the Workspace it belongs to.\n- AssistantAPIClient.deleteFunction has been deprecated in favor of calling\ndeleteFunction or update on the Workspace it belongs to.\n- AssistantAPIClient.getFunctionById has been deprecated in favor of calling\nAssistantAPIClient.getFunctionOfServiceByName.\n- AssistantAPIClient.getFunctionsById has been deprecated in favor of calling\nAssistantAPIClient.getFunctionsOfServiceByName.\n- AssistantAPIClient.getFunctionGraph and workspace.getFunctionGraph have been\ndeprecated in favor of calling workspace.getFunctionsByName.\n- AssistantAPIClient.createKind has been deprecated in favor of calling\ncreateKind or update on the Workspace it belongs to.\n- AssistantAPIClient.updateKind has been deprecated in favor of calling\nupdate on the Kind object or the Workspace it belongs to.\n- AssistantAPIClient.deleteKind has been deprecated in favor of calling\ndeleteKind or update on the Workspace it belongs to.\n- AssistantAPIClient.getKindById has been deprecated in favor of calling\nAssistantAPIClient.getKindOfServiceByName.\n- AssistantAPIClient.getKindsById has been deprecated in favor of calling\nAssistantAPIClient.getKindsOfServiceByName.\n- knowledgeGraph.offsetX, knowledgeGraph.offsetY, knowledgeGraph.zoom and\nknowledgeGraph.getNodes have been deprecated in favor of getting the information\noff of knowledgeGraph.graph.\n- knowledgeGraph.addNode and knowledgeGraph.removeNode have been deprecated in\nfavor of knowledgeGraph.update that gives you much more fine grained control.\n\n\n## Changes in v3.2.2\n\n### Improvements\n\n- Assistant State Management: WORKING, IDLE\n- Background Messaging/Eventing\n- Render Modes: BACKGROUND, DISPLAY\n- Expansion of Workspace object capabilities\n- Error Reporting\n- Repair Event\n- Plural versions of calls such as updateKind(s) to improve performance and\ndeveloper experience.\n- InventoryChanged diffing is fully granular in v3.2.2--limitations\nin v3.2.1 only fired the Function diff for changes in Function name.\n\n### Deprecation\n\nThe following surface area IS removed from the client in v3.2.2, and IS\ndeprecated in the API:\n\n- AssistantAPIClient.enableSelectionChangedNotification\n- AssistantAPIClient.disableSelectionChangedNotification\n- AssistantAPIClient.enableInventoryChangedNotification\n- AssistantAPIClient.disableInventoryChangedNotification\n\n## API Documentation\nMore information in the [Docs Folder](./docs/README.md)\n\n### Assistant Render Mode\n\nAn assistant's render mode refers to whether it is being displayed in a visible\nmanner to the user. As of v3.2.2, assistants are not closed when they are out of\nview. All assistants will be loaded and kept in `BACKGROUND` render mode until\nthey are placed in the assistant panel, at which point the `DISPLAY` render mode\nevent will be fired.\n\nNote: Assistants will receive all notifications/events while in BACKGROUND mode.\n\nDesign Consideration: It will be up to the developer to determine how state and\nresource use will be managed while an assistant is operating between BACKGROUND\nand DISPLAY modes.\n\n### Repair\nAssistants may get into situations where they are either out of sync with the\nMaana Q UI, or in a failure state. Assistants should be able to recover from\nthese states.\n\nThe repair event functionality added in v3.2.2 is designed to notify the\nassistant that it must repair itself. This could mean a resync with its\nresources on the workspace or externally or, for some assistants, nothing at\nall.\n\nWhen is repair triggered?\nEither manually by a user clicking 'repair workspace' under the assistant\ninventory panel, or upon a workspace clone event. An assistant will be expected\nto handle either scenario.\n\nPerformance Consideration:\nFor some assistants, repair might involve 'introspecting' and processing the\ncurrent workspace or Q system resources. This could be very resource intensive.\nMake sure you review this API guide to have an idea of what tools are available\nto get the best results. It's always a good idea to check performance of repair\non a large workspace and ensure necessary optimizations have been made.\n\nDesign Consideration:\nMake your workflows modular enough to be reused between repair and normal usage\nif possible.\n\nRecommended Usage: A repair process should be wrapped in the try/catch/finally flow shown in the `setAssistantState` API call to provide the user assistant-state and error updates as well as pause `inventoryChanged` notifications during repair (if the assistant has subscribed).\n\n## Troubleshooting Assistant Issues\n### Assistant root file has loaded, but not other content\n\nObserving in the browser's dev tools that some resources have loaded correctly\n(usually the root), but other's haven't (usually nested files or chunks), is\nindicative of a failure of Q Gateway to proxy due to not having a 'relative'\npath structure.\n\n### You are seeing post-robot `NO ACK` errors in the console.\n\nThese errors stem from a failed acknowledgement for a call either between the\nclient and the API or vice-versa. Here, this means that the web app 'window'\n(the assistant) cannot communicate with, or access, the 'window.parent'\n(Maana K-Portal) object.\n\nCommonly, these will stem from the 'window' (the assistant) not being loaded or\nin a loadable state, which means the API will not receive an acknowledgement\nwhen it fires an event.\n\nImproper CORS configuration is also a common culprit (also verify if using\ndocker or nginx that your proxying and networking is configured correctly to\nallow communication and to account for CORS).\n","readmeFilename":"README.md","gitHead":"6c15963e385cd4e9c244dd10b9c81eba3bb6fffa","_id":"@io-maana/q-assistant-client@3.3.0-beta.18","_nodeVersion":"12.22.1","_npmVersion":"6.14.12","dist":{"integrity":"sha512-wSJVcrqDWViTtyGTpaxttQL7Gj0YRnH87BnvOCJQGA1GyDgeqCgu1g5eDOlp47yXrbQoZdRJL1kdhH4GO+e7IQ==","shasum":"b7e7440b5fc661f64a6428783f1c631cf80acd0c","tarball":"https://registry.npmjs.org/@io-maana/q-assistant-client/-/q-assistant-client-3.3.0-beta.18.tgz","fileCount":90,"unpackedSize":384956,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJg2iHgCRA9TVsSAnZWagAAgaYP/1QUroEmBKVR4d7jJEmk\nvojWaFO4SMJrAkpCASbijXcrJtgYNCBrrsJ6ZvIjVzHvnK/YdEsEAjUVVnI8\nMYKKp2ZJZPqKm1swvYMA6tGa5eqFpG/uOSYxJZ2McSWltfIQ+5TPZfSkVOud\n7qJO/DE4MpzH3shHeU0WDtZSkOD07tB4aV8nPYvTFJjhFdAmarsCbHqWfTBu\nZc6wu7WHm4nTexTfyhUXw+6mVcuGuH3InOTvNs62+sIslAMrZVNAAOKK9a+6\nKLkrueISiJEngihiRni20lHW2FpjO6z23adt4tjfhyASrINkVA+eA2Gn6LwY\nZBxzEZDDK6+lpJDf5KAONEC95h8sBpvKKwLb6YCxq4legS4UQ2V8W5oXaxOb\nC/f6YZSlh1BUq+DLDRlYg2U2eKMnvoAozgJ6jJemXDq5zc7M5HahpWzjeA+B\nOKNwCTuIjdFzmMBkXGHQ2dtaFgeo6xM8BK3Ahm9a/nDps6AYioaffPZIiMSw\nka6HbaurJKYo6ZccMxaxP0dDI0EtfGWna0II1nj68pZP01xnT4DQxzyaUoMk\nxEu0u9wkpX7bRttVG9xDlVlpLoZCo/+7RE5kiscFncNMMsmN6sgT2d1QFA1M\nRVlVooazAAqgRMG5j0JLXM4HYipiv1dcmm3kcP66lz0CldDOcYN9zHhi8ZsW\ny6LB\r\n=HSsY\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIQC2Sug1X8xCTgSbOcAH5aUFBFK/F4C41Cp9MTadjAf88gIgHJG7Hyo9v4bfrzYJoPBeRn7twNYHe7AIaZO7v64tyA8="}]},"_npmUser":{"name":"teamcitymaana","email":"teamcity@maana.io"},"directories":{},"maintainers":[{"name":"witt3rd","email":"witt3rd@witt3rd.com"},{"name":"bzvetey","email":"bzvestey@gmail.com"},{"name":"abatyuk","email":"andrey@maana.io"},{"name":"rpovey","email":"rob@maana.io"},{"name":"teamcitymaana","email":"teamcity@maana.io"},{"name":"dlsmaana","email":"dlewissandy@maana.io"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/q-assistant-client_3.3.0-beta.18_1624908255733_0.5591483488726561"},"_hasShrinkwrap":false},"3.2.4-beta.40":{"name":"@io-maana/q-assistant-client","version":"3.2.4-beta.40","description":"JavaScript package to streamline communication between an assistant and the Maana Q Assistant API.","main":"build/index.js","exports":{".":"./build"},"scripts":{"build":"babel src --out-dir build","prepack":"npm run build","test":"echo \"Error: no test specified\" && exit 1","format":"prettier --write \"src/**/*.js\""},"repository":{"type":"git","url":"git+https://github.com/maana-io/q-assistant-client.git"},"keywords":["Maana","Q"],"author":{"name":"Logan Gore @ Maana.io"},"license":"MIT","bugs":{"url":"https://github.com/maana-io/q-assistant-client/issues"},"homepage":"https://github.com/maana-io/q-assistant-client#readme","dependencies":{"core-js":"3.6.4","post-robot":"10.0.29"},"devDependencies":{"@babel/cli":"^7.5.5","@babel/core":"^7.5.5","@babel/plugin-proposal-class-properties":"^7.5.5","@babel/preset-env":"^7.5.5","prettier":"1.19.1"},"readme":"# q-assistant-client\nA lightweight JavaScript client for Maana-Q Assistant developers that wraps post-message communication between an embedded Maana-Q assistant and the Maana-Q UI.\n\n## Abstract\nThe Q-Assistant-Client is intented to be used in a web application being leveraged as a Maana Q assistant (embedded as an iframe).\nThis assistant client will facilitate communication between the assistant and the parent frame.\nThe client provides a rich, asynchronous experience over what would otherwise be 'fire-and-forget'-style messaging\nvia post-post message communication.\n\n## Requirements and Assumptions\n\n### Post-Robot Library\nThe Maana Knowledge Portal (KPortal) uses the kraken/post-robot library [kraken/post-robot](https://github.com/krakenjs/post-robot) to enrich the communication with the assistant. Post-robot allows for asynchronous, promise-based request/response style behavior between the assistant and the assistant API.\n\nThe API requires that the client use the post-robot library. This assistant-client library is the easiest way to achieve this, and also adds a fair amount of 'sugar' to the process to improve developer productivity. Developers could, however, use post-robot directly in their own client implementation.\n\n### Maana-Gateway Proxy Requirements\nThe Maana-Gateway service requires relative paths (paths relative to the root) in the assistant web application in order to proxy the application and its content. For create-react-apps, for instance, this means setting \"homepage\" to \".\" in the package.json file.\n\n## Singleton Instance\nThe client is exported as a singleton to avoid duplicate registration on event listeners.\nYou can import the instance like this:\n\n```js\nimport AssistantAPIClient from '@io-maana/q-assistant-client';\n```\n\nFunction calls can be made against the client instance like any other javascript object. They are all async.\n\n```js\nconst workspace = await AssistantAPIClient.getWorkspace();\nconsole.log(\"Workspace:\", workspace)\n```\n\n## Dependencies\nPost-Robot\nhttps://github.com/krakenjs/post-robot\n\nPost-robot is used to provide a richer communication layer atop post-message.\n\n## Versioning\nThe Maana Q Assistant Client does not follow semantic versioning. Its versions\ntrack the releases of the Maana Q platform.\n\n## Examples\n@TODO Logan\n\n\n## Changes in v3.2.2\nImprovements in v3.2.2\n- Assistant State Management: WORKING, IDLE\n- Background Messaging/Eventing\n- Render Modes: BACKGROUND, DISPLAY\n- Expansion of Workspace object capabilities\n- Error Reporting\n- Repair Event\n- Plural versions of calls such as updateKind(s) to improve performance and developer experience.\n- InventoryChanged diffing is fully granular in v3.2.2--limitations\nin v3.2.1 only fired the Function diff for changes in Function name.\n\n### Deprecation\nThe following surface area IS removed from the\nclient in v3.2.2, and IS deprecated in the API:\n- AssistantAPIClient.enableSelectionChangedNotification\n- AssistantAPIClient.disableSelectionChangedNotification\n- AssistantAPIClient.enableInventoryChangedNotification\n- AssistantAPIClient.disableInventoryChangedNotification\n\nThe following surface area WILL BE removed from\nthe client in v3.2.4, and WILL BE deprecated in the API:\n- AssistantAPIClient.updateFunction (expected move to Workspace object)\n- AssistantAPIClient.updateKind (expected move to Workspace object)\n- AssistantAPIClient.deleteKind (expected move to Workspace object)\n- AssistantAPIClient.deleteFunction (expected move to Workspace object)\n\n## API Documentation\n\n### Assistant Render Mode\nAn assistant's render mode refers to whether it is being displayed in a visible manner to the user. As of v3.2.2, assistants are not closed when they are out of view.\nAll assistants will be loaded and kept in `BACKGROUND` render mode until they are\nplaced in the assistant panel, at which point the `DISPLAY` render mode event will be fired.\n\nNote: Assistants will receive all notifications/events while in BACKGROUND mode.\n\nDesign Consideration: It will be up to the developer to determine how state and resource use will be managed while an assistant is operating between BACKGROUND and DISPLAY modes.\n\n#### addRenderModeChangedListener = (cb) =>\nA listener to receive push events as to the assitant's render mode being changed.\n\n```js\nfunction handleRenderModeChanged(renderMode){\n  if (renderMode === 'DISPLAY'){\n    // Assistant is visible\n  } else {\n    // Assistant is not visible and running in background.\n  }\n}\n\nAssistantAPIClient.addRenderModeChangedListener(handleRenderModeChanged)\n\n```\n\n#### removeRenderModeChangedListener = (cb) =>\nRemoves the renderModeChanged listener by reference, or if no callback function reference is provided, it removes all listeners.\n\n#### getRenderMode = () =>\nReturns the current assistant render mode.\n\n```js\nconst renderMode = await AssistantAPIClient.getRenderMode()\n\nif (renderMode === 'DISPLAY'){\n  // Assistant is visible\n} else {\n  // Assistant is not visible and running in background.\n}\n\n```\n\n### Repair\nAssistants may get into situations where they are either out of sync with the Maana Q UI, or in a failure state. Assistants should be able to recover from these states.\n\nThe repair event functionality added in v3.2.2 is designed to notify the assistant that it must repair itself. This could mean a resync with its resources on the workspace or externally or, for some assistants, nothing at all.\n\nWhen is repair triggered?\nEither manually by a user clicking 'repair workspace' under the\nassistant inventory panel, or upon a workspace clone event. An assistant will be expected to handle either scenario.\n\nPerformance Consideration:\nFor some assistants, repair might involve 'introspecting'\nand processing the current workspace or Q system resources. This could be very resource intensive. Make sure you review this API guide to have an idea of what tools are\navailable to get the best results. It's always a good idea to check performance of repair on a large workspace and ensure necessary optimizations have been made.\n\nDesign Consideration:\nMake your workflows modular enough to be reused between repair and normal usage if possible.\n\n#### addRepairListener (cb) =>\n```js\n\nAssistantAPIClient.addRepairListener(()=>{\n  // Self-heal\n})\n\n```\n\nRecommended Usage: A repair process should be wrapped in the try/catch/finally flow shown in the `setAssistantState` API call to provide the user assistant-state and error updates as well as pause `inventoryChanged` notifications during repair (if the assistant has subscribed).\n\n#### removeRepairListener = (cb) =>\nRemoves the repair listener by reference, or if no callback function reference is provided, it removes all listeners.\n\n### User-facing Error Handling\n\n#### reportError (error) =>\nReports an error to the UI to be displayed in the assistant's error log in the\ninventory panel. This call is not disruptive and designed to operated independently of other assistant operations, such as state management. See `setAssistantState` in the next section.\n\nRecommended usage: use this functionality where it would futher the user experience\nto show the user an error and it's cause. Do not use this where things will be retried,\ncleaned up automatically, or are not relevant to the user.\n\n```js\ntry{\n  // Do work\n} catch(e) {\n  AssistantAPIClient.reportError(e)\n}\n```\n\n### State management\n\n#### clearState = () =>\nThis will remove all callbacks from all listeners.\n\n```js\nawait AssistantAPIClient.clearState()\n```\n\n#### setAssistantState = (state) =>\nThis sets the current state of the assistant using the\n`AssistantState` enum. Setting a state of `WORKING` will\ncreate the 'working' status spinner in the Assistant\nInventory Panel in the Maana Q UI. Conversely, setting an `IDLE` state will\nremove the spinner. This adds to user experience by informing users of the\nstatus of operations.\n\n```js\nimport {\n  default as AssistantAPIClient,\n  AssistantState\n} from '@io-maana/q-assistant-client'\n\n...\n\nAssistantAPIClient.setAssistantState(AssistantState.WORKING)\n\n...\n\nAssistantAPIClient.setAssistantState(AssistantState.IDLE)\n\n```\nUI User Prompt: If the assistant is in a `WORKING` state, the Maana Q UI will\nwarn the user before leaving the workspace.\n\nNOTE: while an assistant is in a working state, it will\nnot receive `inventoryChanged` events--an aggregated inventory diff\nwill be sent once the assistant is set back to `IDLE`.\n\nRecommended usage: Control states at a high level using try/catch/finally\nflow incorporating the `reportError` API call.\n\n```js\ntry{\n  AssistantAPIClient.setAssistantState(AssistantState.WORKING)\n  // Do work, await high-level tasks, etc.\n} catch(e) {\n  AssistantAPIClient.reportError(e)\n} finally{\n  AssistantAPIClient.setAssistantState(AssistantState.IDLE)\n}\n```\n\n#### AssistantState (enum)\nContains the valid assistant states: `IDLE` or `WORKING`.\n\nMust be imported in addition to the AssistantAPIClient:\n\n```js\nimport {\n  default as AssistantAPIClient,\n  AssistantState\n} from '@io-maana/q-assistant-client'\n```\n\n\n### User Info\nThe `UserInfo` object:\n```js\n{\n email: string,\n name: string\n}\n```\n\n#### getUserInfo = () =>\nReturns a Userinfo object pertaining to the logged in user.\n\n```js\nconst userInfo = await AssistantAPIClient.getUserInfo()\n```\n### Selection\nThe `Selection` object:\n```js\n{\n  kindId: string\n  kindName: string\n  id: string\n}\n```\n\n#### getCurrentSelection = () =>\nReturns an Array of `Selection` objects:\n\n```js\nconst {selection} = await AssistantAPIClient.getCurrentSelection();\n```\n\n#### addSelectionChangedListener = async cb =>\nAdds a callback function to be executed upon a valid workspace selection change.\n\nCallback value is an array of Selection objects:\n\n```js\n// Create the selection callback.\nconst selectionCB = ({selection})=>{\n  console.log('Workspace selection has changed.')\n  selection.forEach(i=>{\n    console.log('Kind: ',i.kindName)\n    console.log('Instance Id:',i.id)\n    console.log('Kind Id:',i.kindId)\n  })\n}\n\n// Add the listener.\nAssistantAPIClient.addSelectionChangedListener(selectionCB);\n```\n\nThis function only exists on the Q-Assistant-Client--only enableSelectionChangedNotification is called on the API.\n\n#### removeSelectionChangedListener = async cb =>\nThis will have to be called on a 1:1 basis with addSelectionChangedListener calls if supplying a callback.\n\n```js\nAssistantAPIClient.removeSelectionChangedListener(selectionCB)\n```\n\n**If NOT supplying a callback to this call, all selection changed listeners will be removed.\n\n```js\nAssistantAPIClient.removeSelectionChangedListener()\n```\n\nThis function only exists on the Q-Assistant-Client--only disableSelectionChangedNotification is called on the API.\n\n\n### Services\nThe `Service` object:\n```js\n{\n   id: string,\n   name: string\n   endpointUrl: string,\n   getKinds: () => // Returns [] of Kinds objects\n   getFunctions: () => // Returns [] of Function objects\n}\n```\n\n#### getServiceById = id =>\nThis will return a service that exists within the scope of the workspace.\n** Assistant services will return null. Services outside the scope of the workspace will cause an error to be returned as 'Unable to load a Service from outside of the workspace.'\n\n```js\nconst svc = await AssistantAPIClient.getServiceById(id)\n```\n\n#### createService = id =>\nCreates a service in Q.\n\nNote: This will create the service, but does NOT import it into the workspace.\nYou will need to use `importService` on the Workspace object to import it.\nReturns a promise that resolves\n\n```js\n    const service = {\n      id: ...,\n      name: ...,\n      endpointUrl: ...,\n      serviceType: ...\n    }\n\n    await AssistantAPIClient.createService(service)\n```\n\n#### deleteService = id =>\nDeletes a service from Q.\n\n```js\n    await AssistantAPIClient.deleteService(id)\n```\n\n#### refreshServiceSchema = id =>\nRefreshes a service by fetching its schema. This will also\nreload the service inventory in the currently visible workspace.\n\n```js\nawait AssistantAPIClient.refreshServiceSchema(\"id\")\n```\n\n#### reloadService = id =>\nReloads a service in the inventory in the currently visible workspace.\n\n```js\nawait AssistantAPIClient.reloadService(\"id\")\n```\n\n### Workspace\n\n#### getWorkspace = () =>\nReturns a Workspace object representing the workspace.\n\n```js\nconst ws = await AssistantAPIClient.getWorkspace(id)\n```\n\nNote: The `id` parameter is optional. If it is not supplied, the query\nwill return the current/visible workspace.\n\nThe `Workspace` object:\n\n```js\n\n{\n    id: string,\n    name: string,\n    endpointUrl: string,\n    workspaceServiceId: string,\n    modelServiceId: string,\n    logicServiceId: string,\n\n    //\n    // Locking information\n    //\n    async lockedBy() {\n      // Returns the e-mail address of the user who locked the Workspace, or\n      // null if the Workspace is not currently locked.\n    }\n    async canEdit() {\n      // Returns `true` when the Workspace is not locked, or the current user\n      // owns the lock.\n      // Returns 'false' when the Workspace is locked by a different user.\n    }\n    async setLocked(isLocked) {\n      // Takes a boolean or undefined for `isLocked`.\n      //  `true` locks the Workspace as the current User.\n      //  `false` unlocks the Workspace\n      //  `undefined` causes it to toggle the current locked state.\n      // Returns a Promise that will resolve or reject when the task is done.\n    }\n\n    //\n    // Knowledge Graphs\n    //\n    getActiveGraph: async () => {\n      // Returns the active Graph object.\n      // Returns null if active graph is not of type 'Knowledge Graph', or if an\n      // active graph is deleted, thereby setting active graph to null.\n    },\n    getKnowledgeGraphs: async () => {\n      // Returns [Graph]\n    },\n    // TODO: define input\n    createKnowledgeGraph: input =>\n    // TODO: define input\n    createKnowledgeGraphs: input =>\n\n    //\n    // Services\n    //\n    getImportedServices: async () => {\n      // Returns an array of Service objects that have\n      // been imported into the workspace.\n      // No assistant services will be returned.\n    },\n    getImportedAssistants: async () => {\n      // Returns a list of imported assistants.\n    },\n    importService: serviceId => {\n      // Imports a service by it's ID.\n    },\n    importServices: serviceIds => {\n      // Imports services by their IDs.\n    },\n    removeServices: serviceIds => {\n      // Removes a list of services from the workspace.\n    },\n    removeService: serviceId => {\n      // Removes a service from the workspace.\n    },\n\n    //\n    // Functions\n    //\n    getFunctions: async () => {\n      // Returns an array of functions in the workspace (includes boilerplate).\n    },\n    createFunction: funcData => {\n      // Creates a function and adds it to the graph.\n    }\n    createFunctions: funcData =>{\n      // Creates several functions and adds them to the graph.\n    }\n    updateFunction: funcData => {\n      // Updates a function.\n    },\n    updateFunctions: funcData =>{\n      // Updates functions based on input array.\n    },\n    deleteFunction: funcId => {\n      // Deletes a function by its ID.\n    },\n    getFunctionGraph: funcId => {\n      // Returns a function graph by its ID.\n    }\n\n    //\n    // Kinds\n    //\n    getKinds: async () => {\n      // Returns an array of functions in the workspace (includes boilerplate).\n    },\n    createKind: kindData => {\n      // Currently same input as AssistantAPIClient call.\n    },\n    createKinds: kindData => {\n      // Currently same input as AssistantAPIClient call.\n    },\n    updateKind: kindData => {\n      // Currently same input as AssistantAPIClient call.\n    },\n    updateKinds: kindData => {\n      // Currently same input as AssistantAPIClient call.\n    },\n    deleteKind: kindId => {\n      // Currently same input as AssistantAPIClient call.\n    }\n    // Event Triggers\n    triggerRepairEvent: () => {\n      // Triggers the repair event on a workspace.\n    }\n  };\n}\n```\n\n\n### Graphs\nThe `Graph` object:\n```js\n{\n  id: string,\n  name: string,\n  offsetX: Number,\n  offsetY: Number,\n  zoom: Number,\n  getNodes: async () => {\n      // Returns [Node]\n  },\n\n  addNode: async (type, instance, changeSelection) => {\n      // Returns Node\n  },\n  removeNode: async id => {\n      // Should return nothing or error.\n      // Currently returning [] in all cases.\n  },\n  updateNodeLayout: async (nodeId, { x, y, collapsed }) => {\n  },\n  updateGraphLayout: async ({ offsetX, offsetY, zoom }) => {\n  }\n\n  //\n  // Locking information\n  //\n  async lockedBy() {\n    // Returns the e-mail address of the user who locked the Graph, or null if\n    // the Graph is not currently locked.\n  }\n  async canEdit() {\n    // Returns `true` when the Graph is not locked, or the current user owns the\n    // lock.\n    // Returns 'false' when the Graph is locked by a different user.\n  }\n  async setLocked(isLocked) {\n    // Takes a boolean or undefined for `isLocked`.\n    //  `true` locks the Graph as the current User.\n    //  `false` unlocks the Graph\n    //  `undefined` causes it to toggle the current locked state.\n    // Returns a Promise that will resolve or reject when the task is done.\n  }\n}\n```\n\n#### Getting a graph object:\nGraph objects are obtained through an instance of a Workspace\n\n```js\nconst ag = await ws.getActiveGraph()\n```\n\nor\n\n```js\nconst kgs = await ws.getKnowledgeGraphs()\n```\n\n#### Manipulating Graphs\n\n**Only the active graph may be manipulated.\n\nAll graph manipulations should be ‘visually’ verifiable on the graph itself, i.e., adds/removes/positioning, should all be reflected on the graph itself.\n\nThe `Node` object:\n```js\n{\nid: string\nx: number\ny: number\ncollapsed: boolean\nknowledgeGraphNode {\n  id: string\n  innerKind: Kind\n  innerFunction: Function\n}\n}\n```\n\n#### addNode(type, instance, changeSelection) =>\n\nTakes type (“Function” or “Kind”), instance (the Function or Kind object), and optionally a boolean to indicate whether the selection should be changed to this new node.\n\nReturns the newly created Node object.\n\n```js\nconst node = await ag.addNode('Kind',kind)\n```\n\n#### removeNode(id) =>\n\nTakes the id of Node to be deleted. Returns either undefined or an error.\n\n```js\nawait ag.removeNode(node.id)\n```\n\n#### getNodes() =>\nReturns an array of Node objects from the graph.\n\n```js\nconst nodes = await ag.getNodes()\n```\n\n#### updateNodeLayout: async (nodeId, { x, y, collapsed})=>\nUpdates a Node layout given a node ID and node coordinates (`x` and/or `y`) or a `collapsed` value. x/y values must be a number, and collapsed must be a boolean. Whatever is not specified will remain current.\n\n```js\nag.updateNodeLayout(id,{x:100,y:100,collapsed:true})\n```\n\n#### updateGraphLayout: async ({ offsetX, offsetY, zoom})=>\nUpdates a Graph layout given numerical values for x/y offsets and the zoom.\n\n```js\nag.updateGraphLayout({offsetX:50, offsetY:50, zoom: 70})\n```\n\n### Functions\n\nThe `Function` object:\n```js\n{\n    id: string\n    name: string\n    service {\n      id: string\n      name: string\n    }\n    arguments {\n      id: string\n      name: string\n      type: string\n      modifiers: Array[string]\n      typeKindId:: string\n      kind {\n        id: string\n        name: string\n      }\n    }\n    implementation {\n      id: string\n      entrypoint {\n        id: string\n      }\n      operations {\n        id: string\n        type: string\n        function {\n          id: string\n          name: string\n        }\n        argumentValues {\n          id: string\n          argument {\n            id: string\n          }\n          operation {\n            id: string\n          }\n          argumentRef: string\n        }\n      }\n    }\n    isGenerated: boolean\n    functionType: string\n    graphqlOperationType: string\n    outputType: string\n    outputKindId: string\n    outputModifiers: Array[string]\n    kind {\n      id: string\n      name: string\n    }\n\n    //\n    // Locking information\n    //\n    async lockedBy() {\n      // Returns the e-mail address of the user who locked the Function, or null\n      // if the Function is not currently locked.\n    }\n    async canEdit() {\n      // Returns `true` when the Function is not locked, or the current user\n      // owns the lock.\n      // Returns 'false' when the Function is locked by a different user.\n    }\n    async setLocked(isLocked) {\n      // Takes a boolean or undefined for `isLocked`.\n      //  `true` locks the Function as the current User.\n      //  `false` unlocks the Function\n      //  `undefined` causes it to toggle the current locked state.\n      // Returns a Promise that will resolve or reject when the task is done.\n    }\n}\n```\n\n`FunctionExecutionResult` object:\n```js\n{\n  id: string,\n  result: JSON\n}\n```\n\n#### executeFunction = ( {id, variables, resolve} ) =>\nExecutes a function based on its id, with optional inputs for variables and a resolve string (this specifies the fields to be returned, which must be valid based on the result).\n\nReturns : JSON matching shape of result , unless no sub-selection of fields is required in the execution.\n\nThis following piece of code will execute a Function given a function ID, and pass in variables for ‘example’, requesting back id and name fields.\n\n```js\nconst res = await AssistantAPIClient.executeFunction({functionId: func.id, variables: {\"variableName\": \"variableValue\"}, resolve: \"{ id name }\");\n```\n\n#### createFunction = input =>\nCreates a function based on the input provided.\n\nReturns: the created Function object.\n\n**Using create function will only place the function in the workspace’s inventory--it will not place the function as a node on the Graph. In order to do this, you must pass the created function into the addNode function on the active Graph, making sure to specify ‘Function' as the type.\n\n```js\nconst createFunctionInput = {\n  name:\"yourName\",\n  arguments:[],\n  outputType: \"STRING\",\n  graphqlOperationType:\"QUERY\",\n  functionType: \"CKG\"\n}\n\nconst createdFunction = await AssistantAPIClient.createFunction(createFunctionInput)\n```\n\n#### updateFunction = input =>\nInput is the same for creating a function. It’s important to note that the arguments property will be replaced in it’s entirety with whatever is provided (if a value is provided.\n\nReturns the updated `Function` object.\n\n```js\nconst updatedFunction = await AssistantAPIClient.updateFunction(input);\n```\n\n#### deleteFunction = input =>\nInput is the id of the Function to be deleted. Returns the deleted function as a promise.\n\n```js\nconst deletedFunction = await AssistantAPIClient.deleteFunction('id...');\n```\n\n#### getFunctionById = id =>\nReturns a Function as a promise based on the ID provided.\n\n```js\nconst func = await AssistantAPIClient.getFunctionById('id...');\n```\n\n#### addFunctionExecutionListener = async (id, cb) =>\nAssociates a callback function with the execution of a particular Function. When the Function matching the id parameter is executed, its FunctionExecutionResult object passed to the callback. Returns undefined.\n\nExample function execution callback and listener registration:\n\n```js\nfunction exampleFunctionCB (result){\n  console.log(`Function executed with result:`, result)\n}\n\nAssistantAPIClient.addFunctionExecutionListener('id...', exampleFunctionCB)\n```\n\n#### removeFunctionExecutionListener = async (id, cb) =>\nRemoves a Function execution listener based on the function ID and a reference to the callback function. If no callback is supplied, all listeners associated with the Function ID will be removed. Returns undefined.\n\n```js\nAssistantAPIClient.removeFunctionExecutionListener('id..', exampleFunctionCB)\n```\n\n### Kinds\nThe `Kind` object:\n```js\n{\n    id: string\n    name: string\n    service: {\n      id\n      name\n    }\n    isGenerated: boolean\n    schema {\n      id: string\n      name: string\n      type: string\n      typeKindId: string\n      modifiers: Array[string]\n      kind {\n        id: string\n        name: string\n      }\n    }\n}\n```\n\n#### createKind = input =>\nCreates a Kind based on an input object. Returns a promise that resolves to the created Kind object.\n\n```js\nconst kindInput = {\n name: \"someKind\",\n schema:[\n  { name: \"someField1\", type: STRING },\n  { name: \"someField2\", type: STRING }\n ]\n}\n\nconst newKind = await AssistantAPIClient.createKind(kindInput)\n```\n\n#### createKinds = input =>\nA plural version of `createKind` accepting an array of input objects.\nReturns a promise that resolves to an array of created Kind objects.\n\n```js\nconst kindsInput = [{\n name: \"someKind\",\n schema:[\n  { name: \"someField1\", type: STRING },\n  { name: \"someField2\", type: STRING }\n ]\n}, ...]\n\nconst newKinds = await AssistantAPIClient.createKinds(kindsInput)\n```\n\n\n#### updateKind = input =>\nUpdates a Kind based on an input object.\n\nUpdate Semantics: Only properties specified will be updated. If updating the schema, the entire schema must be specified as it will be replaced in its entirety.\n\nReturns a promise that resolves to the updated `Kind` object.\n\n```js\nconst updated = await AssistantAPIClient.updateKind(input)\n```\n\n#### deleteKind = input =>\nDeletes a Kind given a kind ID.\n\n```js\nconst deleted = await AssistantAPIClient.deleteKind(input)\n```\n\n#### getKindById = id =>\nReturns a promise that resolves to a Kind object given the specified kind ID.\n\nIn v3.2.2, any requested non-system kinds will be returned.\nIn v3.2.1, only kinds in the workspace or those of imported services will be returned.\n\n```js\nconst kind = await AssistantAPIClient.getKindById(id)\n```\n\n#### getKindsById = ids =>\nReturns a promise that resolves to an array of Kind objects given an array of kind IDs. Only kinds in the workspace or those of imported services will be returned.\n\n```js\nconst ids = [\"...\",\"...\",...]\nconst kind = await AssistantAPIClient.getKindsById(ids)\n```\n\n#### getAllReferencedKinds = input =>\nRecursively collects all kinds that are referenced in a kind's schema, starting\nwith a kind ID. For example if the ID of kind A is supplied as an input, and Kind `A` contains a field of type Kind `B`, and `B` contains a field of type Kind `C`,\nan array containing the kinds objects for `A`, `B`, `C` will be returned (as a promise).\n\n```js\nconst initialId = [\"...\"]\nconst kinds = await AssistantAPIClient.getAllReferencedKinds({\n          ids: initialId\n        })\n```\n\n\n### Inventory\n\nThe `InventoryChanged` object:\n```js\n{\n  kinds: {\n    adds: [DiffItem]\n    deletes: [DiffItem]\n    updates: [DiffItem]\n  }\n  functions:{\n    adds: [DiffItem]\n    deletes: [DiffItem]\n    updates: [DiffItem]\n  }\n  services: {\n    adds: [DiffItem]\n    deletes: [DiffItem]\n    updates: [DiffItem]\n  }\n}\n```\n\nThe `DiffItem` object:\n```js\n{\n  id: string,\n  name: string\n}\n```\n\n#### addInventoryChangedListener = async cb =>\nRegisters a callback function with the inventory changed event. When workspace inventory changes the callback function will be called with the InventoryChangedobject. Returns undefined.\n\n**Use-case note: an ‘update’ diff for inventory services is unlikely in general usage.\n\n```js\nconst inventoryCB = ({diff}) => {\n  if(diff.kinds) console.log('KINDS CHANGED',diff.kinds)\n  if(diff.functions) console.log('FUNCTIONS CHANGED', diff.functions)\n  if(diff.services) console.log('SERVICES CHANGED',diff.services)\n}\n\nAssistantAPIClient.addInventoryChangedListener(inventoryCB)\n```\n\nThis function exists on the Q-Assisant-Client only--only enableSelectionChangedNotification is used on the API side.\n\n#### removeInventoryChangedListener = async cb =>\nRemoves an inventory changed listener given the referenced callback. If no callback is specified, all listeners will be removed. Returns undefined.\n\n```js\nAssistantAPIClient.removeInventoryChangedListener(inventoryCB)\n```\n\nThis function exists on the Q-Assisant-Client only--only disableSelectionChangedNotification is used on the API side.\n\n#### moveKindsAndFunctions = (originId, targetId, kindIds, functionIds) =>\nMoves a collection of Kinds and Functions from the origin Workspace to the target Workspace.\n\n```js\n  await AssistantAPIClient.moveKindsAndFunctions(\n    originWorkspaceId,\n    targetId,\n    kindIds,\n    functionIds\n  );\n```\n\n### Locking Changed Event\n\nAn event is triggered when the locked state of the currently active Workspace or\nits Knowledge Graphs and Functions change.\n\nThe `LockingChanged` object:\n```js\n{\n  workspaces: [LockItem],\n  knowledgeGraphs: [LockItem],\n  functions: [LockItem]\n}\n```\n\nThe `LockItem` object:\n```js\n{\n  id: string\n  lockedBy: string\n}\n```\n\n#### addLockingChangedListener = cb =>\n\nRegisters a callback function with the locking changed event. When the currently\nactive Workspace or its Knowledge Graphs and Functions change the callback\nfunction will be called with the `LockingChanged` object. Returns undefined.\n\n```js\nconst lockingChangedCB = ({ locks }) => {\n  if(locks.workspace) console.log('WORKSPACES CHANGED', locks.workspace);\n  if(locks.knowledgeGraphs) console.log('KNOWLEDGE GRAPHS CHANGED', locks.knowledgeGraphs);\n  if(locks.functions) console.log('FUNCTIONS CHANGED', locks.functions);\n}\n\nAssistantAPIClient.addLockingChangedListener(lockingChangedCB);\n```\n\n#### removeLockingChangedListener = cb =>\n\nRemoves an locking changed listener given the referenced callback. If no\ncallback is specified, all listeners will be removed. Returns undefined.\n\n```js\nAssistantAPIClient.removeLockingChangedListener(lockingChangedCB)\n```\n\n## Troubleshooting Assistant Issues\n### Assistant root file has loaded, but not other content\nObserving in the browser's dev tools that some resources have loaded correctly (usually the root), but other's haven't (usually nested files or chunks), is indicative of a failure of Q Gateway to proxy due to not having a 'relative' path structure.\n\n### You are seeing post-robot `NO ACK` errors in the console.\nThese errors stem from a failed acknowledgement for a call either between the client and the API or vice-versa. Here, this means that the web app 'window' (the assistant) cannot communicate with, or access, the 'window.parent' (Maana K-Portal) object.\n\nCommonly, these will stem from the 'window' (the assistant) not being loaded or in a loadable state, which means the API will not receive an acknowledgement when it fires an event.\n\nImproper CORS configuration is also a common culprit (also verify if using docker or nginx that your proxying and networking is configured correctly to allow communication and to accout for CORS).","readmeFilename":"README.md","gitHead":"d36d159838b6eb9e4a66013a2ce5d9ed386784ed","_id":"@io-maana/q-assistant-client@3.2.4-beta.40","_nodeVersion":"12.22.12","_npmVersion":"6.14.16","dist":{"integrity":"sha512-LieSQUk/MVm+wXIxxmEVyeW/O8HwhTF0hgdXvWSmcUiQerBzY0fNYZGXDgIdxQnMx2wMebmM+RrvrixRJ3xlxQ==","shasum":"da30fdd835402098818f5b0b7ada579fd2dae97b","tarball":"https://registry.npmjs.org/@io-maana/q-assistant-client/-/q-assistant-client-3.2.4-beta.40.tgz","fileCount":11,"unpackedSize":79857,"signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEQCIAaVEXYYjmxjEtKsviMC7Bck3Wob/ZCvW0+dz29Yak2qAiBAqqXS80k4cn/dIIDskXPawv7f4Xl/EuO8h9W8kCtzBg=="}],"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v4.10.10\r\nComment: https://openpgpjs.org\r\n\r\nwsFzBAEBCAAGBQJihslMACEJED1NWxICdlZqFiEECWMYAoorWMhJKdjhPU1b\r\nEgJ2VmpmNw/9GDXaiNxvM+CEOzhYFb9tLtN6D3GpLylamvt45BKzbW3MjHBC\r\nlGsMRX0QItFngnIDL06qpo6dstdGPEiNOAJvB3nb/OxkS/BoFcWdMtr9z2QI\r\nS3+FYW2xDahqerYdFiH1PKCKdHniv6RimhnrvSnIYzuJ3xBsqNX0SchMhqkX\r\nAy+zHlYutmaCBHip7b+x2yYVMi29d7yJZ6GwWVh7nxL7ZH6f2PpT8UerqG4b\r\n1fUH/h91D28wNlivuo22qEzjGe0/88Kq9TkuiftxCRShq6LDcFazBD3IUgz/\r\nINuxV0wE2OKcQEA6Bs36f+6Tz5cNReEkYkN5kyGr1FTP1+h2+tpVbN3HiEfq\r\nDW38ZNVSHf21k7R6JXBDFMXW3vc2dEh+K3i3JQ/W2EorxjTKtKNC9iZ/Mgix\r\nuAXEjzPnaCn3H9rmQJrS0XabdLEc4gMCbt+xmQ09GRQ0JMPNS/yMX9wDk2Ap\r\n1EgBFe05xS4fEGDdXqhIAzfl4JdJB2254AsIUkRDuEQYMZ2Loa/dChD/j/yp\r\ncTdhZifsPanqiA5zEh/9ZeFfabXyTGk0NrQFICPYBY3/KOIAyF26yEFsAxbc\r\nRq2SeGOlST0F9E9ASRu7ERCKhGaglo9H2M4U8cwcDdJ9mFqSzqfv3GT6A6Uw\r\nU42rH4uMS1vcBz1F1jWTx9TZ5ii6165vyY4=\r\n=qOQe\r\n-----END PGP SIGNATURE-----\r\n"},"_npmUser":{"name":"teamcitymaana","email":"teamcity@maana.io"},"directories":{},"maintainers":[{"name":"witt3rd","email":"witt3rd@witt3rd.com"},{"name":"bzvetey","email":"bzvestey@gmail.com"},{"name":"abatyuk","email":"andrey@maana.io"},{"name":"rpovey","email":"rob@maana.io"},{"name":"teamcitymaana","email":"teamcity@maana.io"},{"name":"dlsmaana","email":"dlewissandy@maana.io"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/q-assistant-client_3.2.4-beta.40_1653000524013_0.4772982229873748"},"_hasShrinkwrap":false},"3.3.0-beta.20":{"name":"@io-maana/q-assistant-client","version":"3.3.0-beta.20","description":"JavaScript package to streamline communication between an assistant and the Maana Q Assistant API.","main":"build/index.js","types":"build/index.d.ts","engines":{"node":">=14","npm":">=6"},"exports":{".":"./build/"},"scripts":{"build":"npm run build:ts && npm run build:doc","build:ts":"tsc --build tsconfig.json","build:doc":"typedoc","prepack":"npm run build","test":"echo \"Error: no test specified\" && exit 1","format":"prettier --write \"src/**/*.js\""},"repository":{"type":"git","url":"git+https://github.com/maana-io/q-assistant-client.git"},"keywords":["Maana","Q"],"author":{"name":"Logan Gore @ Maana.io"},"license":"MIT","bugs":{"url":"https://github.com/maana-io/q-assistant-client/issues"},"homepage":"https://github.com/maana-io/q-assistant-client#readme","dependencies":{"@io-maana/typesystem-utils":"^1.0.9","post-robot":"10.0.29"},"devDependencies":{"@types/node":"^14.18.33","@typescript-eslint/eslint-plugin":"^5.46.1","@typescript-eslint/parser":"^5.46.1","eslint":"^8.29.0","eslint-plugin-react":"^7.31.11","prettier":"^2.7.1","typedoc":"^0.23.21","typedoc-plugin-markdown":"^3.13.6","typescript":"^4.8.4"},"readme":"# q-assistant-client\n\nA lightweight JavaScript client for Maana-Q Assistant developers that wraps\npost-message communication between an embedded Maana-Q assistant and the Maana-Q\nUI.\n\nYou can find the [API Documentation here](./docs/README.md).\n\n## Abstract\n\nThe Q-Assistant-Client is intended to be used in a web application being\nleveraged as a Maana Q assistant (embedded as an iframe). This assistant client\nwill facilitate communication between the assistant and the parent frame. The\nclient provides a rich, asynchronous experience over what would otherwise be\n'fire-and-forget'-style messaging via post-post message communication.\n\n## Requirements and Assumptions\n\n### Post-Robot Library\n\nThe Maana Knowledge Portal (KPortal) uses the\n[kraken/post-robot library](https://github.com/krakenjs/post-robot) to enrich\nthe communication with the assistant. Post-robot allows for asynchronous,\npromise-based request/response style behavior between the assistant and the\nassistant API.\n\nThe API requires that the client use the post-robot library. This\nassistant-client library is the easiest way to achieve this, and also adds a\nfair amount of 'sugar' to the process to improve developer productivity.\nDevelopers could, however, use post-robot directly in their own client\nimplementation.\n\n### Maana-Gateway Proxy Requirements\n\nThe Maana-Gateway service requires relative paths (paths relative to the root)\nin the assistant web application in order to proxy the application and its\ncontent. For create-react-apps, for instance, this means setting `\"homepage\"` to\n`\".\"` in the package.json file.\n\n## Singleton Instance\n\nThe client is exported as a singleton to avoid duplicate registration on event\nlisteners. You can import the instance like this:\n\n```js\nimport { AssistantAPIClient } from '@io-maana/q-assistant-client';\n```\n\nFunction calls can be made against the client instance like any other javascript\nobject. They are all async.\n\n```js\nconst workspace = await AssistantAPIClient.getWorkspace();\nconsole.log(\"Workspace:\", workspace)\n```\n\n## Dependencies\n\nPost-Robot\nhttps://github.com/krakenjs/post-robot\n\nPost-robot is used to provide a richer communication layer atop post-message.\n\n## Versioning\n\nThe Maana Q Assistant Client does not follow semantic versioning. Its versions\ntrack the releases of the Maana Q platform.\n\n## Changes in v3.3.0\n\n### Improvements\n\n- Full Typescript support with interfaces for all types used.\n- More comprehensive documentation.\n- Support for the Maana Q 3.3.0 data types.\n- More control over updating the Workspaces and other entities.\n- A collection of enums and constants for places where the API expects or\nreturns enumerated information.\n- Improved information returned to the Assistant when there is an error in an\nAPI call.\n\n### Deprecation\n\nThe following surface area is deprecated and should be updated as described.\n\n- AssistantAPIClient.moveKindsAndFunctions has been deprecated in favor of\ncalling update on the target Workspace to move the entities.\n- AssistantAPIClient.createFunction has been deprecated in favor of calling\ncreateFunction or update on the Workspace it belongs to.\n- AssistantAPIClient.updateFunction has been deprecated in favor of calling\nupdate on the Function object or the Workspace it belongs to.\n- AssistantAPIClient.deleteFunction has been deprecated in favor of calling\ndeleteFunction or update on the Workspace it belongs to.\n- AssistantAPIClient.getFunctionById has been deprecated in favor of calling\nAssistantAPIClient.getFunctionOfServiceByName.\n- AssistantAPIClient.getFunctionsById has been deprecated in favor of calling\nAssistantAPIClient.getFunctionsOfServiceByName.\n- AssistantAPIClient.getFunctionGraph and workspace.getFunctionGraph have been\ndeprecated in favor of calling workspace.getFunctionsByName.\n- AssistantAPIClient.createKind has been deprecated in favor of calling\ncreateKind or update on the Workspace it belongs to.\n- AssistantAPIClient.updateKind has been deprecated in favor of calling\nupdate on the Kind object or the Workspace it belongs to.\n- AssistantAPIClient.deleteKind has been deprecated in favor of calling\ndeleteKind or update on the Workspace it belongs to.\n- AssistantAPIClient.getKindById has been deprecated in favor of calling\nAssistantAPIClient.getKindOfServiceByName.\n- AssistantAPIClient.getKindsById has been deprecated in favor of calling\nAssistantAPIClient.getKindsOfServiceByName.\n- knowledgeGraph.offsetX, knowledgeGraph.offsetY, knowledgeGraph.zoom and\nknowledgeGraph.getNodes have been deprecated in favor of getting the information\noff of knowledgeGraph.graph.\n- knowledgeGraph.addNode and knowledgeGraph.removeNode have been deprecated in\nfavor of knowledgeGraph.update that gives you much more fine grained control.\n\n\n## Changes in v3.2.2\n\n### Improvements\n\n- Assistant State Management: WORKING, IDLE\n- Background Messaging/Eventing\n- Render Modes: BACKGROUND, DISPLAY\n- Expansion of Workspace object capabilities\n- Error Reporting\n- Repair Event\n- Plural versions of calls such as updateKind(s) to improve performance and\ndeveloper experience.\n- InventoryChanged diffing is fully granular in v3.2.2--limitations\nin v3.2.1 only fired the Function diff for changes in Function name.\n\n### Deprecation\n\nThe following surface area IS removed from the client in v3.2.2, and IS\ndeprecated in the API:\n\n- AssistantAPIClient.enableSelectionChangedNotification\n- AssistantAPIClient.disableSelectionChangedNotification\n- AssistantAPIClient.enableInventoryChangedNotification\n- AssistantAPIClient.disableInventoryChangedNotification\n\n## API Documentation\nMore information in the [Docs Folder](./docs/README.md)\n\n### Assistant Render Mode\n\nAn assistant's render mode refers to whether it is being displayed in a visible\nmanner to the user. As of v3.2.2, assistants are not closed when they are out of\nview. All assistants will be loaded and kept in `BACKGROUND` render mode until\nthey are placed in the assistant panel, at which point the `DISPLAY` render mode\nevent will be fired.\n\nNote: Assistants will receive all notifications/events while in BACKGROUND mode.\n\nDesign Consideration: It will be up to the developer to determine how state and\nresource use will be managed while an assistant is operating between BACKGROUND\nand DISPLAY modes.\n\n### Repair\nAssistants may get into situations where they are either out of sync with the\nMaana Q UI, or in a failure state. Assistants should be able to recover from\nthese states.\n\nThe repair event functionality added in v3.2.2 is designed to notify the\nassistant that it must repair itself. This could mean a resync with its\nresources on the workspace or externally or, for some assistants, nothing at\nall.\n\nWhen is repair triggered?\nEither manually by a user clicking 'repair workspace' under the assistant\ninventory panel, or upon a workspace clone event. An assistant will be expected\nto handle either scenario.\n\nPerformance Consideration:\nFor some assistants, repair might involve 'introspecting' and processing the\ncurrent workspace or Q system resources. This could be very resource intensive.\nMake sure you review this API guide to have an idea of what tools are available\nto get the best results. It's always a good idea to check performance of repair\non a large workspace and ensure necessary optimizations have been made.\n\nDesign Consideration:\nMake your workflows modular enough to be reused between repair and normal usage\nif possible.\n\nRecommended Usage: A repair process should be wrapped in the try/catch/finally flow shown in the `setAssistantState` API call to provide the user assistant-state and error updates as well as pause `inventoryChanged` notifications during repair (if the assistant has subscribed).\n\n## Troubleshooting Assistant Issues\n### Assistant root file has loaded, but not other content\n\nObserving in the browser's dev tools that some resources have loaded correctly\n(usually the root), but other's haven't (usually nested files or chunks), is\nindicative of a failure of Q Gateway to proxy due to not having a 'relative'\npath structure.\n\n### You are seeing post-robot `NO ACK` errors in the console.\n\nThese errors stem from a failed acknowledgement for a call either between the\nclient and the API or vice-versa. Here, this means that the web app 'window'\n(the assistant) cannot communicate with, or access, the 'window.parent'\n(Maana K-Portal) object.\n\nCommonly, these will stem from the 'window' (the assistant) not being loaded or\nin a loadable state, which means the API will not receive an acknowledgement\nwhen it fires an event.\n\nImproper CORS configuration is also a common culprit (also verify if using\ndocker or nginx that your proxying and networking is configured correctly to\nallow communication and to account for CORS).\n","readmeFilename":"README.md","gitHead":"846dfee073bc6949ec54d78f8338a2c56ecd7a47","_id":"@io-maana/q-assistant-client@3.3.0-beta.20","_nodeVersion":"14.21.1","_npmVersion":"6.14.17","dist":{"integrity":"sha512-T59m9Z3IPuyKLTVWIWKqbRhZ568qEywiL4baCMxS46TTOzgezXA94f5c8Qh7ZNmSl6tbsTmeFho7C3ytRLgyWQ==","shasum":"53938a5b9e4043b5c6f44472370ad7d53ff4585e","tarball":"https://registry.npmjs.org/@io-maana/q-assistant-client/-/q-assistant-client-3.3.0-beta.20.tgz","fileCount":83,"unpackedSize":265905,"signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIQDPlPgGKOggmB00XfZhXV0G4va4f5O/Qnl9Qhfo0rUWZgIgaE793tq8vNQtnLgMdAUpf/e02fBj9aSReVyqCh7jmkE="}],"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v4.10.10\r\nComment: https://openpgpjs.org\r\n\r\nwsFzBAEBCAAGBQJjvIeGACEJED1NWxICdlZqFiEECWMYAoorWMhJKdjhPU1b\r\nEgJ2Vmq8bA/+OwU7qr8YdHFVk5xZKmwhysNpL5Frk9J1UDPaNKXI2GQaRGqB\r\nVKZM9BtKdeNvgM4Np1he7Aekvso2LL4yctwuJp2RX9D+sB7UdPPCCb0ZqVu9\r\nU48b7kwWYPCvWSXObjgSu1qWSXsn9DiEo+4QMZXfW/Hlxbp7czff7KoM81uM\r\naIJurjGekqXNMopSpC4aM57b28YystVqnpGBswRdm+kOdR6hHlQq8xrdm37q\r\ncHK6+IoEu0i95am+cdGMPD72qYRoabZY/y9k/hjd6D2fUBfoO48oNi88Qun/\r\nhwiaHkWrGApjNVGJU058IAESpOO1aculpgQrUgD40Py4K2GWl5B2dziojie+\r\n5JF47BdIAqPZlMwQOhRzf4etlSReOSulc3+oPPLqRXqXGCRLk4ZlgGGoTf0R\r\n+f1GydxP4WoiXYYbcShJNKtYk3frF6KMGHDTlHk6Kr+MJNCLV5tAzKOI3DRW\r\nuKPJalzQFnt/e4z9MrTrfEBxl2Ce1nC78fx12hNGxMX0dyiWjOKR7teub8NG\r\nvLUr92OsFoSMnl0QsJyQIstZHDL/xFBrFqWghVVLX7wpY5gywhiwbsJ8gbdA\r\npHftQfOdCkq+wtrmnD7+w+a2O0QlLd8PwoLR7XINBzn1ydfDXmCCxyI0zKYv\r\nozrGKTiDqayUIBGB4yRXPPS0UjYRf3zW0M4=\r\n=g04z\r\n-----END PGP SIGNATURE-----\r\n"},"_npmUser":{"name":"teamcitymaana","email":"teamcity@maana.io"},"directories":{},"maintainers":[{"name":"witt3rd","email":"witt3rd@witt3rd.com"},{"name":"bzvetey","email":"bzvestey@gmail.com"},{"name":"abatyuk","email":"andrey@maana.io"},{"name":"rpovey","email":"rob@maana.io"},{"name":"teamcitymaana","email":"teamcity@maana.io"},{"name":"dlsmaana","email":"dlewissandy@maana.io"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/q-assistant-client_3.3.0-beta.20_1673299845955_0.7330139183130613"},"_hasShrinkwrap":false}},"time":{"created":"2019-08-14T19:52:10.309Z","3.2.1-beta.1":"2019-08-14T19:52:10.573Z","modified":"2023-01-09T21:30:46.359Z","3.2.1-beta.2":"2019-08-14T20:26:06.382Z","3.2.1-beta.3":"2019-08-14T20:39:41.354Z","3.2.1-beta.4":"2019-08-19T23:05:03.028Z","3.2.1-beta.5":"2019-09-05T17:20:21.497Z","3.2.1-beta.6":"2019-09-12T01:27:21.097Z","3.2.1-beta.7":"2019-09-13T20:15:48.093Z","3.2.1-beta.8":"2019-09-16T19:14:18.251Z","3.2.1-beta.9":"2019-10-01T20:24:50.325Z","3.2.1-beta.10":"2019-10-04T03:46:23.940Z","3.2.1-beta.11":"2019-10-04T19:44:10.494Z","3.2.1-beta.12":"2019-10-14T01:00:17.050Z","3.2.1-beta.13":"2019-10-14T16:13:55.296Z","3.2.1-beta.14":"2019-10-23T18:43:00.808Z","3.2.1-beta.15":"2019-11-06T21:48:34.605Z","3.2.2-beta.16":"2019-11-19T00:43:29.720Z","3.2.1":"2019-11-19T03:47:14.312Z","3.2.2-beta.17":"2019-11-26T03:09:47.107Z","3.2.2-beta.18":"2019-11-26T04:02:35.297Z","3.2.2-beta.19":"2019-12-17T19:23:05.439Z","3.2.2-beta.20":"2020-02-11T23:43:26.699Z","3.2.2-beta.21":"2020-02-12T17:15:15.438Z","3.2.2-beta.22":"2020-02-12T23:36:46.738Z","3.2.2-beta.23":"2020-02-27T00:35:18.116Z","3.2.2-beta.24":"2020-03-04T00:26:13.989Z","3.2.2-beta.25":"2020-03-06T00:27:21.739Z","3.2.2-beta.26":"2020-03-09T21:19:23.007Z","3.2.2-beta.27":"2020-03-10T21:00:39.910Z","3.2.2-beta.28":"2020-03-31T16:13:45.468Z","3.2.2-beta.29":"2020-03-31T16:36:31.711Z","3.2.2-beta.30":"2020-04-16T00:06:56.801Z","3.2.2-beta.31":"2020-05-11T02:59:29.066Z","3.2.2-beta.32":"2020-06-04T16:11:21.813Z","3.2.2-beta.33":"2020-06-05T17:45:15.382Z","3.2.2-beta.34":"2020-06-05T18:09:40.996Z","3.2.2":"2020-06-05T19:32:08.523Z","3.2.3-beta.35":"2020-06-05T21:24:07.047Z","3.2.3-beta.36":"2020-07-01T20:51:33.280Z","3.2.3-beta.37":"2020-07-07T23:04:59.993Z","3.2.3-beta.38":"2020-07-09T20:13:56.914Z","3.2.3":"2020-07-09T21:44:18.467Z","3.2.4-beta.39":"2020-07-09T22:33:54.925Z","3.3.0-beta.2":"2020-10-08T23:04:58.297Z","3.3.0-beta.4":"2020-10-16T16:25:57.445Z","3.3.0-beta.5":"2020-11-24T23:30:50.906Z","3.3.0-beta.6":"2021-01-29T17:08:39.373Z","3.3.0-beta.7":"2021-02-03T01:11:44.834Z","3.3.0-beta.8":"2021-02-04T00:42:46.753Z","3.3.0-beta.9":"2021-03-11T20:07:12.445Z","3.3.0-beta.10":"2021-03-23T23:42:46.001Z","3.3.0-beta.11":"2021-03-26T16:22:21.658Z","3.3.0-beta.13":"2021-04-16T17:11:42.077Z","3.3.0-beta.15":"2021-04-23T17:22:14.415Z","3.3.0-beta.16":"2021-04-27T23:09:45.701Z","3.3.0-beta.17":"2021-06-25T16:57:52.459Z","3.3.0-beta.18":"2021-06-28T19:24:15.873Z","3.2.4-beta.40":"2022-05-19T22:48:44.272Z","3.3.0-beta.20":"2023-01-09T21:30:46.181Z"},"maintainers":[{"name":"witt3rd","email":"witt3rd@witt3rd.com"},{"name":"bzvetey","email":"bzvestey@gmail.com"},{"name":"abatyuk","email":"andrey@maana.io"},{"name":"rpovey","email":"rob@maana.io"},{"name":"teamcitymaana","email":"teamcity@maana.io"},{"name":"dlsmaana","email":"dlewissandy@maana.io"}],"description":"JavaScript package to streamline communication between an assistant and the Maana Q Assistant API.","homepage":"https://github.com/maana-io/q-assistant-client#readme","keywords":["Maana","Q"],"repository":{"type":"git","url":"git+https://github.com/maana-io/q-assistant-client.git"},"author":{"name":"Logan Gore @ Maana.io"},"bugs":{"url":"https://github.com/maana-io/q-assistant-client/issues"},"license":"MIT","readme":"","readmeFilename":""}