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.
- package/dist/adapters/drizzle.d.mts +25 -0
- package/dist/adapters/drizzle.d.ts +25 -0
- package/dist/adapters/drizzle.js +38 -0
- package/dist/adapters/drizzle.mjs +7 -0
- package/dist/adapters/prisma.d.mts +25 -0
- package/dist/adapters/prisma.d.ts +25 -0
- package/dist/adapters/prisma.js +38 -0
- package/dist/adapters/prisma.mjs +7 -0
- package/dist/adapters.d.mts +7 -0
- package/dist/adapters.d.ts +7 -0
- package/dist/adapters.js +39 -0
- package/dist/adapters.mjs +8 -0
- package/dist/browser.d.mts +41 -0
- package/dist/browser.d.ts +41 -0
- package/dist/browser.js +79 -0
- package/dist/browser.mjs +10 -0
- package/dist/index.d.mts +59 -0
- package/dist/index.d.ts +59 -7
- package/dist/index.js +367 -7
- package/dist/index.mjs +336 -0
- package/dist/react.d.mts +48 -0
- package/dist/react.d.ts +48 -0
- package/dist/react.js +132 -0
- package/dist/react.mjs +61 -0
- package/dist/shared/chunk-8tbv1rg5.js +45 -0
- package/package.json +60 -48
- package/README.md +0 -73
- package/dist/client/LocallyticsGrabber.d.ts +0 -30
- package/dist/client/LocallyticsGrabber.d.ts.map +0 -1
- package/dist/client/LocallyticsGrabber.js +0 -71
- package/dist/client/LocallyticsGrabber.js.map +0 -1
- package/dist/client/batcher.d.ts +0 -48
- package/dist/client/batcher.d.ts.map +0 -1
- package/dist/client/batcher.js +0 -139
- package/dist/client/batcher.js.map +0 -1
- package/dist/client/tracker.d.ts +0 -18
- package/dist/client/tracker.d.ts.map +0 -1
- package/dist/client/tracker.js +0 -108
- package/dist/client/tracker.js.map +0 -1
- package/dist/db/factory.d.ts +0 -11
- package/dist/db/factory.d.ts.map +0 -1
- package/dist/db/factory.js +0 -47
- package/dist/db/factory.js.map +0 -1
- package/dist/db/mysql.d.ts +0 -17
- package/dist/db/mysql.d.ts.map +0 -1
- package/dist/db/mysql.js +0 -144
- package/dist/db/mysql.js.map +0 -1
- package/dist/db/postgres.d.ts +0 -16
- package/dist/db/postgres.d.ts.map +0 -1
- package/dist/db/postgres.js +0 -143
- package/dist/db/postgres.js.map +0 -1
- package/dist/db/sqlite.d.ts +0 -17
- package/dist/db/sqlite.d.ts.map +0 -1
- package/dist/db/sqlite.js +0 -130
- package/dist/db/sqlite.js.map +0 -1
- package/dist/index.d.ts.map +0 -1
- package/dist/index.js.map +0 -1
- package/dist/server/handlers.d.ts +0 -10
- package/dist/server/handlers.d.ts.map +0 -1
- package/dist/server/handlers.js +0 -105
- package/dist/server/handlers.js.map +0 -1
- package/dist/server/index.d.ts +0 -42
- package/dist/server/index.d.ts.map +0 -1
- package/dist/server/index.js +0 -100
- package/dist/server/index.js.map +0 -1
- package/dist/server/queries.d.ts +0 -10
- package/dist/server/queries.d.ts.map +0 -1
- package/dist/server/queries.js +0 -24
- package/dist/server/queries.js.map +0 -1
- package/dist/server/validator.d.ts +0 -32
- package/dist/server/validator.d.ts.map +0 -1
- package/dist/server/validator.js +0 -144
- package/dist/server/validator.js.map +0 -1
- package/dist/types/index.d.ts +0 -135
- package/dist/types/index.d.ts.map +0 -1
- package/dist/types/index.js +0 -24
- package/dist/types/index.js.map +0 -1
- package/dist/utils/hash.d.ts +0 -16
- package/dist/utils/hash.d.ts.map +0 -1
- package/dist/utils/hash.js +0 -36
- package/dist/utils/hash.js.map +0 -1
- package/dist/utils/rate-limit.d.ts +0 -32
- package/dist/utils/rate-limit.d.ts.map +0 -1
- package/dist/utils/rate-limit.js +0 -73
- package/dist/utils/rate-limit.js.map +0 -1
- package/src/db/schema-mysql.sql +0 -17
- package/src/db/schema-sqlite.sql +0 -29
- package/src/db/schema.sql +0 -35
package/dist/react.d.mts
ADDED
|
@@ -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.d.ts
ADDED
|
@@ -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.
|
|
4
|
-
"description": "
|
|
5
|
-
"
|
|
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
|
-
"
|
|
11
|
-
"
|
|
12
|
-
"
|
|
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
|
-
"./
|
|
15
|
-
|
|
16
|
-
|
|
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
|
-
"
|
|
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
|
-
"
|
|
51
|
-
"optional": true
|
|
52
|
-
},
|
|
53
|
-
"mysql2": {
|
|
67
|
+
"react": {
|
|
54
68
|
"optional": true
|
|
55
69
|
}
|
|
56
70
|
},
|
|
57
|
-
"
|
|
58
|
-
"
|
|
59
|
-
"
|
|
71
|
+
"scripts": {
|
|
72
|
+
"build": "bunup",
|
|
73
|
+
"dev": "bunup --watch",
|
|
74
|
+
"typecheck": "tsc --noEmit"
|
|
60
75
|
},
|
|
61
76
|
"devDependencies": {
|
|
62
|
-
"@types/
|
|
63
|
-
"
|
|
64
|
-
"
|
|
65
|
-
"
|
|
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"}
|