@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.
- package/LICENSE +165 -0
- package/README.md +142 -0
- package/dist/chunk-7D4SUZUM.js +38 -0
- package/dist/chunk-7D4SUZUM.js.map +1 -0
- package/dist/chunk-ABUPERUQ.js +58 -0
- package/dist/chunk-ABUPERUQ.js.map +1 -0
- package/dist/chunk-L3N32JO4.js +153 -0
- package/dist/chunk-L3N32JO4.js.map +1 -0
- package/dist/client/index.d.ts +6 -0
- package/dist/client/index.js +10 -0
- package/dist/client/index.js.map +1 -0
- package/dist/esm-O5HEMDRH.js +4966 -0
- package/dist/esm-O5HEMDRH.js.map +1 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.js +14 -0
- package/dist/index.js.map +1 -0
- package/dist/server/index.d.ts +11 -0
- package/dist/server/index.js +16 -0
- package/dist/server/index.js.map +1 -0
- package/dist/storage/api.d.ts +10 -0
- package/dist/storage/api.js +22 -0
- package/dist/storage/api.js.map +1 -0
- package/dist/storage/postgres.d.ts +10 -0
- package/dist/storage/postgres.js +67 -0
- package/dist/storage/postgres.js.map +1 -0
- package/dist/types-EaeYBDKE.d.ts +38 -0
- package/package.json +59 -0
package/dist/index.d.ts
ADDED
package/dist/index.js
ADDED
|
@@ -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
|
+
}
|