diff --git a/.gitignore b/.gitignore
index 47be70dc..a2442a92 100644
--- a/.gitignore
+++ b/.gitignore
@@ -14,7 +14,6 @@
# production
/build
-/public/umami.js
# misc
.DS_Store
diff --git a/components/layout.js b/components/layout.js
index c3880bd3..19750bcd 100644
--- a/components/layout.js
+++ b/components/layout.js
@@ -17,7 +17,7 @@ export default function Layout({ title, children }) {
)}
diff --git a/pages/api/session.js b/pages/api/session.js
index bca7ce7a..801dca85 100644
--- a/pages/api/session.js
+++ b/pages/api/session.js
@@ -5,7 +5,7 @@ import { allowPost } from 'lib/middleware';
export default async (req, res) => {
await allowPost(req, res);
- let result = { success: 0, time: Date.now() };
+ let result = { success: 0 };
const {
website_id,
@@ -23,6 +23,7 @@ export default async (req, res) => {
if (website) {
const session = await getSession(session_id);
+ const time = Date.now();
if (!session) {
await createSession(website_id, session_id, {
@@ -40,7 +41,8 @@ export default async (req, res) => {
success: 1,
session_id,
website_id,
- hash: hash(`${website_id}${session_id}${result.time}`),
+ time,
+ hash: hash(`${website_id}${session_id}${time}`),
};
}
}
diff --git a/pages/index.js b/pages/index.js
index 5d881cdb..e632bfd1 100644
--- a/pages/index.js
+++ b/pages/index.js
@@ -1,14 +1,19 @@
import React from 'react';
import Layout from 'components/layout';
+import Link from 'next/link';
export default function Home() {
return (
Hello.
- abc
+
+ abc
+
- 123
+
+ 123
+
);
}
diff --git a/public/umami.js b/public/umami.js
new file mode 100644
index 00000000..d8860b78
--- /dev/null
+++ b/public/umami.js
@@ -0,0 +1 @@
+!function(){"use strict";function e(e){var n=this.constructor;return this.then((function(t){return n.resolve(e()).then((function(){return t}))}),(function(t){return n.resolve(e()).then((function(){return n.reject(t)}))}))}var n=setTimeout;function t(e){return Boolean(e&&void 0!==e.length)}function r(){}function o(e){if(!(this instanceof o))throw new TypeError("Promises must be constructed via new");if("function"!=typeof e)throw new TypeError("not a function");this._state=0,this._handled=!1,this._value=void 0,this._deferreds=[],f(e,this)}function i(e,n){for(;3===e._state;)e=e._value;0!==e._state?(e._handled=!0,o._immediateFn((function(){var t=1===e._state?n.onFulfilled:n.onRejected;if(null!==t){var r;try{r=t(e._value)}catch(e){return void s(n.promise,e)}u(n.promise,r)}else(1===e._state?u:s)(n.promise,e._value)}))):e._deferreds.push(n)}function u(e,n){try{if(n===e)throw new TypeError("A promise cannot be resolved with itself.");if(n&&("object"==typeof n||"function"==typeof n)){var t=n.then;if(n instanceof o)return e._state=3,e._value=n,void c(e);if("function"==typeof t)return void f((r=t,i=n,function(){r.apply(i,arguments)}),e)}e._state=1,e._value=n,c(e)}catch(n){s(e,n)}var r,i}function s(e,n){e._state=2,e._value=n,c(e)}function c(e){2===e._state&&0===e._deferreds.length&&o._immediateFn((function(){e._handled||o._unhandledRejectionFn(e._value)}));for(var n=0,t=e._deferreds.length;n
- fetch(url, {
- method: 'post',
- cache: 'no-cache',
- headers: {
- Accept: 'application/json',
- 'Content-Type': 'application/json',
- },
- body: JSON.stringify(params),
- }).then(res => res.json());
-
-const createSession = data =>
- post(`${HOST_URL}/api/session`, data).then(({ success, ...session }) => {
- if (success) {
- store.setItem(SESSION_VAR, JSON.stringify(session));
- return success;
- }
- });
-
-const getSession = () => JSON.parse(store.getItem(SESSION_VAR));
-
-const pageView = (url, referrer) =>
- post(`${HOST_URL}/api/collect`, {
- type: 'pageview',
- payload: { url, referrer, session: getSession() },
- }).then(({ success }) => {
- if (!success) {
- store.removeItem(SESSION_VAR);
- }
- return success;
- });
-
const script = document.querySelector('script[data-website-id]');
if (script) {
const website_id = script.getAttribute('data-website-id');
if (website_id) {
- const referrer = document.referrer;
+ const sessionKey = 'umami.session';
+ const hostUrl = new URL(script.src).origin;
const screen = `${width}x${height}`;
- const url = `${pathname}${search}`;
- const data = { website_id, hostname, url, screen, language };
+ let currentUrl = `${pathname}${search}`;
+ let currenrRef = document.referrer;
- if (!store.getItem(SESSION_VAR)) {
- createSession(data).then(success => success && pageView(url, referrer));
- } else {
- pageView(url, referrer).then(success => !success && createSession(data));
- }
+ const post = (url, params) =>
+ fetch(url, {
+ method: 'post',
+ cache: 'no-cache',
+ headers: {
+ Accept: 'application/json',
+ 'Content-Type': 'application/json',
+ },
+ body: JSON.stringify(params),
+ }).then(res => res.json());
+
+ const createSession = data =>
+ post(`${hostUrl}/api/session`, data).then(({ success, ...session }) => {
+ if (success) {
+ store.setItem(sessionKey, JSON.stringify(session));
+ return success;
+ }
+ });
+
+ const getSession = () => JSON.parse(store.getItem(sessionKey));
+
+ const getSessionData = url => ({ website_id, hostname, url, screen, language });
+
+ const pageView = (url, referrer) =>
+ post(`${hostUrl}/api/collect`, {
+ type: 'pageview',
+ payload: { url, referrer, session: getSession() },
+ }).then(({ success }) => {
+ if (!success) {
+ store.removeItem(sessionKey);
+ }
+ return success;
+ });
+
+ const execute = (url, referrer) => {
+ const data = getSessionData(url);
+
+ if (!store.getItem(sessionKey)) {
+ createSession(data).then(success => success && pageView(url, referrer));
+ } else {
+ pageView(url, referrer).then(success => !success && createSession(data));
+ }
+ };
+
+ const handlePush = (state, title, url) => {
+ currenrRef = currentUrl;
+ currentUrl = url;
+ execute(currentUrl, currenrRef);
+ };
+
+ const hook = (type, cb) => {
+ const orig = history[type];
+ return (state, title, url) => {
+ const args = [state, title, url];
+ cb.apply(null, args);
+ return orig.apply(history, args);
+ };
+ };
+
+ history.pushState = hook('pushState', handlePush);
+ history.replaceState = hook('replaceState', handlePush);
+
+ execute(currentUrl, currenrRef);
}
}