Skip to content

Commit 4cbfdb3

Browse files
TimDaubclaude
andcommitted
feat: add telemetry configuration option
Add a `telemetry` config option to Porto.create() that allows developers to disable Sentry error tracking in the Porto dialog and authentication interfaces. Changes: - Add `telemetry?: boolean` to Porto.Config (defaults to true) - Pass telemetry setting through dialog mode to all dialog types - Update dialog and id apps to respect telemetry preference via localStorage - Make React error handlers conditional based on Sentry initialization - Update documentation with telemetry parameter Usage: ```ts Porto.create({ telemetry: false }) ``` 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
1 parent 0e14f76 commit 4cbfdb3

File tree

7 files changed

+121
-42
lines changed

7 files changed

+121
-42
lines changed

apps/dialog/src/main.tsx

Lines changed: 51 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -14,24 +14,40 @@ import * as Wagmi from '~/lib/Wagmi.ts'
1414
import { App } from './App.js'
1515
import './styles.css'
1616

17+
// Initialize Sentry conditionally based on telemetry setting
18+
let sentryInitialized = false
19+
1720
if (import.meta.env.PROD) {
18-
Sentry.init({
19-
dsn: 'https://457697aad11614a3f667c8e61f6b9e20@o4509056062849024.ingest.us.sentry.io/4509080285741056',
20-
enabled: document.referrer
21-
? TrustedHosts.hostnames.includes(new URL(document.referrer).hostname)
22-
: true,
23-
environment: Env.get(),
24-
integrations: [
25-
Sentry.replayIntegration(),
26-
Sentry.tanstackRouterBrowserTracingIntegration(Router.router),
27-
],
28-
replaysOnErrorSampleRate: 1.0,
29-
replaysSessionSampleRate: 0.1,
30-
})
21+
// Check localStorage for telemetry preference
22+
const telemetryDisabled = localStorage.getItem('__porto_telemetry_disabled') === 'true'
23+
24+
if (!telemetryDisabled) {
25+
Sentry.init({
26+
dsn: 'https://457697aad11614a3f667c8e61f6b9e20@o4509056062849024.ingest.us.sentry.io/4509080285741056',
27+
enabled: document.referrer
28+
? TrustedHosts.hostnames.includes(new URL(document.referrer).hostname)
29+
: true,
30+
environment: Env.get(),
31+
integrations: [
32+
Sentry.replayIntegration(),
33+
Sentry.tanstackRouterBrowserTracingIntegration(Router.router),
34+
],
35+
replaysOnErrorSampleRate: 1.0,
36+
replaysSessionSampleRate: 0.1,
37+
})
38+
sentryInitialized = true
39+
}
3140
}
3241

3342
const offInitialized = Events.onInitialized(porto, async (payload, event) => {
34-
const { chainIds, mode, referrer, theme } = payload
43+
const { chainIds, mode, referrer, telemetry, theme } = payload
44+
45+
// Store telemetry preference in localStorage
46+
if (telemetry === false) {
47+
localStorage.setItem('__porto_telemetry_disabled', 'true')
48+
} else {
49+
localStorage.removeItem('__porto_telemetry_disabled')
50+
}
3551

3652
// Prevent showing stale route from a previous action.
3753
const pathname = Router.router.state.location.pathname.replace(/\/+$/, '')
@@ -163,15 +179,27 @@ const rootElement = document.querySelector('div#root')
163179
if (!rootElement) throw new Error('Root element not found')
164180

165181
createRoot(rootElement, {
166-
onCaughtError: Sentry.reactErrorHandler((error) => {
167-
console.error(error)
168-
}),
169-
onRecoverableError: Sentry.reactErrorHandler((error) => {
170-
console.error(error)
171-
}),
172-
onUncaughtError: Sentry.reactErrorHandler((error) => {
173-
console.error(error)
174-
}),
182+
onCaughtError: sentryInitialized
183+
? Sentry.reactErrorHandler((error) => {
184+
console.error(error)
185+
})
186+
: (error) => {
187+
console.error(error)
188+
},
189+
onRecoverableError: sentryInitialized
190+
? Sentry.reactErrorHandler((error) => {
191+
console.error(error)
192+
})
193+
: (error) => {
194+
console.error(error)
195+
},
196+
onUncaughtError: sentryInitialized
197+
? Sentry.reactErrorHandler((error) => {
198+
console.error(error)
199+
})
200+
: (error) => {
201+
console.error(error)
202+
},
175203
}).render(
176204
<StrictMode>
177205
<App />

apps/docs/pages/sdk/api/porto/create.mdx

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -147,6 +147,21 @@ Available:
147147
- [`Storage.localStorage()`](/sdk/api/storage#storagelocalstorage): Uses `window.localStorage{:ts}`
148148
- [`Storage.cookie()`](/sdk/api/storage#storagecookie): Uses `document.cookie{:ts}`
149149

150+
### telemetry
151+
152+
- **Type:** `boolean | undefined`
153+
- **Default:** `true{:ts}`
154+
155+
Whether to enable telemetry and error tracking. When set to `false`, disables anonymous error reporting via Sentry in the Porto dialog and authentication interfaces.
156+
157+
```ts twoslash
158+
import { Porto } from 'porto'
159+
160+
const porto = Porto.create({
161+
telemetry: false, // Disable telemetry
162+
})
163+
```
164+
150165
### transports
151166

152167
- **Type:** `{ [chainId: string]: Transport }{:ts}`

apps/id/src/main.tsx

Lines changed: 36 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -7,29 +7,50 @@ import * as Router from '~/lib/Router.js'
77
import { App } from './App.js'
88
import './styles.css'
99

10+
// Initialize Sentry conditionally based on telemetry setting
11+
let sentryInitialized = false
12+
1013
if (import.meta.env.PROD) {
11-
Sentry.init({
12-
dsn: 'https://1b4e28921c688e2b03d1b63f8d018913@o4509056062849024.ingest.us.sentry.io/4509080371724288',
13-
environment: Env.get(),
14-
integrations: [
15-
Sentry.replayIntegration(),
16-
Sentry.tanstackRouterBrowserTracingIntegration(Router.router),
17-
],
18-
replaysOnErrorSampleRate: 1.0,
19-
replaysSessionSampleRate: 0.1,
20-
})
14+
// Check localStorage for telemetry preference
15+
const telemetryDisabled = localStorage.getItem('__porto_telemetry_disabled') === 'true'
16+
17+
if (!telemetryDisabled) {
18+
Sentry.init({
19+
dsn: 'https://1b4e28921c688e2b03d1b63f8d018913@o4509056062849024.ingest.us.sentry.io/4509080371724288',
20+
environment: Env.get(),
21+
integrations: [
22+
Sentry.replayIntegration(),
23+
Sentry.tanstackRouterBrowserTracingIntegration(Router.router),
24+
],
25+
replaysOnErrorSampleRate: 1.0,
26+
replaysSessionSampleRate: 0.1,
27+
})
28+
sentryInitialized = true
29+
}
2130
}
2231

2332
const rootElement = document.querySelector('div#root')
2433

2534
if (!rootElement) throw new Error('Root element not found')
2635

2736
createRoot(rootElement, {
28-
onCaughtError: Sentry.reactErrorHandler(),
29-
onRecoverableError: Sentry.reactErrorHandler(),
30-
onUncaughtError: Sentry.reactErrorHandler((error, errorInfo) => {
31-
console.warn('Uncaught error', error, errorInfo.componentStack)
32-
}),
37+
onCaughtError: sentryInitialized
38+
? Sentry.reactErrorHandler()
39+
: (error) => {
40+
console.error(error)
41+
},
42+
onRecoverableError: sentryInitialized
43+
? Sentry.reactErrorHandler()
44+
: (error) => {
45+
console.error(error)
46+
},
47+
onUncaughtError: sentryInitialized
48+
? Sentry.reactErrorHandler((error, errorInfo) => {
49+
console.warn('Uncaught error', error, errorInfo.componentStack)
50+
})
51+
: (error) => {
52+
console.warn('Uncaught error', error)
53+
},
3354
}).render(
3455
<StrictMode>
3556
<App />

src/core/Dialog.ts

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@ export type Dialog = {
3333
setup: (parameters: {
3434
host: string
3535
internal: Internal
36+
telemetry?: boolean | undefined
3637
theme?: ThemeFragment | undefined
3738
themeController?: ThemeController | undefined
3839
}) => {
@@ -83,7 +84,7 @@ export function iframe(options: iframe.Options = {}) {
8384
return from({
8485
name: 'iframe',
8586
setup(parameters) {
86-
const { host, internal, theme, themeController } = parameters
87+
const { host, internal, telemetry, theme, themeController } = parameters
8788
const { store } = internal
8889

8990
const fallback = popup().setup(parameters)
@@ -191,6 +192,7 @@ export function iframe(options: iframe.Options = {}) {
191192
chainIds: compatibleChainIds,
192193
mode: 'iframe',
193194
referrer: getReferrer(),
195+
telemetry,
194196
theme,
195197
type: 'init',
196198
})
@@ -310,6 +312,7 @@ export function iframe(options: iframe.Options = {}) {
310312
messenger.send('__internal', {
311313
mode: 'iframe',
312314
referrer: getReferrer(),
315+
telemetry,
313316
type: 'init',
314317
})
315318

@@ -340,6 +343,7 @@ export function iframe(options: iframe.Options = {}) {
340343
messenger.send('__internal', {
341344
mode: 'iframe',
342345
referrer: getReferrer(),
346+
telemetry,
343347
type: 'init',
344348
})
345349
},
@@ -445,7 +449,7 @@ export function popup(options: popup.Options = {}) {
445449
return from({
446450
name: 'popup',
447451
setup(parameters) {
448-
const { host, internal, themeController } = parameters
452+
const { host, internal, telemetry, themeController } = parameters
449453
const { store } = internal
450454

451455
const hostUrl = new URL(host)
@@ -515,6 +519,7 @@ export function popup(options: popup.Options = {}) {
515519
messenger.send('__internal', {
516520
mode: resolvedType === 'page' ? 'page' : 'popup',
517521
referrer: getReferrer(),
522+
telemetry,
518523
theme: themeController?.getTheme() ?? parameters.theme,
519524
type: 'init',
520525
})
@@ -826,7 +831,7 @@ export function experimental_inline(options: inline.Options) {
826831
return from({
827832
name: 'inline',
828833
setup(parameters) {
829-
const { host, internal, theme, themeController } = parameters
834+
const { host, internal, telemetry, theme, themeController } = parameters
830835
const { store } = internal
831836

832837
let open = false
@@ -874,6 +879,7 @@ export function experimental_inline(options: inline.Options) {
874879
messenger.send('__internal', {
875880
mode: 'inline-iframe',
876881
referrer: getReferrer(),
882+
telemetry,
877883
theme,
878884
type: 'init',
879885
})
@@ -896,6 +902,7 @@ export function experimental_inline(options: inline.Options) {
896902
messenger.send('__internal', {
897903
mode: 'iframe',
898904
referrer: getReferrer(),
905+
telemetry,
899906
type: 'init',
900907
})
901908
},

src/core/Messenger.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -93,6 +93,7 @@ export type Schema = [
9393
icon?: string | { light: string; dark: string } | undefined
9494
title: string
9595
}
96+
telemetry?: boolean | undefined
9697
theme?: Theme.ThemeFragment | undefined
9798
}
9899
| {

src/core/Porto.ts

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,7 @@ export function create(
7272
relay: parameters.relay ?? defaultConfig.relay,
7373
storage: parameters.storage ?? defaultConfig.storage,
7474
storageKey: parameters.storageKey ?? defaultConfig.storageKey,
75+
telemetry: parameters.telemetry ?? true,
7576
transports,
7677
} satisfies Config
7778

@@ -210,6 +211,11 @@ export type Config<
210211
* Key to use for store.
211212
*/
212213
storageKey?: string | undefined
214+
/**
215+
* Whether to enable telemetry/error tracking.
216+
* @default true
217+
*/
218+
telemetry?: boolean | undefined
213219
/**
214220
* Public RPC Transport overrides to use for each chain.
215221
*/

src/core/internal/modes/dialog.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -958,11 +958,12 @@ export function dialog(parameters: dialog.Parameters = {}) {
958958
name: 'dialog',
959959
setup(parameters) {
960960
const { internal } = parameters
961-
const { store } = internal
961+
const { config, store } = internal
962962

963963
const dialog = renderer.setup({
964964
host,
965965
internal,
966+
telemetry: config.telemetry,
966967
theme,
967968
themeController,
968969
})

0 commit comments

Comments
 (0)