@ianmenethil/zp-devicefp 0.1.1 → 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/README.md +173 -103
- package/dist/cdn/zp.dfp.esm.js +294 -84
- package/dist/cdn/zp.dfp.js +287 -84
- package/dist/cdn/zp.dfp.manifest.json +17 -17
- package/dist/cdn/zp.dfp.min.js +1 -1
- package/dist/cdn/zp.dfp.obf.js +1 -1
- package/dist/npm/index.cjs +301 -84
- package/dist/npm/index.d.ts +21 -8
- package/dist/npm/index.mjs +294 -84
- package/docs/api-reference.md +520 -472
- package/docs/architecture.md +171 -40
- package/docs/privacy.md +20 -20
- package/docs/signals.md +425 -383
- package/docs/testing.md +54 -32
- package/package.json +2 -2
package/dist/cdn/zp.dfp.js
CHANGED
|
@@ -24,6 +24,35 @@
|
|
|
24
24
|
return Boolean(env.document?.createElement?.("canvas").getContext);
|
|
25
25
|
}
|
|
26
26
|
|
|
27
|
+
// src/signals/adblock.ts
|
|
28
|
+
var adblockCollector = {
|
|
29
|
+
name: "adblock",
|
|
30
|
+
tier: "extended",
|
|
31
|
+
supportsSync: false,
|
|
32
|
+
async collect(context) {
|
|
33
|
+
const started = now(context.env);
|
|
34
|
+
const doc = context.env.document;
|
|
35
|
+
if (!doc || !hasDom(context.env)) {
|
|
36
|
+
return { status: "unsupported", durationMs: now(context.env) - started };
|
|
37
|
+
}
|
|
38
|
+
return new Promise((resolve) => {
|
|
39
|
+
const bait = doc.createElement("div");
|
|
40
|
+
bait.innerHTML = "\xA0";
|
|
41
|
+
bait.className = "adsbox";
|
|
42
|
+
doc.body.appendChild(bait);
|
|
43
|
+
setTimeout(() => {
|
|
44
|
+
const adblockEnabled = bait.offsetHeight === 0;
|
|
45
|
+
doc.body.removeChild(bait);
|
|
46
|
+
resolve({
|
|
47
|
+
status: "ok",
|
|
48
|
+
durationMs: now(context.env) - started,
|
|
49
|
+
value: { adblockEnabled }
|
|
50
|
+
});
|
|
51
|
+
}, 100);
|
|
52
|
+
});
|
|
53
|
+
}
|
|
54
|
+
};
|
|
55
|
+
|
|
27
56
|
// src/signals/audio.ts
|
|
28
57
|
function getOfflineAudioContext(env) {
|
|
29
58
|
const g = env;
|
|
@@ -142,7 +171,9 @@
|
|
|
142
171
|
"paymentSupport",
|
|
143
172
|
"referrerInfo",
|
|
144
173
|
"navigationInfo",
|
|
145
|
-
"riskSignals"
|
|
174
|
+
"riskSignals",
|
|
175
|
+
"adblock",
|
|
176
|
+
"geolocation"
|
|
146
177
|
];
|
|
147
178
|
var SYNC_SIGNALS = [
|
|
148
179
|
"ua",
|
|
@@ -161,16 +192,76 @@
|
|
|
161
192
|
];
|
|
162
193
|
var DEFAULT_TIMEOUT_MS = 1500;
|
|
163
194
|
var DEFAULT_FONT_LIST = [
|
|
195
|
+
"Andale Mono",
|
|
196
|
+
"American Typewriter",
|
|
197
|
+
"Apple Chancery",
|
|
164
198
|
"Arial",
|
|
165
|
-
"
|
|
166
|
-
"
|
|
167
|
-
"
|
|
199
|
+
"Arial Black",
|
|
200
|
+
"Arial Narrow",
|
|
201
|
+
"Arial Rounded MT Bold",
|
|
202
|
+
"Baskerville",
|
|
203
|
+
"Book Antiqua",
|
|
204
|
+
"Bookman Old Style",
|
|
205
|
+
"Bradley Hand ITC",
|
|
206
|
+
"Calibri",
|
|
207
|
+
"Cambria",
|
|
208
|
+
"Candara",
|
|
209
|
+
"Century",
|
|
210
|
+
"Century Gothic",
|
|
211
|
+
"Century Schoolbook",
|
|
212
|
+
"Chalkboard",
|
|
213
|
+
"Charcoal",
|
|
214
|
+
"Cochin",
|
|
215
|
+
"Comic Sans MS",
|
|
216
|
+
"Consolas",
|
|
217
|
+
"Constantia",
|
|
218
|
+
"Corbel",
|
|
219
|
+
"Courier",
|
|
168
220
|
"Courier New",
|
|
221
|
+
"Franklin Gothic Medium",
|
|
222
|
+
"Futura",
|
|
223
|
+
"Garamond",
|
|
224
|
+
"Geneva",
|
|
225
|
+
"Georgia",
|
|
226
|
+
"Gill Sans",
|
|
227
|
+
"Gill Sans MT",
|
|
228
|
+
"Helvetica",
|
|
229
|
+
"Hoefler Text",
|
|
230
|
+
"Impact",
|
|
231
|
+
"Lucida Bright",
|
|
232
|
+
"Lucida Console",
|
|
233
|
+
"Lucida Grande",
|
|
234
|
+
"Lucida Sans",
|
|
235
|
+
"MS Gothic",
|
|
236
|
+
"MS PGothic",
|
|
237
|
+
"MS Serif",
|
|
238
|
+
"MS UI Gothic",
|
|
239
|
+
"Meiryo",
|
|
240
|
+
"Meiryo UI",
|
|
241
|
+
"Monaco",
|
|
242
|
+
"Monotype Corsiva",
|
|
243
|
+
"New York",
|
|
244
|
+
"Optima",
|
|
245
|
+
"Palatino",
|
|
246
|
+
"Palatino Linotype",
|
|
247
|
+
"Papyrus",
|
|
248
|
+
"Plantagenet Cherokee",
|
|
249
|
+
"Segoe Print",
|
|
250
|
+
"Segoe Script",
|
|
251
|
+
"Segoe UI",
|
|
252
|
+
"Segoe UI Light",
|
|
253
|
+
"Segoe UI Semibold",
|
|
254
|
+
"Segoe UI Symbol",
|
|
255
|
+
"Symbol",
|
|
256
|
+
"Tahoma",
|
|
257
|
+
"Times",
|
|
258
|
+
"Times New Roman",
|
|
169
259
|
"Trebuchet MS",
|
|
170
260
|
"Verdana",
|
|
171
|
-
"
|
|
172
|
-
"
|
|
173
|
-
"
|
|
261
|
+
"Wingdings",
|
|
262
|
+
"Wingdings 2",
|
|
263
|
+
"Wingdings 3",
|
|
264
|
+
"Zapfino"
|
|
174
265
|
];
|
|
175
266
|
var DEFAULT_PERMISSION_NAMES = ["geolocation", "notifications", "camera", "microphone"];
|
|
176
267
|
var DEFAULT_UA_HINTS = [
|
|
@@ -298,6 +389,44 @@
|
|
|
298
389
|
}
|
|
299
390
|
};
|
|
300
391
|
|
|
392
|
+
// src/signals/geolocation.ts
|
|
393
|
+
var geolocationCollector = {
|
|
394
|
+
name: "geolocation",
|
|
395
|
+
tier: "extended",
|
|
396
|
+
supportsSync: false,
|
|
397
|
+
async collect(context) {
|
|
398
|
+
const started = now(context.env);
|
|
399
|
+
const nav = context.env.navigator;
|
|
400
|
+
if (!nav?.geolocation) {
|
|
401
|
+
return { status: "unsupported", durationMs: now(context.env) - started };
|
|
402
|
+
}
|
|
403
|
+
return new Promise((resolve) => {
|
|
404
|
+
nav.geolocation.getCurrentPosition(
|
|
405
|
+
(pos) => {
|
|
406
|
+
resolve({
|
|
407
|
+
status: "ok",
|
|
408
|
+
durationMs: now(context.env) - started,
|
|
409
|
+
value: {
|
|
410
|
+
latitude: pos.coords.latitude,
|
|
411
|
+
longitude: pos.coords.longitude,
|
|
412
|
+
accuracy: pos.coords.accuracy
|
|
413
|
+
}
|
|
414
|
+
});
|
|
415
|
+
},
|
|
416
|
+
(err) => {
|
|
417
|
+
resolve({
|
|
418
|
+
// PERMISSION_DENIED = 1
|
|
419
|
+
status: err.code === 1 ? "blocked" : "error",
|
|
420
|
+
durationMs: now(context.env) - started,
|
|
421
|
+
error: err.message
|
|
422
|
+
});
|
|
423
|
+
},
|
|
424
|
+
{ timeout: context.options.timeoutMs, maximumAge: 6e4 }
|
|
425
|
+
);
|
|
426
|
+
});
|
|
427
|
+
}
|
|
428
|
+
};
|
|
429
|
+
|
|
301
430
|
// src/signals/hardware.ts
|
|
302
431
|
var hardwareCollector = {
|
|
303
432
|
name: "hardware",
|
|
@@ -313,6 +442,17 @@
|
|
|
313
442
|
if (!nav) {
|
|
314
443
|
return { status: "unsupported", durationMs: now(context.env) - started };
|
|
315
444
|
}
|
|
445
|
+
const doc = context.env.document;
|
|
446
|
+
const g = context.env.global;
|
|
447
|
+
let touchEventCreationSuccessful = false;
|
|
448
|
+
try {
|
|
449
|
+
if (doc) {
|
|
450
|
+
doc.createEvent("TouchEvent");
|
|
451
|
+
touchEventCreationSuccessful = true;
|
|
452
|
+
}
|
|
453
|
+
} catch {
|
|
454
|
+
}
|
|
455
|
+
const onTouchStartAvailable = g != null && "ontouchstart" in g;
|
|
316
456
|
return {
|
|
317
457
|
status: "ok",
|
|
318
458
|
durationMs: now(context.env) - started,
|
|
@@ -320,7 +460,9 @@
|
|
|
320
460
|
hardwareConcurrency: nav.hardwareConcurrency,
|
|
321
461
|
deviceMemory: nav.deviceMemory,
|
|
322
462
|
platform: nav.platform,
|
|
323
|
-
maxTouchPoints: nav.maxTouchPoints
|
|
463
|
+
maxTouchPoints: nav.maxTouchPoints,
|
|
464
|
+
touchEventCreationSuccessful,
|
|
465
|
+
onTouchStartAvailable
|
|
324
466
|
}
|
|
325
467
|
};
|
|
326
468
|
}
|
|
@@ -342,28 +484,36 @@
|
|
|
342
484
|
if (!nav || !intl) {
|
|
343
485
|
return { status: "unsupported", durationMs: now(context.env) - started };
|
|
344
486
|
}
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
487
|
+
try {
|
|
488
|
+
const formatter = new intl.DateTimeFormat();
|
|
489
|
+
const options = formatter.resolvedOptions();
|
|
490
|
+
const numberFormatter = new intl.NumberFormat(nav.language);
|
|
491
|
+
const relativeTimeFormatter = typeof intl.RelativeTimeFormat === "function" ? new intl.RelativeTimeFormat(nav.language, { numeric: "auto" }) : void 0;
|
|
492
|
+
const sampleDate = new Date(Date.UTC(2024, 0, 2, 3, 4, 5));
|
|
493
|
+
return {
|
|
494
|
+
status: "ok",
|
|
495
|
+
durationMs: now(context.env) - started,
|
|
496
|
+
value: {
|
|
497
|
+
language: nav.language,
|
|
498
|
+
languages: nav.languages,
|
|
499
|
+
locale: options.locale,
|
|
500
|
+
calendar: options.calendar,
|
|
501
|
+
numberingSystem: options.numberingSystem,
|
|
502
|
+
timeZone: options.timeZone,
|
|
503
|
+
hourCycle: options.hourCycle,
|
|
504
|
+
timeZoneOffsetMinutes: sampleDate.getTimezoneOffset(),
|
|
505
|
+
formattedNumber: numberFormatter.format(123456.789),
|
|
506
|
+
formattedDate: formatter.format(sampleDate),
|
|
507
|
+
formattedRelativeDay: relativeTimeFormatter?.format(-1, "day")
|
|
508
|
+
}
|
|
509
|
+
};
|
|
510
|
+
} catch (error) {
|
|
511
|
+
return {
|
|
512
|
+
status: "error",
|
|
513
|
+
durationMs: now(context.env) - started,
|
|
514
|
+
error: error instanceof Error ? error.message : String(error)
|
|
515
|
+
};
|
|
516
|
+
}
|
|
367
517
|
}
|
|
368
518
|
};
|
|
369
519
|
|
|
@@ -674,6 +824,7 @@
|
|
|
674
824
|
if (!screen2) {
|
|
675
825
|
return { status: "unsupported", durationMs: now(context.env) - started };
|
|
676
826
|
}
|
|
827
|
+
const orientation = screen2.orientation;
|
|
677
828
|
return {
|
|
678
829
|
status: "ok",
|
|
679
830
|
durationMs: now(context.env) - started,
|
|
@@ -684,10 +835,24 @@
|
|
|
684
835
|
availHeight: screen2.availHeight,
|
|
685
836
|
colorDepth: screen2.colorDepth,
|
|
686
837
|
pixelDepth: screen2.pixelDepth,
|
|
687
|
-
|
|
688
|
-
orientationAngle:
|
|
838
|
+
// eslint-disable-next-line @typescript-eslint/no-unnecessary-condition -- orientation is optional at runtime despite the Screen intersection
|
|
839
|
+
...orientation ? { orientationType: orientation.type, orientationAngle: orientation.angle } : {},
|
|
689
840
|
maxTouchPoints: nav?.maxTouchPoints ?? 0,
|
|
841
|
+
resolution: `${String(screen2.width)}x${String(screen2.height)}`,
|
|
842
|
+
ratio: screen2.height > 0 ? Math.round(screen2.width / screen2.height * 1e10) / 1e10 : 0,
|
|
690
843
|
devicePixelRatio: typeof runtime.devicePixelRatio === "number" ? runtime.devicePixelRatio : void 0,
|
|
844
|
+
// Fingerprint2 / Cardinal Commerce has_lied_resolution: availWidth never exceeds width on a real device
|
|
845
|
+
fakedResolution: screen2.availWidth > screen2.width || screen2.availHeight > screen2.height,
|
|
846
|
+
// Cardinal Commerce CCAScreenSize — outerWidth/outerHeight bucket code
|
|
847
|
+
ccaScreenSize: (() => {
|
|
848
|
+
const w = typeof runtime.outerWidth === "number" ? runtime.outerWidth : 0;
|
|
849
|
+
const h = typeof runtime.outerHeight === "number" ? runtime.outerHeight : 0;
|
|
850
|
+
if (w < 390) return "01";
|
|
851
|
+
if (w < 500) return "02";
|
|
852
|
+
if (w < 600) return "03";
|
|
853
|
+
if (h < 600) return "04";
|
|
854
|
+
return "02";
|
|
855
|
+
})(),
|
|
691
856
|
colorGamutP3: getMediaPreference(runtime, "(color-gamut: p3)"),
|
|
692
857
|
prefersReducedMotion: getMediaPreference(runtime, "(prefers-reduced-motion: reduce)"),
|
|
693
858
|
prefersContrastMore: getMediaPreference(runtime, "(prefers-contrast: more)"),
|
|
@@ -754,6 +919,16 @@
|
|
|
754
919
|
if (!nav) {
|
|
755
920
|
return { status: "unsupported", durationMs: now(context.env) - started };
|
|
756
921
|
}
|
|
922
|
+
let plugins = [];
|
|
923
|
+
try {
|
|
924
|
+
plugins = Array.from(nav.plugins).map((p) => {
|
|
925
|
+
const mimes = Array.from({ length: p.length }, (_, i) => p.item(i)).filter((m) => m !== null).map((m) => `${m.type}~${m.suffixes}`).join(",");
|
|
926
|
+
return `${p.name}::${p.description}::${mimes}`;
|
|
927
|
+
});
|
|
928
|
+
} catch {
|
|
929
|
+
}
|
|
930
|
+
const rawDnt = nav.doNotTrack ?? context.env.global.doNotTrack ?? null;
|
|
931
|
+
const doNotTrack = rawDnt === "1" ? "enabled" : rawDnt === "0" ? "disabled" : rawDnt ?? "not_set";
|
|
757
932
|
return {
|
|
758
933
|
status: "ok",
|
|
759
934
|
durationMs: now(context.env) - started,
|
|
@@ -765,7 +940,9 @@
|
|
|
765
940
|
webdriver: nav.webdriver,
|
|
766
941
|
maxTouchPoints: nav.maxTouchPoints,
|
|
767
942
|
cookieEnabled: nav.cookieEnabled,
|
|
768
|
-
vendorSub: nav.vendorSub
|
|
943
|
+
vendorSub: nav.vendorSub,
|
|
944
|
+
doNotTrack,
|
|
945
|
+
plugins
|
|
769
946
|
}
|
|
770
947
|
};
|
|
771
948
|
}
|
|
@@ -922,7 +1099,9 @@
|
|
|
922
1099
|
paymentSupportCollector,
|
|
923
1100
|
referrerInfoCollector,
|
|
924
1101
|
navigationInfoCollector,
|
|
925
|
-
riskSignalsCollector
|
|
1102
|
+
riskSignalsCollector,
|
|
1103
|
+
adblockCollector,
|
|
1104
|
+
geolocationCollector
|
|
926
1105
|
];
|
|
927
1106
|
var collectorMap = new Map(signalCollectors.map((collector) => [collector.name, collector]));
|
|
928
1107
|
|
|
@@ -936,6 +1115,13 @@
|
|
|
936
1115
|
function asNumber(value) {
|
|
937
1116
|
return typeof value === "number" && Number.isFinite(value) ? value : void 0;
|
|
938
1117
|
}
|
|
1118
|
+
function canonicalizeLegacyPlatform(legacyPlatform) {
|
|
1119
|
+
if (legacyPlatform.startsWith("win")) return "windows";
|
|
1120
|
+
if (legacyPlatform.startsWith("mac")) return "macos";
|
|
1121
|
+
if (/cros|chrome/.test(legacyPlatform)) return "chrome os";
|
|
1122
|
+
if (/linux|x11/.test(legacyPlatform)) return "linux";
|
|
1123
|
+
return legacyPlatform;
|
|
1124
|
+
}
|
|
939
1125
|
function analyseSignals(signals) {
|
|
940
1126
|
const anomalies = [];
|
|
941
1127
|
const automationHints = [];
|
|
@@ -957,8 +1143,12 @@
|
|
|
957
1143
|
if (userAgent.includes("headless")) {
|
|
958
1144
|
automationHints.push("headless_user_agent");
|
|
959
1145
|
}
|
|
960
|
-
if (platform && hintPlatform
|
|
961
|
-
|
|
1146
|
+
if (platform && hintPlatform) {
|
|
1147
|
+
const canonicalLegacy = canonicalizeLegacyPlatform(platform);
|
|
1148
|
+
const linuxFamilyOk = canonicalLegacy === "linux" && (hintPlatform === "linux" || hintPlatform === "android" || hintPlatform === "chrome os");
|
|
1149
|
+
if (!linuxFamilyOk && canonicalLegacy !== hintPlatform) {
|
|
1150
|
+
anomalies.push("ua_platform_mismatch");
|
|
1151
|
+
}
|
|
962
1152
|
}
|
|
963
1153
|
if (userAgent.includes("iphone") && maxTouchPoints === 0) {
|
|
964
1154
|
anomalies.push("touch_claim_without_touch_points");
|
|
@@ -978,10 +1168,16 @@
|
|
|
978
1168
|
const anomalyPenalty = anomalies.length * 0.12;
|
|
979
1169
|
const automationPenalty = automationHints.length * 0.18;
|
|
980
1170
|
const score = Math.max(0, Math.min(1, Number((1 - anomalyPenalty - automationPenalty).toFixed(3))));
|
|
1171
|
+
const fakedOS = anomalies.includes("ua_platform_mismatch");
|
|
1172
|
+
const riskVal = asRecord(signals.riskSignals?.value);
|
|
1173
|
+
const headlessHints = Array.isArray(riskVal?.headlessHints) ? riskVal.headlessHints : [];
|
|
1174
|
+
const fakedBrowser = headlessHints.includes("missing-chrome-object");
|
|
981
1175
|
return {
|
|
982
1176
|
score,
|
|
983
1177
|
anomalies,
|
|
984
|
-
automationHints
|
|
1178
|
+
automationHints,
|
|
1179
|
+
fakedOS,
|
|
1180
|
+
fakedBrowser
|
|
985
1181
|
};
|
|
986
1182
|
}
|
|
987
1183
|
|
|
@@ -1051,7 +1247,9 @@
|
|
|
1051
1247
|
paymentSupport: 0.2,
|
|
1052
1248
|
referrerInfo: 0.3,
|
|
1053
1249
|
navigationInfo: 0.4,
|
|
1054
|
-
riskSignals: 0.7
|
|
1250
|
+
riskSignals: 0.7,
|
|
1251
|
+
adblock: 0.3,
|
|
1252
|
+
geolocation: 0.5
|
|
1055
1253
|
};
|
|
1056
1254
|
function computeConfidence(signals, antiSpoof) {
|
|
1057
1255
|
let earned = 0;
|
|
@@ -1273,28 +1471,9 @@
|
|
|
1273
1471
|
return included.filter((signal) => !excluded.has(signal));
|
|
1274
1472
|
}
|
|
1275
1473
|
|
|
1276
|
-
// src/core/upload.ts
|
|
1277
|
-
async function uploadFingerprint(env, result, options) {
|
|
1278
|
-
const fetchImpl = options.endpoint && env.fetch;
|
|
1279
|
-
if (!fetchImpl) {
|
|
1280
|
-
throw new Error("Fetch is not available in this runtime.");
|
|
1281
|
-
}
|
|
1282
|
-
return fetchImpl(options.endpoint, {
|
|
1283
|
-
method: "POST",
|
|
1284
|
-
headers: {
|
|
1285
|
-
"content-type": "application/json",
|
|
1286
|
-
...options.headers
|
|
1287
|
-
},
|
|
1288
|
-
body: JSON.stringify({
|
|
1289
|
-
fingerprint: result,
|
|
1290
|
-
...options.bodyExtras
|
|
1291
|
-
})
|
|
1292
|
-
});
|
|
1293
|
-
}
|
|
1294
|
-
|
|
1295
1474
|
// src/version.ts
|
|
1296
|
-
var LIBRARY_VERSION = "0.
|
|
1297
|
-
var SCHEMA_VERSION =
|
|
1475
|
+
var LIBRARY_VERSION = true ? "0.2.0" : "0.0.0-dev";
|
|
1476
|
+
var SCHEMA_VERSION = 2;
|
|
1298
1477
|
|
|
1299
1478
|
// src/client.ts
|
|
1300
1479
|
function toTimedOutResult(durationMs) {
|
|
@@ -1304,6 +1483,18 @@
|
|
|
1304
1483
|
error: "Signal collection timed out."
|
|
1305
1484
|
};
|
|
1306
1485
|
}
|
|
1486
|
+
function toErrorResult(durationMs, error) {
|
|
1487
|
+
return {
|
|
1488
|
+
status: "error",
|
|
1489
|
+
durationMs,
|
|
1490
|
+
error: error instanceof Error ? error.message : String(error)
|
|
1491
|
+
};
|
|
1492
|
+
}
|
|
1493
|
+
function debugLog(resolved, message) {
|
|
1494
|
+
if (resolved.debug) {
|
|
1495
|
+
console.debug(`[zp-devicefp] ${message}`);
|
|
1496
|
+
}
|
|
1497
|
+
}
|
|
1307
1498
|
async function runCollectorWithTimeout(collector, env, options, warn) {
|
|
1308
1499
|
const started = env.performance?.now?.() ?? Date.now();
|
|
1309
1500
|
if (options.abortSignal?.aborted) {
|
|
@@ -1315,31 +1506,36 @@
|
|
|
1315
1506
|
}
|
|
1316
1507
|
let clearTimeoutHandle = () => {
|
|
1317
1508
|
};
|
|
1509
|
+
let removeAbortListener = () => {
|
|
1510
|
+
};
|
|
1318
1511
|
const timeoutPromise = new Promise((resolve) => {
|
|
1319
1512
|
const timeout = setTimeout(() => {
|
|
1320
1513
|
resolve(toTimedOutResult((env.performance?.now?.() ?? Date.now()) - started));
|
|
1321
1514
|
}, options.timeoutMs);
|
|
1322
1515
|
clearTimeoutHandle = () => clearTimeout(timeout);
|
|
1323
|
-
|
|
1324
|
-
|
|
1325
|
-
(
|
|
1326
|
-
|
|
1327
|
-
|
|
1328
|
-
|
|
1329
|
-
|
|
1330
|
-
|
|
1331
|
-
|
|
1332
|
-
|
|
1333
|
-
{ once: true }
|
|
1334
|
-
);
|
|
1335
|
-
});
|
|
1336
|
-
const resultPromise = collector.collect({
|
|
1337
|
-
env,
|
|
1338
|
-
options,
|
|
1339
|
-
warn
|
|
1516
|
+
const onAbort = () => {
|
|
1517
|
+
clearTimeoutHandle();
|
|
1518
|
+
resolve({
|
|
1519
|
+
status: "error",
|
|
1520
|
+
durationMs: (env.performance?.now?.() ?? Date.now()) - started,
|
|
1521
|
+
error: "Collection aborted."
|
|
1522
|
+
});
|
|
1523
|
+
};
|
|
1524
|
+
options.abortSignal?.addEventListener("abort", onAbort, { once: true });
|
|
1525
|
+
removeAbortListener = () => options.abortSignal?.removeEventListener("abort", onAbort);
|
|
1340
1526
|
});
|
|
1527
|
+
const resultPromise = (async () => {
|
|
1528
|
+
try {
|
|
1529
|
+
return await collector.collect({ env, options, warn });
|
|
1530
|
+
} catch (error) {
|
|
1531
|
+
const result = toErrorResult((env.performance?.now?.() ?? Date.now()) - started, error);
|
|
1532
|
+
warn(`Signal "${collector.name}" threw: ${result.error ?? "unknown error"}`, collector.name);
|
|
1533
|
+
return result;
|
|
1534
|
+
}
|
|
1535
|
+
})();
|
|
1341
1536
|
return Promise.race([resultPromise, timeoutPromise]).finally(() => {
|
|
1342
1537
|
clearTimeoutHandle();
|
|
1538
|
+
removeAbortListener();
|
|
1343
1539
|
});
|
|
1344
1540
|
}
|
|
1345
1541
|
function buildResult(signals, warnings, requestedSignals, elapsedMs) {
|
|
@@ -1401,6 +1597,7 @@
|
|
|
1401
1597
|
}
|
|
1402
1598
|
const result = await runCollectorWithTimeout(collector, env, resolved, warn);
|
|
1403
1599
|
collected[name] = result;
|
|
1600
|
+
debugLog(resolved, `${name}: ${result.status} (${String(result.durationMs)}ms)`);
|
|
1404
1601
|
completed += 1;
|
|
1405
1602
|
emitter.emit("progress", {
|
|
1406
1603
|
completed,
|
|
@@ -1431,16 +1628,22 @@
|
|
|
1431
1628
|
warn(`Signal "${name}" is not available in synchronous mode.`, name);
|
|
1432
1629
|
continue;
|
|
1433
1630
|
}
|
|
1434
|
-
|
|
1435
|
-
|
|
1436
|
-
|
|
1437
|
-
|
|
1438
|
-
|
|
1631
|
+
const signalStarted = env.performance?.now?.() ?? Date.now();
|
|
1632
|
+
let result;
|
|
1633
|
+
try {
|
|
1634
|
+
result = collector.collectSync({
|
|
1635
|
+
env,
|
|
1636
|
+
options: resolved,
|
|
1637
|
+
warn
|
|
1638
|
+
});
|
|
1639
|
+
} catch (error) {
|
|
1640
|
+
result = toErrorResult((env.performance?.now?.() ?? Date.now()) - signalStarted, error);
|
|
1641
|
+
warn(`Signal "${name}" threw: ${result.error ?? "unknown error"}`, name);
|
|
1642
|
+
}
|
|
1643
|
+
collected[name] = result;
|
|
1644
|
+
debugLog(resolved, `${name}: ${result.status} (${String(result.durationMs)}ms)`);
|
|
1439
1645
|
}
|
|
1440
1646
|
return buildResult(collected, warnings, signalNames, (env.performance?.now?.() ?? Date.now()) - started);
|
|
1441
|
-
},
|
|
1442
|
-
upload(result, uploadOptions) {
|
|
1443
|
-
return uploadFingerprint(getBrowserEnv(), result, uploadOptions);
|
|
1444
1647
|
}
|
|
1445
1648
|
};
|
|
1446
1649
|
}
|
|
@@ -1,34 +1,34 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ianmenethil/zp-devicefp",
|
|
3
|
-
"version": "0.
|
|
4
|
-
"tag": "@ianmenethil/zp-devicefp@0.
|
|
5
|
-
"npmIdentifier": "ianmenethil-zp-devicefp-0.
|
|
6
|
-
"manifestPath": "ianmenethil-zp-devicefp-0.
|
|
7
|
-
"buildTimestamp": "2026-
|
|
3
|
+
"version": "0.2.0",
|
|
4
|
+
"tag": "@ianmenethil/zp-devicefp@0.2.0",
|
|
5
|
+
"npmIdentifier": "ianmenethil-zp-devicefp-0.2.0",
|
|
6
|
+
"manifestPath": "ianmenethil-zp-devicefp-0.2.0-manifest.json",
|
|
7
|
+
"buildTimestamp": "2026-08-30T08:46:59.985Z",
|
|
8
8
|
"files": [
|
|
9
9
|
{
|
|
10
10
|
"file": "zp.dfp.js",
|
|
11
|
-
"hash": "
|
|
12
|
-
"hashSri": "sha384-
|
|
13
|
-
"size":
|
|
11
|
+
"hash": "53dff92d0aab91260dfe6ab398e49a7ee027a210ca9e496a024d3080564c646ccf086c47a6028050d909ddba795cdd9d",
|
|
12
|
+
"hashSri": "sha384-U9/5LQqrkSYN/mqzmOSafuAnohDKnklqAk0wgFZMZGzPCGxHpgKAUNkJ3bp5XN2d",
|
|
13
|
+
"size": 52767
|
|
14
14
|
},
|
|
15
15
|
{
|
|
16
16
|
"file": "zp.dfp.min.js",
|
|
17
|
-
"hash": "
|
|
18
|
-
"hashSri": "sha384-
|
|
19
|
-
"size":
|
|
17
|
+
"hash": "9b302bb3c03c2e0ba2f6a3b88a7b60b3c88504be349a729ab89d5a67459a1e6c683f2c9094e6f944bb115d78b8108d5a",
|
|
18
|
+
"hashSri": "sha384-mzArs8A8Lgui9qO4intgs8iFBL40mnKauJ1aZ0WaHmxoPyyQlOb5RLsRXXi4EI1a",
|
|
19
|
+
"size": 24231
|
|
20
20
|
},
|
|
21
21
|
{
|
|
22
22
|
"file": "zp.dfp.obf.js",
|
|
23
|
-
"hash": "
|
|
24
|
-
"hashSri": "sha384-
|
|
25
|
-
"size":
|
|
23
|
+
"hash": "df8b4b22f511a7ad898f7328ada31e18ad5a90ef7a2424630df573f1c12ed62ad5b539f4e191b59daa69b0edb8c836b3",
|
|
24
|
+
"hashSri": "sha384-34tLIvURp62Jj3MoraMeGK1akO96JCRjDfVz8cEu1irVtTn04ZG1nappsO24yDaz",
|
|
25
|
+
"size": 296662
|
|
26
26
|
},
|
|
27
27
|
{
|
|
28
28
|
"file": "zp.dfp.esm.js",
|
|
29
|
-
"hash": "
|
|
30
|
-
"hashSri": "sha384-
|
|
31
|
-
"size":
|
|
29
|
+
"hash": "c4a110d84132b21f9c80d456e30836879cd2fe619b34ef4d776f37728dc0328dcc4dc30079ea497cdfa3be57d971d379",
|
|
30
|
+
"hashSri": "sha384-xKEQ2EEysh+cgNRW4wg2h5zS/mGbNO9Nd283co3AMo3MTcMAeepJfN+jvlfZcdN5",
|
|
31
|
+
"size": 49555
|
|
32
32
|
}
|
|
33
33
|
]
|
|
34
34
|
}
|