@mixdive/browser 0.1.0 → 0.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +165 -8
- package/dist/index.cjs +1 -1
- package/dist/index.js +1 -1
- package/dist/mixdive.js +2 -2
- package/package.json +8 -4
package/README.md
CHANGED
|
@@ -1,18 +1,175 @@
|
|
|
1
1
|
# @mixdive/browser
|
|
2
2
|
|
|
3
|
-
The [Mixdive](https://mixdive.com)
|
|
4
|
-
|
|
5
|
-
|
|
3
|
+
The browser SDK for **[Mixdive](https://mixdive.com/?utm_source=npm&utm_medium=referral&utm_campaign=browser_readme&utm_content=intro)**,
|
|
4
|
+
self-hosted product analytics. One script tag on any website, or an npm import
|
|
5
|
+
in a bundled app. Page views, visitors, sessions and session durations count
|
|
6
|
+
themselves. Your own events take one call.
|
|
6
7
|
|
|
7
|
-
|
|
8
|
-
|
|
8
|
+
[](https://mixdive.com/?utm_source=npm&utm_medium=referral&utm_campaign=browser_readme&utm_content=hero)
|
|
9
|
+
|
|
10
|
+
The console your events land in, running on your own server.
|
|
11
|
+
[Open the live demo](https://demo1.mixdive.com/): a full Mixdive filled with a
|
|
12
|
+
fictional shop's data, no sign-up.
|
|
13
|
+
|
|
14
|
+
[Website](https://mixdive.com/?utm_source=npm&utm_medium=referral&utm_campaign=browser_readme&utm_content=links)
|
|
15
|
+
·
|
|
16
|
+
[Documentation](https://docs.mixdive.com/?utm_source=npm&utm_medium=referral&utm_campaign=browser_readme&utm_content=links)
|
|
17
|
+
·
|
|
18
|
+
[Live demo](https://demo1.mixdive.com/)
|
|
19
|
+
·
|
|
20
|
+
[Web tag guide](https://docs.mixdive.com/integrations/web-tag/?utm_source=npm&utm_medium=referral&utm_campaign=browser_readme&utm_content=links)
|
|
21
|
+
·
|
|
22
|
+
[GitHub](https://github.com/mixdive/mixdive-js)
|
|
23
|
+
|
|
24
|
+
## Why send your events here
|
|
25
|
+
|
|
26
|
+
**Your visitors' behaviour stays with you.** Mixdive runs on a server you own
|
|
27
|
+
and writes to a database you hold the credentials for. Nobody else keeps a copy
|
|
28
|
+
of who your users are or what they did. Teams in regulated industries, EU public
|
|
29
|
+
sector work, and anyone whose data simply cannot go to a third party tend to
|
|
30
|
+
arrive for exactly this reason.
|
|
31
|
+
|
|
32
|
+
**Nothing to define first.** Send `checkout_completed` and its report screen
|
|
33
|
+
exists. Properties register themselves the first time they show up, so a new
|
|
34
|
+
field becomes a breakdown you can look at instead of a ticket for somebody else.
|
|
35
|
+
|
|
36
|
+
**You don't need a data team.** The screens answer what a product person
|
|
37
|
+
actually asks: which features get used, by whom, how often, and what people did
|
|
38
|
+
before they stopped.
|
|
39
|
+
|
|
40
|
+
## Install
|
|
41
|
+
|
|
42
|
+
```sh
|
|
43
|
+
npm i @mixdive/browser
|
|
9
44
|
```
|
|
10
45
|
|
|
11
46
|
```ts
|
|
12
47
|
import { mixdive } from '@mixdive/browser'
|
|
48
|
+
|
|
13
49
|
mixdive.init({ key: 'mx_…', server: 'https://analytics.example.com' })
|
|
14
|
-
|
|
50
|
+
|
|
51
|
+
mixdive.track('checkout_completed', { plan: 'team', seats: 4 })
|
|
52
|
+
mixdive.identify(user.id)
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
The key comes from a **Web** app under **Settings → Apps** in your Mixdive
|
|
56
|
+
console. It is visible in page source, which is fine: it can write events and
|
|
57
|
+
read nothing.
|
|
58
|
+
|
|
59
|
+
React app? [`@mixdive/react`](https://www.npmjs.com/package/@mixdive/react) adds
|
|
60
|
+
a provider, a hook and router-driven page views on top of this package.
|
|
61
|
+
|
|
62
|
+
## Or one script tag, no build step
|
|
63
|
+
|
|
64
|
+
```html
|
|
65
|
+
<script defer src="https://analytics.example.com/js/mixdive.js" data-key="mx_…"></script>
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
That is the whole integration, and your Mixdive server serves the file. To call
|
|
69
|
+
`mixdive(…)` from page code before the script has loaded, add the one-line stub:
|
|
70
|
+
|
|
71
|
+
```html
|
|
72
|
+
<script>window.mixdive=window.mixdive||function(){(mixdive.q=mixdive.q||[]).push(arguments)};</script>
|
|
73
|
+
<script defer src="https://analytics.example.com/js/mixdive.js" data-key="mx_…"></script>
|
|
74
|
+
<script>
|
|
75
|
+
mixdive('track', 'checkout_completed', { plan: 'team' });
|
|
76
|
+
mixdive('identify', currentUser.id);
|
|
77
|
+
</script>
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
The same file ships in this package as `dist/mixdive.js` (7 KB), so you can copy
|
|
81
|
+
it from `node_modules` into your own static assets or load it from a CDN mirror:
|
|
82
|
+
`https://cdn.jsdelivr.net/npm/@mixdive/browser@0.1/dist/mixdive.js`. Attributes:
|
|
83
|
+
`data-key`, `data-server`, `data-auto-page-views`, `data-app-version`,
|
|
84
|
+
`data-debug`. Full reference:
|
|
85
|
+
[Web tag](https://docs.mixdive.com/integrations/web-tag/?utm_source=npm&utm_medium=referral&utm_campaign=browser_readme&utm_content=tag).
|
|
86
|
+
|
|
87
|
+
## What arrives without you writing anything
|
|
88
|
+
|
|
89
|
+
- **Page views** on load and on every history change, single-page apps
|
|
90
|
+
included, with the path, the title and the previous path as referrer. Query
|
|
91
|
+
strings are never sent.
|
|
92
|
+
- **Visitors and sessions**: a device id minted on the first visit, never
|
|
93
|
+
derived from the browser, and a session that renews after 30 minutes idle and
|
|
94
|
+
rotates when a landing URL carries a different `utm_source`.
|
|
95
|
+
- **Session duration**, sent when the page is hidden or unloaded.
|
|
96
|
+
- **Acquisition and context** on every item: landing referrer, `utm_source`,
|
|
97
|
+
`utm_medium`, `utm_campaign`, screen size, browser language.
|
|
98
|
+
|
|
99
|
+
Never sent: full URLs, query strings, the visitor's IP, or browser timestamps.
|
|
100
|
+
In an automated browser nothing is sent at all, so test runners stay out of your
|
|
101
|
+
numbers. [Visitors and
|
|
102
|
+
sessions](https://docs.mixdive.com/concepts/visitors-sessions/?utm_source=npm&utm_medium=referral&utm_campaign=browser_readme&utm_content=concepts)
|
|
103
|
+
has the rules.
|
|
104
|
+
|
|
105
|
+
## API
|
|
106
|
+
|
|
107
|
+
```ts
|
|
108
|
+
mixdive.init({ key, server, autoPageViews?, appVersion?, debug? })
|
|
109
|
+
mixdive.track(eventKey, properties?, { count?, sum?, duration?, id? }?)
|
|
110
|
+
mixdive.pageView(url?)
|
|
111
|
+
mixdive.identify(userId)
|
|
112
|
+
mixdive.setUser(userId, { name?, username?, email?, organization?, phone?, picture?, gender?, birthYear?, custom? }?)
|
|
113
|
+
mixdive.login(method?)
|
|
114
|
+
mixdive.signUp(method?)
|
|
115
|
+
mixdive.reset()
|
|
116
|
+
mixdive.version
|
|
15
117
|
```
|
|
16
118
|
|
|
17
|
-
|
|
18
|
-
|
|
119
|
+
Every call returns immediately and never throws into your page. With no key, no
|
|
120
|
+
server, or an automated browser, every call is a silent no-op. The first `init`
|
|
121
|
+
wins, and calls made before it are buffered and delivered once it runs.
|
|
122
|
+
|
|
123
|
+
`track` takes three measures beside the properties: `count` for one occurrence
|
|
124
|
+
that stands for several, `sum` for money or points, `duration` in seconds. The
|
|
125
|
+
report totals and averages them for you.
|
|
126
|
+
|
|
127
|
+
`identify(userId)` must be **your** user id, the same one your backend sends.
|
|
128
|
+
The device's earlier anonymous history is then attributed to that user, so
|
|
129
|
+
pre-signup browsing becomes part of their story. `reset()` forgets device,
|
|
130
|
+
session and user, which is what you want on sign-out and when consent is
|
|
131
|
+
withdrawn.
|
|
132
|
+
|
|
133
|
+
## Consent
|
|
134
|
+
|
|
135
|
+
The device id is a persistent identifier, so treat the tag like any other
|
|
136
|
+
analytics tag: load it once consent is granted, and call `reset()` when it is
|
|
137
|
+
withdrawn. No cookies are set. Three localStorage keys are used, `mx_did`,
|
|
138
|
+
`mx_ses` and `mx_uid`, which you can name in your storage declarations.
|
|
139
|
+
|
|
140
|
+
## Running Mixdive
|
|
141
|
+
|
|
142
|
+
```sh
|
|
143
|
+
curl -O https://docs.mixdive.com/compose.yaml
|
|
144
|
+
docker compose up -d
|
|
145
|
+
```
|
|
146
|
+
|
|
147
|
+
Then open `http://localhost:8080`, where a one-time wizard asks for a project
|
|
148
|
+
name, the address your apps will use, and an owner account.
|
|
149
|
+
[Quick start](https://docs.mixdive.com/start/quick-start/?utm_source=npm&utm_medium=referral&utm_campaign=browser_readme&utm_content=quickstart)
|
|
150
|
+
·
|
|
151
|
+
[Install](https://docs.mixdive.com/operate/install/?utm_source=npm&utm_medium=referral&utm_campaign=browser_readme&utm_content=install)
|
|
152
|
+
|
|
153
|
+
Mixdive is in beta with a small group of teams whose requirements shape what
|
|
154
|
+
gets built. Running a real product whose data cannot go to a third party? A few
|
|
155
|
+
lines to beta@mixdive.com is enough, and a person answers.
|
|
156
|
+
|
|
157
|
+
## More SDKs
|
|
158
|
+
|
|
159
|
+
A backend belongs in the picture too: profile enrichment and server-side events
|
|
160
|
+
go through [`mixdive-go`](https://github.com/mixdive/mixdive-go). There is also
|
|
161
|
+
a [Google Tag
|
|
162
|
+
Manager](https://docs.mixdive.com/integrations/google-tag-manager/?utm_source=npm&utm_medium=referral&utm_campaign=browser_readme&utm_content=integrations)
|
|
163
|
+
template and an [HTTP
|
|
164
|
+
API](https://docs.mixdive.com/integrations/http-api/?utm_source=npm&utm_medium=referral&utm_campaign=browser_readme&utm_content=integrations)
|
|
165
|
+
for anything that can POST JSON.
|
|
166
|
+
|
|
167
|
+
More SDKs are on the way. Missing one for your platform? Tell us at
|
|
168
|
+
[hello@mixdive.com](mailto:hello@mixdive.com). Requests set the order.
|
|
169
|
+
|
|
170
|
+
## License
|
|
171
|
+
|
|
172
|
+
This SDK is Apache-2.0. The Mixdive server itself is commercial software you run
|
|
173
|
+
on your own machines, and [that
|
|
174
|
+
distinction](https://docs.mixdive.com/start/open-source/?utm_source=npm&utm_medium=referral&utm_campaign=browser_readme&utm_content=license)
|
|
175
|
+
is worth two minutes if it matters to you.
|
package/dist/index.cjs
CHANGED
package/dist/index.js
CHANGED
package/dist/mixdive.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
/*! Mixdive web tag v0.1.
|
|
2
|
-
"use strict";(()=>{var Z=Object.defineProperty;var R=Object.getOwnPropertySymbols;var K=Object.prototype.hasOwnProperty,ee=Object.prototype.propertyIsEnumerable;var T=(i,t,n)=>t in i?Z(i,t,{enumerable:!0,configurable:!0,writable:!0,value:n}):i[t]=n,E=(i,t)=>{for(var n in t||(t={}))K.call(t,n)&&T(i,n,t[n]);if(R)for(var n of R(t))ee.call(t,n)&&T(i,n,t[n]);return i};function I(){let i="";try{let t=new Uint8Array(16);crypto.getRandomValues(t);for(let n=0;n<16;n++)i+=(t[n]+256).toString(16).slice(1);return i}catch(t){}for(let t=0;t<32;t++)i+=Math.floor(Math.random()*16).toString(16);return i}function L(i,t){let n={ref:"",us:"",um:"",uc:""};try{if(t){let a=/^[a-z]+:\/\/([^/]+)/i.exec(t);a&&a[1].toLowerCase()!==i.host.toLowerCase()&&(n.ref=t.split("?")[0].slice(0,256))}let u=i.search.replace(/^\?/,"").split("&");for(let a of u){let f=a.indexOf("="),g=f<0?a:a.slice(0,f),m=f<0?"":a.slice(f+1),s="";try{s=decodeURIComponent(m.replace(/\+/g," ")).slice(0,128)}catch(d){s=m.slice(0,128)}g==="utm_source"&&(n.us=s),g==="utm_medium"&&(n.um=s),g==="utm_campaign"&&(n.uc=s)}}catch(u){}return n}function D(i,t,n,u){let a=!!t.us&&!!i&&i.us!==t.us,f=i;return(!f||n-f.last>18e5||a)&&(f={id:u(),start:n,last:n,ref:t.ref,us:t.us,um:t.um,uc:t.uc}),f.last=n,f}function N(i){if(!i)return null;try{let t=JSON.parse(i);if(t&&typeof t.id=="string"&&typeof t.start=="number"&&typeof t.last=="number")return{id:t.id,start:t.start,last:t.last,ref:t.ref||"",us:t.us||"",um:t.um||"",uc:t.uc||""}}catch(t){}return null}function U(i,t){let n={};return t.language&&(n.language=String(t.language).slice(0,16)),t.width&&t.height&&(n.resolution=`${t.width}x${t.height}`),t.density&&(n.density=t.density),i.ref&&(n.referrer=i.ref),i.us&&(n.utm_source=i.us),i.um&&(n.utm_medium=i.um),i.uc&&(n.utm_campaign=i.uc),n}function C(){let i=new Map;return{get(t){var n;try{let u=window.localStorage.getItem(t);if(u!==null)return u}catch(u){}return(n=i.get(t))!=null?n:null},set(t,n){i.set(t,n);try{window.localStorage.setItem(t,n)}catch(u){}},remove(t){i.delete(t);try{window.localStorage.removeItem(t)}catch(n){}}}}function H(i){return{send(t,n,u){if(!u){let a=typeof navigator!="undefined"?navigator:void 0;if(a&&typeof a.sendBeacon=="function")try{if(a.sendBeacon(t,new Blob([n],{type:"text/plain"})))return}catch(f){}}if(typeof fetch!="function"){i("no fetch available; dropped",t);return}try{let a={method:"POST",body:n,keepalive:!0};u&&(a.headers=E({"Content-Type":"application/json"},u));let f=fetch(t,a);f&&typeof f.then=="function"&&f.then(g=>{g.ok||i(`${g.status} from ${t}`)},g=>i("send failed",g))}catch(a){i("send failed",a)}}}}var j="0.1.
|
|
1
|
+
/*! Mixdive web tag v0.1.1 · https://github.com/mixdive/mixdive-js · Apache-2.0 */
|
|
2
|
+
"use strict";(()=>{var Z=Object.defineProperty;var R=Object.getOwnPropertySymbols;var K=Object.prototype.hasOwnProperty,ee=Object.prototype.propertyIsEnumerable;var T=(i,t,n)=>t in i?Z(i,t,{enumerable:!0,configurable:!0,writable:!0,value:n}):i[t]=n,E=(i,t)=>{for(var n in t||(t={}))K.call(t,n)&&T(i,n,t[n]);if(R)for(var n of R(t))ee.call(t,n)&&T(i,n,t[n]);return i};function I(){let i="";try{let t=new Uint8Array(16);crypto.getRandomValues(t);for(let n=0;n<16;n++)i+=(t[n]+256).toString(16).slice(1);return i}catch(t){}for(let t=0;t<32;t++)i+=Math.floor(Math.random()*16).toString(16);return i}function L(i,t){let n={ref:"",us:"",um:"",uc:""};try{if(t){let a=/^[a-z]+:\/\/([^/]+)/i.exec(t);a&&a[1].toLowerCase()!==i.host.toLowerCase()&&(n.ref=t.split("?")[0].slice(0,256))}let u=i.search.replace(/^\?/,"").split("&");for(let a of u){let f=a.indexOf("="),g=f<0?a:a.slice(0,f),m=f<0?"":a.slice(f+1),s="";try{s=decodeURIComponent(m.replace(/\+/g," ")).slice(0,128)}catch(d){s=m.slice(0,128)}g==="utm_source"&&(n.us=s),g==="utm_medium"&&(n.um=s),g==="utm_campaign"&&(n.uc=s)}}catch(u){}return n}function D(i,t,n,u){let a=!!t.us&&!!i&&i.us!==t.us,f=i;return(!f||n-f.last>18e5||a)&&(f={id:u(),start:n,last:n,ref:t.ref,us:t.us,um:t.um,uc:t.uc}),f.last=n,f}function N(i){if(!i)return null;try{let t=JSON.parse(i);if(t&&typeof t.id=="string"&&typeof t.start=="number"&&typeof t.last=="number")return{id:t.id,start:t.start,last:t.last,ref:t.ref||"",us:t.us||"",um:t.um||"",uc:t.uc||""}}catch(t){}return null}function U(i,t){let n={};return t.language&&(n.language=String(t.language).slice(0,16)),t.width&&t.height&&(n.resolution=`${t.width}x${t.height}`),t.density&&(n.density=t.density),i.ref&&(n.referrer=i.ref),i.us&&(n.utm_source=i.us),i.um&&(n.utm_medium=i.um),i.uc&&(n.utm_campaign=i.uc),n}function C(){let i=new Map;return{get(t){var n;try{let u=window.localStorage.getItem(t);if(u!==null)return u}catch(u){}return(n=i.get(t))!=null?n:null},set(t,n){i.set(t,n);try{window.localStorage.setItem(t,n)}catch(u){}},remove(t){i.delete(t);try{window.localStorage.removeItem(t)}catch(n){}}}}function H(i){return{send(t,n,u){if(!u){let a=typeof navigator!="undefined"?navigator:void 0;if(a&&typeof a.sendBeacon=="function")try{if(a.sendBeacon(t,new Blob([n],{type:"text/plain"})))return}catch(f){}}if(typeof fetch!="function"){i("no fetch available; dropped",t);return}try{let a={method:"POST",body:n,keepalive:!0};u&&(a.headers=E({"Content-Type":"application/json"},u));let f=fetch(t,a);f&&typeof f.then=="function"&&f.then(g=>{g.ok||i(`${g.status} from ${t}`)},g=>i("send failed",g))}catch(a){i("send failed",a)}}}}var j="0.1.1",h={device:"mx_did",session:"mx_ses",user:"mx_uid"},ne=200,ie=1e6,re=["name","username","email","organization","phone","picture","gender"];function X(){let i=C(),t=null,n=!1,u=[],a={ref:"",us:"",um:"",uc:""},f=null,g=null,m=null,s=null,d=(e,...r)=>{if(t&&t.debug)try{console.log("[mixdive]",e,...r)}catch(o){}},v=H(d),V=()=>typeof window!="undefined"&&typeof document!="undefined";function b(){if(g)return g;let e=i.get(h.device);return e||(e=I(),i.set(h.device,e)),g=e,e}function k(){return f!=null?f:N(i.get(h.session))}function A(e){f=e,i.set(h.session,JSON.stringify(e))}function B(e){let r=D(k(),a,e,I);return A(r),r}function P(e){let r={};try{navigator.language&&(r.language=navigator.language)}catch(o){}try{r.width=screen.width,r.height=screen.height}catch(o){}try{window.devicePixelRatio&&(r.density=window.devicePixelRatio)}catch(o){}return U(e,r)}function _(e,r,o=!1){let c=t,l=JSON.stringify(r);c.appVersion&&!o?v.send(c.server+e,l,{"X-Api-Key":c.key,"X-App-Version":c.appVersion}):v.send(c.server+e+"?api_key="+encodeURIComponent(c.key),l),d("sent",e,r)}function y(e){if(!n){if(!t){u.length>=ne&&u.shift(),u.push(e);return}try{e()}catch(r){d("call failed",r)}}}function w(e,r,o){if(typeof e!="string"||!e.trim()||e.indexOf("gtm.")===0){d("ignored event key",e);return}let c=B(Date.now()),l={event_key:e,device_id:b(),session_id:c.id,context:P(c)};if(m&&(l.user_id=m),r&&typeof r=="object"&&(l.properties=r),o&&typeof o=="object"){typeof o.id=="string"&&o.id&&(l.id=o.id);let{count:p,sum:x,duration:S}=o;typeof p=="number"&&Number.isInteger(p)&&p>1&&p<=ie?l.count=p:p!==void 0&&p!==1&&d("ignored count (whole number 2\u20261000000)",p),typeof x=="number"&&Number.isFinite(x)&&x!==0&&(l.sum=x),typeof S=="number"&&Number.isFinite(S)&&S>0&&(l.duration=S)}_("/ingest/event",l)}function M(e){let r=typeof e=="string"&&e?e:"";if(!r)try{r=location.pathname||"/"}catch(l){r="/"}if(r===s)return;let o={url:r};try{document.title&&(o.title=String(document.title).slice(0,256))}catch(l){}let c=s;if(!c)try{document.referrer&&(c=document.referrer.split("?")[0].slice(0,256))}catch(l){}c&&(o.referrer=c),s=r,w("page_view",o)}function G(e,r){let o={user_id:e,device_id:b()};if(r&&typeof r=="object"){for(let l of re){let p=r[l];typeof p=="string"&&p&&(o[l]=p)}let c=r.birthYear;typeof c=="number"&&Number.isInteger(c)&&c>0&&(o.birth_year=c),r.custom&&typeof r.custom=="object"&&(o.custom=r.custom)}return o}function O(e,r){if(typeof e!="string"||!e.trim()){d("ignored user id",e);return}m=e,i.set(h.user,e),_("/ingest/user",G(e,r))}function q(){try{let e=k();if(!e)return;let r=Date.now(),o=r-e.last>18e5?e.last:r,c=Math.max(0,Math.round((o-e.start)/1e3));_("/ingest/event",{event_key:"session_end",id:e.id+":end",device_id:b(),session_id:e.id,context:P(e),properties:{duration:c}},!0)}catch(e){d("session_end failed",e)}}function J(){let e=k();e&&(e.last=Date.now(),A(e))}function z(){document.addEventListener("visibilitychange",()=>{document.visibilityState==="hidden"?q():J()}),window.addEventListener("pagehide",q)}function Y(){let e=window.history,r=()=>{setTimeout(()=>y(()=>M()),0)};for(let o of["pushState","replaceState"]){let c=e[o];typeof c=="function"&&(e[o]=function(...l){let p=c.apply(this,l);return r(),p})}window.addEventListener("popstate",r)}function W(e){if(!V())return;if(t){d("init called again; the first call wins");return}let r=e&&typeof e.key=="string"?e.key.trim():"",o=e&&typeof e.server=="string"?e.server.trim().replace(/\/+$/,""):"";if(!r||!/^https?:\/\/[^/]+/i.test(o)){n=!0,u=[];try{console.warn("[mixdive] off: init needs an API key and the server origin (https://analytics.example.com)")}catch(l){}return}if(typeof navigator!="undefined"&&navigator.webdriver){n=!0,u=[];return}t={key:r,server:o,autoPageViews:e.autoPageViews!==!1,appVersion:typeof e.appVersion=="string"?e.appVersion.slice(0,64):"",debug:!!e.debug},a=L(location,document.referrer),m=i.get(h.user),z();let c=u;u=[];for(let l of c)y(l);t.autoPageViews&&(Y(),y(()=>M())),d("started",{server:o,autoPageViews:t.autoPageViews,version:j})}function Q(){i.remove(h.device),i.remove(h.session),i.remove(h.user),f=null,g=null,m=null}return{init:W,track:(e,r,o)=>y(()=>w(e,r,o)),pageView:e=>y(()=>M(e)),identify:e=>y(()=>O(e)),setUser:(e,r)=>y(()=>O(e,r)),login:e=>y(()=>w("login",e?{method:e}:void 0)),signUp:e=>y(()=>w("sign_up",e?{method:e}:void 0)),reset:Q,get version(){return j}}}var F=["init","track","pageView","identify","setUser","login","signUp","reset"];function $(i,t){let n=i.mixdive;if(n&&n.loaded)return null;let u=X(),a=(s,d)=>{typeof s=="string"&&F.indexOf(s)>=0&&u[s](...d)},f=s=>{try{let d=Array.prototype.slice.call(s);a(d[0],d.slice(1))}catch(d){}},g=function(s,...d){a(s,d)};for(let s of F)g[s]=(...d)=>a(s,d);Object.defineProperty(g,"version",{get:()=>u.version}),g.loaded=!0,g.q={push:f},i.mixdive=g;let m=n&&n.q&&typeof n.q.length=="number"?Array.prototype.slice.call(n.q):[];for(let s of m)f(s);if(t){let s=t.dataset,d=s.key||"",v=s.server||"";if(!v)try{v=new URL(t.src,i.location.href).origin}catch(V){}d&&u.init({key:d,server:v,autoPageViews:s.autoPageViews!=="false",appVersion:s.appVersion||void 0,debug:s.debug==="true"})}return u}$(window,document.currentScript);})();
|
package/package.json
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@mixdive/browser",
|
|
3
|
-
"version": "0.1.
|
|
4
|
-
"description": "
|
|
3
|
+
"version": "0.1.1",
|
|
4
|
+
"description": "Self-hosted product analytics for the web. The Mixdive script tag and npm client: page views, visitors, sessions and your own events.",
|
|
5
5
|
"license": "Apache-2.0",
|
|
6
|
-
"homepage": "https://
|
|
6
|
+
"homepage": "https://mixdive.com",
|
|
7
7
|
"repository": {
|
|
8
8
|
"type": "git",
|
|
9
9
|
"url": "git+https://github.com/mixdive/mixdive-js.git",
|
|
@@ -16,7 +16,11 @@
|
|
|
16
16
|
"product-analytics",
|
|
17
17
|
"web-analytics",
|
|
18
18
|
"self-hosted",
|
|
19
|
-
"privacy"
|
|
19
|
+
"privacy",
|
|
20
|
+
"gdpr",
|
|
21
|
+
"cookieless",
|
|
22
|
+
"page-views",
|
|
23
|
+
"event-tracking"
|
|
20
24
|
],
|
|
21
25
|
"type": "module",
|
|
22
26
|
"sideEffects": [
|