@newtalaria/browser 0.1.16 → 0.1.18
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 +94 -10
- package/dist/client.d.ts +1 -1
- package/dist/client.d.ts.map +1 -1
- package/dist/index.js +292 -79
- package/dist/index.js.map +2 -2
- package/dist/replay/hooks.d.ts +61 -8
- package/dist/replay/hooks.d.ts.map +1 -1
- package/dist/replay/privacy.d.ts +1 -1
- package/dist/replay/privacy.d.ts.map +1 -1
- package/dist/sdk_meta.d.ts +1 -1
- package/dist/talaria.browser.iife.js +292 -79
- package/dist/talaria.browser.iife.js.map +2 -2
- package/dist/types.d.ts +18 -4
- package/dist/types.d.ts.map +1 -1
- package/dist/utils/browser_context.d.ts +10 -0
- package/dist/utils/browser_context.d.ts.map +1 -1
- package/dist/utils/network_error.d.ts +16 -0
- package/dist/utils/network_error.d.ts.map +1 -1
- package/package.json +1 -1
|
@@ -100,9 +100,46 @@
|
|
|
100
100
|
}
|
|
101
101
|
|
|
102
102
|
// src/utils/browser_context.ts
|
|
103
|
+
var BOT_RULES = [
|
|
104
|
+
{ name: "Baiduspider", re: /Baiduspider/i },
|
|
105
|
+
{ name: "Googlebot", re: /Googlebot/i },
|
|
106
|
+
{ name: "Bingbot", re: /bingbot/i },
|
|
107
|
+
{ name: "DuckDuckBot", re: /DuckDuckBot/i },
|
|
108
|
+
{ name: "YandexBot", re: /Yandex(Bot|Images)/i },
|
|
109
|
+
{ name: "Applebot", re: /Applebot/i },
|
|
110
|
+
{ name: "facebookexternalhit", re: /facebookexternalhit|Facebot/i },
|
|
111
|
+
{ name: "Twitterbot", re: /Twitterbot/i },
|
|
112
|
+
{ name: "LinkedInBot", re: /LinkedInBot/i },
|
|
113
|
+
{ name: "Slackbot", re: /Slackbot/i },
|
|
114
|
+
{ name: "Discordbot", re: /Discordbot/i },
|
|
115
|
+
{ name: "Bytespider", re: /Bytespider/i },
|
|
116
|
+
{ name: "PetalBot", re: /PetalBot/i },
|
|
117
|
+
{ name: "SemrushBot", re: /SemrushBot/i },
|
|
118
|
+
{ name: "AhrefsBot", re: /AhrefsBot/i },
|
|
119
|
+
{ name: "DotBot", re: /DotBot/i },
|
|
120
|
+
{ name: "GPTBot", re: /GPTBot/i },
|
|
121
|
+
{ name: "ClaudeBot", re: /ClaudeBot|anthropic-ai/i },
|
|
122
|
+
{ name: "Amazonbot", re: /Amazonbot/i },
|
|
123
|
+
{ name: "Sogou", re: /Sogou/i },
|
|
124
|
+
// Generic last — still mark as bot without inventing a browser name.
|
|
125
|
+
{ name: "bot", re: /\b(?:bot|crawler|spider|slurp)\b/i }
|
|
126
|
+
];
|
|
127
|
+
function detectBot(ua) {
|
|
128
|
+
if (!ua) return { bot: false };
|
|
129
|
+
for (const rule2 of BOT_RULES) {
|
|
130
|
+
if (rule2.re.test(ua)) {
|
|
131
|
+
return {
|
|
132
|
+
bot: true,
|
|
133
|
+
botName: rule2.name === "bot" ? void 0 : rule2.name
|
|
134
|
+
};
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
return { bot: false };
|
|
138
|
+
}
|
|
103
139
|
function parseBrowserContext(ua = typeof navigator !== "undefined" ? navigator.userAgent : "", language = typeof navigator !== "undefined" ? navigator.language : "") {
|
|
104
140
|
const userAgent = ua || "";
|
|
105
141
|
const lang = language || "";
|
|
142
|
+
const botInfo = detectBot(userAgent);
|
|
106
143
|
let name = "unknown";
|
|
107
144
|
let version = "";
|
|
108
145
|
const rules = [
|
|
@@ -113,18 +150,20 @@
|
|
|
113
150
|
{ name: "Chrome", re: /(?:Chrome|CriOS)\/([\d.]+)/ },
|
|
114
151
|
{ name: "Safari", re: /Version\/([\d.]+).*Safari/ }
|
|
115
152
|
];
|
|
116
|
-
|
|
117
|
-
const
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
153
|
+
if (!botInfo.bot) {
|
|
154
|
+
for (const rule2 of rules) {
|
|
155
|
+
const m = userAgent.match(rule2.re);
|
|
156
|
+
if (m) {
|
|
157
|
+
name = rule2.name;
|
|
158
|
+
version = m[1] ?? "";
|
|
159
|
+
break;
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
if (name === "unknown" && /iPhone|iPad|iPod/.test(userAgent) && /AppleWebKit/.test(userAgent)) {
|
|
163
|
+
name = "Safari";
|
|
164
|
+
const m = userAgent.match(/OS ([\d_]+)/);
|
|
165
|
+
if (m?.[1]) version = m[1].replace(/_/g, ".");
|
|
122
166
|
}
|
|
123
|
-
}
|
|
124
|
-
if (name === "unknown" && /iPhone|iPad|iPod/.test(userAgent) && /AppleWebKit/.test(userAgent)) {
|
|
125
|
-
name = "Safari";
|
|
126
|
-
const m = userAgent.match(/OS ([\d_]+)/);
|
|
127
|
-
if (m?.[1]) version = m[1].replace(/_/g, ".");
|
|
128
167
|
}
|
|
129
168
|
let os = "unknown";
|
|
130
169
|
let osVersion = "";
|
|
@@ -170,7 +209,9 @@
|
|
|
170
209
|
osVersion,
|
|
171
210
|
device,
|
|
172
211
|
language: lang,
|
|
173
|
-
userAgent
|
|
212
|
+
userAgent,
|
|
213
|
+
bot: botInfo.bot,
|
|
214
|
+
...botInfo.botName ? { botName: botInfo.botName } : {}
|
|
174
215
|
};
|
|
175
216
|
}
|
|
176
217
|
function browserContextTags(ctx) {
|
|
@@ -179,11 +220,16 @@
|
|
|
179
220
|
"browser.version": ctx.version || "unknown",
|
|
180
221
|
"os.name": ctx.os,
|
|
181
222
|
"os.version": ctx.osVersion || "unknown",
|
|
182
|
-
device: ctx.device
|
|
223
|
+
device: ctx.device,
|
|
224
|
+
...ctx.bot ? {
|
|
225
|
+
bot: "true",
|
|
226
|
+
...ctx.botName ? { "bot.name": ctx.botName } : {}
|
|
227
|
+
} : {}
|
|
183
228
|
};
|
|
184
229
|
}
|
|
185
230
|
async function collectBrowserContext() {
|
|
186
231
|
const base = parseBrowserContext();
|
|
232
|
+
if (base.bot) return base;
|
|
187
233
|
const nav = typeof navigator !== "undefined" ? navigator : void 0;
|
|
188
234
|
const uad = nav?.userAgentData;
|
|
189
235
|
if (!uad) return base;
|
|
@@ -228,7 +274,7 @@
|
|
|
228
274
|
|
|
229
275
|
// src/sdk_meta.ts
|
|
230
276
|
var SDK_NAME = "@newtalaria/browser";
|
|
231
|
-
var SDK_VERSION = "0.1.
|
|
277
|
+
var SDK_VERSION = "0.1.18";
|
|
232
278
|
|
|
233
279
|
// src/transport/serverpod.ts
|
|
234
280
|
var ServerpodTransport = class {
|
|
@@ -13438,18 +13484,22 @@
|
|
|
13438
13484
|
var { takeFullSnapshot } = record;
|
|
13439
13485
|
|
|
13440
13486
|
// src/replay/privacy.ts
|
|
13441
|
-
var
|
|
13487
|
+
var SENSITIVE_QUERY_KEY = /^(?:token|secret|password|auth|api[_-]?key|access[_-]?token|gclid|fbclid|gcl_au|msclkid|_ga(?:_.*)?|cid|sid)$/i;
|
|
13488
|
+
var SENSITIVE_QUERY_LEGACY = /(?:^|[?&])(token|secret|password|auth|api[_-]?key|access[_-]?token|gclid|fbclid|gcl_au|msclkid|_ga(?:_[^=&#]*)?|cid|sid)=([^&#]*)/gi;
|
|
13489
|
+
function isSensitiveQueryKey(key) {
|
|
13490
|
+
return SENSITIVE_QUERY_KEY.test(key);
|
|
13491
|
+
}
|
|
13442
13492
|
function redactUrl(raw) {
|
|
13443
13493
|
try {
|
|
13444
13494
|
const url = new URL(raw, typeof location !== "undefined" ? location.href : void 0);
|
|
13445
13495
|
for (const key of [...url.searchParams.keys()]) {
|
|
13446
|
-
if (
|
|
13496
|
+
if (isSensitiveQueryKey(key)) {
|
|
13447
13497
|
url.searchParams.set(key, "[Filtered]");
|
|
13448
13498
|
}
|
|
13449
13499
|
}
|
|
13450
13500
|
return url.toString();
|
|
13451
13501
|
} catch {
|
|
13452
|
-
return raw.replace(
|
|
13502
|
+
return raw.replace(SENSITIVE_QUERY_LEGACY, (_m, name) => `${name}=[Filtered]`);
|
|
13453
13503
|
}
|
|
13454
13504
|
}
|
|
13455
13505
|
function sanitizeNetworkUrl(raw, opts) {
|
|
@@ -13546,27 +13596,40 @@
|
|
|
13546
13596
|
function isAbortError(error) {
|
|
13547
13597
|
return error instanceof Error && error.name === "AbortError";
|
|
13548
13598
|
}
|
|
13599
|
+
function isTimeoutError(error) {
|
|
13600
|
+
return error instanceof Error && error.name === "TimeoutError";
|
|
13601
|
+
}
|
|
13549
13602
|
function isLikelyNetworkFetchError(error) {
|
|
13550
13603
|
if (!(error instanceof Error)) return false;
|
|
13551
|
-
if (error.name === "AbortError") return false;
|
|
13604
|
+
if (error.name === "AbortError" || error.name === "TimeoutError") return false;
|
|
13552
13605
|
if (error.name === "NetworkError") return true;
|
|
13553
13606
|
const msg = error.message.toLowerCase().trim();
|
|
13554
13607
|
return msg === "failed to fetch" || msg === "load failed" || msg === "networkerror when attempting to fetch resource." || msg.startsWith("networkerror") || msg.includes("failed to fetch");
|
|
13555
13608
|
}
|
|
13609
|
+
function isCorrelatableTransportError(error) {
|
|
13610
|
+
return isLikelyNetworkFetchError(error) || isTimeoutError(error);
|
|
13611
|
+
}
|
|
13556
13612
|
function describeUnknownError(error) {
|
|
13557
13613
|
if (error instanceof Error) {
|
|
13558
13614
|
return {
|
|
13559
13615
|
errorName: error.name || "Error",
|
|
13560
13616
|
errorMessage: (error.message || "").slice(0, 500),
|
|
13561
|
-
aborted: error.name === "AbortError"
|
|
13617
|
+
aborted: error.name === "AbortError",
|
|
13618
|
+
timedOut: error.name === "TimeoutError"
|
|
13562
13619
|
};
|
|
13563
13620
|
}
|
|
13564
13621
|
return {
|
|
13565
13622
|
errorName: "Error",
|
|
13566
13623
|
errorMessage: String(error).slice(0, 500),
|
|
13567
|
-
aborted: false
|
|
13624
|
+
aborted: false,
|
|
13625
|
+
timedOut: false
|
|
13568
13626
|
};
|
|
13569
13627
|
}
|
|
13628
|
+
function classifyTransportFailure(opts) {
|
|
13629
|
+
if (opts.aborted || opts.errorName === "AbortError") return "abort";
|
|
13630
|
+
if (opts.timedOut || opts.errorName === "TimeoutError") return "timeout";
|
|
13631
|
+
return "network";
|
|
13632
|
+
}
|
|
13570
13633
|
|
|
13571
13634
|
// src/replay/hooks.ts
|
|
13572
13635
|
function installVisibilityResumeHook(onResume) {
|
|
@@ -13693,6 +13756,56 @@
|
|
|
13693
13756
|
}
|
|
13694
13757
|
return false;
|
|
13695
13758
|
}
|
|
13759
|
+
function normalizeNetworkOrigin(raw) {
|
|
13760
|
+
const trimmed = (raw || "").trim();
|
|
13761
|
+
if (!trimmed || trimmed === "*") return trimmed;
|
|
13762
|
+
try {
|
|
13763
|
+
return new URL(trimmed).origin;
|
|
13764
|
+
} catch {
|
|
13765
|
+
try {
|
|
13766
|
+
return new URL(`https://${trimmed}`).origin;
|
|
13767
|
+
} catch {
|
|
13768
|
+
return trimmed.replace(/\/+$/, "");
|
|
13769
|
+
}
|
|
13770
|
+
}
|
|
13771
|
+
}
|
|
13772
|
+
function resolvePageOrigin(pageOrigin) {
|
|
13773
|
+
if (pageOrigin) {
|
|
13774
|
+
try {
|
|
13775
|
+
return new URL(pageOrigin).origin;
|
|
13776
|
+
} catch {
|
|
13777
|
+
return pageOrigin.replace(/\/+$/, "");
|
|
13778
|
+
}
|
|
13779
|
+
}
|
|
13780
|
+
if (typeof location !== "undefined" && location.origin) {
|
|
13781
|
+
return location.origin;
|
|
13782
|
+
}
|
|
13783
|
+
return "";
|
|
13784
|
+
}
|
|
13785
|
+
function resolveRequestOrigin(rawUrl, pageOrigin) {
|
|
13786
|
+
const base = pageOrigin || (typeof location !== "undefined" ? location.href : void 0);
|
|
13787
|
+
try {
|
|
13788
|
+
return new URL(rawUrl, base).origin;
|
|
13789
|
+
} catch {
|
|
13790
|
+
return "";
|
|
13791
|
+
}
|
|
13792
|
+
}
|
|
13793
|
+
function isAllowedNetworkOrigin(requestOrigin, opts) {
|
|
13794
|
+
if (!requestOrigin) return false;
|
|
13795
|
+
const allow = opts.networkErrorOrigins.map(normalizeNetworkOrigin);
|
|
13796
|
+
if (allow.includes("*")) return true;
|
|
13797
|
+
const page = resolvePageOrigin(opts.pageOrigin);
|
|
13798
|
+
if (page && requestOrigin === page) return true;
|
|
13799
|
+
return allow.includes(requestOrigin);
|
|
13800
|
+
}
|
|
13801
|
+
function classifyNetworkParty(requestOrigin, pageOrigin) {
|
|
13802
|
+
const page = resolvePageOrigin(pageOrigin);
|
|
13803
|
+
if (page && requestOrigin && requestOrigin === page) return "first_party";
|
|
13804
|
+
return "third_party";
|
|
13805
|
+
}
|
|
13806
|
+
function isHttpOkStatus(status) {
|
|
13807
|
+
return status >= 200 && status < 300;
|
|
13808
|
+
}
|
|
13696
13809
|
function shouldPromoteFailedRequest(meta, opts) {
|
|
13697
13810
|
if (!opts.captureFailedRequests) return false;
|
|
13698
13811
|
if (typeof meta.status !== "number" || Number.isNaN(meta.status)) return false;
|
|
@@ -13703,17 +13816,33 @@
|
|
|
13703
13816
|
opts.talariaBaseUrl
|
|
13704
13817
|
);
|
|
13705
13818
|
if (urlMatchesIgnoreList(meta.url || "", ignore)) return false;
|
|
13819
|
+
const requestOrigin = meta.origin || resolveRequestOrigin(meta.url || "", opts.pageOrigin);
|
|
13820
|
+
if (!isAllowedNetworkOrigin(requestOrigin, {
|
|
13821
|
+
networkErrorOrigins: opts.networkErrorOrigins ?? [],
|
|
13822
|
+
pageOrigin: opts.pageOrigin
|
|
13823
|
+
})) {
|
|
13824
|
+
return false;
|
|
13825
|
+
}
|
|
13706
13826
|
return true;
|
|
13707
13827
|
}
|
|
13708
13828
|
function shouldPromoteNetworkError(meta, opts) {
|
|
13709
13829
|
if (!opts.captureNetworkErrors) return false;
|
|
13710
|
-
if (meta.aborted) return false;
|
|
13711
|
-
if (meta.failureKind !== "network")
|
|
13830
|
+
if (meta.aborted || meta.failureKind === "abort") return false;
|
|
13831
|
+
if (meta.failureKind !== "network" && meta.failureKind !== "timeout") {
|
|
13832
|
+
return false;
|
|
13833
|
+
}
|
|
13712
13834
|
const ignore = buildFailedRequestIgnoreUrls(
|
|
13713
13835
|
opts.failedRequestIgnoreUrls,
|
|
13714
13836
|
opts.talariaBaseUrl
|
|
13715
13837
|
);
|
|
13716
13838
|
if (urlMatchesIgnoreList(meta.url || "", ignore)) return false;
|
|
13839
|
+
const requestOrigin = meta.origin || resolveRequestOrigin(meta.url || "", opts.pageOrigin);
|
|
13840
|
+
if (!isAllowedNetworkOrigin(requestOrigin, {
|
|
13841
|
+
networkErrorOrigins: opts.networkErrorOrigins ?? [],
|
|
13842
|
+
pageOrigin: opts.pageOrigin
|
|
13843
|
+
})) {
|
|
13844
|
+
return false;
|
|
13845
|
+
}
|
|
13717
13846
|
return true;
|
|
13718
13847
|
}
|
|
13719
13848
|
function enrichNetworkMeta(meta) {
|
|
@@ -13724,18 +13853,27 @@
|
|
|
13724
13853
|
failureKind: meta.ok === false ? "http" : meta.failureKind
|
|
13725
13854
|
};
|
|
13726
13855
|
}
|
|
13727
|
-
|
|
13856
|
+
const hasTransportSignal = !!meta.errorName || !!meta.errorMessage || !!meta.aborted || meta.failureKind === "abort" || meta.failureKind === "timeout" || meta.failureKind === "network";
|
|
13857
|
+
if (hasTransportSignal) {
|
|
13858
|
+
const failureKind = meta.failureKind === "abort" || meta.failureKind === "timeout" || meta.failureKind === "network" ? meta.failureKind : classifyTransportFailure({
|
|
13859
|
+
aborted: meta.aborted,
|
|
13860
|
+
errorName: meta.errorName
|
|
13861
|
+
});
|
|
13728
13862
|
return {
|
|
13729
13863
|
...meta,
|
|
13730
|
-
failureKind
|
|
13864
|
+
failureKind,
|
|
13865
|
+
aborted: meta.aborted ?? failureKind === "abort"
|
|
13731
13866
|
};
|
|
13732
13867
|
}
|
|
13733
13868
|
return meta;
|
|
13734
13869
|
}
|
|
13735
|
-
function networkUrlParts(rawUrl, includeQuery) {
|
|
13736
|
-
const
|
|
13870
|
+
function networkUrlParts(rawUrl, includeQuery, pageOrigin) {
|
|
13871
|
+
const baseHref = pageOrigin || (typeof location !== "undefined" ? location.href : void 0);
|
|
13872
|
+
const parts = sanitizeNetworkUrl(rawUrl, { includeQuery, baseHref });
|
|
13873
|
+
const origin = resolveRequestOrigin(rawUrl, pageOrigin);
|
|
13737
13874
|
return {
|
|
13738
13875
|
url: parts.url,
|
|
13876
|
+
origin: origin || void 0,
|
|
13739
13877
|
hostname: parts.hostname,
|
|
13740
13878
|
pathname: parts.pathname,
|
|
13741
13879
|
...parts.search ? { search: parts.search } : {}
|
|
@@ -13751,14 +13889,22 @@
|
|
|
13751
13889
|
captureNetworkErrors: options.captureNetworkErrors ?? true,
|
|
13752
13890
|
failedRequestStatusCodes: options.failedRequestStatusCodes ?? [[500, 599]],
|
|
13753
13891
|
failedRequestIgnoreUrls: options.failedRequestIgnoreUrls ?? [],
|
|
13892
|
+
networkErrorOrigins: options.networkErrorOrigins ?? [],
|
|
13893
|
+
pageOrigin: options.pageOrigin,
|
|
13754
13894
|
talariaBaseUrl: options.talariaBaseUrl
|
|
13755
13895
|
};
|
|
13756
|
-
const includeQuery = options.includeNetworkUrlQuery ?? false;
|
|
13896
|
+
const includeQuery = options.captureRequestQueryParameters ?? options.includeNetworkUrlQuery ?? false;
|
|
13757
13897
|
const handleMeta = (meta) => {
|
|
13758
13898
|
const { rawUrl, ...rest } = meta;
|
|
13899
|
+
const parts = networkUrlParts(rawUrl, includeQuery, matchOpts.pageOrigin);
|
|
13900
|
+
const party = classifyNetworkParty(
|
|
13901
|
+
parts.origin || "",
|
|
13902
|
+
matchOpts.pageOrigin
|
|
13903
|
+
);
|
|
13759
13904
|
const enriched = enrichNetworkMeta({
|
|
13760
13905
|
...rest,
|
|
13761
|
-
...
|
|
13906
|
+
...parts,
|
|
13907
|
+
party
|
|
13762
13908
|
});
|
|
13763
13909
|
try {
|
|
13764
13910
|
emitNetwork(enriched);
|
|
@@ -13778,27 +13924,32 @@
|
|
|
13778
13924
|
const rawUrl = typeof input2 === "string" ? input2 : input2 instanceof URL ? input2.toString() : input2.url;
|
|
13779
13925
|
try {
|
|
13780
13926
|
const response = await originalFetch(input2, init);
|
|
13927
|
+
const opaque = response.type === "opaque" || response.type === "opaqueredirect";
|
|
13781
13928
|
handleMeta({
|
|
13782
13929
|
method,
|
|
13783
13930
|
rawUrl,
|
|
13784
13931
|
url: rawUrl,
|
|
13932
|
+
transport: "fetch",
|
|
13785
13933
|
status: response.status,
|
|
13786
13934
|
durationMs: Date.now() - started,
|
|
13787
|
-
|
|
13935
|
+
// Opaque responses resolve successfully with status 0 — not a failure.
|
|
13936
|
+
ok: opaque ? true : response.ok
|
|
13788
13937
|
});
|
|
13789
13938
|
return response;
|
|
13790
13939
|
} catch (error) {
|
|
13791
13940
|
const described = describeUnknownError(error);
|
|
13941
|
+
const failureKind = classifyTransportFailure(described);
|
|
13792
13942
|
handleMeta({
|
|
13793
13943
|
method,
|
|
13794
13944
|
rawUrl,
|
|
13795
13945
|
url: rawUrl,
|
|
13946
|
+
transport: "fetch",
|
|
13796
13947
|
durationMs: Date.now() - started,
|
|
13797
13948
|
ok: false,
|
|
13798
13949
|
errorName: described.errorName,
|
|
13799
13950
|
errorMessage: described.errorMessage,
|
|
13800
13951
|
aborted: described.aborted,
|
|
13801
|
-
failureKind
|
|
13952
|
+
failureKind
|
|
13802
13953
|
});
|
|
13803
13954
|
throw error;
|
|
13804
13955
|
}
|
|
@@ -13812,25 +13963,48 @@
|
|
|
13812
13963
|
};
|
|
13813
13964
|
XHR.prototype.send = function(body) {
|
|
13814
13965
|
this.__talariaStarted = Date.now();
|
|
13966
|
+
this.__talariaTimedOut = false;
|
|
13967
|
+
this.__talariaAborted = false;
|
|
13968
|
+
this.addEventListener(
|
|
13969
|
+
"timeout",
|
|
13970
|
+
() => {
|
|
13971
|
+
this.__talariaTimedOut = true;
|
|
13972
|
+
},
|
|
13973
|
+
{ once: true }
|
|
13974
|
+
);
|
|
13975
|
+
this.addEventListener(
|
|
13976
|
+
"abort",
|
|
13977
|
+
() => {
|
|
13978
|
+
this.__talariaAborted = true;
|
|
13979
|
+
},
|
|
13980
|
+
{ once: true }
|
|
13981
|
+
);
|
|
13815
13982
|
const onDone = () => {
|
|
13816
13983
|
const status = this.status;
|
|
13817
|
-
const
|
|
13984
|
+
const transportFail = status === 0;
|
|
13818
13985
|
const rawUrl = this.__talariaUrl ?? "";
|
|
13986
|
+
const aborted = !!this.__talariaAborted;
|
|
13987
|
+
const timedOut = !!this.__talariaTimedOut;
|
|
13988
|
+
const failureKind = transportFail ? classifyTransportFailure({ aborted, timedOut }) : void 0;
|
|
13989
|
+
const errorName = transportFail ? failureKind === "abort" ? "AbortError" : failureKind === "timeout" ? "TimeoutError" : "NetworkError" : void 0;
|
|
13990
|
+
const errorMessage = transportFail ? failureKind === "abort" ? "XMLHttpRequest aborted" : failureKind === "timeout" ? "XMLHttpRequest timed out" : "XMLHttpRequest failed (status 0)" : void 0;
|
|
13819
13991
|
handleMeta({
|
|
13820
13992
|
method: this.__talariaMethod ?? "GET",
|
|
13821
13993
|
rawUrl,
|
|
13822
13994
|
url: rawUrl,
|
|
13995
|
+
transport: "xhr",
|
|
13823
13996
|
status,
|
|
13824
13997
|
durationMs: Date.now() - (this.__talariaStarted ?? Date.now()),
|
|
13825
|
-
ok: status
|
|
13826
|
-
...
|
|
13827
|
-
failureKind
|
|
13828
|
-
errorName
|
|
13829
|
-
errorMessage
|
|
13998
|
+
ok: isHttpOkStatus(status),
|
|
13999
|
+
...transportFail ? {
|
|
14000
|
+
failureKind,
|
|
14001
|
+
errorName,
|
|
14002
|
+
errorMessage,
|
|
14003
|
+
aborted
|
|
13830
14004
|
} : {}
|
|
13831
14005
|
});
|
|
13832
14006
|
};
|
|
13833
|
-
this.addEventListener("loadend", onDone);
|
|
14007
|
+
this.addEventListener("loadend", onDone, { once: true });
|
|
13834
14008
|
return originalSend.call(this, body);
|
|
13835
14009
|
};
|
|
13836
14010
|
}
|
|
@@ -13842,20 +14016,54 @@
|
|
|
13842
14016
|
}
|
|
13843
14017
|
|
|
13844
14018
|
// src/client.ts
|
|
13845
|
-
function
|
|
14019
|
+
function networkExceptionClass(failure) {
|
|
14020
|
+
if (failure.failureKind === "http") return "HttpError";
|
|
14021
|
+
if (failure.failureKind === "timeout") return "TimeoutError";
|
|
14022
|
+
return "NetworkError";
|
|
14023
|
+
}
|
|
14024
|
+
function networkFailureTags(failure) {
|
|
13846
14025
|
return {
|
|
14026
|
+
"http.method": failure.method || "GET",
|
|
14027
|
+
"network.failure_kind": failure.failureKind ?? "network",
|
|
14028
|
+
...failure.party ? { "network.party": failure.party } : {},
|
|
14029
|
+
...failure.transport ? { "network.transport": failure.transport } : {},
|
|
14030
|
+
...failure.errorName ? { "network.error_name": failure.errorName } : {}
|
|
14031
|
+
};
|
|
14032
|
+
}
|
|
14033
|
+
function networkFailureExtra(failure) {
|
|
14034
|
+
const http = {
|
|
13847
14035
|
method: failure.method || "GET",
|
|
13848
|
-
url: failure.url || "(unknown url)"
|
|
13849
|
-
|
|
13850
|
-
|
|
13851
|
-
|
|
13852
|
-
|
|
14036
|
+
url: failure.url || "(unknown url)"
|
|
14037
|
+
};
|
|
14038
|
+
if (failure.origin) http.origin = failure.origin;
|
|
14039
|
+
if (failure.hostname) http.hostname = failure.hostname;
|
|
14040
|
+
if (failure.pathname) http.pathname = failure.pathname;
|
|
14041
|
+
if (failure.search) http.search = failure.search;
|
|
14042
|
+
if (typeof failure.status === "number" && failure.status > 0) {
|
|
14043
|
+
http.status = failure.status;
|
|
14044
|
+
}
|
|
14045
|
+
if (failure.transport) http.transport = failure.transport;
|
|
14046
|
+
const fail = {
|
|
14047
|
+
kind: failure.failureKind ?? "network"
|
|
14048
|
+
};
|
|
14049
|
+
if (failure.errorName) fail.name = failure.errorName;
|
|
14050
|
+
if (failure.errorMessage) fail.message = failure.errorMessage;
|
|
14051
|
+
const statusCode = typeof failure.status === "number" && failure.status > 0 ? failure.status : null;
|
|
14052
|
+
return {
|
|
14053
|
+
http,
|
|
14054
|
+
failure: fail,
|
|
14055
|
+
network: {
|
|
14056
|
+
party: failure.party ?? "third_party",
|
|
14057
|
+
durationMs: failure.durationMs,
|
|
14058
|
+
aborted: failure.aborted ?? false,
|
|
14059
|
+
ok: failure.ok ?? false
|
|
14060
|
+
},
|
|
14061
|
+
// Top-level for server fingerprint compatibility.
|
|
14062
|
+
status_code: statusCode,
|
|
14063
|
+
exception_class: networkExceptionClass(failure),
|
|
13853
14064
|
durationMs: failure.durationMs,
|
|
13854
|
-
ok: failure.ok ?? false,
|
|
13855
|
-
failureKind: failure.failureKind ?? "network",
|
|
13856
14065
|
aborted: failure.aborted ?? false,
|
|
13857
|
-
|
|
13858
|
-
...failure.errorMessage ? { errorMessage: failure.errorMessage } : {}
|
|
14066
|
+
ok: failure.ok ?? false
|
|
13859
14067
|
};
|
|
13860
14068
|
}
|
|
13861
14069
|
function mergeNetworkFailureContext(context, failure) {
|
|
@@ -13863,13 +14071,11 @@
|
|
|
13863
14071
|
...context,
|
|
13864
14072
|
tags: {
|
|
13865
14073
|
...context?.tags ?? {},
|
|
13866
|
-
|
|
13867
|
-
"network.failure_kind": "network",
|
|
13868
|
-
...failure.errorName ? { "network.error_name": failure.errorName } : {}
|
|
14074
|
+
...networkFailureTags(failure)
|
|
13869
14075
|
},
|
|
13870
14076
|
extra: {
|
|
13871
14077
|
...context?.extra ?? {},
|
|
13872
|
-
|
|
14078
|
+
...networkFailureExtra(failure)
|
|
13873
14079
|
}
|
|
13874
14080
|
};
|
|
13875
14081
|
}
|
|
@@ -13900,7 +14106,8 @@
|
|
|
13900
14106
|
disableDefaultIntegrations: options.disableDefaultIntegrations ?? false,
|
|
13901
14107
|
captureFailedRequests: options.captureFailedRequests ?? true,
|
|
13902
14108
|
captureNetworkErrors: options.captureNetworkErrors ?? true,
|
|
13903
|
-
|
|
14109
|
+
networkErrorOrigins: options.networkErrorOrigins ?? [],
|
|
14110
|
+
includeNetworkUrlQuery: options.captureRequestQueryParameters ?? options.includeNetworkUrlQuery ?? false,
|
|
13904
14111
|
failedRequestStatusCodes: options.failedRequestStatusCodes ?? [[500, 599]],
|
|
13905
14112
|
failedRequestIgnoreUrls: options.failedRequestIgnoreUrls ?? []
|
|
13906
14113
|
};
|
|
@@ -14029,12 +14236,14 @@
|
|
|
14029
14236
|
installNetworkHook({
|
|
14030
14237
|
captureFailedRequests: this.options.captureFailedRequests,
|
|
14031
14238
|
captureNetworkErrors: this.options.captureNetworkErrors,
|
|
14239
|
+
networkErrorOrigins: this.options.networkErrorOrigins,
|
|
14240
|
+
pageOrigin: typeof location !== "undefined" ? location.origin : void 0,
|
|
14032
14241
|
includeNetworkUrlQuery: this.options.includeNetworkUrlQuery,
|
|
14033
14242
|
failedRequestStatusCodes: this.options.failedRequestStatusCodes,
|
|
14034
14243
|
failedRequestIgnoreUrls: this.options.failedRequestIgnoreUrls,
|
|
14035
14244
|
talariaBaseUrl: this.options.baseUrl,
|
|
14036
14245
|
onNetwork: (meta) => {
|
|
14037
|
-
if (meta.failureKind === "network" && !meta.aborted) {
|
|
14246
|
+
if ((meta.failureKind === "network" || meta.failureKind === "timeout") && !meta.aborted) {
|
|
14038
14247
|
this.rememberNetworkFailure(meta, { promoted: false });
|
|
14039
14248
|
}
|
|
14040
14249
|
},
|
|
@@ -14042,22 +14251,20 @@
|
|
|
14042
14251
|
const status = meta.status;
|
|
14043
14252
|
const method = meta.method || "GET";
|
|
14044
14253
|
const url = meta.url || "(unknown url)";
|
|
14254
|
+
const enriched = {
|
|
14255
|
+
...meta,
|
|
14256
|
+
failureKind: "http",
|
|
14257
|
+
aborted: false
|
|
14258
|
+
};
|
|
14045
14259
|
void this.captureMessage(
|
|
14046
14260
|
`HTTP ${status}: ${method} ${url}`,
|
|
14047
14261
|
status >= 500 ? "error" : "warning",
|
|
14048
14262
|
{
|
|
14049
14263
|
tags: {
|
|
14050
|
-
|
|
14051
|
-
"http.
|
|
14052
|
-
"network.failure_kind": "http"
|
|
14264
|
+
...networkFailureTags(enriched),
|
|
14265
|
+
"http.status_code": String(status)
|
|
14053
14266
|
},
|
|
14054
|
-
extra:
|
|
14055
|
-
...networkFailureExtra({
|
|
14056
|
-
...meta,
|
|
14057
|
-
failureKind: "http",
|
|
14058
|
-
aborted: false
|
|
14059
|
-
})
|
|
14060
|
-
}
|
|
14267
|
+
extra: networkFailureExtra(enriched)
|
|
14061
14268
|
}
|
|
14062
14269
|
);
|
|
14063
14270
|
},
|
|
@@ -14066,20 +14273,13 @@
|
|
|
14066
14273
|
const method = meta.method || "GET";
|
|
14067
14274
|
const url = meta.url || "(unknown url)";
|
|
14068
14275
|
const errLabel = meta.errorName && meta.errorMessage ? `${meta.errorName}: ${meta.errorMessage}` : meta.errorMessage || meta.errorName || "Failed to fetch";
|
|
14276
|
+
const prefix = meta.failureKind === "timeout" ? "Timeout error" : "Network error";
|
|
14069
14277
|
void this.captureMessage(
|
|
14070
|
-
|
|
14278
|
+
`${prefix}: ${method} ${url} \u2014 ${errLabel}`,
|
|
14071
14279
|
"error",
|
|
14072
14280
|
{
|
|
14073
|
-
tags:
|
|
14074
|
-
|
|
14075
|
-
"network.failure_kind": "network",
|
|
14076
|
-
...meta.errorName ? { "network.error_name": meta.errorName } : {}
|
|
14077
|
-
},
|
|
14078
|
-
extra: networkFailureExtra({
|
|
14079
|
-
...meta,
|
|
14080
|
-
failureKind: "network",
|
|
14081
|
-
aborted: false
|
|
14082
|
-
})
|
|
14281
|
+
tags: networkFailureTags(meta),
|
|
14282
|
+
extra: networkFailureExtra(meta)
|
|
14083
14283
|
}
|
|
14084
14284
|
);
|
|
14085
14285
|
}
|
|
@@ -14131,6 +14331,7 @@
|
|
|
14131
14331
|
}
|
|
14132
14332
|
const correlated = this.consumeCorrelatedNetworkFailure(err);
|
|
14133
14333
|
if (correlated?.promoted) return;
|
|
14334
|
+
if (correlated && correlated.party === "third_party") return;
|
|
14134
14335
|
const mergedContext = correlated ? mergeNetworkFailureContext(context, correlated) : context;
|
|
14135
14336
|
this.capturing = true;
|
|
14136
14337
|
try {
|
|
@@ -14335,7 +14536,9 @@
|
|
|
14335
14536
|
osVersion: this.browserContext.osVersion,
|
|
14336
14537
|
device: this.browserContext.device,
|
|
14337
14538
|
language: this.browserContext.language,
|
|
14338
|
-
userAgent: this.browserContext.userAgent
|
|
14539
|
+
userAgent: this.browserContext.userAgent,
|
|
14540
|
+
bot: this.browserContext.bot,
|
|
14541
|
+
...this.browserContext.botName ? { botName: this.browserContext.botName } : {}
|
|
14339
14542
|
}
|
|
14340
14543
|
} : {},
|
|
14341
14544
|
sdk: {
|
|
@@ -14611,6 +14814,13 @@
|
|
|
14611
14814
|
);
|
|
14612
14815
|
}
|
|
14613
14816
|
rememberNetworkFailure(meta, opts) {
|
|
14817
|
+
if (this.options) {
|
|
14818
|
+
const ignore = buildFailedRequestIgnoreUrls(
|
|
14819
|
+
this.options.failedRequestIgnoreUrls,
|
|
14820
|
+
this.options.baseUrl
|
|
14821
|
+
);
|
|
14822
|
+
if (urlMatchesIgnoreList(meta.url || "", ignore)) return;
|
|
14823
|
+
}
|
|
14614
14824
|
const now = Date.now();
|
|
14615
14825
|
this.pruneRecentNetworkFailures(now);
|
|
14616
14826
|
for (let i = this.recentNetworkFailures.length - 1; i >= 0; i--) {
|
|
@@ -14621,6 +14831,8 @@
|
|
|
14621
14831
|
existing.errorName = meta.errorName ?? existing.errorName;
|
|
14622
14832
|
existing.aborted = meta.aborted ?? existing.aborted;
|
|
14623
14833
|
existing.failureKind = meta.failureKind ?? existing.failureKind;
|
|
14834
|
+
existing.party = meta.party ?? existing.party;
|
|
14835
|
+
existing.origin = meta.origin ?? existing.origin;
|
|
14624
14836
|
return;
|
|
14625
14837
|
}
|
|
14626
14838
|
}
|
|
@@ -14631,11 +14843,12 @@
|
|
|
14631
14843
|
});
|
|
14632
14844
|
}
|
|
14633
14845
|
/**
|
|
14634
|
-
* Find a recent transport failure for a bare fetch TypeError.
|
|
14846
|
+
* Find a recent transport failure for a bare fetch TypeError / TimeoutError.
|
|
14635
14847
|
* Consumes the entry so a later duplicate path cannot reuse it.
|
|
14636
14848
|
*/
|
|
14637
14849
|
consumeCorrelatedNetworkFailure(error) {
|
|
14638
|
-
if (!
|
|
14850
|
+
if (!isCorrelatableTransportError(error)) return null;
|
|
14851
|
+
const wantKind = isTimeoutError(error) ? "timeout" : "network";
|
|
14639
14852
|
const now = Date.now();
|
|
14640
14853
|
this.pruneRecentNetworkFailures(now);
|
|
14641
14854
|
const takeAt = (index2) => {
|
|
@@ -14644,14 +14857,14 @@
|
|
|
14644
14857
|
};
|
|
14645
14858
|
for (let i = this.recentNetworkFailures.length - 1; i >= 0; i--) {
|
|
14646
14859
|
const failure = this.recentNetworkFailures[i];
|
|
14647
|
-
if (failure.aborted || failure.failureKind !==
|
|
14860
|
+
if (failure.aborted || failure.failureKind !== wantKind) continue;
|
|
14648
14861
|
if (failure.errorMessage && failure.errorMessage === error.message) {
|
|
14649
14862
|
return takeAt(i);
|
|
14650
14863
|
}
|
|
14651
14864
|
}
|
|
14652
14865
|
for (let i = this.recentNetworkFailures.length - 1; i >= 0; i--) {
|
|
14653
14866
|
const failure = this.recentNetworkFailures[i];
|
|
14654
|
-
if (failure.aborted || failure.failureKind !==
|
|
14867
|
+
if (failure.aborted || failure.failureKind !== wantKind) continue;
|
|
14655
14868
|
return takeAt(i);
|
|
14656
14869
|
}
|
|
14657
14870
|
return null;
|