Skip to content

Commit 30056ee

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 30056ee

File tree

2 files changed

+57
-34
lines changed

2 files changed

+57
-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: 56 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,15 +158,14 @@ 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
};
@@ -180,8 +183,28 @@ function getApp() {
180183
appId: "1:684852107701:web:d77a8ed0ee5095279a61fc",
181184
measurementId: "G-TR97D81LT3",
182185
},
183-
"rtirl-api"
186+
"rtirl-api",
184187
);
185188
}
186189
return app;
187190
}
191+
192+
const safeLogEvent = (() => {
193+
let analyticsInstance: Analytics | null = null;
194+
195+
return (eventName: string, eventParams?: any) => {
196+
if (analyticsInstance) {
197+
logEvent(analyticsInstance, eventName, eventParams);
198+
return;
199+
}
200+
201+
isSupported()
202+
.then((supported) => {
203+
if (supported) {
204+
analyticsInstance = getAnalytics(getApp());
205+
logEvent(analyticsInstance, eventName, eventParams);
206+
}
207+
})
208+
.catch(() => {});
209+
};
210+
})();

0 commit comments

Comments
 (0)