locallytics 0.1.8 → 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 (88) hide show
  1. package/dist/adapters/drizzle.d.mts +25 -0
  2. package/dist/adapters/drizzle.d.ts +25 -0
  3. package/dist/adapters/drizzle.js +38 -0
  4. package/dist/adapters/drizzle.mjs +7 -0
  5. package/dist/adapters/prisma.d.mts +25 -0
  6. package/dist/adapters/prisma.d.ts +25 -0
  7. package/dist/adapters/prisma.js +38 -0
  8. package/dist/adapters/prisma.mjs +7 -0
  9. package/dist/adapters.d.mts +7 -0
  10. package/dist/adapters.d.ts +7 -0
  11. package/dist/adapters.js +39 -0
  12. package/dist/adapters.mjs +8 -0
  13. package/dist/browser.d.mts +41 -0
  14. package/dist/browser.d.ts +41 -0
  15. package/dist/browser.js +79 -0
  16. package/dist/browser.mjs +10 -0
  17. package/dist/index.d.mts +59 -0
  18. package/dist/index.d.ts +59 -7
  19. package/dist/index.js +367 -7
  20. package/dist/index.mjs +336 -0
  21. package/dist/react.d.mts +48 -0
  22. package/dist/react.d.ts +48 -0
  23. package/dist/react.js +132 -0
  24. package/dist/react.mjs +61 -0
  25. package/dist/shared/chunk-8tbv1rg5.js +45 -0
  26. package/package.json +60 -48
  27. package/README.md +0 -73
  28. package/dist/client/LocallyticsGrabber.d.ts +0 -30
  29. package/dist/client/LocallyticsGrabber.d.ts.map +0 -1
  30. package/dist/client/LocallyticsGrabber.js +0 -71
  31. package/dist/client/LocallyticsGrabber.js.map +0 -1
  32. package/dist/client/batcher.d.ts +0 -48
  33. package/dist/client/batcher.d.ts.map +0 -1
  34. package/dist/client/batcher.js +0 -139
  35. package/dist/client/batcher.js.map +0 -1
  36. package/dist/client/tracker.d.ts +0 -18
  37. package/dist/client/tracker.d.ts.map +0 -1
  38. package/dist/client/tracker.js +0 -108
  39. package/dist/client/tracker.js.map +0 -1
  40. package/dist/db/factory.d.ts +0 -11
  41. package/dist/db/factory.d.ts.map +0 -1
  42. package/dist/db/factory.js +0 -47
  43. package/dist/db/factory.js.map +0 -1
  44. package/dist/db/mysql.d.ts +0 -17
  45. package/dist/db/mysql.d.ts.map +0 -1
  46. package/dist/db/mysql.js +0 -144
  47. package/dist/db/mysql.js.map +0 -1
  48. package/dist/db/postgres.d.ts +0 -16
  49. package/dist/db/postgres.d.ts.map +0 -1
  50. package/dist/db/postgres.js +0 -143
  51. package/dist/db/postgres.js.map +0 -1
  52. package/dist/db/sqlite.d.ts +0 -17
  53. package/dist/db/sqlite.d.ts.map +0 -1
  54. package/dist/db/sqlite.js +0 -130
  55. package/dist/db/sqlite.js.map +0 -1
  56. package/dist/index.d.ts.map +0 -1
  57. package/dist/index.js.map +0 -1
  58. package/dist/server/handlers.d.ts +0 -10
  59. package/dist/server/handlers.d.ts.map +0 -1
  60. package/dist/server/handlers.js +0 -105
  61. package/dist/server/handlers.js.map +0 -1
  62. package/dist/server/index.d.ts +0 -42
  63. package/dist/server/index.d.ts.map +0 -1
  64. package/dist/server/index.js +0 -100
  65. package/dist/server/index.js.map +0 -1
  66. package/dist/server/queries.d.ts +0 -10
  67. package/dist/server/queries.d.ts.map +0 -1
  68. package/dist/server/queries.js +0 -24
  69. package/dist/server/queries.js.map +0 -1
  70. package/dist/server/validator.d.ts +0 -32
  71. package/dist/server/validator.d.ts.map +0 -1
  72. package/dist/server/validator.js +0 -144
  73. package/dist/server/validator.js.map +0 -1
  74. package/dist/types/index.d.ts +0 -135
  75. package/dist/types/index.d.ts.map +0 -1
  76. package/dist/types/index.js +0 -24
  77. package/dist/types/index.js.map +0 -1
  78. package/dist/utils/hash.d.ts +0 -16
  79. package/dist/utils/hash.d.ts.map +0 -1
  80. package/dist/utils/hash.js +0 -36
  81. package/dist/utils/hash.js.map +0 -1
  82. package/dist/utils/rate-limit.d.ts +0 -32
  83. package/dist/utils/rate-limit.d.ts.map +0 -1
  84. package/dist/utils/rate-limit.js +0 -73
  85. package/dist/utils/rate-limit.js.map +0 -1
  86. package/src/db/schema-mysql.sql +0 -17
  87. package/src/db/schema-sqlite.sql +0 -29
  88. package/src/db/schema.sql +0 -35
@@ -0,0 +1,48 @@
1
+ /**
2
+ * Locallytics - Analytics built around a database-first API.
3
+ * @packageDocumentation
4
+ */
5
+ type LocallyticsEvent = {
6
+ id?: string | number;
7
+ type: string;
8
+ timestamp: number;
9
+ sessionId?: string;
10
+ userId?: string;
11
+ metadata?: Record<string, unknown>;
12
+ };
13
+ type ClientQueryResult = {
14
+ events: LocallyticsEvent[];
15
+ loading: boolean;
16
+ error: Error | null;
17
+ refresh: () => Promise<LocallyticsEvent[]>;
18
+ };
19
+ type QueryResult = ClientQueryResult & PromiseLike<LocallyticsEvent[]>;
20
+ interface Locallytics {
21
+ track(type: string, metadata?: Record<string, unknown>): Promise<LocallyticsEvent>;
22
+ trackPageView(route?: string): Promise<LocallyticsEvent>;
23
+ query(): QueryResult;
24
+ setUserId(userId: string | undefined): void;
25
+ getUserId(): string | undefined;
26
+ getSessionId(): string | undefined;
27
+ subscribe(listener: () => void): () => void;
28
+ }
29
+ import { ReactElement, ReactNode } from "react";
30
+ type LocallyticsProviderProps = {
31
+ instance: Locallytics;
32
+ children: ReactNode;
33
+ };
34
+ /**
35
+ * Client boundary for Locallytics context.
36
+ * Keep this component small so server-rendered children can stay server components.
37
+ */
38
+ declare function LocallyticsProvider({ instance, children }: LocallyticsProviderProps): ReactElement;
39
+ declare function useLocallytics(): Locallytics;
40
+ type LocallyticsGrabberProps = {
41
+ trackClicks?: boolean;
42
+ trackPageViews?: boolean;
43
+ };
44
+ /**
45
+ * Automatically tracks page views and clicks.
46
+ */
47
+ declare function LocallyticsGrabber({ trackClicks, trackPageViews }?: LocallyticsGrabberProps): null;
48
+ export { useLocallytics, LocallyticsProviderProps, LocallyticsProvider, LocallyticsGrabberProps, LocallyticsGrabber };
@@ -0,0 +1,48 @@
1
+ /**
2
+ * Locallytics - Analytics built around a database-first API.
3
+ * @packageDocumentation
4
+ */
5
+ type LocallyticsEvent = {
6
+ id?: string | number;
7
+ type: string;
8
+ timestamp: number;
9
+ sessionId?: string;
10
+ userId?: string;
11
+ metadata?: Record<string, unknown>;
12
+ };
13
+ type ClientQueryResult = {
14
+ events: LocallyticsEvent[];
15
+ loading: boolean;
16
+ error: Error | null;
17
+ refresh: () => Promise<LocallyticsEvent[]>;
18
+ };
19
+ type QueryResult = ClientQueryResult & PromiseLike<LocallyticsEvent[]>;
20
+ interface Locallytics {
21
+ track(type: string, metadata?: Record<string, unknown>): Promise<LocallyticsEvent>;
22
+ trackPageView(route?: string): Promise<LocallyticsEvent>;
23
+ query(): QueryResult;
24
+ setUserId(userId: string | undefined): void;
25
+ getUserId(): string | undefined;
26
+ getSessionId(): string | undefined;
27
+ subscribe(listener: () => void): () => void;
28
+ }
29
+ import { ReactElement, ReactNode } from "react";
30
+ type LocallyticsProviderProps = {
31
+ instance: Locallytics;
32
+ children: ReactNode;
33
+ };
34
+ /**
35
+ * Client boundary for Locallytics context.
36
+ * Keep this component small so server-rendered children can stay server components.
37
+ */
38
+ declare function LocallyticsProvider({ instance, children }: LocallyticsProviderProps): ReactElement;
39
+ declare function useLocallytics(): Locallytics;
40
+ type LocallyticsGrabberProps = {
41
+ trackClicks?: boolean;
42
+ trackPageViews?: boolean;
43
+ };
44
+ /**
45
+ * Automatically tracks page views and clicks.
46
+ */
47
+ declare function LocallyticsGrabber({ trackClicks, trackPageViews }?: LocallyticsGrabberProps): null;
48
+ export { useLocallytics, LocallyticsProviderProps, LocallyticsProvider, LocallyticsGrabberProps, LocallyticsGrabber };
package/dist/react.js ADDED
@@ -0,0 +1,132 @@
1
+ "use client";
2
+ var import_node_module = require("node:module");
3
+ var __defProp = Object.defineProperty;
4
+ var __getOwnPropNames = Object.getOwnPropertyNames;
5
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
6
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
7
+ var __moduleCache = /* @__PURE__ */ new WeakMap;
8
+ var __toCommonJS = (from) => {
9
+ var entry = __moduleCache.get(from), desc;
10
+ if (entry)
11
+ return entry;
12
+ entry = __defProp({}, "__esModule", { value: true });
13
+ if (from && typeof from === "object" || typeof from === "function")
14
+ __getOwnPropNames(from).map((key) => !__hasOwnProp.call(entry, key) && __defProp(entry, key, {
15
+ get: () => from[key],
16
+ enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable
17
+ }));
18
+ __moduleCache.set(from, entry);
19
+ return entry;
20
+ };
21
+ var __export = (target, all) => {
22
+ for (var name in all)
23
+ __defProp(target, name, {
24
+ get: all[name],
25
+ enumerable: true,
26
+ configurable: true,
27
+ set: (newValue) => all[name] = () => newValue
28
+ });
29
+ };
30
+
31
+ // src/browser.ts
32
+ var exports_browser = {};
33
+ __export(exports_browser, {
34
+ trackPageView: () => trackPageView,
35
+ bindPageViewTracking: () => bindPageViewTracking,
36
+ bindClickTracking: () => bindClickTracking
37
+ });
38
+ module.exports = __toCommonJS(exports_browser);
39
+ function trackPageView(locallytics, route) {
40
+ return locallytics.trackPageView(route).then(() => {
41
+ return;
42
+ });
43
+ }
44
+ function bindClickTracking(locallytics, target = window) {
45
+ const handler = (event) => {
46
+ const element = event.target;
47
+ locallytics.track("click", {
48
+ tag: element?.tagName,
49
+ id: element?.id,
50
+ classes: element?.className,
51
+ text: element?.textContent?.trim().slice(0, 100)
52
+ });
53
+ };
54
+ target.addEventListener("click", handler);
55
+ return () => {
56
+ target.removeEventListener("click", handler);
57
+ };
58
+ }
59
+ function bindPageViewTracking(locallytics) {
60
+ trackPageView(locallytics);
61
+ const popstateHandler = () => {
62
+ trackPageView(locallytics);
63
+ };
64
+ const originalPushState = history.pushState;
65
+ const originalReplaceState = history.replaceState;
66
+ history.pushState = function(...args) {
67
+ originalPushState.apply(this, args);
68
+ trackPageView(locallytics);
69
+ };
70
+ history.replaceState = function(...args) {
71
+ originalReplaceState.apply(this, args);
72
+ trackPageView(locallytics);
73
+ };
74
+ window.addEventListener("popstate", popstateHandler);
75
+ return () => {
76
+ window.removeEventListener("popstate", popstateHandler);
77
+ history.pushState = originalPushState;
78
+ history.replaceState = originalReplaceState;
79
+ };
80
+ }
81
+
82
+ // src/react.tsx
83
+ var exports_react = {};
84
+ __export(exports_react, {
85
+ useLocallytics: () => useLocallytics,
86
+ LocallyticsProvider: () => LocallyticsProvider,
87
+ LocallyticsGrabber: () => LocallyticsGrabber
88
+ });
89
+ module.exports = __toCommonJS(exports_react);
90
+ var import_react = require("react");
91
+
92
+ var LocallyticsContext = import_react.createContext(null);
93
+ function LocallyticsProvider({
94
+ instance,
95
+ children
96
+ }) {
97
+ const [, setVersion] = import_react.useState(0);
98
+ import_react.useEffect(() => {
99
+ return instance.subscribe(() => {
100
+ setVersion((value) => value + 1);
101
+ });
102
+ }, [instance]);
103
+ return import_react.createElement(LocallyticsContext.Provider, { value: instance }, children);
104
+ }
105
+ function useLocallytics() {
106
+ const instance = import_react.useContext(LocallyticsContext);
107
+ if (!instance) {
108
+ throw new Error("useLocallytics must be used within a LocallyticsProvider");
109
+ }
110
+ return instance;
111
+ }
112
+ function LocallyticsGrabber({
113
+ trackClicks = true,
114
+ trackPageViews = true
115
+ } = {}) {
116
+ const locallytics = useLocallytics();
117
+ import_react.useEffect(() => {
118
+ const cleanups = [];
119
+ if (trackPageViews) {
120
+ cleanups.push(bindPageViewTracking(locallytics));
121
+ }
122
+ if (trackClicks) {
123
+ cleanups.push(bindClickTracking(locallytics, window));
124
+ }
125
+ return () => {
126
+ for (const cleanup of cleanups) {
127
+ cleanup();
128
+ }
129
+ };
130
+ }, [locallytics, trackClicks, trackPageViews]);
131
+ return null;
132
+ }
package/dist/react.mjs ADDED
@@ -0,0 +1,61 @@
1
+ "use client";
2
+ import {
3
+ bindClickTracking,
4
+ bindPageViewTracking
5
+ } from "./shared/chunk-8tbv1rg5.js";
6
+
7
+ // src/react.tsx
8
+ import {
9
+ createElement,
10
+ createContext,
11
+ useContext,
12
+ useEffect,
13
+ useState
14
+ } from "react";
15
+
16
+ var LocallyticsContext = createContext(null);
17
+ function LocallyticsProvider({
18
+ instance,
19
+ children
20
+ }) {
21
+ const [, setVersion] = useState(0);
22
+ useEffect(() => {
23
+ return instance.subscribe(() => {
24
+ setVersion((value) => value + 1);
25
+ });
26
+ }, [instance]);
27
+ return createElement(LocallyticsContext.Provider, { value: instance }, children);
28
+ }
29
+ function useLocallytics() {
30
+ const instance = useContext(LocallyticsContext);
31
+ if (!instance) {
32
+ throw new Error("useLocallytics must be used within a LocallyticsProvider");
33
+ }
34
+ return instance;
35
+ }
36
+ function LocallyticsGrabber({
37
+ trackClicks = true,
38
+ trackPageViews = true
39
+ } = {}) {
40
+ const locallytics = useLocallytics();
41
+ useEffect(() => {
42
+ const cleanups = [];
43
+ if (trackPageViews) {
44
+ cleanups.push(bindPageViewTracking(locallytics));
45
+ }
46
+ if (trackClicks) {
47
+ cleanups.push(bindClickTracking(locallytics, window));
48
+ }
49
+ return () => {
50
+ for (const cleanup of cleanups) {
51
+ cleanup();
52
+ }
53
+ };
54
+ }, [locallytics, trackClicks, trackPageViews]);
55
+ return null;
56
+ }
57
+ export {
58
+ useLocallytics,
59
+ LocallyticsProvider,
60
+ LocallyticsGrabber
61
+ };
@@ -0,0 +1,45 @@
1
+ // src/browser.ts
2
+ function trackPageView(locallytics, route) {
3
+ return locallytics.trackPageView(route).then(() => {
4
+ return;
5
+ });
6
+ }
7
+ function bindClickTracking(locallytics, target = window) {
8
+ const handler = (event) => {
9
+ const element = event.target;
10
+ locallytics.track("click", {
11
+ tag: element?.tagName,
12
+ id: element?.id,
13
+ classes: element?.className,
14
+ text: element?.textContent?.trim().slice(0, 100)
15
+ });
16
+ };
17
+ target.addEventListener("click", handler);
18
+ return () => {
19
+ target.removeEventListener("click", handler);
20
+ };
21
+ }
22
+ function bindPageViewTracking(locallytics) {
23
+ trackPageView(locallytics);
24
+ const popstateHandler = () => {
25
+ trackPageView(locallytics);
26
+ };
27
+ const originalPushState = history.pushState;
28
+ const originalReplaceState = history.replaceState;
29
+ history.pushState = function(...args) {
30
+ originalPushState.apply(this, args);
31
+ trackPageView(locallytics);
32
+ };
33
+ history.replaceState = function(...args) {
34
+ originalReplaceState.apply(this, args);
35
+ trackPageView(locallytics);
36
+ };
37
+ window.addEventListener("popstate", popstateHandler);
38
+ return () => {
39
+ window.removeEventListener("popstate", popstateHandler);
40
+ history.pushState = originalPushState;
41
+ history.replaceState = originalReplaceState;
42
+ };
43
+ }
44
+
45
+ export { trackPageView, bindClickTracking, bindPageViewTracking };
package/package.json CHANGED
@@ -1,70 +1,82 @@
1
1
  {
2
2
  "name": "locallytics",
3
- "version": "0.1.8",
4
- "description": "Self-hosted, privacy-first analytics SDK for Next.js",
5
- "type": "module",
3
+ "version": "0.2.0",
4
+ "description": "Simple analytics that lives with your app.",
5
+ "keywords": [
6
+ "analytics",
7
+ "kysely",
8
+ "postgres",
9
+ "sqlite",
10
+ "mysql",
11
+ "react",
12
+ "nextjs"
13
+ ],
14
+ "author": "Aidan McAlister",
15
+ "license": "MIT",
16
+ "repository": {
17
+ "type": "git",
18
+ "url": "git+https://github.com/aidankmcalister/locallytics.git"
19
+ },
20
+ "homepage": "https://github.com/aidankmcalister/locallytics#readme",
21
+ "bugs": {
22
+ "url": "https://github.com/aidankmcalister/locallytics/issues"
23
+ },
6
24
  "main": "./dist/index.js",
25
+ "module": "./dist/index.mjs",
7
26
  "types": "./dist/index.d.ts",
8
27
  "exports": {
9
28
  ".": {
10
- "types": "./dist/index.d.ts",
11
- "import": "./dist/index.js",
12
- "default": "./dist/index.js"
29
+ "import": "./dist/index.mjs",
30
+ "require": "./dist/index.js",
31
+ "types": "./dist/index.d.ts"
32
+ },
33
+ "./adapters": {
34
+ "import": "./dist/adapters.mjs",
35
+ "require": "./dist/adapters.js",
36
+ "types": "./dist/adapters.d.ts"
37
+ },
38
+ "./adapters/prisma": {
39
+ "import": "./dist/adapters/prisma.mjs",
40
+ "require": "./dist/adapters/prisma.js",
41
+ "types": "./dist/adapters/prisma.d.ts"
13
42
  },
14
- "./schema.sql": "./src/db/schema.sql",
15
- "./schema-sqlite.sql": "./src/db/schema-sqlite.sql",
16
- "./schema-mysql.sql": "./src/db/schema-mysql.sql"
43
+ "./adapters/drizzle": {
44
+ "import": "./dist/adapters/drizzle.mjs",
45
+ "require": "./dist/adapters/drizzle.js",
46
+ "types": "./dist/adapters/drizzle.d.ts"
47
+ },
48
+ "./browser": {
49
+ "import": "./dist/browser.mjs",
50
+ "require": "./dist/browser.js",
51
+ "types": "./dist/browser.d.ts"
52
+ },
53
+ "./react": {
54
+ "import": "./dist/react.mjs",
55
+ "require": "./dist/react.js",
56
+ "types": "./dist/react.d.ts"
57
+ }
17
58
  },
18
59
  "files": [
19
60
  "dist",
20
- "src/db/schema.sql",
21
- "src/db/schema-sqlite.sql",
22
- "src/db/schema-mysql.sql"
61
+ "README.md"
23
62
  ],
24
- "scripts": {
25
- "build": "tsc",
26
- "dev": "tsc --watch",
27
- "typecheck": "tsc --noEmit",
28
- "test": "vitest",
29
- "prepublishOnly": "npm run build"
30
- },
31
- "keywords": [
32
- "analytics",
33
- "privacy",
34
- "nextjs",
35
- "postgresql",
36
- "mysql",
37
- "sqlite",
38
- "self-hosted"
39
- ],
40
- "author": "",
41
- "license": "MIT",
42
- "dependencies": {
43
- "pg": "^8.11.3"
44
- },
45
63
  "peerDependencies": {
46
- "next": ">=13.0.0",
47
64
  "react": ">=18.0.0"
48
65
  },
49
66
  "peerDependenciesMeta": {
50
- "better-sqlite3": {
51
- "optional": true
52
- },
53
- "mysql2": {
67
+ "react": {
54
68
  "optional": true
55
69
  }
56
70
  },
57
- "optionalDependencies": {
58
- "better-sqlite3": "^11.0.0",
59
- "mysql2": "^3.9.0"
71
+ "scripts": {
72
+ "build": "bunup",
73
+ "dev": "bunup --watch",
74
+ "typecheck": "tsc --noEmit"
60
75
  },
61
76
  "devDependencies": {
62
- "@types/better-sqlite3": "^7.6.8",
63
- "@types/node": "^20.10.0",
64
- "@types/pg": "^8.10.9",
65
- "@types/react": "^18.2.0",
66
- "mysql2": "^3.16.1",
67
- "typescript": "^5.3.0",
68
- "vitest": "^1.1.0"
77
+ "@types/react": "^19.0.0",
78
+ "bunup": "^0.16.26",
79
+ "react": "^19.0.0",
80
+ "typescript": "^5.9.3"
69
81
  }
70
82
  }
package/README.md DELETED
@@ -1,73 +0,0 @@
1
- # Locallytics
2
-
3
- Self-hosted, privacy-first analytics SDK for Next.js.
4
-
5
- ## Installation
6
-
7
- ```bash
8
- npm install locallytics
9
- ```
10
-
11
- ## Quick Start
12
-
13
- ### 1. Setup Database
14
-
15
- Use our CLI to set up your PostgreSQL database automatically:
16
-
17
- ```bash
18
- npx locallytics-cli migrate
19
- ```
20
-
21
- ### 2. Add API Route
22
-
23
- ```typescript
24
- // app/api/analytics/route.ts
25
- import { locallytics } from "locallytics";
26
-
27
- const analytics = await locallytics({
28
- database: process.env.DATABASE_URL!,
29
- });
30
-
31
- export const { GET, POST } = analytics;
32
- ```
33
-
34
- ### 3. Add Tracker
35
-
36
- ```tsx
37
- // app/layout.tsx
38
- import { LocallyticsGrabber } from "locallytics";
39
-
40
- export default function RootLayout({ children }) {
41
- return (
42
- <html>
43
- <body>
44
- {children}
45
- <LocallyticsGrabber />
46
- </body>
47
- </html>
48
- );
49
- }
50
- ```
51
-
52
- ### 4. Fetch Data
53
-
54
- ```tsx
55
- // app/page.tsx
56
- import { LocallyticsData } from "locallytics";
57
-
58
- export default async function Home() {
59
- const data = await LocallyticsData(); // Simple! No arguments.
60
-
61
- return <pre>{JSON.stringify(data, null, 2)}</pre>;
62
- }
63
- ```
64
-
65
- ## Features
66
-
67
- - **Privacy**: No cookies, hashed IPs, supports Do Not Track.
68
- - **Simplicity**: Zero-config data fetching.
69
- - **Speed**: Lightweight (< 5KB) and fast.
70
-
71
- ## License
72
-
73
- MIT
@@ -1,30 +0,0 @@
1
- interface LocallyticsGrabberProps {
2
- /** API endpoint URL (defaults to /api/analytics) */
3
- endpoint?: string;
4
- /** Interval in ms to batch events before sending (defaults to 30000) */
5
- trackInterval?: number;
6
- }
7
- /**
8
- * React component for tracking pageviews
9
- * Drop this into your layout to automatically track pageviews
10
- *
11
- * @example
12
- * ```tsx
13
- * // app/layout.tsx
14
- * import { LocallyticsGrabber } from 'locallytics';
15
- *
16
- * export default function RootLayout({ children }) {
17
- * return (
18
- * <html>
19
- * <body>
20
- * {children}
21
- * <LocallyticsGrabber maxLength={5} trackInterval={5000} />
22
- * </body>
23
- * </html>
24
- * );
25
- * }
26
- * ```
27
- */
28
- export declare function LocallyticsGrabber({ endpoint, trackInterval, }: LocallyticsGrabberProps): null;
29
- export {};
30
- //# sourceMappingURL=LocallyticsGrabber.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"LocallyticsGrabber.d.ts","sourceRoot":"","sources":["../../src/client/LocallyticsGrabber.tsx"],"names":[],"mappings":"AAKA,UAAU,uBAAuB;IAC/B,oDAAoD;IACpD,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,wEAAwE;IACxE,aAAa,CAAC,EAAE,MAAM,CAAC;CACxB;AAED;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,wBAAgB,kBAAkB,CAAC,EACjC,QAA2B,EAC3B,aAAa,GACd,EAAE,uBAAuB,GAAG,IAAI,CAuDhC"}
@@ -1,71 +0,0 @@
1
- "use client";
2
- import { useEffect, useRef } from "react";
3
- import { Tracker } from "./tracker.js";
4
- /**
5
- * React component for tracking pageviews
6
- * Drop this into your layout to automatically track pageviews
7
- *
8
- * @example
9
- * ```tsx
10
- * // app/layout.tsx
11
- * import { LocallyticsGrabber } from 'locallytics';
12
- *
13
- * export default function RootLayout({ children }) {
14
- * return (
15
- * <html>
16
- * <body>
17
- * {children}
18
- * <LocallyticsGrabber maxLength={5} trackInterval={5000} />
19
- * </body>
20
- * </html>
21
- * );
22
- * }
23
- * ```
24
- */
25
- export function LocallyticsGrabber({ endpoint = "/api/analytics", trackInterval, }) {
26
- const trackerRef = useRef(null);
27
- const lastPathRef = useRef("");
28
- useEffect(() => {
29
- // Initialize tracker
30
- const tracker = new Tracker(endpoint, trackInterval);
31
- trackerRef.current = tracker;
32
- // Track initial pageview
33
- tracker.trackPageview();
34
- lastPathRef.current = window.location.pathname;
35
- // Handle browser back/forward navigation
36
- const handlePopstate = () => {
37
- if (window.location.pathname !== lastPathRef.current) {
38
- lastPathRef.current = window.location.pathname;
39
- tracker.trackPageview();
40
- }
41
- };
42
- window.addEventListener("popstate", handlePopstate);
43
- // Handle client-side navigation (Next.js App Router)
44
- // Use MutationObserver to detect URL changes
45
- let observer = null;
46
- const checkForNavigation = () => {
47
- if (window.location.pathname !== lastPathRef.current) {
48
- lastPathRef.current = window.location.pathname;
49
- tracker.trackPageview();
50
- }
51
- };
52
- // Observe changes to the document that might indicate navigation
53
- observer = new MutationObserver(() => {
54
- // Use requestAnimationFrame to batch checks
55
- requestAnimationFrame(checkForNavigation);
56
- });
57
- observer.observe(document, {
58
- subtree: true,
59
- childList: true,
60
- });
61
- // Cleanup
62
- return () => {
63
- window.removeEventListener("popstate", handlePopstate);
64
- observer?.disconnect();
65
- tracker.destroy();
66
- };
67
- }, [endpoint, trackInterval]);
68
- // This component renders nothing
69
- return null;
70
- }
71
- //# sourceMappingURL=LocallyticsGrabber.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"LocallyticsGrabber.js","sourceRoot":"","sources":["../../src/client/LocallyticsGrabber.tsx"],"names":[],"mappings":"AAAA,YAAY,CAAC;AAEb,OAAO,EAAE,SAAS,EAAE,MAAM,EAAE,MAAM,OAAO,CAAC;AAC1C,OAAO,EAAE,OAAO,EAAE,MAAM,cAAc,CAAC;AASvC;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,MAAM,UAAU,kBAAkB,CAAC,EACjC,QAAQ,GAAG,gBAAgB,EAC3B,aAAa,GACW;IACxB,MAAM,UAAU,GAAG,MAAM,CAAiB,IAAI,CAAC,CAAC;IAChD,MAAM,WAAW,GAAG,MAAM,CAAS,EAAE,CAAC,CAAC;IAEvC,SAAS,CAAC,GAAG,EAAE;QACb,qBAAqB;QACrB,MAAM,OAAO,GAAG,IAAI,OAAO,CAAC,QAAQ,EAAE,aAAa,CAAC,CAAC;QACrD,UAAU,CAAC,OAAO,GAAG,OAAO,CAAC;QAE7B,yBAAyB;QACzB,OAAO,CAAC,aAAa,EAAE,CAAC;QACxB,WAAW,CAAC,OAAO,GAAG,MAAM,CAAC,QAAQ,CAAC,QAAQ,CAAC;QAE/C,yCAAyC;QACzC,MAAM,cAAc,GAAG,GAAS,EAAE;YAChC,IAAI,MAAM,CAAC,QAAQ,CAAC,QAAQ,KAAK,WAAW,CAAC,OAAO,EAAE,CAAC;gBACrD,WAAW,CAAC,OAAO,GAAG,MAAM,CAAC,QAAQ,CAAC,QAAQ,CAAC;gBAC/C,OAAO,CAAC,aAAa,EAAE,CAAC;YAC1B,CAAC;QACH,CAAC,CAAC;QAEF,MAAM,CAAC,gBAAgB,CAAC,UAAU,EAAE,cAAc,CAAC,CAAC;QAEpD,qDAAqD;QACrD,6CAA6C;QAC7C,IAAI,QAAQ,GAA4B,IAAI,CAAC;QAE7C,MAAM,kBAAkB,GAAG,GAAS,EAAE;YACpC,IAAI,MAAM,CAAC,QAAQ,CAAC,QAAQ,KAAK,WAAW,CAAC,OAAO,EAAE,CAAC;gBACrD,WAAW,CAAC,OAAO,GAAG,MAAM,CAAC,QAAQ,CAAC,QAAQ,CAAC;gBAC/C,OAAO,CAAC,aAAa,EAAE,CAAC;YAC1B,CAAC;QACH,CAAC,CAAC;QAEF,iEAAiE;QACjE,QAAQ,GAAG,IAAI,gBAAgB,CAAC,GAAG,EAAE;YACnC,4CAA4C;YAC5C,qBAAqB,CAAC,kBAAkB,CAAC,CAAC;QAC5C,CAAC,CAAC,CAAC;QAEH,QAAQ,CAAC,OAAO,CAAC,QAAQ,EAAE;YACzB,OAAO,EAAE,IAAI;YACb,SAAS,EAAE,IAAI;SAChB,CAAC,CAAC;QAEH,UAAU;QACV,OAAO,GAAG,EAAE;YACV,MAAM,CAAC,mBAAmB,CAAC,UAAU,EAAE,cAAc,CAAC,CAAC;YACvD,QAAQ,EAAE,UAAU,EAAE,CAAC;YACvB,OAAO,CAAC,OAAO,EAAE,CAAC;QACpB,CAAC,CAAC;IACJ,CAAC,EAAE,CAAC,QAAQ,EAAE,aAAa,CAAC,CAAC,CAAC;IAE9B,iCAAiC;IACjC,OAAO,IAAI,CAAC;AACd,CAAC"}