@@ -22,6 +22,22 @@ if (!SENTRY_CLIENT_ID) {
2222const BUN_SQLITE_FILTER = / ^ b u n : s q l i t e $ / ;
2323const ANY_FILTER = / .* / ;
2424
25+ // Regex patterns for SDK type extraction
26+ /** Matches `export type FooParams = { ... };` blocks (multiline via dotAll) */
27+ const EXPORTED_TYPE_BLOCK_RE = / ^ e x p o r t t y p e \w + P a r a m s = \{ [ ^ } ] * \} ; / gms;
28+
29+ /** Matches method lines: `name: (params): Promise<T> =>` */
30+ const SDK_METHOD_RE = / ^ ( \s + ) ( \w + ) : \( ( [ ^ ) ] * ) \) : ( P r o m i s e < .+ > ) \s * = > $ / ;
31+
32+ /** Matches namespace opening: ` name: {` */
33+ const SDK_NAMESPACE_RE = / ^ \s + \w + : \{ $ / ;
34+
35+ /** Matches invoke call bodies to strip from output */
36+ const SDK_INVOKE_RE = / ^ \s + i n v o k e / ;
37+
38+ /** Matches trailing comma before closing brace in method tree */
39+ const TRAILING_COMMA_BRACE_RE = / } , ? $ / ;
40+
2541/** Plugin to replace bun:sqlite with our node:sqlite polyfill. */
2642const bunSqlitePlugin : Plugin = {
2743 name : "bun-sqlite-polyfill" ,
@@ -48,6 +64,102 @@ const bunSqlitePlugin: Plugin = {
4864
4965type InjectedFile = { jsPath : string ; mapPath : string ; debugId : string } ;
5066
67+ /** Count net brace depth change in a line (`{` = +1, `}` = -1). */
68+ function countBraces ( line : string ) : number {
69+ let delta = 0 ;
70+ for ( const ch of line ) {
71+ if ( ch === "{" ) {
72+ delta += 1 ;
73+ }
74+ if ( ch === "}" ) {
75+ delta -= 1 ;
76+ }
77+ }
78+ return delta ;
79+ }
80+
81+ /**
82+ * Extract the method tree lines from `createSDKMethods` function body.
83+ * Returns lines between `return {` and the closing `}` of the function,
84+ * excluding the `return {` line itself.
85+ */
86+ function extractMethodTreeLines ( lines : string [ ] ) : string [ ] {
87+ const methodLines : string [ ] = [ ] ;
88+ let inMethodTree = false ;
89+ let depth = 0 ;
90+
91+ for ( const line of lines ) {
92+ if ( line . includes ( "export function createSDKMethods" ) ) {
93+ inMethodTree = true ;
94+ depth = 0 ;
95+ continue ;
96+ }
97+ if ( ! inMethodTree ) {
98+ continue ;
99+ }
100+
101+ depth += countBraces ( line ) ;
102+
103+ if ( depth <= 0 ) {
104+ break ;
105+ }
106+ if ( line . trim ( ) === "return {" ) {
107+ continue ;
108+ }
109+
110+ methodLines . push ( line ) ;
111+ }
112+
113+ return methodLines ;
114+ }
115+
116+ /** Transform a method implementation line into a type declaration line. */
117+ function transformMethodLine ( line : string ) : string | null {
118+ const methodMatch = SDK_METHOD_RE . exec ( line ) ;
119+ if ( methodMatch ) {
120+ const [ , indent , name , params , returnType ] = methodMatch ;
121+ return `${ indent } ${ name } (${ params } ): ${ returnType } ;` ;
122+ }
123+ if ( SDK_NAMESPACE_RE . test ( line ) ) {
124+ return line ;
125+ }
126+ if ( line . trim ( ) . startsWith ( "}" ) ) {
127+ return line . replace ( TRAILING_COMMA_BRACE_RE , "};" ) ;
128+ }
129+ // JSDoc comments
130+ if ( line . trim ( ) . startsWith ( "/**" ) || line . trim ( ) . startsWith ( "*" ) ) {
131+ return line ;
132+ }
133+ // Invoke call bodies — skip
134+ if ( SDK_INVOKE_RE . test ( line ) ) {
135+ return null ;
136+ }
137+ return line ;
138+ }
139+
140+ /**
141+ * Extract parameter types and SentrySDK type from the generated SDK source.
142+ *
143+ * Parses `sdk.generated.ts` to produce standalone `.d.cts`-safe type declarations:
144+ * 1. All `export type XxxParams = { ... };` blocks (extracted verbatim)
145+ * 2. The `SentrySDK` type built from `createSDKMethods` return shape
146+ * (method implementations → type signatures, invoke bodies stripped)
147+ */
148+ function extractSdkTypes ( source : string ) : string {
149+ const paramTypes = [ ...source . matchAll ( EXPORTED_TYPE_BLOCK_RE ) ] . map (
150+ ( m ) => m [ 0 ]
151+ ) ;
152+
153+ const methodLines = extractMethodTreeLines ( source . split ( "\n" ) ) ;
154+ const sdkBody = methodLines
155+ . map ( transformMethodLine )
156+ . filter ( ( l ) : l is string => l !== null )
157+ . join ( "\n" ) ;
158+
159+ const sdkType = `export type SentrySDK = {\n${ sdkBody } \n};` ;
160+ return `${ paramTypes . join ( "\n\n" ) } \n\n${ sdkType } ` ;
161+ }
162+
51163/** Delete .map files after a successful upload — they shouldn't ship to users. */
52164async function deleteMapFiles ( injected : InjectedFile [ ] ) : Promise < void > {
53165 for ( const { mapPath } of injected ) {
@@ -181,9 +293,8 @@ const result = await build({
181293 entryPoints : [ "./src/index.ts" ] ,
182294 bundle : true ,
183295 minify : true ,
184- banner : {
185- js : `{let e=process.emit;process.emit=function(n,...a){return n==="warning"?!1:e.apply(this,[n,...a])}}` ,
186- } ,
296+ // No banner — warning suppression moved to dist/bin.cjs (CLI-only).
297+ // The library bundle must not suppress the host application's warnings.
187298 sourcemap : true ,
188299 platform : "node" ,
189300 target : "node22" ,
@@ -207,12 +318,14 @@ const result = await build({
207318// Write the CLI bin wrapper (tiny — shebang + version check + dispatch)
208319const BIN_WRAPPER = `#!/usr/bin/env node
209320if(parseInt(process.versions.node)<22){console.error("Error: sentry requires Node.js 22 or later (found "+process.version+").\\n\\nEither upgrade Node.js, or install the standalone binary instead:\\n curl -fsSL https://cli.sentry.dev/install | bash\\n");process.exit(1)}
321+ {let e=process.emit;process.emit=function(n,...a){return n==="warning"?!1:e.apply(this,[n,...a])}}
210322require('./index.cjs')._cli().catch(()=>{process.exitCode=1});
211323` ;
212324await Bun . write ( "./dist/bin.cjs" , BIN_WRAPPER ) ;
213325
214- // Write TypeScript declarations for the library API
215- const TYPE_DECLARATIONS = `export type SentryOptions = {
326+ // Write TypeScript declarations for the library API.
327+ // The SentrySDK type is derived from sdk.generated.ts to stay in sync.
328+ const CORE_DECLARATIONS = `export type SentryOptions = {
216329 /** Auth token. Auto-filled from SENTRY_AUTH_TOKEN / SENTRY_TOKEN env vars. */
217330 token?: string;
218331 /** Return human-readable text instead of parsed JSON. */
@@ -234,35 +347,14 @@ export { sentry };
234347export default sentry;
235348
236349export declare function createSentrySDK(options?: SentryOptions): SentrySDK;
237-
238- export type SentrySDK = {
239- organizations: {
240- list(params?: { limit?: number }): Promise<unknown>;
241- get(params?: { org?: string }): Promise<unknown>;
242- };
243- projects: {
244- list(params?: { target?: string; limit?: number }): Promise<unknown>;
245- get(params?: { target?: string }): Promise<unknown>;
246- };
247- issues: {
248- list(params: { org: string; project: string; limit?: number; query?: string }): Promise<unknown>;
249- get(params: { issueId: string }): Promise<unknown>;
250- };
251- events: {
252- get(params: { eventId: string }): Promise<unknown>;
253- };
254- traces: {
255- list(params?: { target?: string; limit?: number }): Promise<unknown>;
256- get(params: { traceId: string }): Promise<unknown>;
257- };
258- spans: {
259- list(params?: { target?: string; limit?: number }): Promise<unknown>;
260- };
261- teams: {
262- list(params?: { target?: string; limit?: number }): Promise<unknown>;
263- };
264- };
265350` ;
351+
352+ // Extract parameter types and SentrySDK type from sdk.generated.ts.
353+ // This keeps the bundled .d.cts in sync with the generated SDK automatically.
354+ const sdkSource = await Bun . file ( "./src/sdk.generated.ts" ) . text ( ) ;
355+ const sdkTypes = extractSdkTypes ( sdkSource ) ;
356+
357+ const TYPE_DECLARATIONS = `${ CORE_DECLARATIONS } \n${ sdkTypes } \n` ;
266358await Bun . write ( "./dist/index.d.cts" , TYPE_DECLARATIONS ) ;
267359
268360console . log ( " -> dist/bin.cjs (CLI wrapper)" ) ;
0 commit comments