Compare commits

..

1 Commits

Author SHA1 Message Date
Edwin Joassart
ec7e0b745e patch: send sourcemap to sentry at build 2023-01-12 17:46:00 +01:00
12 changed files with 729 additions and 771 deletions

View File

@@ -72,6 +72,29 @@ runs:
chmod +x "$(dirname "$(which node)")/resinci-deploy" && which resinci-deploy chmod +x "$(dirname "$(which node)")/resinci-deploy" && which resinci-deploy
fi fi
# Upload sourcemaps to sentry
- name: Generate Sentry DSN
id: sentry
shell: bash --noprofile --norc -eo pipefail -x {0}
run: |
set -ea
[[ '${{ inputs.VERBOSE }}' =~ on|On|Yes|yes|true|True ]] && set -x
branch="$(echo '${{ github.event.pull_request.head.ref }}' | sed 's/[^[:alnum:]]/-/g')"
stdout="$(resinci-deploy store sentry \
--branch="${branch}" \
--name="$(jq -r '.name' package.json)" \
--team="$(yq e '.sentry.team' repo.yml)" \
--org="$(yq e '.sentry.org' repo.yml)" \
--type="$(yq e '.sentry.type' repo.yml)")"
echo "dsn=$(echo "${stdout}" | tail -n 1)" >> $GITHUB_OUTPUT
env:
SENTRY_TOKEN: ${{ fromJSON(inputs.secrets).SENTRY_AUTH_TOKEN }}
# https://www.electron.build/code-signing.html # https://www.electron.build/code-signing.html
# https://github.com/Apple-Actions/import-codesign-certs # https://github.com/Apple-Actions/import-codesign-certs
- name: Import Apple code signing certificate - name: Import Apple code signing certificate
@@ -145,8 +168,8 @@ runs:
for target in ${TARGETS}; do for target in ${TARGETS}; do
electron-builder ${ELECTRON_BUILDER_OS} ${target} ${ARCHITECTURE_FLAGS} \ electron-builder ${ELECTRON_BUILDER_OS} ${target} ${ARCHITECTURE_FLAGS} \
--c.extraMetadata.analytics.sentry.token='https://739bbcfc0ba4481481138d3fc831136d@o95242.ingest.sentry.io/4504451487301632' \ --c.extraMetadata.analytics.sentry.token='${{ steps.sentry.outputs.dsn }}' \
--c.extraMetadata.analytics.amplitude.token='balena-etcher' \ --c.extraMetadata.analytics.mixpanel.token='balena-etcher' \
--c.extraMetadata.packageType="${target}" --c.extraMetadata.packageType="${target}"
find dist -type f -maxdepth 1 find dist -type f -maxdepth 1
@@ -180,6 +203,16 @@ runs:
-name "latest*.yml" \ -name "latest*.yml" \
-exec yq -i e .stagingPercentage=\"$percentage\" {} \; -exec yq -i e .stagingPercentage=\"$percentage\" {} \;
- name: Upload sourcemap to Sentry
shell: bash --noprofile --norc -eo pipefail -x {0}
run: |
VERSION=${{ steps.package_release.outputs.version }} npm run uploadSourcemap
env:
SENTRY_AUTH_TOKEN: ${{ fromJSON(inputs.secrets).SENTRY_AUTH_TOKEN }}
npm_config_SENTRY_ORG: balenaEtcher
npm_config_SENTRY_PROJECT: balenaetcher
npm_config_SENTRY_VERSION: ${{ steps.package_release.outputs.version }}
- name: Upload artifacts - name: Upload artifacts
uses: actions/upload-artifact@v3 uses: actions/upload-artifact@v3
with: with:

View File

@@ -1,57 +1,3 @@
- commits:
- subject: Anonymizes all paths before sending
hash: 86d43a536f7c9aa6b450a9f2f90341e07364208e
body: ""
footer:
Change-type: patch
change-type: patch
author: Otávio Jacobi
nested: []
- subject: "patch: Sentry fix path"
hash: 6c417e35a13873cd95d25f42a819de3750cdf65d
body: ""
footer: {}
author: Edwin Joassart
nested: []
- subject: Remove personal path on etcher
hash: 2b728d3c521b76177a2c019b4891627272f35aac
body: ""
footer:
Change-type: minor
change-type: minor
author: Otávio Jacobi
nested: []
- subject: Unifying sentry reports in a single project
hash: f3f7ecb852503d4d97dbe6a78bf920ca177bddd1
body: ""
footer:
Change-type: patch
change-type: patch
author: Edwin Joassart
nested: []
- subject: Removes corvus in favor of sentry and analytics client
hash: 41fca03c98d4a72bd8c3842d7e6b9d41f65336f9
body: ""
footer:
Change-type: patch
change-type: patch
Signed-off-by: Otavio Jacobi
signed-off-by: Otavio Jacobi
author: Otávio Jacobi
nested: []
- subject: Removes corvus in favor of sentry and analytics client
hash: 10caf8f1b6a174762192b13ce7bb4eaa71e90fcc
body: ""
footer:
Change-type: patch
change-type: patch
Signed-off-by: Otavio Jacobi
signed-off-by: Otavio Jacobi
author: Otávio Jacobi
nested: []
version: 1.14.0
title: ""
date: 2023-01-16T11:23:54.866Z
- commits: - commits:
- subject: Adding EtcherPro device serial number to the Settings modal - subject: Adding EtcherPro device serial number to the Settings modal
hash: d25eda9a7d6bf89284b630b2d55cbb0a7e3a9432 hash: d25eda9a7d6bf89284b630b2d55cbb0a7e3a9432

View File

@@ -3,16 +3,6 @@
All notable changes to this project will be documented in this file. All notable changes to this project will be documented in this file.
This project adheres to [Semantic Versioning](http://semver.org/). This project adheres to [Semantic Versioning](http://semver.org/).
# v1.14.0
## (2023-01-16)
* Anonymizes all paths before sending [Otávio Jacobi]
* patch: Sentry fix path [Edwin Joassart]
* Remove personal path on etcher [Otávio Jacobi]
* Unifying sentry reports in a single project [Edwin Joassart]
* Removes corvus in favor of sentry and analytics client [Otávio Jacobi]
* Removes corvus in favor of sentry and analytics client [Otávio Jacobi]
# v1.13.4 # v1.13.4
## (2023-01-12) ## (2023-01-12)

View File

@@ -31,7 +31,7 @@ Releasing
- [Post release note to forums](https://forums.balena.io/c/etcher) - [Post release note to forums](https://forums.balena.io/c/etcher)
- [Submit Windows binaries to Symantec for whitelisting](#submitting-binaries-to-symantec) - [Submit Windows binaries to Symantec for whitelisting](#submitting-binaries-to-symantec)
- [Update the website](https://github.com/balena-io/etcher-homepage) - [Update the website](https://github.com/balena-io/etcher-homepage)
- Wait 2-3 hours for analytics (Sentry, Amplitude) to trickle in and check for elevated error rates, or regressions - Wait 2-3 hours for analytics (Sentry, Mixpanel) to trickle in and check for elevated error rates, or regressions
- If regressions arise; pull the release, and release a patched version, else: - If regressions arise; pull the release, and release a patched version, else:
- [Upload deb & rpm packages to Bintray](#uploading-packages-to-bintray) - [Upload deb & rpm packages to Bintray](#uploading-packages-to-bintray)
- [Upload build artifacts to Amazon S3](#uploading-binaries-to-amazon-s3) - [Upload build artifacts to Amazon S3](#uploading-binaries-to-amazon-s3)
@@ -48,7 +48,7 @@ Make sure to set the analytics tokens when generating production release binarie
```bash ```bash
export ANALYTICS_SENTRY_TOKEN="xxxxxx" export ANALYTICS_SENTRY_TOKEN="xxxxxx"
export ANALYTICS_AMPLITUDE_TOKEN="xxxxxx" export ANALYTICS_MIXPANEL_TOKEN="xxxxxx"
``` ```
#### Linux #### Linux

View File

@@ -112,4 +112,4 @@ Analytics
- [ ] Disable analytics, open DevTools Network pane or a packet sniffer, and - [ ] Disable analytics, open DevTools Network pane or a packet sniffer, and
check that no request is sent check that no request is sent
- [ ] **Disable analytics, refresh application from DevTools (using Cmd-R or - [ ] **Disable analytics, refresh application from DevTools (using Cmd-R or
F5), and check that initial events are not sent to Amplitude** F5), and check that initial events are not sent to Mixpanel**

View File

@@ -296,8 +296,6 @@ driveScanner.start();
let popupExists = false; let popupExists = false;
analytics.initAnalytics();
window.addEventListener('beforeunload', async (event) => { window.addEventListener('beforeunload', async (event) => {
if (!flashState.isFlashing() || popupExists) { if (!flashState.isFlashing() || popupExists) {
analytics.logEvent('Close application', { analytics.logEvent('Close application', {

View File

@@ -183,12 +183,7 @@ export class SafeWebview extends React.PureComponent<
// only care about this event if it's a request for the main frame // only care about this event if it's a request for the main frame
if (event.resourceType === 'mainFrame') { if (event.resourceType === 'mainFrame') {
const HTTP_OK = 200; const HTTP_OK = 200;
const { webContents, ...webviewEvent } = event; analytics.logEvent('SafeWebview loaded', { event });
analytics.logEvent('SafeWebview loaded', {
...webviewEvent,
screen_height: webContents?.hostWebContents.browserWindowOptions.height,
screen_width: webContents?.hostWebContents.browserWindowOptions.width,
});
this.setState({ this.setState({
shouldShow: event.statusCode === HTTP_OK, shouldShow: event.statusCode === HTTP_OK,
}); });

View File

@@ -15,188 +15,84 @@
*/ */
import * as _ from 'lodash'; import * as _ from 'lodash';
import { Client, createClient, createNoopClient } from 'analytics-client'; import * as resinCorvus from 'resin-corvus/browser';
import * as SentryRenderer from '@sentry/electron/renderer';
import * as packageJSON from '../../../../package.json';
import { getConfig } from '../../../shared/utils';
import * as settings from '../models/settings'; import * as settings from '../models/settings';
import { store } from '../models/store'; import { store } from '../models/store';
import * as packageJSON from '../../../../package.json';
type AnalyticsPayload = _.Dictionary<any>; const DEFAULT_PROBABILITY = 0.1;
const clearUserPath = (filename: string): string => { async function installCorvus(): Promise<void> {
const generatedFile = filename.split('generated').reverse()[0]; const sentryToken =
return generatedFile !== filename ? `generated${generatedFile}` : filename; (await settings.get('analyticsSentryToken')) ||
}; _.get(packageJSON, ['analytics', 'sentry', 'token']);
const mixpanelToken =
export const anonymizeSentryData = ( (await settings.get('analyticsMixpanelToken')) ||
event: SentryRenderer.Event, _.get(packageJSON, ['analytics', 'mixpanel', 'token']);
): SentryRenderer.Event => { resinCorvus.install({
event.exception?.values?.forEach((exception) => { services: {
exception.stacktrace?.frames?.forEach((frame) => { sentry: sentryToken,
if (frame.filename) { mixpanel: mixpanelToken,
frame.filename = clearUserPath(frame.filename); },
} options: {
}); release: packageJSON.version,
shouldReport: () => {
return settings.getSync('errorReporting');
},
mixpanelDeferred: true,
},
}); });
}
event.breadcrumbs?.forEach((breadcrumb) => { let mixpanelSample = DEFAULT_PROBABILITY;
if (breadcrumb.data?.url) {
breadcrumb.data.url = clearUserPath(breadcrumb.data.url);
}
});
if (event.request?.url) {
event.request.url = clearUserPath(event.request.url);
}
return event;
};
const extractPathRegex = /(.*)(^|\s)(file\:\/\/)?(\w\:)?([\\\/].+)/;
const etcherSegmentMarkers = ['app.asar', 'Resources'];
export const anonymizePath = (input: string) => {
// First, extract a part of the value that matches a path pattern.
const match = extractPathRegex.exec(input);
if (match === null) {
return input;
}
const mainPart = match[5];
const space = match[2];
const beginning = match[1];
const uriPrefix = match[3] || '';
// We have to deal with both Windows and POSIX here.
// The path starts with its separator (we work with absolute paths).
const sep = mainPart[0];
const segments = mainPart.split(sep);
// Moving from the end, find the first marker and cut the path from there.
const startCutIndex = _.findLastIndex(segments, (segment) =>
etcherSegmentMarkers.includes(segment),
);
return (
beginning +
space +
uriPrefix +
'[PERSONAL PATH]' +
sep +
segments.splice(startCutIndex).join(sep)
);
};
const safeAnonymizePath = (input: string) => {
try {
return anonymizePath(input);
} catch (e) {
return '[ANONYMIZE PATH FAILED]';
}
};
const sensitiveEtcherProperties = [
'error.description',
'error.message',
'error.stack',
'image',
'image.path',
'path',
];
export const anonymizeAnalyticsPayload = (
data: AnalyticsPayload,
): AnalyticsPayload => {
for (const prop of sensitiveEtcherProperties) {
const value = data[prop];
if (value != null) {
data[prop] = safeAnonymizePath(value.toString());
}
}
return data;
};
let analyticsClient: Client;
/** /**
* @summary Init analytics configurations * @summary Init analytics configurations
*/ */
export const initAnalytics = _.once(() => { async function initConfig() {
const dsn = await installCorvus();
settings.getSync('analyticsSentryToken') || let validatedConfig = null;
_.get(packageJSON, ['analytics', 'sentry', 'token']); try {
SentryRenderer.init({ dsn, beforeSend: anonymizeSentryData }); const configUrl = await settings.get('configUrl');
const config = await getConfig(configUrl);
const projectName = const mixpanel = _.get(config, ['analytics', 'mixpanel'], {});
settings.getSync('analyticsAmplitudeToken') || mixpanelSample = mixpanel.probability || DEFAULT_PROBABILITY;
_.get(packageJSON, ['analytics', 'amplitude', 'token']); if (isClientEligible(mixpanelSample)) {
validatedConfig = validateMixpanelConfig(mixpanel);
const clientConfig = {
projectName,
endpoint: 'data.balena-cloud.com',
componentName: 'etcher',
componentVersion: packageJSON.version,
};
analyticsClient = projectName
? createClient(clientConfig)
: createNoopClient();
});
const getCircularReplacer = () => {
const seen = new WeakSet();
return (key: any, value: any) => {
if (typeof value === 'object' && value !== null) {
if (seen.has(value)) {
return;
}
seen.add(value);
}
return value;
};
};
function flattenObject(obj: any) {
const toReturn: AnalyticsPayload = {};
for (const i in obj) {
if (!obj.hasOwnProperty(i)) {
continue;
}
if (Array.isArray(obj[i])) {
toReturn[i] = obj[i];
continue;
}
if (typeof obj[i] === 'object' && obj[i] !== null) {
const flatObject = flattenObject(obj[i]);
for (const x in flatObject) {
if (!flatObject.hasOwnProperty(x)) {
continue;
}
toReturn[i.toLowerCase() + '.' + x.toLowerCase()] = flatObject[x];
}
} else {
toReturn[i] = obj[i];
} }
} catch (err) {
resinCorvus.logException(err);
} }
return toReturn; resinCorvus.setConfigs({
} mixpanel: validatedConfig,
function formatEvent(data: any): AnalyticsPayload {
const event = JSON.parse(JSON.stringify(data, getCircularReplacer()));
return anonymizeAnalyticsPayload(flattenObject(event));
}
function reportAnalytics(message: string, data: AnalyticsPayload = {}) {
const { applicationSessionUuid, flashingWorkflowUuid } = store
.getState()
.toJS();
const event = formatEvent({
...data,
applicationSessionUuid,
flashingWorkflowUuid,
}); });
analyticsClient.track(message, event); }
initConfig();
/**
* @summary Check that the client is eligible for analytics
*/
function isClientEligible(probability: number) {
return Math.random() < probability;
}
/**
* @summary Check that config has at least HTTP_PROTOCOL and api_host
*/
function validateMixpanelConfig(config: {
api_host?: string;
HTTP_PROTOCOL?: string;
}) {
const mixpanelConfig = {
api_host: 'https://api.mixpanel.com',
};
if (config.HTTP_PROTOCOL !== undefined && config.api_host !== undefined) {
mixpanelConfig.api_host = `${config.HTTP_PROTOCOL}://${config.api_host}`;
}
return mixpanelConfig;
} }
/** /**
@@ -205,12 +101,16 @@ function reportAnalytics(message: string, data: AnalyticsPayload = {}) {
* @description * @description
* This function sends the debug message to product analytics services. * This function sends the debug message to product analytics services.
*/ */
export async function logEvent(message: string, data: AnalyticsPayload = {}) { export function logEvent(message: string, data: _.Dictionary<any> = {}) {
const shouldReportAnalytics = await settings.get('errorReporting'); const { applicationSessionUuid, flashingWorkflowUuid } = store
if (shouldReportAnalytics) { .getState()
initAnalytics(); .toJS();
reportAnalytics(message, data); resinCorvus.logEvent(message, {
} ...data,
sample: mixpanelSample,
applicationSessionUuid,
flashingWorkflowUuid,
});
} }
/** /**
@@ -219,11 +119,4 @@ export async function logEvent(message: string, data: AnalyticsPayload = {}) {
* @description * @description
* This function logs an exception to error reporting services. * This function logs an exception to error reporting services.
*/ */
export function logException(error: any) { export const logException = resinCorvus.logException;
const shouldReportErrors = settings.getSync('errorReporting');
if (shouldReportErrors) {
initAnalytics();
console.error(error);
SentryRenderer.captureException(error);
}
}

View File

@@ -20,7 +20,6 @@ import { promises as fs } from 'fs';
import { platform } from 'os'; import { platform } from 'os';
import * as path from 'path'; import * as path from 'path';
import * as semver from 'semver'; import * as semver from 'semver';
import * as _ from 'lodash';
import './app/i18n'; import './app/i18n';
@@ -28,11 +27,9 @@ import { packageType, version } from '../../package.json';
import * as EXIT_CODES from '../shared/exit-codes'; import * as EXIT_CODES from '../shared/exit-codes';
import { delay, getConfig } from '../shared/utils'; import { delay, getConfig } from '../shared/utils';
import * as settings from './app/models/settings'; import * as settings from './app/models/settings';
import { logException } from './app/modules/analytics';
import { buildWindowMenu } from './menu'; import { buildWindowMenu } from './menu';
import * as i18n from 'i18next'; import * as i18n from 'i18next';
import * as SentryMain from '@sentry/electron/main';
import * as packageJSON from '../../package.json';
import { anonymizeSentryData } from './app/modules/analytics';
const customProtocol = 'etcher'; const customProtocol = 'etcher';
const scheme = `${customProtocol}://`; const scheme = `${customProtocol}://`;
@@ -56,21 +53,13 @@ async function checkForUpdates(interval: number) {
packageUpdated = true; packageUpdated = true;
} }
} catch (err) { } catch (err) {
logMainProcessException(err); logException(err);
} }
} }
await delay(interval); await delay(interval);
} }
} }
function logMainProcessException(error: any) {
const shouldReportErrors = settings.getSync('errorReporting');
if (shouldReportErrors) {
console.error(error);
SentryMain.captureException(error);
}
}
async function isFile(filePath: string): Promise<boolean> { async function isFile(filePath: string): Promise<boolean> {
try { try {
const stat = await fs.stat(filePath); const stat = await fs.stat(filePath);
@@ -105,14 +94,6 @@ async function getCommandLineURL(argv: string[]): Promise<string | undefined> {
} }
} }
const initSentryMain = _.once(() => {
const dsn =
settings.getSync('analyticsSentryToken') ||
_.get(packageJSON, ['analytics', 'sentry', 'token']);
SentryMain.init({ dsn, beforeSend: anonymizeSentryData });
});
const sourceSelectorReady = new Promise((resolve) => { const sourceSelectorReady = new Promise((resolve) => {
electron.ipcMain.on('source-selector-ready', resolve); electron.ipcMain.on('source-selector-ready', resolve);
}); });
@@ -209,9 +190,8 @@ async function createMainWindow() {
const page = mainWindow.webContents; const page = mainWindow.webContents;
page.once('did-frame-finish-load', async () => { page.once('did-frame-finish-load', async () => {
console.log('packageUpdatable', packageUpdatable);
autoUpdater.on('error', (err) => { autoUpdater.on('error', (err) => {
logMainProcessException(err); logException(err);
}); });
if (packageUpdatable) { if (packageUpdatable) {
try { try {
@@ -228,7 +208,7 @@ async function createMainWindow() {
onlineConfig?.autoUpdates?.checkForUpdatesTimer ?? 300000; onlineConfig?.autoUpdates?.checkForUpdatesTimer ?? 300000;
checkForUpdates(checkForUpdatesTimer); checkForUpdates(checkForUpdatesTimer);
} catch (err) { } catch (err) {
logMainProcessException(err); logException(err);
} }
} }
}); });
@@ -253,7 +233,6 @@ async function main(): Promise<void> {
if (!electron.app.requestSingleInstanceLock()) { if (!electron.app.requestSingleInstanceLock()) {
electron.app.quit(); electron.app.quit();
} else { } else {
initSentryMain();
await electron.app.whenReady(); await electron.app.whenReady();
const window = await createMainWindow(); const window = await createMainWindow();
electron.app.on('second-instance', async (_event, argv) => { electron.app.on('second-instance', async (_event, argv) => {
@@ -277,6 +256,7 @@ async function main(): Promise<void> {
}); });
} }
} }
main(); main();
console.time('ready-to-show'); console.time('ready-to-show');

1083
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@@ -2,7 +2,7 @@
"name": "balena-etcher", "name": "balena-etcher",
"private": true, "private": true,
"displayName": "balenaEtcher", "displayName": "balenaEtcher",
"version": "1.14.0", "version": "1.13.4",
"packageType": "local", "packageType": "local",
"main": "generated/etcher.js", "main": "generated/etcher.js",
"description": "Flash OS images to SD cards and USB drives, safely and easily.", "description": "Flash OS images to SD cards and USB drives, safely and easily.",
@@ -31,6 +31,7 @@
"test-spectron": "mocha --recursive --reporter spec --require ts-node/register/transpile-only --require-main tests/gui/allow-renderer-process-reuse.ts tests/spectron/runner.spec.ts", "test-spectron": "mocha --recursive --reporter spec --require ts-node/register/transpile-only --require-main tests/gui/allow-renderer-process-reuse.ts tests/spectron/runner.spec.ts",
"test-windows": "npm run lint && npm run test-gui && npm run test-shared && npm run test-spectron && npm run sanity-checks", "test-windows": "npm run lint && npm run test-gui && npm run test-shared && npm run test-spectron && npm run sanity-checks",
"test": "echo npm run test-{linux,windows,macos}", "test": "echo npm run test-{linux,windows,macos}",
"uploadSourcemap": "sentry-cli releases files $npm_config_SENTRY_VERSION upload-sourcemaps ./generated/*.js.map --org $npm_config_SENTRY_ORG --project $npm_config_SENTRY_PROJECT",
"watch": "webpack serve --no-optimization-minimize --config ./webpack.dev.config.ts", "watch": "webpack serve --no-optimization-minimize --config ./webpack.dev.config.ts",
"webpack": "webpack" "webpack": "webpack"
}, },
@@ -53,7 +54,7 @@
"@balena/lint": "5.4.2", "@balena/lint": "5.4.2",
"@balena/sudo-prompt": "9.2.1-workaround-windows-amperstand-in-username-0849e215b947987a643fe5763902aea201255534", "@balena/sudo-prompt": "9.2.1-workaround-windows-amperstand-in-username-0849e215b947987a643fe5763902aea201255534",
"@fortawesome/fontawesome-free": "5.15.4", "@fortawesome/fontawesome-free": "5.15.4",
"@sentry/electron": "^4.1.2", "@sentry/cli": "^2.11.0",
"@svgr/webpack": "5.5.0", "@svgr/webpack": "5.5.0",
"@types/chai": "4.3.4", "@types/chai": "4.3.4",
"@types/copy-webpack-plugin": "6.4.3", "@types/copy-webpack-plugin": "6.4.3",
@@ -69,7 +70,6 @@
"@types/terser-webpack-plugin": "5.0.4", "@types/terser-webpack-plugin": "5.0.4",
"@types/tmp": "0.2.3", "@types/tmp": "0.2.3",
"@types/webpack-node-externals": "2.5.3", "@types/webpack-node-externals": "2.5.3",
"analytics-client": "^2.0.1",
"aws4-axios": "2.4.9", "aws4-axios": "2.4.9",
"chai": "4.3.7", "chai": "4.3.7",
"copy-webpack-plugin": "7.0.0", "copy-webpack-plugin": "7.0.0",
@@ -104,6 +104,7 @@
"react-i18next": "11.18.6", "react-i18next": "11.18.6",
"redux": "4.2.0", "redux": "4.2.0",
"rendition": "19.3.2", "rendition": "19.3.2",
"resin-corvus": "2.0.5",
"semver": "7.3.8", "semver": "7.3.8",
"simple-progress-webpack-plugin": "1.1.2", "simple-progress-webpack-plugin": "1.1.2",
"sinon": "9.2.4", "sinon": "9.2.4",
@@ -127,6 +128,6 @@
"node": ">=14 < 16" "node": ">=14 < 16"
}, },
"versionist": { "versionist": {
"publishedAt": "2023-01-16T11:23:55.599Z" "publishedAt": "2023-01-12T15:10:50.986Z"
} }
} }

View File

@@ -29,7 +29,7 @@ import * as PnpWebpackPlugin from 'pnp-webpack-plugin';
import * as tsconfigRaw from './tsconfig.webpack.json'; import * as tsconfigRaw from './tsconfig.webpack.json';
/** /**
* Don't webpack package.json as sentry tokens * Don't webpack package.json as mixpanel & sentry tokens
* will be inserted in it after webpacking * will be inserted in it after webpacking
*/ */
function externalPackageJson(packageJsonPath: string) { function externalPackageJson(packageJsonPath: string) {
@@ -455,6 +455,7 @@ const guiConfig = {
const mainConfig = { const mainConfig = {
...commonConfig, ...commonConfig,
target: 'electron-main', target: 'electron-main',
devtool: 'source-map',
node: { node: {
__dirname: false, __dirname: false,
__filename: true, __filename: true,