├── .eslintignore ├── .eslintrc ├── .gitattributes ├── .gitignore ├── .npmignore ├── LICENSE.md ├── README.md ├── package-lock.json ├── package.json ├── tests └── server.js └── yametrika.js /.eslintignore: -------------------------------------------------------------------------------- 1 | .* 2 | node_modules/** 3 | -------------------------------------------------------------------------------- /.eslintrc: -------------------------------------------------------------------------------- 1 | { 2 | "parserOptions": { 3 | "ecmaVersion": 6 4 | }, 5 | "rules": { 6 | "semi": [2, "always"], 7 | "quotes": [2, "single"], 8 | "no-console": [0], 9 | "curly": [ 10 | 2, 11 | "all" 12 | ], 13 | "keyword-spacing": [ 14 | 2, 15 | {} 16 | ], 17 | "space-before-function-paren": [ 18 | 2, 19 | "never" 20 | ], 21 | "array-bracket-spacing": [ 22 | 2, 23 | "never", 24 | { 25 | "singleValue": true 26 | } 27 | ], 28 | "key-spacing": [ 29 | 2, 30 | { 31 | "beforeColon": false, 32 | "afterColon": true 33 | } 34 | ], 35 | "space-unary-ops": [ 36 | 2, 37 | { 38 | "words": false, 39 | "nonwords": false 40 | } 41 | ], 42 | "space-infix-ops": 2, 43 | "no-with": 2, 44 | "no-multiple-empty-lines": 2, 45 | "brace-style": [ 46 | 2, 47 | "1tbs", 48 | { 49 | "allowSingleLine": true 50 | } 51 | ], 52 | "eol-last": 2, 53 | "indent": [ 54 | 2, 55 | 4, 56 | { 57 | "SwitchCase": 1 58 | } 59 | ], 60 | "valid-jsdoc": [ 61 | 2, 62 | { 63 | "prefer": { 64 | "return": "returns" 65 | }, 66 | "requireParamDescription": false, 67 | "requireReturnDescription": false, 68 | "requireReturn": false 69 | } 70 | ] 71 | }, 72 | "env": { 73 | "node": true, 74 | "mocha": true 75 | }, 76 | "extends": "eslint:recommended" 77 | } 78 | -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | *.js eol=lf 2 | *.md eol=lf 3 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules/ 2 | -------------------------------------------------------------------------------- /.npmignore: -------------------------------------------------------------------------------- 1 | tests/ -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | ## Лицензия 2 | The MIT License (MIT) 3 | 4 | © 2021 Денис Селезнев, 5 | 6 | Данная лицензия разрешает лицам, получившим копию данного программного обеспечения и сопутствующей документации (в дальнейшем именуемыми «Программное Обеспечение»), безвозмездно использовать Программное Обеспечение без ограничений, включая неограниченное право на использование, копирование, изменение, добавление, публикацию, распространение, сублицензирование и/или продажу копий Программного Обеспечения, также как и лицам, которым предоставляется данное Программное Обеспечение, при соблюдении следующих условий: 7 | 8 | Указанное выше уведомление об авторском праве и данные условия должны быть включены во все копии или значимые части данного Программного Обеспечения. 9 | 10 | ДАННОЕ ПРОГРАММНОЕ ОБЕСПЕЧЕНИЕ ПРЕДОСТАВЛЯЕТСЯ «КАК ЕСТЬ», БЕЗ КАКИХ-ЛИБО ГАРАНТИЙ, ЯВНО ВЫРАЖЕННЫХ ИЛИ ПОДРАЗУМЕВАЕМЫХ, ВКЛЮЧАЯ, НО НЕ ОГРАНИЧИВАЯСЬ ГАРАНТИЯМИ ТОВАРНОЙ ПРИГОДНОСТИ, СООТВЕТСТВИЯ ПО ЕГО КОНКРЕТНОМУ НАЗНАЧЕНИЮ И ОТСУТСТВИЯ НАРУШЕНИЙ ПРАВ. НИ В КАКОМ СЛУЧАЕ АВТОРЫ ИЛИ ПРАВООБЛАДАТЕЛИ НЕ НЕСУТ ОТВЕТСТВЕННОСТИ ПО ИСКАМ О ВОЗМЕЩЕНИИ УЩЕРБА, УБЫТКОВ ИЛИ ДРУГИХ ТРЕБОВАНИЙ ПО ДЕЙСТВУЮЩИМ КОНТРАКТАМ, ДЕЛИКТАМ ИЛИ ИНОМУ, ВОЗНИКШИМ ИЗ, ИМЕЮЩИМ ПРИЧИНОЙ ИЛИ СВЯЗАННЫМ С ПРОГРАММНЫМ ОБЕСПЕЧЕНИЕМ ИЛИ ИСПОЛЬЗОВАНИЕМ ПРОГРАММНОГО ОБЕСПЕЧЕНИЯ ИЛИ ИНЫМИ ДЕЙСТВИЯМИ С ПРОГРАММНЫМ ОБЕСПЕЧЕНИЕМ. 11 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Серверное отслеживание посетителей с помощью Яндекс.Метрики для Node.js 2 | [![NPM version](https://img.shields.io/npm/v/yametrika.svg)](https://www.npmjs.com/package/yametrika) 3 | [![NPM Downloads](https://img.shields.io/npm/dm/yametrika.svg?style=flat)](https://www.npmjs.org/package/yametrika) 4 | [![install size](https://packagephobia.com/badge?p=yametrika)](https://packagephobia.com/result?p=yametrika) 5 | 6 | 7 | В некоторых случаях требуется отслеживать действия на стороне сервера. 8 | 9 | Например: 10 | + Слежка за поисковыми роботами 11 | + Редиректы 12 | + Загрузка файлов 13 | + Страницы с ошибками (403, 404, 500) 14 | + RSS 15 | + Время выполнения скриптов 16 | + Время запросов к базам данных 17 | + Треккинг AJAX-запросов 18 | + и пр. 19 | 20 | ## Возможности 21 | + Загрузка страницы - hit() 22 | + Внешняя ссылка - extLink() 23 | + Загрузка файла - file() 24 | + Параметры визита - params() 25 | + Неотказ - notBounce() 26 | 27 | ## Настройки счётчика Метрики 28 | **В настройках счётчика во вкладке «Фильтры» / «Фильтрация роботов» необходимо выбрать опцию «Учитывать посещения всех роботов». В противном случае, статистика собираться не будет.** 29 | 30 | ## Ограничения 31 | Отчёты, которые будут недоступны в Метрике при серверной отправки: 32 | + Половозрастная структура 33 | + Пол и возраст 34 | + Разрешения дисплеев 35 | + Версия Flash 36 | + Вебвизор, аналитика форм 37 | + Карта кликов 38 | 39 | Уникальные посетители считаются по user agent'у и IP-адресу. 40 | 41 | ## Установка 42 | `npm install yametrika` 43 | 44 | ## Использование 45 | ```js 46 | var http = require('http'); 47 | 48 | // Создаем счётчик, 12345 — номер счётчика 49 | var counter = require('yametrika').counter({id: 12345}); 50 | 51 | http.createServer(function (req, res) { 52 | res.writeHead(200, {'Content-Type': 'text/plain'}); 53 | res.end('okay'); 54 | 55 | // Заполняем счётчик данными (referer, ip и ua) из запроса к серверу. 56 | counter.req(req); 57 | 58 | // Страница https://example.com, с заголовком 'Main page' 59 | // переход был с реферером https://othersite.com 60 | counter.hit('https://example.com', 'Main page', 'https://othersite.com'); 61 | }).listen(8080); 62 | ``` 63 | 64 | ## Отправка хита 65 | ```js 66 | /** 67 | * @param {string} pageUrl - Адрес страницы. 68 | * @param {string} [pageTitle] - Заголовок страницы. 69 | * @param {string} [pageRef] - Реферер страницы. 70 | * @param {Object} [userParams] - Параметры визитов. 71 | * @param {string} [ut] - Для запрета индексирования 'noindex' 72 | * 73 | * @returns {Object} this 74 | */ 75 | counter.hit('https://mysite.org', 'Main page', 'https://google.com/...'); 76 | 77 | // С запретом на индексирование и параметрами визитов 78 | counter.hit('https://mysite.org', 'Main page', 'https://google.com/...', {level1: {level2: 1}}, 'noindex'); 79 | ``` 80 | 81 | ## Достижение цели 82 | ```js 83 | /** 84 | * @param {string} target - Название цели. 85 | * @param {Object} [userParams] - Параметры визитов. 86 | * 87 | * @returns {Object} this 88 | */ 89 | counter.hit(); 90 | counter.reachGoal('goalName'); 91 | 92 | // или 93 | 94 | // С параметрами визитов 95 | counter.hit(); 96 | counter.reachGoal('goalName', {level1: {level2: 1}}); 97 | ``` 98 | Вызов метода `hit()` перед `reachGoal()` необходим для корректной привязки цели к визиту. 99 | 100 | ## Внешняя ссылка 101 | ```js 102 | /** 103 | * @param {string} url - Адрес страницы. 104 | * @param {string} [title] - Заголовок страницы. 105 | * 106 | * @returns {Object} this 107 | */ 108 | counter.extLink('https://nodejs.org'); 109 | ``` 110 | 111 | ## Загрузка файла 112 | ```js 113 | /** 114 | * @param {string} file - Ссылка на файл. 115 | * @param {string} [title] - Заголовок страницы. 116 | * 117 | * @returns {Object} this 118 | */ 119 | counter.file('https://mysite.org/secret.zip'); 120 | ``` 121 | 122 | ## Параметры визитов 123 | ```js 124 | /** 125 | * @param {...*} data - Параметры визитов. 126 | * 127 | * @returns {Object} this 128 | */ 129 | counter.params({level1: {level2: {level3: 1}}}); 130 | 131 | // или 132 | counter.params('level1', 'level2', 'level3', 1); 133 | ``` 134 | 135 | ## Не отказ 136 | ```js 137 | /** 138 | * @returns {Object} this 139 | */ 140 | counter.notBounce(); 141 | ``` 142 | 143 | ## Полезные ссылки 144 | + [Версия для PHP](https://github.com/hcodes/server_yametrika/) 145 | + [Помощь Яндекс.Метрики](https://yandex.ru/support/metrika/) 146 | 147 | ## Лицензия 148 | MIT License 149 | -------------------------------------------------------------------------------- /package-lock.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "yametrika", 3 | "version": "2.2.1", 4 | "lockfileVersion": 1, 5 | "requires": true, 6 | "dependencies": { 7 | "@babel/code-frame": { 8 | "version": "7.12.11", 9 | "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.12.11.tgz", 10 | "integrity": "sha512-Zt1yodBx1UcyiePMSkWnU4hPqhwq7hGi2nFL1LeA3EUl+q2LQx16MISgJ0+z7dnmgvP9QtIleuETGOiOH1RcIw==", 11 | "dev": true, 12 | "requires": { 13 | "@babel/highlight": "^7.10.4" 14 | } 15 | }, 16 | "@babel/helper-validator-identifier": { 17 | "version": "7.12.11", 18 | "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.12.11.tgz", 19 | "integrity": "sha512-np/lG3uARFybkoHokJUmf1QfEvRVCPbmQeUQpKow5cQ3xWrV9i3rUHodKDJPQfTVX61qKi+UdYk8kik84n7XOw==", 20 | "dev": true 21 | }, 22 | "@babel/highlight": { 23 | "version": "7.10.4", 24 | "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.10.4.tgz", 25 | "integrity": "sha512-i6rgnR/YgPEQzZZnbTHHuZdlE8qyoBNalD6F+q4vAFlcMEcqmkoG+mPqJYJCo63qPf74+Y1UZsl3l6f7/RIkmA==", 26 | "dev": true, 27 | "requires": { 28 | "@babel/helper-validator-identifier": "^7.10.4", 29 | "chalk": "^2.0.0", 30 | "js-tokens": "^4.0.0" 31 | }, 32 | "dependencies": { 33 | "chalk": { 34 | "version": "2.4.2", 35 | "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", 36 | "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", 37 | "dev": true, 38 | "requires": { 39 | "ansi-styles": "^3.2.1", 40 | "escape-string-regexp": "^1.0.5", 41 | "supports-color": "^5.3.0" 42 | } 43 | } 44 | } 45 | }, 46 | "@eslint/eslintrc": { 47 | "version": "0.2.2", 48 | "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-0.2.2.tgz", 49 | "integrity": "sha512-EfB5OHNYp1F4px/LI/FEnGylop7nOqkQ1LRzCM0KccA2U8tvV8w01KBv37LbO7nW4H+YhKyo2LcJhRwjjV17QQ==", 50 | "dev": true, 51 | "requires": { 52 | "ajv": "^6.12.4", 53 | "debug": "^4.1.1", 54 | "espree": "^7.3.0", 55 | "globals": "^12.1.0", 56 | "ignore": "^4.0.6", 57 | "import-fresh": "^3.2.1", 58 | "js-yaml": "^3.13.1", 59 | "lodash": "^4.17.19", 60 | "minimatch": "^3.0.4", 61 | "strip-json-comments": "^3.1.1" 62 | } 63 | }, 64 | "acorn": { 65 | "version": "7.4.1", 66 | "resolved": "https://registry.npmjs.org/acorn/-/acorn-7.4.1.tgz", 67 | "integrity": "sha512-nQyp0o1/mNdbTO1PO6kHkwSrmgZ0MT/jCCpNiwbUjGoRN4dlBhqJtoQuCnEOKzgTVwg0ZWiCoQy6SxMebQVh8A==", 68 | "dev": true 69 | }, 70 | "acorn-jsx": { 71 | "version": "5.3.1", 72 | "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.1.tgz", 73 | "integrity": "sha512-K0Ptm/47OKfQRpNQ2J/oIN/3QYiK6FwW+eJbILhsdxh2WTLdl+30o8aGdTbm5JbffpFFAg/g+zi1E+jvJha5ng==", 74 | "dev": true 75 | }, 76 | "ajv": { 77 | "version": "6.12.6", 78 | "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", 79 | "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", 80 | "dev": true, 81 | "requires": { 82 | "fast-deep-equal": "^3.1.1", 83 | "fast-json-stable-stringify": "^2.0.0", 84 | "json-schema-traverse": "^0.4.1", 85 | "uri-js": "^4.2.2" 86 | } 87 | }, 88 | "ansi-colors": { 89 | "version": "4.1.1", 90 | "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-4.1.1.tgz", 91 | "integrity": "sha512-JoX0apGbHaUJBNl6yF+p6JAFYZ666/hhCGKN5t9QFjbJQKUU/g8MNbFDbvfrgKXvI1QpZplPOnwIo99lX/AAmA==", 92 | "dev": true 93 | }, 94 | "ansi-regex": { 95 | "version": "5.0.0", 96 | "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.0.tgz", 97 | "integrity": "sha512-bY6fj56OUQ0hU1KjFNDQuJFezqKdrAyFdIevADiqrWHwSlbmBNMHp5ak2f40Pm8JTFyM2mqxkG6ngkHO11f/lg==", 98 | "dev": true 99 | }, 100 | "ansi-styles": { 101 | "version": "3.2.1", 102 | "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", 103 | "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", 104 | "dev": true, 105 | "requires": { 106 | "color-convert": "^1.9.0" 107 | } 108 | }, 109 | "argparse": { 110 | "version": "1.0.10", 111 | "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", 112 | "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", 113 | "dev": true, 114 | "requires": { 115 | "sprintf-js": "~1.0.2" 116 | } 117 | }, 118 | "astral-regex": { 119 | "version": "2.0.0", 120 | "resolved": "https://registry.npmjs.org/astral-regex/-/astral-regex-2.0.0.tgz", 121 | "integrity": "sha512-Z7tMw1ytTXt5jqMcOP+OQteU1VuNK9Y02uuJtKQ1Sv69jXQKKg5cibLwGJow8yzZP+eAc18EmLGPal0bp36rvQ==", 122 | "dev": true 123 | }, 124 | "balanced-match": { 125 | "version": "1.0.0", 126 | "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz", 127 | "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=", 128 | "dev": true 129 | }, 130 | "brace-expansion": { 131 | "version": "1.1.11", 132 | "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", 133 | "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", 134 | "dev": true, 135 | "requires": { 136 | "balanced-match": "^1.0.0", 137 | "concat-map": "0.0.1" 138 | } 139 | }, 140 | "callsites": { 141 | "version": "3.1.0", 142 | "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", 143 | "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", 144 | "dev": true 145 | }, 146 | "chalk": { 147 | "version": "4.1.0", 148 | "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.0.tgz", 149 | "integrity": "sha512-qwx12AxXe2Q5xQ43Ac//I6v5aXTipYrSESdOgzrN+9XjgEpyjpKuvSGaN4qE93f7TQTlerQQ8S+EQ0EyDoVL1A==", 150 | "dev": true, 151 | "requires": { 152 | "ansi-styles": "^4.1.0", 153 | "supports-color": "^7.1.0" 154 | }, 155 | "dependencies": { 156 | "ansi-styles": { 157 | "version": "4.3.0", 158 | "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", 159 | "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", 160 | "dev": true, 161 | "requires": { 162 | "color-convert": "^2.0.1" 163 | } 164 | }, 165 | "color-convert": { 166 | "version": "2.0.1", 167 | "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", 168 | "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", 169 | "dev": true, 170 | "requires": { 171 | "color-name": "~1.1.4" 172 | } 173 | }, 174 | "color-name": { 175 | "version": "1.1.4", 176 | "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", 177 | "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", 178 | "dev": true 179 | }, 180 | "has-flag": { 181 | "version": "4.0.0", 182 | "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", 183 | "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", 184 | "dev": true 185 | }, 186 | "supports-color": { 187 | "version": "7.2.0", 188 | "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", 189 | "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", 190 | "dev": true, 191 | "requires": { 192 | "has-flag": "^4.0.0" 193 | } 194 | } 195 | } 196 | }, 197 | "color-convert": { 198 | "version": "1.9.3", 199 | "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", 200 | "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", 201 | "dev": true, 202 | "requires": { 203 | "color-name": "1.1.3" 204 | } 205 | }, 206 | "color-name": { 207 | "version": "1.1.3", 208 | "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", 209 | "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=", 210 | "dev": true 211 | }, 212 | "concat-map": { 213 | "version": "0.0.1", 214 | "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", 215 | "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=", 216 | "dev": true 217 | }, 218 | "cross-spawn": { 219 | "version": "7.0.3", 220 | "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", 221 | "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", 222 | "dev": true, 223 | "requires": { 224 | "path-key": "^3.1.0", 225 | "shebang-command": "^2.0.0", 226 | "which": "^2.0.1" 227 | } 228 | }, 229 | "debug": { 230 | "version": "4.3.1", 231 | "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.1.tgz", 232 | "integrity": "sha512-doEwdvm4PCeK4K3RQN2ZC2BYUBaxwLARCqZmMjtF8a51J2Rb0xpVloFRnCODwqjpwnAoao4pelN8l3RJdv3gRQ==", 233 | "dev": true, 234 | "requires": { 235 | "ms": "2.1.2" 236 | } 237 | }, 238 | "deep-is": { 239 | "version": "0.1.3", 240 | "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.3.tgz", 241 | "integrity": "sha1-s2nW+128E+7PUk+RsHD+7cNXzzQ=", 242 | "dev": true 243 | }, 244 | "doctrine": { 245 | "version": "3.0.0", 246 | "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz", 247 | "integrity": "sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==", 248 | "dev": true, 249 | "requires": { 250 | "esutils": "^2.0.2" 251 | } 252 | }, 253 | "emoji-regex": { 254 | "version": "8.0.0", 255 | "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", 256 | "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", 257 | "dev": true 258 | }, 259 | "enquirer": { 260 | "version": "2.3.6", 261 | "resolved": "https://registry.npmjs.org/enquirer/-/enquirer-2.3.6.tgz", 262 | "integrity": "sha512-yjNnPr315/FjS4zIsUxYguYUPP2e1NK4d7E7ZOLiyYCcbFBiTMyID+2wvm2w6+pZ/odMA7cRkjhsPbltwBOrLg==", 263 | "dev": true, 264 | "requires": { 265 | "ansi-colors": "^4.1.1" 266 | } 267 | }, 268 | "escape-string-regexp": { 269 | "version": "1.0.5", 270 | "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", 271 | "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=", 272 | "dev": true 273 | }, 274 | "eslint": { 275 | "version": "7.16.0", 276 | "resolved": "https://registry.npmjs.org/eslint/-/eslint-7.16.0.tgz", 277 | "integrity": "sha512-iVWPS785RuDA4dWuhhgXTNrGxHHK3a8HLSMBgbbU59ruJDubUraXN8N5rn7kb8tG6sjg74eE0RA3YWT51eusEw==", 278 | "dev": true, 279 | "requires": { 280 | "@babel/code-frame": "^7.0.0", 281 | "@eslint/eslintrc": "^0.2.2", 282 | "ajv": "^6.10.0", 283 | "chalk": "^4.0.0", 284 | "cross-spawn": "^7.0.2", 285 | "debug": "^4.0.1", 286 | "doctrine": "^3.0.0", 287 | "enquirer": "^2.3.5", 288 | "eslint-scope": "^5.1.1", 289 | "eslint-utils": "^2.1.0", 290 | "eslint-visitor-keys": "^2.0.0", 291 | "espree": "^7.3.1", 292 | "esquery": "^1.2.0", 293 | "esutils": "^2.0.2", 294 | "file-entry-cache": "^6.0.0", 295 | "functional-red-black-tree": "^1.0.1", 296 | "glob-parent": "^5.0.0", 297 | "globals": "^12.1.0", 298 | "ignore": "^4.0.6", 299 | "import-fresh": "^3.0.0", 300 | "imurmurhash": "^0.1.4", 301 | "is-glob": "^4.0.0", 302 | "js-yaml": "^3.13.1", 303 | "json-stable-stringify-without-jsonify": "^1.0.1", 304 | "levn": "^0.4.1", 305 | "lodash": "^4.17.19", 306 | "minimatch": "^3.0.4", 307 | "natural-compare": "^1.4.0", 308 | "optionator": "^0.9.1", 309 | "progress": "^2.0.0", 310 | "regexpp": "^3.1.0", 311 | "semver": "^7.2.1", 312 | "strip-ansi": "^6.0.0", 313 | "strip-json-comments": "^3.1.0", 314 | "table": "^6.0.4", 315 | "text-table": "^0.2.0", 316 | "v8-compile-cache": "^2.0.3" 317 | } 318 | }, 319 | "eslint-scope": { 320 | "version": "5.1.1", 321 | "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.1.tgz", 322 | "integrity": "sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==", 323 | "dev": true, 324 | "requires": { 325 | "esrecurse": "^4.3.0", 326 | "estraverse": "^4.1.1" 327 | } 328 | }, 329 | "eslint-utils": { 330 | "version": "2.1.0", 331 | "resolved": "https://registry.npmjs.org/eslint-utils/-/eslint-utils-2.1.0.tgz", 332 | "integrity": "sha512-w94dQYoauyvlDc43XnGB8lU3Zt713vNChgt4EWwhXAP2XkBvndfxF0AgIqKOOasjPIPzj9JqgwkwbCYD0/V3Zg==", 333 | "dev": true, 334 | "requires": { 335 | "eslint-visitor-keys": "^1.1.0" 336 | }, 337 | "dependencies": { 338 | "eslint-visitor-keys": { 339 | "version": "1.3.0", 340 | "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-1.3.0.tgz", 341 | "integrity": "sha512-6J72N8UNa462wa/KFODt/PJ3IU60SDpC3QXC1Hjc1BXXpfL2C9R5+AU7jhe0F6GREqVMh4Juu+NY7xn+6dipUQ==", 342 | "dev": true 343 | } 344 | } 345 | }, 346 | "eslint-visitor-keys": { 347 | "version": "2.0.0", 348 | "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-2.0.0.tgz", 349 | "integrity": "sha512-QudtT6av5WXels9WjIM7qz1XD1cWGvX4gGXvp/zBn9nXG02D0utdU3Em2m/QjTnrsk6bBjmCygl3rmj118msQQ==", 350 | "dev": true 351 | }, 352 | "espree": { 353 | "version": "7.3.1", 354 | "resolved": "https://registry.npmjs.org/espree/-/espree-7.3.1.tgz", 355 | "integrity": "sha512-v3JCNCE64umkFpmkFGqzVKsOT0tN1Zr+ueqLZfpV1Ob8e+CEgPWa+OxCoGH3tnhimMKIaBm4m/vaRpJ/krRz2g==", 356 | "dev": true, 357 | "requires": { 358 | "acorn": "^7.4.0", 359 | "acorn-jsx": "^5.3.1", 360 | "eslint-visitor-keys": "^1.3.0" 361 | }, 362 | "dependencies": { 363 | "eslint-visitor-keys": { 364 | "version": "1.3.0", 365 | "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-1.3.0.tgz", 366 | "integrity": "sha512-6J72N8UNa462wa/KFODt/PJ3IU60SDpC3QXC1Hjc1BXXpfL2C9R5+AU7jhe0F6GREqVMh4Juu+NY7xn+6dipUQ==", 367 | "dev": true 368 | } 369 | } 370 | }, 371 | "esprima": { 372 | "version": "4.0.1", 373 | "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", 374 | "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", 375 | "dev": true 376 | }, 377 | "esquery": { 378 | "version": "1.3.1", 379 | "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.3.1.tgz", 380 | "integrity": "sha512-olpvt9QG0vniUBZspVRN6lwB7hOZoTRtT+jzR+tS4ffYx2mzbw+z0XCOk44aaLYKApNX5nMm+E+P6o25ip/DHQ==", 381 | "dev": true, 382 | "requires": { 383 | "estraverse": "^5.1.0" 384 | }, 385 | "dependencies": { 386 | "estraverse": { 387 | "version": "5.2.0", 388 | "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.2.0.tgz", 389 | "integrity": "sha512-BxbNGGNm0RyRYvUdHpIwv9IWzeM9XClbOxwoATuFdOE7ZE6wHL+HQ5T8hoPM+zHvmKzzsEqhgy0GrQ5X13afiQ==", 390 | "dev": true 391 | } 392 | } 393 | }, 394 | "esrecurse": { 395 | "version": "4.3.0", 396 | "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", 397 | "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", 398 | "dev": true, 399 | "requires": { 400 | "estraverse": "^5.2.0" 401 | }, 402 | "dependencies": { 403 | "estraverse": { 404 | "version": "5.2.0", 405 | "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.2.0.tgz", 406 | "integrity": "sha512-BxbNGGNm0RyRYvUdHpIwv9IWzeM9XClbOxwoATuFdOE7ZE6wHL+HQ5T8hoPM+zHvmKzzsEqhgy0GrQ5X13afiQ==", 407 | "dev": true 408 | } 409 | } 410 | }, 411 | "estraverse": { 412 | "version": "4.3.0", 413 | "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz", 414 | "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==", 415 | "dev": true 416 | }, 417 | "esutils": { 418 | "version": "2.0.3", 419 | "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", 420 | "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", 421 | "dev": true 422 | }, 423 | "fast-deep-equal": { 424 | "version": "3.1.3", 425 | "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", 426 | "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", 427 | "dev": true 428 | }, 429 | "fast-json-stable-stringify": { 430 | "version": "2.1.0", 431 | "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", 432 | "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", 433 | "dev": true 434 | }, 435 | "fast-levenshtein": { 436 | "version": "2.0.6", 437 | "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", 438 | "integrity": "sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc=", 439 | "dev": true 440 | }, 441 | "file-entry-cache": { 442 | "version": "6.0.0", 443 | "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-6.0.0.tgz", 444 | "integrity": "sha512-fqoO76jZ3ZnYrXLDRxBR1YvOvc0k844kcOg40bgsPrE25LAb/PDqTY+ho64Xh2c8ZXgIKldchCFHczG2UVRcWA==", 445 | "dev": true, 446 | "requires": { 447 | "flat-cache": "^3.0.4" 448 | } 449 | }, 450 | "flat-cache": { 451 | "version": "3.0.4", 452 | "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-3.0.4.tgz", 453 | "integrity": "sha512-dm9s5Pw7Jc0GvMYbshN6zchCA9RgQlzzEZX3vylR9IqFfS8XciblUXOKfW6SiuJ0e13eDYZoZV5wdrev7P3Nwg==", 454 | "dev": true, 455 | "requires": { 456 | "flatted": "^3.1.0", 457 | "rimraf": "^3.0.2" 458 | } 459 | }, 460 | "flatted": { 461 | "version": "3.1.0", 462 | "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.1.0.tgz", 463 | "integrity": "sha512-tW+UkmtNg/jv9CSofAKvgVcO7c2URjhTdW1ZTkcAritblu8tajiYy7YisnIflEwtKssCtOxpnBRoCB7iap0/TA==", 464 | "dev": true 465 | }, 466 | "fs.realpath": { 467 | "version": "1.0.0", 468 | "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", 469 | "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=", 470 | "dev": true 471 | }, 472 | "functional-red-black-tree": { 473 | "version": "1.0.1", 474 | "resolved": "https://registry.npmjs.org/functional-red-black-tree/-/functional-red-black-tree-1.0.1.tgz", 475 | "integrity": "sha1-GwqzvVU7Kg1jmdKcDj6gslIHgyc=", 476 | "dev": true 477 | }, 478 | "glob": { 479 | "version": "7.1.6", 480 | "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.6.tgz", 481 | "integrity": "sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA==", 482 | "dev": true, 483 | "requires": { 484 | "fs.realpath": "^1.0.0", 485 | "inflight": "^1.0.4", 486 | "inherits": "2", 487 | "minimatch": "^3.0.4", 488 | "once": "^1.3.0", 489 | "path-is-absolute": "^1.0.0" 490 | } 491 | }, 492 | "glob-parent": { 493 | "version": "5.1.2", 494 | "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", 495 | "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", 496 | "dev": true, 497 | "requires": { 498 | "is-glob": "^4.0.1" 499 | } 500 | }, 501 | "globals": { 502 | "version": "12.4.0", 503 | "resolved": "https://registry.npmjs.org/globals/-/globals-12.4.0.tgz", 504 | "integrity": "sha512-BWICuzzDvDoH54NHKCseDanAhE3CeDorgDL5MT6LMXXj2WCnd9UC2szdk4AWLfjdgNBCXLUanXYcpBBKOSWGwg==", 505 | "dev": true, 506 | "requires": { 507 | "type-fest": "^0.8.1" 508 | } 509 | }, 510 | "has-flag": { 511 | "version": "3.0.0", 512 | "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", 513 | "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=", 514 | "dev": true 515 | }, 516 | "ignore": { 517 | "version": "4.0.6", 518 | "resolved": "https://registry.npmjs.org/ignore/-/ignore-4.0.6.tgz", 519 | "integrity": "sha512-cyFDKrqc/YdcWFniJhzI42+AzS+gNwmUzOSFcRCQYwySuBBBy/KjuxWLZ/FHEH6Moq1NizMOBWyTcv8O4OZIMg==", 520 | "dev": true 521 | }, 522 | "import-fresh": { 523 | "version": "3.3.0", 524 | "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz", 525 | "integrity": "sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==", 526 | "dev": true, 527 | "requires": { 528 | "parent-module": "^1.0.0", 529 | "resolve-from": "^4.0.0" 530 | } 531 | }, 532 | "imurmurhash": { 533 | "version": "0.1.4", 534 | "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", 535 | "integrity": "sha1-khi5srkoojixPcT7a21XbyMUU+o=", 536 | "dev": true 537 | }, 538 | "inflight": { 539 | "version": "1.0.6", 540 | "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", 541 | "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", 542 | "dev": true, 543 | "requires": { 544 | "once": "^1.3.0", 545 | "wrappy": "1" 546 | } 547 | }, 548 | "inherits": { 549 | "version": "2.0.4", 550 | "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", 551 | "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", 552 | "dev": true 553 | }, 554 | "is-extglob": { 555 | "version": "2.1.1", 556 | "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", 557 | "integrity": "sha1-qIwCU1eR8C7TfHahueqXc8gz+MI=", 558 | "dev": true 559 | }, 560 | "is-fullwidth-code-point": { 561 | "version": "3.0.0", 562 | "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", 563 | "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", 564 | "dev": true 565 | }, 566 | "is-glob": { 567 | "version": "4.0.1", 568 | "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.1.tgz", 569 | "integrity": "sha512-5G0tKtBTFImOqDnLB2hG6Bp2qcKEFduo4tZu9MT/H6NQv/ghhy30o55ufafxJ/LdH79LLs2Kfrn85TLKyA7BUg==", 570 | "dev": true, 571 | "requires": { 572 | "is-extglob": "^2.1.1" 573 | } 574 | }, 575 | "isexe": { 576 | "version": "2.0.0", 577 | "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", 578 | "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=", 579 | "dev": true 580 | }, 581 | "js-tokens": { 582 | "version": "4.0.0", 583 | "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", 584 | "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", 585 | "dev": true 586 | }, 587 | "js-yaml": { 588 | "version": "3.14.1", 589 | "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.1.tgz", 590 | "integrity": "sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==", 591 | "dev": true, 592 | "requires": { 593 | "argparse": "^1.0.7", 594 | "esprima": "^4.0.0" 595 | } 596 | }, 597 | "json-schema-traverse": { 598 | "version": "0.4.1", 599 | "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", 600 | "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", 601 | "dev": true 602 | }, 603 | "json-stable-stringify-without-jsonify": { 604 | "version": "1.0.1", 605 | "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", 606 | "integrity": "sha1-nbe1lJatPzz+8wp1FC0tkwrXJlE=", 607 | "dev": true 608 | }, 609 | "levn": { 610 | "version": "0.4.1", 611 | "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", 612 | "integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==", 613 | "dev": true, 614 | "requires": { 615 | "prelude-ls": "^1.2.1", 616 | "type-check": "~0.4.0" 617 | } 618 | }, 619 | "lodash": { 620 | "version": "4.17.21", 621 | "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", 622 | "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==", 623 | "dev": true 624 | }, 625 | "lru-cache": { 626 | "version": "6.0.0", 627 | "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", 628 | "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", 629 | "dev": true, 630 | "requires": { 631 | "yallist": "^4.0.0" 632 | } 633 | }, 634 | "minimatch": { 635 | "version": "3.0.4", 636 | "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", 637 | "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", 638 | "dev": true, 639 | "requires": { 640 | "brace-expansion": "^1.1.7" 641 | } 642 | }, 643 | "ms": { 644 | "version": "2.1.2", 645 | "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", 646 | "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", 647 | "dev": true 648 | }, 649 | "natural-compare": { 650 | "version": "1.4.0", 651 | "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", 652 | "integrity": "sha1-Sr6/7tdUHywnrPspvbvRXI1bpPc=", 653 | "dev": true 654 | }, 655 | "once": { 656 | "version": "1.4.0", 657 | "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", 658 | "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", 659 | "dev": true, 660 | "requires": { 661 | "wrappy": "1" 662 | } 663 | }, 664 | "optionator": { 665 | "version": "0.9.1", 666 | "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.1.tgz", 667 | "integrity": "sha512-74RlY5FCnhq4jRxVUPKDaRwrVNXMqsGsiW6AJw4XK8hmtm10wC0ypZBLw5IIp85NZMr91+qd1RvvENwg7jjRFw==", 668 | "dev": true, 669 | "requires": { 670 | "deep-is": "^0.1.3", 671 | "fast-levenshtein": "^2.0.6", 672 | "levn": "^0.4.1", 673 | "prelude-ls": "^1.2.1", 674 | "type-check": "^0.4.0", 675 | "word-wrap": "^1.2.3" 676 | } 677 | }, 678 | "parent-module": { 679 | "version": "1.0.1", 680 | "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", 681 | "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", 682 | "dev": true, 683 | "requires": { 684 | "callsites": "^3.0.0" 685 | } 686 | }, 687 | "path-is-absolute": { 688 | "version": "1.0.1", 689 | "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", 690 | "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=", 691 | "dev": true 692 | }, 693 | "path-key": { 694 | "version": "3.1.1", 695 | "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", 696 | "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", 697 | "dev": true 698 | }, 699 | "prelude-ls": { 700 | "version": "1.2.1", 701 | "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", 702 | "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==", 703 | "dev": true 704 | }, 705 | "progress": { 706 | "version": "2.0.3", 707 | "resolved": "https://registry.npmjs.org/progress/-/progress-2.0.3.tgz", 708 | "integrity": "sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA==", 709 | "dev": true 710 | }, 711 | "punycode": { 712 | "version": "2.1.1", 713 | "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz", 714 | "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==", 715 | "dev": true 716 | }, 717 | "regexpp": { 718 | "version": "3.1.0", 719 | "resolved": "https://registry.npmjs.org/regexpp/-/regexpp-3.1.0.tgz", 720 | "integrity": "sha512-ZOIzd8yVsQQA7j8GCSlPGXwg5PfmA1mrq0JP4nGhh54LaKN3xdai/vHUDu74pKwV8OxseMS65u2NImosQcSD0Q==", 721 | "dev": true 722 | }, 723 | "resolve-from": { 724 | "version": "4.0.0", 725 | "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", 726 | "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", 727 | "dev": true 728 | }, 729 | "rimraf": { 730 | "version": "3.0.2", 731 | "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", 732 | "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", 733 | "dev": true, 734 | "requires": { 735 | "glob": "^7.1.3" 736 | } 737 | }, 738 | "semver": { 739 | "version": "7.3.4", 740 | "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.4.tgz", 741 | "integrity": "sha512-tCfb2WLjqFAtXn4KEdxIhalnRtoKFN7nAwj0B3ZXCbQloV2tq5eDbcTmT68JJD3nRJq24/XgxtQKFIpQdtvmVw==", 742 | "dev": true, 743 | "requires": { 744 | "lru-cache": "^6.0.0" 745 | } 746 | }, 747 | "shebang-command": { 748 | "version": "2.0.0", 749 | "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", 750 | "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", 751 | "dev": true, 752 | "requires": { 753 | "shebang-regex": "^3.0.0" 754 | } 755 | }, 756 | "shebang-regex": { 757 | "version": "3.0.0", 758 | "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", 759 | "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", 760 | "dev": true 761 | }, 762 | "slice-ansi": { 763 | "version": "4.0.0", 764 | "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-4.0.0.tgz", 765 | "integrity": "sha512-qMCMfhY040cVHT43K9BFygqYbUPFZKHOg7K73mtTWJRb8pyP3fzf4Ixd5SzdEJQ6MRUg/WBnOLxghZtKKurENQ==", 766 | "dev": true, 767 | "requires": { 768 | "ansi-styles": "^4.0.0", 769 | "astral-regex": "^2.0.0", 770 | "is-fullwidth-code-point": "^3.0.0" 771 | }, 772 | "dependencies": { 773 | "ansi-styles": { 774 | "version": "4.3.0", 775 | "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", 776 | "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", 777 | "dev": true, 778 | "requires": { 779 | "color-convert": "^2.0.1" 780 | } 781 | }, 782 | "color-convert": { 783 | "version": "2.0.1", 784 | "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", 785 | "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", 786 | "dev": true, 787 | "requires": { 788 | "color-name": "~1.1.4" 789 | } 790 | }, 791 | "color-name": { 792 | "version": "1.1.4", 793 | "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", 794 | "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", 795 | "dev": true 796 | } 797 | } 798 | }, 799 | "sprintf-js": { 800 | "version": "1.0.3", 801 | "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", 802 | "integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw=", 803 | "dev": true 804 | }, 805 | "string-width": { 806 | "version": "4.2.0", 807 | "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.0.tgz", 808 | "integrity": "sha512-zUz5JD+tgqtuDjMhwIg5uFVV3dtqZ9yQJlZVfq4I01/K5Paj5UHj7VyrQOJvzawSVlKpObApbfD0Ed6yJc+1eg==", 809 | "dev": true, 810 | "requires": { 811 | "emoji-regex": "^8.0.0", 812 | "is-fullwidth-code-point": "^3.0.0", 813 | "strip-ansi": "^6.0.0" 814 | } 815 | }, 816 | "strip-ansi": { 817 | "version": "6.0.0", 818 | "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.0.tgz", 819 | "integrity": "sha512-AuvKTrTfQNYNIctbR1K/YGTR1756GycPsg7b9bdV9Duqur4gv6aKqHXah67Z8ImS7WEz5QVcOtlfW2rZEugt6w==", 820 | "dev": true, 821 | "requires": { 822 | "ansi-regex": "^5.0.0" 823 | } 824 | }, 825 | "strip-json-comments": { 826 | "version": "3.1.1", 827 | "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", 828 | "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", 829 | "dev": true 830 | }, 831 | "supports-color": { 832 | "version": "5.5.0", 833 | "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", 834 | "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", 835 | "dev": true, 836 | "requires": { 837 | "has-flag": "^3.0.0" 838 | } 839 | }, 840 | "table": { 841 | "version": "6.0.4", 842 | "resolved": "https://registry.npmjs.org/table/-/table-6.0.4.tgz", 843 | "integrity": "sha512-sBT4xRLdALd+NFBvwOz8bw4b15htyythha+q+DVZqy2RS08PPC8O2sZFgJYEY7bJvbCFKccs+WIZ/cd+xxTWCw==", 844 | "dev": true, 845 | "requires": { 846 | "ajv": "^6.12.4", 847 | "lodash": "^4.17.20", 848 | "slice-ansi": "^4.0.0", 849 | "string-width": "^4.2.0" 850 | } 851 | }, 852 | "text-table": { 853 | "version": "0.2.0", 854 | "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", 855 | "integrity": "sha1-f17oI66AUgfACvLfSoTsP8+lcLQ=", 856 | "dev": true 857 | }, 858 | "type-check": { 859 | "version": "0.4.0", 860 | "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", 861 | "integrity": "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==", 862 | "dev": true, 863 | "requires": { 864 | "prelude-ls": "^1.2.1" 865 | } 866 | }, 867 | "type-fest": { 868 | "version": "0.8.1", 869 | "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.8.1.tgz", 870 | "integrity": "sha512-4dbzIzqvjtgiM5rw1k5rEHtBANKmdudhGyBEajN01fEyhaAIhsoKNy6y7+IN93IfpFtwY9iqi7kD+xwKhQsNJA==", 871 | "dev": true 872 | }, 873 | "uri-js": { 874 | "version": "4.4.0", 875 | "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.0.tgz", 876 | "integrity": "sha512-B0yRTzYdUCCn9n+F4+Gh4yIDtMQcaJsmYBDsTSG8g/OejKBodLQ2IHfN3bM7jUsRXndopT7OIXWdYqc1fjmV6g==", 877 | "dev": true, 878 | "requires": { 879 | "punycode": "^2.1.0" 880 | } 881 | }, 882 | "v8-compile-cache": { 883 | "version": "2.2.0", 884 | "resolved": "https://registry.npmjs.org/v8-compile-cache/-/v8-compile-cache-2.2.0.tgz", 885 | "integrity": "sha512-gTpR5XQNKFwOd4clxfnhaqvfqMpqEwr4tOtCyz4MtYZX2JYhfr1JvBFKdS+7K/9rfpZR3VLX+YWBbKoxCgS43Q==", 886 | "dev": true 887 | }, 888 | "which": { 889 | "version": "2.0.2", 890 | "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", 891 | "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", 892 | "dev": true, 893 | "requires": { 894 | "isexe": "^2.0.0" 895 | } 896 | }, 897 | "word-wrap": { 898 | "version": "1.2.3", 899 | "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.3.tgz", 900 | "integrity": "sha512-Hz/mrNwitNRh/HUAtM/VT/5VH+ygD6DV7mYKZAtHOrbs8U7lvPS6xf7EJKMF0uW1KJCl0H701g3ZGus+muE5vQ==", 901 | "dev": true 902 | }, 903 | "wrappy": { 904 | "version": "1.0.2", 905 | "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", 906 | "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=", 907 | "dev": true 908 | }, 909 | "yallist": { 910 | "version": "4.0.0", 911 | "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", 912 | "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", 913 | "dev": true 914 | } 915 | } 916 | } 917 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "yametrika", 3 | "main": "yametrika.js", 4 | "description": "Серверное отслеживание посетителей с помощью Яндекс.Метрики", 5 | "version": "2.2.1", 6 | "author": { 7 | "name": "Denis Seleznev", 8 | "email": "hcodes@yandex.ru", 9 | "url": "https://github.com/hcodes" 10 | }, 11 | "license": "MIT", 12 | "homepage": "https://github.com/hcodes/server_yametrika_nodejs", 13 | "repository": { 14 | "type": "git", 15 | "url": "git@github.com:hcodes/server_yametrika_nodejs.git" 16 | }, 17 | "keywords": [ 18 | "yandex", 19 | "metrika", 20 | "analytics", 21 | "stats", 22 | "metrics", 23 | "track" 24 | ], 25 | "engines": { 26 | "node": ">= 6" 27 | }, 28 | "files": [ 29 | "yametrika.js", 30 | "LICENSE.md", 31 | "README.md" 32 | ], 33 | "scripts": { 34 | "eslint": "eslint .", 35 | "test": "npm run eslint" 36 | }, 37 | "devDependencies": { 38 | "eslint": "^7.16.0" 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /tests/server.js: -------------------------------------------------------------------------------- 1 | // https://metrika.yandex.ru/stat/?counter_id=21312094 2 | 'use strict'; 3 | 4 | const 5 | http = require('http'), 6 | counter = require('../yametrika').counter({id: 21312094}); 7 | 8 | http.createServer(function(req, res) { 9 | res.writeHead(200, {'Content-Type': 'text/plain'}); 10 | res.end('okay'); 11 | 12 | counter.req(req); 13 | 14 | counter.hit('http://example.com', 'Main page', 'http://google.com'); 15 | counter.hit('http://example.com/back/', 'Back', 'http://example.com/back/'); 16 | counter.reachGoal('action'); 17 | counter.extLink('http://nodejs.org'); 18 | counter.file('http://example.com/file.zip'); 19 | counter.params('level1', 'level2', 'level3', 1); 20 | }).listen(8080); 21 | -------------------------------------------------------------------------------- /yametrika.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Серверная отправка хитов с помощью Node.js в Яндекс.Метрику 3 | * 4 | * Author: Denis Seleznev 5 | * License: MIT 6 | */ 7 | 8 | 'use strict'; 9 | 10 | const 11 | querystring = require('querystring'), 12 | https = require('https'), 13 | HOST = 'mc.yandex.ru', 14 | PATH = '/watch/', 15 | PORT = 443; 16 | 17 | class Counter { 18 | /** 19 | * Конструктор счётчика Метрики 20 | * @constructor 21 | * 22 | * @param {Object} settings - Настройки счётчика. 23 | * @param {string|number} settings.id - Номер счётчика. 24 | * @param {number} [settings.type] - Тип счётчика: 0 - обычный счётчик, 1 - РСЯ-счётчик. 25 | * @param {Function} [settings.onerror] - Для отладки сетевых ошибок. 26 | * @param {https.Agent} [settings.agent] 27 | */ 28 | constructor(settings) { 29 | this._id = settings.id; 30 | this._type = settings.type || 0; 31 | this._onerror = settings.onerror; 32 | this._agent = settings.agent; 33 | 34 | this._request = { 35 | host: null, 36 | url: null, 37 | referer: null, 38 | 'user-agent': null, 39 | ip: null 40 | }; 41 | } 42 | 43 | /** 44 | * Отправка хита. 45 | * 46 | * @param {string} pageUrl - Адрес страницы. 47 | * @param {string} [pageTitle] - Заголовок страницы. 48 | * @param {string} [pageRef] - Реферер страницы. 49 | * @param {Object} [userParams] - Параметры визитов. 50 | * @param {string} [ut] - Для запрета индексирования 'noindex'. 51 | * 52 | * @returns {Object} this 53 | * 54 | * @example 55 | * counter.hit('https://mysite.org', 'Main page', 'https://google.com/...'); 56 | */ 57 | hit(pageUrl, pageTitle, pageRef, userParams, ut) { 58 | if (!pageUrl) { 59 | pageUrl = this._request.url; 60 | } 61 | 62 | if (!pageRef) { 63 | pageRef = this._request.referer; 64 | } 65 | 66 | this._hitExt(pageUrl, pageTitle, pageRef, userParams, {ut}); 67 | 68 | return this; 69 | } 70 | 71 | /** 72 | * Достижение цели. 73 | * 74 | * @param {string} target - Название цели. 75 | * @param {Object} [userParams] - Параметры визитов. 76 | * 77 | * @returns {Object} this 78 | * 79 | * @example 80 | * counter.reachGoal('goalName'); 81 | */ 82 | reachGoal(target, userParams) { 83 | const req = this._request; 84 | let referer; 85 | if (target) { 86 | target = 'goal://' + req.host + '/' + target; 87 | referer = req.url; 88 | } else { 89 | target = req.url; 90 | referer = req.referer; 91 | } 92 | 93 | this._hitExt(target, null, referer, userParams, null); 94 | 95 | return this; 96 | } 97 | 98 | /** 99 | * Внешняя ссылка. 100 | * 101 | * @param {string} url - Адрес страницы. 102 | * @param {string} [title] - Заголовок страницы. 103 | * 104 | * @returns {Object} this 105 | * 106 | * @example 107 | * counter.extLink('https://nodejs.org'); 108 | */ 109 | extLink(url, title) { 110 | if (url) { 111 | this._hitExt(url, title, this._request.url, null, { 112 | ln: true, 113 | ut: 'noindex' 114 | }); 115 | } 116 | 117 | return this; 118 | } 119 | 120 | /** 121 | * Загрузка файла. 122 | * 123 | * @param {string} file - Ссылка на файл. 124 | * @param {string} [title] - Заголовок страницы. 125 | * 126 | * @returns {Object} this 127 | * 128 | * @example 129 | * counter.file('https://mysite.org/secret.zip'); 130 | */ 131 | file(file, title) { 132 | if (file) { 133 | this._hitExt(file, title, this._request.url, null, { 134 | dl: true, 135 | ln: true 136 | }); 137 | } 138 | 139 | return this; 140 | } 141 | 142 | /** 143 | * Параметры визитов. 144 | * 145 | * @param {...*} data - Параметры визитов. 146 | * 147 | * @returns {Object} this 148 | * 149 | * @example 150 | * counter.params({level1: {level2: {level3: 1}}}); 151 | * или 152 | * counter.params('level1', 'level2', 'level3', 1); 153 | */ 154 | params(data) { 155 | const 156 | len = arguments.length, 157 | obj = {}; 158 | 159 | let pointer = obj; 160 | if (len > 1) { 161 | for (let i = 0; i < len - 1; i++) { 162 | pointer[arguments[i]] = {}; 163 | if (i == len - 2) { 164 | pointer[arguments[i]] = arguments[i + 1]; 165 | } else { 166 | pointer = pointer[arguments[i]]; 167 | } 168 | } 169 | 170 | this._hitExt('', '', '', obj, {pa: true}); 171 | } else { 172 | if (data) { 173 | this._hitExt('', '', '', data, {pa: true}); 174 | } 175 | } 176 | 177 | return this; 178 | } 179 | 180 | /** 181 | * Не отказ. 182 | * 183 | * @returns {Object} this 184 | * 185 | * @example 186 | * counter.notBounce(); 187 | */ 188 | notBounce() { 189 | this._hitExt('', '', '', null, {nb: true}); 190 | 191 | return this; 192 | } 193 | 194 | /** 195 | * Заполнение необходимых параметров из запроса сервера для отправки данных в Метрику. 196 | * 197 | * @param {Object} req 198 | * 199 | * @returns {Object} this 200 | * 201 | * @example 202 | * counter.req(req); 203 | */ 204 | req(req) { 205 | const rh = req.headers; 206 | this._request = { 207 | host: rh.host, 208 | url: this._protocol(req) + '://' + rh.host + req.url, 209 | referer: rh.referer, 210 | 'user-agent': rh['user-agent'], 211 | ip: this._clientIP(req) 212 | }; 213 | 214 | return this; 215 | } 216 | 217 | _clientIP(req) { 218 | const rh = req.headers; 219 | return rh['x-real-ip'] || rh['x-forwarded-for'] || rh['x-remote-ip'] || rh['x-originating-ip'] || req.connection.remoteAddress; 220 | } 221 | 222 | _protocol(req) { 223 | const rh = req.headers; 224 | return rh['x-forwarded-proto'] || rh.protocol || (req.secure ? 'https' : 'http'); 225 | } 226 | 227 | _hitExt(pageUrl, pageTitle, pageRef, userParams, modes) { 228 | const postData = {}; 229 | 230 | if (this._type) { 231 | postData['cnt-class'] = this._type; 232 | } 233 | 234 | if (pageUrl) { 235 | postData['page-url'] = pageUrl; 236 | } 237 | 238 | if (pageRef) { 239 | postData['page-ref'] = pageRef; 240 | } 241 | 242 | if (modes) { 243 | modes.ar = true; 244 | } else { 245 | modes = {ar: true}; 246 | } 247 | 248 | const browserInfo = []; 249 | Object.keys(modes).forEach((key) => { 250 | if (key != 'ut') { 251 | browserInfo.push(key + ':' + (modes[key] === true ? '1' : modes[key])); 252 | } 253 | }); 254 | 255 | browserInfo.push('en:utf-8'); 256 | browserInfo.push('rn:' + (Math.floor(Math.random() * 1E6))); 257 | 258 | if (pageTitle) { 259 | browserInfo.push('t:' + pageTitle); 260 | } 261 | 262 | postData['browser-info'] = browserInfo.join(':'); 263 | 264 | if (userParams) { 265 | postData['site-info'] = JSON.stringify(userParams); 266 | } 267 | 268 | if (modes['ut']) { 269 | postData['ut'] = modes['ut']; 270 | } 271 | 272 | this._sendData(postData); 273 | } 274 | 275 | _sendData(data) { 276 | const path = PATH + this._id 277 | + '/1?rn=' + (Math.floor(Math.random() * 1E6)) 278 | + '&wmode=2' 279 | + '&' + querystring.stringify(data); 280 | 281 | const req = https.request({ 282 | agent: this._agent, 283 | host: HOST, 284 | port: PORT, 285 | path: path, 286 | method: 'GET', 287 | headers: { 288 | 'x-forwarded-for': this._request.ip, 289 | 'user-agent': this._request['user-agent'] 290 | } 291 | }, function() {}); 292 | 293 | if (this._onerror) { 294 | req.on('error', this._onerror); 295 | } 296 | 297 | req.end(); 298 | } 299 | } 300 | 301 | module.exports.counter = function(settings) { 302 | return new Counter(settings); 303 | }; 304 | --------------------------------------------------------------------------------