2027-track 0.1.1 → 0.1.2
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/README.md +31 -0
- package/dist/chunk-2UMSOEKA.mjs +46 -0
- package/dist/index.js +2 -2
- package/dist/index.mjs +1 -1
- package/dist/next.js +12 -10
- package/dist/next.mjs +11 -9
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -34,6 +34,37 @@ await trackVisit({
|
|
|
34
34
|
});
|
|
35
35
|
```
|
|
36
36
|
|
|
37
|
+
## Route Filtering
|
|
38
|
+
|
|
39
|
+
**Important:** Only track public documentation routes. Exclude private endpoints to avoid leaking sensitive paths.
|
|
40
|
+
|
|
41
|
+
### Next.js matcher (recommended)
|
|
42
|
+
|
|
43
|
+
```ts
|
|
44
|
+
// middleware.ts
|
|
45
|
+
import { withAIAnalytics } from "2027-track/next";
|
|
46
|
+
|
|
47
|
+
export default withAIAnalytics();
|
|
48
|
+
|
|
49
|
+
export const config = {
|
|
50
|
+
matcher: [
|
|
51
|
+
// Exclude private routes, track everything else
|
|
52
|
+
"/((?!api|_next|app|admin|dashboard|auth|login|signup).*)",
|
|
53
|
+
],
|
|
54
|
+
};
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
### Manual filtering
|
|
58
|
+
|
|
59
|
+
```ts
|
|
60
|
+
import { trackVisit } from "2027-track";
|
|
61
|
+
|
|
62
|
+
// Only track if path starts with /docs
|
|
63
|
+
if (path.startsWith("/docs")) {
|
|
64
|
+
await trackVisit({ host, path, userAgent, accept });
|
|
65
|
+
}
|
|
66
|
+
```
|
|
67
|
+
|
|
37
68
|
## Configuration
|
|
38
69
|
|
|
39
70
|
### Kill switch
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
// src/index.ts
|
|
2
|
+
var DEFAULT_ENDPOINT = "https://ai-docs-analytics-api.theisease.workers.dev/track";
|
|
3
|
+
var TIMEOUT_MS = 2500;
|
|
4
|
+
function getEndpoint() {
|
|
5
|
+
const env = typeof process !== "undefined" ? process.env.AI_ANALYTICS_ENDPOINT : void 0;
|
|
6
|
+
if (env === "") return null;
|
|
7
|
+
return env || DEFAULT_ENDPOINT;
|
|
8
|
+
}
|
|
9
|
+
function isPageView(accept) {
|
|
10
|
+
const a = accept.toLowerCase();
|
|
11
|
+
return a.includes("text/html") || a.includes("text/markdown");
|
|
12
|
+
}
|
|
13
|
+
async function trackVisit(options) {
|
|
14
|
+
const endpoint = getEndpoint();
|
|
15
|
+
if (!endpoint) {
|
|
16
|
+
return { ok: true, skipped: "disabled" };
|
|
17
|
+
}
|
|
18
|
+
if (!isPageView(options.accept)) {
|
|
19
|
+
return { ok: true, skipped: "not-page-view" };
|
|
20
|
+
}
|
|
21
|
+
const controller = new AbortController();
|
|
22
|
+
const timeoutId = setTimeout(() => controller.abort(), TIMEOUT_MS);
|
|
23
|
+
try {
|
|
24
|
+
const response = await fetch(endpoint, {
|
|
25
|
+
method: "POST",
|
|
26
|
+
headers: { "Content-Type": "application/json" },
|
|
27
|
+
body: JSON.stringify({
|
|
28
|
+
host: options.host,
|
|
29
|
+
path: options.path,
|
|
30
|
+
user_agent: options.userAgent,
|
|
31
|
+
accept: options.accept,
|
|
32
|
+
country: options.country || "unknown"
|
|
33
|
+
}),
|
|
34
|
+
signal: controller.signal
|
|
35
|
+
});
|
|
36
|
+
clearTimeout(timeoutId);
|
|
37
|
+
return await response.json();
|
|
38
|
+
} catch (e) {
|
|
39
|
+
clearTimeout(timeoutId);
|
|
40
|
+
return { ok: false, error: e instanceof Error ? e.message : "unknown error" };
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
export {
|
|
45
|
+
trackVisit
|
|
46
|
+
};
|
package/dist/index.js
CHANGED
|
@@ -30,7 +30,7 @@ function getEndpoint() {
|
|
|
30
30
|
if (env === "") return null;
|
|
31
31
|
return env || DEFAULT_ENDPOINT;
|
|
32
32
|
}
|
|
33
|
-
function
|
|
33
|
+
function isPageView(accept) {
|
|
34
34
|
const a = accept.toLowerCase();
|
|
35
35
|
return a.includes("text/html") || a.includes("text/markdown");
|
|
36
36
|
}
|
|
@@ -39,7 +39,7 @@ async function trackVisit(options) {
|
|
|
39
39
|
if (!endpoint) {
|
|
40
40
|
return { ok: true, skipped: "disabled" };
|
|
41
41
|
}
|
|
42
|
-
if (!
|
|
42
|
+
if (!isPageView(options.accept)) {
|
|
43
43
|
return { ok: true, skipped: "not-page-view" };
|
|
44
44
|
}
|
|
45
45
|
const controller = new AbortController();
|
package/dist/index.mjs
CHANGED
package/dist/next.js
CHANGED
|
@@ -34,7 +34,7 @@ function getEndpoint() {
|
|
|
34
34
|
if (env === "") return null;
|
|
35
35
|
return env || DEFAULT_ENDPOINT;
|
|
36
36
|
}
|
|
37
|
-
function
|
|
37
|
+
function isPageView(accept) {
|
|
38
38
|
const a = accept.toLowerCase();
|
|
39
39
|
return a.includes("text/html") || a.includes("text/markdown");
|
|
40
40
|
}
|
|
@@ -43,7 +43,7 @@ async function trackVisit(options) {
|
|
|
43
43
|
if (!endpoint) {
|
|
44
44
|
return { ok: true, skipped: "disabled" };
|
|
45
45
|
}
|
|
46
|
-
if (!
|
|
46
|
+
if (!isPageView(options.accept)) {
|
|
47
47
|
return { ok: true, skipped: "not-page-view" };
|
|
48
48
|
}
|
|
49
49
|
const controller = new AbortController();
|
|
@@ -73,14 +73,16 @@ async function trackVisit(options) {
|
|
|
73
73
|
function withAIAnalytics(middleware) {
|
|
74
74
|
return async (request, event) => {
|
|
75
75
|
const response = middleware ? await middleware(request, event) : import_server.NextResponse.next();
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
76
|
+
event.waitUntil(
|
|
77
|
+
trackVisit({
|
|
78
|
+
host: request.headers.get("host") || request.nextUrl.host,
|
|
79
|
+
path: request.nextUrl.pathname,
|
|
80
|
+
userAgent: request.headers.get("user-agent") || "",
|
|
81
|
+
accept: request.headers.get("accept") || "",
|
|
82
|
+
country: request.geo?.country || "unknown"
|
|
83
|
+
}).catch(() => {
|
|
84
|
+
})
|
|
85
|
+
);
|
|
84
86
|
return response;
|
|
85
87
|
};
|
|
86
88
|
}
|
package/dist/next.mjs
CHANGED
|
@@ -1,20 +1,22 @@
|
|
|
1
1
|
import {
|
|
2
2
|
trackVisit
|
|
3
|
-
} from "./chunk-
|
|
3
|
+
} from "./chunk-2UMSOEKA.mjs";
|
|
4
4
|
|
|
5
5
|
// src/next.ts
|
|
6
6
|
import { NextResponse } from "next/server";
|
|
7
7
|
function withAIAnalytics(middleware) {
|
|
8
8
|
return async (request, event) => {
|
|
9
9
|
const response = middleware ? await middleware(request, event) : NextResponse.next();
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
10
|
+
event.waitUntil(
|
|
11
|
+
trackVisit({
|
|
12
|
+
host: request.headers.get("host") || request.nextUrl.host,
|
|
13
|
+
path: request.nextUrl.pathname,
|
|
14
|
+
userAgent: request.headers.get("user-agent") || "",
|
|
15
|
+
accept: request.headers.get("accept") || "",
|
|
16
|
+
country: request.geo?.country || "unknown"
|
|
17
|
+
}).catch(() => {
|
|
18
|
+
})
|
|
19
|
+
);
|
|
18
20
|
return response;
|
|
19
21
|
};
|
|
20
22
|
}
|