@flareapp/js 2.3.0 → 2.4.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/dist/BrowserFlushScheduler-CR7L8-z6.d.cts +43 -0
- package/dist/BrowserFlushScheduler-CZiDvxtf.d.mts +43 -0
- package/dist/browser.cjs +21 -0
- package/dist/browser.d.cts +9 -0
- package/dist/browser.d.mts +9 -0
- package/dist/browser.mjs +16 -0
- package/dist/catchWindowErrors-CTX8goVc.cjs +180 -0
- package/dist/catchWindowErrors-DKjw0DIA.mjs +151 -0
- package/dist/index.cjs +5 -160
- package/dist/index.d.cts +2 -4
- package/dist/index.d.mts +2 -4
- package/dist/index.mjs +3 -158
- package/package.json +13 -3
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import { ContextCollector, FileReader, FlushFn, FlushScheduler } from "@flareapp/core";
|
|
2
|
+
|
|
3
|
+
//#region src/browser/catchWindowErrors.d.ts
|
|
4
|
+
declare function catchWindowErrors(): void;
|
|
5
|
+
//#endregion
|
|
6
|
+
//#region src/browser/context/collectBrowser.d.ts
|
|
7
|
+
declare const collectBrowser: ContextCollector;
|
|
8
|
+
//#endregion
|
|
9
|
+
//#region src/browser/FetchFileReader.d.ts
|
|
10
|
+
/**
|
|
11
|
+
* Browser `FileReader` implementation that fetches source files over HTTP(S).
|
|
12
|
+
*
|
|
13
|
+
* Wired into `@flareapp/js`'s singleton so the stack-trace builder can pull
|
|
14
|
+
* the original source for each frame and render a code snippet around the
|
|
15
|
+
* offending line. The source URL comes from the frame (usually the URL of
|
|
16
|
+
* the JS bundle that produced the error, post-sourcemap resolution).
|
|
17
|
+
*
|
|
18
|
+
* Three safety gates:
|
|
19
|
+
*
|
|
20
|
+
* 1. **Scheme allowlist.** Only `http:` and `https:` URLs are fetched. Other
|
|
21
|
+
* schemes (`chrome-extension://`, `file://`, `blob:`, `data:`) return
|
|
22
|
+
* `null` immediately. This avoids surprise privilege boundaries (e.g.,
|
|
23
|
+
* pages should not read extension-internal files) and dodges CORS/CSP
|
|
24
|
+
* walls that would error noisily.
|
|
25
|
+
* 2. **Status check.** Only `200 OK` responses are used. 3xx redirects are
|
|
26
|
+
* handled transparently by `fetch`; 4xx/5xx fall back to `null` so the
|
|
27
|
+
* snippet is simply omitted from the report.
|
|
28
|
+
* 3. **Catch-all.** Network failures, CORS errors, and aborted requests
|
|
29
|
+
* return `null`. We never let a source-fetch failure leak as an error
|
|
30
|
+
* that the consumer page would see.
|
|
31
|
+
*
|
|
32
|
+
* The `read()` contract returns `null` on any failure path, never throws.
|
|
33
|
+
*/
|
|
34
|
+
declare class FetchFileReader implements FileReader {
|
|
35
|
+
read(url: string): Promise<string | null>;
|
|
36
|
+
}
|
|
37
|
+
//#endregion
|
|
38
|
+
//#region src/browser/BrowserFlushScheduler.d.ts
|
|
39
|
+
declare class BrowserFlushScheduler implements FlushScheduler {
|
|
40
|
+
register(flush: FlushFn): void;
|
|
41
|
+
}
|
|
42
|
+
//#endregion
|
|
43
|
+
export { catchWindowErrors as i, FetchFileReader as n, collectBrowser as r, BrowserFlushScheduler as t };
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import { ContextCollector, FileReader, FlushFn, FlushScheduler } from "@flareapp/core";
|
|
2
|
+
|
|
3
|
+
//#region src/browser/catchWindowErrors.d.ts
|
|
4
|
+
declare function catchWindowErrors(): void;
|
|
5
|
+
//#endregion
|
|
6
|
+
//#region src/browser/context/collectBrowser.d.ts
|
|
7
|
+
declare const collectBrowser: ContextCollector;
|
|
8
|
+
//#endregion
|
|
9
|
+
//#region src/browser/FetchFileReader.d.ts
|
|
10
|
+
/**
|
|
11
|
+
* Browser `FileReader` implementation that fetches source files over HTTP(S).
|
|
12
|
+
*
|
|
13
|
+
* Wired into `@flareapp/js`'s singleton so the stack-trace builder can pull
|
|
14
|
+
* the original source for each frame and render a code snippet around the
|
|
15
|
+
* offending line. The source URL comes from the frame (usually the URL of
|
|
16
|
+
* the JS bundle that produced the error, post-sourcemap resolution).
|
|
17
|
+
*
|
|
18
|
+
* Three safety gates:
|
|
19
|
+
*
|
|
20
|
+
* 1. **Scheme allowlist.** Only `http:` and `https:` URLs are fetched. Other
|
|
21
|
+
* schemes (`chrome-extension://`, `file://`, `blob:`, `data:`) return
|
|
22
|
+
* `null` immediately. This avoids surprise privilege boundaries (e.g.,
|
|
23
|
+
* pages should not read extension-internal files) and dodges CORS/CSP
|
|
24
|
+
* walls that would error noisily.
|
|
25
|
+
* 2. **Status check.** Only `200 OK` responses are used. 3xx redirects are
|
|
26
|
+
* handled transparently by `fetch`; 4xx/5xx fall back to `null` so the
|
|
27
|
+
* snippet is simply omitted from the report.
|
|
28
|
+
* 3. **Catch-all.** Network failures, CORS errors, and aborted requests
|
|
29
|
+
* return `null`. We never let a source-fetch failure leak as an error
|
|
30
|
+
* that the consumer page would see.
|
|
31
|
+
*
|
|
32
|
+
* The `read()` contract returns `null` on any failure path, never throws.
|
|
33
|
+
*/
|
|
34
|
+
declare class FetchFileReader implements FileReader {
|
|
35
|
+
read(url: string): Promise<string | null>;
|
|
36
|
+
}
|
|
37
|
+
//#endregion
|
|
38
|
+
//#region src/browser/BrowserFlushScheduler.d.ts
|
|
39
|
+
declare class BrowserFlushScheduler implements FlushScheduler {
|
|
40
|
+
register(flush: FlushFn): void;
|
|
41
|
+
}
|
|
42
|
+
//#endregion
|
|
43
|
+
export { catchWindowErrors as i, FetchFileReader as n, collectBrowser as r, BrowserFlushScheduler as t };
|
package/dist/browser.cjs
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
|
|
2
|
+
const require_catchWindowErrors = require('./catchWindowErrors-CTX8goVc.cjs');
|
|
3
|
+
let _flareapp_core = require("@flareapp/core");
|
|
4
|
+
|
|
5
|
+
//#region src/browser.ts
|
|
6
|
+
var Flare = class extends _flareapp_core.Flare {
|
|
7
|
+
constructor(api = new _flareapp_core.Api(), contextCollector = require_catchWindowErrors.collectBrowser, fileReader = new require_catchWindowErrors.FetchFileReader(), scopeProvider = new _flareapp_core.GlobalScopeProvider()) {
|
|
8
|
+
super(api, contextCollector, fileReader, scopeProvider, new require_catchWindowErrors.BrowserFlushScheduler());
|
|
9
|
+
this.setSdkInfo({
|
|
10
|
+
name: "@flareapp/js",
|
|
11
|
+
version: require_catchWindowErrors.CLIENT_VERSION
|
|
12
|
+
});
|
|
13
|
+
}
|
|
14
|
+
};
|
|
15
|
+
|
|
16
|
+
//#endregion
|
|
17
|
+
exports.BrowserFlushScheduler = require_catchWindowErrors.BrowserFlushScheduler;
|
|
18
|
+
exports.FetchFileReader = require_catchWindowErrors.FetchFileReader;
|
|
19
|
+
exports.Flare = Flare;
|
|
20
|
+
exports.catchWindowErrors = require_catchWindowErrors.catchWindowErrors;
|
|
21
|
+
exports.collectBrowser = require_catchWindowErrors.collectBrowser;
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { i as catchWindowErrors, n as FetchFileReader, r as collectBrowser, t as BrowserFlushScheduler } from "./BrowserFlushScheduler-CR7L8-z6.cjs";
|
|
2
|
+
import { Api, ContextCollector, FileReader, Flare as Flare$1, ScopeProvider } from "@flareapp/core";
|
|
3
|
+
|
|
4
|
+
//#region src/browser.d.ts
|
|
5
|
+
declare class Flare extends Flare$1 {
|
|
6
|
+
constructor(api?: Api, contextCollector?: ContextCollector, fileReader?: FileReader, scopeProvider?: ScopeProvider);
|
|
7
|
+
}
|
|
8
|
+
//#endregion
|
|
9
|
+
export { BrowserFlushScheduler, FetchFileReader, Flare, catchWindowErrors, collectBrowser };
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { i as catchWindowErrors, n as FetchFileReader, r as collectBrowser, t as BrowserFlushScheduler } from "./BrowserFlushScheduler-CZiDvxtf.mjs";
|
|
2
|
+
import { Api, ContextCollector, FileReader, Flare as Flare$1, ScopeProvider } from "@flareapp/core";
|
|
3
|
+
|
|
4
|
+
//#region src/browser.d.ts
|
|
5
|
+
declare class Flare extends Flare$1 {
|
|
6
|
+
constructor(api?: Api, contextCollector?: ContextCollector, fileReader?: FileReader, scopeProvider?: ScopeProvider);
|
|
7
|
+
}
|
|
8
|
+
//#endregion
|
|
9
|
+
export { BrowserFlushScheduler, FetchFileReader, Flare, catchWindowErrors, collectBrowser };
|
package/dist/browser.mjs
ADDED
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { a as BrowserFlushScheduler, i as collectBrowser, n as CLIENT_VERSION, r as FetchFileReader, t as catchWindowErrors } from "./catchWindowErrors-DKjw0DIA.mjs";
|
|
2
|
+
import { Api, Flare as Flare$1, GlobalScopeProvider } from "@flareapp/core";
|
|
3
|
+
|
|
4
|
+
//#region src/browser.ts
|
|
5
|
+
var Flare = class extends Flare$1 {
|
|
6
|
+
constructor(api = new Api(), contextCollector = collectBrowser, fileReader = new FetchFileReader(), scopeProvider = new GlobalScopeProvider()) {
|
|
7
|
+
super(api, contextCollector, fileReader, scopeProvider, new BrowserFlushScheduler());
|
|
8
|
+
this.setSdkInfo({
|
|
9
|
+
name: "@flareapp/js",
|
|
10
|
+
version: CLIENT_VERSION
|
|
11
|
+
});
|
|
12
|
+
}
|
|
13
|
+
};
|
|
14
|
+
|
|
15
|
+
//#endregion
|
|
16
|
+
export { BrowserFlushScheduler, FetchFileReader, Flare, catchWindowErrors, collectBrowser };
|
|
@@ -0,0 +1,180 @@
|
|
|
1
|
+
let _flareapp_core = require("@flareapp/core");
|
|
2
|
+
|
|
3
|
+
//#region src/browser/BrowserFlushScheduler.ts
|
|
4
|
+
var BrowserFlushScheduler = class {
|
|
5
|
+
register(flush) {
|
|
6
|
+
if (typeof document === "undefined" || !document) return;
|
|
7
|
+
document.addEventListener("visibilitychange", () => {
|
|
8
|
+
if (document.visibilityState === "hidden") flush({ keepalive: true });
|
|
9
|
+
});
|
|
10
|
+
}
|
|
11
|
+
};
|
|
12
|
+
|
|
13
|
+
//#endregion
|
|
14
|
+
//#region src/browser/context/cookie.ts
|
|
15
|
+
function cookie() {
|
|
16
|
+
if (!window.document.cookie) return {};
|
|
17
|
+
const cookies = {};
|
|
18
|
+
window.document.cookie.split("; ").forEach((rawCookie) => {
|
|
19
|
+
const idx = rawCookie.indexOf("=");
|
|
20
|
+
if (idx === -1) {
|
|
21
|
+
cookies[rawCookie] = "";
|
|
22
|
+
return;
|
|
23
|
+
}
|
|
24
|
+
const name = rawCookie.slice(0, idx);
|
|
25
|
+
cookies[name] = rawCookie.slice(idx + 1);
|
|
26
|
+
});
|
|
27
|
+
return { "http.request.cookies": cookies };
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
//#endregion
|
|
31
|
+
//#region src/browser/context/request.ts
|
|
32
|
+
function request(urlDenylist) {
|
|
33
|
+
return {
|
|
34
|
+
"url.full": (0, _flareapp_core.redactUrlQuery)(window.location.href, urlDenylist),
|
|
35
|
+
"user_agent.original": window.navigator.userAgent,
|
|
36
|
+
"http.request.referrer": (0, _flareapp_core.redactUrlQuery)(window.document.referrer, urlDenylist),
|
|
37
|
+
"document.ready_state": window.document.readyState
|
|
38
|
+
};
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
//#endregion
|
|
42
|
+
//#region src/browser/context/requestData.ts
|
|
43
|
+
function requestData(urlDenylist) {
|
|
44
|
+
if (!window.location.search) return {};
|
|
45
|
+
return { "url.query": (0, _flareapp_core.redactUrlQuery)(window.location.search, urlDenylist).replace(/^\?/, "") };
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
//#endregion
|
|
49
|
+
//#region src/browser/context/collectBrowser.ts
|
|
50
|
+
const collectBrowser = (config) => {
|
|
51
|
+
if (typeof window === "undefined") return { "flare.entry_point.type": "server" };
|
|
52
|
+
const attrs = { "flare.entry_point.type": "web" };
|
|
53
|
+
if (window?.location?.href) {
|
|
54
|
+
attrs["flare.entry_point.value"] = (0, _flareapp_core.redactUrlQuery)(window.location.href, config.urlDenylist);
|
|
55
|
+
if (window.location.pathname) {
|
|
56
|
+
attrs["flare.entry_point.handler.identifier"] = window.location.pathname;
|
|
57
|
+
attrs["flare.entry_point.handler.type"] = "browser";
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
if (window?.location?.hostname) attrs["host.name"] = window.location.hostname;
|
|
61
|
+
Object.assign(attrs, request(config.urlDenylist));
|
|
62
|
+
Object.assign(attrs, requestData(config.urlDenylist));
|
|
63
|
+
Object.assign(attrs, cookie());
|
|
64
|
+
return attrs;
|
|
65
|
+
};
|
|
66
|
+
|
|
67
|
+
//#endregion
|
|
68
|
+
//#region src/browser/FetchFileReader.ts
|
|
69
|
+
/**
|
|
70
|
+
* Browser `FileReader` implementation that fetches source files over HTTP(S).
|
|
71
|
+
*
|
|
72
|
+
* Wired into `@flareapp/js`'s singleton so the stack-trace builder can pull
|
|
73
|
+
* the original source for each frame and render a code snippet around the
|
|
74
|
+
* offending line. The source URL comes from the frame (usually the URL of
|
|
75
|
+
* the JS bundle that produced the error, post-sourcemap resolution).
|
|
76
|
+
*
|
|
77
|
+
* Three safety gates:
|
|
78
|
+
*
|
|
79
|
+
* 1. **Scheme allowlist.** Only `http:` and `https:` URLs are fetched. Other
|
|
80
|
+
* schemes (`chrome-extension://`, `file://`, `blob:`, `data:`) return
|
|
81
|
+
* `null` immediately. This avoids surprise privilege boundaries (e.g.,
|
|
82
|
+
* pages should not read extension-internal files) and dodges CORS/CSP
|
|
83
|
+
* walls that would error noisily.
|
|
84
|
+
* 2. **Status check.** Only `200 OK` responses are used. 3xx redirects are
|
|
85
|
+
* handled transparently by `fetch`; 4xx/5xx fall back to `null` so the
|
|
86
|
+
* snippet is simply omitted from the report.
|
|
87
|
+
* 3. **Catch-all.** Network failures, CORS errors, and aborted requests
|
|
88
|
+
* return `null`. We never let a source-fetch failure leak as an error
|
|
89
|
+
* that the consumer page would see.
|
|
90
|
+
*
|
|
91
|
+
* The `read()` contract returns `null` on any failure path, never throws.
|
|
92
|
+
*/
|
|
93
|
+
var FetchFileReader = class {
|
|
94
|
+
read(url) {
|
|
95
|
+
if (!/^https?:\/\//i.test(url)) return Promise.resolve(null);
|
|
96
|
+
return fetch(url).then((response) => {
|
|
97
|
+
if (response.status !== 200) return null;
|
|
98
|
+
return response.text();
|
|
99
|
+
}).catch(() => null);
|
|
100
|
+
}
|
|
101
|
+
};
|
|
102
|
+
|
|
103
|
+
//#endregion
|
|
104
|
+
//#region src/env/index.ts
|
|
105
|
+
const CLIENT_VERSION = typeof process !== "undefined" && true ? "2.4.0" : "?";
|
|
106
|
+
|
|
107
|
+
//#endregion
|
|
108
|
+
//#region src/browser/catchWindowErrors.ts
|
|
109
|
+
function catchWindowErrors() {
|
|
110
|
+
if (typeof window === "undefined") return;
|
|
111
|
+
window.addEventListener("error", (event) => {
|
|
112
|
+
const flare = window.flare;
|
|
113
|
+
if (!flare) return;
|
|
114
|
+
if (event.error instanceof Error) flare.reportSilently(event.error);
|
|
115
|
+
});
|
|
116
|
+
window.addEventListener("unhandledrejection", (event) => {
|
|
117
|
+
const flare = window.flare;
|
|
118
|
+
if (!flare) return;
|
|
119
|
+
const reason = event.reason;
|
|
120
|
+
if (reason instanceof Error) {
|
|
121
|
+
flare.reportSilently(reason);
|
|
122
|
+
return;
|
|
123
|
+
}
|
|
124
|
+
if (hasStack(reason)) {
|
|
125
|
+
const error = new Error(describeRejectionReason(reason));
|
|
126
|
+
error.stack = reason.stack;
|
|
127
|
+
flare.reportSilently(error);
|
|
128
|
+
return;
|
|
129
|
+
}
|
|
130
|
+
Promise.resolve(flare.reportUnhandledRejection(describeRejectionReason(reason))).catch(() => {});
|
|
131
|
+
});
|
|
132
|
+
}
|
|
133
|
+
function describeRejectionReason(reason) {
|
|
134
|
+
if (typeof reason === "string") return reason;
|
|
135
|
+
if (reason && typeof reason === "object") {
|
|
136
|
+
const message = reason.message;
|
|
137
|
+
if (typeof message === "string") return message;
|
|
138
|
+
try {
|
|
139
|
+
return JSON.stringify(reason);
|
|
140
|
+
} catch {
|
|
141
|
+
return "Unhandled promise rejection (non-serializable reason)";
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
return String(reason);
|
|
145
|
+
}
|
|
146
|
+
function hasStack(value) {
|
|
147
|
+
return typeof value === "object" && value !== null && "stack" in value && typeof value.stack === "string";
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
//#endregion
|
|
151
|
+
Object.defineProperty(exports, 'BrowserFlushScheduler', {
|
|
152
|
+
enumerable: true,
|
|
153
|
+
get: function () {
|
|
154
|
+
return BrowserFlushScheduler;
|
|
155
|
+
}
|
|
156
|
+
});
|
|
157
|
+
Object.defineProperty(exports, 'CLIENT_VERSION', {
|
|
158
|
+
enumerable: true,
|
|
159
|
+
get: function () {
|
|
160
|
+
return CLIENT_VERSION;
|
|
161
|
+
}
|
|
162
|
+
});
|
|
163
|
+
Object.defineProperty(exports, 'FetchFileReader', {
|
|
164
|
+
enumerable: true,
|
|
165
|
+
get: function () {
|
|
166
|
+
return FetchFileReader;
|
|
167
|
+
}
|
|
168
|
+
});
|
|
169
|
+
Object.defineProperty(exports, 'catchWindowErrors', {
|
|
170
|
+
enumerable: true,
|
|
171
|
+
get: function () {
|
|
172
|
+
return catchWindowErrors;
|
|
173
|
+
}
|
|
174
|
+
});
|
|
175
|
+
Object.defineProperty(exports, 'collectBrowser', {
|
|
176
|
+
enumerable: true,
|
|
177
|
+
get: function () {
|
|
178
|
+
return collectBrowser;
|
|
179
|
+
}
|
|
180
|
+
});
|
|
@@ -0,0 +1,151 @@
|
|
|
1
|
+
import { redactUrlQuery } from "@flareapp/core";
|
|
2
|
+
|
|
3
|
+
//#region src/browser/BrowserFlushScheduler.ts
|
|
4
|
+
var BrowserFlushScheduler = class {
|
|
5
|
+
register(flush) {
|
|
6
|
+
if (typeof document === "undefined" || !document) return;
|
|
7
|
+
document.addEventListener("visibilitychange", () => {
|
|
8
|
+
if (document.visibilityState === "hidden") flush({ keepalive: true });
|
|
9
|
+
});
|
|
10
|
+
}
|
|
11
|
+
};
|
|
12
|
+
|
|
13
|
+
//#endregion
|
|
14
|
+
//#region src/browser/context/cookie.ts
|
|
15
|
+
function cookie() {
|
|
16
|
+
if (!window.document.cookie) return {};
|
|
17
|
+
const cookies = {};
|
|
18
|
+
window.document.cookie.split("; ").forEach((rawCookie) => {
|
|
19
|
+
const idx = rawCookie.indexOf("=");
|
|
20
|
+
if (idx === -1) {
|
|
21
|
+
cookies[rawCookie] = "";
|
|
22
|
+
return;
|
|
23
|
+
}
|
|
24
|
+
const name = rawCookie.slice(0, idx);
|
|
25
|
+
cookies[name] = rawCookie.slice(idx + 1);
|
|
26
|
+
});
|
|
27
|
+
return { "http.request.cookies": cookies };
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
//#endregion
|
|
31
|
+
//#region src/browser/context/request.ts
|
|
32
|
+
function request(urlDenylist) {
|
|
33
|
+
return {
|
|
34
|
+
"url.full": redactUrlQuery(window.location.href, urlDenylist),
|
|
35
|
+
"user_agent.original": window.navigator.userAgent,
|
|
36
|
+
"http.request.referrer": redactUrlQuery(window.document.referrer, urlDenylist),
|
|
37
|
+
"document.ready_state": window.document.readyState
|
|
38
|
+
};
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
//#endregion
|
|
42
|
+
//#region src/browser/context/requestData.ts
|
|
43
|
+
function requestData(urlDenylist) {
|
|
44
|
+
if (!window.location.search) return {};
|
|
45
|
+
return { "url.query": redactUrlQuery(window.location.search, urlDenylist).replace(/^\?/, "") };
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
//#endregion
|
|
49
|
+
//#region src/browser/context/collectBrowser.ts
|
|
50
|
+
const collectBrowser = (config) => {
|
|
51
|
+
if (typeof window === "undefined") return { "flare.entry_point.type": "server" };
|
|
52
|
+
const attrs = { "flare.entry_point.type": "web" };
|
|
53
|
+
if (window?.location?.href) {
|
|
54
|
+
attrs["flare.entry_point.value"] = redactUrlQuery(window.location.href, config.urlDenylist);
|
|
55
|
+
if (window.location.pathname) {
|
|
56
|
+
attrs["flare.entry_point.handler.identifier"] = window.location.pathname;
|
|
57
|
+
attrs["flare.entry_point.handler.type"] = "browser";
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
if (window?.location?.hostname) attrs["host.name"] = window.location.hostname;
|
|
61
|
+
Object.assign(attrs, request(config.urlDenylist));
|
|
62
|
+
Object.assign(attrs, requestData(config.urlDenylist));
|
|
63
|
+
Object.assign(attrs, cookie());
|
|
64
|
+
return attrs;
|
|
65
|
+
};
|
|
66
|
+
|
|
67
|
+
//#endregion
|
|
68
|
+
//#region src/browser/FetchFileReader.ts
|
|
69
|
+
/**
|
|
70
|
+
* Browser `FileReader` implementation that fetches source files over HTTP(S).
|
|
71
|
+
*
|
|
72
|
+
* Wired into `@flareapp/js`'s singleton so the stack-trace builder can pull
|
|
73
|
+
* the original source for each frame and render a code snippet around the
|
|
74
|
+
* offending line. The source URL comes from the frame (usually the URL of
|
|
75
|
+
* the JS bundle that produced the error, post-sourcemap resolution).
|
|
76
|
+
*
|
|
77
|
+
* Three safety gates:
|
|
78
|
+
*
|
|
79
|
+
* 1. **Scheme allowlist.** Only `http:` and `https:` URLs are fetched. Other
|
|
80
|
+
* schemes (`chrome-extension://`, `file://`, `blob:`, `data:`) return
|
|
81
|
+
* `null` immediately. This avoids surprise privilege boundaries (e.g.,
|
|
82
|
+
* pages should not read extension-internal files) and dodges CORS/CSP
|
|
83
|
+
* walls that would error noisily.
|
|
84
|
+
* 2. **Status check.** Only `200 OK` responses are used. 3xx redirects are
|
|
85
|
+
* handled transparently by `fetch`; 4xx/5xx fall back to `null` so the
|
|
86
|
+
* snippet is simply omitted from the report.
|
|
87
|
+
* 3. **Catch-all.** Network failures, CORS errors, and aborted requests
|
|
88
|
+
* return `null`. We never let a source-fetch failure leak as an error
|
|
89
|
+
* that the consumer page would see.
|
|
90
|
+
*
|
|
91
|
+
* The `read()` contract returns `null` on any failure path, never throws.
|
|
92
|
+
*/
|
|
93
|
+
var FetchFileReader = class {
|
|
94
|
+
read(url) {
|
|
95
|
+
if (!/^https?:\/\//i.test(url)) return Promise.resolve(null);
|
|
96
|
+
return fetch(url).then((response) => {
|
|
97
|
+
if (response.status !== 200) return null;
|
|
98
|
+
return response.text();
|
|
99
|
+
}).catch(() => null);
|
|
100
|
+
}
|
|
101
|
+
};
|
|
102
|
+
|
|
103
|
+
//#endregion
|
|
104
|
+
//#region src/env/index.ts
|
|
105
|
+
const CLIENT_VERSION = typeof process !== "undefined" && true ? "2.4.0" : "?";
|
|
106
|
+
|
|
107
|
+
//#endregion
|
|
108
|
+
//#region src/browser/catchWindowErrors.ts
|
|
109
|
+
function catchWindowErrors() {
|
|
110
|
+
if (typeof window === "undefined") return;
|
|
111
|
+
window.addEventListener("error", (event) => {
|
|
112
|
+
const flare = window.flare;
|
|
113
|
+
if (!flare) return;
|
|
114
|
+
if (event.error instanceof Error) flare.reportSilently(event.error);
|
|
115
|
+
});
|
|
116
|
+
window.addEventListener("unhandledrejection", (event) => {
|
|
117
|
+
const flare = window.flare;
|
|
118
|
+
if (!flare) return;
|
|
119
|
+
const reason = event.reason;
|
|
120
|
+
if (reason instanceof Error) {
|
|
121
|
+
flare.reportSilently(reason);
|
|
122
|
+
return;
|
|
123
|
+
}
|
|
124
|
+
if (hasStack(reason)) {
|
|
125
|
+
const error = new Error(describeRejectionReason(reason));
|
|
126
|
+
error.stack = reason.stack;
|
|
127
|
+
flare.reportSilently(error);
|
|
128
|
+
return;
|
|
129
|
+
}
|
|
130
|
+
Promise.resolve(flare.reportUnhandledRejection(describeRejectionReason(reason))).catch(() => {});
|
|
131
|
+
});
|
|
132
|
+
}
|
|
133
|
+
function describeRejectionReason(reason) {
|
|
134
|
+
if (typeof reason === "string") return reason;
|
|
135
|
+
if (reason && typeof reason === "object") {
|
|
136
|
+
const message = reason.message;
|
|
137
|
+
if (typeof message === "string") return message;
|
|
138
|
+
try {
|
|
139
|
+
return JSON.stringify(reason);
|
|
140
|
+
} catch {
|
|
141
|
+
return "Unhandled promise rejection (non-serializable reason)";
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
return String(reason);
|
|
145
|
+
}
|
|
146
|
+
function hasStack(value) {
|
|
147
|
+
return typeof value === "object" && value !== null && "stack" in value && typeof value.stack === "string";
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
//#endregion
|
|
151
|
+
export { BrowserFlushScheduler as a, collectBrowser as i, CLIENT_VERSION as n, FetchFileReader as r, catchWindowErrors as t };
|
package/dist/index.cjs
CHANGED
|
@@ -1,168 +1,13 @@
|
|
|
1
1
|
Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
|
|
2
|
+
const require_catchWindowErrors = require('./catchWindowErrors-CTX8goVc.cjs');
|
|
3
|
+
const require_browser = require('./browser.cjs');
|
|
2
4
|
let _flareapp_core = require("@flareapp/core");
|
|
3
5
|
|
|
4
|
-
//#region src/browser/catchWindowErrors.ts
|
|
5
|
-
function catchWindowErrors() {
|
|
6
|
-
if (typeof window === "undefined") return;
|
|
7
|
-
window.addEventListener("error", (event) => {
|
|
8
|
-
const flare = window.flare;
|
|
9
|
-
if (!flare) return;
|
|
10
|
-
if (event.error instanceof Error) flare.reportSilently(event.error);
|
|
11
|
-
});
|
|
12
|
-
window.addEventListener("unhandledrejection", (event) => {
|
|
13
|
-
const flare = window.flare;
|
|
14
|
-
if (!flare) return;
|
|
15
|
-
const reason = event.reason;
|
|
16
|
-
if (reason instanceof Error) {
|
|
17
|
-
flare.reportSilently(reason);
|
|
18
|
-
return;
|
|
19
|
-
}
|
|
20
|
-
if (hasStack(reason)) {
|
|
21
|
-
const error = new Error(describeRejectionReason(reason));
|
|
22
|
-
error.stack = reason.stack;
|
|
23
|
-
flare.reportSilently(error);
|
|
24
|
-
return;
|
|
25
|
-
}
|
|
26
|
-
Promise.resolve(flare.reportUnhandledRejection(describeRejectionReason(reason))).catch(() => {});
|
|
27
|
-
});
|
|
28
|
-
}
|
|
29
|
-
function describeRejectionReason(reason) {
|
|
30
|
-
if (typeof reason === "string") return reason;
|
|
31
|
-
if (reason && typeof reason === "object") {
|
|
32
|
-
const message = reason.message;
|
|
33
|
-
if (typeof message === "string") return message;
|
|
34
|
-
try {
|
|
35
|
-
return JSON.stringify(reason);
|
|
36
|
-
} catch {
|
|
37
|
-
return "Unhandled promise rejection (non-serializable reason)";
|
|
38
|
-
}
|
|
39
|
-
}
|
|
40
|
-
return String(reason);
|
|
41
|
-
}
|
|
42
|
-
function hasStack(value) {
|
|
43
|
-
return typeof value === "object" && value !== null && "stack" in value && typeof value.stack === "string";
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
//#endregion
|
|
47
|
-
//#region src/browser/BrowserFlushScheduler.ts
|
|
48
|
-
var BrowserFlushScheduler = class {
|
|
49
|
-
register(flush) {
|
|
50
|
-
if (typeof document === "undefined" || !document) return;
|
|
51
|
-
document.addEventListener("visibilitychange", () => {
|
|
52
|
-
if (document.visibilityState === "hidden") flush({ keepalive: true });
|
|
53
|
-
});
|
|
54
|
-
}
|
|
55
|
-
};
|
|
56
|
-
|
|
57
|
-
//#endregion
|
|
58
|
-
//#region src/browser/context/cookie.ts
|
|
59
|
-
function cookie() {
|
|
60
|
-
if (!window.document.cookie) return {};
|
|
61
|
-
const cookies = {};
|
|
62
|
-
window.document.cookie.split("; ").forEach((rawCookie) => {
|
|
63
|
-
const idx = rawCookie.indexOf("=");
|
|
64
|
-
if (idx === -1) {
|
|
65
|
-
cookies[rawCookie] = "";
|
|
66
|
-
return;
|
|
67
|
-
}
|
|
68
|
-
const name = rawCookie.slice(0, idx);
|
|
69
|
-
cookies[name] = rawCookie.slice(idx + 1);
|
|
70
|
-
});
|
|
71
|
-
return { "http.request.cookies": cookies };
|
|
72
|
-
}
|
|
73
|
-
|
|
74
|
-
//#endregion
|
|
75
|
-
//#region src/browser/context/request.ts
|
|
76
|
-
function request(urlDenylist) {
|
|
77
|
-
return {
|
|
78
|
-
"url.full": (0, _flareapp_core.redactUrlQuery)(window.location.href, urlDenylist),
|
|
79
|
-
"user_agent.original": window.navigator.userAgent,
|
|
80
|
-
"http.request.referrer": (0, _flareapp_core.redactUrlQuery)(window.document.referrer, urlDenylist),
|
|
81
|
-
"document.ready_state": window.document.readyState
|
|
82
|
-
};
|
|
83
|
-
}
|
|
84
|
-
|
|
85
|
-
//#endregion
|
|
86
|
-
//#region src/browser/context/requestData.ts
|
|
87
|
-
function requestData(urlDenylist) {
|
|
88
|
-
if (!window.location.search) return {};
|
|
89
|
-
return { "url.query": (0, _flareapp_core.redactUrlQuery)(window.location.search, urlDenylist).replace(/^\?/, "") };
|
|
90
|
-
}
|
|
91
|
-
|
|
92
|
-
//#endregion
|
|
93
|
-
//#region src/browser/context/collectBrowser.ts
|
|
94
|
-
const collectBrowser = (config) => {
|
|
95
|
-
if (typeof window === "undefined") return { "flare.entry_point.type": "server" };
|
|
96
|
-
const attrs = { "flare.entry_point.type": "web" };
|
|
97
|
-
if (window?.location?.href) {
|
|
98
|
-
attrs["flare.entry_point.value"] = (0, _flareapp_core.redactUrlQuery)(window.location.href, config.urlDenylist);
|
|
99
|
-
if (window.location.pathname) {
|
|
100
|
-
attrs["flare.entry_point.handler.identifier"] = window.location.pathname;
|
|
101
|
-
attrs["flare.entry_point.handler.type"] = "browser";
|
|
102
|
-
}
|
|
103
|
-
}
|
|
104
|
-
if (window?.location?.hostname) attrs["host.name"] = window.location.hostname;
|
|
105
|
-
Object.assign(attrs, request(config.urlDenylist));
|
|
106
|
-
Object.assign(attrs, requestData(config.urlDenylist));
|
|
107
|
-
Object.assign(attrs, cookie());
|
|
108
|
-
return attrs;
|
|
109
|
-
};
|
|
110
|
-
|
|
111
|
-
//#endregion
|
|
112
|
-
//#region src/browser/FetchFileReader.ts
|
|
113
|
-
/**
|
|
114
|
-
* Browser `FileReader` implementation that fetches source files over HTTP(S).
|
|
115
|
-
*
|
|
116
|
-
* Wired into `@flareapp/js`'s singleton so the stack-trace builder can pull
|
|
117
|
-
* the original source for each frame and render a code snippet around the
|
|
118
|
-
* offending line. The source URL comes from the frame (usually the URL of
|
|
119
|
-
* the JS bundle that produced the error, post-sourcemap resolution).
|
|
120
|
-
*
|
|
121
|
-
* Three safety gates:
|
|
122
|
-
*
|
|
123
|
-
* 1. **Scheme allowlist.** Only `http:` and `https:` URLs are fetched. Other
|
|
124
|
-
* schemes (`chrome-extension://`, `file://`, `blob:`, `data:`) return
|
|
125
|
-
* `null` immediately. This avoids surprise privilege boundaries (e.g.,
|
|
126
|
-
* pages should not read extension-internal files) and dodges CORS/CSP
|
|
127
|
-
* walls that would error noisily.
|
|
128
|
-
* 2. **Status check.** Only `200 OK` responses are used. 3xx redirects are
|
|
129
|
-
* handled transparently by `fetch`; 4xx/5xx fall back to `null` so the
|
|
130
|
-
* snippet is simply omitted from the report.
|
|
131
|
-
* 3. **Catch-all.** Network failures, CORS errors, and aborted requests
|
|
132
|
-
* return `null`. We never let a source-fetch failure leak as an error
|
|
133
|
-
* that the consumer page would see.
|
|
134
|
-
*
|
|
135
|
-
* The `read()` contract returns `null` on any failure path, never throws.
|
|
136
|
-
*/
|
|
137
|
-
var FetchFileReader = class {
|
|
138
|
-
read(url) {
|
|
139
|
-
if (!/^https?:\/\//i.test(url)) return Promise.resolve(null);
|
|
140
|
-
return fetch(url).then((response) => {
|
|
141
|
-
if (response.status !== 200) return null;
|
|
142
|
-
return response.text();
|
|
143
|
-
}).catch(() => null);
|
|
144
|
-
}
|
|
145
|
-
};
|
|
146
|
-
|
|
147
|
-
//#endregion
|
|
148
|
-
//#region src/env/index.ts
|
|
149
|
-
const CLIENT_VERSION = typeof process !== "undefined" && true ? "2.3.0" : "?";
|
|
150
|
-
|
|
151
|
-
//#endregion
|
|
152
6
|
//#region src/index.ts
|
|
153
|
-
|
|
154
|
-
constructor(api = new _flareapp_core.Api(), contextCollector = collectBrowser, fileReader = new FetchFileReader(), scopeProvider = new _flareapp_core.GlobalScopeProvider()) {
|
|
155
|
-
super(api, contextCollector, fileReader, scopeProvider, new BrowserFlushScheduler());
|
|
156
|
-
this.setSdkInfo({
|
|
157
|
-
name: "@flareapp/js",
|
|
158
|
-
version: CLIENT_VERSION
|
|
159
|
-
});
|
|
160
|
-
}
|
|
161
|
-
};
|
|
162
|
-
const flare = new Flare();
|
|
7
|
+
const flare = new require_browser.Flare();
|
|
163
8
|
if (typeof window !== "undefined" && window) {
|
|
164
9
|
window.flare = flare;
|
|
165
|
-
catchWindowErrors();
|
|
10
|
+
require_catchWindowErrors.catchWindowErrors();
|
|
166
11
|
}
|
|
167
12
|
|
|
168
13
|
//#endregion
|
|
@@ -172,7 +17,7 @@ Object.defineProperty(exports, 'DEFAULT_URL_DENYLIST', {
|
|
|
172
17
|
return _flareapp_core.DEFAULT_URL_DENYLIST;
|
|
173
18
|
}
|
|
174
19
|
});
|
|
175
|
-
exports.Flare = Flare;
|
|
20
|
+
exports.Flare = require_browser.Flare;
|
|
176
21
|
Object.defineProperty(exports, 'GlobalScopeProvider', {
|
|
177
22
|
enumerable: true,
|
|
178
23
|
get: function () {
|
package/dist/index.d.cts
CHANGED
|
@@ -1,9 +1,7 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { Flare } from "./browser.cjs";
|
|
2
|
+
import { AttributeValue, Attributes, Config, ContextCollector, DEFAULT_URL_DENYLIST, EntryPointHandler, FileReader, FlushFn, FlushScheduler, Framework, GlobalScopeProvider, Glow, Logger, MessageLevel, NullFileReader, OverriddenGrouping, Report, Scope, ScopeProvider, SdkInfo, SpanEvent, StackFrame, convertToError, redactUrlQuery, redactUrlQuery as redactFullPath, resolveDenylist } from "@flareapp/core";
|
|
2
3
|
|
|
3
4
|
//#region src/index.d.ts
|
|
4
|
-
declare class Flare extends Flare$1 {
|
|
5
|
-
constructor(api?: Api, contextCollector?: ContextCollector$1, fileReader?: FileReader$1, scopeProvider?: ScopeProvider$1);
|
|
6
|
-
}
|
|
7
5
|
declare const flare: Flare;
|
|
8
6
|
//#endregion
|
|
9
7
|
export { type AttributeValue, type Attributes, type Config, type ContextCollector, DEFAULT_URL_DENYLIST, type EntryPointHandler, type FileReader, Flare, type FlushFn, type FlushScheduler, type Framework, GlobalScopeProvider, type Glow, Logger, type MessageLevel, NullFileReader, type OverriddenGrouping, type Report, Scope, type ScopeProvider, type SdkInfo, type SpanEvent, type StackFrame, convertToError, flare, redactFullPath, redactUrlQuery, resolveDenylist };
|
package/dist/index.d.mts
CHANGED
|
@@ -1,9 +1,7 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { Flare } from "./browser.mjs";
|
|
2
|
+
import { AttributeValue, Attributes, Config, ContextCollector, DEFAULT_URL_DENYLIST, EntryPointHandler, FileReader, FlushFn, FlushScheduler, Framework, GlobalScopeProvider, Glow, Logger, MessageLevel, NullFileReader, OverriddenGrouping, Report, Scope, ScopeProvider, SdkInfo, SpanEvent, StackFrame, convertToError, redactUrlQuery, redactUrlQuery as redactFullPath, resolveDenylist } from "@flareapp/core";
|
|
2
3
|
|
|
3
4
|
//#region src/index.d.ts
|
|
4
|
-
declare class Flare extends Flare$1 {
|
|
5
|
-
constructor(api?: Api, contextCollector?: ContextCollector$1, fileReader?: FileReader$1, scopeProvider?: ScopeProvider$1);
|
|
6
|
-
}
|
|
7
5
|
declare const flare: Flare;
|
|
8
6
|
//#endregion
|
|
9
7
|
export { type AttributeValue, type Attributes, type Config, type ContextCollector, DEFAULT_URL_DENYLIST, type EntryPointHandler, type FileReader, Flare, type FlushFn, type FlushScheduler, type Framework, GlobalScopeProvider, type Glow, Logger, type MessageLevel, NullFileReader, type OverriddenGrouping, type Report, Scope, type ScopeProvider, type SdkInfo, type SpanEvent, type StackFrame, convertToError, flare, redactFullPath, redactUrlQuery, resolveDenylist };
|
package/dist/index.mjs
CHANGED
|
@@ -1,163 +1,8 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { t as catchWindowErrors } from "./catchWindowErrors-DKjw0DIA.mjs";
|
|
2
|
+
import { Flare } from "./browser.mjs";
|
|
3
|
+
import { DEFAULT_URL_DENYLIST, GlobalScopeProvider, Logger, NullFileReader, Scope, convertToError, redactUrlQuery, redactUrlQuery as redactFullPath, resolveDenylist } from "@flareapp/core";
|
|
2
4
|
|
|
3
|
-
//#region src/browser/catchWindowErrors.ts
|
|
4
|
-
function catchWindowErrors() {
|
|
5
|
-
if (typeof window === "undefined") return;
|
|
6
|
-
window.addEventListener("error", (event) => {
|
|
7
|
-
const flare = window.flare;
|
|
8
|
-
if (!flare) return;
|
|
9
|
-
if (event.error instanceof Error) flare.reportSilently(event.error);
|
|
10
|
-
});
|
|
11
|
-
window.addEventListener("unhandledrejection", (event) => {
|
|
12
|
-
const flare = window.flare;
|
|
13
|
-
if (!flare) return;
|
|
14
|
-
const reason = event.reason;
|
|
15
|
-
if (reason instanceof Error) {
|
|
16
|
-
flare.reportSilently(reason);
|
|
17
|
-
return;
|
|
18
|
-
}
|
|
19
|
-
if (hasStack(reason)) {
|
|
20
|
-
const error = new Error(describeRejectionReason(reason));
|
|
21
|
-
error.stack = reason.stack;
|
|
22
|
-
flare.reportSilently(error);
|
|
23
|
-
return;
|
|
24
|
-
}
|
|
25
|
-
Promise.resolve(flare.reportUnhandledRejection(describeRejectionReason(reason))).catch(() => {});
|
|
26
|
-
});
|
|
27
|
-
}
|
|
28
|
-
function describeRejectionReason(reason) {
|
|
29
|
-
if (typeof reason === "string") return reason;
|
|
30
|
-
if (reason && typeof reason === "object") {
|
|
31
|
-
const message = reason.message;
|
|
32
|
-
if (typeof message === "string") return message;
|
|
33
|
-
try {
|
|
34
|
-
return JSON.stringify(reason);
|
|
35
|
-
} catch {
|
|
36
|
-
return "Unhandled promise rejection (non-serializable reason)";
|
|
37
|
-
}
|
|
38
|
-
}
|
|
39
|
-
return String(reason);
|
|
40
|
-
}
|
|
41
|
-
function hasStack(value) {
|
|
42
|
-
return typeof value === "object" && value !== null && "stack" in value && typeof value.stack === "string";
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
//#endregion
|
|
46
|
-
//#region src/browser/BrowserFlushScheduler.ts
|
|
47
|
-
var BrowserFlushScheduler = class {
|
|
48
|
-
register(flush) {
|
|
49
|
-
if (typeof document === "undefined" || !document) return;
|
|
50
|
-
document.addEventListener("visibilitychange", () => {
|
|
51
|
-
if (document.visibilityState === "hidden") flush({ keepalive: true });
|
|
52
|
-
});
|
|
53
|
-
}
|
|
54
|
-
};
|
|
55
|
-
|
|
56
|
-
//#endregion
|
|
57
|
-
//#region src/browser/context/cookie.ts
|
|
58
|
-
function cookie() {
|
|
59
|
-
if (!window.document.cookie) return {};
|
|
60
|
-
const cookies = {};
|
|
61
|
-
window.document.cookie.split("; ").forEach((rawCookie) => {
|
|
62
|
-
const idx = rawCookie.indexOf("=");
|
|
63
|
-
if (idx === -1) {
|
|
64
|
-
cookies[rawCookie] = "";
|
|
65
|
-
return;
|
|
66
|
-
}
|
|
67
|
-
const name = rawCookie.slice(0, idx);
|
|
68
|
-
cookies[name] = rawCookie.slice(idx + 1);
|
|
69
|
-
});
|
|
70
|
-
return { "http.request.cookies": cookies };
|
|
71
|
-
}
|
|
72
|
-
|
|
73
|
-
//#endregion
|
|
74
|
-
//#region src/browser/context/request.ts
|
|
75
|
-
function request(urlDenylist) {
|
|
76
|
-
return {
|
|
77
|
-
"url.full": redactUrlQuery$1(window.location.href, urlDenylist),
|
|
78
|
-
"user_agent.original": window.navigator.userAgent,
|
|
79
|
-
"http.request.referrer": redactUrlQuery$1(window.document.referrer, urlDenylist),
|
|
80
|
-
"document.ready_state": window.document.readyState
|
|
81
|
-
};
|
|
82
|
-
}
|
|
83
|
-
|
|
84
|
-
//#endregion
|
|
85
|
-
//#region src/browser/context/requestData.ts
|
|
86
|
-
function requestData(urlDenylist) {
|
|
87
|
-
if (!window.location.search) return {};
|
|
88
|
-
return { "url.query": redactUrlQuery$1(window.location.search, urlDenylist).replace(/^\?/, "") };
|
|
89
|
-
}
|
|
90
|
-
|
|
91
|
-
//#endregion
|
|
92
|
-
//#region src/browser/context/collectBrowser.ts
|
|
93
|
-
const collectBrowser = (config) => {
|
|
94
|
-
if (typeof window === "undefined") return { "flare.entry_point.type": "server" };
|
|
95
|
-
const attrs = { "flare.entry_point.type": "web" };
|
|
96
|
-
if (window?.location?.href) {
|
|
97
|
-
attrs["flare.entry_point.value"] = redactUrlQuery$1(window.location.href, config.urlDenylist);
|
|
98
|
-
if (window.location.pathname) {
|
|
99
|
-
attrs["flare.entry_point.handler.identifier"] = window.location.pathname;
|
|
100
|
-
attrs["flare.entry_point.handler.type"] = "browser";
|
|
101
|
-
}
|
|
102
|
-
}
|
|
103
|
-
if (window?.location?.hostname) attrs["host.name"] = window.location.hostname;
|
|
104
|
-
Object.assign(attrs, request(config.urlDenylist));
|
|
105
|
-
Object.assign(attrs, requestData(config.urlDenylist));
|
|
106
|
-
Object.assign(attrs, cookie());
|
|
107
|
-
return attrs;
|
|
108
|
-
};
|
|
109
|
-
|
|
110
|
-
//#endregion
|
|
111
|
-
//#region src/browser/FetchFileReader.ts
|
|
112
|
-
/**
|
|
113
|
-
* Browser `FileReader` implementation that fetches source files over HTTP(S).
|
|
114
|
-
*
|
|
115
|
-
* Wired into `@flareapp/js`'s singleton so the stack-trace builder can pull
|
|
116
|
-
* the original source for each frame and render a code snippet around the
|
|
117
|
-
* offending line. The source URL comes from the frame (usually the URL of
|
|
118
|
-
* the JS bundle that produced the error, post-sourcemap resolution).
|
|
119
|
-
*
|
|
120
|
-
* Three safety gates:
|
|
121
|
-
*
|
|
122
|
-
* 1. **Scheme allowlist.** Only `http:` and `https:` URLs are fetched. Other
|
|
123
|
-
* schemes (`chrome-extension://`, `file://`, `blob:`, `data:`) return
|
|
124
|
-
* `null` immediately. This avoids surprise privilege boundaries (e.g.,
|
|
125
|
-
* pages should not read extension-internal files) and dodges CORS/CSP
|
|
126
|
-
* walls that would error noisily.
|
|
127
|
-
* 2. **Status check.** Only `200 OK` responses are used. 3xx redirects are
|
|
128
|
-
* handled transparently by `fetch`; 4xx/5xx fall back to `null` so the
|
|
129
|
-
* snippet is simply omitted from the report.
|
|
130
|
-
* 3. **Catch-all.** Network failures, CORS errors, and aborted requests
|
|
131
|
-
* return `null`. We never let a source-fetch failure leak as an error
|
|
132
|
-
* that the consumer page would see.
|
|
133
|
-
*
|
|
134
|
-
* The `read()` contract returns `null` on any failure path, never throws.
|
|
135
|
-
*/
|
|
136
|
-
var FetchFileReader = class {
|
|
137
|
-
read(url) {
|
|
138
|
-
if (!/^https?:\/\//i.test(url)) return Promise.resolve(null);
|
|
139
|
-
return fetch(url).then((response) => {
|
|
140
|
-
if (response.status !== 200) return null;
|
|
141
|
-
return response.text();
|
|
142
|
-
}).catch(() => null);
|
|
143
|
-
}
|
|
144
|
-
};
|
|
145
|
-
|
|
146
|
-
//#endregion
|
|
147
|
-
//#region src/env/index.ts
|
|
148
|
-
const CLIENT_VERSION = typeof process !== "undefined" && true ? "2.3.0" : "?";
|
|
149
|
-
|
|
150
|
-
//#endregion
|
|
151
5
|
//#region src/index.ts
|
|
152
|
-
var Flare = class extends Flare$1 {
|
|
153
|
-
constructor(api = new Api(), contextCollector = collectBrowser, fileReader = new FetchFileReader(), scopeProvider = new GlobalScopeProvider$1()) {
|
|
154
|
-
super(api, contextCollector, fileReader, scopeProvider, new BrowserFlushScheduler());
|
|
155
|
-
this.setSdkInfo({
|
|
156
|
-
name: "@flareapp/js",
|
|
157
|
-
version: CLIENT_VERSION
|
|
158
|
-
});
|
|
159
|
-
}
|
|
160
|
-
};
|
|
161
6
|
const flare = new Flare();
|
|
162
7
|
if (typeof window !== "undefined" && window) {
|
|
163
8
|
window.flare = flare;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@flareapp/js",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.4.0",
|
|
4
4
|
"description": "JavaScript client for flareapp.io",
|
|
5
5
|
"homepage": "https://flareapp.io",
|
|
6
6
|
"bugs": {
|
|
@@ -39,17 +39,27 @@
|
|
|
39
39
|
"types": "./dist/index.d.cts",
|
|
40
40
|
"default": "./dist/index.cjs"
|
|
41
41
|
}
|
|
42
|
+
},
|
|
43
|
+
"./browser": {
|
|
44
|
+
"import": {
|
|
45
|
+
"types": "./dist/browser.d.mts",
|
|
46
|
+
"default": "./dist/browser.mjs"
|
|
47
|
+
},
|
|
48
|
+
"require": {
|
|
49
|
+
"types": "./dist/browser.d.cts",
|
|
50
|
+
"default": "./dist/browser.cjs"
|
|
51
|
+
}
|
|
42
52
|
}
|
|
43
53
|
},
|
|
44
54
|
"scripts": {
|
|
45
55
|
"prepublishOnly": "npm run build",
|
|
46
|
-
"build": "tsdown src/index.ts --format cjs,esm --dts --env.FLARE_JS_CLIENT_VERSION=$(node -p \"require('./package.json').version\") --clean",
|
|
56
|
+
"build": "tsdown src/index.ts src/browser.ts --format cjs,esm --dts --env.FLARE_JS_CLIENT_VERSION=$(node -p \"require('./package.json').version\") --clean",
|
|
47
57
|
"test": "vitest run",
|
|
48
58
|
"typescript": "tsc --noEmit",
|
|
49
59
|
"release": "release-it"
|
|
50
60
|
},
|
|
51
61
|
"dependencies": {
|
|
52
|
-
"@flareapp/core": "2.
|
|
62
|
+
"@flareapp/core": "2.4.0"
|
|
53
63
|
},
|
|
54
64
|
"devDependencies": {
|
|
55
65
|
"error-stack-parser": "^2.0.2",
|