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.
@@ -1,8 +1,8 @@
1
- import { Router } from './router.ts';
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): Router;
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, dates: /* @__PURE__ */ new Set() };
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
- function analytics(options) {
6878
- const excluded = options?.excluded ?? DEFAULT_EXCLUDED;
6879
- const store = new MemStore();
6880
- function shouldExclude(path2) {
6881
- return excluded.some((e) => path2.startsWith(e));
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
- const middleware = async (req, ctx, next) => {
6884
- const url = new URL(req.url);
6885
- const path2 = url.pathname;
6886
- if (!shouldExclude(path2)) {
6887
- const date = (/* @__PURE__ */ new Date()).toISOString().slice(0, 10);
6888
- const ref = req.headers.get("referer") || "";
6889
- const refDomain = ref ? new URL(ref).hostname.replace(/^www\./, "") : "";
6890
- const ua = req.headers.get("user-agent") || "";
6891
- const mobile = /mobile|android|iphone|ipad/i.test(ua);
6892
- store.record(path2, date, refDomain, mobile);
6893
- }
6894
- return next(req, ctx);
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;transition:height .3s}
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
- <h2>Daily Page Views</h2>
6963
- <div class="chart">${bars}</div>
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
- </html>`;
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
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "weifuwu",
3
- "version": "0.17.5",
3
+ "version": "0.17.6",
4
4
  "description": "Web-standard HTTP framework for Node.js — (req, ctx) => Response",
5
5
  "main": "./dist/index.js",
6
6
  "types": "./dist/index.d.ts",