diff --git a/packages/frontend/apps/android/src/index.tsx b/packages/frontend/apps/android/src/index.tsx
index 13db0e77b..327f1ce7d 100644
--- a/packages/frontend/apps/android/src/index.tsx
+++ b/packages/frontend/apps/android/src/index.tsx
@@ -1,58 +1,24 @@
import './setup';
-import {
- init,
- reactRouterV6BrowserTracingIntegration,
- setTags,
-} from '@sentry/react';
-import { StrictMode, useEffect } from 'react';
+import { Telemetry } from '@affine/core/components/telemetry';
+import { StrictMode } from 'react';
import { createRoot } from 'react-dom/client';
-import {
- createRoutesFromChildren,
- matchRoutes,
- useLocation,
- useNavigationType,
-} from 'react-router-dom';
import { App } from './app';
-function main() {
- if (BUILD_CONFIG.debug || window.SENTRY_RELEASE) {
- // https://docs.sentry.io/platforms/javascript/guides/react/#configure
- init({
- dsn: process.env.SENTRY_DSN,
- environment: process.env.BUILD_TYPE ?? 'development',
- integrations: [
- reactRouterV6BrowserTracingIntegration({
- useEffect,
- useLocation,
- useNavigationType,
- createRoutesFromChildren,
- matchRoutes,
- }),
- ],
- });
- setTags({
- distribution: BUILD_CONFIG.distribution,
- appVersion: BUILD_CONFIG.appVersion,
- editorVersion: BUILD_CONFIG.editorVersion,
- });
- }
- mountApp();
-}
-
function mountApp() {
- // oxlint-disable-next-line @typescript-eslint/no-non-null-assertion
+ // oxlint-disable-next-line no-non-null-assertion
const root = document.getElementById('app')!;
createRoot(root).render(
+
);
}
try {
- main();
+ mountApp();
} catch (err) {
console.error('Failed to bootstrap app', err);
}
diff --git a/packages/frontend/apps/electron-renderer/src/index.tsx b/packages/frontend/apps/electron-renderer/src/index.tsx
index 898bfe3e3..5d7af7d26 100644
--- a/packages/frontend/apps/electron-renderer/src/index.tsx
+++ b/packages/frontend/apps/electron-renderer/src/index.tsx
@@ -1,46 +1,13 @@
import './setup';
import { appConfigProxy } from '@affine/core/components/hooks/use-app-config-storage';
-import {
- init,
- reactRouterV6BrowserTracingIntegration,
- setTags,
-} from '@sentry/react';
-import { StrictMode, useEffect } from 'react';
+import { Telemetry } from '@affine/core/components/telemetry';
+import { StrictMode } from 'react';
import { createRoot } from 'react-dom/client';
-import {
- createRoutesFromChildren,
- matchRoutes,
- useLocation,
- useNavigationType,
-} from 'react-router-dom';
import { App } from './app';
function main() {
- // skip bootstrap setup for desktop onboarding
- if (BUILD_CONFIG.debug || window.SENTRY_RELEASE) {
- // https://docs.sentry.io/platforms/javascript/guides/react/#configure
- init({
- dsn: process.env.SENTRY_DSN,
- environment: process.env.BUILD_TYPE ?? 'development',
- integrations: [
- reactRouterV6BrowserTracingIntegration({
- useEffect,
- useLocation,
- useNavigationType,
- createRoutesFromChildren,
- matchRoutes,
- }),
- ],
- });
- setTags({
- distribution: BUILD_CONFIG.distribution,
- appVersion: BUILD_CONFIG.appVersion,
- editorVersion: BUILD_CONFIG.editorVersion,
- });
- }
-
// load persistent config for electron
// TODO(@Peng): should be sync, but it's not necessary for now
appConfigProxy
@@ -55,6 +22,7 @@ function mountApp() {
const root = document.getElementById('app')!;
createRoot(root).render(
+
);
diff --git a/packages/frontend/apps/ios/src/index.tsx b/packages/frontend/apps/ios/src/index.tsx
index 10bceb97a..3ee551fad 100644
--- a/packages/frontend/apps/ios/src/index.tsx
+++ b/packages/frontend/apps/ios/src/index.tsx
@@ -2,20 +2,10 @@ import './setup';
import '@affine/component/theme';
import '@affine/core/mobile/styles/mobile.css';
+import { Telemetry } from '@affine/core/components/telemetry';
import { bindNativeDBApis } from '@affine/nbstore/sqlite';
-import {
- init,
- reactRouterV6BrowserTracingIntegration,
- setTags,
-} from '@sentry/react';
-import { StrictMode, useEffect } from 'react';
+import { StrictMode } from 'react';
import { createRoot } from 'react-dom/client';
-import {
- createRoutesFromChildren,
- matchRoutes,
- useLocation,
- useNavigationType,
-} from 'react-router-dom';
import { App } from './app';
import { NbStoreNativeDBApis } from './plugins/nbstore';
@@ -25,43 +15,19 @@ bindNativeDBApis(NbStoreNativeDBApis);
// TODO(@L-Sun) Uncomment this when the `show` method implement by `@capacitor/keyboard` in ios
// import './virtual-keyboard';
-function main() {
- if (BUILD_CONFIG.debug || window.SENTRY_RELEASE) {
- // https://docs.sentry.io/platforms/javascript/guides/react/#configure
- init({
- dsn: process.env.SENTRY_DSN,
- environment: process.env.BUILD_TYPE ?? 'development',
- integrations: [
- reactRouterV6BrowserTracingIntegration({
- useEffect,
- useLocation,
- useNavigationType,
- createRoutesFromChildren,
- matchRoutes,
- }),
- ],
- });
- setTags({
- distribution: BUILD_CONFIG.distribution,
- appVersion: BUILD_CONFIG.appVersion,
- editorVersion: BUILD_CONFIG.editorVersion,
- });
- }
- mountApp();
-}
-
function mountApp() {
// oxlint-disable-next-line @typescript-eslint/no-non-null-assertion
const root = document.getElementById('app')!;
createRoot(root).render(
+
);
}
try {
- main();
+ mountApp();
} catch (err) {
console.error('Failed to bootstrap app', err);
}
diff --git a/packages/frontend/apps/mobile/src/index.tsx b/packages/frontend/apps/mobile/src/index.tsx
index ede248010..327f1ce7d 100644
--- a/packages/frontend/apps/mobile/src/index.tsx
+++ b/packages/frontend/apps/mobile/src/index.tsx
@@ -1,58 +1,24 @@
import './setup';
-import {
- init,
- reactRouterV6BrowserTracingIntegration,
- setTags,
-} from '@sentry/react';
-import { StrictMode, useEffect } from 'react';
+import { Telemetry } from '@affine/core/components/telemetry';
+import { StrictMode } from 'react';
import { createRoot } from 'react-dom/client';
-import {
- createRoutesFromChildren,
- matchRoutes,
- useLocation,
- useNavigationType,
-} from 'react-router-dom';
import { App } from './app';
-function main() {
- if (BUILD_CONFIG.debug || window.SENTRY_RELEASE) {
- // https://docs.sentry.io/platforms/javascript/guides/react/#configure
- init({
- dsn: process.env.SENTRY_DSN,
- environment: process.env.BUILD_TYPE ?? 'development',
- integrations: [
- reactRouterV6BrowserTracingIntegration({
- useEffect,
- useLocation,
- useNavigationType,
- createRoutesFromChildren,
- matchRoutes,
- }),
- ],
- });
- setTags({
- distribution: BUILD_CONFIG.distribution,
- appVersion: BUILD_CONFIG.appVersion,
- editorVersion: BUILD_CONFIG.editorVersion,
- });
- }
- mountApp();
-}
-
function mountApp() {
// oxlint-disable-next-line no-non-null-assertion
const root = document.getElementById('app')!;
createRoot(root).render(
+
);
}
try {
- main();
+ mountApp();
} catch (err) {
console.error('Failed to bootstrap app', err);
}
diff --git a/packages/frontend/apps/web/package.json b/packages/frontend/apps/web/package.json
index db49f47a5..fd407816c 100644
--- a/packages/frontend/apps/web/package.json
+++ b/packages/frontend/apps/web/package.json
@@ -13,6 +13,7 @@
"@affine/core": "workspace:*",
"@affine/i18n": "workspace:*",
"@affine/nbstore": "workspace:*",
+ "@affine/track": "workspace:*",
"@emotion/react": "^11.14.0",
"@sentry/react": "^9.2.0",
"@toeverything/infra": "workspace:*",
diff --git a/packages/frontend/apps/web/src/index.tsx b/packages/frontend/apps/web/src/index.tsx
index 26e98270e..786ce2017 100644
--- a/packages/frontend/apps/web/src/index.tsx
+++ b/packages/frontend/apps/web/src/index.tsx
@@ -1,60 +1,24 @@
import './setup';
-import {
- init,
- reactRouterV6BrowserTracingIntegration,
- setTags,
-} from '@sentry/react';
-import { StrictMode, useEffect } from 'react';
+import { Telemetry } from '@affine/core/components/telemetry';
+import { StrictMode } from 'react';
import { createRoot } from 'react-dom/client';
-import {
- createRoutesFromChildren,
- matchRoutes,
- useLocation,
- useNavigationType,
-} from 'react-router-dom';
import { App } from './app';
-function main() {
- // skip bootstrap setup for desktop onboarding
- if (BUILD_CONFIG.debug || window.SENTRY_RELEASE) {
- // https://docs.sentry.io/platforms/javascript/guides/react/#configure
- init({
- dsn: process.env.SENTRY_DSN,
- environment: process.env.BUILD_TYPE ?? 'development',
- integrations: [
- reactRouterV6BrowserTracingIntegration({
- useEffect,
- useLocation,
- useNavigationType,
- createRoutesFromChildren,
- matchRoutes,
- }),
- ],
- });
- setTags({
- distribution: BUILD_CONFIG.distribution,
- appVersion: BUILD_CONFIG.appVersion,
- editorVersion: BUILD_CONFIG.editorVersion,
- });
- }
-
- mountApp();
-}
-
function mountApp() {
// oxlint-disable-next-line @typescript-eslint/no-non-null-assertion
const root = document.getElementById('app')!;
createRoot(root).render(
+
);
}
try {
- main();
+ mountApp();
} catch (err) {
console.error('Failed to bootstrap app', err);
}
diff --git a/packages/frontend/core/src/bootstrap/browser.ts b/packages/frontend/core/src/bootstrap/browser.ts
index 35073fbc8..31efd9dda 100644
--- a/packages/frontend/core/src/bootstrap/browser.ts
+++ b/packages/frontend/core/src/bootstrap/browser.ts
@@ -2,3 +2,4 @@
import './env';
import './public-path';
import './polyfill/browser';
+import './telemetry';
diff --git a/packages/frontend/core/src/bootstrap/electron.ts b/packages/frontend/core/src/bootstrap/electron.ts
index f0391ff46..869a555ab 100644
--- a/packages/frontend/core/src/bootstrap/electron.ts
+++ b/packages/frontend/core/src/bootstrap/electron.ts
@@ -2,3 +2,4 @@
import './env';
import './public-path';
import './polyfill/electron';
+import './telemetry';
diff --git a/packages/frontend/core/src/bootstrap/telemetry.ts b/packages/frontend/core/src/bootstrap/telemetry.ts
new file mode 100644
index 000000000..5257d4022
--- /dev/null
+++ b/packages/frontend/core/src/bootstrap/telemetry.ts
@@ -0,0 +1,4 @@
+import { mixpanel, sentry } from '@affine/track';
+
+mixpanel.init();
+sentry.init();
diff --git a/packages/frontend/core/src/desktop/pages/root/telemetry/index.tsx b/packages/frontend/core/src/components/telemetry/index.tsx
similarity index 76%
rename from packages/frontend/core/src/desktop/pages/root/telemetry/index.tsx
rename to packages/frontend/core/src/components/telemetry/index.tsx
index 838326151..c930e9461 100644
--- a/packages/frontend/core/src/desktop/pages/root/telemetry/index.tsx
+++ b/packages/frontend/core/src/components/telemetry/index.tsx
@@ -1,4 +1,4 @@
-import { enableAutoTrack, mixpanel } from '@affine/track';
+import { enableAutoTrack, mixpanel, sentry } from '@affine/track';
import { appSettingAtom } from '@toeverything/infra';
import { useAtomValue } from 'jotai/react';
import { useLayoutEffect } from 'react';
@@ -7,9 +7,12 @@ export function Telemetry() {
const settings = useAtomValue(appSettingAtom);
useLayoutEffect(() => {
if (settings.enableTelemetry === false) {
+ sentry.disable();
mixpanel.opt_out_tracking();
return;
} else {
+ sentry.enable();
+ mixpanel.opt_in_tracking();
return enableAutoTrack(document.body, mixpanel.track);
}
}, [settings.enableTelemetry]);
diff --git a/packages/frontend/core/src/desktop/dialogs/setting/general-setting/about/index.tsx b/packages/frontend/core/src/desktop/dialogs/setting/general-setting/about/index.tsx
index 30e5ba537..11262806d 100644
--- a/packages/frontend/core/src/desktop/dialogs/setting/general-setting/about/index.tsx
+++ b/packages/frontend/core/src/desktop/dialogs/setting/general-setting/about/index.tsx
@@ -8,7 +8,6 @@ import { useAppUpdater } from '@affine/core/components/hooks/use-app-updater';
import { UrlService } from '@affine/core/modules/url';
import { appIconMap, appNames } from '@affine/core/utils/channel';
import { useI18n } from '@affine/i18n';
-import { mixpanel } from '@affine/track';
import { ArrowRightSmallIcon, OpenInNewIcon } from '@blocksuite/icons/rc';
import { useServices } from '@toeverything/infra';
import { useCallback } from 'react';
@@ -47,11 +46,6 @@ export const AboutAffine = () => {
const onSwitchTelemetry = useCallback(
(checked: boolean) => {
- if (!checked) {
- mixpanel.opt_out_tracking();
- } else {
- mixpanel.opt_in_tracking();
- }
updateSettings('enableTelemetry', checked);
},
[updateSettings]
diff --git a/packages/frontend/track/package.json b/packages/frontend/track/package.json
index 3314b861f..db0661834 100644
--- a/packages/frontend/track/package.json
+++ b/packages/frontend/track/package.json
@@ -9,10 +9,13 @@
"sideEffects": "false",
"dependencies": {
"@affine/debug": "workspace:*",
- "mixpanel-browser": "^2.56.0"
+ "@sentry/react": "^9.2.0",
+ "mixpanel-browser": "^2.56.0",
+ "react-router-dom": "6.28.0"
},
"devDependencies": {
"@types/mixpanel-browser": "^2.50.2",
+ "@types/react": "^19.0.1",
"vitest": "^3.0.0"
}
}
diff --git a/packages/frontend/track/src/index.ts b/packages/frontend/track/src/index.ts
index 02ffebded..036e48361 100644
--- a/packages/frontend/track/src/index.ts
+++ b/packages/frontend/track/src/index.ts
@@ -1,9 +1,10 @@
import { enableAutoTrack, makeTracker } from './auto';
import { mixpanel } from './mixpanel';
+import { sentry } from './sentry';
export const track = makeTracker((event, props) => {
mixpanel.track(event, props);
});
-export { enableAutoTrack, mixpanel };
+export { enableAutoTrack, mixpanel, sentry };
export default track;
diff --git a/packages/frontend/track/src/mixpanel.ts b/packages/frontend/track/src/mixpanel.ts
index 613b0f50d..5c8f6d65c 100644
--- a/packages/frontend/track/src/mixpanel.ts
+++ b/packages/frontend/track/src/mixpanel.ts
@@ -94,7 +94,6 @@ function createMixpanel() {
}
export const mixpanel = createMixpanel();
-mixpanel.init();
function createProxyHandler() {
const handler = {
diff --git a/packages/frontend/track/src/sentry.ts b/packages/frontend/track/src/sentry.ts
new file mode 100644
index 000000000..94358bb8b
--- /dev/null
+++ b/packages/frontend/track/src/sentry.ts
@@ -0,0 +1,50 @@
+import * as Sentry from '@sentry/react';
+import { useEffect } from 'react';
+import {
+ createRoutesFromChildren,
+ matchRoutes,
+ useLocation,
+ useNavigationType,
+} from 'react-router-dom';
+
+function createSentry() {
+ let enabled = true;
+ const wrapped = {
+ init() {
+ // https://docs.sentry.io/platforms/javascript/guides/react/#configure
+ Sentry.init({
+ enabled: enabled,
+ dsn: process.env.SENTRY_DSN,
+ debug: BUILD_CONFIG.debug ?? false,
+ environment: process.env.BUILD_TYPE ?? 'development',
+ integrations: [
+ Sentry.reactRouterV6BrowserTracingIntegration({
+ useEffect,
+ useLocation,
+ useNavigationType,
+ createRoutesFromChildren,
+ matchRoutes,
+ }),
+ ],
+ beforeSend(event) {
+ return enabled ? event : null;
+ },
+ });
+ Sentry.setTags({
+ distribution: BUILD_CONFIG.distribution,
+ appVersion: BUILD_CONFIG.appVersion,
+ editorVersion: BUILD_CONFIG.editorVersion,
+ });
+ },
+ enable() {
+ enabled = true;
+ },
+ disable() {
+ enabled = false;
+ },
+ };
+
+ return wrapped;
+}
+
+export const sentry = createSentry();
diff --git a/yarn.lock b/yarn.lock
index cfa6a3d94..f6c096691 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -935,8 +935,11 @@ __metadata:
resolution: "@affine/track@workspace:packages/frontend/track"
dependencies:
"@affine/debug": "workspace:*"
+ "@sentry/react": "npm:^9.2.0"
"@types/mixpanel-browser": "npm:^2.50.2"
+ "@types/react": "npm:^19.0.1"
mixpanel-browser: "npm:^2.56.0"
+ react-router-dom: "npm:6.28.0"
vitest: "npm:^3.0.0"
languageName: unknown
linkType: soft
@@ -949,6 +952,7 @@ __metadata:
"@affine/core": "workspace:*"
"@affine/i18n": "workspace:*"
"@affine/nbstore": "workspace:*"
+ "@affine/track": "workspace:*"
"@emotion/react": "npm:^11.14.0"
"@sentry/react": "npm:^9.2.0"
"@toeverything/infra": "workspace:*"
@@ -11224,6 +11228,13 @@ __metadata:
languageName: node
linkType: hard
+"@remix-run/router@npm:1.21.0":
+ version: 1.21.0
+ resolution: "@remix-run/router@npm:1.21.0"
+ checksum: 10/cf0fb69d19c1b79095ff67c59cea89086f3982a9a54c8a993818a60fc76e0ebab5a8db647c1a96a662729fad8e806ddd0a96622adf473f5a9f0b99998b2dbad4
+ languageName: node
+ linkType: hard
+
"@remix-run/router@npm:1.23.0":
version: 1.23.0
resolution: "@remix-run/router@npm:1.23.0"
@@ -28807,6 +28818,19 @@ __metadata:
languageName: node
linkType: hard
+"react-router-dom@npm:6.28.0":
+ version: 6.28.0
+ resolution: "react-router-dom@npm:6.28.0"
+ dependencies:
+ "@remix-run/router": "npm:1.21.0"
+ react-router: "npm:6.28.0"
+ peerDependencies:
+ react: ">=16.8"
+ react-dom: ">=16.8"
+ checksum: 10/e637825132ea96c3514ef7b8322f9bf0b752a942d6b4ffc4c20e389b5911726adf3dba8208ed4b97bf5b9c3bd465d9d1a1db1a58a610a8d528f18d890e0b143f
+ languageName: node
+ linkType: hard
+
"react-router-dom@npm:^6.28.0":
version: 6.30.0
resolution: "react-router-dom@npm:6.30.0"
@@ -28820,6 +28844,17 @@ __metadata:
languageName: node
linkType: hard
+"react-router@npm:6.28.0":
+ version: 6.28.0
+ resolution: "react-router@npm:6.28.0"
+ dependencies:
+ "@remix-run/router": "npm:1.21.0"
+ peerDependencies:
+ react: ">=16.8"
+ checksum: 10/f021a644513144884a567d9c2dcc432e8e3233f931378c219c5a3b5b842340f0faca86225a708bafca1e9010965afe1a7dada28aef5b7b6138c885c0552d9a7d
+ languageName: node
+ linkType: hard
+
"react-router@npm:6.30.0":
version: 6.30.0
resolution: "react-router@npm:6.30.0"