@faststats/web 0.8.2 → 0.9.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/README.md +1 -1
- package/dist/error.js +1 -1
- package/dist/replay.d.ts +1 -1
- package/dist/web-vitals.d.ts +7 -5
- package/dist/web-vitals.js +94 -54
- package/package.json +6 -6
package/README.md
CHANGED
package/dist/error.js
CHANGED
|
@@ -3,7 +3,7 @@ import { r as getSessionContext, t as sendData } from "./chunks/send-data-Dplz7m
|
|
|
3
3
|
import { t as getAnonymousId } from "./chunks/identifiers-xX7o7oZz.js";
|
|
4
4
|
//#region src/error.ts
|
|
5
5
|
const SDK_NAME = "@faststats/web";
|
|
6
|
-
const SDK_VERSION = "0.
|
|
6
|
+
const SDK_VERSION = "0.9.0";
|
|
7
7
|
function errorTracking(options = {}) {
|
|
8
8
|
return {
|
|
9
9
|
name: "error-tracking",
|
package/dist/replay.d.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { t as AnalyticsExtension } from "./chunks/extensions-DW7tJY0T.js";
|
|
2
2
|
import { record } from "@rrweb/record";
|
|
3
3
|
import { LogLevel } from "@rrweb/rrweb-plugin-console-record";
|
|
4
|
-
//#region ../../node_modules/.bun/@rrweb+types@2.1.
|
|
4
|
+
//#region ../../node_modules/.bun/@rrweb+types@2.1.4/node_modules/@rrweb/types/dist/index.d.ts
|
|
5
5
|
declare global {
|
|
6
6
|
interface Window {
|
|
7
7
|
FontFace: typeof FontFace;
|
package/dist/web-vitals.d.ts
CHANGED
|
@@ -4,27 +4,29 @@ export interface WebVitalsOptions {
|
|
|
4
4
|
siteKey: string;
|
|
5
5
|
baseUrl?: string;
|
|
6
6
|
debug?: boolean;
|
|
7
|
-
attribution?: boolean;
|
|
8
7
|
trackHash?: boolean;
|
|
9
8
|
cookieless?: boolean;
|
|
10
9
|
}
|
|
11
|
-
export
|
|
12
|
-
export declare function webVitals(options?: WebVitalsExtensionOptions): AnalyticsExtension;
|
|
10
|
+
export declare function webVitals(): AnalyticsExtension;
|
|
13
11
|
export default class WebVitalsTracker {
|
|
14
12
|
private readonly options;
|
|
15
13
|
private readonly endpoint;
|
|
16
14
|
private metrics;
|
|
17
15
|
private started;
|
|
18
|
-
private
|
|
16
|
+
private sending?;
|
|
17
|
+
private generation;
|
|
18
|
+
private unsubscribe?;
|
|
19
|
+
private readonly sentMetrics;
|
|
19
20
|
private initialUrl;
|
|
20
21
|
private session;
|
|
21
22
|
private cookieless;
|
|
22
23
|
constructor(options: WebVitalsOptions);
|
|
23
24
|
setCookielessMode(cookieless: boolean): void;
|
|
24
|
-
start():
|
|
25
|
+
start(): void;
|
|
25
26
|
stop(discard?: boolean): void;
|
|
26
27
|
onPageHidden(persisted?: boolean): void;
|
|
27
28
|
private onMetric;
|
|
29
|
+
private discard;
|
|
28
30
|
private flush;
|
|
29
31
|
}
|
|
30
32
|
//#endregion
|
package/dist/web-vitals.js
CHANGED
|
@@ -1,12 +1,43 @@
|
|
|
1
1
|
import { a as sanitizeUrl, i as resolveBaseUrl, n as URLS, t as ANALYTICS_BASE } from "./chunks/api-urls-DWk43fu6.js";
|
|
2
2
|
import { r as getSessionContext, t as sendData } from "./chunks/send-data-Dplz7m4c.js";
|
|
3
|
+
import { onCLS, onFCP, onINP, onLCP, onTTFB } from "web-vitals/attribution";
|
|
4
|
+
//#region src/utils/web-vitals-collector.ts
|
|
5
|
+
const collectors = /* @__PURE__ */ new WeakMap();
|
|
6
|
+
function subscribeToVitals(subscriber) {
|
|
7
|
+
let collector = collectors.get(document);
|
|
8
|
+
if (!collector) {
|
|
9
|
+
collector = {
|
|
10
|
+
subscribers: /* @__PURE__ */ new Set(),
|
|
11
|
+
latest: /* @__PURE__ */ new Map()
|
|
12
|
+
};
|
|
13
|
+
collectors.set(document, collector);
|
|
14
|
+
const { latest, subscribers } = collector;
|
|
15
|
+
const report = (metric) => {
|
|
16
|
+
const snapshot = { ...metric };
|
|
17
|
+
snapshot.attribution = { ...metric.attribution };
|
|
18
|
+
latest.set(metric.name, snapshot);
|
|
19
|
+
for (const listener of subscribers) listener(snapshot);
|
|
20
|
+
};
|
|
21
|
+
const changes = { reportAllChanges: true };
|
|
22
|
+
onCLS(report, changes);
|
|
23
|
+
onINP(report, changes);
|
|
24
|
+
onLCP(report, changes);
|
|
25
|
+
onFCP(report);
|
|
26
|
+
onTTFB(report);
|
|
27
|
+
}
|
|
28
|
+
collector.subscribers.add(subscriber);
|
|
29
|
+
for (const metric of collector.latest.values()) subscriber(metric);
|
|
30
|
+
return () => {
|
|
31
|
+
collector.subscribers.delete(subscriber);
|
|
32
|
+
};
|
|
33
|
+
}
|
|
34
|
+
//#endregion
|
|
3
35
|
//#region src/web-vitals.ts
|
|
4
|
-
function webVitals(
|
|
36
|
+
function webVitals() {
|
|
5
37
|
return {
|
|
6
38
|
name: "web-vitals",
|
|
7
|
-
|
|
39
|
+
setup(context) {
|
|
8
40
|
const tracker = new WebVitalsTracker({
|
|
9
|
-
...options,
|
|
10
41
|
siteKey: context.siteKey,
|
|
11
42
|
baseUrl: context.baseUrl,
|
|
12
43
|
debug: context.debug,
|
|
@@ -15,7 +46,7 @@ function webVitals(options = {}) {
|
|
|
15
46
|
});
|
|
16
47
|
context.on("pageHide", ({ persisted }) => tracker.onPageHidden(persisted));
|
|
17
48
|
context.on("consentChange", ({ cookieless }) => tracker.setCookielessMode(cookieless));
|
|
18
|
-
|
|
49
|
+
tracker.start();
|
|
19
50
|
return ({ discard }) => tracker.stop(discard);
|
|
20
51
|
}
|
|
21
52
|
};
|
|
@@ -32,7 +63,10 @@ var WebVitalsTracker = class {
|
|
|
32
63
|
endpoint;
|
|
33
64
|
metrics = /* @__PURE__ */ new Map();
|
|
34
65
|
started = false;
|
|
35
|
-
|
|
66
|
+
sending;
|
|
67
|
+
generation = 0;
|
|
68
|
+
unsubscribe;
|
|
69
|
+
sentMetrics = /* @__PURE__ */ new Map();
|
|
36
70
|
initialUrl = "";
|
|
37
71
|
session = null;
|
|
38
72
|
cookieless;
|
|
@@ -44,77 +78,83 @@ var WebVitalsTracker = class {
|
|
|
44
78
|
setCookielessMode(cookieless) {
|
|
45
79
|
if (this.cookieless === cookieless) return;
|
|
46
80
|
this.cookieless = cookieless;
|
|
47
|
-
this.
|
|
81
|
+
this.discard();
|
|
48
82
|
this.session = this.started ? getSessionContext(this.options.siteKey, cookieless) : null;
|
|
49
83
|
}
|
|
50
|
-
|
|
84
|
+
start() {
|
|
51
85
|
if (this.started || typeof window === "undefined") return;
|
|
52
86
|
this.started = true;
|
|
53
|
-
this.initialUrl = sanitizeUrl(window.location.href, this.options.trackHash ?? false);
|
|
87
|
+
this.initialUrl = sanitizeUrl(window.performance?.getEntriesByType("navigation")[0]?.name || window.location.href, this.options.trackHash ?? false);
|
|
54
88
|
this.session = getSessionContext(this.options.siteKey, this.cookieless);
|
|
55
|
-
|
|
56
|
-
if (!this.started) return;
|
|
57
|
-
const changes = { reportAllChanges: true };
|
|
58
|
-
vitals.onCLS(this.onMetric, changes);
|
|
59
|
-
vitals.onINP(this.onMetric, changes);
|
|
60
|
-
vitals.onLCP(this.onMetric, changes);
|
|
61
|
-
vitals.onFCP(this.onMetric);
|
|
62
|
-
vitals.onTTFB(this.onMetric);
|
|
89
|
+
this.unsubscribe = subscribeToVitals(this.onMetric);
|
|
63
90
|
}
|
|
64
91
|
stop(discard = false) {
|
|
65
92
|
if (!this.started) return;
|
|
66
93
|
this.started = false;
|
|
67
|
-
|
|
94
|
+
this.unsubscribe?.();
|
|
95
|
+
this.unsubscribe = void 0;
|
|
96
|
+
if (discard) this.discard();
|
|
68
97
|
else this.flush();
|
|
69
98
|
}
|
|
70
99
|
onPageHidden(persisted = false) {
|
|
71
100
|
if (persisted) return;
|
|
72
|
-
|
|
101
|
+
const generation = this.generation;
|
|
102
|
+
queueMicrotask(() => {
|
|
103
|
+
if (generation === this.generation) this.flush();
|
|
104
|
+
});
|
|
73
105
|
}
|
|
74
106
|
onMetric = (metric) => {
|
|
75
107
|
if (!this.started) return;
|
|
76
108
|
const name = metric.name;
|
|
77
109
|
if (!METRIC_NAMES.has(name) || !Number.isFinite(metric.value) || metric.value < 0) return;
|
|
78
|
-
|
|
79
|
-
const attribution = this.options.attribution && "attribution" in metric && metric.attribution ? metric.attribution : void 0;
|
|
80
|
-
this.metrics.set(name, {
|
|
81
|
-
metric: name,
|
|
82
|
-
value: metric.value,
|
|
83
|
-
attributes: {
|
|
84
|
-
id,
|
|
85
|
-
rating,
|
|
86
|
-
delta,
|
|
87
|
-
navigationType,
|
|
88
|
-
...attribution
|
|
89
|
-
}
|
|
90
|
-
});
|
|
110
|
+
this.metrics.set(name, metric);
|
|
91
111
|
};
|
|
112
|
+
discard() {
|
|
113
|
+
this.generation++;
|
|
114
|
+
this.metrics.clear();
|
|
115
|
+
this.sentMetrics.clear();
|
|
116
|
+
}
|
|
92
117
|
async flush() {
|
|
93
|
-
|
|
94
|
-
this.
|
|
118
|
+
const generation = this.generation;
|
|
119
|
+
while (this.sending) await this.sending;
|
|
120
|
+
if (generation !== this.generation || !this.metrics.size) return;
|
|
95
121
|
const batch = this.metrics;
|
|
96
|
-
this.metrics = /* @__PURE__ */ new Map();
|
|
97
122
|
const session = this.session ?? getSessionContext(this.options.siteKey, this.cookieless);
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
}
|
|
116
|
-
this.
|
|
117
|
-
}
|
|
123
|
+
const data = JSON.stringify({
|
|
124
|
+
token: this.options.siteKey,
|
|
125
|
+
sessionId: session.sessionId,
|
|
126
|
+
windowId: session.windowId,
|
|
127
|
+
vitals: [...batch.values()].map(({ name, value, id, rating, navigationType, attribution }) => {
|
|
128
|
+
const previous = this.sentMetrics.get(name);
|
|
129
|
+
return {
|
|
130
|
+
metric: name,
|
|
131
|
+
value,
|
|
132
|
+
attributes: {
|
|
133
|
+
...attribution,
|
|
134
|
+
id,
|
|
135
|
+
rating,
|
|
136
|
+
navigationType,
|
|
137
|
+
delta: value - (previous?.id === id ? previous.value : 0)
|
|
138
|
+
}
|
|
139
|
+
};
|
|
140
|
+
}),
|
|
141
|
+
metadata: { url: this.initialUrl }
|
|
142
|
+
});
|
|
143
|
+
this.metrics = /* @__PURE__ */ new Map();
|
|
144
|
+
this.sending = sendData({
|
|
145
|
+
url: this.endpoint,
|
|
146
|
+
data,
|
|
147
|
+
debug: this.options.debug,
|
|
148
|
+
debugPrefix: "[WebVitals]"
|
|
149
|
+
});
|
|
150
|
+
const sent = await this.sending;
|
|
151
|
+
this.sending = void 0;
|
|
152
|
+
if (generation !== this.generation) return;
|
|
153
|
+
for (const [name, vital] of batch) if (sent) this.sentMetrics.set(name, {
|
|
154
|
+
id: vital.id,
|
|
155
|
+
value: vital.value
|
|
156
|
+
});
|
|
157
|
+
else if (!this.metrics.has(name)) this.metrics.set(name, vital);
|
|
118
158
|
}
|
|
119
159
|
};
|
|
120
160
|
//#endregion
|
package/package.json
CHANGED
|
@@ -42,7 +42,7 @@
|
|
|
42
42
|
"publishConfig": {
|
|
43
43
|
"access": "public"
|
|
44
44
|
},
|
|
45
|
-
"version": "0.
|
|
45
|
+
"version": "0.9.0",
|
|
46
46
|
"scripts": {
|
|
47
47
|
"build": "tsdown && bun run check-size",
|
|
48
48
|
"dev": "bun run build",
|
|
@@ -51,14 +51,14 @@
|
|
|
51
51
|
"check-size": "node scripts/check-bundle-size.mjs"
|
|
52
52
|
},
|
|
53
53
|
"devDependencies": {
|
|
54
|
-
"@rrweb/types": "^2.1.
|
|
55
|
-
"@types/bun": "^1.4.
|
|
54
|
+
"@rrweb/types": "^2.1.4",
|
|
55
|
+
"@types/bun": "^1.4.2",
|
|
56
56
|
"tsdown": "^0.23.0",
|
|
57
|
-
"typescript": "^
|
|
57
|
+
"typescript": "^7.0.2"
|
|
58
58
|
},
|
|
59
59
|
"dependencies": {
|
|
60
|
-
"@rrweb/record": "^2.1.
|
|
61
|
-
"@rrweb/rrweb-plugin-console-record": "^2.1.
|
|
60
|
+
"@rrweb/record": "^2.1.4",
|
|
61
|
+
"@rrweb/rrweb-plugin-console-record": "^2.1.4",
|
|
62
62
|
"web-vitals": "^6.2.1"
|
|
63
63
|
}
|
|
64
64
|
}
|