{"_id":"@borisch/snitch","_rev":"10-ca5d30836fc5472226db091b7aca2738","name":"@borisch/snitch","dist-tags":{"latest":"1.2.5"},"versions":{"1.0.0":{"name":"@borisch/snitch","version":"1.0.0","keywords":["analytics","tracking","plugins","beacon","web-vitals"],"author":{"name":"Boris Chumichev","email":"borisboha@gmail.com"},"license":"MIT","_id":"@borisch/snitch@1.0.0","maintainers":[{"name":"borisch","email":"borisboha@gmail.com"}],"homepage":"https://github.com/BorisChumichev/snitch#readme","bugs":{"url":"https://github.com/BorisChumichev/snitch/issues"},"dist":{"shasum":"e8610fc6d6a7a4717f3c0143065882dd3810677a","tarball":"https://registry.npmjs.org/@borisch/snitch/-/snitch-1.0.0.tgz","fileCount":149,"integrity":"sha512-9RjmDJFJ4hiyxh7MtF4Bh8JLRUzXVVW4F7EGkXCpBQ/1L6AoiP2loE2FuGC+Leo73FDwqOQIuLFrxXW/pleI9g==","signatures":[{"sig":"MEUCIHwnomT3CZOrCypooDBll7Gs369aPchtdYbgHXVzLwbCAiEAhU8wAsIvRQr/oboEsQnQ15OkkFxJ3nSw44HwI6Hk5OI=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":103039},"jest":{"testMatch":["**/*.test.ts"],"transform":{"^.+\\.[tj]s$":"ts-jest"},"testEnvironment":"jsdom","collectCoverageFrom":["packages/**/*.ts"],"moduleFileExtensions":["ts","js"],"coveragePathIgnorePatterns":["/node_modules/"]},"main":"dist/index.js","engines":{"node":">=18.0.0"},"gitHead":"c153a5a1d053bf43bdc9c17c50d1206fd7196342","scripts":{"test":"jest","build":"tsc","prebuild":"rimraf dist","test:watch":"jest --coverage --watch"},"typings":"dist/index.d.ts","_npmUser":{"name":"borisch","email":"borisboha@gmail.com"},"prettier":{"semi":false,"singleQuote":true},"repository":{"url":"git+https://github.com/BorisChumichev/snitch.git","type":"git"},"_npmVersion":"11.6.1","description":"Modular analytics tracking library with pluggable transports","directories":{},"_nodeVersion":"24.11.0","dependencies":{"web-vitals":"^3.0.4"},"_hasShrinkwrap":false,"devDependencies":{"jest":"^27.0.6","delay":"^5.0.0","jsdom":"^16.6.0","tslib":"^2.3.0","rimraf":"^2.6.2","ts-jest":"^27.0.3","ts-node":"^7.0.1","prettier":"^1.14.3","typescript":"^4.3.5","@types/jest":"^23.3.2","@types/node":"^10.17.60"},"_npmOperationalInternal":{"tmp":"tmp/snitch_1.0.0_1770918339724_0.12256137656976995","host":"s3://npm-registry-packages-npm-production"}},"1.0.1":{"name":"@borisch/snitch","version":"1.0.1","keywords":["analytics","tracking","plugins","beacon","web-vitals"],"author":{"name":"Boris Chumichev","email":"borisboha@gmail.com"},"license":"MIT","_id":"@borisch/snitch@1.0.1","maintainers":[{"name":"borisch","email":"borisboha@gmail.com"}],"homepage":"https://github.com/BorisChumichev/snitch#readme","bugs":{"url":"https://github.com/BorisChumichev/snitch/issues"},"dist":{"shasum":"afcf7f692c0c7efccb971d097c26e335988d1031","tarball":"https://registry.npmjs.org/@borisch/snitch/-/snitch-1.0.1.tgz","fileCount":149,"integrity":"sha512-GkRbzRASRK/s1sbTqFlKOkIufuS9vNQjAwnki12fjxjnion5YFOaj71cJi9pFNuIApeuJyBPjqszaxclLev45Q==","signatures":[{"sig":"MEUCIQCQjzCZ7wX2ydYZYSFA4ZZd1KLissiBdoawSyyY9xwxSwIgDsM1BmieC0Inz3FO6THunXPxCS2HNZ5a0G0WEdXEdmM=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":104396},"jest":{"testMatch":["**/*.test.ts"],"transform":{"^.+\\.[tj]s$":"ts-jest"},"testEnvironment":"jsdom","collectCoverageFrom":["packages/**/*.ts"],"moduleFileExtensions":["ts","js"],"coveragePathIgnorePatterns":["/node_modules/"]},"main":"dist/index.js","engines":{"node":">=18.0.0"},"gitHead":"00d323f454b6ad33ba01d9218913f9a59e49ddd5","scripts":{"test":"jest","build":"tsc","prebuild":"rimraf dist","test:watch":"jest --coverage --watch"},"typings":"dist/index.d.ts","_npmUser":{"name":"borisch","email":"borisboha@gmail.com"},"prettier":{"semi":false,"singleQuote":true},"repository":{"url":"git+https://github.com/BorisChumichev/snitch.git","type":"git"},"_npmVersion":"11.6.1","description":"Modular analytics tracking library with pluggable transports","directories":{},"_nodeVersion":"24.11.0","dependencies":{"web-vitals":"^3.5.0"},"_hasShrinkwrap":false,"devDependencies":{"jest":"^29.7.0","delay":"^5.0.0","tslib":"^2.8.0","rimraf":"^6.0.0","ts-jest":"^29.2.0","ts-node":"^10.9.0","prettier":"^3.5.0","typescript":"^5.8.0","@types/jest":"^29.5.0","@types/node":"^22.0.0","jest-environment-jsdom":"^29.7.0"},"_npmOperationalInternal":{"tmp":"tmp/snitch_1.0.1_1770918966183_0.3149721547175084","host":"s3://npm-registry-packages-npm-production"}},"1.0.2":{"name":"@borisch/snitch","version":"1.0.2","keywords":["analytics","tracking","plugins","beacon","web-vitals"],"author":{"name":"Boris Chumichev","email":"borisboha@gmail.com"},"license":"MIT","_id":"@borisch/snitch@1.0.2","maintainers":[{"name":"borisch","email":"borisboha@gmail.com"}],"homepage":"https://github.com/BorisChumichev/snitch#readme","bugs":{"url":"https://github.com/BorisChumichev/snitch/issues"},"dist":{"shasum":"4423fe84210ee17699daf6b0d3d5d0cd07eb1b46","tarball":"https://registry.npmjs.org/@borisch/snitch/-/snitch-1.0.2.tgz","fileCount":149,"integrity":"sha512-PnnxVIzD6oHYEd+DsdMZCHN0qEV/2ggsPB2YHGM9n2/rnLiKIlyKpN04F2AGzcDaaKGav1npiZO+SUBZH6Y35A==","signatures":[{"sig":"MEYCIQCYV6hTfOQVWzL/FWFjfeGF3loCdwAKtwc6fcirLKG4qgIhAPCU/HoJ0b1NcDTJEatsMk/5BHlIPSrO/RRl5o+jVhBQ","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":110662},"jest":{"testMatch":["**/*.test.ts"],"transform":{"^.+\\.[tj]s$":"ts-jest"},"testEnvironment":"jsdom","collectCoverageFrom":["packages/**/*.ts"],"moduleFileExtensions":["ts","js"],"coveragePathIgnorePatterns":["/node_modules/"]},"main":"dist/index.js","engines":{"node":">=18.0.0"},"gitHead":"f3d9931b6b522ec0864aa8305b48d0706bab30c1","scripts":{"test":"jest","build":"tsc","prebuild":"rimraf dist","test:watch":"jest --coverage --watch"},"typings":"dist/index.d.ts","_npmUser":{"name":"borisch","email":"borisboha@gmail.com"},"prettier":{"semi":false,"singleQuote":true},"repository":{"url":"git+https://github.com/BorisChumichev/snitch.git","type":"git"},"_npmVersion":"11.6.1","description":"Modular analytics tracking library with pluggable transports","directories":{},"_nodeVersion":"24.11.0","dependencies":{"web-vitals":"^3.5.0"},"_hasShrinkwrap":false,"devDependencies":{"jest":"^29.7.0","delay":"^5.0.0","tslib":"^2.8.0","rimraf":"^6.0.0","ts-jest":"^29.2.0","ts-node":"^10.9.0","prettier":"^3.5.0","typescript":"^5.8.0","@types/jest":"^29.5.0","@types/node":"^22.0.0","jest-environment-jsdom":"^29.7.0"},"_npmOperationalInternal":{"tmp":"tmp/snitch_1.0.2_1770920224396_0.9627344990832916","host":"s3://npm-registry-packages-npm-production"}},"1.1.0":{"name":"@borisch/snitch","version":"1.1.0","keywords":["analytics","tracking","plugins","beacon","web-vitals"],"author":{"name":"Boris Chumichev","email":"borisboha@gmail.com"},"license":"MIT","_id":"@borisch/snitch@1.1.0","maintainers":[{"name":"borisch","email":"borisboha@gmail.com"}],"homepage":"https://github.com/BorisChumichev/snitch#readme","bugs":{"url":"https://github.com/BorisChumichev/snitch/issues"},"dist":{"shasum":"2c12a4b8998d5ca455279cedcfed6f2032c0b626","tarball":"https://registry.npmjs.org/@borisch/snitch/-/snitch-1.1.0.tgz","fileCount":161,"integrity":"sha512-VQqP+j+6fZRT5qYjTIZmfOohE2AxLb3kQWtnRf976OmvRRQE1SWsI83rq3ND/lDUinfh+t6ty+l/lY5RtdM27Q==","signatures":[{"sig":"MEUCIQDN6nzCa/fszOI3Iyn45N588hGxuGdgSVZHGt39eECoTgIgdr9kENn5MaNrBjAJV7rpiZ7LjSFHjWY1P2CrrtigRxE=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":119780},"jest":{"testMatch":["**/*.test.ts"],"transform":{"^.+\\.[tj]s$":"ts-jest"},"testEnvironment":"jsdom","collectCoverageFrom":["packages/**/*.ts"],"moduleFileExtensions":["ts","js"],"coveragePathIgnorePatterns":["/node_modules/"]},"main":"dist/index.js","engines":{"node":">=18.0.0"},"gitHead":"c8ea4470b9be93d76f37ce84a646367232a320c6","scripts":{"test":"jest","build":"tsc","prebuild":"rimraf dist","test:watch":"jest --coverage --watch"},"typings":"dist/index.d.ts","_npmUser":{"name":"borisch","email":"borisboha@gmail.com"},"prettier":{"semi":false,"singleQuote":true},"repository":{"url":"git+https://github.com/BorisChumichev/snitch.git","type":"git"},"_npmVersion":"11.6.1","description":"Modular analytics tracking library with pluggable transports","directories":{},"_nodeVersion":"24.11.0","dependencies":{"web-vitals":"^3.5.0"},"_hasShrinkwrap":false,"devDependencies":{"jest":"^29.7.0","delay":"^5.0.0","tslib":"^2.8.0","rimraf":"^6.0.0","ts-jest":"^29.2.0","ts-node":"^10.9.0","prettier":"^3.5.0","typescript":"^5.8.0","@types/jest":"^29.5.0","@types/node":"^22.0.0","jest-environment-jsdom":"^29.7.0"},"_npmOperationalInternal":{"tmp":"tmp/snitch_1.1.0_1770922598877_0.24396511144027344","host":"s3://npm-registry-packages-npm-production"}},"1.2.0":{"name":"@borisch/snitch","version":"1.2.0","keywords":["analytics","tracking","plugins","beacon","web-vitals"],"author":{"name":"Boris Chumichev","email":"borisboha@gmail.com"},"license":"MIT","_id":"@borisch/snitch@1.2.0","maintainers":[{"name":"borisch","email":"borisboha@gmail.com"}],"homepage":"https://github.com/BorisChumichev/snitch#readme","bugs":{"url":"https://github.com/BorisChumichev/snitch/issues"},"dist":{"shasum":"11354660dd7dcaec93d4a42b9253dbd1ca98ab5f","tarball":"https://registry.npmjs.org/@borisch/snitch/-/snitch-1.2.0.tgz","fileCount":164,"integrity":"sha512-vlSA2xEKBt03h6KUX1WOXrMsq/LohCChV1JQdh8F1g4pdHnn11zkPARHMvgAd0f4uLlhYsHSPmtVLFYeFQVKvA==","signatures":[{"sig":"MEUCIBHBu2DWrpaadMxwrUkG27UBbqUl3JR+7gnjY3Ci5lNBAiEA4eb/tbkU7ccFOgv9ocwhHcDStQO4hHe3TN9Er7awwP8=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":124829},"jest":{"testMatch":["**/*.test.ts"],"transform":{"^.+\\.[tj]s$":"ts-jest"},"testEnvironment":"jsdom","collectCoverageFrom":["packages/**/*.ts"],"moduleFileExtensions":["ts","js"],"coveragePathIgnorePatterns":["/node_modules/"]},"main":"dist/index.js","engines":{"node":">=18.0.0"},"exports":{".":{"types":"./dist/index.d.ts","default":"./dist/index.js"},"./server":{"types":"./dist/server.d.ts","default":"./dist/server.js"}},"gitHead":"c5dc684358e4da8a96072c96c9f51cc7618e0787","scripts":{"test":"jest","build":"tsc","prebuild":"rimraf dist","test:watch":"jest --coverage --watch"},"typings":"dist/index.d.ts","_npmUser":{"name":"borisch","email":"borisboha@gmail.com"},"prettier":{"semi":false,"singleQuote":true},"repository":{"url":"git+https://github.com/BorisChumichev/snitch.git","type":"git"},"_npmVersion":"11.6.1","description":"Modular analytics tracking library with pluggable transports","directories":{},"_nodeVersion":"24.11.0","dependencies":{"web-vitals":"^3.5.0"},"_hasShrinkwrap":false,"devDependencies":{"jest":"^29.7.0","delay":"^5.0.0","tslib":"^2.8.0","rimraf":"^6.0.0","ts-jest":"^29.2.0","ts-node":"^10.9.0","prettier":"^3.5.0","typescript":"^5.8.0","@types/jest":"^29.5.0","@types/node":"^22.0.0","jest-environment-jsdom":"^29.7.0"},"_npmOperationalInternal":{"tmp":"tmp/snitch_1.2.0_1770930570385_0.4082135610586577","host":"s3://npm-registry-packages-npm-production"}},"1.2.1":{"name":"@borisch/snitch","version":"1.2.1","keywords":["analytics","tracking","plugins","beacon","web-vitals"],"author":{"name":"Boris Chumichev","email":"borisboha@gmail.com"},"license":"MIT","_id":"@borisch/snitch@1.2.1","maintainers":[{"name":"borisch","email":"borisboha@gmail.com"}],"homepage":"https://github.com/BorisChumichev/snitch#readme","bugs":{"url":"https://github.com/BorisChumichev/snitch/issues"},"dist":{"shasum":"a11cce9d886436fc8583e88181954ecbd26fe75d","tarball":"https://registry.npmjs.org/@borisch/snitch/-/snitch-1.2.1.tgz","fileCount":326,"integrity":"sha512-ErbL39iAjvEckXh3kyUHJUpSRXBptr3EGsU/FHndmn2AwUtBj0B7jBD+CATd42W1TohG4OLPxOEVvIUBKVcBCw==","signatures":[{"sig":"MEYCIQDQsXACZ7GyZf4JT5D9SwhvHMBIZ4EelyualRBHMAWwQwIhAL5rgEmLMCtkOfgFNdSmlDOgbt4SCqpWErQ4xLt+g8ty","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":215417},"jest":{"testMatch":["**/*.test.ts"],"transform":{"^.+\\.[tj]s$":"ts-jest"},"testEnvironment":"jsdom","collectCoverageFrom":["packages/**/*.ts"],"moduleFileExtensions":["ts","js"],"coveragePathIgnorePatterns":["/node_modules/"]},"main":"dist/cjs/index.js","module":"dist/esm/index.js","engines":{"node":">=18.0.0"},"exports":{".":{"types":"./dist/cjs/index.d.ts","import":"./dist/esm/index.js","require":"./dist/cjs/index.js"},"./server":{"types":"./dist/cjs/server.d.ts","import":"./dist/esm/server.js","require":"./dist/cjs/server.js"}},"gitHead":"40764e958063927374b002debdc97bab3108c7ea","scripts":{"test":"jest","build":"tsc -p tsconfig.cjs.json && tsc -p tsconfig.esm.json","prebuild":"rimraf dist","test:watch":"jest --coverage --watch"},"typings":"dist/cjs/index.d.ts","_npmUser":{"name":"borisch","email":"borisboha@gmail.com"},"prettier":{"semi":false,"singleQuote":true},"repository":{"url":"git+https://github.com/BorisChumichev/snitch.git","type":"git"},"_npmVersion":"11.6.1","description":"Modular analytics tracking library with pluggable transports","directories":{},"_nodeVersion":"24.11.0","dependencies":{"web-vitals":"^3.5.0"},"_hasShrinkwrap":false,"devDependencies":{"jest":"^29.7.0","delay":"^5.0.0","tslib":"^2.8.0","rimraf":"^6.0.0","ts-jest":"^29.2.0","ts-node":"^10.9.0","prettier":"^3.5.0","typescript":"^5.8.0","@types/jest":"^29.5.0","@types/node":"^22.0.0","jest-environment-jsdom":"^29.7.0"},"_npmOperationalInternal":{"tmp":"tmp/snitch_1.2.1_1770931276517_0.7296533832874126","host":"s3://npm-registry-packages-npm-production"}},"1.2.2":{"name":"@borisch/snitch","version":"1.2.2","keywords":["analytics","tracking","plugins","beacon","web-vitals"],"author":{"name":"Boris Chumichev","email":"borisboha@gmail.com"},"license":"MIT","_id":"@borisch/snitch@1.2.2","maintainers":[{"name":"borisch","email":"borisboha@gmail.com"}],"homepage":"https://github.com/BorisChumichev/snitch#readme","bugs":{"url":"https://github.com/BorisChumichev/snitch/issues"},"dist":{"shasum":"0dee9bd0348e41325dc2fa3c63ac3e6fbc17ef1a","tarball":"https://registry.npmjs.org/@borisch/snitch/-/snitch-1.2.2.tgz","fileCount":327,"integrity":"sha512-McokXliXqQ29vGuD/23LSpbwdx6Ajgt+oV36HQQni6Fi3fujydZIKIN75YnL+PIXoHGRCe70Sze3FqRRWUXyFw==","signatures":[{"sig":"MEUCIQCGcXunOEj01lVuTmbuHzMVGpX7FB0yUJFsdyNFwyKAygIgZe5J6a0EUTMaFk+JISSjbNcMREIKH1J0RMislHfhDj8=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":215664},"jest":{"testMatch":["**/*.test.ts"],"transform":{"^.+\\.[tj]s$":"ts-jest"},"testEnvironment":"jsdom","collectCoverageFrom":["packages/**/*.ts"],"moduleFileExtensions":["ts","js"],"coveragePathIgnorePatterns":["/node_modules/"]},"main":"dist/cjs/index.js","module":"dist/esm/index.js","engines":{"node":">=18.0.0"},"exports":{".":{"types":"./dist/cjs/index.d.ts","import":"./dist/esm/index.js","require":"./dist/cjs/index.js"},"./server":{"types":"./dist/cjs/server.d.ts","import":"./dist/esm/server.js","require":"./dist/cjs/server.js"}},"gitHead":"36c492accbbf35514136e53f527dc71b6bb069b4","scripts":{"test":"jest","build":"tsc -p tsconfig.cjs.json && tsc -p tsconfig.esm.json && node scripts/fix-esm-imports.js","prebuild":"rimraf dist","test:watch":"jest --coverage --watch"},"typings":"dist/cjs/index.d.ts","_npmUser":{"name":"borisch","email":"borisboha@gmail.com"},"prettier":{"semi":false,"singleQuote":true},"repository":{"url":"git+https://github.com/BorisChumichev/snitch.git","type":"git"},"_npmVersion":"11.6.1","description":"Modular analytics tracking library with pluggable transports","directories":{},"_nodeVersion":"24.11.0","dependencies":{"web-vitals":"^3.5.0"},"_hasShrinkwrap":false,"devDependencies":{"jest":"^29.7.0","delay":"^5.0.0","tslib":"^2.8.0","rimraf":"^6.0.0","ts-jest":"^29.2.0","ts-node":"^10.9.0","prettier":"^3.5.0","typescript":"^5.8.0","@types/jest":"^29.5.0","@types/node":"^22.0.0","jest-environment-jsdom":"^29.7.0"},"_npmOperationalInternal":{"tmp":"tmp/snitch_1.2.2_1770931632651_0.9817578415044697","host":"s3://npm-registry-packages-npm-production"}},"1.2.3":{"name":"@borisch/snitch","version":"1.2.3","keywords":["analytics","tracking","plugins","beacon","web-vitals"],"author":{"name":"Boris Chumichev","email":"borisboha@gmail.com"},"license":"MIT","_id":"@borisch/snitch@1.2.3","maintainers":[{"name":"borisch","email":"borisboha@gmail.com"}],"homepage":"https://github.com/BorisChumichev/snitch#readme","bugs":{"url":"https://github.com/BorisChumichev/snitch/issues"},"dist":{"shasum":"2cf555ecf9e84cdee1282ea15764efd6e297c05d","tarball":"https://registry.npmjs.org/@borisch/snitch/-/snitch-1.2.3.tgz","fileCount":327,"integrity":"sha512-VTW75JiCaL880Owz5xt5cbI7MJoVw1WyOOjuIiBFkR+F2hXhSN3Zp3pmETOAQ+BkDG5qpMlBqZGmJZgL6trajg==","signatures":[{"sig":"MEQCIAT1gM1pqwNRZGhqUJRD7iY/ztmzXYc/2hWGQzHUZhfqAiAHM8oO8vvSVFeK3po0kskzCp1RR/Au5H+ViWB5QGmnHg==","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":216676},"jest":{"testMatch":["**/*.test.ts"],"transform":{"^.+\\.[tj]s$":"ts-jest"},"testEnvironment":"jsdom","collectCoverageFrom":["packages/**/*.ts"],"moduleFileExtensions":["ts","js"],"coveragePathIgnorePatterns":["/node_modules/"]},"main":"dist/cjs/index.js","module":"dist/esm/index.js","engines":{"node":">=18.0.0"},"exports":{".":{"types":"./dist/cjs/index.d.ts","import":"./dist/esm/index.js","require":"./dist/cjs/index.js"},"./server":{"types":"./dist/cjs/server.d.ts","import":"./dist/esm/server.js","require":"./dist/cjs/server.js"}},"gitHead":"1251b5d020f47949c6ee5b0827b02d91f31c94d6","scripts":{"test":"jest","build":"tsc -p tsconfig.cjs.json && tsc -p tsconfig.esm.json && node scripts/fix-esm-imports.js","prebuild":"rimraf dist","test:watch":"jest --coverage --watch"},"typings":"dist/cjs/index.d.ts","_npmUser":{"name":"borisch","email":"borisboha@gmail.com"},"prettier":{"semi":false,"singleQuote":true},"repository":{"url":"git+https://github.com/BorisChumichev/snitch.git","type":"git"},"_npmVersion":"11.16.0","description":"Modular analytics tracking library with pluggable transports","directories":{},"_nodeVersion":"24.18.0","dependencies":{"web-vitals":"^3.5.0"},"_hasShrinkwrap":false,"devDependencies":{"jest":"^29.7.0","delay":"^5.0.0","tslib":"^2.8.0","rimraf":"^6.0.0","ts-jest":"^29.2.0","ts-node":"^10.9.0","prettier":"^3.5.0","typescript":"^5.8.0","@types/jest":"^29.5.0","@types/node":"^22.0.0","jest-environment-jsdom":"^29.7.0"},"_npmOperationalInternal":{"tmp":"tmp/snitch_1.2.3_1783785624673_0.8651385991531266","host":"s3://npm-registry-packages-npm-production"}},"1.2.4":{"name":"@borisch/snitch","version":"1.2.4","keywords":["analytics","tracking","plugins","beacon","web-vitals"],"author":{"name":"Boris Chumichev","email":"borisboha@gmail.com"},"license":"MIT","_id":"@borisch/snitch@1.2.4","maintainers":[{"name":"borisch","email":"borisboha@gmail.com"}],"homepage":"https://github.com/BorisChumichev/snitch#readme","bugs":{"url":"https://github.com/BorisChumichev/snitch/issues"},"dist":{"shasum":"19d921b4039ecfbc7f7ac870de6235ae0144bf33","tarball":"https://registry.npmjs.org/@borisch/snitch/-/snitch-1.2.4.tgz","fileCount":345,"integrity":"sha512-86H6tmP+cXp8yL92xkXe0wOjcACVolFPl6mzdBclXHJtbOQLmsjqjIxFwVKvIfyO7bthuTe80S/fN9W5QUfe2g==","signatures":[{"sig":"MEUCIQDzgdHTyy/896SovNPA6LM01+JlmiwoP2zkIq0vMK5qPwIgQAFfFKcW9VxbX+xoEwX75XwIuRxsw2v3dFBWHSGkbsY=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":247473},"jest":{"testMatch":["**/*.test.ts"],"transform":{"^.+\\.[tj]s$":"ts-jest"},"testEnvironment":"jsdom","collectCoverageFrom":["packages/**/*.ts"],"moduleFileExtensions":["ts","js"],"coveragePathIgnorePatterns":["/node_modules/"]},"main":"dist/cjs/index.js","module":"dist/esm/index.js","engines":{"node":">=18.0.0"},"exports":{".":{"types":"./dist/cjs/index.d.ts","import":"./dist/esm/index.js","require":"./dist/cjs/index.js"},"./server":{"types":"./dist/cjs/server.d.ts","import":"./dist/esm/server.js","require":"./dist/cjs/server.js"}},"gitHead":"3b5c6d0156ebf75fb71bfc1cd067995555009280","scripts":{"test":"jest","build":"tsc -p tsconfig.cjs.json && tsc -p tsconfig.esm.json && node scripts/fix-esm-imports.js","prebuild":"rimraf dist","test:watch":"jest --coverage --watch"},"typings":"dist/cjs/index.d.ts","_npmUser":{"name":"borisch","email":"borisboha@gmail.com"},"prettier":{"semi":false,"singleQuote":true},"repository":{"url":"git+https://github.com/BorisChumichev/snitch.git","type":"git"},"_npmVersion":"11.16.0","description":"Modular analytics tracking library with pluggable transports","directories":{},"_nodeVersion":"24.18.0","dependencies":{"web-vitals":"^3.5.0"},"_hasShrinkwrap":false,"devDependencies":{"jest":"^29.7.0","delay":"^5.0.0","tslib":"^2.8.0","rimraf":"^6.0.0","ts-jest":"^29.2.0","ts-node":"^10.9.0","prettier":"^3.5.0","typescript":"^5.8.0","@types/jest":"^29.5.0","@types/node":"^22.0.0","jest-environment-jsdom":"^29.7.0"},"_npmOperationalInternal":{"tmp":"tmp/snitch_1.2.4_1783815628490_0.8279454582799872","host":"s3://npm-registry-packages-npm-production"}},"1.2.5":{"name":"@borisch/snitch","version":"1.2.5","description":"Modular analytics tracking library with pluggable transports","keywords":["analytics","tracking","plugins","beacon","web-vitals"],"main":"dist/cjs/index.js","module":"dist/esm/index.js","typings":"dist/cjs/index.d.ts","exports":{".":{"types":"./dist/cjs/index.d.ts","import":"./dist/esm/index.js","require":"./dist/cjs/index.js"},"./server":{"types":"./dist/cjs/server.d.ts","import":"./dist/esm/server.js","require":"./dist/cjs/server.js"}},"author":{"name":"Boris Chumichev","email":"borisboha@gmail.com"},"repository":{"type":"git","url":"git+https://github.com/BorisChumichev/snitch.git"},"license":"MIT","engines":{"node":">=18.0.0"},"scripts":{"prebuild":"rimraf dist","build":"tsc -p tsconfig.cjs.json && tsc -p tsconfig.esm.json && node scripts/fix-esm-imports.js","test":"jest","test:watch":"jest --coverage --watch"},"jest":{"transform":{"^.+\\.[tj]s$":"ts-jest"},"testEnvironment":"jsdom","testMatch":["**/*.test.ts"],"moduleFileExtensions":["ts","js"],"coveragePathIgnorePatterns":["/node_modules/"],"collectCoverageFrom":["packages/**/*.ts"]},"prettier":{"semi":false,"singleQuote":true},"devDependencies":{"@types/jest":"^29.5.0","@types/node":"^22.0.0","delay":"^5.0.0","jest":"^29.7.0","jest-environment-jsdom":"^29.7.0","prettier":"^3.5.0","rimraf":"^6.0.0","ts-jest":"^29.2.0","ts-node":"^10.9.0","tslib":"^2.8.0","typescript":"^5.8.0"},"dependencies":{"web-vitals":"^3.5.0"},"gitHead":"a7c943a6e6f221ba4e1fe9f9e570d82e06aee484","_id":"@borisch/snitch@1.2.5","bugs":{"url":"https://github.com/BorisChumichev/snitch/issues"},"homepage":"https://github.com/BorisChumichev/snitch#readme","_nodeVersion":"24.18.0","_npmVersion":"11.16.0","dist":{"integrity":"sha512-/+4CE57dhG6G7VOHE/7qSdnjKKWg7dLUNJRdv3wv8TIvsVcvX1IfQqpy73lpFdHgFUon9sR0CHXTBhppYeBYLA==","shasum":"1b035c4bf4f35a270c21b50caee03a37727d7d7a","tarball":"https://registry.npmjs.org/@borisch/snitch/-/snitch-1.2.5.tgz","fileCount":357,"unpackedSize":252522,"signatures":[{"keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U","sig":"MEQCIAFKUazz4R/S7Q6C5cGpEMpHoKMGpAWPSCvylOwHQFbeAiBf1v54nkSspXwK8bVsy788OuUn2vO5ffHH11IQpJfMuA=="}]},"_npmUser":{"name":"borisch","email":"borisboha@gmail.com"},"directories":{},"maintainers":[{"name":"borisch","email":"borisboha@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages-npm-production","tmp":"tmp/snitch_1.2.5_1783879506905_0.8325549812197295"},"_hasShrinkwrap":false}},"time":{"created":"2026-02-12T17:45:39.622Z","modified":"2026-07-12T18:05:07.159Z","1.0.0":"2026-02-12T17:45:39.870Z","1.0.1":"2026-02-12T17:56:06.449Z","1.0.2":"2026-02-12T18:17:04.554Z","1.1.0":"2026-02-12T18:56:39.052Z","1.2.0":"2026-02-12T21:09:30.548Z","1.2.1":"2026-02-12T21:21:16.684Z","1.2.2":"2026-02-12T21:27:12.825Z","1.2.3":"2026-07-11T16:00:24.830Z","1.2.4":"2026-07-12T00:20:28.621Z","1.2.5":"2026-07-12T18:05:07.051Z"},"bugs":{"url":"https://github.com/BorisChumichev/snitch/issues"},"author":{"name":"Boris Chumichev","email":"borisboha@gmail.com"},"license":"MIT","homepage":"https://github.com/BorisChumichev/snitch#readme","keywords":["analytics","tracking","plugins","beacon","web-vitals"],"repository":{"type":"git","url":"git+https://github.com/BorisChumichev/snitch.git"},"description":"Modular analytics tracking library with pluggable transports","maintainers":[{"name":"borisch","email":"borisboha@gmail.com"}],"readme":"# Snitch\n\nModular analytics tracking library. Compose your tracker from small, focused plugins and transports.\n\n## Install\n\n```bash\nnpm install @borisch/snitch\n```\n\n## Quick Start (Browser)\n\n```ts\nimport {\n  snitch,\n  environmentPlugin,\n  devicePlugin,\n  deviceInfoPlugin,\n  userPlugin,\n  sessionPlugin,\n  launchPlugin,\n  scrollPlugin,\n  locationPlugin,\n  beaconTransportPlugin,\n  debugLoggerPlugin,\n} from '@borisch/snitch'\n\nconst captureEvent = snitch(\n  environmentPlugin({ av: '2.4.0' }),\n  devicePlugin(),\n  deviceInfoPlugin(),\n  userPlugin(),\n  sessionPlugin(),\n  launchPlugin(),\n  scrollPlugin(),\n  locationPlugin({ captureLocationChange: true }),\n  beaconTransportPlugin({ hostname: 'analytics.example.com' }),\n  debugLoggerPlugin(),\n)\n\n// Manually capture events\ncaptureEvent('button_click', { buttonId: 'signup' })\n```\n\n## Reading Snitch Context\n\nThe callable object returned by `snitch()` exposes `getContext()`. It returns a fresh snapshot of the fields currently provided by configured plugins, such as `did`, `sid`, `uid`, `lid`, screen details, and location.\n\nUse it to associate another application request with the same analytics context:\n\n```ts\nconst track = snitch(\n  devicePlugin(),\n  sessionPlugin(),\n  launchPlugin(),\n)\n\nawait fetch('/order', {\n  method: 'POST',\n  headers: { 'content-type': 'application/json' },\n  body: JSON.stringify({\n    items: ['bread', 'milk', 'icecream'],\n    _snitch: track.getContext(),\n  }),\n})\n```\n\n`getContext()` is a pure read: it does not capture an event, invoke before-capture hooks, call a transport, or update session activity. When `sessionPlugin()` is configured, an expired session keeps its previous `sid` until the next captured event starts a new session.\n\n---\n\n## Server-Side Usage\n\nMany plugins use browser APIs (`window`, `document`, `localStorage`). Importing `@borisch/snitch` on the server will fail because some plugins reference `window` at the module level.\n\nUse the server entry point instead:\n\n```ts\nimport {\n  snitch,\n  environmentPlugin,\n  userPlugin,\n  devicePlugin,\n  screenPlugin,\n  debugLoggerPlugin,\n  s2sTransportPlugin,\n} from '@borisch/snitch/server'\n```\n\nThe server entry point exports only the plugins and transports that work without browser APIs:\n\n| Export               | Description                                                |\n| -------------------- | ---------------------------------------------------------- |\n| `snitch`             | Core factory function                                      |\n| `environmentPlugin`  | Static build and deployment metadata                       |\n| `userPlugin`         | In-memory user ID tracking                                 |\n| `devicePlugin`       | Device ID (falls back to random ID without `localStorage`) |\n| `screenPlugin`       | Screen tracking (pure state management)                    |\n| `debugLoggerPlugin`  | Console logger (silently disabled without `localStorage`)  |\n| `s2sTransportPlugin` | HTTP transport via `fetch()` (available in Node 18+)       |\n\nAll types are also re-exported from `@borisch/snitch/server`.\n\n**Example — server-side event tracking:**\n\n```ts\nimport { snitch, userPlugin, s2sTransportPlugin } from '@borisch/snitch/server'\n\nconst track = snitch(userPlugin(), s2sTransportPlugin({ hostname: 'analytics.example.com' })) as any\n\n// One-shot event with a specific user ID\ntrack.withUserId(req.userId, 'checkout_completed', { orderId: '12345' })\n```\n\nThe `snitch()` function accepts any number of plugins and returns a `captureEvent` function. Plugins can:\n\n- **Provide event parameters** — automatically attached to every event\n- **Emit events** on their own (e.g. scroll milestones, page views)\n- **Transport events** to a backend\n- **Intercept events** before they are sent\n- **Expose mixins** — additional methods attached to the `captureEvent` function\n\n## Plugins\n\n### `environmentPlugin(payload)`\n\nAttaches static application, build, or deployment metadata to every event. It accepts any string and number fields supported by `TrackerEventPayload`:\n\n```ts\nenvironmentPlugin({\n  av: '2.4.0',\n  environment: 'production',\n  build: 184,\n})\n```\n\nThe plugin shallow-copies the payload when it is created, so later changes to the original object do not affect analytics. Its fields are also exposed by `getContext()`. It works from both `@borisch/snitch` and `@borisch/snitch/server` and accepts an empty object.\n\n`av` is the recommended application-version field for measuring release adoption and investigating version-specific problems. It is only a convention: `environmentPlugin` does not require or validate it, semantic versions, or any other field.\n\nAs with other payload-provider plugins, these fields override same-named fields passed directly to an event. A later provider plugin can override them again.\n\n---\n\n### `sessionPlugin()`\n\nManages user sessions using `localStorage`. A new session starts when:\n\n- No previous session exists\n- The previous session has been inactive for 30+ minutes\n- UTM parameters are present in the URL\n\nIf a session expires between events, a new session is started automatically before the next event is sent.\n\nEmits: `sessionStart`\n\nAttaches to every event:\n| Param | Description |\n|-------|-------------|\n| `sid` | Unique session ID |\n| `scnt` | Total session count for this device |\n| `set` | Milliseconds since session started |\n| `sutm` | Compact UTM parameters from the URL that started the session |\n\n---\n\n### `launchPlugin()`\n\nCaptures a `launch` event when the tracker initializes. Records whether the page runs inside an iframe.\n\nEmits: `launch` with `{ ifr: \"true\" | \"false\" }`\n\nAttaches to every event:\n| Param | Description |\n|-------|-------------|\n| `lid` | Unique launch ID (generated per `snitch()` call) |\n| `ref` | `document.referrer` at initialization time |\n\n---\n\n### `scrollPlugin()`\n\nTracks scroll depth. Emits events when the user scrolls past depth milestones (25%, 50%, 75%, 100%). The scroll depth cache resets whenever a `locationChange` or `screenChange` event occurs, so milestones are tracked per-page.\n\nEmits: `scroll` with `{ depthPercent: number }`\n\n---\n\n### `locationPlugin(options)`\n\nTracks the current page URL and optionally emits events on URL changes (SPA navigation, `pushState`, etc.).\n\n**Options:**\n| Option | Type | Description |\n|--------|------|-------------|\n| `captureLocationChange` | `boolean` | Whether to listen for URL changes and emit events |\n| `getLocation` | `() => string` | Custom location getter (defaults to `window.location.href`) |\n\nEmits (when `captureLocationChange` is `true`): `locationChange` with `{ phref: string }` (previous URL)\n\nAttaches to every event:\n| Param | Description |\n|-------|-------------|\n| `href` | Current page URL (truncated to 500 characters) |\n\n---\n\n### `engagementPlugin(options?)`\n\nPeriodically emits engagement events while the page is visible. Events are suppressed when the tab is hidden (`document.hidden === true`).\n\n**Options:**\n| Option | Type | Default | Description |\n|--------|------|---------|-------------|\n| `engagementTrackingIntervalMsec` | `number` | `10000` | Interval in milliseconds between engagement pings |\n\nEmits: `engage` (at configured interval, only when tab is visible)\n\n---\n\n### `screenPlugin(initialScreen)`\n\nTracks screen/page views within an app. Maintains current and previous screen state.\n\n**Options:**\n| Option | Type | Description |\n|--------|------|-------------|\n| `screenType` | `string` | Type/category of the initial screen |\n| `screenId` | `string?` | Optional screen identifier |\n\nTo change screens, call `captureEvent('screenChange', { screenType: 'catalog', screenId: 'page2' })`. The plugin automatically injects previous screen params and removes the raw `screenType`/`screenId` from the event payload.\n\nAttaches to every event:\n| Param | Description |\n|-------|-------------|\n| `sct` | Current screen type |\n| `scid` | Current screen ID (or `\"\"`) |\n\nAttaches to `screenChange` events:\n| Param | Description |\n|-------|-------------|\n| `psct` | Previous screen type |\n| `pscid` | Previous screen ID (or `\"\"`) |\n\n---\n\n### `exceptionsPlugin()`\n\nCaptures unhandled errors and promise rejections globally.\n\nEmits:\n\n- `uncaughtError` with `{ message, filename, lineno, colno, error }`\n- `unhandledRejection` with `{ reason }`\n\n---\n\n### `webVitalsPlugin()`\n\nReports [Core Web Vitals](https://web.dev/vitals/) using the `web-vitals` library. Tracks CLS, FID, LCP, TTFB, and FCP.\n\nEmits: `webVital` with `{ name, value, delta, metricId }`\n\n---\n\n### `flagPlugin(options)`\n\nFeature flag evaluation plugin. Adds `getFlag()` and `getFlags()` methods to the `captureEvent` function via mixins.\n\n**Options:**\n| Option | Type | Description |\n|--------|------|-------------|\n| `flagApiEndpoint` | `string` | URL of the flag evaluation API |\n| `userIdResolver` | `() => string \\| null \\| undefined` | Optional custom user ID resolver |\n\nUser ID is resolved in order: custom resolver → VK user ID from URL → Top Mail.ru counter cookie → auto-generated anonymous ID (persisted in `localStorage`).\n\n**Usage:**\n\n```ts\nconst captureEvent = snitch(flagPlugin({ flagApiEndpoint: 'https://flags.example.com/api' })) as any\n\nconst flag = await captureEvent.getFlag('new-feature')\n// { flagKey: 'new-feature', match: true, variant: 'control', attachment: '...' }\n\nconst flags = await captureEvent.getFlags(['feature-a', 'feature-b'])\n```\n\nEmits:\n\n- `flagEvaluationComplete` with full evaluation response\n- `flagEvaluationFailed` with `{ flagKey, errorMessage }`\n\n---\n\n### `useragentPlugin()`\n\nAttaches the browser user agent string to every event.\n\nAttaches to every event:\n| Param | Description |\n|-------|-------------|\n| `ua` | `navigator.userAgent` |\n\n---\n\n### `deviceInfoPlugin()`\n\nCaptures a browser device snapshot when the plugin is created and attaches it to every event. The snapshot does not change after rotation, monitor changes, or system-setting changes.\n\nAttaches to every event:\n\n| Param | Description |\n|-------|-------------|\n| `sw` | Screen width in CSS pixels |\n| `sh` | Screen height in CSS pixels |\n| `os` | Best-effort normalized operating-system family |\n| `dtype` | `mobile`, `tablet`, `desktop`, `tv`, `console`, `wearable`, `embedded`, or `unknown` |\n| `lang` | Preferred browser UI language, used as the closest Web API signal for system language |\n| `tz` | IANA system timezone, or `unknown` when unavailable |\n| `touch` | `1` when the device reports touch points; otherwise `0` |\n| `cursor` | `1` when any input can hover; otherwise `0` |\n\nOS and device type are conservative classifications based on synchronous browser APIs and UA fallbacks. The plugin does not use screen-size breakpoints, request high-entropy Client Hints, or add the raw user agent as `ua`. The receiving server can inspect the HTTP `User-Agent` header; use `useragentPlugin()` only when the raw value must also be part of the event payload.\n\n---\n\n### `devicePlugin(options?)`\n\nWhen called without options, generates a persistent device (browser) identifier stored in `localStorage` under the key `snitch:did`. The ID is created once and reused forever across all sessions — it survives page reloads, tab closes, and new sessions. It only resets if the user clears their browser storage.\n\nIf the application already has a device identifier, pass it directly:\n\n```ts\ndevicePlugin({ deviceId: existingDeviceId })\n```\n\nThe supplied ID is used as-is and is kept in memory only; `devicePlugin` does not read or write `localStorage` in this mode. The application owns persistence and should pass the same ID when creating a later Snitch instance.\n\nIf `localStorage` is unavailable and no `deviceId` is supplied, a new ID is generated per `snitch()` call (in-memory only).\n\nAttaches to every event:\n| Param | Description |\n|-------|-------------|\n| `did` | Persistent device ID |\n\n---\n\n### `userPlugin(userId?)`\n\nTracks the current user. Exposes `.setUserId(id)` and `.clearUserId()` methods on the `captureEvent` function via mixins. The user ID is stored in-memory only — no `localStorage`, no emitted events. This makes it safe to use in both browser and server-side environments.\n\nWhen no user ID is set, `uid` is omitted from events entirely.\n\nIf the user ID is known at initialization time, it can be passed directly:\n\n```ts\nconst captureEvent = snitch(\n  userPlugin('user-123'),\n  // ...\n) as any\n```\n\nOtherwise, set it later:\n\n```ts\ncaptureEvent.setUserId('user-123')\n```\n\n**Methods (mixins):**\n| Method | Description |\n|--------|-------------|\n| `setUserId(id: string)` | Set the user ID. All subsequent events will include `uid`. |\n| `clearUserId()` | Clear the user ID. `uid` is no longer attached to events. |\n| `withUserId(id: string, eventName: string, eventPayload?)` | Temporarily set the user ID, send a single event, then restore the previous user ID. Designed for server-side use where a single snitch instance handles multiple users. |\n\nAttaches to every event (while user ID is set):\n| Param | Description |\n|-------|-------------|\n| `uid` | Current user ID |\n\n**Usage:**\n\n```ts\nconst captureEvent = snitch(\n  devicePlugin(),\n  userPlugin(),\n  sessionPlugin(),\n  beaconTransportPlugin({ hostname: '...' }),\n) as any\n\n// User logs in\ncaptureEvent.setUserId('user-123')\n\ncaptureEvent('add_to_cart', { productId: 'abc' })\n// => { event: 'add_to_cart', productId: 'abc', uid: 'user-123', did: '...', sid: '...' }\n\n// User logs out\ncaptureEvent.clearUserId()\n// uid is no longer attached to events\n\n// Server-side (s2s-transport) — pass uid at init, no localStorage needed\nconst track = snitch(\n  userPlugin(req.userId),\n  s2sTransportPlugin({ hostname: 'analytics.example.com' }),\n)\ntrack('subscriptionRenewalPaymentFailed')\n// => { event: 'subscriptionRenewalPaymentFailed', uid: 'user-123' }\n```\n\n**Server-side with `.withUserId()`:**\n\nWhen a single snitch instance handles requests from multiple users (e.g., in an Express handler), use `.withUserId()` to atomically send an event with a specific user ID without affecting other requests. The captureEvent pipeline is synchronous, so the temporary uid swap is safe — no interleaving is possible.\n\n```ts\nconst track = snitch(userPlugin(), s2sTransportPlugin({ hostname: 'analytics.example.com' })) as any\n\napp.post('/api/checkout', (req, res) => {\n  // Sends this one event with uid='user-42', then restores previous state\n  track.withUserId(req.userId, 'checkout_completed', { orderId: req.body.orderId })\n  res.json({ ok: true })\n})\n```\n\n---\n\n### `debugLoggerPlugin()`\n\nDevelopment helper. Logs every event to the browser console with timestamps and time deltas between events. When the event has a non-empty payload, it is also rendered via `console.table()`.\n\n**Silent by default.** To enable, set a `localStorage` flag:\n\n```js\nlocalStorage.setItem('snitch:debug', 'true')\n```\n\nThe flag is read once when `debugLoggerPlugin()` is called. To disable, remove the flag and reload:\n\n```js\nlocalStorage.removeItem('snitch:debug')\n```\n\n---\n\n## Transports\n\n### `beaconTransportPlugin(options?)`\n\nSends events via [`navigator.sendBeacon()`](https://developer.mozilla.org/en-US/docs/Web/API/Navigator/sendBeacon). All event data is encoded as URL query parameters — designed for CDN log-based analytics where request URLs are parsed from access logs.\n\n**Options:**\n| Option | Type | Default | Description |\n|--------|------|---------|-------------|\n| `hostname` | `string` | `window.location.hostname` | Target hostname |\n| `path` | `string` | `/_snitch` | URL path |\n\nRequests are sent to: `{protocol}//{hostname}{path}?event={name}&...params`\n\n---\n\n### `s2sTransportPlugin(options)`\n\nSends events via `fetch()` GET requests over HTTPS. Fire-and-forget (errors are silently caught). Designed for server-side environments (Node 18+, Cloudflare Workers) or any environment with `fetch`.\n\n**Options:**\n| Option | Type | Default | Description |\n|--------|------|---------|-------------|\n| `hostname` | `string` | _required_ | Target hostname |\n| `path` | `string` | `/_snitch` | URL path |\n| `s2sToken` | `string` | — | Optional auth token (sent as a query parameter) |\n\nRequests are sent to: `https://{hostname}{path}?event={name}&...params[&s2sToken=...]`\n\n---\n\n### `topmailruTransportPlugin(counterId, userIdResolver?)`\n\nSends events to [Top Mail.ru](https://top.mail.ru/) analytics counter by pushing to the `window._tmr` queue.\n\n**Parameters:**\n| Param | Type | Description |\n|-------|------|-------------|\n| `counterId` | `string` | Top Mail.ru counter ID (required) |\n| `userIdResolver` | `() => string \\| null \\| undefined` | Optional custom user ID resolver |\n\nUser ID resolution order: custom resolver → TMR counter cookie → auto-generated anonymous ID.\n\n---\n\n### `vkBridgeTransportPlugin()`\n\nSends events via [VK Bridge](https://dev.vk.com/mini-apps/bridge) for VK Mini Apps. Extracts `vk_user_id` from the URL. Each event triggers two VK Bridge calls: `VKWebAppTrackEvent` and `VKWebAppSendCustomEvent`. All param values are coerced to strings to work around iOS VK Bridge limitations.\n\n---\n\n## Platform-Specific Plugins\n\n### `vkmaLaunchPlugin()`\n\nA VK Mini Apps variant of `launchPlugin`. Parses VK Mini App launch parameters from the URL (`vk_user_id`, `vk_app_id`, `vk_platform`, `vk_ref`, etc.).\n\nEmits: `launch` (with iframe flag + VKMA params), `mt_internal_launch`\n\nAttaches to every event:\n| Param | Description |\n|-------|-------------|\n| `lid` | Unique launch ID |\n| `ref` | `document.referrer` |\n| `mauid` | VK user ID |\n| `maaid` | VK app ID |\n| `malang` | VK language |\n| `mac` | VK access token settings |\n| `map` | VK platform |\n| `maref` | VK ref |\n\n---\n\n## Types\n\nAll public types are exported for TypeScript consumers:\n\n```ts\nimport type {\n  Plugin,\n  EventTransport,\n  EventSource,\n  EventPayloadParamsProvider,\n  InitializationHandler,\n  BeforeCaptureEventHandler,\n  MixinProvider,\n  TrackerEventPayload,\n  EventHandler,\n  SnitchInstance,\n} from '@borisch/snitch'\n```\n\n## Writing a Custom Plugin\n\nA plugin is any object that partially implements the `Plugin` interface:\n\n```ts\nimport type { Plugin } from '@borisch/snitch'\n\nfunction myPlugin(): Plugin {\n  return {\n    // Attach params to every event\n    getEventPayloadParams() {\n      return { customParam: 'value' }\n    },\n    // React to events before transport\n    beforeCaptureEvent(eventName, eventParams) {\n      // filter, modify, log, etc.\n    },\n    // Transport events\n    sendEvent(eventName, eventParams) {\n      fetch('/analytics', {\n        method: 'POST',\n        body: JSON.stringify({ eventName, ...eventParams }),\n      })\n    },\n  }\n}\n```\n\n## License\n\nMIT\n","readmeFilename":"README.md"}