@seneris/nosework 0.1.0 → 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.
@@ -0,0 +1 @@
1
+ {"version":3,"file":"schema.d.ts","sourceRoot":"","sources":["../src/schema.ts"],"names":[],"mappings":"AAaA,eAAO,MAAM,SAAS;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAuCrB,CAAC;AAGF,eAAO,MAAM,MAAM;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAqBlB,CAAC;AAGF,eAAO,MAAM,UAAU;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAGrB,CAAC;AAGH,eAAO,MAAM,eAAe;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAoC3B,CAAC;AAGF,eAAO,MAAM,WAAW;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAuBvB,CAAC;AAGF,MAAM,MAAM,QAAQ,GAAG,OAAO,SAAS,CAAC,YAAY,CAAC;AACrD,MAAM,MAAM,WAAW,GAAG,OAAO,SAAS,CAAC,YAAY,CAAC;AACxD,MAAM,MAAM,KAAK,GAAG,OAAO,MAAM,CAAC,YAAY,CAAC;AAC/C,MAAM,MAAM,QAAQ,GAAG,OAAO,MAAM,CAAC,YAAY,CAAC;AAClD,MAAM,MAAM,SAAS,GAAG,OAAO,UAAU,CAAC,YAAY,CAAC;AACvD,MAAM,MAAM,cAAc,GAAG,OAAO,eAAe,CAAC,YAAY,CAAC;AACjE,MAAM,MAAM,iBAAiB,GAAG,OAAO,eAAe,CAAC,YAAY,CAAC;AACpE,MAAM,MAAM,UAAU,GAAG,OAAO,WAAW,CAAC,YAAY,CAAC"}
package/dist/schema.js ADDED
@@ -0,0 +1,101 @@
1
+ import { pgTable, text, timestamp, boolean, integer, json, date, index, unique, } from "drizzle-orm/pg-core";
2
+ // Page view events
3
+ export const pageViews = pgTable("page_views", {
4
+ id: text("id").primaryKey().$defaultFn(() => crypto.randomUUID()),
5
+ siteId: text("siteId").notNull(),
6
+ // Page info
7
+ url: text("url").notNull(),
8
+ pathname: text("pathname").notNull(),
9
+ referrer: text("referrer"),
10
+ // Visitor (cookieless identification)
11
+ visitorHash: text("visitorHash").notNull(),
12
+ sessionId: text("sessionId").notNull(),
13
+ // Location (from Vercel geo headers)
14
+ country: text("country"),
15
+ countryCode: text("countryCode"),
16
+ region: text("region"),
17
+ city: text("city"),
18
+ // Device (parsed from User-Agent)
19
+ browser: text("browser"),
20
+ browserVer: text("browserVer"),
21
+ os: text("os"),
22
+ osVer: text("osVer"),
23
+ device: text("device"),
24
+ // Optional user link
25
+ userId: text("userId"),
26
+ isBot: boolean("isBot").default(false).notNull(),
27
+ timestamp: timestamp("timestamp").defaultNow().notNull(),
28
+ }, (table) => [
29
+ index("page_views_site_timestamp_idx").on(table.siteId, table.timestamp),
30
+ index("page_views_site_pathname_idx").on(table.siteId, table.pathname),
31
+ index("page_views_session_idx").on(table.sessionId),
32
+ index("page_views_user_idx").on(table.userId),
33
+ ]);
34
+ // Custom events
35
+ export const events = pgTable("events", {
36
+ id: text("id").primaryKey().$defaultFn(() => crypto.randomUUID()),
37
+ siteId: text("siteId").notNull(),
38
+ name: text("name").notNull(),
39
+ properties: json("properties"),
40
+ visitorHash: text("visitorHash").notNull(),
41
+ sessionId: text("sessionId").notNull(),
42
+ userId: text("userId"),
43
+ url: text("url"),
44
+ timestamp: timestamp("timestamp").defaultNow().notNull(),
45
+ }, (table) => [
46
+ index("events_site_name_timestamp_idx").on(table.siteId, table.name, table.timestamp),
47
+ index("events_site_timestamp_idx").on(table.siteId, table.timestamp),
48
+ index("events_user_idx").on(table.userId),
49
+ ]);
50
+ // Daily salt for visitor hashing (privacy - rotates daily)
51
+ export const dailySalts = pgTable("daily_salts", {
52
+ date: date("date").primaryKey(),
53
+ salt: text("salt").notNull(),
54
+ });
55
+ // Error tracking - individual occurrences
56
+ export const analyticsErrors = pgTable("analytics_errors", {
57
+ id: text("id").primaryKey().$defaultFn(() => crypto.randomUUID()),
58
+ siteId: text("siteId").notNull(),
59
+ // Error details
60
+ message: text("message").notNull(),
61
+ stack: text("stack"),
62
+ fingerprint: text("fingerprint").notNull(),
63
+ // Context
64
+ url: text("url").notNull(),
65
+ pathname: text("pathname").notNull(),
66
+ // Visitor context
67
+ visitorHash: text("visitorHash"),
68
+ sessionId: text("sessionId"),
69
+ userId: text("userId"),
70
+ // Browser context
71
+ browser: text("browser"),
72
+ browserVer: text("browserVer"),
73
+ os: text("os"),
74
+ device: text("device"),
75
+ // Metadata
76
+ metadata: json("metadata"),
77
+ timestamp: timestamp("timestamp").defaultNow().notNull(),
78
+ }, (table) => [
79
+ index("errors_site_timestamp_idx").on(table.siteId, table.timestamp),
80
+ index("errors_site_fingerprint_idx").on(table.siteId, table.fingerprint),
81
+ index("errors_user_idx").on(table.userId),
82
+ ]);
83
+ // Error groups - aggregated by fingerprint
84
+ export const errorGroups = pgTable("error_groups", {
85
+ id: text("id").primaryKey().$defaultFn(() => crypto.randomUUID()),
86
+ siteId: text("siteId").notNull(),
87
+ fingerprint: text("fingerprint").notNull(),
88
+ // Representative error
89
+ message: text("message").notNull(),
90
+ stack: text("stack"),
91
+ // Counts
92
+ count: integer("count").default(1).notNull(),
93
+ lastSeen: timestamp("lastSeen").notNull(),
94
+ firstSeen: timestamp("firstSeen").notNull(),
95
+ // Status: open, resolved, ignored
96
+ status: text("status").default("open").notNull(),
97
+ }, (table) => [
98
+ unique("error_groups_site_fingerprint_unique").on(table.siteId, table.fingerprint),
99
+ index("error_groups_site_status_lastseen_idx").on(table.siteId, table.status, table.lastSeen),
100
+ ]);
101
+ //# sourceMappingURL=schema.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"schema.js","sourceRoot":"","sources":["../src/schema.ts"],"names":[],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"track.d.ts","sourceRoot":"","sources":["../src/track.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,oBAAoB,EAAE,iBAAiB,EAAE,MAAM,YAAY,CAAC;AAE1E,wBAAsB,aAAa,CACjC,OAAO,EAAE,oBAAoB,GAC5B,OAAO,CAAC,IAAI,CAAC,CAkEf;AAED,wBAAsB,UAAU,CAAC,OAAO,EAAE,iBAAiB,GAAG,OAAO,CAAC,IAAI,CAAC,CAuB1E"}
1
+ {"version":3,"file":"track.d.ts","sourceRoot":"","sources":["../src/track.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,oBAAoB,EAAE,iBAAiB,EAAE,MAAM,YAAY,CAAC;AAE1E,wBAAsB,aAAa,CACjC,OAAO,EAAE,oBAAoB,GAC5B,OAAO,CAAC,IAAI,CAAC,CAgEf;AAED,wBAAsB,UAAU,CAAC,OAAO,EAAE,iBAAiB,GAAG,OAAO,CAAC,IAAI,CAAC,CAqB1E"}
package/dist/track.js CHANGED
@@ -1,4 +1,5 @@
1
1
  import { getClient } from "./client.js";
2
+ import { pageViews, events } from "./schema.js";
2
3
  import { parseUserAgent } from "./ua.js";
3
4
  import { isBot, getVisitorInfo, extractPathname } from "./utils.js";
4
5
  export async function trackPageView(options) {
@@ -29,26 +30,24 @@ export async function trackPageView(options) {
29
30
  }
30
31
  }
31
32
  const db = getClient();
32
- await db.pageView.create({
33
- data: {
34
- siteId,
35
- url,
36
- pathname,
37
- referrer: cleanReferrer,
38
- visitorHash,
39
- sessionId,
40
- country: country ?? null,
41
- countryCode: countryCode ?? null,
42
- region: region ?? null,
43
- city: city ?? null,
44
- browser: ua.browser,
45
- browserVer: ua.browserVer,
46
- os: ua.os,
47
- osVer: ua.osVer,
48
- device: ua.device,
49
- userId,
50
- isBot: isBotRequest,
51
- },
33
+ await db.insert(pageViews).values({
34
+ siteId,
35
+ url,
36
+ pathname,
37
+ referrer: cleanReferrer,
38
+ visitorHash,
39
+ sessionId,
40
+ country: country ?? null,
41
+ countryCode: countryCode ?? null,
42
+ region: region ?? null,
43
+ city: city ?? null,
44
+ browser: ua.browser,
45
+ browserVer: ua.browserVer,
46
+ os: ua.os,
47
+ osVer: ua.osVer,
48
+ device: ua.device,
49
+ userId: userId ?? null,
50
+ isBot: isBotRequest,
52
51
  });
53
52
  }
54
53
  export async function trackEvent(options) {
@@ -59,16 +58,14 @@ export async function trackEvent(options) {
59
58
  // Get visitor info (hashes for privacy)
60
59
  const { visitorHash, sessionId } = await getVisitorInfo(ipNorm, uaNorm);
61
60
  const db = getClient();
62
- await db.event.create({
63
- data: {
64
- siteId,
65
- name,
66
- properties: properties,
67
- url,
68
- visitorHash,
69
- sessionId,
70
- userId,
71
- },
61
+ await db.insert(events).values({
62
+ siteId,
63
+ name,
64
+ properties: properties ?? null,
65
+ url: url ?? null,
66
+ visitorHash,
67
+ sessionId,
68
+ userId: userId ?? null,
72
69
  });
73
70
  }
74
71
  //# sourceMappingURL=track.js.map
package/dist/track.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"track.js","sourceRoot":"","sources":["../src/track.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"track.js","sourceRoot":"","sources":["../src/track.ts"],"names":[],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"utils.d.ts","sourceRoot":"","sources":["../src/utils.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AA6C9C,wBAAgB,KAAK,CAAC,SAAS,EAAE,MAAM,GAAG,IAAI,GAAG,OAAO,CAIvD;AAiCD,wBAAsB,cAAc,CAClC,EAAE,EAAE,MAAM,GAAG,IAAI,EACjB,SAAS,EAAE,MAAM,GAAG,IAAI,GACvB,OAAO,CAAC,WAAW,CAAC,CAgBtB;AAED,wBAAgB,eAAe,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CASnD;AAGD,wBAAsB,eAAe,IAAI,OAAO,CAAC,MAAM,CAAC,CAUvD"}
1
+ {"version":3,"file":"utils.d.ts","sourceRoot":"","sources":["../src/utils.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AA6C9C,wBAAgB,KAAK,CAAC,SAAS,EAAE,MAAM,GAAG,IAAI,GAAG,OAAO,CAIvD;AAsCD,wBAAsB,cAAc,CAClC,EAAE,EAAE,MAAM,GAAG,IAAI,EACjB,SAAS,EAAE,MAAM,GAAG,IAAI,GACvB,OAAO,CAAC,WAAW,CAAC,CAgBtB;AAED,wBAAgB,eAAe,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CASnD;AAGD,wBAAsB,eAAe,IAAI,OAAO,CAAC,MAAM,CAAC,CAYvD"}
package/dist/utils.js CHANGED
@@ -1,5 +1,7 @@
1
1
  import { createHash, randomBytes } from "crypto";
2
2
  import { getClient } from "./client.js";
3
+ import { dailySalts } from "./schema.js";
4
+ import { eq, lt } from "drizzle-orm";
3
5
  // Bot patterns to detect
4
6
  const BOT_PATTERNS = [
5
7
  /bot/i,
@@ -52,27 +54,32 @@ function hash(input) {
52
54
  }
53
55
  async function getDailySalt(date) {
54
56
  const db = getClient();
55
- const dateOnly = new Date(date.toISOString().split("T")[0] + "T00:00:00.000Z");
57
+ // Format date as YYYY-MM-DD string for the date column
58
+ const dateStr = date.toISOString().split("T")[0];
56
59
  // Try to get existing salt
57
- let dailySalt = await db.dailySalt.findUnique({
58
- where: { date: dateOnly },
59
- });
60
+ const [existingSalt] = await db
61
+ .select()
62
+ .from(dailySalts)
63
+ .where(eq(dailySalts.date, dateStr))
64
+ .limit(1);
65
+ if (existingSalt) {
66
+ return existingSalt.salt;
67
+ }
60
68
  // Create if doesn't exist
61
- if (!dailySalt) {
62
- const salt = randomBytes(32).toString("hex");
63
- try {
64
- dailySalt = await db.dailySalt.create({
65
- data: { date: dateOnly, salt },
66
- });
67
- }
68
- catch {
69
- // Race condition - another request created it
70
- dailySalt = await db.dailySalt.findUnique({
71
- where: { date: dateOnly },
72
- });
73
- }
69
+ const salt = randomBytes(32).toString("hex");
70
+ try {
71
+ await db.insert(dailySalts).values({ date: dateStr, salt });
72
+ return salt;
73
+ }
74
+ catch {
75
+ // Race condition - another request created it, try to fetch again
76
+ const [retry] = await db
77
+ .select()
78
+ .from(dailySalts)
79
+ .where(eq(dailySalts.date, dateStr))
80
+ .limit(1);
81
+ return retry?.salt ?? salt;
74
82
  }
75
- return dailySalt?.salt ?? randomBytes(32).toString("hex");
76
83
  }
77
84
  export async function getVisitorInfo(ip, userAgent) {
78
85
  const now = new Date();
@@ -104,9 +111,11 @@ export async function cleanupOldSalts() {
104
111
  const db = getClient();
105
112
  const sevenDaysAgo = new Date();
106
113
  sevenDaysAgo.setDate(sevenDaysAgo.getDate() - 7);
107
- const result = await db.dailySalt.deleteMany({
108
- where: { date: { lt: sevenDaysAgo } },
109
- });
110
- return result.count;
114
+ const dateStr = sevenDaysAgo.toISOString().split("T")[0];
115
+ const deleted = await db
116
+ .delete(dailySalts)
117
+ .where(lt(dailySalts.date, dateStr))
118
+ .returning({ date: dailySalts.date });
119
+ return deleted.length;
111
120
  }
112
121
  //# sourceMappingURL=utils.js.map
package/dist/utils.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"utils.js","sourceRoot":"","sources":["../src/utils.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"utils.js","sourceRoot":"","sources":["../src/utils.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@seneris/nosework",
3
- "version": "0.1.0",
3
+ "version": "0.2.0",
4
4
  "description": "Privacy-focused, self-hosted analytics for your app suite",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
@@ -17,16 +17,11 @@
17
17
  }
18
18
  },
19
19
  "files": [
20
- "dist",
21
- "prisma"
20
+ "dist"
22
21
  ],
23
22
  "scripts": {
24
23
  "build": "tsc",
25
24
  "dev": "tsc --watch",
26
- "db:generate": "prisma generate",
27
- "db:migrate": "prisma migrate dev",
28
- "db:push": "prisma db push",
29
- "postinstall": "prisma generate",
30
25
  "prepublishOnly": "bun run build"
31
26
  },
32
27
  "keywords": [
@@ -39,13 +34,13 @@
39
34
  "author": "",
40
35
  "license": "MIT",
41
36
  "dependencies": {
42
- "@prisma/client": "^6.2.1",
37
+ "drizzle-orm": "^0.38.3",
38
+ "postgres": "^3.4.5",
43
39
  "ua-parser-js": "^2.0.1"
44
40
  },
45
41
  "devDependencies": {
46
42
  "@types/bun": "^1.3.5",
47
43
  "@types/ua-parser-js": "^0.7.39",
48
- "prisma": "^6.2.1",
49
44
  "typescript": "^5.7.3"
50
45
  },
51
46
  "peerDependencies": {
@@ -1,145 +0,0 @@
1
- generator client {
2
- provider = "prisma-client-js"
3
- }
4
-
5
- datasource db {
6
- provider = "postgresql"
7
- url = env("ANALYTICS_DATABASE_URL")
8
- }
9
-
10
- model Site {
11
- id String @id @default(cuid())
12
- name String
13
- domain String @unique
14
- createdAt DateTime @default(now())
15
-
16
- pageViews PageView[]
17
- events Event[]
18
- errors Error[]
19
- errorGroups ErrorGroup[]
20
- }
21
-
22
- model PageView {
23
- id String @id @default(cuid())
24
- siteId String
25
- site Site @relation(fields: [siteId], references: [id], onDelete: Cascade)
26
-
27
- // Page info
28
- url String
29
- pathname String
30
- referrer String?
31
-
32
- // Visitor (cookieless)
33
- visitorHash String // Hash of IP + UA + daily salt
34
- sessionId String // Hash with shorter rotation (30 min)
35
-
36
- // Location (from GeoIP)
37
- country String?
38
- countryCode String?
39
- region String?
40
- city String?
41
-
42
- // Device (from User-Agent)
43
- browser String?
44
- browserVer String?
45
- os String?
46
- osVer String?
47
- device String? // desktop, mobile, tablet
48
-
49
- // User context (optional, from your OAuth)
50
- userId String?
51
-
52
- // Bot detection
53
- isBot Boolean @default(false)
54
-
55
- timestamp DateTime @default(now())
56
-
57
- @@index([siteId, timestamp])
58
- @@index([siteId, pathname])
59
- @@index([siteId, country])
60
- @@index([visitorHash, timestamp])
61
- @@index([sessionId])
62
- }
63
-
64
- model Event {
65
- id String @id @default(cuid())
66
- siteId String
67
- site Site @relation(fields: [siteId], references: [id], onDelete: Cascade)
68
-
69
- name String // e.g., "signup", "purchase", "button_click"
70
- properties Json? // Flexible event data
71
-
72
- visitorHash String
73
- sessionId String
74
- userId String?
75
-
76
- url String?
77
-
78
- timestamp DateTime @default(now())
79
-
80
- @@index([siteId, name, timestamp])
81
- @@index([siteId, timestamp])
82
- }
83
-
84
- // Daily salt for visitor hashing (privacy - rotates daily)
85
- model DailySalt {
86
- date DateTime @id @db.Date
87
- salt String
88
- }
89
-
90
- // Error tracking
91
- model Error {
92
- id String @id @default(cuid())
93
- siteId String
94
- site Site @relation(fields: [siteId], references: [id], onDelete: Cascade)
95
-
96
- // Error details
97
- message String
98
- stack String? @db.Text
99
- fingerprint String // Hash for grouping similar errors
100
-
101
- // Context
102
- url String
103
- pathname String
104
-
105
- // Visitor context (reuse existing pattern)
106
- visitorHash String?
107
- sessionId String?
108
- userId String?
109
-
110
- // Browser context
111
- browser String?
112
- browserVer String?
113
- os String?
114
- device String?
115
-
116
- // Metadata
117
- metadata Json? // Custom context from app
118
-
119
- timestamp DateTime @default(now())
120
-
121
- @@index([siteId, timestamp])
122
- @@index([siteId, fingerprint])
123
- }
124
-
125
- model ErrorGroup {
126
- id String @id @default(cuid())
127
- siteId String
128
- site Site @relation(fields: [siteId], references: [id], onDelete: Cascade)
129
- fingerprint String
130
-
131
- // Representative error
132
- message String
133
- stack String? @db.Text
134
-
135
- // Counts
136
- count Int @default(1)
137
- lastSeen DateTime
138
- firstSeen DateTime
139
-
140
- // Status: open, resolved, ignored
141
- status String @default("open")
142
-
143
- @@unique([siteId, fingerprint])
144
- @@index([siteId, status, lastSeen])
145
- }