@@ -25,36 +25,33 @@ function getTelemetryFlagFilePath(): string {
25
25
}
26
26
27
27
/**
28
- * Checks if the telemetry event has already been fired by looking for a flag file.
29
- */
30
- async function hasTelemetryEventBeenFired ( ) : Promise < boolean > {
31
- try {
32
- await fs . access ( getTelemetryFlagFilePath ( ) ) ;
33
- return true ;
34
- } catch {
35
- return false ;
36
- }
37
- }
38
-
39
- /**
40
- * Creates a flag file to mark that the telemetry event has been fired.
28
+ * Atomically attempts to create a telemetry flag file to prevent duplicate events.
29
+ * This uses the 'wx' flag to ensure only one process can successfully create the file.
30
+ *
31
+ * @returns true if this process won the race and created the flag file, false if it already exists
41
32
*/
42
- async function markTelemetryEventAsFired ( ) : Promise < void > {
33
+ async function tryCreateTelemetryFlag ( ) : Promise < boolean > {
43
34
try {
44
35
// Ensure the directory exists
45
36
const dir = join ( process . cwd ( ) , '.clerk/.tmp' ) ;
46
37
await fs . mkdir ( dir , { recursive : true } ) ;
47
38
48
- // Create the flag file with timestamp
39
+ // Create the flag file with timestamp using 'wx' flag for atomic creation
49
40
const flagData = {
50
41
firedAt : new Date ( ) . toISOString ( ) ,
51
42
event : EVENT_KEYLESS_ENV_DRIFT_DETECTED ,
52
43
} ;
53
44
54
- await fs . writeFile ( getTelemetryFlagFilePath ( ) , JSON . stringify ( flagData , null , 2 ) ) ;
55
- } catch ( error ) {
56
- // Silently handle errors to avoid breaking the application
45
+ await fs . writeFile ( getTelemetryFlagFilePath ( ) , JSON . stringify ( flagData , null , 2 ) , { flag : 'wx' } ) ;
46
+ return true ; // Successfully created the file - we won the race
47
+ } catch ( error : any ) {
48
+ if ( error . code === 'EEXIST' ) {
49
+ // File already exists - another process won the race
50
+ return false ;
51
+ }
52
+ // Other errors (permission issues, etc.) - silently handle to avoid breaking the application
57
53
console . warn ( 'Failed to create telemetry flag file:' , error ) ;
54
+ return false ;
58
55
}
59
56
}
60
57
@@ -77,11 +74,6 @@ export async function detectKeylessEnvDrift(): Promise<void> {
77
74
}
78
75
79
76
try {
80
- // Check if telemetry event has already been fired
81
- if ( await hasTelemetryEventBeenFired ( ) ) {
82
- return ;
83
- }
84
-
85
77
// Dynamically import server-side dependencies to avoid client-side issues
86
78
const { safeParseClerkFile } = await import ( './keyless-node.js' ) ;
87
79
@@ -101,7 +93,7 @@ export async function detectKeylessEnvDrift(): Promise<void> {
101
93
const keylessFileHasKeys = Boolean ( keylessFile ?. publishableKey && keylessFile ?. secretKey ) ;
102
94
103
95
if ( envVarsMissing && keylessFileHasKeys ) {
104
- // Environment variables are missing but keyless file has keys - this is normal for keyless mode
96
+ // Environment variables are missing and keyless file has keys. This is expected for keyless mode
105
97
return ;
106
98
}
107
99
@@ -114,22 +106,23 @@ export async function detectKeylessEnvDrift(): Promise<void> {
114
106
// Check if there's a drift (mismatch between env vars and keyless file)
115
107
const hasDrift = ! publicKeyMatch || ! secretKeyMatch ;
116
108
117
- const payload : EventKeylessEnvDriftPayload = {
118
- publicKeyMatch,
119
- secretKeyMatch,
120
- envVarsMissing,
121
- keylessFileHasKeys,
122
- keylessPublishableKey : keylessFile . publishableKey ,
123
- envPublishableKey : envPublishableKey as string ,
124
- } ;
109
+ // Only emit telemetry if there's drift and we can atomically create the flag file
110
+ if ( hasDrift && ( await tryCreateTelemetryFlag ( ) ) ) {
111
+ const payload : EventKeylessEnvDriftPayload = {
112
+ publicKeyMatch,
113
+ secretKeyMatch,
114
+ envVarsMissing,
115
+ keylessFileHasKeys,
116
+ keylessPublishableKey : keylessFile . publishableKey ,
117
+ envPublishableKey : envPublishableKey as string ,
118
+ } ;
125
119
126
- // Create a clerk client to access telemetry
127
- const clerkClient = createClerkClientWithOptions ( {
128
- publishableKey : keylessFile . publishableKey ,
129
- secretKey : keylessFile . secretKey ,
130
- } ) ;
120
+ // Create a clerk client to access telemetry
121
+ const clerkClient = createClerkClientWithOptions ( {
122
+ publishableKey : keylessFile . publishableKey ,
123
+ secretKey : keylessFile . secretKey ,
124
+ } ) ;
131
125
132
- if ( hasDrift ) {
133
126
// Fire drift detected event
134
127
const driftDetectedEvent : TelemetryEventRaw < EventKeylessEnvDriftPayload > = {
135
128
event : EVENT_KEYLESS_ENV_DRIFT_DETECTED ,
@@ -138,9 +131,6 @@ export async function detectKeylessEnvDrift(): Promise<void> {
138
131
} ;
139
132
140
133
clerkClient . telemetry ?. record ( driftDetectedEvent ) ;
141
-
142
- // Mark the telemetry event as fired to prevent future executions
143
- await markTelemetryEventAsFired ( ) ;
144
134
}
145
135
} catch ( error ) {
146
136
// Silently handle errors to avoid breaking the application
0 commit comments