@@ -17,7 +17,13 @@ import {
1717 resolveProject ,
1818} from "../../lib/dsn/index.js" ;
1919import { isAuthenticated } from "../../lib/db/auth.js" ;
20- import { bold , green , muted , yellow } from "../../lib/formatters/colors.js" ;
20+ import {
21+ colorTag ,
22+ escapeMarkdownInline ,
23+ mdKvTable ,
24+ renderMarkdown ,
25+ safeCodeSpan ,
26+ } from "../../lib/formatters/markdown.js" ;
2127import { CommandOutput } from "../../lib/formatters/output.js" ;
2228import {
2329 applyFreshFlag ,
@@ -85,101 +91,110 @@ type DsnDiscoveryData = {
8591
8692/** Mask the middle of a DSN's public key for display */
8793function maskDsnKey ( dsn : string ) : string {
88- // Replace the public key portion: https://KEY@host /id → https://KEY[masked]@host/id
8994 return dsn . replace (
9095 / ^ ( h t t p s ? : \/ \/ ) ( [ a - z 0 - 9 ] { 4 } ) [ a - z 0 - 9 ] + ( @ ) / i,
9196 ( _ , proto , start , at ) => `${ proto } ${ start } ****${ at } `
9297 ) ;
9398}
9499
95- function formatDsnEntry (
96- entry : DsnDiscoveryData [ "dsns" ] [ number ] ,
97- index : number ,
98- total : number
99- ) : string {
100+ function formatDsnEntry ( entry : DsnDiscoveryData [ "dsns" ] [ number ] ) : string {
100101 const lines : string [ ] = [ ] ;
101102
102- const prefix = total > 1 ? ` ${ index + 1 } . ` : "" ;
103- const primaryTag = entry . primary ? green ( " (primary)" ) : "" ;
104- lines . push ( ` ${ prefix } ${ bold ( maskDsnKey ( entry . dsn ) ) } ${ primaryTag } ` ) ;
105- lines . push ( ` Source: ${ entry . sourceDescription } ` ) ;
103+ const rows : [ string , string ] [ ] = [
104+ [ "DSN" , safeCodeSpan ( maskDsnKey ( entry . dsn ) ) ] ,
105+ [ "Source" , escapeMarkdownInline ( entry . sourceDescription ) ] ,
106+ ] ;
106107 if ( entry . packagePath ) {
107- lines . push ( ` Package: ${ entry . packagePath } ` ) ;
108+ rows . push ( [ " Package" , safeCodeSpan ( entry . packagePath ) ] ) ;
108109 }
109- lines . push ( ` Project ID: ${ entry . projectId } ` ) ;
110+ rows . push ( [ " Project ID" , safeCodeSpan ( entry . projectId ) ] ) ;
110111 if ( entry . orgId ) {
111- lines . push ( ` Org ID: ${ entry . orgId } ` ) ;
112+ rows . push ( [ " Org ID" , safeCodeSpan ( entry . orgId ) ] ) ;
112113 }
113114 if ( entry . resolved ) {
114- lines . push (
115- ` Resolved: ${ green ( `${ entry . resolved . orgSlug } /${ entry . resolved . projectSlug } ` ) } `
116- ) ;
115+ rows . push ( [
116+ "Resolved" ,
117+ colorTag (
118+ "green" ,
119+ `${ entry . resolved . orgSlug } /${ entry . resolved . projectSlug } `
120+ ) ,
121+ ] ) ;
117122 } else {
118- lines . push ( ` Resolved: ${ muted ( " (not yet resolved)") } ` ) ;
123+ rows . push ( [ " Resolved" , colorTag ( "muted" , " (not yet resolved)") ] ) ;
119124 }
120125
126+ lines . push ( mdKvTable ( rows ) ) ;
121127 return lines . join ( "\n" ) ;
122128}
123129
124130function formatDsnDiscovery ( data : DsnDiscoveryData ) : string {
125131 const lines : string [ ] = [ ] ;
126132
127133 // Project root
128- lines . push ( bold ( "Project root" ) ) ;
129- lines . push ( ` Path: ${ data . projectRoot . path } ` ) ;
130- lines . push ( ` Reason: ${ data . projectRoot . reason } ` ) ;
134+ lines . push ( "## Project root" ) ;
135+ lines . push ( "" ) ;
136+ lines . push (
137+ mdKvTable ( [
138+ [ "Path" , safeCodeSpan ( data . projectRoot . path ) ] ,
139+ [ "Reason" , data . projectRoot . reason ] ,
140+ ] )
141+ ) ;
131142
132143 // Scan summary
144+ lines . push ( "## Scan" ) ;
133145 lines . push ( "" ) ;
134- lines . push ( bold ( "Scan" ) ) ;
146+ const dirCount = data . scan . dirs . length ;
147+ const fileCount = data . scan . files ;
135148 lines . push (
136- ` ${ data . scan . dirs . length } director${ data . scan . dirs . length === 1 ? "y" : "ies" } , ${ data . scan . files } file${ data . scan . files === 1 ? "" : "s" } checked`
149+ `${ dirCount } director${ dirCount === 1 ? "y" : "ies" } , ${ fileCount } file${ fileCount === 1 ? "" : "s" } checked`
137150 ) ;
138- if ( data . scan . dirs . length > 0 ) {
139- // Sort dirs for stable display, show relative paths
151+ lines . push ( "" ) ;
152+ if ( dirCount > 0 ) {
140153 const sortedDirs = [ ...data . scan . dirs ] . sort ( ) ;
141154 for ( const dir of sortedDirs ) {
142- lines . push ( ` ${ muted ( dir ) } ` ) ;
155+ lines . push ( `- ${ colorTag ( "muted" , dir ) } ` ) ;
143156 }
157+ lines . push ( "" ) ;
144158 }
145159
146160 // Env var
161+ lines . push ( "## Environment" ) ;
147162 lines . push ( "" ) ;
148- lines . push ( bold ( "Environment" ) ) ;
149163 if ( data . envVar ) {
150- lines . push ( ` SENTRY_DSN : ${ maskDsnKey ( data . envVar ) } ` ) ;
164+ lines . push ( `SENTRY\\_DSN : ${ safeCodeSpan ( maskDsnKey ( data . envVar ) ) } ` ) ;
151165 } else {
152- lines . push ( ` SENTRY_DSN : ${ muted ( "(not set)" ) } ` ) ;
166+ lines . push ( `SENTRY\\_DSN : ${ colorTag ( "muted" , "(not set)" ) } ` ) ;
153167 }
168+ lines . push ( "" ) ;
154169
155170 // DSNs
156- lines . push ( "" ) ;
157171 if ( data . count === 0 ) {
158- lines . push ( yellow ( "No DSNs found" ) ) ;
172+ lines . push ( colorTag ( "yellow" , "No DSNs found" ) ) ;
159173 lines . push ( "" ) ;
160174 lines . push ( "The CLI looks for DSNs in:" ) ;
161- lines . push ( " 1. Source code (Sentry.init calls, DSN strings)" ) ;
162- lines . push ( " 2. .env files (SENTRY_DSN =...)" ) ;
163- lines . push ( " 3. SENTRY_DSN environment variable" ) ;
175+ lines . push ( "1. Source code (Sentry.init calls, DSN strings)" ) ;
176+ lines . push ( "2. .env files (SENTRY\\_DSN =...)" ) ;
177+ lines . push ( "3. SENTRY\\_DSN environment variable" ) ;
164178 lines . push ( "" ) ;
165179 lines . push (
166- `Searched from ${ muted ( data . cwd ) } up to ${ muted ( data . projectRoot . path ) } `
180+ `Searched from ${ safeCodeSpan ( data . cwd ) } up to ${ safeCodeSpan ( data . projectRoot . path ) } `
167181 ) ;
168182 } else {
169- lines . push (
170- bold ( `Found ${ data . count } DSN ${ data . count > 1 ? "s" : "" } ` )
171- ) ;
172- lines . push ( "" ) ;
173- for ( let i = 0 ; i < data . dsns . length ; i ++ ) {
174- const entry = data . dsns [ i ] ! ;
175- lines . push ( formatDsnEntry ( entry , i , data . count ) ) ;
176- if ( i < data . dsns . length - 1 ) {
183+ lines . push ( `## Found ${ data . count } DSN ${ data . count > 1 ? "s" : "" } ` ) ;
184+ for ( const [ i , entry ] of data . dsns . entries ( ) ) {
185+ lines . push ( "" ) ;
186+ if ( data . count > 1 ) {
187+ const primaryTag = entry . primary
188+ ? ` ${ colorTag ( "green" , "(primary)" ) } `
189+ : "" ;
190+ lines . push ( `### ${ i + 1 } . ${ primaryTag } ` ) ;
177191 lines . push ( "" ) ;
178192 }
193+ lines . push ( formatDsnEntry ( entry ) ) ;
179194 }
180195 }
181196
182- return lines . join ( "\n" ) ;
197+ return renderMarkdown ( lines . join ( "\n" ) ) ;
183198}
184199
185200function mapDsn (
0 commit comments