oddmisc 1.0.0
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 +133 -0
- package/dist/index.cjs +12 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +94 -0
- package/dist/index.d.ts +94 -0
- package/dist/index.js +12 -0
- package/dist/index.js.map +1 -0
- package/package.json +46 -0
package/README.md
ADDED
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
# oddmisc
|
|
2
|
+
|
|
3
|
+
杂七杂八奇怪小工具 npm 包
|
|
4
|
+
|
|
5
|
+
[](https://www.npmjs.com/package/oddmisc)
|
|
6
|
+
[](https://github.com/yCENzh/oddmisc/blob/main/LICENSE)
|
|
7
|
+
|
|
8
|
+
## 安装
|
|
9
|
+
|
|
10
|
+
```bash
|
|
11
|
+
npm install oddmisc
|
|
12
|
+
# 或
|
|
13
|
+
pnpm add oddmisc
|
|
14
|
+
# 或
|
|
15
|
+
yarn add oddmisc
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
## 快速开始
|
|
19
|
+
|
|
20
|
+
### 基本使用
|
|
21
|
+
|
|
22
|
+
```javascript
|
|
23
|
+
import { createUmamiClient } from 'oddmisc';
|
|
24
|
+
|
|
25
|
+
// 创建客户端
|
|
26
|
+
const client = createUmamiClient({
|
|
27
|
+
shareUrl: 'https://your-umami-instance.com/share/your-share-id'
|
|
28
|
+
});
|
|
29
|
+
|
|
30
|
+
// 获取页面访问统计
|
|
31
|
+
const stats = await client.getPageStats('/about');
|
|
32
|
+
console.log(`页面浏览量: ${stats.pageviews}, 访客数: ${stats.visitors}`);
|
|
33
|
+
|
|
34
|
+
// 获取网站整体统计
|
|
35
|
+
const siteStats = await client.getSiteStats();
|
|
36
|
+
console.log(`总浏览量: ${siteStats.pageviews}, 总访客数: ${siteStats.visitors}`);
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
### Astro 集成
|
|
40
|
+
|
|
41
|
+
在 `astro.config.mjs` 中配置:
|
|
42
|
+
|
|
43
|
+
```javascript
|
|
44
|
+
import { defineConfig } from 'astro/config';
|
|
45
|
+
import { umami } from 'oddmisc';
|
|
46
|
+
|
|
47
|
+
export default defineConfig({
|
|
48
|
+
integrations: [
|
|
49
|
+
umami({
|
|
50
|
+
shareUrl: 'https://your-umami-instance.com/share/your-share-id',
|
|
51
|
+
timezone: 'Asia/Shanghai',
|
|
52
|
+
enableCache: true,
|
|
53
|
+
cacheTTL: 3600000 // 1小时
|
|
54
|
+
})
|
|
55
|
+
]
|
|
56
|
+
});
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
然后在前端代码中使用:
|
|
60
|
+
|
|
61
|
+
```javascript
|
|
62
|
+
// 全局可用
|
|
63
|
+
const stats = await window.oddmisc.getStats('/some-page');
|
|
64
|
+
const siteStats = await window.oddmisc.getSiteStats();
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
## API 参考
|
|
68
|
+
|
|
69
|
+
### UmamiClient
|
|
70
|
+
|
|
71
|
+
#### 构造函数
|
|
72
|
+
```javascript
|
|
73
|
+
const client = createUmamiClient(config);
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
#### 配置选项
|
|
77
|
+
```javascript
|
|
78
|
+
const config = {
|
|
79
|
+
shareUrl: 'https://umami.example.com/share/abc123', // 必需
|
|
80
|
+
timezone: 'Asia/Shanghai', // 可选,默认 'Asia/Shanghai'
|
|
81
|
+
enableCache: true, // 可选,默认 true
|
|
82
|
+
cacheTTL: 3600000 // 可选,默认 1小时(毫秒)
|
|
83
|
+
};
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
#### 方法
|
|
87
|
+
|
|
88
|
+
- `getPageStats(path, options)` - 获取指定页面统计
|
|
89
|
+
- `getPageStatsByUrl(url, options)` - 通过 URL 获取页面统计
|
|
90
|
+
- `getSiteStats(options)` - 获取网站整体统计
|
|
91
|
+
- `clearCache()` - 清除缓存
|
|
92
|
+
- `getConfig()` - 获取当前配置
|
|
93
|
+
- `updateConfig(newConfig)` - 更新配置
|
|
94
|
+
|
|
95
|
+
### Astro 集成
|
|
96
|
+
|
|
97
|
+
```javascript
|
|
98
|
+
umami(options: UmamiIntegrationOptions)
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
选项:
|
|
102
|
+
```javascript
|
|
103
|
+
interface UmamiIntegrationOptions {
|
|
104
|
+
shareUrl: string; // Umami 分享链接
|
|
105
|
+
timezone?: string; // 时区,默认 'Asia/Shanghai'
|
|
106
|
+
enableCache?: boolean; // 启用缓存,默认 true
|
|
107
|
+
cacheTTL?: number; // 缓存时间,单位毫秒
|
|
108
|
+
}
|
|
109
|
+
```
|
|
110
|
+
|
|
111
|
+
## 支持的 Umami URL 格式
|
|
112
|
+
|
|
113
|
+
- `https://umami.example.com/share/abc123`
|
|
114
|
+
- `https://cloud.umami.is/analytics/us/share/abc123`
|
|
115
|
+
- `https://umami.example.com/analytics/share/abc123`
|
|
116
|
+
|
|
117
|
+
## 浏览器兼容性
|
|
118
|
+
|
|
119
|
+
- 现代浏览器(Chrome 60+, Firefox 60+, Safari 12+)
|
|
120
|
+
- 支持 localStorage 的环境
|
|
121
|
+
|
|
122
|
+
## License
|
|
123
|
+
|
|
124
|
+
MIT © yCENzh
|
|
125
|
+
|
|
126
|
+
## 贡献
|
|
127
|
+
|
|
128
|
+
欢迎提交 Issue 和 Pull Request!
|
|
129
|
+
|
|
130
|
+
## 相关链接
|
|
131
|
+
|
|
132
|
+
- [Umami 官网](https://umami.is/)
|
|
133
|
+
- [GitHub 仓库](https://github.com/yCENzh/oddmisc)
|
package/dist/index.cjs
ADDED
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
"use strict";var l=Object.defineProperty;var I=Object.getOwnPropertyDescriptor;var T=Object.getOwnPropertyNames;var P=Object.prototype.hasOwnProperty;var x=(r,e)=>{for(var a in e)l(r,a,{get:e[a],enumerable:!0})},b=(r,e,a,t)=>{if(e&&typeof e=="object"||typeof e=="function")for(let i of T(e))!P.call(r,i)&&i!==a&&l(r,i,{get:()=>e[i],enumerable:!(t=I(e,i))||t.enumerable});return r};var L=r=>b(l({},"__esModule",{value:!0}),r);var A={};x(A,{CacheManager:()=>o,DEFAULT_CONFIG:()=>w,UmamiClient:()=>n,UmamiError:()=>c,VERSION:()=>d,createUmamiClient:()=>f,isValidConfig:()=>C,isValidShareUrl:()=>S,parseShareUrl:()=>g,umami:()=>p});module.exports=L(A);var d="1.0.0",w={timezone:"Asia/Shanghai",enableCache:!0,cacheTTL:36e5};function C(r){return typeof r=="object"&&r!==null&&typeof r.baseUrl=="string"&&typeof r.shareId=="string"&&r.baseUrl.length>0&&r.shareId.length>0}var c=class extends Error{constructor(a,t){super(a);this.code=t;this.name="UmamiError"}};var o=class{constructor(e="default",a=36e5){this.memoryCache=new Map;this.CACHE_KEY=`cache-${e}`,this.DEFAULT_TTL=a}get(e){if(this.memoryCache.has(e))return this.memoryCache.get(e);try{let a=localStorage.getItem(this.CACHE_KEY);if(a){let i=JSON.parse(a)[e];if(i&&Date.now()-i.timestamp<this.DEFAULT_TTL)return i.value}}catch{}return null}set(e,a){this.memoryCache.set(e,a);try{let t=localStorage.getItem(this.CACHE_KEY),i=t?JSON.parse(t):{};i[e]={timestamp:Date.now(),value:a},localStorage.setItem(this.CACHE_KEY,JSON.stringify(i))}catch{}}clear(){this.memoryCache.clear();try{localStorage.removeItem(this.CACHE_KEY)}catch{}}delete(e){this.memoryCache.delete(e);try{let a=localStorage.getItem(this.CACHE_KEY);if(a){let t=JSON.parse(a);delete t[e],localStorage.setItem(this.CACHE_KEY,JSON.stringify(t))}}catch{}}};var m=class{constructor(e){this.sharePromise=null;this.cacheManager=e}async getShareData(e,a){return this.sharePromise||(this.sharePromise=this.fetchShareData(e,a).catch(t=>{throw this.sharePromise=null,t})),this.sharePromise}async fetchShareData(e,a){let t=await fetch(`${e}/api/share/${a}`);if(!t.ok)throw new Error(`\u83B7\u53D6\u5206\u4EAB\u4FE1\u606F\u5931\u8D25: ${t.status} ${t.statusText}`);return t.json()}async getStats(e,a,t){let i=`${e}|${a}|${JSON.stringify(t)}`,s=this.cacheManager.get(i);if(s)return{...s,_fromCache:!0};let{websiteId:U,token:y}=await this.getShareData(e,a),E=new URLSearchParams({startAt:"0",endAt:Date.now().toString(),unit:"hour",timezone:t.timezone||"Asia/Shanghai",compare:"false",...t}),v=`${e}/api/websites/${U}/stats?${E.toString()}`,h=await fetch(v,{headers:{"x-umami-share-token":y}});if(!h.ok)throw h.status===401?(this.cacheManager.clear(),new Error("\u8BA4\u8BC1\u5931\u8D25\uFF0C\u8BF7\u68C0\u67E5 shareId")):new Error(`\u83B7\u53D6\u7EDF\u8BA1\u5931\u8D25: ${h.status} ${h.statusText}`);let u=await h.json();return this.cacheManager.set(i,u),u}clearShareCache(){this.sharePromise=null}};function g(r){try{let e=new URL(r),a=`${e.protocol}//${e.host}`,t=e.pathname.split("/"),i=t.indexOf("share");if(i===-1||i===t.length-1)throw new Error("\u65E0\u6548\u7684\u5206\u4EAB URL\uFF1A\u672A\u627E\u5230 share \u8DEF\u5F84");let s=t[i+1];if(!s||s.length<10)throw new Error("\u65E0\u6548\u7684\u5206\u4EAB ID");return{baseUrl:a,shareId:s}}catch(e){throw e instanceof Error?new Error(`URL \u89E3\u6790\u5931\u8D25: ${e.message}`):new Error("URL \u89E3\u6790\u5931\u8D25: \u65E0\u6548\u7684 URL \u683C\u5F0F")}}function S(r){try{return new URL(r).pathname.includes("/share/")}catch{return!1}}var n=class{constructor(e){if(!e.shareUrl)throw new Error("shareUrl \u662F\u5FC5\u9700\u53C2\u6570");let{baseUrl:a,shareId:t}=g(e.shareUrl);this.config={timezone:"Asia/Shanghai",enableCache:!0,cacheTTL:36e5,baseUrl:a,shareId:t,...e},this.cacheManager=new o("umami",this.config.cacheTTL),this.api=new m(this.cacheManager)}async getPageStats(e,a={}){if(!this.config.baseUrl||!this.config.shareId)throw new Error("\u5BA2\u6237\u7AEF\u672A\u6B63\u786E\u521D\u59CB\u5316");let t=await this.api.getStats(this.config.baseUrl,this.config.shareId,{path:`eq.${e}`,timezone:this.config.timezone,...a});return{pageviews:t.pageviews?.value||t.pageviews||0,visitors:t.visitors?.value||t.visitors||0,_fromCache:t._fromCache}}async getPageStatsByUrl(e,a={}){if(!this.config.baseUrl||!this.config.shareId)throw new Error("\u5BA2\u6237\u7AEF\u672A\u6B63\u786E\u521D\u59CB\u5316");let t=await this.api.getStats(this.config.baseUrl,this.config.shareId,{url:e,timezone:this.config.timezone,...a});return{pageviews:t.pageviews?.value||t.pageviews||0,visitors:t.visitors?.value||t.visitors||0,_fromCache:t._fromCache}}async getSiteStats(e={}){if(!this.config.baseUrl||!this.config.shareId)throw new Error("\u5BA2\u6237\u7AEF\u672A\u6B63\u786E\u521D\u59CB\u5316");let a=await this.api.getStats(this.config.baseUrl,this.config.shareId,{timezone:this.config.timezone,...e});return{pageviews:a.pageviews||0,visitors:a.visitors||0,_fromCache:a._fromCache}}clearCache(){this.cacheManager.clear(),this.api.clearShareCache()}getConfig(){return{...this.config}}updateConfig(e){this.config={...this.config,...e}}};function f(r){return new n(r)}typeof window<"u"&&(window.UmamiClient=n,window.createUmamiClient=f);function p(r){if(!r.shareUrl)throw new Error("\u9700\u8981\u914D\u7F6E shareUrl");return{name:"astro-umami-integration",hooks:{"astro:config:setup":({injectScript:e})=>{let a={shareUrl:r.shareUrl,timezone:r.timezone||"Asia/Shanghai",enableCache:r.enableCache!==!1,cacheTTL:r.cacheTTL||36e5};e("page",`
|
|
2
|
+
import { createUmamiClient } from 'oddmisc';
|
|
3
|
+
|
|
4
|
+
// \u521B\u5EFA\u547D\u540D\u7A7A\u95F4\u907F\u514D\u51B2\u7A81
|
|
5
|
+
window.oddmisc = window.oddmisc || {};
|
|
6
|
+
window.oddmisc.umami = createUmamiClient(${JSON.stringify(a)});
|
|
7
|
+
|
|
8
|
+
// \u547D\u540D\u7A7A\u95F4\u4E0B\u7684\u5FEB\u6377\u65B9\u6CD5
|
|
9
|
+
window.oddmisc.getStats = (path) => window.oddmisc.umami.getPageStats(path);
|
|
10
|
+
window.oddmisc.getSiteStats = () => window.oddmisc.umami.getSiteStats();
|
|
11
|
+
`)}}}}0&&(module.exports={CacheManager,DEFAULT_CONFIG,UmamiClient,UmamiError,VERSION,createUmamiClient,isValidConfig,isValidShareUrl,parseShareUrl,umami});
|
|
12
|
+
//# sourceMappingURL=index.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/index.ts","../src/shared/index.ts","../src/utils/umami/cache.ts","../src/modules/umami/api.ts","../src/utils/umami/url-parser.ts","../src/modules/umami/client.ts","../src/astro/integration.ts"],"sourcesContent":["// 核心导出\r\nexport { VERSION, DEFAULT_CONFIG, isValidConfig, UmamiError } from './shared';\r\n\r\n// Umami 模块\r\nexport { UmamiClient, createUmamiClient } from './modules/umami/client';\r\nexport type { UmamiConfig, StatsResult, StatsQueryParams } from './modules/umami/types';\r\n\r\n// 工具函数\r\nexport { CacheManager } from './utils/umami/cache';\r\nexport { parseShareUrl, isValidShareUrl } from './utils/umami/url-parser';\r\n\r\n// Astro 集成\r\nexport { umami } from './astro';\r\nexport type { UmamiIntegrationOptions } from './astro';","// 版本信息\r\nexport const VERSION = '1.0.0';\r\n\r\n// 默认配置\r\nexport const DEFAULT_CONFIG = {\r\n timezone: 'Asia/Shanghai',\r\n enableCache: true,\r\n cacheTTL: 3600000\r\n} as const;\r\n\r\n// 配置验证\r\nexport function isValidConfig(config: any): boolean {\r\n return (\r\n typeof config === 'object' &&\r\n config !== null &&\r\n typeof config.baseUrl === 'string' &&\r\n typeof config.shareId === 'string' &&\r\n config.baseUrl.length > 0 &&\r\n config.shareId.length > 0\r\n );\r\n}\r\n\r\n// 自定义错误类\r\nexport class UmamiError extends Error {\r\n constructor(message: string, public code?: string) {\r\n super(message);\r\n this.name = 'UmamiError';\r\n }\r\n}","// 通用缓存管理器\r\nexport class CacheManager<T = any> {\r\n private memoryCache = new Map<string, T>();\r\n private readonly CACHE_KEY: string;\r\n private readonly DEFAULT_TTL: number;\r\n\r\n constructor(namespace = 'default', ttl = 3600000) {\r\n this.CACHE_KEY = `cache-${namespace}`;\r\n this.DEFAULT_TTL = ttl;\r\n }\r\n\r\n get(key: string): T | null {\r\n // 内存缓存\r\n if (this.memoryCache.has(key)) {\r\n return this.memoryCache.get(key)!;\r\n }\r\n \r\n // localStorage 缓存\r\n try {\r\n const cached = localStorage.getItem(this.CACHE_KEY);\r\n if (cached) {\r\n const parsed = JSON.parse(cached);\r\n const cachedData = parsed[key];\r\n if (cachedData && Date.now() - cachedData.timestamp < this.DEFAULT_TTL) {\r\n return cachedData.value;\r\n }\r\n }\r\n } catch {\r\n // ignore\r\n }\r\n \r\n return null;\r\n }\r\n\r\n set(key: string, value: T): void {\r\n // 内存缓存\r\n this.memoryCache.set(key, value);\r\n \r\n // localStorage 缓存\r\n try {\r\n const cached = localStorage.getItem(this.CACHE_KEY);\r\n const cacheObj = cached ? JSON.parse(cached) : {};\r\n \r\n cacheObj[key] = {\r\n timestamp: Date.now(),\r\n value: value\r\n };\r\n \r\n localStorage.setItem(this.CACHE_KEY, JSON.stringify(cacheObj));\r\n } catch {\r\n // ignore\r\n }\r\n }\r\n\r\n clear(): void {\r\n this.memoryCache.clear();\r\n try {\r\n localStorage.removeItem(this.CACHE_KEY);\r\n } catch {\r\n // ignore\r\n }\r\n }\r\n\r\n delete(key: string): void {\r\n this.memoryCache.delete(key);\r\n try {\r\n const cached = localStorage.getItem(this.CACHE_KEY);\r\n if (cached) {\r\n const cacheObj = JSON.parse(cached);\r\n delete cacheObj[key];\r\n localStorage.setItem(this.CACHE_KEY, JSON.stringify(cacheObj));\r\n }\r\n } catch {\r\n // ignore\r\n }\r\n }\r\n}","import type { ShareData } from './types';\r\nimport { CacheManager } from '../../utils/umami/cache';\r\n\r\nexport class UmamiAPI {\r\n private cacheManager: CacheManager;\r\n private sharePromise: Promise<ShareData> | null = null;\r\n\r\n constructor(cacheManager: CacheManager) {\r\n this.cacheManager = cacheManager;\r\n }\r\n\r\n async getShareData(baseUrl: string, shareId: string): Promise<ShareData> {\r\n if (!this.sharePromise) {\r\n this.sharePromise = this.fetchShareData(baseUrl, shareId).catch((err) => {\r\n this.sharePromise = null;\r\n throw err;\r\n });\r\n }\r\n return this.sharePromise;\r\n }\r\n\r\n private async fetchShareData(baseUrl: string, shareId: string): Promise<ShareData> {\r\n const res = await fetch(`${baseUrl}/api/share/${shareId}`);\r\n if (!res.ok) {\r\n throw new Error(`获取分享信息失败: ${res.status} ${res.statusText}`);\r\n }\r\n return res.json();\r\n }\r\n\r\n async getStats(baseUrl: string, shareId: string, params: any) {\r\n const cacheKey = `${baseUrl}|${shareId}|${JSON.stringify(params)}`;\r\n \r\n const cached = this.cacheManager.get(cacheKey);\r\n if (cached) {\r\n return { ...cached, _fromCache: true };\r\n }\r\n\r\n const { websiteId, token } = await this.getShareData(baseUrl, shareId);\r\n \r\n const queryParams = new URLSearchParams({\r\n startAt: '0',\r\n endAt: Date.now().toString(),\r\n unit: 'hour',\r\n timezone: params.timezone || 'Asia/Shanghai',\r\n compare: 'false',\r\n ...params\r\n });\r\n\r\n const statsUrl = `${baseUrl}/api/websites/${websiteId}/stats?${queryParams.toString()}`;\r\n \r\n const res = await fetch(statsUrl, {\r\n headers: { 'x-umami-share-token': token }\r\n });\r\n\r\n if (!res.ok) {\r\n if (res.status === 401) {\r\n this.cacheManager.clear();\r\n throw new Error('认证失败,请检查 shareId');\r\n }\r\n throw new Error(`获取统计失败: ${res.status} ${res.statusText}`);\r\n }\r\n\r\n const data = await res.json();\r\n this.cacheManager.set(cacheKey, data);\r\n return data;\r\n }\r\n\r\n clearShareCache(): void {\r\n this.sharePromise = null;\r\n }\r\n}","/**\r\n * 从分享 URL 中提取 baseUrl 和 shareId\r\n * 支持多种 Umami 实例格式:\r\n * - https://umami.example.com/share/abc123\r\n * - https://cloud.umami.is/analytics/us/share/abc123\r\n * - https://umami.example.com/analytics/share/abc123\r\n */\r\nexport function parseShareUrl(shareUrl: string): { baseUrl: string; shareId: string } {\r\n try {\r\n const url = new URL(shareUrl);\r\n \r\n // 提取 baseUrl(协议 + 主机 + 端口)\r\n const baseUrl = `${url.protocol}//${url.host}`;\r\n \r\n // 提取 shareId(/share/ 后面的部分)\r\n const pathParts = url.pathname.split('/');\r\n const shareIndex = pathParts.indexOf('share');\r\n \r\n if (shareIndex === -1 || shareIndex === pathParts.length - 1) {\r\n throw new Error('无效的分享 URL:未找到 share 路径');\r\n }\r\n \r\n const shareId = pathParts[shareIndex + 1];\r\n \r\n if (!shareId || shareId.length < 10) {\r\n throw new Error('无效的分享 ID');\r\n }\r\n \r\n return { baseUrl, shareId };\r\n } catch (error) {\r\n if (error instanceof Error) {\r\n throw new Error(`URL 解析失败: ${error.message}`);\r\n }\r\n throw new Error('URL 解析失败: 无效的 URL 格式');\r\n }\r\n}\r\n\r\n/**\r\n * 验证分享 URL 格式\r\n */\r\nexport function isValidShareUrl(url: string): boolean {\r\n try {\r\n const parsed = new URL(url);\r\n return parsed.pathname.includes('/share/');\r\n } catch {\r\n return false;\r\n }\r\n}","import { CacheManager } from '../../utils/umami/cache';\r\nimport { UmamiAPI } from './api';\r\nimport { parseShareUrl } from '../../utils/umami/url-parser';\r\nimport type { UmamiConfig, StatsResult, StatsQueryParams } from './types';\r\n\r\nexport class UmamiClient {\r\n private config: UmamiConfig;\r\n private cacheManager: CacheManager;\r\n private api: UmamiAPI;\r\n\r\n constructor(config: UmamiConfig) {\r\n // 验证必需参数\r\n if (!config.shareUrl) {\r\n throw new Error('shareUrl 是必需参数');\r\n }\r\n \r\n // 自动解析 shareUrl\r\n const { baseUrl, shareId } = parseShareUrl(config.shareUrl);\r\n \r\n this.config = {\r\n timezone: 'Asia/Shanghai',\r\n enableCache: true,\r\n cacheTTL: 3600000,\r\n baseUrl,\r\n shareId,\r\n ...config\r\n };\r\n \r\n this.cacheManager = new CacheManager('umami', this.config.cacheTTL);\r\n this.api = new UmamiAPI(this.cacheManager);\r\n }\r\n\r\n async getPageStats(\r\n path: string, \r\n options: Partial<StatsQueryParams> = {}\r\n ): Promise<StatsResult> {\r\n if (!this.config.baseUrl || !this.config.shareId) {\r\n throw new Error('客户端未正确初始化');\r\n }\r\n \r\n const data = await this.api.getStats(this.config.baseUrl, this.config.shareId, {\r\n path: `eq.${path}`,\r\n timezone: this.config.timezone,\r\n ...options\r\n });\r\n \r\n return {\r\n pageviews: (data.pageviews?.value) || data.pageviews || 0,\r\n visitors: (data.visitors?.value) || data.visitors || 0,\r\n _fromCache: data._fromCache\r\n };\r\n }\r\n\r\n async getPageStatsByUrl(\r\n url: string,\r\n options: Partial<StatsQueryParams> = {}\r\n ): Promise<StatsResult> {\r\n if (!this.config.baseUrl || !this.config.shareId) {\r\n throw new Error('客户端未正确初始化');\r\n }\r\n \r\n const data = await this.api.getStats(this.config.baseUrl, this.config.shareId, {\r\n url: url,\r\n timezone: this.config.timezone,\r\n ...options\r\n });\r\n \r\n return {\r\n pageviews: (data.pageviews?.value) || data.pageviews || 0,\r\n visitors: (data.visitors?.value) || data.visitors || 0,\r\n _fromCache: data._fromCache\r\n };\r\n }\r\n\r\n async getSiteStats(options: Partial<StatsQueryParams> = {}): Promise<StatsResult> {\r\n if (!this.config.baseUrl || !this.config.shareId) {\r\n throw new Error('客户端未正确初始化');\r\n }\r\n \r\n const data = await this.api.getStats(this.config.baseUrl, this.config.shareId, {\r\n timezone: this.config.timezone,\r\n ...options\r\n });\r\n \r\n return {\r\n pageviews: data.pageviews || 0,\r\n visitors: data.visitors || 0,\r\n _fromCache: data._fromCache\r\n };\r\n }\r\n\r\n clearCache(): void {\r\n this.cacheManager.clear();\r\n this.api.clearShareCache();\r\n }\r\n\r\n getConfig(): Readonly<UmamiConfig> {\r\n return { ...this.config };\r\n }\r\n\r\n updateConfig(newConfig: Partial<UmamiConfig>): void {\r\n this.config = { ...this.config, ...newConfig };\r\n }\r\n}\r\n\r\nexport function createUmamiClient(config: UmamiConfig): UmamiClient {\r\n return new UmamiClient(config);\r\n}\r\n\r\n// 兼容旧版本\r\nif (typeof window !== 'undefined') {\r\n (window as any).UmamiClient = UmamiClient;\r\n (window as any).createUmamiClient = createUmamiClient;\r\n}","// Astro 集成配置\r\nexport interface UmamiIntegrationOptions {\r\n shareUrl: string; // Umami 分享链接\r\n timezone?: string; // 时区,默认 'Asia/Shanghai'\r\n enableCache?: boolean; // 启用缓存,默认 true\r\n cacheTTL?: number; // 缓存时间,单位毫秒\r\n}\r\n\r\n// Astro 集成函数\r\nexport function umami(options: UmamiIntegrationOptions) {\r\n if (!options.shareUrl) {\r\n throw new Error('需要配置 shareUrl');\r\n }\r\n\r\n return {\r\n name: 'astro-umami-integration',\r\n hooks: {\r\n 'astro:config:setup': ({ injectScript }: any) => {\r\n const config = {\r\n shareUrl: options.shareUrl,\r\n timezone: options.timezone || 'Asia/Shanghai',\r\n enableCache: options.enableCache !== false,\r\n cacheTTL: options.cacheTTL || 3600000\r\n };\r\n\r\n // 注入全局统计客户端\r\n injectScript('page', `\r\n import { createUmamiClient } from 'oddmisc';\r\n \r\n // 创建命名空间避免冲突\r\n window.oddmisc = window.oddmisc || {};\r\n window.oddmisc.umami = createUmamiClient(${JSON.stringify(config)});\r\n \r\n // 命名空间下的快捷方法\r\n window.oddmisc.getStats = (path) => window.oddmisc.umami.getPageStats(path);\r\n window.oddmisc.getSiteStats = () => window.oddmisc.umami.getSiteStats();\r\n `);\r\n }\r\n }\r\n };\r\n}"],"mappings":"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","names":["index_exports","__export","CacheManager","DEFAULT_CONFIG","UmamiClient","UmamiError","VERSION","createUmamiClient","isValidConfig","isValidShareUrl","parseShareUrl","umami","__toCommonJS","VERSION","DEFAULT_CONFIG","isValidConfig","config","UmamiError","message","code","CacheManager","namespace","ttl","key","cached","cachedData","value","cacheObj","UmamiAPI","cacheManager","baseUrl","shareId","err","res","params","cacheKey","cached","websiteId","token","queryParams","statsUrl","data","parseShareUrl","shareUrl","url","baseUrl","pathParts","shareIndex","shareId","error","isValidShareUrl","UmamiClient","config","baseUrl","shareId","parseShareUrl","CacheManager","UmamiAPI","path","options","data","url","newConfig","createUmamiClient","umami","options","injectScript","config"]}
|
package/dist/index.d.cts
ADDED
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
declare const VERSION = "1.0.0";
|
|
2
|
+
declare const DEFAULT_CONFIG: {
|
|
3
|
+
readonly timezone: "Asia/Shanghai";
|
|
4
|
+
readonly enableCache: true;
|
|
5
|
+
readonly cacheTTL: 3600000;
|
|
6
|
+
};
|
|
7
|
+
declare function isValidConfig(config: any): boolean;
|
|
8
|
+
declare class UmamiError extends Error {
|
|
9
|
+
code?: string | undefined;
|
|
10
|
+
constructor(message: string, code?: string | undefined);
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
interface UmamiConfig {
|
|
14
|
+
/** 分享 URL,如: https://umami.example.com/share/abc123 */
|
|
15
|
+
shareUrl: string;
|
|
16
|
+
/** 时区,默认 'Asia/Shanghai' */
|
|
17
|
+
timezone?: string;
|
|
18
|
+
/** 是否启用缓存,默认 true */
|
|
19
|
+
enableCache?: boolean;
|
|
20
|
+
/** 缓存过期时间(毫秒),默认 1小时 */
|
|
21
|
+
cacheTTL?: number;
|
|
22
|
+
baseUrl?: string;
|
|
23
|
+
shareId?: string;
|
|
24
|
+
}
|
|
25
|
+
interface StatsQueryParams {
|
|
26
|
+
path?: string;
|
|
27
|
+
url?: string;
|
|
28
|
+
startAt?: number;
|
|
29
|
+
endAt?: number;
|
|
30
|
+
unit?: 'hour' | 'day' | 'month' | 'year';
|
|
31
|
+
timezone?: string;
|
|
32
|
+
compare?: boolean;
|
|
33
|
+
}
|
|
34
|
+
interface StatsResult {
|
|
35
|
+
pageviews: number;
|
|
36
|
+
visitors: number;
|
|
37
|
+
_fromCache?: boolean;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
declare class UmamiClient {
|
|
41
|
+
private config;
|
|
42
|
+
private cacheManager;
|
|
43
|
+
private api;
|
|
44
|
+
constructor(config: UmamiConfig);
|
|
45
|
+
getPageStats(path: string, options?: Partial<StatsQueryParams>): Promise<StatsResult>;
|
|
46
|
+
getPageStatsByUrl(url: string, options?: Partial<StatsQueryParams>): Promise<StatsResult>;
|
|
47
|
+
getSiteStats(options?: Partial<StatsQueryParams>): Promise<StatsResult>;
|
|
48
|
+
clearCache(): void;
|
|
49
|
+
getConfig(): Readonly<UmamiConfig>;
|
|
50
|
+
updateConfig(newConfig: Partial<UmamiConfig>): void;
|
|
51
|
+
}
|
|
52
|
+
declare function createUmamiClient(config: UmamiConfig): UmamiClient;
|
|
53
|
+
|
|
54
|
+
declare class CacheManager<T = any> {
|
|
55
|
+
private memoryCache;
|
|
56
|
+
private readonly CACHE_KEY;
|
|
57
|
+
private readonly DEFAULT_TTL;
|
|
58
|
+
constructor(namespace?: string, ttl?: number);
|
|
59
|
+
get(key: string): T | null;
|
|
60
|
+
set(key: string, value: T): void;
|
|
61
|
+
clear(): void;
|
|
62
|
+
delete(key: string): void;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
/**
|
|
66
|
+
* 从分享 URL 中提取 baseUrl 和 shareId
|
|
67
|
+
* 支持多种 Umami 实例格式:
|
|
68
|
+
* - https://umami.example.com/share/abc123
|
|
69
|
+
* - https://cloud.umami.is/analytics/us/share/abc123
|
|
70
|
+
* - https://umami.example.com/analytics/share/abc123
|
|
71
|
+
*/
|
|
72
|
+
declare function parseShareUrl(shareUrl: string): {
|
|
73
|
+
baseUrl: string;
|
|
74
|
+
shareId: string;
|
|
75
|
+
};
|
|
76
|
+
/**
|
|
77
|
+
* 验证分享 URL 格式
|
|
78
|
+
*/
|
|
79
|
+
declare function isValidShareUrl(url: string): boolean;
|
|
80
|
+
|
|
81
|
+
interface UmamiIntegrationOptions {
|
|
82
|
+
shareUrl: string;
|
|
83
|
+
timezone?: string;
|
|
84
|
+
enableCache?: boolean;
|
|
85
|
+
cacheTTL?: number;
|
|
86
|
+
}
|
|
87
|
+
declare function umami(options: UmamiIntegrationOptions): {
|
|
88
|
+
name: string;
|
|
89
|
+
hooks: {
|
|
90
|
+
'astro:config:setup': ({ injectScript }: any) => void;
|
|
91
|
+
};
|
|
92
|
+
};
|
|
93
|
+
|
|
94
|
+
export { CacheManager, DEFAULT_CONFIG, type StatsQueryParams, type StatsResult, UmamiClient, type UmamiConfig, UmamiError, type UmamiIntegrationOptions, VERSION, createUmamiClient, isValidConfig, isValidShareUrl, parseShareUrl, umami };
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
declare const VERSION = "1.0.0";
|
|
2
|
+
declare const DEFAULT_CONFIG: {
|
|
3
|
+
readonly timezone: "Asia/Shanghai";
|
|
4
|
+
readonly enableCache: true;
|
|
5
|
+
readonly cacheTTL: 3600000;
|
|
6
|
+
};
|
|
7
|
+
declare function isValidConfig(config: any): boolean;
|
|
8
|
+
declare class UmamiError extends Error {
|
|
9
|
+
code?: string | undefined;
|
|
10
|
+
constructor(message: string, code?: string | undefined);
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
interface UmamiConfig {
|
|
14
|
+
/** 分享 URL,如: https://umami.example.com/share/abc123 */
|
|
15
|
+
shareUrl: string;
|
|
16
|
+
/** 时区,默认 'Asia/Shanghai' */
|
|
17
|
+
timezone?: string;
|
|
18
|
+
/** 是否启用缓存,默认 true */
|
|
19
|
+
enableCache?: boolean;
|
|
20
|
+
/** 缓存过期时间(毫秒),默认 1小时 */
|
|
21
|
+
cacheTTL?: number;
|
|
22
|
+
baseUrl?: string;
|
|
23
|
+
shareId?: string;
|
|
24
|
+
}
|
|
25
|
+
interface StatsQueryParams {
|
|
26
|
+
path?: string;
|
|
27
|
+
url?: string;
|
|
28
|
+
startAt?: number;
|
|
29
|
+
endAt?: number;
|
|
30
|
+
unit?: 'hour' | 'day' | 'month' | 'year';
|
|
31
|
+
timezone?: string;
|
|
32
|
+
compare?: boolean;
|
|
33
|
+
}
|
|
34
|
+
interface StatsResult {
|
|
35
|
+
pageviews: number;
|
|
36
|
+
visitors: number;
|
|
37
|
+
_fromCache?: boolean;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
declare class UmamiClient {
|
|
41
|
+
private config;
|
|
42
|
+
private cacheManager;
|
|
43
|
+
private api;
|
|
44
|
+
constructor(config: UmamiConfig);
|
|
45
|
+
getPageStats(path: string, options?: Partial<StatsQueryParams>): Promise<StatsResult>;
|
|
46
|
+
getPageStatsByUrl(url: string, options?: Partial<StatsQueryParams>): Promise<StatsResult>;
|
|
47
|
+
getSiteStats(options?: Partial<StatsQueryParams>): Promise<StatsResult>;
|
|
48
|
+
clearCache(): void;
|
|
49
|
+
getConfig(): Readonly<UmamiConfig>;
|
|
50
|
+
updateConfig(newConfig: Partial<UmamiConfig>): void;
|
|
51
|
+
}
|
|
52
|
+
declare function createUmamiClient(config: UmamiConfig): UmamiClient;
|
|
53
|
+
|
|
54
|
+
declare class CacheManager<T = any> {
|
|
55
|
+
private memoryCache;
|
|
56
|
+
private readonly CACHE_KEY;
|
|
57
|
+
private readonly DEFAULT_TTL;
|
|
58
|
+
constructor(namespace?: string, ttl?: number);
|
|
59
|
+
get(key: string): T | null;
|
|
60
|
+
set(key: string, value: T): void;
|
|
61
|
+
clear(): void;
|
|
62
|
+
delete(key: string): void;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
/**
|
|
66
|
+
* 从分享 URL 中提取 baseUrl 和 shareId
|
|
67
|
+
* 支持多种 Umami 实例格式:
|
|
68
|
+
* - https://umami.example.com/share/abc123
|
|
69
|
+
* - https://cloud.umami.is/analytics/us/share/abc123
|
|
70
|
+
* - https://umami.example.com/analytics/share/abc123
|
|
71
|
+
*/
|
|
72
|
+
declare function parseShareUrl(shareUrl: string): {
|
|
73
|
+
baseUrl: string;
|
|
74
|
+
shareId: string;
|
|
75
|
+
};
|
|
76
|
+
/**
|
|
77
|
+
* 验证分享 URL 格式
|
|
78
|
+
*/
|
|
79
|
+
declare function isValidShareUrl(url: string): boolean;
|
|
80
|
+
|
|
81
|
+
interface UmamiIntegrationOptions {
|
|
82
|
+
shareUrl: string;
|
|
83
|
+
timezone?: string;
|
|
84
|
+
enableCache?: boolean;
|
|
85
|
+
cacheTTL?: number;
|
|
86
|
+
}
|
|
87
|
+
declare function umami(options: UmamiIntegrationOptions): {
|
|
88
|
+
name: string;
|
|
89
|
+
hooks: {
|
|
90
|
+
'astro:config:setup': ({ injectScript }: any) => void;
|
|
91
|
+
};
|
|
92
|
+
};
|
|
93
|
+
|
|
94
|
+
export { CacheManager, DEFAULT_CONFIG, type StatsQueryParams, type StatsResult, UmamiClient, type UmamiConfig, UmamiError, type UmamiIntegrationOptions, VERSION, createUmamiClient, isValidConfig, isValidShareUrl, parseShareUrl, umami };
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
var S="1.0.0",U={timezone:"Asia/Shanghai",enableCache:!0,cacheTTL:36e5};function y(r){return typeof r=="object"&&r!==null&&typeof r.baseUrl=="string"&&typeof r.shareId=="string"&&r.baseUrl.length>0&&r.shareId.length>0}var m=class extends Error{constructor(a,t){super(a);this.code=t;this.name="UmamiError"}};var n=class{constructor(e="default",a=36e5){this.memoryCache=new Map;this.CACHE_KEY=`cache-${e}`,this.DEFAULT_TTL=a}get(e){if(this.memoryCache.has(e))return this.memoryCache.get(e);try{let a=localStorage.getItem(this.CACHE_KEY);if(a){let i=JSON.parse(a)[e];if(i&&Date.now()-i.timestamp<this.DEFAULT_TTL)return i.value}}catch{}return null}set(e,a){this.memoryCache.set(e,a);try{let t=localStorage.getItem(this.CACHE_KEY),i=t?JSON.parse(t):{};i[e]={timestamp:Date.now(),value:a},localStorage.setItem(this.CACHE_KEY,JSON.stringify(i))}catch{}}clear(){this.memoryCache.clear();try{localStorage.removeItem(this.CACHE_KEY)}catch{}}delete(e){this.memoryCache.delete(e);try{let a=localStorage.getItem(this.CACHE_KEY);if(a){let t=JSON.parse(a);delete t[e],localStorage.setItem(this.CACHE_KEY,JSON.stringify(t))}}catch{}}};var c=class{constructor(e){this.sharePromise=null;this.cacheManager=e}async getShareData(e,a){return this.sharePromise||(this.sharePromise=this.fetchShareData(e,a).catch(t=>{throw this.sharePromise=null,t})),this.sharePromise}async fetchShareData(e,a){let t=await fetch(`${e}/api/share/${a}`);if(!t.ok)throw new Error(`\u83B7\u53D6\u5206\u4EAB\u4FE1\u606F\u5931\u8D25: ${t.status} ${t.statusText}`);return t.json()}async getStats(e,a,t){let i=`${e}|${a}|${JSON.stringify(t)}`,s=this.cacheManager.get(i);if(s)return{...s,_fromCache:!0};let{websiteId:u,token:d}=await this.getShareData(e,a),w=new URLSearchParams({startAt:"0",endAt:Date.now().toString(),unit:"hour",timezone:t.timezone||"Asia/Shanghai",compare:"false",...t}),C=`${e}/api/websites/${u}/stats?${w.toString()}`,o=await fetch(C,{headers:{"x-umami-share-token":d}});if(!o.ok)throw o.status===401?(this.cacheManager.clear(),new Error("\u8BA4\u8BC1\u5931\u8D25\uFF0C\u8BF7\u68C0\u67E5 shareId")):new Error(`\u83B7\u53D6\u7EDF\u8BA1\u5931\u8D25: ${o.status} ${o.statusText}`);let l=await o.json();return this.cacheManager.set(i,l),l}clearShareCache(){this.sharePromise=null}};function g(r){try{let e=new URL(r),a=`${e.protocol}//${e.host}`,t=e.pathname.split("/"),i=t.indexOf("share");if(i===-1||i===t.length-1)throw new Error("\u65E0\u6548\u7684\u5206\u4EAB URL\uFF1A\u672A\u627E\u5230 share \u8DEF\u5F84");let s=t[i+1];if(!s||s.length<10)throw new Error("\u65E0\u6548\u7684\u5206\u4EAB ID");return{baseUrl:a,shareId:s}}catch(e){throw e instanceof Error?new Error(`URL \u89E3\u6790\u5931\u8D25: ${e.message}`):new Error("URL \u89E3\u6790\u5931\u8D25: \u65E0\u6548\u7684 URL \u683C\u5F0F")}}function E(r){try{return new URL(r).pathname.includes("/share/")}catch{return!1}}var h=class{constructor(e){if(!e.shareUrl)throw new Error("shareUrl \u662F\u5FC5\u9700\u53C2\u6570");let{baseUrl:a,shareId:t}=g(e.shareUrl);this.config={timezone:"Asia/Shanghai",enableCache:!0,cacheTTL:36e5,baseUrl:a,shareId:t,...e},this.cacheManager=new n("umami",this.config.cacheTTL),this.api=new c(this.cacheManager)}async getPageStats(e,a={}){if(!this.config.baseUrl||!this.config.shareId)throw new Error("\u5BA2\u6237\u7AEF\u672A\u6B63\u786E\u521D\u59CB\u5316");let t=await this.api.getStats(this.config.baseUrl,this.config.shareId,{path:`eq.${e}`,timezone:this.config.timezone,...a});return{pageviews:t.pageviews?.value||t.pageviews||0,visitors:t.visitors?.value||t.visitors||0,_fromCache:t._fromCache}}async getPageStatsByUrl(e,a={}){if(!this.config.baseUrl||!this.config.shareId)throw new Error("\u5BA2\u6237\u7AEF\u672A\u6B63\u786E\u521D\u59CB\u5316");let t=await this.api.getStats(this.config.baseUrl,this.config.shareId,{url:e,timezone:this.config.timezone,...a});return{pageviews:t.pageviews?.value||t.pageviews||0,visitors:t.visitors?.value||t.visitors||0,_fromCache:t._fromCache}}async getSiteStats(e={}){if(!this.config.baseUrl||!this.config.shareId)throw new Error("\u5BA2\u6237\u7AEF\u672A\u6B63\u786E\u521D\u59CB\u5316");let a=await this.api.getStats(this.config.baseUrl,this.config.shareId,{timezone:this.config.timezone,...e});return{pageviews:a.pageviews||0,visitors:a.visitors||0,_fromCache:a._fromCache}}clearCache(){this.cacheManager.clear(),this.api.clearShareCache()}getConfig(){return{...this.config}}updateConfig(e){this.config={...this.config,...e}}};function f(r){return new h(r)}typeof window<"u"&&(window.UmamiClient=h,window.createUmamiClient=f);function p(r){if(!r.shareUrl)throw new Error("\u9700\u8981\u914D\u7F6E shareUrl");return{name:"astro-umami-integration",hooks:{"astro:config:setup":({injectScript:e})=>{let a={shareUrl:r.shareUrl,timezone:r.timezone||"Asia/Shanghai",enableCache:r.enableCache!==!1,cacheTTL:r.cacheTTL||36e5};e("page",`
|
|
2
|
+
import { createUmamiClient } from 'oddmisc';
|
|
3
|
+
|
|
4
|
+
// \u521B\u5EFA\u547D\u540D\u7A7A\u95F4\u907F\u514D\u51B2\u7A81
|
|
5
|
+
window.oddmisc = window.oddmisc || {};
|
|
6
|
+
window.oddmisc.umami = createUmamiClient(${JSON.stringify(a)});
|
|
7
|
+
|
|
8
|
+
// \u547D\u540D\u7A7A\u95F4\u4E0B\u7684\u5FEB\u6377\u65B9\u6CD5
|
|
9
|
+
window.oddmisc.getStats = (path) => window.oddmisc.umami.getPageStats(path);
|
|
10
|
+
window.oddmisc.getSiteStats = () => window.oddmisc.umami.getSiteStats();
|
|
11
|
+
`)}}}}export{n as CacheManager,U as DEFAULT_CONFIG,h as UmamiClient,m as UmamiError,S as VERSION,f as createUmamiClient,y as isValidConfig,E as isValidShareUrl,g as parseShareUrl,p as umami};
|
|
12
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/shared/index.ts","../src/utils/umami/cache.ts","../src/modules/umami/api.ts","../src/utils/umami/url-parser.ts","../src/modules/umami/client.ts","../src/astro/integration.ts"],"sourcesContent":["// 版本信息\r\nexport const VERSION = '1.0.0';\r\n\r\n// 默认配置\r\nexport const DEFAULT_CONFIG = {\r\n timezone: 'Asia/Shanghai',\r\n enableCache: true,\r\n cacheTTL: 3600000\r\n} as const;\r\n\r\n// 配置验证\r\nexport function isValidConfig(config: any): boolean {\r\n return (\r\n typeof config === 'object' &&\r\n config !== null &&\r\n typeof config.baseUrl === 'string' &&\r\n typeof config.shareId === 'string' &&\r\n config.baseUrl.length > 0 &&\r\n config.shareId.length > 0\r\n );\r\n}\r\n\r\n// 自定义错误类\r\nexport class UmamiError extends Error {\r\n constructor(message: string, public code?: string) {\r\n super(message);\r\n this.name = 'UmamiError';\r\n }\r\n}","// 通用缓存管理器\r\nexport class CacheManager<T = any> {\r\n private memoryCache = new Map<string, T>();\r\n private readonly CACHE_KEY: string;\r\n private readonly DEFAULT_TTL: number;\r\n\r\n constructor(namespace = 'default', ttl = 3600000) {\r\n this.CACHE_KEY = `cache-${namespace}`;\r\n this.DEFAULT_TTL = ttl;\r\n }\r\n\r\n get(key: string): T | null {\r\n // 内存缓存\r\n if (this.memoryCache.has(key)) {\r\n return this.memoryCache.get(key)!;\r\n }\r\n \r\n // localStorage 缓存\r\n try {\r\n const cached = localStorage.getItem(this.CACHE_KEY);\r\n if (cached) {\r\n const parsed = JSON.parse(cached);\r\n const cachedData = parsed[key];\r\n if (cachedData && Date.now() - cachedData.timestamp < this.DEFAULT_TTL) {\r\n return cachedData.value;\r\n }\r\n }\r\n } catch {\r\n // ignore\r\n }\r\n \r\n return null;\r\n }\r\n\r\n set(key: string, value: T): void {\r\n // 内存缓存\r\n this.memoryCache.set(key, value);\r\n \r\n // localStorage 缓存\r\n try {\r\n const cached = localStorage.getItem(this.CACHE_KEY);\r\n const cacheObj = cached ? JSON.parse(cached) : {};\r\n \r\n cacheObj[key] = {\r\n timestamp: Date.now(),\r\n value: value\r\n };\r\n \r\n localStorage.setItem(this.CACHE_KEY, JSON.stringify(cacheObj));\r\n } catch {\r\n // ignore\r\n }\r\n }\r\n\r\n clear(): void {\r\n this.memoryCache.clear();\r\n try {\r\n localStorage.removeItem(this.CACHE_KEY);\r\n } catch {\r\n // ignore\r\n }\r\n }\r\n\r\n delete(key: string): void {\r\n this.memoryCache.delete(key);\r\n try {\r\n const cached = localStorage.getItem(this.CACHE_KEY);\r\n if (cached) {\r\n const cacheObj = JSON.parse(cached);\r\n delete cacheObj[key];\r\n localStorage.setItem(this.CACHE_KEY, JSON.stringify(cacheObj));\r\n }\r\n } catch {\r\n // ignore\r\n }\r\n }\r\n}","import type { ShareData } from './types';\r\nimport { CacheManager } from '../../utils/umami/cache';\r\n\r\nexport class UmamiAPI {\r\n private cacheManager: CacheManager;\r\n private sharePromise: Promise<ShareData> | null = null;\r\n\r\n constructor(cacheManager: CacheManager) {\r\n this.cacheManager = cacheManager;\r\n }\r\n\r\n async getShareData(baseUrl: string, shareId: string): Promise<ShareData> {\r\n if (!this.sharePromise) {\r\n this.sharePromise = this.fetchShareData(baseUrl, shareId).catch((err) => {\r\n this.sharePromise = null;\r\n throw err;\r\n });\r\n }\r\n return this.sharePromise;\r\n }\r\n\r\n private async fetchShareData(baseUrl: string, shareId: string): Promise<ShareData> {\r\n const res = await fetch(`${baseUrl}/api/share/${shareId}`);\r\n if (!res.ok) {\r\n throw new Error(`获取分享信息失败: ${res.status} ${res.statusText}`);\r\n }\r\n return res.json();\r\n }\r\n\r\n async getStats(baseUrl: string, shareId: string, params: any) {\r\n const cacheKey = `${baseUrl}|${shareId}|${JSON.stringify(params)}`;\r\n \r\n const cached = this.cacheManager.get(cacheKey);\r\n if (cached) {\r\n return { ...cached, _fromCache: true };\r\n }\r\n\r\n const { websiteId, token } = await this.getShareData(baseUrl, shareId);\r\n \r\n const queryParams = new URLSearchParams({\r\n startAt: '0',\r\n endAt: Date.now().toString(),\r\n unit: 'hour',\r\n timezone: params.timezone || 'Asia/Shanghai',\r\n compare: 'false',\r\n ...params\r\n });\r\n\r\n const statsUrl = `${baseUrl}/api/websites/${websiteId}/stats?${queryParams.toString()}`;\r\n \r\n const res = await fetch(statsUrl, {\r\n headers: { 'x-umami-share-token': token }\r\n });\r\n\r\n if (!res.ok) {\r\n if (res.status === 401) {\r\n this.cacheManager.clear();\r\n throw new Error('认证失败,请检查 shareId');\r\n }\r\n throw new Error(`获取统计失败: ${res.status} ${res.statusText}`);\r\n }\r\n\r\n const data = await res.json();\r\n this.cacheManager.set(cacheKey, data);\r\n return data;\r\n }\r\n\r\n clearShareCache(): void {\r\n this.sharePromise = null;\r\n }\r\n}","/**\r\n * 从分享 URL 中提取 baseUrl 和 shareId\r\n * 支持多种 Umami 实例格式:\r\n * - https://umami.example.com/share/abc123\r\n * - https://cloud.umami.is/analytics/us/share/abc123\r\n * - https://umami.example.com/analytics/share/abc123\r\n */\r\nexport function parseShareUrl(shareUrl: string): { baseUrl: string; shareId: string } {\r\n try {\r\n const url = new URL(shareUrl);\r\n \r\n // 提取 baseUrl(协议 + 主机 + 端口)\r\n const baseUrl = `${url.protocol}//${url.host}`;\r\n \r\n // 提取 shareId(/share/ 后面的部分)\r\n const pathParts = url.pathname.split('/');\r\n const shareIndex = pathParts.indexOf('share');\r\n \r\n if (shareIndex === -1 || shareIndex === pathParts.length - 1) {\r\n throw new Error('无效的分享 URL:未找到 share 路径');\r\n }\r\n \r\n const shareId = pathParts[shareIndex + 1];\r\n \r\n if (!shareId || shareId.length < 10) {\r\n throw new Error('无效的分享 ID');\r\n }\r\n \r\n return { baseUrl, shareId };\r\n } catch (error) {\r\n if (error instanceof Error) {\r\n throw new Error(`URL 解析失败: ${error.message}`);\r\n }\r\n throw new Error('URL 解析失败: 无效的 URL 格式');\r\n }\r\n}\r\n\r\n/**\r\n * 验证分享 URL 格式\r\n */\r\nexport function isValidShareUrl(url: string): boolean {\r\n try {\r\n const parsed = new URL(url);\r\n return parsed.pathname.includes('/share/');\r\n } catch {\r\n return false;\r\n }\r\n}","import { CacheManager } from '../../utils/umami/cache';\r\nimport { UmamiAPI } from './api';\r\nimport { parseShareUrl } from '../../utils/umami/url-parser';\r\nimport type { UmamiConfig, StatsResult, StatsQueryParams } from './types';\r\n\r\nexport class UmamiClient {\r\n private config: UmamiConfig;\r\n private cacheManager: CacheManager;\r\n private api: UmamiAPI;\r\n\r\n constructor(config: UmamiConfig) {\r\n // 验证必需参数\r\n if (!config.shareUrl) {\r\n throw new Error('shareUrl 是必需参数');\r\n }\r\n \r\n // 自动解析 shareUrl\r\n const { baseUrl, shareId } = parseShareUrl(config.shareUrl);\r\n \r\n this.config = {\r\n timezone: 'Asia/Shanghai',\r\n enableCache: true,\r\n cacheTTL: 3600000,\r\n baseUrl,\r\n shareId,\r\n ...config\r\n };\r\n \r\n this.cacheManager = new CacheManager('umami', this.config.cacheTTL);\r\n this.api = new UmamiAPI(this.cacheManager);\r\n }\r\n\r\n async getPageStats(\r\n path: string, \r\n options: Partial<StatsQueryParams> = {}\r\n ): Promise<StatsResult> {\r\n if (!this.config.baseUrl || !this.config.shareId) {\r\n throw new Error('客户端未正确初始化');\r\n }\r\n \r\n const data = await this.api.getStats(this.config.baseUrl, this.config.shareId, {\r\n path: `eq.${path}`,\r\n timezone: this.config.timezone,\r\n ...options\r\n });\r\n \r\n return {\r\n pageviews: (data.pageviews?.value) || data.pageviews || 0,\r\n visitors: (data.visitors?.value) || data.visitors || 0,\r\n _fromCache: data._fromCache\r\n };\r\n }\r\n\r\n async getPageStatsByUrl(\r\n url: string,\r\n options: Partial<StatsQueryParams> = {}\r\n ): Promise<StatsResult> {\r\n if (!this.config.baseUrl || !this.config.shareId) {\r\n throw new Error('客户端未正确初始化');\r\n }\r\n \r\n const data = await this.api.getStats(this.config.baseUrl, this.config.shareId, {\r\n url: url,\r\n timezone: this.config.timezone,\r\n ...options\r\n });\r\n \r\n return {\r\n pageviews: (data.pageviews?.value) || data.pageviews || 0,\r\n visitors: (data.visitors?.value) || data.visitors || 0,\r\n _fromCache: data._fromCache\r\n };\r\n }\r\n\r\n async getSiteStats(options: Partial<StatsQueryParams> = {}): Promise<StatsResult> {\r\n if (!this.config.baseUrl || !this.config.shareId) {\r\n throw new Error('客户端未正确初始化');\r\n }\r\n \r\n const data = await this.api.getStats(this.config.baseUrl, this.config.shareId, {\r\n timezone: this.config.timezone,\r\n ...options\r\n });\r\n \r\n return {\r\n pageviews: data.pageviews || 0,\r\n visitors: data.visitors || 0,\r\n _fromCache: data._fromCache\r\n };\r\n }\r\n\r\n clearCache(): void {\r\n this.cacheManager.clear();\r\n this.api.clearShareCache();\r\n }\r\n\r\n getConfig(): Readonly<UmamiConfig> {\r\n return { ...this.config };\r\n }\r\n\r\n updateConfig(newConfig: Partial<UmamiConfig>): void {\r\n this.config = { ...this.config, ...newConfig };\r\n }\r\n}\r\n\r\nexport function createUmamiClient(config: UmamiConfig): UmamiClient {\r\n return new UmamiClient(config);\r\n}\r\n\r\n// 兼容旧版本\r\nif (typeof window !== 'undefined') {\r\n (window as any).UmamiClient = UmamiClient;\r\n (window as any).createUmamiClient = createUmamiClient;\r\n}","// Astro 集成配置\r\nexport interface UmamiIntegrationOptions {\r\n shareUrl: string; // Umami 分享链接\r\n timezone?: string; // 时区,默认 'Asia/Shanghai'\r\n enableCache?: boolean; // 启用缓存,默认 true\r\n cacheTTL?: number; // 缓存时间,单位毫秒\r\n}\r\n\r\n// Astro 集成函数\r\nexport function umami(options: UmamiIntegrationOptions) {\r\n if (!options.shareUrl) {\r\n throw new Error('需要配置 shareUrl');\r\n }\r\n\r\n return {\r\n name: 'astro-umami-integration',\r\n hooks: {\r\n 'astro:config:setup': ({ injectScript }: any) => {\r\n const config = {\r\n shareUrl: options.shareUrl,\r\n timezone: options.timezone || 'Asia/Shanghai',\r\n enableCache: options.enableCache !== false,\r\n cacheTTL: options.cacheTTL || 3600000\r\n };\r\n\r\n // 注入全局统计客户端\r\n injectScript('page', `\r\n import { createUmamiClient } from 'oddmisc';\r\n \r\n // 创建命名空间避免冲突\r\n window.oddmisc = window.oddmisc || {};\r\n window.oddmisc.umami = createUmamiClient(${JSON.stringify(config)});\r\n \r\n // 命名空间下的快捷方法\r\n window.oddmisc.getStats = (path) => window.oddmisc.umami.getPageStats(path);\r\n window.oddmisc.getSiteStats = () => window.oddmisc.umami.getSiteStats();\r\n `);\r\n }\r\n }\r\n };\r\n}"],"mappings":"AACO,IAAMA,EAAU,QAGVC,EAAiB,CAC5B,SAAU,gBACV,YAAa,GACb,SAAU,IACZ,EAGO,SAASC,EAAcC,EAAsB,CAClD,OACE,OAAOA,GAAW,UAClBA,IAAW,MACX,OAAOA,EAAO,SAAY,UAC1B,OAAOA,EAAO,SAAY,UAC1BA,EAAO,QAAQ,OAAS,GACxBA,EAAO,QAAQ,OAAS,CAE5B,CAGO,IAAMC,EAAN,cAAyB,KAAM,CACpC,YAAYC,EAAwBC,EAAe,CACjD,MAAMD,CAAO,EADqB,UAAAC,EAElC,KAAK,KAAO,YACd,CACF,EC3BO,IAAMC,EAAN,KAA4B,CAKjC,YAAYC,EAAY,UAAWC,EAAM,KAAS,CAJlD,KAAQ,YAAc,IAAI,IAKxB,KAAK,UAAY,SAASD,CAAS,GACnC,KAAK,YAAcC,CACrB,CAEA,IAAIC,EAAuB,CAEzB,GAAI,KAAK,YAAY,IAAIA,CAAG,EAC1B,OAAO,KAAK,YAAY,IAAIA,CAAG,EAIjC,GAAI,CACF,IAAMC,EAAS,aAAa,QAAQ,KAAK,SAAS,EAClD,GAAIA,EAAQ,CAEV,IAAMC,EADS,KAAK,MAAMD,CAAM,EACND,CAAG,EAC7B,GAAIE,GAAc,KAAK,IAAI,EAAIA,EAAW,UAAY,KAAK,YACzD,OAAOA,EAAW,KAEtB,CACF,MAAQ,CAER,CAEA,OAAO,IACT,CAEA,IAAIF,EAAaG,EAAgB,CAE/B,KAAK,YAAY,IAAIH,EAAKG,CAAK,EAG/B,GAAI,CACF,IAAMF,EAAS,aAAa,QAAQ,KAAK,SAAS,EAC5CG,EAAWH,EAAS,KAAK,MAAMA,CAAM,EAAI,CAAC,EAEhDG,EAASJ,CAAG,EAAI,CACd,UAAW,KAAK,IAAI,EACpB,MAAOG,CACT,EAEA,aAAa,QAAQ,KAAK,UAAW,KAAK,UAAUC,CAAQ,CAAC,CAC/D,MAAQ,CAER,CACF,CAEA,OAAc,CACZ,KAAK,YAAY,MAAM,EACvB,GAAI,CACF,aAAa,WAAW,KAAK,SAAS,CACxC,MAAQ,CAER,CACF,CAEA,OAAOJ,EAAmB,CACxB,KAAK,YAAY,OAAOA,CAAG,EAC3B,GAAI,CACF,IAAMC,EAAS,aAAa,QAAQ,KAAK,SAAS,EAClD,GAAIA,EAAQ,CACV,IAAMG,EAAW,KAAK,MAAMH,CAAM,EAClC,OAAOG,EAASJ,CAAG,EACnB,aAAa,QAAQ,KAAK,UAAW,KAAK,UAAUI,CAAQ,CAAC,CAC/D,CACF,MAAQ,CAER,CACF,CACF,ECzEO,IAAMC,EAAN,KAAe,CAIpB,YAAYC,EAA4B,CAFxC,KAAQ,aAA0C,KAGhD,KAAK,aAAeA,CACtB,CAEA,MAAM,aAAaC,EAAiBC,EAAqC,CACvE,OAAK,KAAK,eACR,KAAK,aAAe,KAAK,eAAeD,EAASC,CAAO,EAAE,MAAOC,GAAQ,CACvE,WAAK,aAAe,KACdA,CACR,CAAC,GAEI,KAAK,YACd,CAEA,MAAc,eAAeF,EAAiBC,EAAqC,CACjF,IAAME,EAAM,MAAM,MAAM,GAAGH,CAAO,cAAcC,CAAO,EAAE,EACzD,GAAI,CAACE,EAAI,GACP,MAAM,IAAI,MAAM,qDAAaA,EAAI,MAAM,IAAIA,EAAI,UAAU,EAAE,EAE7D,OAAOA,EAAI,KAAK,CAClB,CAEA,MAAM,SAASH,EAAiBC,EAAiBG,EAAa,CAC5D,IAAMC,EAAW,GAAGL,CAAO,IAAIC,CAAO,IAAI,KAAK,UAAUG,CAAM,CAAC,GAE1DE,EAAS,KAAK,aAAa,IAAID,CAAQ,EAC7C,GAAIC,EACF,MAAO,CAAE,GAAGA,EAAQ,WAAY,EAAK,EAGvC,GAAM,CAAE,UAAAC,EAAW,MAAAC,CAAM,EAAI,MAAM,KAAK,aAAaR,EAASC,CAAO,EAE/DQ,EAAc,IAAI,gBAAgB,CACtC,QAAS,IACT,MAAO,KAAK,IAAI,EAAE,SAAS,EAC3B,KAAM,OACN,SAAUL,EAAO,UAAY,gBAC7B,QAAS,QACT,GAAGA,CACL,CAAC,EAEKM,EAAW,GAAGV,CAAO,iBAAiBO,CAAS,UAAUE,EAAY,SAAS,CAAC,GAE/EN,EAAM,MAAM,MAAMO,EAAU,CAChC,QAAS,CAAE,sBAAuBF,CAAM,CAC1C,CAAC,EAED,GAAI,CAACL,EAAI,GACP,MAAIA,EAAI,SAAW,KACjB,KAAK,aAAa,MAAM,EAClB,IAAI,MAAM,0DAAkB,GAE9B,IAAI,MAAM,yCAAWA,EAAI,MAAM,IAAIA,EAAI,UAAU,EAAE,EAG3D,IAAMQ,EAAO,MAAMR,EAAI,KAAK,EAC5B,YAAK,aAAa,IAAIE,EAAUM,CAAI,EAC7BA,CACT,CAEA,iBAAwB,CACtB,KAAK,aAAe,IACtB,CACF,EC/DO,SAASC,EAAcC,EAAwD,CACpF,GAAI,CACF,IAAMC,EAAM,IAAI,IAAID,CAAQ,EAGtBE,EAAU,GAAGD,EAAI,QAAQ,KAAKA,EAAI,IAAI,GAGtCE,EAAYF,EAAI,SAAS,MAAM,GAAG,EAClCG,EAAaD,EAAU,QAAQ,OAAO,EAE5C,GAAIC,IAAe,IAAMA,IAAeD,EAAU,OAAS,EACzD,MAAM,IAAI,MAAM,+EAAwB,EAG1C,IAAME,EAAUF,EAAUC,EAAa,CAAC,EAExC,GAAI,CAACC,GAAWA,EAAQ,OAAS,GAC/B,MAAM,IAAI,MAAM,mCAAU,EAG5B,MAAO,CAAE,QAAAH,EAAS,QAAAG,CAAQ,CAC5B,OAASC,EAAO,CACd,MAAIA,aAAiB,MACb,IAAI,MAAM,iCAAaA,EAAM,OAAO,EAAE,EAExC,IAAI,MAAM,mEAAsB,CACxC,CACF,CAKO,SAASC,EAAgBN,EAAsB,CACpD,GAAI,CAEF,OADe,IAAI,IAAIA,CAAG,EACZ,SAAS,SAAS,SAAS,CAC3C,MAAQ,CACN,MAAO,EACT,CACF,CC1CO,IAAMO,EAAN,KAAkB,CAKvB,YAAYC,EAAqB,CAE/B,GAAI,CAACA,EAAO,SACV,MAAM,IAAI,MAAM,yCAAgB,EAIlC,GAAM,CAAE,QAAAC,EAAS,QAAAC,CAAQ,EAAIC,EAAcH,EAAO,QAAQ,EAE1D,KAAK,OAAS,CACZ,SAAU,gBACV,YAAa,GACb,SAAU,KACV,QAAAC,EACA,QAAAC,EACA,GAAGF,CACL,EAEA,KAAK,aAAe,IAAII,EAAa,QAAS,KAAK,OAAO,QAAQ,EAClE,KAAK,IAAM,IAAIC,EAAS,KAAK,YAAY,CAC3C,CAEA,MAAM,aACJC,EACAC,EAAqC,CAAC,EAChB,CACtB,GAAI,CAAC,KAAK,OAAO,SAAW,CAAC,KAAK,OAAO,QACvC,MAAM,IAAI,MAAM,wDAAW,EAG7B,IAAMC,EAAO,MAAM,KAAK,IAAI,SAAS,KAAK,OAAO,QAAS,KAAK,OAAO,QAAS,CAC7E,KAAM,MAAMF,CAAI,GAChB,SAAU,KAAK,OAAO,SACtB,GAAGC,CACL,CAAC,EAED,MAAO,CACL,UAAYC,EAAK,WAAW,OAAUA,EAAK,WAAa,EACxD,SAAWA,EAAK,UAAU,OAAUA,EAAK,UAAY,EACrD,WAAYA,EAAK,UACnB,CACF,CAEA,MAAM,kBACJC,EACAF,EAAqC,CAAC,EAChB,CACtB,GAAI,CAAC,KAAK,OAAO,SAAW,CAAC,KAAK,OAAO,QACvC,MAAM,IAAI,MAAM,wDAAW,EAG7B,IAAMC,EAAO,MAAM,KAAK,IAAI,SAAS,KAAK,OAAO,QAAS,KAAK,OAAO,QAAS,CAC7E,IAAKC,EACL,SAAU,KAAK,OAAO,SACtB,GAAGF,CACL,CAAC,EAED,MAAO,CACL,UAAYC,EAAK,WAAW,OAAUA,EAAK,WAAa,EACxD,SAAWA,EAAK,UAAU,OAAUA,EAAK,UAAY,EACrD,WAAYA,EAAK,UACnB,CACF,CAEA,MAAM,aAAaD,EAAqC,CAAC,EAAyB,CAChF,GAAI,CAAC,KAAK,OAAO,SAAW,CAAC,KAAK,OAAO,QACvC,MAAM,IAAI,MAAM,wDAAW,EAG7B,IAAMC,EAAO,MAAM,KAAK,IAAI,SAAS,KAAK,OAAO,QAAS,KAAK,OAAO,QAAS,CAC7E,SAAU,KAAK,OAAO,SACtB,GAAGD,CACL,CAAC,EAED,MAAO,CACL,UAAWC,EAAK,WAAa,EAC7B,SAAUA,EAAK,UAAY,EAC3B,WAAYA,EAAK,UACnB,CACF,CAEA,YAAmB,CACjB,KAAK,aAAa,MAAM,EACxB,KAAK,IAAI,gBAAgB,CAC3B,CAEA,WAAmC,CACjC,MAAO,CAAE,GAAG,KAAK,MAAO,CAC1B,CAEA,aAAaE,EAAuC,CAClD,KAAK,OAAS,CAAE,GAAG,KAAK,OAAQ,GAAGA,CAAU,CAC/C,CACF,EAEO,SAASC,EAAkBX,EAAkC,CAClE,OAAO,IAAID,EAAYC,CAAM,CAC/B,CAGI,OAAO,OAAW,MACnB,OAAe,YAAcD,EAC7B,OAAe,kBAAoBY,GCvG/B,SAASC,EAAMC,EAAkC,CACtD,GAAI,CAACA,EAAQ,SACX,MAAM,IAAI,MAAM,mCAAe,EAGjC,MAAO,CACL,KAAM,0BACN,MAAO,CACL,qBAAsB,CAAC,CAAE,aAAAC,CAAa,IAAW,CAC/C,IAAMC,EAAS,CACb,SAAUF,EAAQ,SAClB,SAAUA,EAAQ,UAAY,gBAC9B,YAAaA,EAAQ,cAAgB,GACrC,SAAUA,EAAQ,UAAY,IAChC,EAGAC,EAAa,OAAQ;AAAA;AAAA;AAAA;AAAA;AAAA,qDAKwB,KAAK,UAAUC,CAAM,CAAC;AAAA;AAAA;AAAA;AAAA;AAAA,SAKlE,CACH,CACF,CACF,CACF","names":["VERSION","DEFAULT_CONFIG","isValidConfig","config","UmamiError","message","code","CacheManager","namespace","ttl","key","cached","cachedData","value","cacheObj","UmamiAPI","cacheManager","baseUrl","shareId","err","res","params","cacheKey","cached","websiteId","token","queryParams","statsUrl","data","parseShareUrl","shareUrl","url","baseUrl","pathParts","shareIndex","shareId","error","isValidShareUrl","UmamiClient","config","baseUrl","shareId","parseShareUrl","CacheManager","UmamiAPI","path","options","data","url","newConfig","createUmamiClient","umami","options","injectScript","config"]}
|
package/package.json
ADDED
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "oddmisc",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "杂七杂八奇怪小工具 npm 包",
|
|
5
|
+
"homepage": "https://github.com/yCENzh/oddmisc#readme",
|
|
6
|
+
"bugs": {
|
|
7
|
+
"url": "https://github.com/yCENzh/oddmisc/issues"
|
|
8
|
+
},
|
|
9
|
+
"repository": {
|
|
10
|
+
"type": "git",
|
|
11
|
+
"url": "git+https://github.com/yCENzh/oddmisc.git"
|
|
12
|
+
},
|
|
13
|
+
"author": "yCENzh",
|
|
14
|
+
"license": "MIT",
|
|
15
|
+
"publishConfig": {
|
|
16
|
+
"access": "public"
|
|
17
|
+
},
|
|
18
|
+
"type": "module",
|
|
19
|
+
"main": "dist/index.js",
|
|
20
|
+
"module": "dist/index.mjs",
|
|
21
|
+
"types": "dist/index.d.ts",
|
|
22
|
+
"files": [
|
|
23
|
+
"dist",
|
|
24
|
+
"README.md"
|
|
25
|
+
],
|
|
26
|
+
"scripts": {
|
|
27
|
+
"build": "tsup",
|
|
28
|
+
"dev": "tsup --watch",
|
|
29
|
+
"prepublishOnly": "pnpm build",
|
|
30
|
+
"test": "echo \"Error: no test specified\" && exit 1"
|
|
31
|
+
},
|
|
32
|
+
"keywords": [
|
|
33
|
+
"umami",
|
|
34
|
+
"analytics",
|
|
35
|
+
"statistics",
|
|
36
|
+
"web-analytics",
|
|
37
|
+
"visitor-tracking",
|
|
38
|
+
"utilities",
|
|
39
|
+
"tools"
|
|
40
|
+
],
|
|
41
|
+
"devDependencies": {
|
|
42
|
+
"@types/node": "^25.2.3",
|
|
43
|
+
"tsup": "^8.5.1",
|
|
44
|
+
"typescript": "^5.9.3"
|
|
45
|
+
}
|
|
46
|
+
}
|