1
0
Fork 0
mirror of https://github.com/Findus23/MatomoLiteTracker.git synced 2024-09-19 16:03:45 +02:00

initial version

This commit is contained in:
Lukas Winkler 2022-04-25 20:36:48 +02:00
commit 30c164f438
Signed by: lukas
GPG key ID: 54DE4D798D244853
17 changed files with 1478 additions and 0 deletions

10
.gitignore vendored Normal file
View file

@ -0,0 +1,10 @@
.idea/
piwik.js
out.js
out.min.js
*.map
node_modules
dist
example/
!example/index.html
!example/main.ts

11
LICENSE Normal file
View file

@ -0,0 +1,11 @@
Copyright 2022 Lukas Winkler
Copyright 2013-2022 Matomo Team
Copyright 2013 Anthon Pang
Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

64
README.md Normal file
View file

@ -0,0 +1,64 @@
# Matomo Lite Tracker
This is an experiment of building a more lightweight variant of matomo.js by removing rarely used features and support
for old browsers.
**Keep in mind this is**:
- experimental: I can't guarantee that it will work as expected
- inofficial: This is not officially maintained by the Matomo team
- incomplete: See below.
That said, if you are interested in trying it out, I'd be interested in hearing your feedback.
## Advantages:
- much smaller (1KB gzipped with only the core code)
- easier to bundle in applications
## Features
- tracking page views
- custom dimensions
- send data via POST
- browser features
- cookie
- res
- browser plugins (pdf, flash, etc.)
- User ID
- Event Tracking
- Campaign tracking
- Search Tracking
- Goal Tracking
- manual Outlink Tracking
- manual ping
- manual DoNotTrack detection
## missing (yet)
- non utf-8 pages
- setCustomUrl
- setReferrerUrl
- automatic outlink tracking
- event queue (every tracking request is sent immediatly when it is tracked)[^1]
- HeartBeatTimer (automatic regular ping)
## missing (???)
- consent tracking, opt-in, opt-out (probably better to be implemented by the user)
- Content Tracking
- download tracking
- setDomains
## missing (intentionally)
- Support for Internet Explorer and other outdated browsers
- everything using cookies (except possibly the opt-out cookie)
- custom variables
- Support for Matomo plugins
- E-Commerce tracking
[^1]: This might create some issues if you run `trackPageview()` and `trackEvent()` at the same time as the requests
might not reach Matomo in this order.

31
build.ts Normal file
View file

@ -0,0 +1,31 @@
import type {BuildFailure, BuildOptions} from "esbuild";
import {build, serve} from "esbuild";
const options: BuildOptions = {
entryPoints: ['src/entry.ts'],
target: "es2017",
bundle: true,
format: "iife",
sourcemap: true,
minify: true,
outfile: "dist/bundle.js"
}
console.log(process.argv)
if (process.argv.length > 2 && process.argv[2] == "serve") {
options.entryPoints = ["example/main.ts"]
options.outfile = "example/main.min.js"
build(options).catch((error: BuildFailure) => console.error(error))
options.minify = false
options.outfile = "example/main.js"
build(options).catch((error: BuildFailure) => console.error(error))
serve({servedir: "example/"}, options)
.catch((error: BuildFailure) => console.error(error))
.then(data => console.log(data))
} else {
build(options).catch((error: BuildFailure) => console.error(error))
options.minify = true
options.outfile = "dist/bundle.min.js"
build(options).catch((error: BuildFailure) => console.error(error))
}

835
package-lock.json generated Normal file
View file

@ -0,0 +1,835 @@
{
"name": "matomo-lite-tracker",
"version": "1.0.0",
"lockfileVersion": 2,
"requires": true,
"packages": {
"": {
"name": "matomo-lite-tracker",
"version": "1.0.0",
"license": "BSD-3-Clause",
"devDependencies": {
"esbuild": "^0.14.38",
"ts-node": "^10.7.0",
"typescript": "^4.6.3"
}
},
"node_modules/@cspotcode/source-map-consumer": {
"version": "0.8.0",
"resolved": "https://registry.npmjs.org/@cspotcode/source-map-consumer/-/source-map-consumer-0.8.0.tgz",
"integrity": "sha512-41qniHzTU8yAGbCp04ohlmSrZf8bkf/iJsl3V0dRGsQN/5GFfx+LbCSsCpp2gqrqjTVg/K6O8ycoV35JIwAzAg==",
"dev": true,
"engines": {
"node": ">= 12"
}
},
"node_modules/@cspotcode/source-map-support": {
"version": "0.7.0",
"resolved": "https://registry.npmjs.org/@cspotcode/source-map-support/-/source-map-support-0.7.0.tgz",
"integrity": "sha512-X4xqRHqN8ACt2aHVe51OxeA2HjbcL4MqFqXkrmQszJ1NOUuUu5u6Vqx/0lZSVNku7velL5FC/s5uEAj1lsBMhA==",
"dev": true,
"dependencies": {
"@cspotcode/source-map-consumer": "0.8.0"
},
"engines": {
"node": ">=12"
}
},
"node_modules/@tsconfig/node10": {
"version": "1.0.8",
"resolved": "https://registry.npmjs.org/@tsconfig/node10/-/node10-1.0.8.tgz",
"integrity": "sha512-6XFfSQmMgq0CFLY1MslA/CPUfhIL919M1rMsa5lP2P097N2Wd1sSX0tx1u4olM16fLNhtHZpRhedZJphNJqmZg==",
"dev": true
},
"node_modules/@tsconfig/node12": {
"version": "1.0.9",
"resolved": "https://registry.npmjs.org/@tsconfig/node12/-/node12-1.0.9.tgz",
"integrity": "sha512-/yBMcem+fbvhSREH+s14YJi18sp7J9jpuhYByADT2rypfajMZZN4WQ6zBGgBKp53NKmqI36wFYDb3yaMPurITw==",
"dev": true
},
"node_modules/@tsconfig/node14": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/@tsconfig/node14/-/node14-1.0.1.tgz",
"integrity": "sha512-509r2+yARFfHHE7T6Puu2jjkoycftovhXRqW328PDXTVGKihlb1P8Z9mMZH04ebyajfRY7dedfGynlrFHJUQCg==",
"dev": true
},
"node_modules/@tsconfig/node16": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/@tsconfig/node16/-/node16-1.0.2.tgz",
"integrity": "sha512-eZxlbI8GZscaGS7kkc/trHTT5xgrjH3/1n2JDwusC9iahPKWMRvRjJSAN5mCXviuTGQ/lHnhvv8Q1YTpnfz9gA==",
"dev": true
},
"node_modules/@types/node": {
"version": "17.0.27",
"resolved": "https://registry.npmjs.org/@types/node/-/node-17.0.27.tgz",
"integrity": "sha512-4/Ke7bbWOasuT3kceBZFGakP1dYN2XFd8v2l9bqF2LNWrmeU07JLpp56aEeG6+Q3olqO5TvXpW0yaiYnZJ5CXg==",
"dev": true,
"peer": true
},
"node_modules/acorn": {
"version": "8.7.0",
"resolved": "https://registry.npmjs.org/acorn/-/acorn-8.7.0.tgz",
"integrity": "sha512-V/LGr1APy+PXIwKebEWrkZPwoeoF+w1jiOBUmuxuiUIaOHtob8Qc9BTrYo7VuI5fR8tqsy+buA2WFooR5olqvQ==",
"dev": true,
"bin": {
"acorn": "bin/acorn"
},
"engines": {
"node": ">=0.4.0"
}
},
"node_modules/acorn-walk": {
"version": "8.2.0",
"resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.2.0.tgz",
"integrity": "sha512-k+iyHEuPgSw6SbuDpGQM+06HQUa04DZ3o+F6CSzXMvvI5KMvnaEqXe+YVe555R9nn6GPt404fos4wcgpw12SDA==",
"dev": true,
"engines": {
"node": ">=0.4.0"
}
},
"node_modules/arg": {
"version": "4.1.3",
"resolved": "https://registry.npmjs.org/arg/-/arg-4.1.3.tgz",
"integrity": "sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==",
"dev": true
},
"node_modules/create-require": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/create-require/-/create-require-1.1.1.tgz",
"integrity": "sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==",
"dev": true
},
"node_modules/diff": {
"version": "4.0.2",
"resolved": "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz",
"integrity": "sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==",
"dev": true,
"engines": {
"node": ">=0.3.1"
}
},
"node_modules/esbuild": {
"version": "0.14.38",
"resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.14.38.tgz",
"integrity": "sha512-12fzJ0fsm7gVZX1YQ1InkOE5f9Tl7cgf6JPYXRJtPIoE0zkWAbHdPHVPPaLi9tYAcEBqheGzqLn/3RdTOyBfcA==",
"dev": true,
"hasInstallScript": true,
"bin": {
"esbuild": "bin/esbuild"
},
"engines": {
"node": ">=12"
},
"optionalDependencies": {
"esbuild-android-64": "0.14.38",
"esbuild-android-arm64": "0.14.38",
"esbuild-darwin-64": "0.14.38",
"esbuild-darwin-arm64": "0.14.38",
"esbuild-freebsd-64": "0.14.38",
"esbuild-freebsd-arm64": "0.14.38",
"esbuild-linux-32": "0.14.38",
"esbuild-linux-64": "0.14.38",
"esbuild-linux-arm": "0.14.38",
"esbuild-linux-arm64": "0.14.38",
"esbuild-linux-mips64le": "0.14.38",
"esbuild-linux-ppc64le": "0.14.38",
"esbuild-linux-riscv64": "0.14.38",
"esbuild-linux-s390x": "0.14.38",
"esbuild-netbsd-64": "0.14.38",
"esbuild-openbsd-64": "0.14.38",
"esbuild-sunos-64": "0.14.38",
"esbuild-windows-32": "0.14.38",
"esbuild-windows-64": "0.14.38",
"esbuild-windows-arm64": "0.14.38"
}
},
"node_modules/esbuild-android-64": {
"version": "0.14.38",
"resolved": "https://registry.npmjs.org/esbuild-android-64/-/esbuild-android-64-0.14.38.tgz",
"integrity": "sha512-aRFxR3scRKkbmNuGAK+Gee3+yFxkTJO/cx83Dkyzo4CnQl/2zVSurtG6+G86EQIZ+w+VYngVyK7P3HyTBKu3nw==",
"cpu": [
"x64"
],
"dev": true,
"optional": true,
"os": [
"android"
],
"engines": {
"node": ">=12"
}
},
"node_modules/esbuild-android-arm64": {
"version": "0.14.38",
"resolved": "https://registry.npmjs.org/esbuild-android-arm64/-/esbuild-android-arm64-0.14.38.tgz",
"integrity": "sha512-L2NgQRWuHFI89IIZIlpAcINy9FvBk6xFVZ7xGdOwIm8VyhX1vNCEqUJO3DPSSy945Gzdg98cxtNt8Grv1CsyhA==",
"cpu": [
"arm64"
],
"dev": true,
"optional": true,
"os": [
"android"
],
"engines": {
"node": ">=12"
}
},
"node_modules/esbuild-darwin-64": {
"version": "0.14.38",
"resolved": "https://registry.npmjs.org/esbuild-darwin-64/-/esbuild-darwin-64-0.14.38.tgz",
"integrity": "sha512-5JJvgXkX87Pd1Og0u/NJuO7TSqAikAcQQ74gyJ87bqWRVeouky84ICoV4sN6VV53aTW+NE87qLdGY4QA2S7KNA==",
"cpu": [
"x64"
],
"dev": true,
"optional": true,
"os": [
"darwin"
],
"engines": {
"node": ">=12"
}
},
"node_modules/esbuild-darwin-arm64": {
"version": "0.14.38",
"resolved": "https://registry.npmjs.org/esbuild-darwin-arm64/-/esbuild-darwin-arm64-0.14.38.tgz",
"integrity": "sha512-eqF+OejMI3mC5Dlo9Kdq/Ilbki9sQBw3QlHW3wjLmsLh+quNfHmGMp3Ly1eWm981iGBMdbtSS9+LRvR2T8B3eQ==",
"cpu": [
"arm64"
],
"dev": true,
"optional": true,
"os": [
"darwin"
],
"engines": {
"node": ">=12"
}
},
"node_modules/esbuild-freebsd-64": {
"version": "0.14.38",
"resolved": "https://registry.npmjs.org/esbuild-freebsd-64/-/esbuild-freebsd-64-0.14.38.tgz",
"integrity": "sha512-epnPbhZUt93xV5cgeY36ZxPXDsQeO55DppzsIgWM8vgiG/Rz+qYDLmh5ts3e+Ln1wA9dQ+nZmVHw+RjaW3I5Ig==",
"cpu": [
"x64"
],
"dev": true,
"optional": true,
"os": [
"freebsd"
],
"engines": {
"node": ">=12"
}
},
"node_modules/esbuild-freebsd-arm64": {
"version": "0.14.38",
"resolved": "https://registry.npmjs.org/esbuild-freebsd-arm64/-/esbuild-freebsd-arm64-0.14.38.tgz",
"integrity": "sha512-/9icXUYJWherhk+y5fjPI5yNUdFPtXHQlwP7/K/zg8t8lQdHVj20SqU9/udQmeUo5pDFHMYzcEFfJqgOVeKNNQ==",
"cpu": [
"arm64"
],
"dev": true,
"optional": true,
"os": [
"freebsd"
],
"engines": {
"node": ">=12"
}
},
"node_modules/esbuild-linux-32": {
"version": "0.14.38",
"resolved": "https://registry.npmjs.org/esbuild-linux-32/-/esbuild-linux-32-0.14.38.tgz",
"integrity": "sha512-QfgfeNHRFvr2XeHFzP8kOZVnal3QvST3A0cgq32ZrHjSMFTdgXhMhmWdKzRXP/PKcfv3e2OW9tT9PpcjNvaq6g==",
"cpu": [
"ia32"
],
"dev": true,
"optional": true,
"os": [
"linux"
],
"engines": {
"node": ">=12"
}
},
"node_modules/esbuild-linux-64": {
"version": "0.14.38",
"resolved": "https://registry.npmjs.org/esbuild-linux-64/-/esbuild-linux-64-0.14.38.tgz",
"integrity": "sha512-uuZHNmqcs+Bj1qiW9k/HZU3FtIHmYiuxZ/6Aa+/KHb/pFKr7R3aVqvxlAudYI9Fw3St0VCPfv7QBpUITSmBR1Q==",
"cpu": [
"x64"
],
"dev": true,
"optional": true,
"os": [
"linux"
],
"engines": {
"node": ">=12"
}
},
"node_modules/esbuild-linux-arm": {
"version": "0.14.38",
"resolved": "https://registry.npmjs.org/esbuild-linux-arm/-/esbuild-linux-arm-0.14.38.tgz",
"integrity": "sha512-FiFvQe8J3VKTDXG01JbvoVRXQ0x6UZwyrU4IaLBZeq39Bsbatd94Fuc3F1RGqPF5RbIWW7RvkVQjn79ejzysnA==",
"cpu": [
"arm"
],
"dev": true,
"optional": true,
"os": [
"linux"
],
"engines": {
"node": ">=12"
}
},
"node_modules/esbuild-linux-arm64": {
"version": "0.14.38",
"resolved": "https://registry.npmjs.org/esbuild-linux-arm64/-/esbuild-linux-arm64-0.14.38.tgz",
"integrity": "sha512-HlMGZTEsBrXrivr64eZ/EO0NQM8H8DuSENRok9d+Jtvq8hOLzrxfsAT9U94K3KOGk2XgCmkaI2KD8hX7F97lvA==",
"cpu": [
"arm64"
],
"dev": true,
"optional": true,
"os": [
"linux"
],
"engines": {
"node": ">=12"
}
},
"node_modules/esbuild-linux-mips64le": {
"version": "0.14.38",
"resolved": "https://registry.npmjs.org/esbuild-linux-mips64le/-/esbuild-linux-mips64le-0.14.38.tgz",
"integrity": "sha512-qd1dLf2v7QBiI5wwfil9j0HG/5YMFBAmMVmdeokbNAMbcg49p25t6IlJFXAeLzogv1AvgaXRXvgFNhScYEUXGQ==",
"cpu": [
"mips64el"
],
"dev": true,
"optional": true,
"os": [
"linux"
],
"engines": {
"node": ">=12"
}
},
"node_modules/esbuild-linux-ppc64le": {
"version": "0.14.38",
"resolved": "https://registry.npmjs.org/esbuild-linux-ppc64le/-/esbuild-linux-ppc64le-0.14.38.tgz",
"integrity": "sha512-mnbEm7o69gTl60jSuK+nn+pRsRHGtDPfzhrqEUXyCl7CTOCLtWN2bhK8bgsdp6J/2NyS/wHBjs1x8aBWwP2X9Q==",
"cpu": [
"ppc64"
],
"dev": true,
"optional": true,
"os": [
"linux"
],
"engines": {
"node": ">=12"
}
},
"node_modules/esbuild-linux-riscv64": {
"version": "0.14.38",
"resolved": "https://registry.npmjs.org/esbuild-linux-riscv64/-/esbuild-linux-riscv64-0.14.38.tgz",
"integrity": "sha512-+p6YKYbuV72uikChRk14FSyNJZ4WfYkffj6Af0/Tw63/6TJX6TnIKE+6D3xtEc7DeDth1fjUOEqm+ApKFXbbVQ==",
"cpu": [
"riscv64"
],
"dev": true,
"optional": true,
"os": [
"linux"
],
"engines": {
"node": ">=12"
}
},
"node_modules/esbuild-linux-s390x": {
"version": "0.14.38",
"resolved": "https://registry.npmjs.org/esbuild-linux-s390x/-/esbuild-linux-s390x-0.14.38.tgz",
"integrity": "sha512-0zUsiDkGJiMHxBQ7JDU8jbaanUY975CdOW1YDrurjrM0vWHfjv9tLQsW9GSyEb/heSK1L5gaweRjzfUVBFoybQ==",
"cpu": [
"s390x"
],
"dev": true,
"optional": true,
"os": [
"linux"
],
"engines": {
"node": ">=12"
}
},
"node_modules/esbuild-netbsd-64": {
"version": "0.14.38",
"resolved": "https://registry.npmjs.org/esbuild-netbsd-64/-/esbuild-netbsd-64-0.14.38.tgz",
"integrity": "sha512-cljBAApVwkpnJZfnRVThpRBGzCi+a+V9Ofb1fVkKhtrPLDYlHLrSYGtmnoTVWDQdU516qYI8+wOgcGZ4XIZh0Q==",
"cpu": [
"x64"
],
"dev": true,
"optional": true,
"os": [
"netbsd"
],
"engines": {
"node": ">=12"
}
},
"node_modules/esbuild-openbsd-64": {
"version": "0.14.38",
"resolved": "https://registry.npmjs.org/esbuild-openbsd-64/-/esbuild-openbsd-64-0.14.38.tgz",
"integrity": "sha512-CDswYr2PWPGEPpLDUO50mL3WO/07EMjnZDNKpmaxUPsrW+kVM3LoAqr/CE8UbzugpEiflYqJsGPLirThRB18IQ==",
"cpu": [
"x64"
],
"dev": true,
"optional": true,
"os": [
"openbsd"
],
"engines": {
"node": ">=12"
}
},
"node_modules/esbuild-sunos-64": {
"version": "0.14.38",
"resolved": "https://registry.npmjs.org/esbuild-sunos-64/-/esbuild-sunos-64-0.14.38.tgz",
"integrity": "sha512-2mfIoYW58gKcC3bck0j7lD3RZkqYA7MmujFYmSn9l6TiIcAMpuEvqksO+ntBgbLep/eyjpgdplF7b+4T9VJGOA==",
"cpu": [
"x64"
],
"dev": true,
"optional": true,
"os": [
"sunos"
],
"engines": {
"node": ">=12"
}
},
"node_modules/esbuild-windows-32": {
"version": "0.14.38",
"resolved": "https://registry.npmjs.org/esbuild-windows-32/-/esbuild-windows-32-0.14.38.tgz",
"integrity": "sha512-L2BmEeFZATAvU+FJzJiRLFUP+d9RHN+QXpgaOrs2klshoAm1AE6Us4X6fS9k33Uy5SzScn2TpcgecbqJza1Hjw==",
"cpu": [
"ia32"
],
"dev": true,
"optional": true,
"os": [
"win32"
],
"engines": {
"node": ">=12"
}
},
"node_modules/esbuild-windows-64": {
"version": "0.14.38",
"resolved": "https://registry.npmjs.org/esbuild-windows-64/-/esbuild-windows-64-0.14.38.tgz",
"integrity": "sha512-Khy4wVmebnzue8aeSXLC+6clo/hRYeNIm0DyikoEqX+3w3rcvrhzpoix0S+MF9vzh6JFskkIGD7Zx47ODJNyCw==",
"cpu": [
"x64"
],
"dev": true,
"optional": true,
"os": [
"win32"
],
"engines": {
"node": ">=12"
}
},
"node_modules/esbuild-windows-arm64": {
"version": "0.14.38",
"resolved": "https://registry.npmjs.org/esbuild-windows-arm64/-/esbuild-windows-arm64-0.14.38.tgz",
"integrity": "sha512-k3FGCNmHBkqdJXuJszdWciAH77PukEyDsdIryEHn9cKLQFxzhT39dSumeTuggaQcXY57UlmLGIkklWZo2qzHpw==",
"cpu": [
"arm64"
],
"dev": true,
"optional": true,
"os": [
"win32"
],
"engines": {
"node": ">=12"
}
},
"node_modules/make-error": {
"version": "1.3.6",
"resolved": "https://registry.npmjs.org/make-error/-/make-error-1.3.6.tgz",
"integrity": "sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==",
"dev": true
},
"node_modules/ts-node": {
"version": "10.7.0",
"resolved": "https://registry.npmjs.org/ts-node/-/ts-node-10.7.0.tgz",
"integrity": "sha512-TbIGS4xgJoX2i3do417KSaep1uRAW/Lu+WAL2doDHC0D6ummjirVOXU5/7aiZotbQ5p1Zp9tP7U6cYhA0O7M8A==",
"dev": true,
"dependencies": {
"@cspotcode/source-map-support": "0.7.0",
"@tsconfig/node10": "^1.0.7",
"@tsconfig/node12": "^1.0.7",
"@tsconfig/node14": "^1.0.0",
"@tsconfig/node16": "^1.0.2",
"acorn": "^8.4.1",
"acorn-walk": "^8.1.1",
"arg": "^4.1.0",
"create-require": "^1.1.0",
"diff": "^4.0.1",
"make-error": "^1.1.1",
"v8-compile-cache-lib": "^3.0.0",
"yn": "3.1.1"
},
"bin": {
"ts-node": "dist/bin.js",
"ts-node-cwd": "dist/bin-cwd.js",
"ts-node-esm": "dist/bin-esm.js",
"ts-node-script": "dist/bin-script.js",
"ts-node-transpile-only": "dist/bin-transpile.js",
"ts-script": "dist/bin-script-deprecated.js"
},
"peerDependencies": {
"@swc/core": ">=1.2.50",
"@swc/wasm": ">=1.2.50",
"@types/node": "*",
"typescript": ">=2.7"
},
"peerDependenciesMeta": {
"@swc/core": {
"optional": true
},
"@swc/wasm": {
"optional": true
}
}
},
"node_modules/typescript": {
"version": "4.6.3",
"resolved": "https://registry.npmjs.org/typescript/-/typescript-4.6.3.tgz",
"integrity": "sha512-yNIatDa5iaofVozS/uQJEl3JRWLKKGJKh6Yaiv0GLGSuhpFJe7P3SbHZ8/yjAHRQwKRoA6YZqlfjXWmVzoVSMw==",
"dev": true,
"bin": {
"tsc": "bin/tsc",
"tsserver": "bin/tsserver"
},
"engines": {
"node": ">=4.2.0"
}
},
"node_modules/v8-compile-cache-lib": {
"version": "3.0.1",
"resolved": "https://registry.npmjs.org/v8-compile-cache-lib/-/v8-compile-cache-lib-3.0.1.tgz",
"integrity": "sha512-wa7YjyUGfNZngI/vtK0UHAN+lgDCxBPCylVXGp0zu59Fz5aiGtNXaq3DhIov063MorB+VfufLh3JlF2KdTK3xg==",
"dev": true
},
"node_modules/yn": {
"version": "3.1.1",
"resolved": "https://registry.npmjs.org/yn/-/yn-3.1.1.tgz",
"integrity": "sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q==",
"dev": true,
"engines": {
"node": ">=6"
}
}
},
"dependencies": {
"@cspotcode/source-map-consumer": {
"version": "0.8.0",
"resolved": "https://registry.npmjs.org/@cspotcode/source-map-consumer/-/source-map-consumer-0.8.0.tgz",
"integrity": "sha512-41qniHzTU8yAGbCp04ohlmSrZf8bkf/iJsl3V0dRGsQN/5GFfx+LbCSsCpp2gqrqjTVg/K6O8ycoV35JIwAzAg==",
"dev": true
},
"@cspotcode/source-map-support": {
"version": "0.7.0",
"resolved": "https://registry.npmjs.org/@cspotcode/source-map-support/-/source-map-support-0.7.0.tgz",
"integrity": "sha512-X4xqRHqN8ACt2aHVe51OxeA2HjbcL4MqFqXkrmQszJ1NOUuUu5u6Vqx/0lZSVNku7velL5FC/s5uEAj1lsBMhA==",
"dev": true,
"requires": {
"@cspotcode/source-map-consumer": "0.8.0"
}
},
"@tsconfig/node10": {
"version": "1.0.8",
"resolved": "https://registry.npmjs.org/@tsconfig/node10/-/node10-1.0.8.tgz",
"integrity": "sha512-6XFfSQmMgq0CFLY1MslA/CPUfhIL919M1rMsa5lP2P097N2Wd1sSX0tx1u4olM16fLNhtHZpRhedZJphNJqmZg==",
"dev": true
},
"@tsconfig/node12": {
"version": "1.0.9",
"resolved": "https://registry.npmjs.org/@tsconfig/node12/-/node12-1.0.9.tgz",
"integrity": "sha512-/yBMcem+fbvhSREH+s14YJi18sp7J9jpuhYByADT2rypfajMZZN4WQ6zBGgBKp53NKmqI36wFYDb3yaMPurITw==",
"dev": true
},
"@tsconfig/node14": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/@tsconfig/node14/-/node14-1.0.1.tgz",
"integrity": "sha512-509r2+yARFfHHE7T6Puu2jjkoycftovhXRqW328PDXTVGKihlb1P8Z9mMZH04ebyajfRY7dedfGynlrFHJUQCg==",
"dev": true
},
"@tsconfig/node16": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/@tsconfig/node16/-/node16-1.0.2.tgz",
"integrity": "sha512-eZxlbI8GZscaGS7kkc/trHTT5xgrjH3/1n2JDwusC9iahPKWMRvRjJSAN5mCXviuTGQ/lHnhvv8Q1YTpnfz9gA==",
"dev": true
},
"@types/node": {
"version": "17.0.27",
"resolved": "https://registry.npmjs.org/@types/node/-/node-17.0.27.tgz",
"integrity": "sha512-4/Ke7bbWOasuT3kceBZFGakP1dYN2XFd8v2l9bqF2LNWrmeU07JLpp56aEeG6+Q3olqO5TvXpW0yaiYnZJ5CXg==",
"dev": true,
"peer": true
},
"acorn": {
"version": "8.7.0",
"resolved": "https://registry.npmjs.org/acorn/-/acorn-8.7.0.tgz",
"integrity": "sha512-V/LGr1APy+PXIwKebEWrkZPwoeoF+w1jiOBUmuxuiUIaOHtob8Qc9BTrYo7VuI5fR8tqsy+buA2WFooR5olqvQ==",
"dev": true
},
"acorn-walk": {
"version": "8.2.0",
"resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.2.0.tgz",
"integrity": "sha512-k+iyHEuPgSw6SbuDpGQM+06HQUa04DZ3o+F6CSzXMvvI5KMvnaEqXe+YVe555R9nn6GPt404fos4wcgpw12SDA==",
"dev": true
},
"arg": {
"version": "4.1.3",
"resolved": "https://registry.npmjs.org/arg/-/arg-4.1.3.tgz",
"integrity": "sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==",
"dev": true
},
"create-require": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/create-require/-/create-require-1.1.1.tgz",
"integrity": "sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==",
"dev": true
},
"diff": {
"version": "4.0.2",
"resolved": "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz",
"integrity": "sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==",
"dev": true
},
"esbuild": {
"version": "0.14.38",
"resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.14.38.tgz",
"integrity": "sha512-12fzJ0fsm7gVZX1YQ1InkOE5f9Tl7cgf6JPYXRJtPIoE0zkWAbHdPHVPPaLi9tYAcEBqheGzqLn/3RdTOyBfcA==",
"dev": true,
"requires": {
"esbuild-android-64": "0.14.38",
"esbuild-android-arm64": "0.14.38",
"esbuild-darwin-64": "0.14.38",
"esbuild-darwin-arm64": "0.14.38",
"esbuild-freebsd-64": "0.14.38",
"esbuild-freebsd-arm64": "0.14.38",
"esbuild-linux-32": "0.14.38",
"esbuild-linux-64": "0.14.38",
"esbuild-linux-arm": "0.14.38",
"esbuild-linux-arm64": "0.14.38",
"esbuild-linux-mips64le": "0.14.38",
"esbuild-linux-ppc64le": "0.14.38",
"esbuild-linux-riscv64": "0.14.38",
"esbuild-linux-s390x": "0.14.38",
"esbuild-netbsd-64": "0.14.38",
"esbuild-openbsd-64": "0.14.38",
"esbuild-sunos-64": "0.14.38",
"esbuild-windows-32": "0.14.38",
"esbuild-windows-64": "0.14.38",
"esbuild-windows-arm64": "0.14.38"
}
},
"esbuild-android-64": {
"version": "0.14.38",
"resolved": "https://registry.npmjs.org/esbuild-android-64/-/esbuild-android-64-0.14.38.tgz",
"integrity": "sha512-aRFxR3scRKkbmNuGAK+Gee3+yFxkTJO/cx83Dkyzo4CnQl/2zVSurtG6+G86EQIZ+w+VYngVyK7P3HyTBKu3nw==",
"dev": true,
"optional": true
},
"esbuild-android-arm64": {
"version": "0.14.38",
"resolved": "https://registry.npmjs.org/esbuild-android-arm64/-/esbuild-android-arm64-0.14.38.tgz",
"integrity": "sha512-L2NgQRWuHFI89IIZIlpAcINy9FvBk6xFVZ7xGdOwIm8VyhX1vNCEqUJO3DPSSy945Gzdg98cxtNt8Grv1CsyhA==",
"dev": true,
"optional": true
},
"esbuild-darwin-64": {
"version": "0.14.38",
"resolved": "https://registry.npmjs.org/esbuild-darwin-64/-/esbuild-darwin-64-0.14.38.tgz",
"integrity": "sha512-5JJvgXkX87Pd1Og0u/NJuO7TSqAikAcQQ74gyJ87bqWRVeouky84ICoV4sN6VV53aTW+NE87qLdGY4QA2S7KNA==",
"dev": true,
"optional": true
},
"esbuild-darwin-arm64": {
"version": "0.14.38",
"resolved": "https://registry.npmjs.org/esbuild-darwin-arm64/-/esbuild-darwin-arm64-0.14.38.tgz",
"integrity": "sha512-eqF+OejMI3mC5Dlo9Kdq/Ilbki9sQBw3QlHW3wjLmsLh+quNfHmGMp3Ly1eWm981iGBMdbtSS9+LRvR2T8B3eQ==",
"dev": true,
"optional": true
},
"esbuild-freebsd-64": {
"version": "0.14.38",
"resolved": "https://registry.npmjs.org/esbuild-freebsd-64/-/esbuild-freebsd-64-0.14.38.tgz",
"integrity": "sha512-epnPbhZUt93xV5cgeY36ZxPXDsQeO55DppzsIgWM8vgiG/Rz+qYDLmh5ts3e+Ln1wA9dQ+nZmVHw+RjaW3I5Ig==",
"dev": true,
"optional": true
},
"esbuild-freebsd-arm64": {
"version": "0.14.38",
"resolved": "https://registry.npmjs.org/esbuild-freebsd-arm64/-/esbuild-freebsd-arm64-0.14.38.tgz",
"integrity": "sha512-/9icXUYJWherhk+y5fjPI5yNUdFPtXHQlwP7/K/zg8t8lQdHVj20SqU9/udQmeUo5pDFHMYzcEFfJqgOVeKNNQ==",
"dev": true,
"optional": true
},
"esbuild-linux-32": {
"version": "0.14.38",
"resolved": "https://registry.npmjs.org/esbuild-linux-32/-/esbuild-linux-32-0.14.38.tgz",
"integrity": "sha512-QfgfeNHRFvr2XeHFzP8kOZVnal3QvST3A0cgq32ZrHjSMFTdgXhMhmWdKzRXP/PKcfv3e2OW9tT9PpcjNvaq6g==",
"dev": true,
"optional": true
},
"esbuild-linux-64": {
"version": "0.14.38",
"resolved": "https://registry.npmjs.org/esbuild-linux-64/-/esbuild-linux-64-0.14.38.tgz",
"integrity": "sha512-uuZHNmqcs+Bj1qiW9k/HZU3FtIHmYiuxZ/6Aa+/KHb/pFKr7R3aVqvxlAudYI9Fw3St0VCPfv7QBpUITSmBR1Q==",
"dev": true,
"optional": true
},
"esbuild-linux-arm": {
"version": "0.14.38",
"resolved": "https://registry.npmjs.org/esbuild-linux-arm/-/esbuild-linux-arm-0.14.38.tgz",
"integrity": "sha512-FiFvQe8J3VKTDXG01JbvoVRXQ0x6UZwyrU4IaLBZeq39Bsbatd94Fuc3F1RGqPF5RbIWW7RvkVQjn79ejzysnA==",
"dev": true,
"optional": true
},
"esbuild-linux-arm64": {
"version": "0.14.38",
"resolved": "https://registry.npmjs.org/esbuild-linux-arm64/-/esbuild-linux-arm64-0.14.38.tgz",
"integrity": "sha512-HlMGZTEsBrXrivr64eZ/EO0NQM8H8DuSENRok9d+Jtvq8hOLzrxfsAT9U94K3KOGk2XgCmkaI2KD8hX7F97lvA==",
"dev": true,
"optional": true
},
"esbuild-linux-mips64le": {
"version": "0.14.38",
"resolved": "https://registry.npmjs.org/esbuild-linux-mips64le/-/esbuild-linux-mips64le-0.14.38.tgz",
"integrity": "sha512-qd1dLf2v7QBiI5wwfil9j0HG/5YMFBAmMVmdeokbNAMbcg49p25t6IlJFXAeLzogv1AvgaXRXvgFNhScYEUXGQ==",
"dev": true,
"optional": true
},
"esbuild-linux-ppc64le": {
"version": "0.14.38",
"resolved": "https://registry.npmjs.org/esbuild-linux-ppc64le/-/esbuild-linux-ppc64le-0.14.38.tgz",
"integrity": "sha512-mnbEm7o69gTl60jSuK+nn+pRsRHGtDPfzhrqEUXyCl7CTOCLtWN2bhK8bgsdp6J/2NyS/wHBjs1x8aBWwP2X9Q==",
"dev": true,
"optional": true
},
"esbuild-linux-riscv64": {
"version": "0.14.38",
"resolved": "https://registry.npmjs.org/esbuild-linux-riscv64/-/esbuild-linux-riscv64-0.14.38.tgz",
"integrity": "sha512-+p6YKYbuV72uikChRk14FSyNJZ4WfYkffj6Af0/Tw63/6TJX6TnIKE+6D3xtEc7DeDth1fjUOEqm+ApKFXbbVQ==",
"dev": true,
"optional": true
},
"esbuild-linux-s390x": {
"version": "0.14.38",
"resolved": "https://registry.npmjs.org/esbuild-linux-s390x/-/esbuild-linux-s390x-0.14.38.tgz",
"integrity": "sha512-0zUsiDkGJiMHxBQ7JDU8jbaanUY975CdOW1YDrurjrM0vWHfjv9tLQsW9GSyEb/heSK1L5gaweRjzfUVBFoybQ==",
"dev": true,
"optional": true
},
"esbuild-netbsd-64": {
"version": "0.14.38",
"resolved": "https://registry.npmjs.org/esbuild-netbsd-64/-/esbuild-netbsd-64-0.14.38.tgz",
"integrity": "sha512-cljBAApVwkpnJZfnRVThpRBGzCi+a+V9Ofb1fVkKhtrPLDYlHLrSYGtmnoTVWDQdU516qYI8+wOgcGZ4XIZh0Q==",
"dev": true,
"optional": true
},
"esbuild-openbsd-64": {
"version": "0.14.38",
"resolved": "https://registry.npmjs.org/esbuild-openbsd-64/-/esbuild-openbsd-64-0.14.38.tgz",
"integrity": "sha512-CDswYr2PWPGEPpLDUO50mL3WO/07EMjnZDNKpmaxUPsrW+kVM3LoAqr/CE8UbzugpEiflYqJsGPLirThRB18IQ==",
"dev": true,
"optional": true
},
"esbuild-sunos-64": {
"version": "0.14.38",
"resolved": "https://registry.npmjs.org/esbuild-sunos-64/-/esbuild-sunos-64-0.14.38.tgz",
"integrity": "sha512-2mfIoYW58gKcC3bck0j7lD3RZkqYA7MmujFYmSn9l6TiIcAMpuEvqksO+ntBgbLep/eyjpgdplF7b+4T9VJGOA==",
"dev": true,
"optional": true
},
"esbuild-windows-32": {
"version": "0.14.38",
"resolved": "https://registry.npmjs.org/esbuild-windows-32/-/esbuild-windows-32-0.14.38.tgz",
"integrity": "sha512-L2BmEeFZATAvU+FJzJiRLFUP+d9RHN+QXpgaOrs2klshoAm1AE6Us4X6fS9k33Uy5SzScn2TpcgecbqJza1Hjw==",
"dev": true,
"optional": true
},
"esbuild-windows-64": {
"version": "0.14.38",
"resolved": "https://registry.npmjs.org/esbuild-windows-64/-/esbuild-windows-64-0.14.38.tgz",
"integrity": "sha512-Khy4wVmebnzue8aeSXLC+6clo/hRYeNIm0DyikoEqX+3w3rcvrhzpoix0S+MF9vzh6JFskkIGD7Zx47ODJNyCw==",
"dev": true,
"optional": true
},
"esbuild-windows-arm64": {
"version": "0.14.38",
"resolved": "https://registry.npmjs.org/esbuild-windows-arm64/-/esbuild-windows-arm64-0.14.38.tgz",
"integrity": "sha512-k3FGCNmHBkqdJXuJszdWciAH77PukEyDsdIryEHn9cKLQFxzhT39dSumeTuggaQcXY57UlmLGIkklWZo2qzHpw==",
"dev": true,
"optional": true
},
"make-error": {
"version": "1.3.6",
"resolved": "https://registry.npmjs.org/make-error/-/make-error-1.3.6.tgz",
"integrity": "sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==",
"dev": true
},
"ts-node": {
"version": "10.7.0",
"resolved": "https://registry.npmjs.org/ts-node/-/ts-node-10.7.0.tgz",
"integrity": "sha512-TbIGS4xgJoX2i3do417KSaep1uRAW/Lu+WAL2doDHC0D6ummjirVOXU5/7aiZotbQ5p1Zp9tP7U6cYhA0O7M8A==",
"dev": true,
"requires": {
"@cspotcode/source-map-support": "0.7.0",
"@tsconfig/node10": "^1.0.7",
"@tsconfig/node12": "^1.0.7",
"@tsconfig/node14": "^1.0.0",
"@tsconfig/node16": "^1.0.2",
"acorn": "^8.4.1",
"acorn-walk": "^8.1.1",
"arg": "^4.1.0",
"create-require": "^1.1.0",
"diff": "^4.0.1",
"make-error": "^1.1.1",
"v8-compile-cache-lib": "^3.0.0",
"yn": "3.1.1"
}
},
"typescript": {
"version": "4.6.3",
"resolved": "https://registry.npmjs.org/typescript/-/typescript-4.6.3.tgz",
"integrity": "sha512-yNIatDa5iaofVozS/uQJEl3JRWLKKGJKh6Yaiv0GLGSuhpFJe7P3SbHZ8/yjAHRQwKRoA6YZqlfjXWmVzoVSMw==",
"dev": true
},
"v8-compile-cache-lib": {
"version": "3.0.1",
"resolved": "https://registry.npmjs.org/v8-compile-cache-lib/-/v8-compile-cache-lib-3.0.1.tgz",
"integrity": "sha512-wa7YjyUGfNZngI/vtK0UHAN+lgDCxBPCylVXGp0zu59Fz5aiGtNXaq3DhIov063MorB+VfufLh3JlF2KdTK3xg==",
"dev": true
},
"yn": {
"version": "3.1.1",
"resolved": "https://registry.npmjs.org/yn/-/yn-3.1.1.tgz",
"integrity": "sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q==",
"dev": true
}
}
}

18
package.json Normal file
View file

@ -0,0 +1,18 @@
{
"name": "matomo-lite-tracker",
"version": "1.0.0",
"description": "- tracking page views - custom dimensions - send data via POST - browser features - cookie - res - browser plugins (pdf, flash, etc.) - User ID - Event Tracking - Campaign tracking - Search Tracking - Goal Tracking - manual Outlink Tracking - manual ping - manual DoNotTrack detection",
"main": "dist/tracker.js",
"module": "dist/tracker.js",
"type": "module",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"devDependencies": {
"esbuild": "^0.14.38",
"ts-node": "^10.7.0",
"typescript": "^4.6.3"
},
"author": "",
"license": "BSD-3-Clause"
}

5
src/aliases.ts Normal file
View file

@ -0,0 +1,5 @@
export const documentAlias = document
export const navigatorAlias = navigator
export const screenAlias = screen
export const windowAlias = window
export const locationAlias = windowAlias.location

55
src/browserfeatures.ts Normal file
View file

@ -0,0 +1,55 @@
import {navigatorAlias, screenAlias} from "./aliases";
export interface BrowserPlugins {
pdf?: boolean
qt?: boolean
realp?: boolean
wma?: boolean
fla?: boolean
java?: boolean
ag?: boolean
[id: string]: any
}
const pluginMap = {
pdf: 'application/pdf',
qt: 'video/quicktime',
realp: 'audio/x-pn-realaudio-plugin',
wma: 'application/x-mplayer2',
fla: 'application/x-shockwave-flash',
java: 'application/x-java-vm',
ag: 'application/x-silverlight'
};
export function detectBrowserPlugins(): BrowserPlugins {
const mimeTypes = navigatorAlias.mimeTypes
const plugins: BrowserPlugins = {}
if (mimeTypes && mimeTypes.length) {
Object.entries(pluginMap).forEach(([key, mimeType]) => {
const mime = mimeTypes.namedItem(mimeType)
plugins[key] = (mime && mime.enabledPlugin)
})
}
return plugins
}
export class BrowserFeatures {
plugins?: BrowserPlugins
cookie: boolean;
res: string
constructor() {
this.cookie = navigatorAlias.cookieEnabled
const width = screenAlias.width
const height = screenAlias.height
this.res = width + "x" + height
}
addBrowserPlugins(plugins: BrowserPlugins) {
this.plugins = plugins
}
}

9
src/entry.ts Normal file
View file

@ -0,0 +1,9 @@
import {MatomoLiteTracker} from "./tracker";
window.MatomoLiteTracker = MatomoLiteTracker
declare global {
interface Window {
MatomoLiteTracker: typeof MatomoLiteTracker;
}
}

0
src/heartbeat.ts Normal file
View file

137
src/linktracking.ts Normal file
View file

@ -0,0 +1,137 @@
import type {MatomoLiteTracker} from "./tracker"
import {documentAlias, locationAlias} from "./aliases"
import type {LinkType} from "./types";
// strongly based on clickHandler of matomo.js
//all names based on right-handed mouse
enum MouseButton {
Left = 0,
Wheel = 1,
Right = 2
}
const scriptProtocol = new RegExp('^(javascript|vbscript|jscript|mocha|livescript|ecmascript|mailto|tel):', 'i');
export const defaultDownloadFileExtensions = ['7z', 'aac', 'apk', 'arc', 'arj', 'asf', 'asx', 'avi', 'azw3', 'bin', 'csv', 'deb', 'dmg', 'doc', 'docx', 'epub', 'exe', 'flv', 'gif', 'gz', 'gzip', 'hqx', 'ibooks', 'jar', 'jpg', 'jpeg', 'js', 'mobi', 'mp2', 'mp3', 'mp4', 'mpg', 'mpeg', 'mov', 'movie', 'msi', 'msp', 'odb', 'odf', 'odg', 'ods', 'odt', 'ogg', 'ogv', 'pdf', 'phps', 'png', 'ppt', 'pptx', 'qt', 'qtm', 'ra', 'ram', 'rar', 'rpm', 'rtf', 'sea', 'sit', 'tar', 'tbz', 'tbz2', 'bz', 'bz2', 'tgz', 'torrent', 'txt', 'wav', 'wma', 'wmv', 'wpd', 'xls', 'xlsx', 'xml', 'z', 'zip']
export function enableLinkTracking(
matomo: MatomoLiteTracker,
downloadFileExtensions?: string[],
alsoTrackMouseclicks: boolean = false,
ignoredClasses = ["matomo_ignore", "piwik_ignore"],
) {
function getLinkType(element: HTMLAnchorElement, href: string): LinkType {
if (element.classList.contains("matomo_link")) {
return "link"
}
if (
element.classList.contains("matomo_download")
|| element.hasAttribute("download")
) {
return "download"
}
if (downloadFileExtensions) {
const downloadExtensionsPattern = new RegExp('\\.(' + downloadFileExtensions.join('|') + ')([?&#]|$)', 'i');
if (downloadExtensionsPattern.test(href)) {
return "download"
}
}
return "link"
}
function processClick(element: HTMLAnchorElement) {
console.log(element)
if (!element.hasAttribute("href")) {
return
}
const href = element.href
if (scriptProtocol.test(href)) {
return;
}
const linkType = getLinkType(element, href)
if (element.host === locationAlias.host) {
// only track external hosts
return;
}
matomo.trackLink(href, linkType)
}
function getLinkTarget(event: MouseEvent): HTMLAnchorElement | undefined {
let target = event.target
if (!(target instanceof Element)) {
return
}
let nodeName = target.nodeName
for (const ignoredClass of ignoredClasses) {
if (target.classList.contains(ignoredClass)) {
return
}
}
while (nodeName != "A" && target && target.parentNode) {
target = target.parentNode
if (!(target instanceof Element)) {
return
}
nodeName = target.nodeName
}
if (target && nodeName == "A") {
return target as HTMLAnchorElement
}
return
}
function clickHandler(event: MouseEvent) {
const target = getLinkTarget(event)
if (!target) {
return
}
const mouseButton: MouseButton = event.button
let lastButton: MouseButton|undefined
let lastTarget: Element|undefined
switch (event.type) {
case "click" :
const ignoreClick = alsoTrackMouseclicks && mouseButton === MouseButton.Wheel
if (!ignoreClick) {
processClick(target)
}
break
case "mousedown":
if (mouseButton === MouseButton.Wheel) {
lastButton = mouseButton
lastTarget = target
} else {
lastButton = lastTarget = undefined
}
break
case "mouseup":
if (mouseButton === lastButton && target === lastTarget) {
processClick(target)
}
lastButton = lastTarget = undefined
break
case "contextmenu":
processClick(target)
break
}
}
const body = documentAlias.body
body.addEventListener("click", clickHandler, true)
if (alsoTrackMouseclicks) {
body.addEventListener("mouseup", clickHandler, true)
body.addEventListener("mousedown", clickHandler, true)
body.addEventListener("contextmenu", clickHandler, true)
}
}

View file

239
src/tracker.ts Normal file
View file

@ -0,0 +1,239 @@
import {documentAlias} from "./aliases";
import {boolToIntBool, getCurrentURL} from "./url";
import type {CustomDimensionName, CustomDimensions, IntBoolean, LinkType} from "./types";
import type {BrowserFeatures} from "./browserfeatures";
import {generateUniqueId} from "./util";
// the query paramters the Matomo API expects to recieve
interface Request {
idsite: number
// always 1
rec: 1
// random string
r: string
// local hour
h: number,
// local minute
m: number,
// local second
s: number,
// current URL
url: string
// referrer URL
urlref?: string
// userID
uid?: string
// random ID
_id?: any
// new visitor
_nid?: any // (maybe always send "1"?)
// campaign tracking (ignored for now)
_rcn?: string
_rck?: string
_refts?: number
_ref?: string
// character set (not needed if utf-8)
cs?: string
send_image: IntBoolean
pdf?: IntBoolean
qt?: IntBoolean
realp?: IntBoolean
wma?: IntBoolean
fla?: IntBoolean
java?: IntBoolean
ag?: IntBoolean
cookie?: IntBoolean
res?: string
// custom dimensions
[id: CustomDimensionName]: string
// Page View ID
pv_id?: string
// fallback for everything else
[id: string]: any
}
interface PageViewRequest extends Request {
// Title
action_name: string
}
interface EventRequest extends Request {
// Event Category
e_c: string
// Event Action
e_a: string
// Event Name
e_n?: string
// Event Value
e_v?: number
}
interface SearchRequest extends Request {
// Search Keyword
search: string
// Search Category
search_cat?: string
// Search Count
search_count?: number
}
interface GoalRequest extends Request {
idgoal: number | string
revenue?: number | string
}
interface OutlinkRequest extends Request {
link?: string
download?: string
}
interface PingRequest extends Request {
ping: 1
}
export class MatomoLiteTracker {
siteID: number
matomoURL: string
phpFileName: string = "matomo.php"
userID?: string
browserFeatures?: BrowserFeatures
customDimensions?: CustomDimensions
requestMethod: "GET" | "POST" = "GET"
private pageViewID?: string;
constructor(matomoURL: string, siteID: number,) {
this.matomoURL = matomoURL;
this.siteID = siteID;
}
getRequest(): Request {
const now = new Date()
const parameters: Request = {
idsite: this.siteID,
rec: 1,
r: String(Math.random()).slice(2, 8),
h: now.getHours(),
m: now.getMinutes(),
s: now.getSeconds(),
url: getCurrentURL(),
send_image: 1
}
const referrer = documentAlias.referrer
if (referrer) {
parameters.urlref = referrer
}
if (this.pageViewID) {
parameters.pv_id = this.pageViewID
}
if (this.userID) {
parameters.uid = this.userID
}
if (this.browserFeatures) {
const features = this.browserFeatures
parameters.res = features.res
parameters.cookie = boolToIntBool(features.cookie)
if (features.plugins) {
Object.entries(features.plugins).forEach(([key, supported]) => {
parameters[key] = boolToIntBool(supported)
})
}
}
const cd = this.customDimensions
if (cd) {
for (let customDimensionsKey in cd) {
parameters[`dimension${customDimensionsKey}`] = cd[customDimensionsKey]
}
}
return parameters
}
trackPageview(customTitle?: string) {
this.pageViewID = generateUniqueId()
const parameters = this.getRequest() as PageViewRequest
parameters.action_name = customTitle ? customTitle : documentAlias.title
this.sendRequest(parameters)
}
trackEvent(category: string, action: string, name?: string, value?: number) {
const parameters = this.getRequest() as EventRequest
parameters.e_c = category
parameters.e_a = action
if (name) {
parameters.e_n = name
}
if (value) {
parameters.e_v = value
}
this.sendRequest(parameters)
}
trackSiteSearch(keyword: string, category?: string, resultsCount?: number) {
const parameters = this.getRequest() as SearchRequest
parameters.search = keyword
if (category) {
parameters.search_cat = category
}
if (resultsCount) {
parameters.search_count = resultsCount
}
this.sendRequest(parameters)
}
trackGoal(idGoal: number | string, customRevenue?: number | string) {
const parameters = this.getRequest() as GoalRequest
parameters.idgoal = idGoal
if (customRevenue) {
parameters.revenue = customRevenue
}
this.sendRequest(parameters)
}
trackLink(sourceUrl: string, linkType: LinkType) {
const parameters = this.getRequest() as OutlinkRequest
parameters[linkType] = sourceUrl
this.sendRequest(parameters)
}
ping() {
const parameters = this.getRequest() as PingRequest
parameters.ping = 1
this.sendRequest(parameters)
}
sendRequest(parameters: Request) {
console.log(parameters)
const requestMethod = this.requestMethod
const params = new URLSearchParams(parameters)
let url = this.matomoURL
+ (this.matomoURL.endsWith("/") ? "" : "/")
+ this.phpFileName
if (requestMethod === "GET") {
url += "?" + params.toString()
}
const options: RequestInit = {
method: requestMethod,
mode: "no-cors",
cache: "no-cache",
credentials: "omit",
}
if (requestMethod === "POST") {
options.body = params
}
console.log(url)
fetch(url, options).then(value => {
console.info(value)
})
}
}

7
src/types.ts Normal file
View file

@ -0,0 +1,7 @@
export type IntBoolean = 1 | 0
export type CustomDimensions = { [id: number]: string }
export type CustomDimensionName = `dimension${number}`
export type LinkType = "link" | "download"

16
src/url.ts Normal file
View file

@ -0,0 +1,16 @@
import {locationAlias} from "./aliases";
import type {IntBoolean} from "./types";
export function getCurrentURL(): string {
// https://stackoverflow.com/a/5818284/4398037
return locationAlias.protocol + '//' +
locationAlias.hostname +
(locationAlias.port ? ":" + locationAlias.port : "") +
locationAlias.pathname +
(locationAlias.search ? locationAlias.search : "")
}
export function boolToIntBool(value: boolean): IntBoolean {
return value ? 1 : 0
}

18
src/util.ts Normal file
View file

@ -0,0 +1,18 @@
import {navigatorAlias} from "./aliases";
export function generateUniqueId(length: number = 6): string {
let id = '';
const chars = 'abcdefghijklmnopqrstuvwxyz0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ';
const charLen = chars.length;
for (let i = 0; i < length; i++) {
id += chars.charAt(Math.floor(Math.random() * charLen));
}
return id;
}
export function isDoNotTrackEnabled(): boolean {
const dnt = navigatorAlias.doNotTrack
return dnt === "yes" || dnt === "1"
}

23
tsconfig.json Normal file
View file

@ -0,0 +1,23 @@
{
"compilerOptions": {
"moduleResolution": "Node",
"target": "ES2017",
"strict": true,
"esModuleInterop": true,
"skipLibCheck": true,
"forceConsistentCasingInFileNames": true,
"allowUnusedLabels": false,
"allowUnreachableCode": false,
"exactOptionalPropertyTypes": true,
"noFallthroughCasesInSwitch": true,
"noImplicitOverride": true,
"noImplicitReturns": true,
"noPropertyAccessFromIndexSignature": true,
"noUncheckedIndexedAccess": true,
"noUnusedLocals": true,
"noUnusedParameters": true,
"importsNotUsedAsValues": "error",
"module": "ES2020",
"outDir": "dist/"
}
}