diff --git a/.flowconfig b/.flowconfig index 4a58bdc..6dfba16 100644 --- a/.flowconfig +++ b/.flowconfig @@ -1,5 +1,5 @@ [ignore] - +project-env.json [include] [libs] diff --git a/.git-crypt/.gitattributes b/.git-crypt/.gitattributes new file mode 100644 index 0000000..17ef601 --- /dev/null +++ b/.git-crypt/.gitattributes @@ -0,0 +1,3 @@ +# Do not edit this file. To specify the files to encrypt, create your own +# .gitattributes file in the directory where your files are. +* !filter !diff diff --git a/.git-crypt/keys/default/0/871D573F10DE4F9D931FF4FE0F0B53D75ECDBC7A.gpg b/.git-crypt/keys/default/0/871D573F10DE4F9D931FF4FE0F0B53D75ECDBC7A.gpg new file mode 100644 index 0000000..2fdb606 Binary files /dev/null and b/.git-crypt/keys/default/0/871D573F10DE4F9D931FF4FE0F0B53D75ECDBC7A.gpg differ diff --git a/.vscode/settings.json b/.vscode/settings.json index 48bfad5..dc2794c 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -1,4 +1,7 @@ // Place your settings in this file to overwrite default and user settings. { - "prettier.trailingComma": "es5" + "prettier.trailingComma": "es5", + "prettier.singleQuote": false, + "prettier.tabWidth": 2, + "prettier.eslintIntegration": true } \ No newline at end of file diff --git a/package-lock.json b/package-lock.json index cc3ddc6..6f10fe4 100644 --- a/package-lock.json +++ b/package-lock.json @@ -15,6 +15,11 @@ "integrity": "sha1-0FVMIlZjbi9W58LlrRg/hZQo2B8=", "dev": true }, + "accepts": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.3.tgz", + "integrity": "sha1-w8p0NJOGSMPg2cHjKN1otiLChMo=" + }, "acorn": { "version": "4.0.13", "resolved": "https://registry.npmjs.org/acorn/-/acorn-4.0.13.tgz", @@ -108,6 +113,11 @@ "integrity": "sha1-3wEKoSh+Fku9pvlyOwqWoexBh6E=", "dev": true }, + "array-flatten": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz", + "integrity": "sha1-ml9pkFGx5wczKPKgCJaLZOopVdI=" + }, "array-unique": { "version": "0.2.1", "resolved": "https://registry.npmjs.org/array-unique/-/array-unique-0.2.1.tgz", @@ -355,11 +365,43 @@ "resolved": "https://registry.npmjs.org/bl/-/bl-1.1.2.tgz", "integrity": "sha1-/cqHGplxOqANGeO7ukHER4emU5g=" }, + "body-parser": { + "version": "1.17.2", + "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.17.2.tgz", + "integrity": "sha1-+IkqvI+eYn1Crtr7yma/WrmRBO4=", + "dependencies": { + "bytes": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/bytes/-/bytes-2.4.0.tgz", + "integrity": "sha1-fZcZb51br39pNeJZhVSe3SpsIzk=" + }, + "debug": { + "version": "2.6.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.7.tgz", + "integrity": "sha1-krrR9tBbu2u6Isyoi80OyJTChh4=" + }, + "iconv-lite": { + "version": "0.4.15", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.15.tgz", + "integrity": "sha1-/iZaIYrGpXz+hUkn6dBMGYJe3es=" + }, + "qs": { + "version": "6.4.0", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.4.0.tgz", + "integrity": "sha1-E+JtKK1rD/qpExLNO/cI7TUecjM=" + } + } + }, "boom": { "version": "2.10.1", "resolved": "https://registry.npmjs.org/boom/-/boom-2.10.1.tgz", "integrity": "sha1-OciRjO/1eZ+D+UkqhI9iWt0Mdm8=" }, + "bootbot": { + "version": "1.0.12", + "resolved": "https://registry.npmjs.org/bootbot/-/bootbot-1.0.12.tgz", + "integrity": "sha1-fQ2fysO/wLSBacQW7BGcBj+YLr0=" + }, "brace-expansion": { "version": "1.1.7", "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.7.tgz", @@ -553,12 +595,34 @@ "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=", "dev": true }, + "config": { + "version": "1.26.1", + "resolved": "https://registry.npmjs.org/config/-/config-1.26.1.tgz", + "integrity": "sha1-9kfOMsNF6AunOo6qeppLTlspDKE=", + "dependencies": { + "json5": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/json5/-/json5-0.4.0.tgz", + "integrity": "sha1-BUNS5MTIDIbAkjh31EneF2pzLI0=" + } + } + }, "configstore": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/configstore/-/configstore-1.4.0.tgz", "integrity": "sha1-w1eB0FAdJowlxUuLF/YkDopPsCE=", "dev": true }, + "content-disposition": { + "version": "0.5.2", + "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.2.tgz", + "integrity": "sha1-DPaLud318r55YcOoUXjLhdunjLQ=" + }, + "content-type": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.2.tgz", + "integrity": "sha1-t9ETrueo3Se9IRM8TcJSnfFyHu0=" + }, "content-type-parser": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/content-type-parser/-/content-type-parser-1.0.1.tgz", @@ -571,6 +635,16 @@ "integrity": "sha1-ms1whRxtXf3ZPZKC5e35SgP/RrU=", "dev": true }, + "cookie": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.3.1.tgz", + "integrity": "sha1-5+Ch+e9DtMi6klxcWpboBtFoc7s=" + }, + "cookie-signature": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz", + "integrity": "sha1-4wOogrNCzD7oylE6eZmXNNqzriw=" + }, "core-js": { "version": "2.4.1", "resolved": "https://registry.npmjs.org/core-js/-/core-js-2.4.1.tgz", @@ -700,11 +774,21 @@ "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", "integrity": "sha1-3zrhmayt+31ECqrgsp4icrJOxhk=" }, + "depd": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/depd/-/depd-1.1.0.tgz", + "integrity": "sha1-4b2Cxqq2ztlluXuIsX7T5SjKGMM=" + }, "deprecate": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/deprecate/-/deprecate-1.0.0.tgz", "integrity": "sha1-ZhSQ7SQokWpsiIPYg05WRvTkpKg=" }, + "destroy": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.0.4.tgz", + "integrity": "sha1-l4hXRCxEdJ5CBmE+N5RiBYJqvYA=" + }, "detect-indent": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/detect-indent/-/detect-indent-4.0.0.tgz", @@ -756,12 +840,27 @@ "resolved": "https://registry.npmjs.org/ecdsa-sig-formatter/-/ecdsa-sig-formatter-1.0.9.tgz", "integrity": "sha1-S8kmJ07Dtau1AW5+HWCSGsJisqE=" }, + "ee-first": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", + "integrity": "sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0=" + }, "elegant-spinner": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/elegant-spinner/-/elegant-spinner-1.0.1.tgz", "integrity": "sha1-2wQ1IcldfjA/2PNFvtwzSc+wcp4=", "dev": true }, + "encodeurl": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.1.tgz", + "integrity": "sha1-eePVhlU0aQn+bw9Fpd5oEDspTSA=" + }, + "encoding": { + "version": "0.1.12", + "resolved": "https://registry.npmjs.org/encoding/-/encoding-0.1.12.tgz", + "integrity": "sha1-U4tm8+5izRq1HsMjgp0flIDHS+s=" + }, "end-of-stream": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.0.0.tgz", @@ -794,6 +893,11 @@ "integrity": "sha1-oIzd6EzNvzTQJ6FFG8kdS80ophM=", "dev": true }, + "escape-html": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", + "integrity": "sha1-Aljq5NPQwJdN4cFpGI7wBR0dGYg=" + }, "escape-string-regexp": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", @@ -838,12 +942,22 @@ "integrity": "sha1-Cr9PHKpbyx96nYrMbepPqqBLrJs=", "dev": true }, + "etag": { + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.0.tgz", + "integrity": "sha1-b2Ma7zNtbEY2K1F2QETOIWvjwFE=" + }, "event-stream": { "version": "3.3.4", "resolved": "https://registry.npmjs.org/event-stream/-/event-stream-3.3.4.tgz", "integrity": "sha1-SrTJoPWlTbkzi0w02Gv86PSzVXE=", "dev": true }, + "eventemitter3": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-1.2.0.tgz", + "integrity": "sha1-HIaZHYFq0eUEdQ5zh0Ik7PO+xQg=" + }, "exec-sh": { "version": "0.2.0", "resolved": "https://registry.npmjs.org/exec-sh/-/exec-sh-0.2.0.tgz", @@ -874,6 +988,23 @@ "integrity": "sha1-opnv/TNf4nIeuujiV+x5ZE/IUzc=", "dev": true }, + "express": { + "version": "4.15.3", + "resolved": "https://registry.npmjs.org/express/-/express-4.15.3.tgz", + "integrity": "sha1-urZdDwOqgMNYQIly/HAPkWlEtmI=", + "dependencies": { + "debug": { + "version": "2.6.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.7.tgz", + "integrity": "sha1-krrR9tBbu2u6Isyoi80OyJTChh4=" + }, + "qs": { + "version": "6.4.0", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.4.0.tgz", + "integrity": "sha1-E+JtKK1rD/qpExLNO/cI7TUecjM=" + } + } + }, "extend": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.1.tgz", @@ -940,6 +1071,18 @@ "integrity": "sha1-ULd9/X5Gm8dJJHCWNpn+eoSFpyM=", "dev": true }, + "finalhandler": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.0.3.tgz", + "integrity": "sha1-70fneVDpmXgOhgIqVg4yF+DQzIk=", + "dependencies": { + "debug": { + "version": "2.6.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.7.tgz", + "integrity": "sha1-krrR9tBbu2u6Isyoi80OyJTChh4=" + } + } + }, "find-parent-dir": { "version": "0.3.0", "resolved": "https://registry.npmjs.org/find-parent-dir/-/find-parent-dir-0.3.0.tgz", @@ -1003,6 +1146,16 @@ } } }, + "forwarded": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.1.0.tgz", + "integrity": "sha1-Ge+YdMSuHCl7zweP3mOgm2aoQ2M=" + }, + "fresh": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.0.tgz", + "integrity": "sha1-9HTKXmqSRtb9jglTz6m5yAWvp44=" + }, "from": { "version": "0.1.7", "resolved": "https://registry.npmjs.org/from/-/from-0.1.7.tgz", @@ -1878,6 +2031,11 @@ "integrity": "sha1-eb96eF6klf5mFl5zQVPzY/9UN9o=", "dev": true }, + "http-errors": { + "version": "1.6.1", + "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.6.1.tgz", + "integrity": "sha1-X4uO2YrKVFZWv1cplzh/kEpyIlc=" + }, "http-signature": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/http-signature/-/http-signature-1.1.1.tgz", @@ -1900,8 +2058,7 @@ "iconv-lite": { "version": "0.4.13", "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.13.tgz", - "integrity": "sha1-H4irpKsLFQjoMSrMOTRfNumS4vI=", - "dev": true + "integrity": "sha1-H4irpKsLFQjoMSrMOTRfNumS4vI=" }, "ignore-by-default": { "version": "1.0.1", @@ -1993,6 +2150,11 @@ "integrity": "sha1-EEqOSqym09jNFXqO+L+rLXo//bY=", "dev": true }, + "ipaddr.js": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.3.0.tgz", + "integrity": "sha1-HgOlL9rYOou7KyXL9JmLTP/NPew=" + }, "is-arrayish": { "version": "0.2.1", "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", @@ -2126,8 +2288,7 @@ "is-stream": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-1.1.0.tgz", - "integrity": "sha1-EtSj3U5o4Lec6428hBc66A2RykQ=", - "dev": true + "integrity": "sha1-EtSj3U5o4Lec6428hBc66A2RykQ=" }, "is-typedarray": { "version": "1.0.0", @@ -2826,18 +2987,38 @@ "integrity": "sha1-5WqpTEyAVaFkBKBnS3jyFffI4ZQ=", "dev": true }, + "media-typer": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", + "integrity": "sha1-hxDXrwqmJvj/+hzgAWhUUmMlV0g=" + }, "merge": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/merge/-/merge-1.2.0.tgz", "integrity": "sha1-dTHjnUlJwoGma4xabgJl6LBYlNo=", "dev": true }, + "merge-descriptors": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.1.tgz", + "integrity": "sha1-sAqqVW3YtEVoFQ7J0blT8/kMu2E=" + }, + "methods": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz", + "integrity": "sha1-VSmk1nZUE07cxSZmVoNbD4Ua/O4=" + }, "micromatch": { "version": "2.3.11", "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-2.3.11.tgz", "integrity": "sha1-hmd8l9FyCzY0MdBNDRUpO9OMFWU=", "dev": true }, + "mime": { + "version": "1.3.4", + "resolved": "https://registry.npmjs.org/mime/-/mime-1.3.4.tgz", + "integrity": "sha1-EV+eO2s9rylZmDyzjxSaLUDrXVM=" + }, "mime-db": { "version": "1.27.0", "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.27.0.tgz", @@ -2904,6 +3085,11 @@ "integrity": "sha1-Sr6/7tdUHywnrPspvbvRXI1bpPc=", "dev": true }, + "negotiator": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.1.tgz", + "integrity": "sha1-KzJxhOiZIQEXeyhWP7XnECrNDKk=" + }, "nested-error-stacks": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/nested-error-stacks/-/nested-error-stacks-1.0.2.tgz", @@ -2921,6 +3107,11 @@ "integrity": "sha1-/ZGOQSdpv4xEgFEjgjOECyr/FqE=", "dev": true }, + "node-fetch": { + "version": "1.7.1", + "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-1.7.1.tgz", + "integrity": "sha512-j8XsFGCLw79vWXkZtMSmmLaOk9z5SQ9bV/tkbZVCqvgwzrjAGq66igobLofHtF63NvMTp2WjytpsNTGKa+XRIQ==" + }, "node-int64": { "version": "0.4.0", "resolved": "https://registry.npmjs.org/node-int64/-/node-int64-0.4.0.tgz", @@ -3020,6 +3211,11 @@ "integrity": "sha1-Gpx0SCnznbuFjHbKNXmuKlTr0fo=", "dev": true }, + "on-finished": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.3.0.tgz", + "integrity": "sha1-IPEzZIGwg811M3mSoWlxqi2QaUc=" + }, "once": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", @@ -3086,8 +3282,7 @@ "os-homedir": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/os-homedir/-/os-homedir-1.0.2.tgz", - "integrity": "sha1-/7xJiDNuDoM94MFox+8VISGqf7M=", - "dev": true + "integrity": "sha1-/7xJiDNuDoM94MFox+8VISGqf7M=" }, "os-locale": { "version": "1.4.0", @@ -3161,6 +3356,11 @@ "integrity": "sha1-m387DeMr543CQBsXVzzK8Pb1nZQ=", "dev": true }, + "parseurl": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.1.tgz", + "integrity": "sha1-yKuMkiO6NIiKpkopeyiFO+wY2lY=" + }, "path-exists": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz", @@ -3185,6 +3385,11 @@ "integrity": "sha1-PBrfhx6pzWyUMbbqK9dKD/BVxME=", "dev": true }, + "path-to-regexp": { + "version": "0.1.7", + "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.7.tgz", + "integrity": "sha1-32BBeABfUi8V60SQ5yR6G/qmf4w=" + }, "path-type": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/path-type/-/path-type-1.1.0.tgz", @@ -3294,6 +3499,11 @@ "integrity": "sha1-FZ+wYZPTIAP0s2kd0uwaY0qoDR0=", "dev": true }, + "proxy-addr": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-1.1.4.tgz", + "integrity": "sha1-J+VF9pYKRKYn2bREZ+NcG2tM4vM=" + }, "prr": { "version": "0.0.0", "resolved": "https://registry.npmjs.org/prr/-/prr-0.0.0.tgz", @@ -3353,6 +3563,28 @@ "integrity": "sha1-EQ3Kv/OX6dz/fAeJzMCkmt8exbs=", "dev": true }, + "range-parser": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.0.tgz", + "integrity": "sha1-9JvmtIeJTdxA3MlKMi9hEJLgDV4=" + }, + "raw-body": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.2.0.tgz", + "integrity": "sha1-mUl2z2pQlqQRYoQEkvC9xdbn+5Y=", + "dependencies": { + "bytes": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/bytes/-/bytes-2.4.0.tgz", + "integrity": "sha1-fZcZb51br39pNeJZhVSe3SpsIzk=" + }, + "iconv-lite": { + "version": "0.4.15", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.15.tgz", + "integrity": "sha1-/iZaIYrGpXz+hUkn6dBMGYJe3es=" + } + } + }, "rc": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/rc/-/rc-1.2.1.tgz", @@ -3601,6 +3833,23 @@ "integrity": "sha1-S7uEN8jTfksM8aaP1ybsbWRdbTY=", "dev": true }, + "send": { + "version": "0.15.3", + "resolved": "https://registry.npmjs.org/send/-/send-0.15.3.tgz", + "integrity": "sha1-UBP5+ZAj31DRvZiSwZ4979HVMwk=", + "dependencies": { + "debug": { + "version": "2.6.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.7.tgz", + "integrity": "sha1-krrR9tBbu2u6Isyoi80OyJTChh4=" + } + } + }, + "serve-static": { + "version": "1.12.3", + "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.12.3.tgz", + "integrity": "sha1-n0uhni8wMMVH+K+ZEHg47DjVseI=" + }, "set-blocking": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz", @@ -3613,6 +3862,11 @@ "integrity": "sha1-SysbJ+uAip+NzEgaWOXlb1mfP2E=", "dev": true }, + "setprototypeof": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.0.3.tgz", + "integrity": "sha1-ZlZ+NwQ+608E2RvWWMDL77VbjgQ=" + }, "shebang-command": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-1.2.0.tgz", @@ -3720,6 +3974,11 @@ "integrity": "sha1-15fhtVHKemOd7AI33G60u5vhfTU=", "dev": true }, + "statuses": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.3.1.tgz", + "integrity": "sha1-+vUbnrdKrvOzrPStX2Gr8ky3uT4=" + }, "stream-combiner": { "version": "0.0.4", "resolved": "https://registry.npmjs.org/stream-combiner/-/stream-combiner-0.0.4.tgz", @@ -3983,6 +4242,11 @@ "resolved": "https://registry.npmjs.org/type-detect/-/type-detect-1.0.0.tgz", "integrity": "sha1-diIXzAbbJY7EiQihKY6LlRIejqI=" }, + "type-is": { + "version": "1.6.15", + "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.15.tgz", + "integrity": "sha1-yrEPtJCeRByChC6v4a1kbIGARBA=" + }, "uglify-js": { "version": "2.8.28", "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-2.8.28.tgz", @@ -4017,6 +4281,11 @@ "integrity": "sha1-7Mo6A+VrmvFzhbqsgSrIO5lKli8=", "dev": true }, + "unpipe": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", + "integrity": "sha1-sr9O6FFKrmFltIF4KdIbLvSZBOw=" + }, "update-notifier": { "version": "0.5.0", "resolved": "https://registry.npmjs.org/update-notifier/-/update-notifier-0.5.0.tgz", @@ -4036,6 +4305,11 @@ "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=" }, + "utils-merge": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.0.tgz", + "integrity": "sha1-ApT7kiu5N1FTVBxPcJYjHyh8ivg=" + }, "uuid": { "version": "2.0.3", "resolved": "https://registry.npmjs.org/uuid/-/uuid-2.0.3.tgz", @@ -4054,6 +4328,11 @@ "integrity": "sha1-KAS6vnEq0zeUWaz74kdGqywwP7w=", "dev": true }, + "vary": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.1.tgz", + "integrity": "sha1-Z1Neu2lMHVIldFeYRmUyP1h+jTc=" + }, "verror": { "version": "1.3.6", "resolved": "https://registry.npmjs.org/verror/-/verror-1.3.6.tgz", diff --git a/package.json b/package.json index a5b3e23..c41a363 100644 --- a/package.json +++ b/package.json @@ -23,6 +23,7 @@ "testEnvironment": "node" }, "dependencies": { + "bootbot": "^1.0.12", "chalk": "^1.1.3", "dotenv": "^4.0.0", "flow": "^0.2.3", @@ -63,4 +64,4 @@ "engines": { "node": "7.8.0" } -} +} \ No newline at end of file diff --git a/src/.gitattributes b/src/.gitattributes new file mode 100644 index 0000000..b005cf6 --- /dev/null +++ b/src/.gitattributes @@ -0,0 +1 @@ +config.json filter=git-crypt diff=git-crypt \ No newline at end of file diff --git a/src/chatbot/api.js b/src/chatbot/api.js new file mode 100644 index 0000000..55f281d --- /dev/null +++ b/src/chatbot/api.js @@ -0,0 +1,6 @@ +// this file will contain the api methods that the bootbot +// will execute on receiving a communication from various senders +// these will be of type event listener, where the user on Facebook has +// attempted to chat with the bot, or +// they will be called from the coinbot logic its self, sending automated +// user notifications diff --git a/src/chatbot/calls.js b/src/chatbot/calls.js new file mode 100644 index 0000000..9d25d17 --- /dev/null +++ b/src/chatbot/calls.js @@ -0,0 +1,3 @@ +// this file will contain the calls that the coinbot notification area +// will make (actual api queries), containing http requests to the +// locally running bootbot server diff --git a/src/chatbot/constants.js b/src/chatbot/constants.js new file mode 100644 index 0000000..786add8 --- /dev/null +++ b/src/chatbot/constants.js @@ -0,0 +1,7 @@ +module.exports = { + CONSENT_DENY: "CONSENT_DENY", + CONSENT_ACCEPT: "CONSENT_ACCEPT", + COINBOT_RELAX: "COINBOT_RELAX", + COINBOT_FEEDBACK: "COINBOT_FEEDBACK", + COINBOT_DONATE: "COINBOT_DONATE" +}; diff --git a/src/chatbot/conversations.js b/src/chatbot/conversations.js new file mode 100644 index 0000000..35f733e --- /dev/null +++ b/src/chatbot/conversations.js @@ -0,0 +1,82 @@ +const { + COINBOT_RELAX, + COINBOT_UPGRADE, + COINBOT_FEEDBACK, + CONSENT_ACCEPT, + CONSENT_DENY +} = require("./constants"); + +function askForConsent(chat) { + chat.say("I don't think we have met before!"); + chat.say( + "My name is Coinbot 🤖 I am here to help you keep an eye on cryptocurrency prices." + ); + chat.say( + "I will let you know if the market is like 📈 or like 📉 according to the GDAX exchange." + ); + chat.say({ + text: "Do you want to me to keep you up to date via Messenger?", + buttons: [ + { + type: "postback", + title: "👍", + payload: CONSENT_ACCEPT + }, + { + type: "postback", + title: "👎", + payload: CONSENT_DENY + } + ] + }); +} + +function handleConsentDeny(chat) { + chat.say( + "Hmm, sorry to hear this. Chat with me any time to change your mind! 👋" + ); +} + +function handleConsentAccept(chat) { + chat.say("Super excited to have you onboard! 😎"); + chat.say("I will let you know of significant coin moovement! Enjoy!"); + chat.say( + "If you need help anytime, just type 'help', or 'info' if you want to learn about me." + ); + chat.say( + "Last thing... If you think I do a good job, you can learn how to support my growth by typing 'premium' ❤️ " + ); + chat.say("Hope to hear from you soon! 🙇"); +} + +function offerBasicHelp(chat) { + chat.say( + "Type 'help' if you need something specific or 'info' for more info." + ); + chat.say({ + text: "Or pick the options below:", + buttons: [ + { + type: "postback", + title: "Take a break", + payload: COINBOT_RELAX + }, + { + type: "postback", + title: "Give feedback", + payload: COINBOT_FEEDBACK + }, + { + type: "postback", + title: "Go Premium", + payload: COINBOT_UPGRADE + } + ] + }); +} + +module.exports = { + askForConsent, + handleConsentDeny, + handleConsentAccept +}; diff --git a/src/chatbot/index.js b/src/chatbot/index.js new file mode 100644 index 0000000..92d9d47 --- /dev/null +++ b/src/chatbot/index.js @@ -0,0 +1,115 @@ +const BootBot = require("bootbot"); +const config = require("../config.json"); +const bot = new BootBot({ + accessToken: config.facebook.access_token, + verifyToken: config.facebook.verify_token, + appSecret: config.facebook.app_secret +}); + +const { + askForConsent, + handleConsentDeny, + handleConsentAccept, + offerBasicHelp +} = require("./conversations"); + +const { + CONSENT_DENY, + CONSENT_ACCEPT, + COINBOT_RELAX, + COINBOT_FEEDBACK, + COINBOT_UPGRADE +} = require("./constants"); + +// mock dummy db, need to consider DB solution. +class Users { + get() {} + create() {} +} + +// will uncomment later and do in another branch +// class Events { +// store(event) {}; +// fire(event) { +// this.store({ +// ...event, +// timestamp: new Date.now(), +// }); +// }; +// } + +// message handler +bot.on("message", async (payload, chat) => { + const { message, sender } = payload; + const { user } = await chat.getUserProfile(); + + chat.say(`Hello, ${user.first_name}!`); + + const store = Users.get(sender.id); + + if (store) { + // Events.fire({ + // user: { user, id: sender.id }, + // category: "message", + // event: "message from member", + // }); + + chat.say("Good to hear from you again. 😌"); + // offer basic help + // check store id, if premium (paying), offer settings + offerBasicHelp(chat); + } else { + // user has not registered, ask them to create a unique identifier + askForConsent(chat); + } +}); + +// postback handler +bot.on("postback", async (payload, chat) => { + const { user } = await chat.getUserProfile(); + // Events.fire({ + // user: { user, id: sender.id }, + // category: "message", + // event: "message from member", + // }); + + switch (payload) { + case CONSENT_DENY: + handleConsentDeny(chat); + return; + case CONSENT_ACCEPT: + handleConsentAccept(chat); + Users.create({ + id: payload.sender.id + }); + return; + case COINBOT_UPGRADE: + chat.say("Upgrade coming soon..."); + // payment conversation + // update user as paying + return; + case COINBOT_RELAX: + chat.say("Relax coming soon..."); + // update user to not get notified + // 1 hour, 1 day, 1 week, custom + return; + case COINBOT_FEEDBACK: + chat.say("Feedback coming soon..."); + // accept feedback message + // offer a smiley face system + // plus text + return; + } +}); + +bot.hear(["info"], (payload, chat) => { + chat.say("more info coming soon..."); +}); +bot.hear(["premium"], (payload, chat) => { + chat.say("premium coming soon..."); +}); +bot.hear(["help"], (payload, chat) => { + chat.say("help coming soon..."); +}); + +bot.start(); diff --git a/src/chatbot/legal.txt b/src/chatbot/legal.txt new file mode 100644 index 0000000..c216ac8 --- /dev/null +++ b/src/chatbot/legal.txt @@ -0,0 +1,4 @@ +i will only be using your facebook profile to say your name. + +your unique and unidentifiable id (based on what your sender id is within facebook) will used to store your personal preferences in the app +- whether the bot can chat with you or not \ No newline at end of file diff --git a/src/config.json b/src/config.json new file mode 100644 index 0000000..cc7f21a Binary files /dev/null and b/src/config.json differ diff --git a/src/index.js b/src/index.js index 257d4b3..67221e9 100644 --- a/src/index.js +++ b/src/index.js @@ -3,12 +3,12 @@ const moment = require("moment"); const logIt = require("./helpers/logger.js"); const { stdNum } = require("./helpers/math.js"); -const { twilioActivated, notifyUserViaText } = require("./notifier"); +const { twilioActivated, notifyUserViaText } = require("./twilio"); const { FIFTEEN_MINS_MS } = require("./helpers/constants.js"); -const { getAccount } = require("./core/account"); -const { getProductSnapshot, get24HourStats } = require("./core/product"); -const { shouldPurchase, shouldSell } = require("./core/advisor"); +const { getAccount } = require("./logic/account"); +const { getProductSnapshot, get24HourStats } = require("./logic/product"); +const { shouldPurchase, shouldSell } = require("./logic/advisor"); const DEFAULT_COINS = ["BTC", "ETH", "LTC"]; diff --git a/src/core/account/index.js b/src/logic/account/index.js similarity index 100% rename from src/core/account/index.js rename to src/logic/account/index.js diff --git a/src/core/account/index.test.js b/src/logic/account/index.test.js similarity index 100% rename from src/core/account/index.test.js rename to src/logic/account/index.test.js diff --git a/src/core/advisor/index.js b/src/logic/advisor/index.js similarity index 100% rename from src/core/advisor/index.js rename to src/logic/advisor/index.js diff --git a/src/core/advisor/index.test.js b/src/logic/advisor/index.test.js similarity index 100% rename from src/core/advisor/index.test.js rename to src/logic/advisor/index.test.js diff --git a/src/core/client.js b/src/logic/client.js similarity index 100% rename from src/core/client.js rename to src/logic/client.js diff --git a/src/core/product/index.js b/src/logic/product/index.js similarity index 100% rename from src/core/product/index.js rename to src/logic/product/index.js diff --git a/src/notifier/index.js b/src/twilio/index.js similarity index 100% rename from src/notifier/index.js rename to src/twilio/index.js