weifuwu 0.17.5 → 0.17.6
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/dist/analytics.d.ts +5 -5
- package/dist/index.js +55 -70
- package/package.json +1 -1
package/dist/analytics.d.ts
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import type { Handler, Middleware } from './types.ts';
|
|
2
2
|
export interface AnalyticsOptions {
|
|
3
|
-
pg?: {
|
|
4
|
-
sql: any;
|
|
5
|
-
};
|
|
6
3
|
excluded?: string[];
|
|
7
4
|
}
|
|
8
|
-
export declare function analytics(options?: AnalyticsOptions):
|
|
5
|
+
export declare function analytics(options?: AnalyticsOptions): {
|
|
6
|
+
middleware: Middleware;
|
|
7
|
+
handler: Handler;
|
|
8
|
+
};
|
package/dist/index.js
CHANGED
|
@@ -6819,11 +6819,10 @@ var MemStore = class {
|
|
|
6819
6819
|
}
|
|
6820
6820
|
let page = this.pages.get(path2);
|
|
6821
6821
|
if (!page) {
|
|
6822
|
-
page = { count: 0
|
|
6822
|
+
page = { count: 0 };
|
|
6823
6823
|
this.pages.set(path2, page);
|
|
6824
6824
|
}
|
|
6825
6825
|
page.count++;
|
|
6826
|
-
page.dates.add(date);
|
|
6827
6826
|
if (refDomain) {
|
|
6828
6827
|
let refs = this.refs.get(date);
|
|
6829
6828
|
if (!refs) {
|
|
@@ -6852,8 +6851,6 @@ var MemStore = class {
|
|
|
6852
6851
|
for (const p of day.uv) allUv.add(p);
|
|
6853
6852
|
}
|
|
6854
6853
|
for (const [path2, page] of this.pages) {
|
|
6855
|
-
let count = 0;
|
|
6856
|
-
for (const d of page.dates) if (d >= sinceStr) count += page.count / page.dates.size;
|
|
6857
6854
|
pageMap.set(path2, page.count);
|
|
6858
6855
|
}
|
|
6859
6856
|
const topPages = [...pageMap.entries()].sort((a, b) => b[1] - a[1]).slice(0, 20).map(([path2, count]) => ({ path: path2, pv: count }));
|
|
@@ -6873,61 +6870,34 @@ var MemStore = class {
|
|
|
6873
6870
|
devices: { mobile: Math.round(totalMobile / total * 1e3) / 10, desktop: Math.round(totalDesktop / total * 1e3) / 10 }
|
|
6874
6871
|
};
|
|
6875
6872
|
}
|
|
6876
|
-
|
|
6877
|
-
|
|
6878
|
-
|
|
6879
|
-
|
|
6880
|
-
|
|
6881
|
-
|
|
6873
|
+
handler() {
|
|
6874
|
+
return async (req) => {
|
|
6875
|
+
const url = new URL(req.url);
|
|
6876
|
+
const days = Math.min(Math.max(Number(url.searchParams.get("days")) || 7, 1), 365);
|
|
6877
|
+
const data = this.query(days);
|
|
6878
|
+
if (url.pathname === "/__analytics/data") {
|
|
6879
|
+
return Response.json(data);
|
|
6880
|
+
}
|
|
6881
|
+
return new Response(this.renderDashboard(days, data), {
|
|
6882
|
+
headers: { "content-type": "text/html; charset=utf-8" }
|
|
6883
|
+
});
|
|
6884
|
+
};
|
|
6882
6885
|
}
|
|
6883
|
-
|
|
6884
|
-
const
|
|
6885
|
-
const
|
|
6886
|
-
|
|
6887
|
-
|
|
6888
|
-
|
|
6889
|
-
|
|
6890
|
-
|
|
6891
|
-
|
|
6892
|
-
|
|
6893
|
-
|
|
6894
|
-
|
|
6895
|
-
|
|
6896
|
-
const router = new Router();
|
|
6897
|
-
router.use(middleware);
|
|
6898
|
-
router.get("/__analytics/data", async (req) => {
|
|
6899
|
-
const url = new URL(req.url);
|
|
6900
|
-
const days = Math.min(Math.max(Number(url.searchParams.get("days")) || 7, 1), 365);
|
|
6901
|
-
return Response.json(store.query(days));
|
|
6902
|
-
});
|
|
6903
|
-
router.get("/analytics", async (req) => {
|
|
6904
|
-
const url = new URL(req.url);
|
|
6905
|
-
const days = Math.min(Math.max(Number(url.searchParams.get("days")) || 7, 1), 365);
|
|
6906
|
-
const data = store.query(days);
|
|
6907
|
-
return new Response(renderDashboard(days, data), {
|
|
6908
|
-
headers: { "content-type": "text/html; charset=utf-8" }
|
|
6909
|
-
});
|
|
6910
|
-
});
|
|
6911
|
-
return router;
|
|
6912
|
-
}
|
|
6913
|
-
function renderDashboard(days, data) {
|
|
6914
|
-
const { total_pv, total_uv, daily, top_pages, referrers, devices } = data;
|
|
6915
|
-
const maxPv = Math.max(...daily.map((d) => d.pv), 1);
|
|
6916
|
-
const bars = daily.map(
|
|
6917
|
-
(d) => `<div class="bar-wrap"><div class="bar" style="height:${d.pv / maxPv * 100}%"></div><span class="bar-label">${d.date.slice(5)}</span></div>`
|
|
6918
|
-
).join("");
|
|
6919
|
-
const rows = top_pages.map(
|
|
6920
|
-
(p, i) => `<tr><td class="num">${i + 1}</td><td class="path">${p.path}</td><td class="num">${p.pv}</td></tr>`
|
|
6921
|
-
).join("");
|
|
6922
|
-
const refRows = referrers.map(
|
|
6923
|
-
(r) => `<tr><td>${r.domain}</td><td class="num">${r.count}</td></tr>`
|
|
6924
|
-
).join("");
|
|
6925
|
-
return `<!DOCTYPE html>
|
|
6886
|
+
renderDashboard(days, data) {
|
|
6887
|
+
const { total_pv, total_uv, daily, top_pages, referrers, devices } = data;
|
|
6888
|
+
const maxPv = Math.max(...daily.map((d) => d.pv), 1);
|
|
6889
|
+
const bars = daily.map(
|
|
6890
|
+
(d) => `<div class="bar-wrap"><div class="bar" style="height:${d.pv / maxPv * 100}%"></div><span class="bar-label">${d.date.slice(5)}</span></div>`
|
|
6891
|
+
).join("");
|
|
6892
|
+
const rows = top_pages.map(
|
|
6893
|
+
(p, i) => `<tr><td class="num">${i + 1}</td><td class="path">${p.path}</td><td class="num">${p.pv}</td></tr>`
|
|
6894
|
+
).join("");
|
|
6895
|
+
const refRows = referrers.map(
|
|
6896
|
+
(r) => `<tr><td>${r.domain}</td><td class="num">${r.count}</td></tr>`
|
|
6897
|
+
).join("");
|
|
6898
|
+
return `<!DOCTYPE html>
|
|
6926
6899
|
<html lang="en">
|
|
6927
|
-
<head>
|
|
6928
|
-
<meta charset="utf-8"/>
|
|
6929
|
-
<meta name="viewport" content="width=device-width, initial-scale=1"/>
|
|
6930
|
-
<title>Analytics - weifuwu</title>
|
|
6900
|
+
<head><meta charset="utf-8"/><meta name="viewport" content="width=device-width,initial-scale=1"/><title>Analytics - weifuwu</title>
|
|
6931
6901
|
<style>
|
|
6932
6902
|
*,:before,:after{box-sizing:border-box;margin:0;padding:0}
|
|
6933
6903
|
body{font-family:-apple-system,BlinkMacSystemFont,'Segoe UI',Roboto,sans-serif;background:#f8f9fa;color:#333;padding:24px;max-width:960px;margin:0 auto}
|
|
@@ -6940,7 +6910,7 @@ h1{font-size:24px;font-weight:700;margin-bottom:24px}
|
|
|
6940
6910
|
.section h2{font-size:14px;font-weight:600;color:#888;text-transform:uppercase;letter-spacing:.05em;margin-bottom:16px}
|
|
6941
6911
|
.chart{display:flex;align-items:flex-end;gap:4px;height:160px;padding-top:8px}
|
|
6942
6912
|
.bar-wrap{flex:1;display:flex;flex-direction:column;align-items:center;height:100%;justify-content:flex-end}
|
|
6943
|
-
.bar{width:100%;background:#2563eb;border-radius:4px 4px 0 0;min-height:2px
|
|
6913
|
+
.bar{width:100%;background:#2563eb;border-radius:4px 4px 0 0;min-height:2px}
|
|
6944
6914
|
.bar-label{font-size:10px;color:#888;margin-top:6px;white-space:nowrap}
|
|
6945
6915
|
table{width:100%;border-collapse:collapse;font-size:13px}
|
|
6946
6916
|
th{text-align:left;padding:6px 8px;color:#888;font-weight:500;border-bottom:1px solid #eee}
|
|
@@ -6948,8 +6918,7 @@ td{padding:6px 8px;border-bottom:1px solid #f0f0f0}
|
|
|
6948
6918
|
.num{text-align:right;font-variant-numeric:tabular-nums}
|
|
6949
6919
|
.path{font-family:ui-monospace,SFMono-Regular,monospace;font-size:12px}
|
|
6950
6920
|
tr:hover td{background:#f8faff}
|
|
6951
|
-
</style>
|
|
6952
|
-
</head>
|
|
6921
|
+
</style></head>
|
|
6953
6922
|
<body>
|
|
6954
6923
|
<h1>Analytics</h1>
|
|
6955
6924
|
<div class="cards">
|
|
@@ -6958,17 +6927,33 @@ tr:hover td{background:#f8faff}
|
|
|
6958
6927
|
<div class="card"><div class="val">${devices.mobile}%</div><div class="lbl">Mobile</div></div>
|
|
6959
6928
|
<div class="card"><div class="val">${devices.desktop}%</div><div class="lbl">Desktop</div></div>
|
|
6960
6929
|
</div>
|
|
6961
|
-
<div class="section">
|
|
6962
|
-
|
|
6963
|
-
|
|
6964
|
-
</div>
|
|
6965
|
-
<div class="section">
|
|
6966
|
-
<h2>Top Pages</h2>
|
|
6967
|
-
<table><thead><tr><th style="width:32px">#</th><th>Path</th><th style="width:64px">Views</th></tr></thead><tbody>${rows}</tbody></table>
|
|
6968
|
-
</div>
|
|
6930
|
+
<div class="section"><h2>Daily Page Views</h2><div class="chart">${bars}</div></div>
|
|
6931
|
+
<div class="section"><h2>Top Pages</h2>
|
|
6932
|
+
<table><thead><tr><th style="width:32px">#</th><th>Path</th><th style="width:64px">Views</th></tr></thead><tbody>${rows}</tbody></table></div>
|
|
6969
6933
|
${referrers.length ? `<div class="section"><h2>Referrers</h2><table><thead><tr><th>Domain</th><th style="width:64px">Views</th></tr></thead><tbody>${refRows}</tbody></table></div>` : ""}
|
|
6970
|
-
</body
|
|
6971
|
-
|
|
6934
|
+
</body></html>`;
|
|
6935
|
+
}
|
|
6936
|
+
};
|
|
6937
|
+
function analytics(options) {
|
|
6938
|
+
const excluded = options?.excluded ?? DEFAULT_EXCLUDED;
|
|
6939
|
+
const store = new MemStore();
|
|
6940
|
+
const middleware = async (req, ctx, next) => {
|
|
6941
|
+
const url = new URL(req.url);
|
|
6942
|
+
const path2 = url.pathname;
|
|
6943
|
+
if (!excluded.some((e) => path2.startsWith(e))) {
|
|
6944
|
+
const date = (/* @__PURE__ */ new Date()).toISOString().slice(0, 10);
|
|
6945
|
+
const ref = req.headers.get("referer") || "";
|
|
6946
|
+
const refDomain = ref ? new URL(ref).hostname.replace(/^www\./, "") : "";
|
|
6947
|
+
const ua = req.headers.get("user-agent") || "";
|
|
6948
|
+
const mobile = /mobile|android|iphone|ipad/i.test(ua);
|
|
6949
|
+
store.record(path2, date, refDomain, mobile);
|
|
6950
|
+
}
|
|
6951
|
+
return next(req, ctx);
|
|
6952
|
+
};
|
|
6953
|
+
return {
|
|
6954
|
+
middleware,
|
|
6955
|
+
handler: store.handler()
|
|
6956
|
+
};
|
|
6972
6957
|
}
|
|
6973
6958
|
|
|
6974
6959
|
// preferences.ts
|