This commit is contained in:
dela
2026-02-20 13:16:51 +08:00
commit 0ac4b23f07
36 changed files with 5042 additions and 0 deletions

View File

@@ -0,0 +1,150 @@
/**
* Performance Mock
*
* Timing and performance metrics for fingerprinting.
*/
export function createPerformance(fingerprint = {}) {
const timeOrigin = Date.now() - (fingerprint.uptime || 10000);
const entries = [];
return {
timeOrigin,
now() {
return Date.now() - timeOrigin;
},
// Timing (deprecated but still used)
timing: {
navigationStart: timeOrigin,
unloadEventStart: 0,
unloadEventEnd: 0,
redirectStart: 0,
redirectEnd: 0,
fetchStart: timeOrigin + 1,
domainLookupStart: timeOrigin + 2,
domainLookupEnd: timeOrigin + 10,
connectStart: timeOrigin + 10,
connectEnd: timeOrigin + 50,
secureConnectionStart: timeOrigin + 20,
requestStart: timeOrigin + 50,
responseStart: timeOrigin + 100,
responseEnd: timeOrigin + 200,
domLoading: timeOrigin + 200,
domInteractive: timeOrigin + 500,
domContentLoadedEventStart: timeOrigin + 500,
domContentLoadedEventEnd: timeOrigin + 510,
domComplete: timeOrigin + 1000,
loadEventStart: timeOrigin + 1000,
loadEventEnd: timeOrigin + 1010,
},
// Navigation (deprecated)
navigation: {
type: 0, // TYPE_NAVIGATE
redirectCount: 0,
},
// Memory (Chrome-specific)
memory: {
jsHeapSizeLimit: 4294705152,
totalJSHeapSize: 35000000,
usedJSHeapSize: 25000000,
},
// Event counts (Chrome)
eventCounts: {
size: 0,
get: () => 0,
has: () => false,
keys: () => [][Symbol.iterator](),
values: () => [][Symbol.iterator](),
entries: () => [][Symbol.iterator](),
forEach: () => {},
[Symbol.iterator]: () => [][Symbol.iterator](),
},
// Entry methods
getEntries() {
return [...entries];
},
getEntriesByType(type) {
return entries.filter(e => e.entryType === type);
},
getEntriesByName(name, type) {
return entries.filter(e =>
e.name === name && (!type || e.entryType === type)
);
},
// Marks and measures
mark(name, options) {
const entry = {
name,
entryType: 'mark',
startTime: this.now(),
duration: 0,
detail: options?.detail || null,
};
entries.push(entry);
return entry;
},
measure(name, startMark, endMark) {
const startTime = typeof startMark === 'string'
? (entries.find(e => e.name === startMark)?.startTime || 0)
: (startMark?.start || 0);
const endTime = typeof endMark === 'string'
? (entries.find(e => e.name === endMark)?.startTime || this.now())
: (endMark?.end || this.now());
const entry = {
name,
entryType: 'measure',
startTime,
duration: endTime - startTime,
};
entries.push(entry);
return entry;
},
clearMarks(name) {
if (name) {
const idx = entries.findIndex(e => e.name === name && e.entryType === 'mark');
if (idx > -1) entries.splice(idx, 1);
} else {
entries.splice(0, entries.length, ...entries.filter(e => e.entryType !== 'mark'));
}
},
clearMeasures(name) {
if (name) {
const idx = entries.findIndex(e => e.name === name && e.entryType === 'measure');
if (idx > -1) entries.splice(idx, 1);
} else {
entries.splice(0, entries.length, ...entries.filter(e => e.entryType !== 'measure'));
}
},
clearResourceTimings() {
entries.splice(0, entries.length, ...entries.filter(e => e.entryType !== 'resource'));
},
setResourceTimingBufferSize() {},
// Observer
observe() {},
// JSON
toJSON() {
return {
timeOrigin: this.timeOrigin,
timing: this.timing,
navigation: this.navigation,
};
},
};
}