Skip to content

Commit 322f02f

Browse files
committed
refactor(server): improve structure
1 parent 0df7382 commit 322f02f

4 files changed

Lines changed: 33 additions & 77 deletions

File tree

packages/analytics/src/server/interfaces.ts

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -40,10 +40,10 @@ export interface IgnoredMetrics {
4040
language?: boolean | undefined;
4141
}
4242

43-
export type ServerComponentSearchParamsProp = Record<string, string | string[] | undefined>;
43+
export type ServerContext = ServerContextWithRequest | ServerContextWithPath;
4444

45-
export type ServerContextWithPath =
46-
| { request: Request }
47-
| { path: string; headers: Headers, searchParams?: Record<string, string | string[] | undefined> };
45+
export type ServerContextWithRequest = { request: Request };
4846

49-
export type PageviewServerContext = { path: string; headers: Headers, searchParams: URLSearchParams };
47+
export type HeaderOnlyContext = { headers: Headers };
48+
49+
export type ServerContextWithPath = { path: string; headers: Headers, searchParams?: Record<string, string | string[] | undefined> };

packages/analytics/src/server/simple-analytics.ts

Lines changed: 7 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,16 @@
11
import "server-only";
22

3-
import type { AnalyticsEvent, AnalyticsPageview, ServerContextWithPath } from "./interfaces";
3+
import { AnalyticsEvent, AnalyticsPageview, HeaderOnlyContext, ServerContext } from "./interfaces";
44
import type { AnalyticsMetadata } from "../interfaces";
5-
import { isDoNotTrackEnabled, parseServerContext } from "./utils";
5+
import { isDoNotTrackEnabled, parseRequest } from "./utils";
66
import { parseHeaders } from "./headers";
77
import { parseUtmParameters } from "./utm";
88

9-
type ServerContext = { request: Request } | { headers: Headers };
10-
119
type TrackEventOptions = {
12-
path?: string | undefined;
1310
hostname?: string | undefined;
1411
collectDnt?: boolean | undefined;
1512
metadata?: AnalyticsMetadata;
16-
} & ServerContext;
13+
} & (ServerContext | HeaderOnlyContext);
1714

1815
export async function trackEvent(
1916
eventName: string,
@@ -69,7 +66,7 @@ type TrackPageviewOptions = {
6966
hostname?: string | undefined;
7067
metadata?: AnalyticsMetadata;
7168
collectDnt?: boolean | undefined;
72-
} & ServerContextWithPath;
69+
} & ServerContext;
7370

7471
export async function trackPageview(options: TrackPageviewOptions) {
7572
const hostname = options.hostname ?? process.env.SIMPLE_ANALYTICS_HOSTNAME;
@@ -84,7 +81,8 @@ export async function trackPageview(options: TrackPageviewOptions) {
8481
return;
8582
}
8683

87-
const { path, headers, searchParams } = parseServerContext(options);
84+
const { path, searchParams } = "path" in options ? options : parseRequest(options.request);
85+
const headers = "headers" in options ? options.headers : options.request.headers;
8886

8987
if (isDoNotTrackEnabled(headers) && !options.collectDnt) {
9088
console.log("Do not track enabled, not tracking pageview");
@@ -101,7 +99,7 @@ export async function trackPageview(options: TrackPageviewOptions) {
10199
event: "pageview",
102100
path,
103101
...(parseHeaders(headers, {})),
104-
...(parseUtmParameters(searchParams, { strictUtm: false })),
102+
...(searchParams ? parseUtmParameters(searchParams, { strictUtm: false }) : {}),
105103
};
106104

107105
console.log("Tracking pageview", payload);
Lines changed: 5 additions & 60 deletions
Original file line numberDiff line numberDiff line change
@@ -1,67 +1,12 @@
1-
import { NextRequest } from "next/server";
2-
import type { PageviewServerContext, ServerContextWithPath, ServerComponentSearchParamsProp } from "./interfaces";
3-
41
export function isDoNotTrackEnabled(headers: Headers) {
52
return headers.has("DNT") && headers.get("DNT") === "1";
63
}
74

8-
function parseSearchParameters(params: ServerComponentSearchParamsProp | undefined) {
9-
const searchParams = new URLSearchParams();
10-
11-
if (!params) {
12-
return searchParams;
13-
}
14-
15-
for (const [key, value] of Object.entries(params)) {
16-
if (value === undefined) {
17-
continue;
18-
}
19-
20-
if (typeof value === "string") {
21-
searchParams.append(key, value);
22-
continue;
23-
}
24-
25-
26-
for (const item of value) {
27-
searchParams.append(key, item);
28-
}
29-
}
30-
31-
return searchParams;
32-
}
33-
34-
export function parseServerContext(options: ServerContextWithPath): PageviewServerContext {
35-
if ("request" in options) {
36-
const searchParams = getSearchParameters(options.request);
37-
38-
return {
39-
path: getPath(options.request),
40-
headers: options.request.headers,
41-
searchParams,
42-
}
43-
}
5+
export function parseRequest(request: Request) {
6+
const url = new URL(request.url);
447

458
return {
46-
path: options.path,
47-
headers: options.headers,
48-
searchParams: parseSearchParameters(options.searchParams),
49-
}
50-
}
51-
52-
function getPath(request: Request) {
53-
// When request is an NextRequest, the URL will already be parsed (see Next.js implementation)
54-
if (request instanceof NextRequest) {
55-
return request.nextUrl.pathname;
56-
}
57-
58-
return new URL(request.url).pathname;
59-
}
60-
61-
function getSearchParameters(request: Request) {
62-
if (request instanceof NextRequest) {
63-
return request.nextUrl.searchParams;
9+
path: url.pathname,
10+
searchParams: url.searchParams,
6411
}
65-
66-
return new URL(request.url).searchParams;
67-
}
12+
}

packages/analytics/src/server/utm.ts

Lines changed: 16 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -24,14 +24,27 @@ interface UtmParameters {
2424
term?: string | undefined;
2525
}
2626

27-
export function parseUtmParameters(searchParams: URLSearchParams, options: UtmOptions) {
27+
export function parseUtmParameters(searchParams: URLSearchParams | Record<string, string | string[] | undefined>, options: UtmOptions) {
2828
const params: UtmParameters = {};
2929

30-
for (const [name, value] of searchParams.entries()) {
30+
if (searchParams instanceof URLSearchParams) {
31+
for (const [name, value] of searchParams.entries()) {
32+
const param = parseUtmParameter(name, options.strictUtm);
33+
34+
if (param) {
35+
params[param] = value;
36+
}
37+
}
38+
39+
return params;
40+
}
41+
42+
for (const name in searchParams) {
43+
const value = searchParams[name];
3144
const param = parseUtmParameter(name, options.strictUtm);
3245

3346
if (param) {
34-
params[param] = value;
47+
params[param] = Array.isArray(value) ? value[0] : value;
3548
}
3649
}
3750

0 commit comments

Comments
 (0)