@flareapp/electron 0.1.0 → 2.5.1
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 +22 -123
- package/dist/main.cjs +11 -22
- package/dist/main.d.cts +4 -11
- package/dist/main.d.mts +4 -11
- package/dist/main.mjs +12 -23
- package/dist/renderer.cjs +1 -1
- package/dist/renderer.mjs +1 -1
- package/package.json +9 -5
package/README.md
CHANGED
|
@@ -1,18 +1,16 @@
|
|
|
1
1
|
# @flareapp/electron
|
|
2
2
|
|
|
3
|
-
> ⚠️ **Experimental (`0.1.0`).** This package is new and its API may change in a minor release. Feedback and bug reports are very welcome at https://github.com/spatie/flare-client-js/issues.
|
|
4
|
-
|
|
5
3
|
Electron SDK for [Flare](https://flareapp.io) error tracking. It captures JavaScript errors in **both** Electron processes and routes every report through the main process, so your API key lives in exactly one place.
|
|
6
4
|
|
|
7
5
|
## What it captures
|
|
8
6
|
|
|
9
7
|
- **Main process:** uncaught exceptions and unhandled promise rejections.
|
|
10
8
|
- **Renderer process:** `window.onerror` and `unhandledrejection`, plus anything you report manually.
|
|
11
|
-
- **Process crashes:** `render-process-gone` and `child-process-gone
|
|
9
|
+
- **Process crashes:** `render-process-gone` and `child-process-gone`, reported with the crash `reason` and `exitCode`.
|
|
12
10
|
|
|
13
11
|
It does **not** capture native crashes (C++/Crashpad minidumps). Only JavaScript-level errors are sent to Flare.
|
|
14
12
|
|
|
15
|
-
##
|
|
13
|
+
## Installation
|
|
16
14
|
|
|
17
15
|
```bash
|
|
18
16
|
npm install @flareapp/electron
|
|
@@ -20,154 +18,55 @@ npm install @flareapp/electron
|
|
|
20
18
|
|
|
21
19
|
`electron` is a peer dependency; this package expects your app to provide it.
|
|
22
20
|
|
|
23
|
-
##
|
|
24
|
-
|
|
25
|
-
Flare needs wiring in all three Electron contexts. The API key, `stage`, `version`, and sourcemap settings are configured **once, in the main process** — the renderer needs none of them.
|
|
21
|
+
## Quick start
|
|
26
22
|
|
|
27
|
-
|
|
23
|
+
Flare needs wiring in all three Electron contexts. The API key is configured **once, in the main process**.
|
|
28
24
|
|
|
29
25
|
```ts
|
|
30
26
|
// main.ts
|
|
31
|
-
import { app } from 'electron';
|
|
32
27
|
import { flare } from '@flareapp/electron/main';
|
|
33
28
|
|
|
34
|
-
flare.light('
|
|
35
|
-
|
|
36
|
-
// Optional: these are set ONCE here and applied to renderer reports too.
|
|
37
|
-
flare.configure({ stage: 'production', version: app.getVersion() });
|
|
38
|
-
|
|
39
|
-
// Optional: fatal-handler behavior and IPC trust policy.
|
|
40
|
-
flare.configureElectron({
|
|
41
|
-
uncaughtExceptionMode: 'report-and-exit', // 'report' | 'report-and-exit' | 'off'
|
|
42
|
-
unhandledRejectionMode: 'report-and-exit',
|
|
43
|
-
captureRenderProcessGone: true,
|
|
44
|
-
});
|
|
29
|
+
flare.light('YOUR_FLARE_API_KEY');
|
|
45
30
|
```
|
|
46
31
|
|
|
47
|
-
In `report-and-exit` mode, after a fatal error Flare reports it, flushes pending reports (up to `shutdownTimeoutMs`), then calls `app.exit(1)`.
|
|
48
|
-
|
|
49
|
-
### 2. Preload script
|
|
50
|
-
|
|
51
|
-
Because `contextIsolation` is on (the Electron default and the recommended setting), the renderer cannot reach `ipcRenderer` directly. The preload helper bridges reports over `contextBridge`. This step is **required** — without it, renderer reports are dropped.
|
|
52
|
-
|
|
53
32
|
```ts
|
|
54
|
-
// preload.ts
|
|
33
|
+
// preload.ts — required so renderer reports reach main over contextBridge
|
|
55
34
|
import { exposeFlare } from '@flareapp/electron/preload';
|
|
56
35
|
|
|
57
36
|
exposeFlare();
|
|
58
37
|
```
|
|
59
38
|
|
|
60
|
-
Make sure your `BrowserWindow` points at this preload script:
|
|
61
|
-
|
|
62
39
|
```ts
|
|
63
|
-
|
|
64
|
-
webPreferences: {
|
|
65
|
-
preload: path.join(__dirname, 'preload.js'),
|
|
66
|
-
contextIsolation: true,
|
|
67
|
-
},
|
|
68
|
-
});
|
|
69
|
-
```
|
|
70
|
-
|
|
71
|
-
### 3. Renderer
|
|
72
|
-
|
|
73
|
-
Import the renderer entry once, as early as possible, to install the global error listeners:
|
|
74
|
-
|
|
75
|
-
```ts
|
|
76
|
-
// renderer entry, e.g. main.tsx / index.ts
|
|
40
|
+
// renderer entry, e.g. main.tsx / index.ts — installs the global listeners
|
|
77
41
|
import '@flareapp/electron/renderer';
|
|
78
42
|
```
|
|
79
43
|
|
|
80
|
-
|
|
44
|
+
Point your `BrowserWindow` at the preload script with `contextIsolation: true` (the default).
|
|
81
45
|
|
|
82
|
-
|
|
83
|
-
import { flare } from '@flareapp/electron/renderer';
|
|
46
|
+
## Using a UI framework
|
|
84
47
|
|
|
85
|
-
|
|
86
|
-
doRiskyThing();
|
|
87
|
-
} catch (error) {
|
|
88
|
-
flare.report(error as Error);
|
|
89
|
-
}
|
|
90
|
-
```
|
|
48
|
+
When your renderer uses React, Vue, or Svelte, inject the Electron Flare instance through the framework's `/inject` entry instead of the `@flareapp/js` web singleton. See the framework configuration guides:
|
|
91
49
|
|
|
92
|
-
|
|
50
|
+
- [Electron + React](https://flareapp.io/docs/react/electron/configuration)
|
|
51
|
+
- [Electron + Vue](https://flareapp.io/docs/vue/electron/configuration)
|
|
52
|
+
- [Electron + Svelte](https://flareapp.io/docs/svelte/electron/configuration)
|
|
93
53
|
|
|
94
|
-
##
|
|
54
|
+
## Identifying users
|
|
95
55
|
|
|
96
|
-
|
|
97
|
-
renderer error
|
|
98
|
-
→ RendererFlare builds Report (stack + snippets + browser context)
|
|
99
|
-
→ renderer beforeSubmit → serialize → size-check
|
|
100
|
-
→ window.__flare.report(jsonString) [contextBridge]
|
|
101
|
-
→ ipcRenderer.invoke('flare:report') [IPC]
|
|
102
|
-
→ main: trust sender → size-check → parse → validate
|
|
103
|
-
→ overlay stage/version/sourcemap + app metadata + user
|
|
104
|
-
→ main beforeSubmit → sent to Flare
|
|
105
|
-
|
|
106
|
-
main-process error
|
|
107
|
-
→ process handlers → sent to Flare (app.exit on report-and-exit)
|
|
108
|
-
|
|
109
|
-
renderer / GPU crash
|
|
110
|
-
→ render-process-gone / child-process-gone → reported → sent to Flare
|
|
111
|
-
```
|
|
112
|
-
|
|
113
|
-
The API key is held only in the main process because that is the single egress point: every report, wherever it originates, is sent from main.
|
|
114
|
-
|
|
115
|
-
## Filtering reports (`beforeSubmit`)
|
|
116
|
-
|
|
117
|
-
`beforeSubmit` runs in **two stages**: once in the renderer (scrub close to the source) and once in main (the final gate before sending). Returning `null`/`false` from either drops the report.
|
|
118
|
-
|
|
119
|
-
```ts
|
|
120
|
-
// main
|
|
121
|
-
flare.configure({
|
|
122
|
-
beforeSubmit: (report) => {
|
|
123
|
-
// final scrub before sending
|
|
124
|
-
return report;
|
|
125
|
-
},
|
|
126
|
-
});
|
|
127
|
-
|
|
128
|
-
// renderer
|
|
129
|
-
import { flare } from '@flareapp/electron/renderer';
|
|
130
|
-
flare.configure({
|
|
131
|
-
beforeSubmit: (report) => {
|
|
132
|
-
delete report.attributes['context.custom'];
|
|
133
|
-
return report;
|
|
134
|
-
},
|
|
135
|
-
});
|
|
136
|
-
```
|
|
137
|
-
|
|
138
|
-
## Sender trust
|
|
139
|
-
|
|
140
|
-
The main process only accepts reports from frames it trusts. By **default** it accepts:
|
|
141
|
-
|
|
142
|
-
- `file:` URLs (packaged builds), and
|
|
143
|
-
- `http(s)` on `localhost` / `127.0.0.1` (dev servers).
|
|
144
|
-
|
|
145
|
-
It rejects everything else, including remote origins and custom protocols. If your app serves its renderer over a custom protocol or loads trusted remote content, opt in:
|
|
146
|
-
|
|
147
|
-
```ts
|
|
148
|
-
// Add a custom protocol scheme:
|
|
149
|
-
flare.configureElectron({ trustedProtocols: ['app'] });
|
|
150
|
-
|
|
151
|
-
// Or take full control:
|
|
152
|
-
flare.configureElectron({
|
|
153
|
-
trustSender: (frame) => new URL(frame.url).origin === 'https://app.example.com',
|
|
154
|
-
});
|
|
155
|
-
```
|
|
156
|
-
|
|
157
|
-
## Attaching the current user
|
|
56
|
+
Set the user in the main process; it is stamped on main-origin reports and on forwarded renderer reports:
|
|
158
57
|
|
|
159
58
|
```ts
|
|
160
59
|
import { flare } from '@flareapp/electron/main';
|
|
161
60
|
|
|
162
|
-
flare.setUser({ id: 123, email: '
|
|
163
|
-
flare.setUser(null); // clear on logout
|
|
61
|
+
flare.setUser({ id: 123, email: 'jane@example.com', fullName: 'Jane Doe' });
|
|
164
62
|
```
|
|
165
63
|
|
|
166
|
-
|
|
64
|
+
Recognised fields: `id`, `email`, `fullName`, `ipAddress`; extra keys land in `user.attributes`. Pass `null` to clear. The main-process user is authoritative for forwarded renderer reports.
|
|
65
|
+
|
|
66
|
+
## Documentation
|
|
167
67
|
|
|
168
|
-
|
|
68
|
+
Full documentation on the report flow, `beforeSubmit` filtering, sender trust, attaching users, and the framework integrations is available at [flareapp.io/docs/javascript/electron/how-it-works](https://flareapp.io/docs/javascript/electron/how-it-works).
|
|
169
69
|
|
|
170
|
-
|
|
171
|
-
- Errors that occur before `flare.light('your-key')` runs in the main process. The fatal process handlers are attached by `light()`, and no report is sent without a key, so call `light()` as early as possible in your main entry. Errors before that point (in any process) are not sent.
|
|
70
|
+
## License
|
|
172
71
|
|
|
173
|
-
|
|
72
|
+
The MIT License (MIT). Please see [License File](../../LICENSE.md) for more information.
|
package/dist/main.cjs
CHANGED
|
@@ -34,7 +34,7 @@ let node_fs_promises = require("node:fs/promises");
|
|
|
34
34
|
let node_url = require("node:url");
|
|
35
35
|
|
|
36
36
|
//#region src/env.ts
|
|
37
|
-
const CLIENT_VERSION = typeof process !== "undefined" && true ? "
|
|
37
|
+
const CLIENT_VERSION = typeof process !== "undefined" && true ? "2.5.1" : "?";
|
|
38
38
|
|
|
39
39
|
//#endregion
|
|
40
40
|
//#region src/types.ts
|
|
@@ -76,23 +76,12 @@ function collectElectronAppAttributes(app) {
|
|
|
76
76
|
} catch {}
|
|
77
77
|
return attrs;
|
|
78
78
|
}
|
|
79
|
-
/** Project a user into OTel enduser.* / client.address keys. */
|
|
80
|
-
function projectUser(user) {
|
|
81
|
-
const attrs = {};
|
|
82
|
-
if (!user) return attrs;
|
|
83
|
-
if (user.id !== void 0) attrs["enduser.id"] = String(user.id);
|
|
84
|
-
if (user.email !== void 0) attrs["enduser.email"] = user.email;
|
|
85
|
-
if (user.username !== void 0) attrs["enduser.username"] = user.username;
|
|
86
|
-
if (user.ipAddress !== void 0) attrs["client.address"] = user.ipAddress;
|
|
87
|
-
return attrs;
|
|
88
|
-
}
|
|
89
79
|
/** Build the ContextCollector core calls on every main-process report. */
|
|
90
|
-
function makeElectronContextCollector(app
|
|
80
|
+
function makeElectronContextCollector(app) {
|
|
91
81
|
return (_config) => ({
|
|
92
82
|
"flare.entry_point.type": "server",
|
|
93
83
|
"process.type": process.type ?? "browser",
|
|
94
|
-
...collectElectronAppAttributes(app)
|
|
95
|
-
...projectUser(getUser())
|
|
84
|
+
...collectElectronAppAttributes(app)
|
|
96
85
|
});
|
|
97
86
|
}
|
|
98
87
|
|
|
@@ -293,7 +282,7 @@ var ElectronFlare = class extends _flareapp_core.Flare {
|
|
|
293
282
|
app;
|
|
294
283
|
ipcMain;
|
|
295
284
|
options = { ...DEFAULT_ELECTRON_OPTIONS };
|
|
296
|
-
|
|
285
|
+
mainScope;
|
|
297
286
|
isLit = false;
|
|
298
287
|
handlerManager;
|
|
299
288
|
renderGoneHandler = null;
|
|
@@ -305,9 +294,11 @@ var ElectronFlare = class extends _flareapp_core.Flare {
|
|
|
305
294
|
mainSourcemapVersionId = "";
|
|
306
295
|
constructor(deps) {
|
|
307
296
|
const app = deps.app;
|
|
308
|
-
const collector = makeElectronContextCollector(app
|
|
297
|
+
const collector = makeElectronContextCollector(app);
|
|
309
298
|
const flushScheduler = new ElectronFlushScheduler(app);
|
|
310
|
-
|
|
299
|
+
const mainScope = new _flareapp_core.GlobalScopeProvider();
|
|
300
|
+
super(new _flareapp_core.Api(), collector, new ElectronDiskFileReader(), mainScope, flushScheduler);
|
|
301
|
+
this.mainScope = mainScope;
|
|
311
302
|
this.app = app;
|
|
312
303
|
this.ipcMain = deps.ipcMain;
|
|
313
304
|
this.flushScheduler = flushScheduler;
|
|
@@ -346,9 +337,6 @@ var ElectronFlare = class extends _flareapp_core.Flare {
|
|
|
346
337
|
this.reconcileCrashListeners();
|
|
347
338
|
return this;
|
|
348
339
|
}
|
|
349
|
-
setUser(user) {
|
|
350
|
-
this.user = user;
|
|
351
|
-
}
|
|
352
340
|
dispose() {
|
|
353
341
|
this.handlerManager.detach();
|
|
354
342
|
this.detachCrashListeners();
|
|
@@ -409,9 +397,10 @@ var ElectronFlare = class extends _flareapp_core.Flare {
|
|
|
409
397
|
});
|
|
410
398
|
});
|
|
411
399
|
}
|
|
412
|
-
/** Overlay main-authoritative config + Electron metadata + user onto a forwarded report, then send. */
|
|
400
|
+
/** Overlay main-authoritative config + Electron metadata + user identity (from the main scope) onto a forwarded report, then send. */
|
|
413
401
|
receiveRendererReport(report) {
|
|
414
|
-
|
|
402
|
+
for (const key of _flareapp_core.USER_IDENTITY_KEYS) delete report.attributes[key];
|
|
403
|
+
Object.assign(report.attributes, collectElectronAppAttributes(this.app), (0, _flareapp_core.userIdentityAttributes)(this.mainScope.active()));
|
|
415
404
|
overlayOrDelete(report.attributes, "service.stage", this.mainStage);
|
|
416
405
|
overlayOrDelete(report.attributes, "service.version", this.mainVersion);
|
|
417
406
|
if (this.mainSourcemapVersionId) report.sourcemapVersionId = this.mainSourcemapVersionId;
|
package/dist/main.d.cts
CHANGED
|
@@ -1,14 +1,8 @@
|
|
|
1
|
-
import { AttributeValue, Attributes, Config, Config as Config$1, DEFAULT_URL_DENYLIST, Flare, GlobalScopeProvider, Glow, Logger, MessageLevel, NullFileReader, Report, Scope, SdkInfo, StackFrame, convertToError, redactUrlQuery, resolveDenylist } from "@flareapp/core";
|
|
1
|
+
import { AttributeValue, Attributes, Config, Config as Config$1, DEFAULT_URL_DENYLIST, Flare, GlobalScopeProvider, Glow, Logger, MessageLevel, NullFileReader, Report, Scope, SdkInfo, StackFrame, User, convertToError, redactUrlQuery, resolveDenylist } from "@flareapp/core";
|
|
2
2
|
import { App, IpcMain } from "electron";
|
|
3
3
|
|
|
4
4
|
//#region src/types.d.ts
|
|
5
5
|
type ElectronFatalMode = 'off' | 'report' | 'report-and-exit';
|
|
6
|
-
type ElectronUser = {
|
|
7
|
-
id?: string | number;
|
|
8
|
-
email?: string;
|
|
9
|
-
username?: string;
|
|
10
|
-
ipAddress?: string;
|
|
11
|
-
};
|
|
12
6
|
/** A frame the IPC receiver evaluates for trust. Mirrors Electron's WebFrameMain shape we use. */
|
|
13
7
|
type SenderFrame = {
|
|
14
8
|
url: string;
|
|
@@ -35,7 +29,7 @@ declare class ElectronFlare extends Flare {
|
|
|
35
29
|
private app;
|
|
36
30
|
private ipcMain;
|
|
37
31
|
private options;
|
|
38
|
-
private
|
|
32
|
+
private mainScope;
|
|
39
33
|
private isLit;
|
|
40
34
|
private handlerManager;
|
|
41
35
|
private renderGoneHandler;
|
|
@@ -49,7 +43,6 @@ declare class ElectronFlare extends Flare {
|
|
|
49
43
|
configure(config: Partial<Config$1>): this;
|
|
50
44
|
light(key?: string, debug?: boolean): this;
|
|
51
45
|
configureElectron(partial: ElectronOptions): this;
|
|
52
|
-
setUser(user: ElectronUser | null): void;
|
|
53
46
|
dispose(): void;
|
|
54
47
|
/** Attach or detach the process-gone listeners to match options.captureRenderProcessGone. Idempotent. */
|
|
55
48
|
private reconcileCrashListeners;
|
|
@@ -61,7 +54,7 @@ declare class ElectronFlare extends Flare {
|
|
|
61
54
|
* first, so the event loop is not kept alive unnecessarily.
|
|
62
55
|
*/
|
|
63
56
|
flush(timeoutMs?: number): Promise<void>;
|
|
64
|
-
/** Overlay main-authoritative config + Electron metadata + user onto a forwarded report, then send. */
|
|
57
|
+
/** Overlay main-authoritative config + Electron metadata + user identity (from the main scope) onto a forwarded report, then send. */
|
|
65
58
|
private receiveRendererReport;
|
|
66
59
|
}
|
|
67
60
|
//#endregion
|
|
@@ -74,4 +67,4 @@ declare const FLARE_BRIDGE_KEY = "__flare";
|
|
|
74
67
|
//#region src/main.d.ts
|
|
75
68
|
declare const flare: ElectronFlare;
|
|
76
69
|
//#endregion
|
|
77
|
-
export { type AttributeValue, type Attributes, type Config, DEFAULT_URL_DENYLIST, type ElectronFatalMode, ElectronFlare, type ElectronOptions,
|
|
70
|
+
export { type AttributeValue, type Attributes, type Config, DEFAULT_URL_DENYLIST, type ElectronFatalMode, ElectronFlare, type ElectronOptions, FLARE_BRIDGE_KEY, FLARE_IPC_CHANNEL, GlobalScopeProvider, type Glow, Logger, type MessageLevel, NullFileReader, type Report, Scope, type SdkInfo, type SenderFrame, type StackFrame, type User, convertToError, flare, redactUrlQuery, resolveDenylist };
|
package/dist/main.d.mts
CHANGED
|
@@ -1,14 +1,8 @@
|
|
|
1
1
|
import { App, IpcMain } from "electron";
|
|
2
|
-
import { AttributeValue, Attributes, Config, Config as Config$1, DEFAULT_URL_DENYLIST, Flare, GlobalScopeProvider, Glow, Logger, MessageLevel, NullFileReader, Report, Scope, SdkInfo, StackFrame, convertToError, redactUrlQuery, resolveDenylist } from "@flareapp/core";
|
|
2
|
+
import { AttributeValue, Attributes, Config, Config as Config$1, DEFAULT_URL_DENYLIST, Flare, GlobalScopeProvider, Glow, Logger, MessageLevel, NullFileReader, Report, Scope, SdkInfo, StackFrame, User, convertToError, redactUrlQuery, resolveDenylist } from "@flareapp/core";
|
|
3
3
|
|
|
4
4
|
//#region src/types.d.ts
|
|
5
5
|
type ElectronFatalMode = 'off' | 'report' | 'report-and-exit';
|
|
6
|
-
type ElectronUser = {
|
|
7
|
-
id?: string | number;
|
|
8
|
-
email?: string;
|
|
9
|
-
username?: string;
|
|
10
|
-
ipAddress?: string;
|
|
11
|
-
};
|
|
12
6
|
/** A frame the IPC receiver evaluates for trust. Mirrors Electron's WebFrameMain shape we use. */
|
|
13
7
|
type SenderFrame = {
|
|
14
8
|
url: string;
|
|
@@ -35,7 +29,7 @@ declare class ElectronFlare extends Flare {
|
|
|
35
29
|
private app;
|
|
36
30
|
private ipcMain;
|
|
37
31
|
private options;
|
|
38
|
-
private
|
|
32
|
+
private mainScope;
|
|
39
33
|
private isLit;
|
|
40
34
|
private handlerManager;
|
|
41
35
|
private renderGoneHandler;
|
|
@@ -49,7 +43,6 @@ declare class ElectronFlare extends Flare {
|
|
|
49
43
|
configure(config: Partial<Config$1>): this;
|
|
50
44
|
light(key?: string, debug?: boolean): this;
|
|
51
45
|
configureElectron(partial: ElectronOptions): this;
|
|
52
|
-
setUser(user: ElectronUser | null): void;
|
|
53
46
|
dispose(): void;
|
|
54
47
|
/** Attach or detach the process-gone listeners to match options.captureRenderProcessGone. Idempotent. */
|
|
55
48
|
private reconcileCrashListeners;
|
|
@@ -61,7 +54,7 @@ declare class ElectronFlare extends Flare {
|
|
|
61
54
|
* first, so the event loop is not kept alive unnecessarily.
|
|
62
55
|
*/
|
|
63
56
|
flush(timeoutMs?: number): Promise<void>;
|
|
64
|
-
/** Overlay main-authoritative config + Electron metadata + user onto a forwarded report, then send. */
|
|
57
|
+
/** Overlay main-authoritative config + Electron metadata + user identity (from the main scope) onto a forwarded report, then send. */
|
|
65
58
|
private receiveRendererReport;
|
|
66
59
|
}
|
|
67
60
|
//#endregion
|
|
@@ -74,4 +67,4 @@ declare const FLARE_BRIDGE_KEY = "__flare";
|
|
|
74
67
|
//#region src/main.d.ts
|
|
75
68
|
declare const flare: ElectronFlare;
|
|
76
69
|
//#endregion
|
|
77
|
-
export { type AttributeValue, type Attributes, type Config, DEFAULT_URL_DENYLIST, type ElectronFatalMode, ElectronFlare, type ElectronOptions,
|
|
70
|
+
export { type AttributeValue, type Attributes, type Config, DEFAULT_URL_DENYLIST, type ElectronFatalMode, ElectronFlare, type ElectronOptions, FLARE_BRIDGE_KEY, FLARE_IPC_CHANNEL, GlobalScopeProvider, type Glow, Logger, type MessageLevel, NullFileReader, type Report, Scope, type SdkInfo, type SenderFrame, type StackFrame, type User, convertToError, flare, redactUrlQuery, resolveDenylist };
|
package/dist/main.mjs
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
import { app, ipcMain } from "electron";
|
|
2
|
-
import { Api, DEFAULT_URL_DENYLIST, Flare, GlobalScopeProvider, GlobalScopeProvider as GlobalScopeProvider$1, Logger, NullFileReader, Scope, convertToError, redactUrlQuery, resolveDenylist } from "@flareapp/core";
|
|
2
|
+
import { Api, DEFAULT_URL_DENYLIST, Flare, GlobalScopeProvider, GlobalScopeProvider as GlobalScopeProvider$1, Logger, NullFileReader, Scope, USER_IDENTITY_KEYS, convertToError, redactUrlQuery, resolveDenylist, userIdentityAttributes } from "@flareapp/core";
|
|
3
3
|
import os from "node:os";
|
|
4
4
|
import { readFile } from "node:fs/promises";
|
|
5
5
|
import { fileURLToPath } from "node:url";
|
|
6
6
|
|
|
7
7
|
//#region src/env.ts
|
|
8
|
-
const CLIENT_VERSION = typeof process !== "undefined" && true ? "
|
|
8
|
+
const CLIENT_VERSION = typeof process !== "undefined" && true ? "2.5.1" : "?";
|
|
9
9
|
|
|
10
10
|
//#endregion
|
|
11
11
|
//#region src/types.ts
|
|
@@ -47,23 +47,12 @@ function collectElectronAppAttributes(app) {
|
|
|
47
47
|
} catch {}
|
|
48
48
|
return attrs;
|
|
49
49
|
}
|
|
50
|
-
/** Project a user into OTel enduser.* / client.address keys. */
|
|
51
|
-
function projectUser(user) {
|
|
52
|
-
const attrs = {};
|
|
53
|
-
if (!user) return attrs;
|
|
54
|
-
if (user.id !== void 0) attrs["enduser.id"] = String(user.id);
|
|
55
|
-
if (user.email !== void 0) attrs["enduser.email"] = user.email;
|
|
56
|
-
if (user.username !== void 0) attrs["enduser.username"] = user.username;
|
|
57
|
-
if (user.ipAddress !== void 0) attrs["client.address"] = user.ipAddress;
|
|
58
|
-
return attrs;
|
|
59
|
-
}
|
|
60
50
|
/** Build the ContextCollector core calls on every main-process report. */
|
|
61
|
-
function makeElectronContextCollector(app
|
|
51
|
+
function makeElectronContextCollector(app) {
|
|
62
52
|
return (_config) => ({
|
|
63
53
|
"flare.entry_point.type": "server",
|
|
64
54
|
"process.type": process.type ?? "browser",
|
|
65
|
-
...collectElectronAppAttributes(app)
|
|
66
|
-
...projectUser(getUser())
|
|
55
|
+
...collectElectronAppAttributes(app)
|
|
67
56
|
});
|
|
68
57
|
}
|
|
69
58
|
|
|
@@ -264,7 +253,7 @@ var ElectronFlare = class extends Flare {
|
|
|
264
253
|
app;
|
|
265
254
|
ipcMain;
|
|
266
255
|
options = { ...DEFAULT_ELECTRON_OPTIONS };
|
|
267
|
-
|
|
256
|
+
mainScope;
|
|
268
257
|
isLit = false;
|
|
269
258
|
handlerManager;
|
|
270
259
|
renderGoneHandler = null;
|
|
@@ -276,9 +265,11 @@ var ElectronFlare = class extends Flare {
|
|
|
276
265
|
mainSourcemapVersionId = "";
|
|
277
266
|
constructor(deps) {
|
|
278
267
|
const app = deps.app;
|
|
279
|
-
const collector = makeElectronContextCollector(app
|
|
268
|
+
const collector = makeElectronContextCollector(app);
|
|
280
269
|
const flushScheduler = new ElectronFlushScheduler(app);
|
|
281
|
-
|
|
270
|
+
const mainScope = new GlobalScopeProvider$1();
|
|
271
|
+
super(new Api(), collector, new ElectronDiskFileReader(), mainScope, flushScheduler);
|
|
272
|
+
this.mainScope = mainScope;
|
|
282
273
|
this.app = app;
|
|
283
274
|
this.ipcMain = deps.ipcMain;
|
|
284
275
|
this.flushScheduler = flushScheduler;
|
|
@@ -317,9 +308,6 @@ var ElectronFlare = class extends Flare {
|
|
|
317
308
|
this.reconcileCrashListeners();
|
|
318
309
|
return this;
|
|
319
310
|
}
|
|
320
|
-
setUser(user) {
|
|
321
|
-
this.user = user;
|
|
322
|
-
}
|
|
323
311
|
dispose() {
|
|
324
312
|
this.handlerManager.detach();
|
|
325
313
|
this.detachCrashListeners();
|
|
@@ -380,9 +368,10 @@ var ElectronFlare = class extends Flare {
|
|
|
380
368
|
});
|
|
381
369
|
});
|
|
382
370
|
}
|
|
383
|
-
/** Overlay main-authoritative config + Electron metadata + user onto a forwarded report, then send. */
|
|
371
|
+
/** Overlay main-authoritative config + Electron metadata + user identity (from the main scope) onto a forwarded report, then send. */
|
|
384
372
|
receiveRendererReport(report) {
|
|
385
|
-
|
|
373
|
+
for (const key of USER_IDENTITY_KEYS) delete report.attributes[key];
|
|
374
|
+
Object.assign(report.attributes, collectElectronAppAttributes(this.app), userIdentityAttributes(this.mainScope.active()));
|
|
386
375
|
overlayOrDelete(report.attributes, "service.stage", this.mainStage);
|
|
387
376
|
overlayOrDelete(report.attributes, "service.version", this.mainVersion);
|
|
388
377
|
if (this.mainSourcemapVersionId) report.sourcemapVersionId = this.mainSourcemapVersionId;
|
package/dist/renderer.cjs
CHANGED
|
@@ -8,7 +8,7 @@ const FLARE_BRIDGE_KEY = "__flare";
|
|
|
8
8
|
|
|
9
9
|
//#endregion
|
|
10
10
|
//#region src/env.ts
|
|
11
|
-
const CLIENT_VERSION = typeof process !== "undefined" && true ? "
|
|
11
|
+
const CLIENT_VERSION = typeof process !== "undefined" && true ? "2.5.1" : "?";
|
|
12
12
|
|
|
13
13
|
//#endregion
|
|
14
14
|
//#region src/renderer/RendererFlare.ts
|
package/dist/renderer.mjs
CHANGED
|
@@ -7,7 +7,7 @@ const FLARE_BRIDGE_KEY = "__flare";
|
|
|
7
7
|
|
|
8
8
|
//#endregion
|
|
9
9
|
//#region src/env.ts
|
|
10
|
-
const CLIENT_VERSION = typeof process !== "undefined" && true ? "
|
|
10
|
+
const CLIENT_VERSION = typeof process !== "undefined" && true ? "2.5.1" : "?";
|
|
11
11
|
|
|
12
12
|
//#endregion
|
|
13
13
|
//#region src/renderer/RendererFlare.ts
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@flareapp/electron",
|
|
3
|
-
"version": "
|
|
4
|
-
"description": "
|
|
3
|
+
"version": "2.5.1",
|
|
4
|
+
"description": "Electron SDK for flareapp.io",
|
|
5
5
|
"homepage": "https://flareapp.io",
|
|
6
6
|
"bugs": {
|
|
7
7
|
"url": "https://github.com/spatie/flare-client-js/issues"
|
|
@@ -62,17 +62,21 @@
|
|
|
62
62
|
"release": "release-it"
|
|
63
63
|
},
|
|
64
64
|
"dependencies": {
|
|
65
|
-
"@flareapp/core": "2.
|
|
66
|
-
"@flareapp/js": "2.
|
|
65
|
+
"@flareapp/core": "2.5.1",
|
|
66
|
+
"@flareapp/js": "2.5.1"
|
|
67
67
|
},
|
|
68
68
|
"peerDependencies": {
|
|
69
69
|
"electron": ">=35"
|
|
70
70
|
},
|
|
71
71
|
"devDependencies": {
|
|
72
|
+
"@flareapp/react": "file:../react",
|
|
73
|
+
"@flareapp/vue": "file:../vue",
|
|
72
74
|
"electron": "^35.0.0",
|
|
75
|
+
"react": "^19.0.0",
|
|
73
76
|
"tsdown": "^0.20.3",
|
|
74
77
|
"typescript": "^5.7.0",
|
|
75
|
-
"vitest": "^4.0.18"
|
|
78
|
+
"vitest": "^4.0.18",
|
|
79
|
+
"vue": "^3.4.0"
|
|
76
80
|
},
|
|
77
81
|
"publishConfig": {
|
|
78
82
|
"access": "public"
|