@casoon/trackr 0.1.1 → 0.2.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.
Files changed (39) hide show
  1. package/README.md +117 -49
  2. package/dist/chunk-7UN7MXBM.js +141 -0
  3. package/dist/chunk-7UN7MXBM.js.map +1 -0
  4. package/dist/{chunk-4EAYUMKF.js → chunk-AOB662OQ.js} +23 -4
  5. package/dist/chunk-AOB662OQ.js.map +1 -0
  6. package/dist/chunk-PEAZRYH7.js +78 -0
  7. package/dist/chunk-PEAZRYH7.js.map +1 -0
  8. package/dist/client/index.d.ts +1 -1
  9. package/dist/client/index.js +1 -1
  10. package/dist/index.d.ts +1 -1
  11. package/dist/index.js +3 -2
  12. package/dist/server/index.d.ts +5 -2
  13. package/dist/server/index.js +8 -2
  14. package/dist/server/pixel.d.ts +5 -0
  15. package/dist/server/pixel.js +97 -0
  16. package/dist/server/pixel.js.map +1 -0
  17. package/dist/storage/api.d.ts +1 -1
  18. package/dist/storage/api.js.map +1 -1
  19. package/dist/storage/batch.d.ts +19 -0
  20. package/dist/storage/batch.js +59 -0
  21. package/dist/storage/batch.js.map +1 -0
  22. package/dist/storage/ga4.d.ts +47 -0
  23. package/dist/storage/ga4.js +131 -0
  24. package/dist/storage/ga4.js.map +1 -0
  25. package/dist/storage/multi.d.ts +21 -0
  26. package/dist/storage/multi.js +14 -0
  27. package/dist/storage/multi.js.map +1 -0
  28. package/dist/storage/postgres.d.ts +1 -1
  29. package/dist/storage/postgres.js +3 -1
  30. package/dist/storage/postgres.js.map +1 -1
  31. package/dist/storage/webhook.d.ts +22 -0
  32. package/dist/storage/webhook.js +54 -0
  33. package/dist/storage/webhook.js.map +1 -0
  34. package/dist/{types-EaeYBDKE.d.ts → types-CceMQIhZ.d.ts} +3 -1
  35. package/package.json +26 -2
  36. package/script.js +1 -0
  37. package/dist/chunk-4EAYUMKF.js.map +0 -1
  38. package/dist/chunk-L3N32JO4.js +0 -153
  39. package/dist/chunk-L3N32JO4.js.map +0 -1
package/script.js ADDED
@@ -0,0 +1 @@
1
+ "use strict";var trackr=(()=>{var s=Object.defineProperty;var f=Object.getOwnPropertyDescriptor;var p=Object.getOwnPropertyNames;var l=Object.prototype.hasOwnProperty;var g=(t,e)=>{for(var n in e)s(t,n,{get:e[n],enumerable:!0})},m=(t,e,n,i)=>{if(e&&typeof e=="object"||typeof e=="function")for(let o of p(e))!l.call(t,o)&&o!==n&&s(t,o,{get:()=>e[o],enumerable:!(i=f(e,o))||i.enumerable});return t};var h=t=>m(s({},"__esModule",{value:!0}),t);var k={};g(k,{init:()=>w,track:()=>y});var r=null;function w(t){r=t,a(),typeof window!="undefined"&&(window.addEventListener("popstate",a),window.addEventListener("hashchange",a),c("pushState"),c("replaceState"))}function c(t){let e=history[t].bind(history);history[t]=function(...n){e(...n),a()}}function y(t,e){if(!r){console.warn("[trackr] Not initialized. Call init() first.");return}d({type:"event",name:t,url:u(),props:e,ts:Date.now()})}function a(){if(!r)return;let t=v();d({type:"pageview",url:u(),referrer:document.referrer?new URL(document.referrer).hostname:void 0,...Object.keys(t).length>0&&{utm:t},ts:Date.now()})}function u(){return window.location.pathname+window.location.search}function v(){let t=new URLSearchParams(window.location.search),e={},n=["utm_source","utm_medium","utm_campaign","utm_term","utm_content"];for(let i of n){let o=t.get(i);o&&(e[i.replace("utm_","")]=o)}return e}function d(t){if(!r)return;let e=JSON.stringify(t);navigator.sendBeacon?navigator.sendBeacon(r.endpoint,new Blob([e],{type:"application/json"})):fetch(r.endpoint,{method:"POST",body:e,keepalive:!0,headers:{"Content-Type":"application/json"}}).catch(()=>{}),r.debug&&console.log("[trackr]",t)}return h(k);})();
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/client/index.ts"],"sourcesContent":["import type { TrackrConfig } from \"../types.js\";\n\nlet config: TrackrConfig | null = null;\n\nexport function init(options: TrackrConfig): void {\n config = options;\n trackPageview();\n\n if (typeof window !== \"undefined\") {\n window.addEventListener(\"popstate\", trackPageview);\n }\n}\n\nexport function track(name: string, props?: Record<string, string | number | boolean>): void {\n if (!config) {\n console.warn(\"[trackr] Not initialized. Call init() first.\");\n return;\n }\n\n sendEvent({\n type: \"event\",\n name,\n url: getPath(),\n props,\n ts: Date.now()\n });\n}\n\nfunction trackPageview(): void {\n if (!config) return;\n\n const utm = getUtmParams();\n\n sendEvent({\n type: \"pageview\",\n url: getPath(),\n referrer: document.referrer ? new URL(document.referrer).hostname : undefined,\n ...(Object.keys(utm).length > 0 && { utm }),\n ts: Date.now()\n });\n}\n\nfunction getPath(): string {\n return window.location.pathname + window.location.search;\n}\n\nfunction getUtmParams(): Record<string, string> {\n const params = new URLSearchParams(window.location.search);\n const utm: Record<string, string> = {};\n const keys = [\"utm_source\", \"utm_medium\", \"utm_campaign\", \"utm_term\", \"utm_content\"];\n\n for (const key of keys) {\n const value = params.get(key);\n if (value) utm[key] = value;\n }\n\n return utm;\n}\n\nfunction sendEvent(event: Record<string, unknown>): void {\n if (!config) return;\n\n const body = JSON.stringify(event);\n\n if (navigator.sendBeacon) {\n navigator.sendBeacon(config.endpoint, body);\n } else {\n fetch(config.endpoint, {\n method: \"POST\",\n body,\n keepalive: true,\n headers: { \"Content-Type\": \"application/json\" }\n }).catch(() => {});\n }\n\n if (config.debug) {\n console.log(\"[trackr]\", event);\n }\n}\n"],"mappings":";AAEA,IAAI,SAA8B;AAE3B,SAAS,KAAK,SAA6B;AAChD,WAAS;AACT,gBAAc;AAEd,MAAI,OAAO,WAAW,aAAa;AACjC,WAAO,iBAAiB,YAAY,aAAa;AAAA,EACnD;AACF;AAEO,SAAS,MAAM,MAAc,OAAyD;AAC3F,MAAI,CAAC,QAAQ;AACX,YAAQ,KAAK,8CAA8C;AAC3D;AAAA,EACF;AAEA,YAAU;AAAA,IACR,MAAM;AAAA,IACN;AAAA,IACA,KAAK,QAAQ;AAAA,IACb;AAAA,IACA,IAAI,KAAK,IAAI;AAAA,EACf,CAAC;AACH;AAEA,SAAS,gBAAsB;AAC7B,MAAI,CAAC,OAAQ;AAEb,QAAM,MAAM,aAAa;AAEzB,YAAU;AAAA,IACR,MAAM;AAAA,IACN,KAAK,QAAQ;AAAA,IACb,UAAU,SAAS,WAAW,IAAI,IAAI,SAAS,QAAQ,EAAE,WAAW;AAAA,IACpE,GAAI,OAAO,KAAK,GAAG,EAAE,SAAS,KAAK,EAAE,IAAI;AAAA,IACzC,IAAI,KAAK,IAAI;AAAA,EACf,CAAC;AACH;AAEA,SAAS,UAAkB;AACzB,SAAO,OAAO,SAAS,WAAW,OAAO,SAAS;AACpD;AAEA,SAAS,eAAuC;AAC9C,QAAM,SAAS,IAAI,gBAAgB,OAAO,SAAS,MAAM;AACzD,QAAM,MAA8B,CAAC;AACrC,QAAM,OAAO,CAAC,cAAc,cAAc,gBAAgB,YAAY,aAAa;AAEnF,aAAW,OAAO,MAAM;AACtB,UAAM,QAAQ,OAAO,IAAI,GAAG;AAC5B,QAAI,MAAO,KAAI,GAAG,IAAI;AAAA,EACxB;AAEA,SAAO;AACT;AAEA,SAAS,UAAU,OAAsC;AACvD,MAAI,CAAC,OAAQ;AAEb,QAAM,OAAO,KAAK,UAAU,KAAK;AAEjC,MAAI,UAAU,YAAY;AACxB,cAAU,WAAW,OAAO,UAAU,IAAI;AAAA,EAC5C,OAAO;AACL,UAAM,OAAO,UAAU;AAAA,MACrB,QAAQ;AAAA,MACR;AAAA,MACA,WAAW;AAAA,MACX,SAAS,EAAE,gBAAgB,mBAAmB;AAAA,IAChD,CAAC,EAAE,MAAM,MAAM;AAAA,IAAC,CAAC;AAAA,EACnB;AAEA,MAAI,OAAO,OAAO;AAChB,YAAQ,IAAI,YAAY,KAAK;AAAA,EAC/B;AACF;","names":[]}
@@ -1,153 +0,0 @@
1
- // src/server/bot.ts
2
- var BOT_PATTERNS = [
3
- /bot/i,
4
- /crawler/i,
5
- /spider/i,
6
- /crawling/i,
7
- /headless/i,
8
- /phantom/i,
9
- /selenium/i,
10
- /google/i,
11
- /bing/i,
12
- /yahoo/i,
13
- /baidu/i,
14
- /facebook/i,
15
- /twitter/i,
16
- /linkedin/i,
17
- /slack/i,
18
- /discord/i,
19
- /telegram/i,
20
- /preview/i,
21
- /curl/i,
22
- /wget/i,
23
- /monitoring/i,
24
- /uptime/i,
25
- /pingdom/i
26
- ];
27
- function isBot(request) {
28
- const ua = request.headers.get("user-agent") || "";
29
- if (BOT_PATTERNS.some((p) => p.test(ua))) return true;
30
- if (!request.headers.get("accept-language")) return true;
31
- if (ua.length < 20) return true;
32
- return false;
33
- }
34
-
35
- // src/server/privacy.ts
36
- var PII_PARAMS = ["email", "mail", "phone", "name", "token", "key", "password", "secret"];
37
- function anonymizeIp(ip) {
38
- if (ip.includes(".")) {
39
- return ip.split(".").slice(0, 3).join(".") + ".0";
40
- }
41
- return ip.split(":").slice(0, 4).join(":") + "::";
42
- }
43
- function stripPii(url) {
44
- try {
45
- const u = new URL(url, "http://localhost");
46
- PII_PARAMS.forEach((p) => u.searchParams.delete(p));
47
- return u.pathname + (u.search || "");
48
- } catch {
49
- return url;
50
- }
51
- }
52
- function createSessionId(ip, ua, date) {
53
- const input = anonymizeIp(ip) + "|" + ua + "|" + date;
54
- return simpleHash(input).slice(0, 16);
55
- }
56
- function simpleHash(str) {
57
- let hash = 0;
58
- for (let i = 0; i < str.length; i++) {
59
- const char = str.charCodeAt(i);
60
- hash = (hash << 5) - hash + char;
61
- hash = hash & hash;
62
- }
63
- return Math.abs(hash).toString(36);
64
- }
65
- function applyPrivacy(event, config) {
66
- const result = { ...event };
67
- if (config.stripPii && result.url) {
68
- result.url = stripPii(result.url);
69
- }
70
- if (config.stripQueryParams && result.url) {
71
- try {
72
- const u = new URL(result.url, "http://localhost");
73
- config.stripQueryParams.forEach((p) => {
74
- if (p.endsWith("*")) {
75
- const prefix = p.slice(0, -1);
76
- [...u.searchParams.keys()].filter((k) => k.startsWith(prefix)).forEach((k) => u.searchParams.delete(k));
77
- } else {
78
- u.searchParams.delete(p);
79
- }
80
- });
81
- result.url = u.pathname + (u.search || "");
82
- } catch {
83
- }
84
- }
85
- return result;
86
- }
87
-
88
- // src/server/index.ts
89
- function createHandler(config) {
90
- return async (request) => {
91
- if (request.method !== "POST") {
92
- return new Response("Method not allowed", { status: 405 });
93
- }
94
- if (config.botFilter && isBot(request)) {
95
- return new Response("OK");
96
- }
97
- try {
98
- const body = await request.json();
99
- if (!isValidEvent(body)) {
100
- return new Response("Invalid event", { status: 400 });
101
- }
102
- let event = {
103
- type: body.type,
104
- name: body.name,
105
- url: body.url,
106
- referrer: body.referrer,
107
- props: body.props,
108
- ts: body.ts
109
- };
110
- if (config.privacy) {
111
- event = applyPrivacy(event, config.privacy);
112
- }
113
- const ip = request.headers.get("x-forwarded-for")?.split(",")[0]?.trim() || request.headers.get("x-real-ip") || "0.0.0.0";
114
- const ua = request.headers.get("user-agent") || "";
115
- const today = (/* @__PURE__ */ new Date()).toISOString().split("T")[0];
116
- if (config.privacy?.anonymizeIp !== false) {
117
- event.sessionId = createSessionId(ip, ua, today);
118
- }
119
- event.device = detectDevice(ua);
120
- event.browser = detectBrowser(ua);
121
- await config.storage.save(event);
122
- return new Response("OK");
123
- } catch {
124
- return new Response("Error", { status: 500 });
125
- }
126
- };
127
- }
128
- function isValidEvent(e) {
129
- if (typeof e !== "object" || e === null) return false;
130
- const obj = e;
131
- return typeof obj.type === "string" && typeof obj.url === "string" && typeof obj.ts === "number";
132
- }
133
- function detectDevice(ua) {
134
- if (/tablet|ipad/i.test(ua)) return "tablet";
135
- if (/mobile|android|iphone/i.test(ua)) return "mobile";
136
- return "desktop";
137
- }
138
- function detectBrowser(ua) {
139
- if (/firefox/i.test(ua)) return "Firefox";
140
- if (/edg/i.test(ua)) return "Edge";
141
- if (/chrome/i.test(ua)) return "Chrome";
142
- if (/safari/i.test(ua)) return "Safari";
143
- return "Other";
144
- }
145
-
146
- export {
147
- isBot,
148
- anonymizeIp,
149
- stripPii,
150
- applyPrivacy,
151
- createHandler
152
- };
153
- //# sourceMappingURL=chunk-L3N32JO4.js.map
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/server/bot.ts","../src/server/privacy.ts","../src/server/index.ts"],"sourcesContent":["const BOT_PATTERNS = [\n /bot/i, /crawler/i, /spider/i, /crawling/i,\n /headless/i, /phantom/i, /selenium/i,\n /google/i, /bing/i, /yahoo/i, /baidu/i,\n /facebook/i, /twitter/i, /linkedin/i,\n /slack/i, /discord/i, /telegram/i,\n /preview/i, /curl/i, /wget/i,\n /monitoring/i, /uptime/i, /pingdom/i\n];\n\nexport function isBot(request: Request): boolean {\n const ua = request.headers.get(\"user-agent\") || \"\";\n \n if (BOT_PATTERNS.some(p => p.test(ua))) return true;\n if (!request.headers.get(\"accept-language\")) return true;\n if (ua.length < 20) return true;\n \n return false;\n}\n","import type { PrivacyConfig, TrackrEvent } from \"../types.js\";\n\nconst PII_PARAMS = [\"email\", \"mail\", \"phone\", \"name\", \"token\", \"key\", \"password\", \"secret\"];\n\nexport function anonymizeIp(ip: string): string {\n if (ip.includes(\".\")) {\n return ip.split(\".\").slice(0, 3).join(\".\") + \".0\";\n }\n return ip.split(\":\").slice(0, 4).join(\":\") + \"::\";\n}\n\nexport function stripPii(url: string): string {\n try {\n const u = new URL(url, \"http://localhost\");\n PII_PARAMS.forEach(p => u.searchParams.delete(p));\n return u.pathname + (u.search || \"\");\n } catch {\n return url;\n }\n}\n\nexport function createSessionId(ip: string, ua: string, date: string): string {\n const input = anonymizeIp(ip) + \"|\" + ua + \"|\" + date;\n return simpleHash(input).slice(0, 16);\n}\n\nfunction simpleHash(str: string): string {\n let hash = 0;\n for (let i = 0; i < str.length; i++) {\n const char = str.charCodeAt(i);\n hash = ((hash << 5) - hash) + char;\n hash = hash & hash;\n }\n return Math.abs(hash).toString(36);\n}\n\nexport function applyPrivacy(\n event: TrackrEvent,\n config: PrivacyConfig\n): TrackrEvent {\n const result = { ...event };\n\n if (config.stripPii && result.url) {\n result.url = stripPii(result.url);\n }\n\n if (config.stripQueryParams && result.url) {\n try {\n const u = new URL(result.url, \"http://localhost\");\n config.stripQueryParams.forEach(p => {\n if (p.endsWith(\"*\")) {\n const prefix = p.slice(0, -1);\n [...u.searchParams.keys()]\n .filter(k => k.startsWith(prefix))\n .forEach(k => u.searchParams.delete(k));\n } else {\n u.searchParams.delete(p);\n }\n });\n result.url = u.pathname + (u.search || \"\");\n } catch {}\n }\n\n return result;\n}\n","import type { HandlerConfig, TrackrEvent } from \"../types.js\";\nimport { isBot } from \"./bot.js\";\nimport { applyPrivacy, createSessionId } from \"./privacy.js\";\n\ninterface RawEvent {\n type: string;\n url: string;\n ts: number;\n name?: string;\n referrer?: string;\n props?: Record<string, string | number | boolean>;\n}\n\nexport function createHandler(config: HandlerConfig): (request: Request) => Promise<Response> {\n return async (request: Request): Promise<Response> => {\n if (request.method !== \"POST\") {\n return new Response(\"Method not allowed\", { status: 405 });\n }\n\n if (config.botFilter && isBot(request)) {\n return new Response(\"OK\");\n }\n\n try {\n const body = await request.json() as unknown;\n\n if (!isValidEvent(body)) {\n return new Response(\"Invalid event\", { status: 400 });\n }\n\n let event: TrackrEvent = {\n type: body.type as \"pageview\" | \"event\",\n name: body.name,\n url: body.url,\n referrer: body.referrer,\n props: body.props,\n ts: body.ts\n };\n\n if (config.privacy) {\n event = applyPrivacy(event, config.privacy);\n }\n\n const ip = request.headers.get(\"x-forwarded-for\")?.split(\",\")[0]?.trim()\n || request.headers.get(\"x-real-ip\")\n || \"0.0.0.0\";\n const ua = request.headers.get(\"user-agent\") || \"\";\n const today = new Date().toISOString().split(\"T\")[0];\n\n if (config.privacy?.anonymizeIp !== false) {\n event.sessionId = createSessionId(ip, ua, today);\n }\n\n event.device = detectDevice(ua);\n event.browser = detectBrowser(ua);\n\n await config.storage.save(event);\n\n return new Response(\"OK\");\n } catch {\n return new Response(\"Error\", { status: 500 });\n }\n };\n}\n\nfunction isValidEvent(e: unknown): e is RawEvent {\n if (typeof e !== \"object\" || e === null) return false;\n const obj = e as Record<string, unknown>;\n return typeof obj.type === \"string\" && typeof obj.url === \"string\" && typeof obj.ts === \"number\";\n}\n\nfunction detectDevice(ua: string): \"desktop\" | \"mobile\" | \"tablet\" {\n if (/tablet|ipad/i.test(ua)) return \"tablet\";\n if (/mobile|android|iphone/i.test(ua)) return \"mobile\";\n return \"desktop\";\n}\n\nfunction detectBrowser(ua: string): string {\n if (/firefox/i.test(ua)) return \"Firefox\";\n if (/edg/i.test(ua)) return \"Edge\";\n if (/chrome/i.test(ua)) return \"Chrome\";\n if (/safari/i.test(ua)) return \"Safari\";\n return \"Other\";\n}\n\nexport { isBot } from \"./bot.js\";\nexport { anonymizeIp, stripPii, applyPrivacy } from \"./privacy.js\";\n"],"mappings":"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","names":[]}