1313/* eslint-disable no-console */
1414/* eslint-disable no-bitwise */
1515
16+ import type { DsnComponents } from '@sentry/core' ;
17+ import { dsnToString , makeDsn } from '@sentry/core' ;
18+
1619const SENTRY_DSN_ENV = 'SENTRY_DSN' ;
1720const EAS_BUILD_ENV = 'EAS_BUILD' ;
1821
@@ -44,13 +47,6 @@ export interface EASBuildHookOptions {
4447 successMessage ?: string ;
4548}
4649
47- interface ParsedDsn {
48- protocol : string ;
49- host : string ;
50- projectId : string ;
51- publicKey : string ;
52- }
53-
5450interface SentryEvent {
5551 event_id : string ;
5652 timestamp : number ;
@@ -92,18 +88,11 @@ export function getEASBuildEnv(): EASBuildEnv {
9288 } ;
9389}
9490
95- function parseDsn ( dsn : string ) : ParsedDsn | undefined {
96- try {
97- const url = new URL ( dsn ) ;
98- const projectId = url . pathname . replace ( '/' , '' ) ;
99- return { protocol : url . protocol . replace ( ':' , '' ) , host : url . host , projectId, publicKey : url . username } ;
100- } catch {
101- return undefined ;
102- }
103- }
104-
105- function getEnvelopeEndpoint ( dsn : ParsedDsn ) : string {
106- return `${ dsn . protocol } ://${ dsn . host } /api/${ dsn . projectId } /envelope/?sentry_key=${ dsn . publicKey } &sentry_version=7` ;
91+ function getEnvelopeEndpoint ( dsn : DsnComponents ) : string {
92+ const { protocol, host, port, path, projectId, publicKey } = dsn ;
93+ const portStr = port ? `:${ port } ` : '' ;
94+ const pathStr = path ? `/${ path } ` : '' ;
95+ return `${ protocol } ://${ host } ${ portStr } ${ pathStr } /api/${ projectId } /envelope/?sentry_key=${ publicKey } &sentry_version=7` ;
10796}
10897
10998function generateEventId ( ) : string {
@@ -154,19 +143,19 @@ function createEASBuildContext(env: EASBuildEnv): Record<string, unknown> {
154143 } ;
155144}
156145
157- function createEnvelope ( event : SentryEvent , dsn : ParsedDsn ) : string {
146+ function createEnvelope ( event : SentryEvent , dsn : DsnComponents ) : string {
158147 const envelopeHeaders = JSON . stringify ( {
159148 event_id : event . event_id ,
160149 sent_at : new Date ( ) . toISOString ( ) ,
161- dsn : ` ${ dsn . protocol } :// ${ dsn . publicKey } @ ${ dsn . host } / ${ dsn . projectId } ` ,
150+ dsn : dsnToString ( dsn ) ,
162151 sdk : event . sdk ,
163152 } ) ;
164153 const itemHeaders = JSON . stringify ( { type : 'event' , content_type : 'application/json' } ) ;
165154 const itemPayload = JSON . stringify ( event ) ;
166155 return `${ envelopeHeaders } \n${ itemHeaders } \n${ itemPayload } ` ;
167156}
168157
169- async function sendEvent ( event : SentryEvent , dsn : ParsedDsn ) : Promise < boolean > {
158+ async function sendEvent ( event : SentryEvent , dsn : DsnComponents ) : Promise < boolean > {
170159 const endpoint = getEnvelopeEndpoint ( dsn ) ;
171160 const envelope = createEnvelope ( event , dsn ) ;
172161 try {
@@ -184,6 +173,18 @@ async function sendEvent(event: SentryEvent, dsn: ParsedDsn): Promise<boolean> {
184173 }
185174}
186175
176+ function getReleaseFromEASEnv ( env : EASBuildEnv ) : string | undefined {
177+ // Honour explicit override first
178+ if ( process . env . SENTRY_RELEASE ) {
179+ return process . env . SENTRY_RELEASE ;
180+ }
181+ // Best approximation without bundle identifier: version+buildNumber
182+ if ( env . EAS_BUILD_APP_VERSION && env . EAS_BUILD_APP_BUILD_VERSION ) {
183+ return `${ env . EAS_BUILD_APP_VERSION } +${ env . EAS_BUILD_APP_BUILD_VERSION } ` ;
184+ }
185+ return env . EAS_BUILD_APP_VERSION ;
186+ }
187+
187188function createBaseEvent (
188189 level : 'error' | 'info' | 'warning' ,
189190 env : EASBuildEnv ,
@@ -196,7 +197,7 @@ function createBaseEvent(
196197 level,
197198 logger : 'eas-build-hook' ,
198199 environment : 'eas-build' ,
199- release : env . EAS_BUILD_APP_VERSION ,
200+ release : getReleaseFromEASEnv ( env ) ,
200201 tags : { ...createEASBuildTags ( env ) , ...customTags } ,
201202 contexts : { eas_build : createEASBuildContext ( env ) , runtime : { name : 'node' , version : process . version } } ,
202203 sdk : { name : 'sentry.javascript.react-native.eas-build-hooks' , version : '1.0.0' } ,
@@ -205,17 +206,17 @@ function createBaseEvent(
205206
206207/** Captures an EAS build error event. Call this from the eas-build-on-error hook. */
207208export async function captureEASBuildError ( options : EASBuildHookOptions = { } ) : Promise < void > {
208- const dsn = options . dsn ?? process . env [ SENTRY_DSN_ENV ] ;
209- if ( ! dsn ) {
209+ const dsnString = options . dsn ?? process . env [ SENTRY_DSN_ENV ] ;
210+ if ( ! dsnString ) {
210211 console . warn ( '[Sentry] No DSN provided. Set SENTRY_DSN environment variable or pass dsn option.' ) ;
211212 return ;
212213 }
213214 if ( ! isEASBuild ( ) ) {
214215 console . warn ( '[Sentry] Not running in EAS Build environment. Skipping error capture.' ) ;
215216 return ;
216217 }
217- const parsedDsn = parseDsn ( dsn ) ;
218- if ( ! parsedDsn ) {
218+ const dsn = makeDsn ( dsnString ) ;
219+ if ( ! dsn ) {
219220 console . error ( '[Sentry] Invalid DSN format.' ) ;
220221 return ;
221222 }
@@ -228,7 +229,7 @@ export async function captureEASBuildError(options: EASBuildHookOptions = {}): P
228229 values : [ { type : 'EASBuildError' , value : errorMessage , mechanism : { type : 'eas-build-hook' , handled : true } } ] ,
229230 } ;
230231 event . fingerprint = [ 'eas-build-error' , env . EAS_BUILD_PLATFORM ?? 'unknown' , env . EAS_BUILD_PROFILE ?? 'unknown' ] ;
231- const success = await sendEvent ( event , parsedDsn ) ;
232+ const success = await sendEvent ( event , dsn ) ;
232233 if ( success ) console . log ( '[Sentry] Build error captured.' ) ;
233234}
234235
@@ -238,17 +239,17 @@ export async function captureEASBuildSuccess(options: EASBuildHookOptions = {}):
238239 console . log ( '[Sentry] Skipping successful build capture (captureSuccessfulBuilds is false).' ) ;
239240 return ;
240241 }
241- const dsn = options . dsn ?? process . env [ SENTRY_DSN_ENV ] ;
242- if ( ! dsn ) {
242+ const dsnString = options . dsn ?? process . env [ SENTRY_DSN_ENV ] ;
243+ if ( ! dsnString ) {
243244 console . warn ( '[Sentry] No DSN provided. Set SENTRY_DSN environment variable or pass dsn option.' ) ;
244245 return ;
245246 }
246247 if ( ! isEASBuild ( ) ) {
247248 console . warn ( '[Sentry] Not running in EAS Build environment. Skipping success capture.' ) ;
248249 return ;
249250 }
250- const parsedDsn = parseDsn ( dsn ) ;
251- if ( ! parsedDsn ) {
251+ const dsn = makeDsn ( dsnString ) ;
252+ if ( ! dsn ) {
252253 console . error ( '[Sentry] Invalid DSN format.' ) ;
253254 return ;
254255 }
@@ -259,7 +260,7 @@ export async function captureEASBuildSuccess(options: EASBuildHookOptions = {}):
259260 const event = createBaseEvent ( 'info' , env , { ...options . tags , 'eas.hook' : 'on-success' } ) ;
260261 event . message = { formatted : successMessage } ;
261262 event . fingerprint = [ 'eas-build-success' , env . EAS_BUILD_PLATFORM ?? 'unknown' , env . EAS_BUILD_PROFILE ?? 'unknown' ] ;
262- const success = await sendEvent ( event , parsedDsn ) ;
263+ const success = await sendEvent ( event , dsn ) ;
263264 if ( success ) console . log ( '[Sentry] Build success captured.' ) ;
264265}
265266
0 commit comments