@newtalaria/browser 0.1.17 → 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 +77 -15
- package/dist/client.d.ts +1 -1
- package/dist/client.d.ts.map +1 -1
- package/dist/index.js +134 -15
- package/dist/index.js.map +2 -2
- package/dist/replay/hooks.d.ts +45 -2
- 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 +134 -15
- package/dist/talaria.browser.iife.js.map +2 -2
- package/dist/types.d.ts +13 -4
- package/dist/types.d.ts.map +1 -1
- package/dist/utils/network_error.d.ts +5 -0
- package/dist/utils/network_error.d.ts.map +1 -1
- package/package.json +1 -1
package/dist/replay/hooks.d.ts
CHANGED
|
@@ -1,4 +1,11 @@
|
|
|
1
1
|
import type { FailedRequestStatusCode } from '../types.js';
|
|
2
|
+
/**
|
|
3
|
+
* Fetch / XHR instrumentation for replay breadcrumbs and optional error promotion.
|
|
4
|
+
*
|
|
5
|
+
* Policy (see package README): always emit `talaria-network` breadcrumbs; promote
|
|
6
|
+
* to Talaria events only for same-origin or `networkErrorOrigins` (never invent
|
|
7
|
+
* a `cors` failure kind from status 0 / Failed to fetch).
|
|
8
|
+
*/
|
|
2
9
|
/** How the request was issued. */
|
|
3
10
|
export type NetworkTransport = 'fetch' | 'xhr';
|
|
4
11
|
/**
|
|
@@ -7,6 +14,8 @@ export type NetworkTransport = 'fetch' | 'xhr';
|
|
|
7
14
|
* (status 0 / Failed to fetch cover many causes).
|
|
8
15
|
*/
|
|
9
16
|
export type NetworkFailureKind = 'http' | 'network' | 'abort' | 'timeout';
|
|
17
|
+
/** Same-origin vs cross-origin relative to the page. */
|
|
18
|
+
export type NetworkParty = 'first_party' | 'third_party';
|
|
10
19
|
export type Teardown = () => void;
|
|
11
20
|
/**
|
|
12
21
|
* Fire when the document becomes visible again (tab focus) or is restored
|
|
@@ -18,6 +27,8 @@ export interface NetworkMeta {
|
|
|
18
27
|
method: string;
|
|
19
28
|
/** Sanitized request URL (origin + pathname; query stripped by default). */
|
|
20
29
|
url: string;
|
|
30
|
+
/** Request origin (scheme + host + port). */
|
|
31
|
+
origin?: string;
|
|
21
32
|
hostname?: string;
|
|
22
33
|
pathname?: string;
|
|
23
34
|
/** Only when query capture is enabled. */
|
|
@@ -31,6 +42,8 @@ export interface NetworkMeta {
|
|
|
31
42
|
errorMessage?: string;
|
|
32
43
|
aborted?: boolean;
|
|
33
44
|
failureKind?: NetworkFailureKind;
|
|
45
|
+
/** Same-origin (`first_party`) vs cross-origin (`third_party`). */
|
|
46
|
+
party?: NetworkParty;
|
|
34
47
|
}
|
|
35
48
|
export interface NetworkHookOptions {
|
|
36
49
|
/** Still emit rrweb breadcrumbs for all requests. */
|
|
@@ -48,8 +61,17 @@ export interface NetworkHookOptions {
|
|
|
48
61
|
*/
|
|
49
62
|
onNetworkError?: (meta: NetworkMeta) => void;
|
|
50
63
|
captureFailedRequests?: boolean;
|
|
51
|
-
/** Promote
|
|
64
|
+
/** Promote transport failures for first-party / allowlisted origins (default `true`). */
|
|
52
65
|
captureNetworkErrors?: boolean;
|
|
66
|
+
/**
|
|
67
|
+
* Extra origins eligible for error promotion (exact origin strings).
|
|
68
|
+
* Same-origin is always eligible. `['*']` promotes all origins.
|
|
69
|
+
*/
|
|
70
|
+
networkErrorOrigins?: string[];
|
|
71
|
+
/**
|
|
72
|
+
* Override page origin (tests / non-browser). Defaults to `location.origin`.
|
|
73
|
+
*/
|
|
74
|
+
pageOrigin?: string;
|
|
53
75
|
/**
|
|
54
76
|
* Keep URL query strings in network telemetry (after sensitive-key redaction).
|
|
55
77
|
* Default `false`. Prefer `captureRequestQueryParameters` (same meaning).
|
|
@@ -68,10 +90,28 @@ export declare function statusMatches(status: number, codes: FailedRequestStatus
|
|
|
68
90
|
/** Shared ignore list for HTTP + network failure promotion. */
|
|
69
91
|
export declare function buildFailedRequestIgnoreUrls(failedRequestIgnoreUrls: string[], talariaBaseUrl?: string): string[];
|
|
70
92
|
export declare function urlMatchesIgnoreList(url: string, ignoreUrls: string[]): boolean;
|
|
93
|
+
/** Normalize an allowlist entry to an origin string (`https://host:port`). */
|
|
94
|
+
export declare function normalizeNetworkOrigin(raw: string): string;
|
|
95
|
+
export declare function resolvePageOrigin(pageOrigin?: string): string;
|
|
96
|
+
/** Resolve the request origin from a (possibly relative) URL. */
|
|
97
|
+
export declare function resolveRequestOrigin(rawUrl: string, pageOrigin?: string): string;
|
|
98
|
+
/**
|
|
99
|
+
* Whether a request origin may be promoted to an error event.
|
|
100
|
+
* Same-origin and `networkErrorOrigins` entries (or `*`) are allowed.
|
|
101
|
+
*/
|
|
102
|
+
export declare function isAllowedNetworkOrigin(requestOrigin: string, opts: {
|
|
103
|
+
networkErrorOrigins: string[];
|
|
104
|
+
pageOrigin?: string;
|
|
105
|
+
}): boolean;
|
|
106
|
+
export declare function classifyNetworkParty(requestOrigin: string, pageOrigin?: string): NetworkParty;
|
|
107
|
+
/** HTTP success = 2xx (aligned for fetch and XHR). */
|
|
108
|
+
export declare function isHttpOkStatus(status: number): boolean;
|
|
71
109
|
export declare function shouldPromoteFailedRequest(meta: NetworkMeta, opts: {
|
|
72
110
|
captureFailedRequests: boolean;
|
|
73
111
|
failedRequestStatusCodes: FailedRequestStatusCode[];
|
|
74
112
|
failedRequestIgnoreUrls: string[];
|
|
113
|
+
networkErrorOrigins?: string[];
|
|
114
|
+
pageOrigin?: string;
|
|
75
115
|
talariaBaseUrl?: string;
|
|
76
116
|
}): meta is NetworkMeta & {
|
|
77
117
|
status: number;
|
|
@@ -79,15 +119,18 @@ export declare function shouldPromoteFailedRequest(meta: NetworkMeta, opts: {
|
|
|
79
119
|
/**
|
|
80
120
|
* Promote fetch rejects / XHR status-0 failures (offline, DNS, blocked, etc.).
|
|
81
121
|
* Abort is never promoted; timeout may be promoted as `failureKind: timeout`.
|
|
122
|
+
* Third-party origins are skipped unless allowlisted (or `*`).
|
|
82
123
|
*/
|
|
83
124
|
export declare function shouldPromoteNetworkError(meta: NetworkMeta, opts: {
|
|
84
125
|
captureNetworkErrors: boolean;
|
|
85
126
|
failedRequestIgnoreUrls: string[];
|
|
127
|
+
networkErrorOrigins?: string[];
|
|
128
|
+
pageOrigin?: string;
|
|
86
129
|
talariaBaseUrl?: string;
|
|
87
130
|
}): boolean;
|
|
88
131
|
export declare function enrichNetworkMeta(meta: NetworkMeta): NetworkMeta;
|
|
89
132
|
/** Apply privacy sanitization to a raw request URL for network meta. */
|
|
90
|
-
export declare function networkUrlParts(rawUrl: string, includeQuery: boolean): Pick<NetworkMeta, 'url' | 'hostname' | 'pathname' | 'search'>;
|
|
133
|
+
export declare function networkUrlParts(rawUrl: string, includeQuery: boolean, pageOrigin?: string): Pick<NetworkMeta, 'url' | 'origin' | 'hostname' | 'pathname' | 'search'>;
|
|
91
134
|
/** Capture fetch / XHR metadata (no bodies, no auth headers); optionally promote failures. */
|
|
92
135
|
export declare function installNetworkHook(options?: NetworkHookOptions): Teardown;
|
|
93
136
|
//# sourceMappingURL=hooks.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"hooks.d.ts","sourceRoot":"","sources":["../../src/replay/hooks.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,uBAAuB,EAAE,MAAM,aAAa,CAAC;AAM3D,kCAAkC;AAClC,MAAM,MAAM,gBAAgB,GAAG,OAAO,GAAG,KAAK,CAAC;AAE/C;;;;GAIG;AACH,MAAM,MAAM,kBAAkB,GAAG,MAAM,GAAG,SAAS,GAAG,OAAO,GAAG,SAAS,CAAC;AAE1E,MAAM,MAAM,QAAQ,GAAG,MAAM,IAAI,CAAC;AAElC;;;;GAIG;AACH,wBAAgB,2BAA2B,CAAC,QAAQ,EAAE,MAAM,IAAI,GAAG,QAAQ,CA4B1E;AAED,MAAM,WAAW,WAAW;IAC1B,MAAM,EAAE,MAAM,CAAC;IACf,4EAA4E;IAC5E,GAAG,EAAE,MAAM,CAAC;IACZ,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,0CAA0C;IAC1C,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,EAAE,CAAC,EAAE,OAAO,CAAC;IACb,SAAS,CAAC,EAAE,gBAAgB,CAAC;IAC7B,mEAAmE;IACnE,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,WAAW,CAAC,EAAE,kBAAkB,CAAC;
|
|
1
|
+
{"version":3,"file":"hooks.d.ts","sourceRoot":"","sources":["../../src/replay/hooks.ts"],"names":[],"mappings":"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"}
|
package/dist/replay/privacy.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
/** Redact sensitive query params from a URL (keeps other query keys). */
|
|
1
|
+
/** Redact sensitive / tracking query params from a URL (keeps other query keys). */
|
|
2
2
|
export declare function redactUrl(raw: string): string;
|
|
3
3
|
export interface SanitizedNetworkUrl {
|
|
4
4
|
/** Safe URL for telemetry: origin + pathname (no query/hash by default). */
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"privacy.d.ts","sourceRoot":"","sources":["../../src/replay/privacy.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"privacy.d.ts","sourceRoot":"","sources":["../../src/replay/privacy.ts"],"names":[],"mappings":"AAUA,oFAAoF;AACpF,wBAAgB,SAAS,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAY7C;AAED,MAAM,WAAW,mBAAmB;IAClC,4EAA4E;IAC5E,GAAG,EAAE,MAAM,CAAC;IACZ,QAAQ,EAAE,MAAM,CAAC;IACjB,QAAQ,EAAE,MAAM,CAAC;IACjB,mFAAmF;IACnF,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAED;;;;GAIG;AACH,wBAAgB,kBAAkB,CAChC,GAAG,EAAE,MAAM,EACX,IAAI,CAAC,EAAE;IAAE,YAAY,CAAC,EAAE,OAAO,CAAC;IAAC,QAAQ,CAAC,EAAE,MAAM,CAAA;CAAE,GACnD,mBAAmB,CAsCrB;AAED,wBAAgB,oBAAoB,CAAC,KAAK,CAAC,EAAE,MAAM,GAAG,MAAM,CAU3D"}
|
package/dist/sdk_meta.d.ts
CHANGED
|
@@ -274,7 +274,7 @@
|
|
|
274
274
|
|
|
275
275
|
// src/sdk_meta.ts
|
|
276
276
|
var SDK_NAME = "@newtalaria/browser";
|
|
277
|
-
var SDK_VERSION = "0.1.
|
|
277
|
+
var SDK_VERSION = "0.1.18";
|
|
278
278
|
|
|
279
279
|
// src/transport/serverpod.ts
|
|
280
280
|
var ServerpodTransport = class {
|
|
@@ -13484,18 +13484,22 @@
|
|
|
13484
13484
|
var { takeFullSnapshot } = record;
|
|
13485
13485
|
|
|
13486
13486
|
// src/replay/privacy.ts
|
|
13487
|
-
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
|
+
}
|
|
13488
13492
|
function redactUrl(raw) {
|
|
13489
13493
|
try {
|
|
13490
13494
|
const url = new URL(raw, typeof location !== "undefined" ? location.href : void 0);
|
|
13491
13495
|
for (const key of [...url.searchParams.keys()]) {
|
|
13492
|
-
if (
|
|
13496
|
+
if (isSensitiveQueryKey(key)) {
|
|
13493
13497
|
url.searchParams.set(key, "[Filtered]");
|
|
13494
13498
|
}
|
|
13495
13499
|
}
|
|
13496
13500
|
return url.toString();
|
|
13497
13501
|
} catch {
|
|
13498
|
-
return raw.replace(
|
|
13502
|
+
return raw.replace(SENSITIVE_QUERY_LEGACY, (_m, name) => `${name}=[Filtered]`);
|
|
13499
13503
|
}
|
|
13500
13504
|
}
|
|
13501
13505
|
function sanitizeNetworkUrl(raw, opts) {
|
|
@@ -13592,6 +13596,9 @@
|
|
|
13592
13596
|
function isAbortError(error) {
|
|
13593
13597
|
return error instanceof Error && error.name === "AbortError";
|
|
13594
13598
|
}
|
|
13599
|
+
function isTimeoutError(error) {
|
|
13600
|
+
return error instanceof Error && error.name === "TimeoutError";
|
|
13601
|
+
}
|
|
13595
13602
|
function isLikelyNetworkFetchError(error) {
|
|
13596
13603
|
if (!(error instanceof Error)) return false;
|
|
13597
13604
|
if (error.name === "AbortError" || error.name === "TimeoutError") return false;
|
|
@@ -13599,6 +13606,9 @@
|
|
|
13599
13606
|
const msg = error.message.toLowerCase().trim();
|
|
13600
13607
|
return msg === "failed to fetch" || msg === "load failed" || msg === "networkerror when attempting to fetch resource." || msg.startsWith("networkerror") || msg.includes("failed to fetch");
|
|
13601
13608
|
}
|
|
13609
|
+
function isCorrelatableTransportError(error) {
|
|
13610
|
+
return isLikelyNetworkFetchError(error) || isTimeoutError(error);
|
|
13611
|
+
}
|
|
13602
13612
|
function describeUnknownError(error) {
|
|
13603
13613
|
if (error instanceof Error) {
|
|
13604
13614
|
return {
|
|
@@ -13746,6 +13756,56 @@
|
|
|
13746
13756
|
}
|
|
13747
13757
|
return false;
|
|
13748
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
|
+
}
|
|
13749
13809
|
function shouldPromoteFailedRequest(meta, opts) {
|
|
13750
13810
|
if (!opts.captureFailedRequests) return false;
|
|
13751
13811
|
if (typeof meta.status !== "number" || Number.isNaN(meta.status)) return false;
|
|
@@ -13756,6 +13816,13 @@
|
|
|
13756
13816
|
opts.talariaBaseUrl
|
|
13757
13817
|
);
|
|
13758
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
|
+
}
|
|
13759
13826
|
return true;
|
|
13760
13827
|
}
|
|
13761
13828
|
function shouldPromoteNetworkError(meta, opts) {
|
|
@@ -13769,6 +13836,13 @@
|
|
|
13769
13836
|
opts.talariaBaseUrl
|
|
13770
13837
|
);
|
|
13771
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
|
+
}
|
|
13772
13846
|
return true;
|
|
13773
13847
|
}
|
|
13774
13848
|
function enrichNetworkMeta(meta) {
|
|
@@ -13779,7 +13853,8 @@
|
|
|
13779
13853
|
failureKind: meta.ok === false ? "http" : meta.failureKind
|
|
13780
13854
|
};
|
|
13781
13855
|
}
|
|
13782
|
-
|
|
13856
|
+
const hasTransportSignal = !!meta.errorName || !!meta.errorMessage || !!meta.aborted || meta.failureKind === "abort" || meta.failureKind === "timeout" || meta.failureKind === "network";
|
|
13857
|
+
if (hasTransportSignal) {
|
|
13783
13858
|
const failureKind = meta.failureKind === "abort" || meta.failureKind === "timeout" || meta.failureKind === "network" ? meta.failureKind : classifyTransportFailure({
|
|
13784
13859
|
aborted: meta.aborted,
|
|
13785
13860
|
errorName: meta.errorName
|
|
@@ -13792,10 +13867,13 @@
|
|
|
13792
13867
|
}
|
|
13793
13868
|
return meta;
|
|
13794
13869
|
}
|
|
13795
|
-
function networkUrlParts(rawUrl, includeQuery) {
|
|
13796
|
-
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);
|
|
13797
13874
|
return {
|
|
13798
13875
|
url: parts.url,
|
|
13876
|
+
origin: origin || void 0,
|
|
13799
13877
|
hostname: parts.hostname,
|
|
13800
13878
|
pathname: parts.pathname,
|
|
13801
13879
|
...parts.search ? { search: parts.search } : {}
|
|
@@ -13811,14 +13889,22 @@
|
|
|
13811
13889
|
captureNetworkErrors: options.captureNetworkErrors ?? true,
|
|
13812
13890
|
failedRequestStatusCodes: options.failedRequestStatusCodes ?? [[500, 599]],
|
|
13813
13891
|
failedRequestIgnoreUrls: options.failedRequestIgnoreUrls ?? [],
|
|
13892
|
+
networkErrorOrigins: options.networkErrorOrigins ?? [],
|
|
13893
|
+
pageOrigin: options.pageOrigin,
|
|
13814
13894
|
talariaBaseUrl: options.talariaBaseUrl
|
|
13815
13895
|
};
|
|
13816
13896
|
const includeQuery = options.captureRequestQueryParameters ?? options.includeNetworkUrlQuery ?? false;
|
|
13817
13897
|
const handleMeta = (meta) => {
|
|
13818
13898
|
const { rawUrl, ...rest } = meta;
|
|
13899
|
+
const parts = networkUrlParts(rawUrl, includeQuery, matchOpts.pageOrigin);
|
|
13900
|
+
const party = classifyNetworkParty(
|
|
13901
|
+
parts.origin || "",
|
|
13902
|
+
matchOpts.pageOrigin
|
|
13903
|
+
);
|
|
13819
13904
|
const enriched = enrichNetworkMeta({
|
|
13820
13905
|
...rest,
|
|
13821
|
-
...
|
|
13906
|
+
...parts,
|
|
13907
|
+
party
|
|
13822
13908
|
});
|
|
13823
13909
|
try {
|
|
13824
13910
|
emitNetwork(enriched);
|
|
@@ -13838,6 +13924,7 @@
|
|
|
13838
13924
|
const rawUrl = typeof input2 === "string" ? input2 : input2 instanceof URL ? input2.toString() : input2.url;
|
|
13839
13925
|
try {
|
|
13840
13926
|
const response = await originalFetch(input2, init);
|
|
13927
|
+
const opaque = response.type === "opaque" || response.type === "opaqueredirect";
|
|
13841
13928
|
handleMeta({
|
|
13842
13929
|
method,
|
|
13843
13930
|
rawUrl,
|
|
@@ -13845,7 +13932,8 @@
|
|
|
13845
13932
|
transport: "fetch",
|
|
13846
13933
|
status: response.status,
|
|
13847
13934
|
durationMs: Date.now() - started,
|
|
13848
|
-
|
|
13935
|
+
// Opaque responses resolve successfully with status 0 — not a failure.
|
|
13936
|
+
ok: opaque ? true : response.ok
|
|
13849
13937
|
});
|
|
13850
13938
|
return response;
|
|
13851
13939
|
} catch (error) {
|
|
@@ -13907,7 +13995,7 @@
|
|
|
13907
13995
|
transport: "xhr",
|
|
13908
13996
|
status,
|
|
13909
13997
|
durationMs: Date.now() - (this.__talariaStarted ?? Date.now()),
|
|
13910
|
-
ok: status
|
|
13998
|
+
ok: isHttpOkStatus(status),
|
|
13911
13999
|
...transportFail ? {
|
|
13912
14000
|
failureKind,
|
|
13913
14001
|
errorName,
|
|
@@ -13916,7 +14004,7 @@
|
|
|
13916
14004
|
} : {}
|
|
13917
14005
|
});
|
|
13918
14006
|
};
|
|
13919
|
-
this.addEventListener("loadend", onDone);
|
|
14007
|
+
this.addEventListener("loadend", onDone, { once: true });
|
|
13920
14008
|
return originalSend.call(this, body);
|
|
13921
14009
|
};
|
|
13922
14010
|
}
|
|
@@ -13928,10 +14016,16 @@
|
|
|
13928
14016
|
}
|
|
13929
14017
|
|
|
13930
14018
|
// src/client.ts
|
|
14019
|
+
function networkExceptionClass(failure) {
|
|
14020
|
+
if (failure.failureKind === "http") return "HttpError";
|
|
14021
|
+
if (failure.failureKind === "timeout") return "TimeoutError";
|
|
14022
|
+
return "NetworkError";
|
|
14023
|
+
}
|
|
13931
14024
|
function networkFailureTags(failure) {
|
|
13932
14025
|
return {
|
|
13933
14026
|
"http.method": failure.method || "GET",
|
|
13934
14027
|
"network.failure_kind": failure.failureKind ?? "network",
|
|
14028
|
+
...failure.party ? { "network.party": failure.party } : {},
|
|
13935
14029
|
...failure.transport ? { "network.transport": failure.transport } : {},
|
|
13936
14030
|
...failure.errorName ? { "network.error_name": failure.errorName } : {}
|
|
13937
14031
|
};
|
|
@@ -13941,6 +14035,7 @@
|
|
|
13941
14035
|
method: failure.method || "GET",
|
|
13942
14036
|
url: failure.url || "(unknown url)"
|
|
13943
14037
|
};
|
|
14038
|
+
if (failure.origin) http.origin = failure.origin;
|
|
13944
14039
|
if (failure.hostname) http.hostname = failure.hostname;
|
|
13945
14040
|
if (failure.pathname) http.pathname = failure.pathname;
|
|
13946
14041
|
if (failure.search) http.search = failure.search;
|
|
@@ -13953,9 +14048,19 @@
|
|
|
13953
14048
|
};
|
|
13954
14049
|
if (failure.errorName) fail.name = failure.errorName;
|
|
13955
14050
|
if (failure.errorMessage) fail.message = failure.errorMessage;
|
|
14051
|
+
const statusCode = typeof failure.status === "number" && failure.status > 0 ? failure.status : null;
|
|
13956
14052
|
return {
|
|
13957
14053
|
http,
|
|
13958
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),
|
|
13959
14064
|
durationMs: failure.durationMs,
|
|
13960
14065
|
aborted: failure.aborted ?? false,
|
|
13961
14066
|
ok: failure.ok ?? false
|
|
@@ -14001,6 +14106,7 @@
|
|
|
14001
14106
|
disableDefaultIntegrations: options.disableDefaultIntegrations ?? false,
|
|
14002
14107
|
captureFailedRequests: options.captureFailedRequests ?? true,
|
|
14003
14108
|
captureNetworkErrors: options.captureNetworkErrors ?? true,
|
|
14109
|
+
networkErrorOrigins: options.networkErrorOrigins ?? [],
|
|
14004
14110
|
includeNetworkUrlQuery: options.captureRequestQueryParameters ?? options.includeNetworkUrlQuery ?? false,
|
|
14005
14111
|
failedRequestStatusCodes: options.failedRequestStatusCodes ?? [[500, 599]],
|
|
14006
14112
|
failedRequestIgnoreUrls: options.failedRequestIgnoreUrls ?? []
|
|
@@ -14130,6 +14236,8 @@
|
|
|
14130
14236
|
installNetworkHook({
|
|
14131
14237
|
captureFailedRequests: this.options.captureFailedRequests,
|
|
14132
14238
|
captureNetworkErrors: this.options.captureNetworkErrors,
|
|
14239
|
+
networkErrorOrigins: this.options.networkErrorOrigins,
|
|
14240
|
+
pageOrigin: typeof location !== "undefined" ? location.origin : void 0,
|
|
14133
14241
|
includeNetworkUrlQuery: this.options.includeNetworkUrlQuery,
|
|
14134
14242
|
failedRequestStatusCodes: this.options.failedRequestStatusCodes,
|
|
14135
14243
|
failedRequestIgnoreUrls: this.options.failedRequestIgnoreUrls,
|
|
@@ -14223,6 +14331,7 @@
|
|
|
14223
14331
|
}
|
|
14224
14332
|
const correlated = this.consumeCorrelatedNetworkFailure(err);
|
|
14225
14333
|
if (correlated?.promoted) return;
|
|
14334
|
+
if (correlated && correlated.party === "third_party") return;
|
|
14226
14335
|
const mergedContext = correlated ? mergeNetworkFailureContext(context, correlated) : context;
|
|
14227
14336
|
this.capturing = true;
|
|
14228
14337
|
try {
|
|
@@ -14705,6 +14814,13 @@
|
|
|
14705
14814
|
);
|
|
14706
14815
|
}
|
|
14707
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
|
+
}
|
|
14708
14824
|
const now = Date.now();
|
|
14709
14825
|
this.pruneRecentNetworkFailures(now);
|
|
14710
14826
|
for (let i = this.recentNetworkFailures.length - 1; i >= 0; i--) {
|
|
@@ -14715,6 +14831,8 @@
|
|
|
14715
14831
|
existing.errorName = meta.errorName ?? existing.errorName;
|
|
14716
14832
|
existing.aborted = meta.aborted ?? existing.aborted;
|
|
14717
14833
|
existing.failureKind = meta.failureKind ?? existing.failureKind;
|
|
14834
|
+
existing.party = meta.party ?? existing.party;
|
|
14835
|
+
existing.origin = meta.origin ?? existing.origin;
|
|
14718
14836
|
return;
|
|
14719
14837
|
}
|
|
14720
14838
|
}
|
|
@@ -14725,11 +14843,12 @@
|
|
|
14725
14843
|
});
|
|
14726
14844
|
}
|
|
14727
14845
|
/**
|
|
14728
|
-
* Find a recent transport failure for a bare fetch TypeError.
|
|
14846
|
+
* Find a recent transport failure for a bare fetch TypeError / TimeoutError.
|
|
14729
14847
|
* Consumes the entry so a later duplicate path cannot reuse it.
|
|
14730
14848
|
*/
|
|
14731
14849
|
consumeCorrelatedNetworkFailure(error) {
|
|
14732
|
-
if (!
|
|
14850
|
+
if (!isCorrelatableTransportError(error)) return null;
|
|
14851
|
+
const wantKind = isTimeoutError(error) ? "timeout" : "network";
|
|
14733
14852
|
const now = Date.now();
|
|
14734
14853
|
this.pruneRecentNetworkFailures(now);
|
|
14735
14854
|
const takeAt = (index2) => {
|
|
@@ -14738,14 +14857,14 @@
|
|
|
14738
14857
|
};
|
|
14739
14858
|
for (let i = this.recentNetworkFailures.length - 1; i >= 0; i--) {
|
|
14740
14859
|
const failure = this.recentNetworkFailures[i];
|
|
14741
|
-
if (failure.aborted || failure.failureKind !==
|
|
14860
|
+
if (failure.aborted || failure.failureKind !== wantKind) continue;
|
|
14742
14861
|
if (failure.errorMessage && failure.errorMessage === error.message) {
|
|
14743
14862
|
return takeAt(i);
|
|
14744
14863
|
}
|
|
14745
14864
|
}
|
|
14746
14865
|
for (let i = this.recentNetworkFailures.length - 1; i >= 0; i--) {
|
|
14747
14866
|
const failure = this.recentNetworkFailures[i];
|
|
14748
|
-
if (failure.aborted || failure.failureKind !==
|
|
14867
|
+
if (failure.aborted || failure.failureKind !== wantKind) continue;
|
|
14749
14868
|
return takeAt(i);
|
|
14750
14869
|
}
|
|
14751
14870
|
return null;
|