@casoon/trackr 0.1.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.
@@ -0,0 +1,3 @@
1
+ export { H as HandlerConfig, P as PrivacyConfig, Q as QueryOptions, S as StorageAdapter, a as TrackrConfig, T as TrackrEvent } from './types-EaeYBDKE.js';
2
+ export { init, track } from './client/index.js';
3
+ export { createHandler } from './server/index.js';
package/dist/index.js ADDED
@@ -0,0 +1,14 @@
1
+ import {
2
+ init,
3
+ track
4
+ } from "./chunk-ABUPERUQ.js";
5
+ import {
6
+ createHandler
7
+ } from "./chunk-L3N32JO4.js";
8
+ import "./chunk-7D4SUZUM.js";
9
+ export {
10
+ createHandler,
11
+ init,
12
+ track
13
+ };
14
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":[],"sourcesContent":[],"mappings":"","names":[]}
@@ -0,0 +1,11 @@
1
+ import { T as TrackrEvent, P as PrivacyConfig, H as HandlerConfig } from '../types-EaeYBDKE.js';
2
+
3
+ declare function isBot(request: Request): boolean;
4
+
5
+ declare function anonymizeIp(ip: string): string;
6
+ declare function stripPii(url: string): string;
7
+ declare function applyPrivacy(event: TrackrEvent, config: PrivacyConfig): TrackrEvent;
8
+
9
+ declare function createHandler(config: HandlerConfig): (request: Request) => Promise<Response>;
10
+
11
+ export { anonymizeIp, applyPrivacy, createHandler, isBot, stripPii };
@@ -0,0 +1,16 @@
1
+ import {
2
+ anonymizeIp,
3
+ applyPrivacy,
4
+ createHandler,
5
+ isBot,
6
+ stripPii
7
+ } from "../chunk-L3N32JO4.js";
8
+ import "../chunk-7D4SUZUM.js";
9
+ export {
10
+ anonymizeIp,
11
+ applyPrivacy,
12
+ createHandler,
13
+ isBot,
14
+ stripPii
15
+ };
16
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":[],"sourcesContent":[],"mappings":"","names":[]}
@@ -0,0 +1,10 @@
1
+ import { T as TrackrEvent, S as StorageAdapter } from '../types-EaeYBDKE.js';
2
+
3
+ interface ApiConfig {
4
+ url: string;
5
+ headers?: Record<string, string>;
6
+ transform?: (event: TrackrEvent) => unknown;
7
+ }
8
+ declare function api(config: ApiConfig): StorageAdapter;
9
+
10
+ export { api };
@@ -0,0 +1,22 @@
1
+ import "../chunk-7D4SUZUM.js";
2
+
3
+ // src/storage/api.ts
4
+ function api(config) {
5
+ return {
6
+ async save(event) {
7
+ const body = config.transform ? config.transform(event) : event;
8
+ await fetch(config.url, {
9
+ method: "POST",
10
+ headers: {
11
+ "Content-Type": "application/json",
12
+ ...config.headers
13
+ },
14
+ body: JSON.stringify(body)
15
+ });
16
+ }
17
+ };
18
+ }
19
+ export {
20
+ api
21
+ };
22
+ //# sourceMappingURL=api.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/storage/api.ts"],"sourcesContent":["import type { StorageAdapter, TrackrEvent } from \"../types.js\";\n\ninterface ApiConfig {\n url: string;\n headers?: Record<string, string>;\n transform?: (event: TrackrEvent) => unknown;\n}\n\nexport function api(config: ApiConfig): StorageAdapter {\n return {\n async save(event: TrackrEvent): Promise<void> {\n const body = config.transform ? config.transform(event) : event;\n \n await fetch(config.url, {\n method: \"POST\",\n headers: {\n \"Content-Type\": \"application/json\",\n ...config.headers\n },\n body: JSON.stringify(body)\n });\n }\n };\n}\n"],"mappings":";;;AAQO,SAAS,IAAI,QAAmC;AACrD,SAAO;AAAA,IACL,MAAM,KAAK,OAAmC;AAC5C,YAAM,OAAO,OAAO,YAAY,OAAO,UAAU,KAAK,IAAI;AAE1D,YAAM,MAAM,OAAO,KAAK;AAAA,QACtB,QAAQ;AAAA,QACR,SAAS;AAAA,UACP,gBAAgB;AAAA,UAChB,GAAG,OAAO;AAAA,QACZ;AAAA,QACA,MAAM,KAAK,UAAU,IAAI;AAAA,MAC3B,CAAC;AAAA,IACH;AAAA,EACF;AACF;","names":[]}
@@ -0,0 +1,10 @@
1
+ import { S as StorageAdapter } from '../types-EaeYBDKE.js';
2
+
3
+ interface PostgresClient {
4
+ query(text: string, values?: unknown[]): Promise<{
5
+ rows: unknown[];
6
+ }>;
7
+ }
8
+ declare function postgres(connectionStringOrClient: string | PostgresClient): StorageAdapter;
9
+
10
+ export { postgres };
@@ -0,0 +1,67 @@
1
+ import "../chunk-7D4SUZUM.js";
2
+
3
+ // src/storage/postgres.ts
4
+ function postgres(connectionStringOrClient) {
5
+ let client = null;
6
+ const getClient = async () => {
7
+ if (client) return client;
8
+ if (typeof connectionStringOrClient === "string") {
9
+ const pg = await import("../esm-O5HEMDRH.js");
10
+ const pool = new pg.default.Pool({ connectionString: connectionStringOrClient });
11
+ client = pool;
12
+ return pool;
13
+ }
14
+ client = connectionStringOrClient;
15
+ return client;
16
+ };
17
+ return {
18
+ async save(event) {
19
+ const db = await getClient();
20
+ await db.query(
21
+ `INSERT INTO trackr_events (type, name, url, referrer_domain, country, device, browser, session_id, props, ts)
22
+ VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, to_timestamp($10 / 1000.0))`,
23
+ [
24
+ event.type,
25
+ event.name || null,
26
+ event.url,
27
+ event.referrer || null,
28
+ event.country || null,
29
+ event.device || null,
30
+ event.browser || null,
31
+ event.sessionId || null,
32
+ JSON.stringify(event.props || {}),
33
+ event.ts
34
+ ]
35
+ );
36
+ },
37
+ async query(options) {
38
+ const db = await getClient();
39
+ const conditions = [];
40
+ const values = [];
41
+ let i = 1;
42
+ if (options.from) {
43
+ conditions.push(`ts >= $${i++}`);
44
+ values.push(options.from);
45
+ }
46
+ if (options.to) {
47
+ conditions.push(`ts <= $${i++}`);
48
+ values.push(options.to);
49
+ }
50
+ if (options.type) {
51
+ conditions.push(`type = $${i++}`);
52
+ values.push(options.type);
53
+ }
54
+ const where = conditions.length ? `WHERE ${conditions.join(" AND ")}` : "";
55
+ const limit = options.limit ? `LIMIT ${options.limit}` : "";
56
+ const result = await db.query(
57
+ `SELECT * FROM trackr_events ${where} ORDER BY ts DESC ${limit}`,
58
+ values
59
+ );
60
+ return result.rows;
61
+ }
62
+ };
63
+ }
64
+ export {
65
+ postgres
66
+ };
67
+ //# sourceMappingURL=postgres.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/storage/postgres.ts"],"sourcesContent":["import type { StorageAdapter, TrackrEvent, QueryOptions } from \"../types.js\";\n\ninterface PostgresClient {\n query(text: string, values?: unknown[]): Promise<{ rows: unknown[] }>;\n}\n\nexport function postgres(connectionStringOrClient: string | PostgresClient): StorageAdapter {\n let client: PostgresClient | null = null;\n \n const getClient = async (): Promise<PostgresClient> => {\n if (client) return client;\n \n if (typeof connectionStringOrClient === \"string\") {\n const pg = await import(\"pg\");\n const pool = new pg.default.Pool({ connectionString: connectionStringOrClient });\n client = pool;\n return pool;\n }\n \n client = connectionStringOrClient;\n return client;\n };\n \n return {\n async save(event: TrackrEvent): Promise<void> {\n const db = await getClient();\n await db.query(\n `INSERT INTO trackr_events (type, name, url, referrer_domain, country, device, browser, session_id, props, ts)\n VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, to_timestamp($10 / 1000.0))`,\n [\n event.type,\n event.name || null,\n event.url,\n event.referrer || null,\n event.country || null,\n event.device || null,\n event.browser || null,\n event.sessionId || null,\n JSON.stringify(event.props || {}),\n event.ts\n ]\n );\n },\n \n async query(options: QueryOptions): Promise<TrackrEvent[]> {\n const db = await getClient();\n const conditions: string[] = [];\n const values: unknown[] = [];\n let i = 1;\n \n if (options.from) {\n conditions.push(`ts >= $${i++}`);\n values.push(options.from);\n }\n if (options.to) {\n conditions.push(`ts <= $${i++}`);\n values.push(options.to);\n }\n if (options.type) {\n conditions.push(`type = $${i++}`);\n values.push(options.type);\n }\n \n const where = conditions.length ? `WHERE ${conditions.join(\" AND \")}` : \"\";\n const limit = options.limit ? `LIMIT ${options.limit}` : \"\";\n \n const result = await db.query(\n `SELECT * FROM trackr_events ${where} ORDER BY ts DESC ${limit}`,\n values\n );\n \n return result.rows as TrackrEvent[];\n }\n };\n}\n"],"mappings":";;;AAMO,SAAS,SAAS,0BAAmE;AAC1F,MAAI,SAAgC;AAEpC,QAAM,YAAY,YAAqC;AACrD,QAAI,OAAQ,QAAO;AAEnB,QAAI,OAAO,6BAA6B,UAAU;AAChD,YAAM,KAAK,MAAM,OAAO,oBAAI;AAC5B,YAAM,OAAO,IAAI,GAAG,QAAQ,KAAK,EAAE,kBAAkB,yBAAyB,CAAC;AAC/E,eAAS;AACT,aAAO;AAAA,IACT;AAEA,aAAS;AACT,WAAO;AAAA,EACT;AAEA,SAAO;AAAA,IACL,MAAM,KAAK,OAAmC;AAC5C,YAAM,KAAK,MAAM,UAAU;AAC3B,YAAM,GAAG;AAAA,QACP;AAAA;AAAA,QAEA;AAAA,UACE,MAAM;AAAA,UACN,MAAM,QAAQ;AAAA,UACd,MAAM;AAAA,UACN,MAAM,YAAY;AAAA,UAClB,MAAM,WAAW;AAAA,UACjB,MAAM,UAAU;AAAA,UAChB,MAAM,WAAW;AAAA,UACjB,MAAM,aAAa;AAAA,UACnB,KAAK,UAAU,MAAM,SAAS,CAAC,CAAC;AAAA,UAChC,MAAM;AAAA,QACR;AAAA,MACF;AAAA,IACF;AAAA,IAEA,MAAM,MAAM,SAA+C;AACzD,YAAM,KAAK,MAAM,UAAU;AAC3B,YAAM,aAAuB,CAAC;AAC9B,YAAM,SAAoB,CAAC;AAC3B,UAAI,IAAI;AAER,UAAI,QAAQ,MAAM;AAChB,mBAAW,KAAK,UAAU,GAAG,EAAE;AAC/B,eAAO,KAAK,QAAQ,IAAI;AAAA,MAC1B;AACA,UAAI,QAAQ,IAAI;AACd,mBAAW,KAAK,UAAU,GAAG,EAAE;AAC/B,eAAO,KAAK,QAAQ,EAAE;AAAA,MACxB;AACA,UAAI,QAAQ,MAAM;AAChB,mBAAW,KAAK,WAAW,GAAG,EAAE;AAChC,eAAO,KAAK,QAAQ,IAAI;AAAA,MAC1B;AAEA,YAAM,QAAQ,WAAW,SAAS,SAAS,WAAW,KAAK,OAAO,CAAC,KAAK;AACxE,YAAM,QAAQ,QAAQ,QAAQ,SAAS,QAAQ,KAAK,KAAK;AAEzD,YAAM,SAAS,MAAM,GAAG;AAAA,QACtB,+BAA+B,KAAK,qBAAqB,KAAK;AAAA,QAC9D;AAAA,MACF;AAEA,aAAO,OAAO;AAAA,IAChB;AAAA,EACF;AACF;","names":[]}
@@ -0,0 +1,38 @@
1
+ interface TrackrEvent {
2
+ type: "pageview" | "event";
3
+ name?: string;
4
+ url: string;
5
+ referrer?: string;
6
+ country?: string;
7
+ device?: "desktop" | "mobile" | "tablet";
8
+ browser?: string;
9
+ sessionId?: string;
10
+ props?: Record<string, string | number | boolean>;
11
+ ts: number;
12
+ }
13
+ interface TrackrConfig {
14
+ endpoint: string;
15
+ debug?: boolean;
16
+ }
17
+ interface StorageAdapter {
18
+ save(event: TrackrEvent): Promise<void>;
19
+ query?(options: QueryOptions): Promise<TrackrEvent[]>;
20
+ }
21
+ interface QueryOptions {
22
+ from?: Date;
23
+ to?: Date;
24
+ type?: "pageview" | "event";
25
+ limit?: number;
26
+ }
27
+ interface PrivacyConfig {
28
+ anonymizeIp?: boolean;
29
+ stripPii?: boolean;
30
+ stripQueryParams?: string[];
31
+ }
32
+ interface HandlerConfig {
33
+ storage: StorageAdapter;
34
+ privacy?: PrivacyConfig;
35
+ botFilter?: boolean;
36
+ }
37
+
38
+ export type { HandlerConfig as H, PrivacyConfig as P, QueryOptions as Q, StorageAdapter as S, TrackrEvent as T, TrackrConfig as a };
package/package.json ADDED
@@ -0,0 +1,59 @@
1
+ {
2
+ "name": "@casoon/trackr",
3
+ "version": "0.1.0",
4
+ "description": "Privacy-first, GDPR-native analytics for static sites.",
5
+ "author": "Joern Seidel <joern@casoon.de>",
6
+ "license": "LGPL-3.0-or-later",
7
+ "type": "module",
8
+ "exports": {
9
+ ".": {
10
+ "types": "./dist/index.d.ts",
11
+ "import": "./dist/index.js"
12
+ },
13
+ "./client": {
14
+ "types": "./dist/client/index.d.ts",
15
+ "import": "./dist/client/index.js"
16
+ },
17
+ "./server": {
18
+ "types": "./dist/server/index.d.ts",
19
+ "import": "./dist/server/index.js"
20
+ },
21
+ "./storage/postgres": {
22
+ "types": "./dist/storage/postgres.d.ts",
23
+ "import": "./dist/storage/postgres.js"
24
+ },
25
+ "./storage/api": {
26
+ "types": "./dist/storage/api.d.ts",
27
+ "import": "./dist/storage/api.js"
28
+ }
29
+ },
30
+ "files": [
31
+ "dist",
32
+ "script.js",
33
+ "LICENSE",
34
+ "README.md"
35
+ ],
36
+ "scripts": {
37
+ "build": "tsup",
38
+ "dev": "tsup --watch",
39
+ "test": "vitest",
40
+ "typecheck": "tsc --noEmit"
41
+ },
42
+ "devDependencies": {
43
+ "@types/node": "^22.10.2",
44
+ "@types/pg": "^8.16.0",
45
+ "tsup": "^8.3.5",
46
+ "typescript": "^5.7.2",
47
+ "vitest": "^2.1.8"
48
+ },
49
+ "optionalDependencies": {
50
+ "pg": "^8.13.1"
51
+ },
52
+ "engines": {
53
+ "node": ">=22.0.0"
54
+ },
55
+ "packageManager": "pnpm@9.15.1",
56
+ "volta": {
57
+ "node": "24.0.0"
58
+ }
59
+ }