1- import type { IntegrationFn } from '@sentry/core' ;
1+ import { existsSync } from 'node:fs' ;
2+ import { join } from 'node:path' ;
3+ import type { Client , IntegrationFn } from '@sentry/core' ;
24import { addVercelAiProcessors , defineIntegration } from '@sentry/core' ;
3- import { generateInstrumentOnce } from '@sentry/node-core' ;
5+ import { generateInstrumentOnce , type modulesIntegration } from '@sentry/node-core' ;
46import { INTEGRATION_NAME } from './constants' ;
57import { SentryVercelAiInstrumentation } from './instrumentation' ;
68import type { VercelAiOptions } from './types' ;
79
810export const instrumentVercelAi = generateInstrumentOnce ( INTEGRATION_NAME , ( ) => new SentryVercelAiInstrumentation ( { } ) ) ;
911
1012/**
11- * Determines if the 'ai' package is installed and available.
12- *
13- * Uses require.resolve() to check for package availability without loading it.
14- * This approach avoids race conditions that can occur with filesystem-based
15- * detection during initialization in serverless environments (Lambda/Vercel).
16- *
17- * @returns true if the 'ai' package can be resolved, false otherwise
13+ * Determines if the integration should be forced based on environment and package availability.
14+ * Returns true if the 'ai' package is available.
1815 */
19- function shouldForceIntegration ( ) : boolean {
20- try {
21- const moduleName = 'ai' ;
22- require . resolve ( moduleName ) ;
23- return true ;
24- } catch {
16+ function shouldForceIntegration ( client : Client ) : boolean {
17+ const modules = client . getIntegrationByName < ReturnType < typeof modulesIntegration > > ( 'Modules' ) ;
18+
19+ if ( ! modules ?. getModules ) {
2520 return false ;
2621 }
22+
23+ let moduleList = modules . getModules ( ) ;
24+
25+ // Workaround for race condition in serverless environments:
26+ // If module list is empty, the filesystem may not have been ready during initialization.
27+ // Perform a filesystem check to warm it up, then retry.
28+ if ( Object . keys ( moduleList ) . length === 0 ) {
29+ try {
30+ existsSync ( join ( process . cwd ( ) , 'package.json' ) ) ;
31+ moduleList = modules . getModules ( ) ;
32+ } catch {
33+ return false ;
34+ }
35+ }
36+
37+ return ! ! moduleList ?. ai ;
2738}
2839
2940const _vercelAIIntegration = ( ( options : VercelAiOptions = { } ) => {
@@ -36,14 +47,13 @@ const _vercelAIIntegration = ((options: VercelAiOptions = {}) => {
3647 instrumentation = instrumentVercelAi ( ) ;
3748 } ,
3849 afterAllSetup ( client ) {
39- // Auto-detect if we should force the integration when the 'ai' package is available
40- // Uses require.resolve() for reliable detection in all environments
41- const shouldForce = options . force ?? shouldForceIntegration ( ) ;
50+ // Auto-detect if we should force the integration when running with 'ai' package available
51+ // Note that this can only be detected if the 'Modules' integration is available, and running in CJS mode
52+ const shouldForce = options . force ?? shouldForceIntegration ( client ) ;
4253
4354 if ( shouldForce ) {
4455 addVercelAiProcessors ( client ) ;
4556 } else {
46- // Lazy registration - only registers when 'ai' package is actually imported
4757 instrumentation ?. callWhenPatched ( ( ) => addVercelAiProcessors ( client ) ) ;
4858 }
4959 } ,
0 commit comments