Skip to content

Commit edc1ab1

Browse files
kevmo314claude
andcommitted
fix: wrap Firebase Analytics in isSupported check to prevent Node.js warnings
- Add isSupported() check before initializing Firebase Analytics - Create safeLogEvent helper that handles analytics gracefully in all environments - Prevents "Analytics not supported in this environment" warnings in Node.js This allows the package to work seamlessly in both browser and Node.js environments without throwing analytics-related warnings. 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <[email protected]>
1 parent 6c335fc commit edc1ab1

File tree

2 files changed

+61
-34
lines changed

2 files changed

+61
-34
lines changed

api/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "@rtirl/api",
3-
"version": "1.2.1",
3+
"version": "1.2.2",
44
"main": "lib/index.js",
55
"browser": "lib/index.min.js",
66
"types": "lib/index.d.ts",

api/src/index.ts

Lines changed: 60 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,9 @@
1-
import { getAnalytics, logEvent } from "firebase/analytics";
1+
import {
2+
Analytics,
3+
getAnalytics,
4+
isSupported,
5+
logEvent,
6+
} from "firebase/analytics";
27
import { FirebaseApp, initializeApp } from "firebase/app";
38
import { child, getDatabase, onValue, ref } from "firebase/database";
49

@@ -13,99 +18,98 @@ type UUID = string;
1318

1419
export function addLocationListener(
1520
pullKey: string,
16-
callback: (location: Location) => void
21+
callback: (location: Location) => void,
1722
) {
1823
return forPullKey(pullKey).addLocationListener(callback);
1924
}
2025

2126
export function addSpeedListener(
2227
pullKey: string,
23-
callback: (speed: MetersPerSecond) => void
28+
callback: (speed: MetersPerSecond) => void,
2429
) {
2530
return forPullKey(pullKey).addSpeedListener(callback);
2631
}
2732

2833
export function addHeadingListener(
2934
pullKey: string,
30-
callback: (heading: Degrees) => void
35+
callback: (heading: Degrees) => void,
3136
) {
3237
return forPullKey(pullKey).addHeadingListener(callback);
3338
}
3439

3540
export function addAltitudeListener(
3641
pullKey: string,
37-
callback: (altitude: Meters) => void
42+
callback: (altitude: Meters) => void,
3843
) {
3944
return forPullKey(pullKey).addAltitudeListener(callback);
4045
}
4146

4247
export function addSessionIdListener(
4348
pullKey: string,
44-
callback: (sessionId: UUID | null) => void
49+
callback: (sessionId: UUID | null) => void,
4550
) {
4651
return forPullKey(pullKey).addSessionIdListener(callback);
4752
}
4853

4954
/** Creates a listener source for a streamer's private data with a pull key. */
5055
export function forPullKey(pullKey: string) {
5156
const db = getDatabase(getApp());
52-
const analytics = getAnalytics(getApp());
5357
const reference = child(ref(db, "pullables"), pullKey);
5458
return {
5559
addLocationListener(callback: (location: Location) => void) {
56-
logEvent(analytics, "listener", { type: "location", pullKey });
60+
safeLogEvent("listener", { type: "location", pullKey });
5761
return onValue(child(reference, "location"), (snapshot) => {
5862
callback(snapshot.val());
59-
logEvent(analytics, "data", { type: "sessionId", pullKey });
63+
safeLogEvent("data", { type: "sessionId", pullKey });
6064
});
6165
},
6266
addSpeedListener(callback: (speed: MetersPerSecond) => void) {
63-
logEvent(analytics, "listener", { type: "speed", pullKey });
67+
safeLogEvent("listener", { type: "speed", pullKey });
6468
return onValue(child(reference, "speed"), (snapshot) => {
6569
callback(snapshot.val());
66-
logEvent(analytics, "data", { type: "sessionId", pullKey });
70+
safeLogEvent("data", { type: "sessionId", pullKey });
6771
});
6872
},
6973
addHeadingListener(callback: (heading: Degrees) => void) {
70-
logEvent(analytics, "listener", { type: "heading", pullKey });
74+
safeLogEvent("listener", { type: "heading", pullKey });
7175
return onValue(child(reference, "heading"), (snapshot) => {
7276
callback(snapshot.val());
73-
logEvent(analytics, "data", { type: "sessionId", pullKey });
77+
safeLogEvent("data", { type: "sessionId", pullKey });
7478
});
7579
},
7680
addAltitudeListener(callback: (altitude: Meters) => void) {
77-
logEvent(analytics, "listener", { type: "altitude", pullKey });
81+
safeLogEvent("listener", { type: "altitude", pullKey });
7882
return onValue(child(reference, "altitude"), (snapshot) => {
7983
callback(snapshot.val());
80-
logEvent(analytics, "data", { type: "sessionId", pullKey });
84+
safeLogEvent("data", { type: "sessionId", pullKey });
8185
});
8286
},
8387
addHeartRateListener(callback: (altitude: BeatsPerMinute) => void) {
84-
logEvent(analytics, "listener", { type: "heartRate", pullKey });
88+
safeLogEvent("listener", { type: "heartRate", pullKey });
8589
return onValue(child(reference, "heartRate"), (snapshot) => {
8690
callback(snapshot.val());
87-
logEvent(analytics, "data", { type: "sessionId", pullKey });
91+
safeLogEvent("data", { type: "sessionId", pullKey });
8892
});
8993
},
9094
addCyclingPowerListener(callback: (power: Watts) => void) {
91-
logEvent(analytics, "listener", { type: "cyclingPower", pullKey });
95+
safeLogEvent("listener", { type: "cyclingPower", pullKey });
9296
return onValue(child(reference, "cyclingPower"), (snapshot) => {
9397
callback(snapshot.val());
94-
logEvent(analytics, "data", { type: "sessionId", pullKey });
98+
safeLogEvent("data", { type: "sessionId", pullKey });
9599
});
96100
},
97101
addCyclingCrankListener(callback: (power: Watts) => void) {
98-
logEvent(analytics, "listener", { type: "cyclingCrank", pullKey });
102+
safeLogEvent("listener", { type: "cyclingCrank", pullKey });
99103
return onValue(child(reference, "cyclingCrank"), (snapshot) => {
100104
callback(snapshot.val());
101-
logEvent(analytics, "data", { type: "sessionId", pullKey });
105+
safeLogEvent("data", { type: "sessionId", pullKey });
102106
});
103107
},
104108
addCyclingWheelListener(callback: (power: Watts) => void) {
105-
logEvent(analytics, "listener", { type: "cyclingWheel", pullKey });
109+
safeLogEvent("listener", { type: "cyclingWheel", pullKey });
106110
return onValue(child(reference, "cyclingWheel"), (snapshot) => {
107111
callback(snapshot.val());
108-
logEvent(analytics, "data", { type: "sessionId", pullKey });
112+
safeLogEvent("data", { type: "sessionId", pullKey });
109113
});
110114
},
111115
/**
@@ -117,10 +121,10 @@ export function forPullKey(pullKey: string) {
117121
* for a given session id.
118122
*/
119123
addPedometerStepsListener(callback: (steps: Steps) => void) {
120-
logEvent(analytics, "listener", { type: "pedometerSteps", pullKey });
124+
safeLogEvent("listener", { type: "pedometerSteps", pullKey });
121125
return onValue(child(reference, "pedometerSteps"), (snapshot) => {
122126
callback(snapshot.val());
123-
logEvent(analytics, "data", { type: "sessionId", pullKey });
127+
safeLogEvent("data", { type: "sessionId", pullKey });
124128
});
125129
},
126130
/**
@@ -129,10 +133,10 @@ export function forPullKey(pullKey: string) {
129133
* as bluetooth heart rate or telemetry data.
130134
*/
131135
addListener(callback: (data: any) => void) {
132-
logEvent(analytics, "listener", { type: "root", pullKey });
136+
safeLogEvent("listener", { type: "root", pullKey });
133137
return onValue(reference, (snapshot) => {
134138
callback(snapshot.val());
135-
logEvent(analytics, "data", { type: "root", pullKey });
139+
safeLogEvent("data", { type: "root", pullKey });
136140
});
137141
},
138142
/**
@@ -142,10 +146,10 @@ export function forPullKey(pullKey: string) {
142146
* possible for two sequential non-null sessionIds to be sent.
143147
*/
144148
addSessionIdListener(callback: (sessionId: UUID | null) => void) {
145-
logEvent(analytics, "listener", { type: "sessionId", pullKey });
149+
safeLogEvent("listener", { type: "sessionId", pullKey });
146150
return onValue(child(reference, "sessionId"), (snapshot) => {
147151
callback(snapshot.val());
148-
logEvent(analytics, "data", { type: "sessionId", pullKey });
152+
safeLogEvent("data", { type: "sessionId", pullKey });
149153
});
150154
},
151155
};
@@ -154,21 +158,22 @@ export function forPullKey(pullKey: string) {
154158
/** Creates a listener source for a streamer's public data. */
155159
export function forStreamer(provider: "twitch", userId: string) {
156160
const db = getDatabase(getApp());
157-
const analytics = getAnalytics(getApp());
158161
const reference = child(ref(db, "streamers"), `${provider}:${userId}`);
159162
return {
160163
/** If the public location is hidden (eg streamer is offline), null is passed. */
161164
addLocationListener(callback: (location: Location | null) => void) {
162-
logEvent(analytics, "listener", { type: "location", provider, userId });
165+
safeLogEvent("listener", { type: "location", provider, userId });
163166
return onValue(child(reference, "location"), (snapshot) => {
164167
callback(snapshot.val());
165-
logEvent(analytics, "data", { type: "location", provider, userId });
168+
safeLogEvent("data", { type: "location", provider, userId });
166169
});
167170
},
168171
};
169172
}
170173

171174
let app: FirebaseApp | null = null;
175+
let analyticsInstance: Analytics | null = null;
176+
let analyticsChecked = false;
172177

173178
function getApp() {
174179
if (!app) {
@@ -180,8 +185,30 @@ function getApp() {
180185
appId: "1:684852107701:web:d77a8ed0ee5095279a61fc",
181186
measurementId: "G-TR97D81LT3",
182187
},
183-
"rtirl-api"
188+
"rtirl-api",
184189
);
185190
}
186191
return app;
187192
}
193+
194+
function safeLogEvent(eventName: string, eventParams?: any) {
195+
const getAnalyticsInstance = async (): Promise<Analytics | null> => {
196+
if (analyticsChecked) {
197+
return analyticsInstance;
198+
}
199+
200+
analyticsChecked = true;
201+
if (await isSupported()) {
202+
analyticsInstance = getAnalytics(getApp());
203+
}
204+
return analyticsInstance;
205+
};
206+
207+
getAnalyticsInstance()
208+
.then((analytics) => {
209+
if (analytics) {
210+
logEvent(analytics, eventName, eventParams);
211+
}
212+
})
213+
.catch(() => {});
214+
}

0 commit comments

Comments
 (0)