gameglue 4.0.0 → 4.0.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (56) hide show
  1. package/LICENSE +21 -21
  2. package/README.md +275 -275
  3. package/babel.config.cjs +5 -5
  4. package/coverage/auth.js.html +525 -525
  5. package/coverage/base.css +224 -224
  6. package/coverage/block-navigation.js +87 -87
  7. package/coverage/favicon.png +0 -0
  8. package/coverage/index.html +175 -175
  9. package/coverage/index.js.html +309 -309
  10. package/coverage/lcov-report/auth.js.html +525 -525
  11. package/coverage/lcov-report/base.css +224 -224
  12. package/coverage/lcov-report/block-navigation.js +87 -87
  13. package/coverage/lcov-report/favicon.png +0 -0
  14. package/coverage/lcov-report/index.html +175 -175
  15. package/coverage/lcov-report/index.js.html +309 -309
  16. package/coverage/lcov-report/listener.js.html +528 -528
  17. package/coverage/lcov-report/prettify.css +1 -1
  18. package/coverage/lcov-report/prettify.js +2 -2
  19. package/coverage/lcov-report/sort-arrow-sprite.png +0 -0
  20. package/coverage/lcov-report/sorter.js +210 -210
  21. package/coverage/lcov-report/user.js.html +117 -117
  22. package/coverage/lcov-report/utils.js.html +117 -117
  23. package/coverage/lcov.info +391 -391
  24. package/coverage/listener.js.html +528 -528
  25. package/coverage/prettify.css +1 -1
  26. package/coverage/prettify.js +2 -2
  27. package/coverage/sort-arrow-sprite.png +0 -0
  28. package/coverage/sorter.js +210 -210
  29. package/coverage/user.js.html +117 -117
  30. package/coverage/utils.js.html +117 -117
  31. package/dist/gg.cjs.js +1 -1
  32. package/dist/gg.cjs.js.map +1 -1
  33. package/dist/gg.esm.js +1 -1
  34. package/dist/gg.esm.js.map +1 -1
  35. package/dist/gg.umd.js +1 -1
  36. package/dist/gg.umd.js.map +1 -1
  37. package/examples/certs/cert.pem +19 -19
  38. package/examples/certs/key.pem +28 -28
  39. package/examples/flight-dashboard.html +431 -431
  40. package/examples/server.js +99 -99
  41. package/examples/telemetry-validator.html +1410 -1410
  42. package/jest.config.cjs +33 -33
  43. package/package.json +56 -56
  44. package/rollup.config.js +57 -57
  45. package/src/auth.js +255 -255
  46. package/src/auth.spec.js +481 -481
  47. package/src/index.js +168 -168
  48. package/src/listener.js +196 -193
  49. package/src/listener.spec.js +598 -598
  50. package/src/presence_listener.js +112 -112
  51. package/src/test/fixtures.js +106 -106
  52. package/src/test/setup.js +51 -51
  53. package/src/utils.js +63 -63
  54. package/src/utils.spec.js +78 -78
  55. package/types/index.d.ts +338 -338
  56. package/webpack.config.js +15 -15
package/types/index.d.ts CHANGED
@@ -1,338 +1,338 @@
1
- declare module 'gameglue' {
2
- export interface GameGlueConfig {
3
- /** OAuth client ID registered with GameGlue */
4
- clientId: string;
5
- /** Scopes to request (e.g., ['msfs:read', 'msfs:write', 'xplane:read', 'xplane:write']) */
6
- scopes?: string[];
7
- /** OAuth redirect URI (defaults to window.location.href) */
8
- redirect_uri?: string;
9
- /** Custom socket server URL (defaults to https://socks.gameglue.gg) */
10
- socketUrl?: string;
11
- /** Custom auth server URL (defaults to https://auth.gameglue.gg/realms/GameGlue) */
12
- authUrl?: string;
13
- }
14
-
15
- export interface ListenerConfig {
16
- /** User ID to listen to (from getUser()) */
17
- userId: string;
18
- /** Game ID (e.g., 'msfs', 'xplane') */
19
- gameId: string;
20
- /** Optional list of fields to subscribe to */
21
- fields?: string[];
22
- }
23
-
24
- export interface PresenceListenerConfig {
25
- /** Client ID of the app (e.g., 'remote-pilot') */
26
- clientId: string;
27
- /** Game ID (e.g., 'msfs', 'xplane') */
28
- gameId: string;
29
- }
30
-
31
- export interface PresenceSnapshot<T = Record<string, unknown>, R = Record<string, unknown>> {
32
- userId: string;
33
- username: string;
34
- displayName: string;
35
- gameId: string;
36
- data: T;
37
- raw?: R;
38
- updatedAt: number;
39
- }
40
-
41
- export interface CommandResult {
42
- status: 'success' | 'failed';
43
- reason?: string;
44
- }
45
-
46
- export interface UpdateEvent<T = Record<string, unknown>, R = Record<string, unknown>> {
47
- /** Normalized telemetry data (canonical field names) */
48
- data: T;
49
- /** Raw telemetry data (game-specific field names) */
50
- raw: R;
51
- }
52
-
53
- // ===========================================
54
- // DERIVED EVENTS
55
- // ===========================================
56
-
57
- /** Position coordinates */
58
- export interface Position {
59
- lat: number;
60
- lon: number;
61
- }
62
-
63
- /** Landing quality rating based on touchdown rate */
64
- export type LandingQuality = 'butter' | 'smooth' | 'normal' | 'firm' | 'hard' | 'crash';
65
-
66
- /** Bounce data for tracking bounces before final landing */
67
- export interface BounceData {
68
- /** Vertical speed at this bounce (feet per minute) */
69
- landing_rate: number;
70
- /** Landing quality of this bounce */
71
- quality: LandingQuality;
72
- /** How long the aircraft was airborne during this bounce (ms) */
73
- airborne_duration_ms: number;
74
- }
75
-
76
- /** Landing event - fired when aircraft touches down and stabilizes */
77
- export interface LandingEvent {
78
- /** Vertical speed at first touchdown (feet per minute, negative = descending) */
79
- landing_rate: number;
80
- /** Landing quality rating (based on first touchdown) */
81
- quality: LandingQuality;
82
- /** Pitch angle at touchdown (degrees) */
83
- pitch_at_touchdown: number;
84
- /** Roll angle at touchdown (degrees) */
85
- roll_at_touchdown: number;
86
- /** Indicated airspeed at touchdown (knots) */
87
- speed_at_touchdown: number;
88
- /** Heading at touchdown (degrees) */
89
- heading_at_touchdown: number;
90
- /** Touchdown position */
91
- position: Position;
92
- /** Number of bounces before landing stabilized (0 = clean landing) */
93
- bounce_count: number;
94
- /** Details of each bounce (if any) */
95
- bounces: BounceData[];
96
- /** Event timestamp (ms since epoch) */
97
- timestamp: number;
98
- }
99
-
100
- /** Takeoff event - fired when aircraft leaves the ground */
101
- export interface TakeoffEvent {
102
- /** Speed at rotation (knots) */
103
- rotation_speed: number;
104
- /** Pitch angle at liftoff (degrees) */
105
- pitch_at_liftoff: number;
106
- /** Heading at liftoff (degrees) */
107
- heading_at_liftoff: number;
108
- /** Liftoff position */
109
- position: Position;
110
- /** Flap setting at liftoff (0-1 ratio) */
111
- flaps_setting: number;
112
- /** Event timestamp (ms since epoch) */
113
- timestamp: number;
114
- }
115
-
116
- /** Flight phases */
117
- export type FlightPhase =
118
- | 'parked'
119
- | 'taxi_out'
120
- | 'takeoff_roll'
121
- | 'initial_climb'
122
- | 'climb'
123
- | 'cruise'
124
- | 'descent'
125
- | 'approach'
126
- | 'final'
127
- | 'landing_roll'
128
- | 'taxi_in';
129
-
130
- /** Flight phase change event */
131
- export interface FlightPhaseEvent {
132
- /** Current flight phase */
133
- phase: FlightPhase;
134
- /** Previous flight phase */
135
- previous_phase: FlightPhase;
136
- /** Current altitude above ground level (feet AGL) */
137
- altitude_agl: number;
138
- /** Current altitude mean sea level (feet MSL) */
139
- altitude_msl: number;
140
- /** Current indicated airspeed (knots) */
141
- speed: number;
142
- /** Event timestamp (ms since epoch) */
143
- timestamp: number;
144
- }
145
-
146
- export interface Listener {
147
- /**
148
- * Subscribe to telemetry update events
149
- * @param event Event name ('update')
150
- * @param callback Callback function receiving update data
151
- */
152
- on<T = Record<string, unknown>, R = Record<string, unknown>>(
153
- event: 'update',
154
- callback: (evt: UpdateEvent<T, R>) => void
155
- ): void;
156
-
157
- /**
158
- * Subscribe to landing events
159
- * @param event Event name ('landing')
160
- * @param callback Callback function receiving landing data
161
- */
162
- on(event: 'landing', callback: (evt: LandingEvent) => void): void;
163
-
164
- /**
165
- * Subscribe to takeoff events
166
- * @param event Event name ('takeoff')
167
- * @param callback Callback function receiving takeoff data
168
- */
169
- on(event: 'takeoff', callback: (evt: TakeoffEvent) => void): void;
170
-
171
- /**
172
- * Subscribe to flight phase change events
173
- * @param event Event name ('flight_phase')
174
- * @param callback Callback function receiving flight phase data
175
- */
176
- on(event: 'flight_phase', callback: (evt: FlightPhaseEvent) => void): void;
177
-
178
- /**
179
- * Unsubscribe a callback from telemetry update events
180
- */
181
- off<T = Record<string, unknown>, R = Record<string, unknown>>(
182
- event: 'update',
183
- callback: (evt: UpdateEvent<T, R>) => void
184
- ): void;
185
-
186
- /**
187
- * Unsubscribe a callback from landing events
188
- */
189
- off(event: 'landing', callback: (evt: LandingEvent) => void): void;
190
-
191
- /**
192
- * Unsubscribe a callback from takeoff events
193
- */
194
- off(event: 'takeoff', callback: (evt: TakeoffEvent) => void): void;
195
-
196
- /**
197
- * Unsubscribe a callback from flight phase change events
198
- */
199
- off(event: 'flight_phase', callback: (evt: FlightPhaseEvent) => void): void;
200
-
201
- /**
202
- * Send a command to the broadcaster (game client)
203
- * Commands are sent as canonical names; the game client handles game-specific translation.
204
- * @param command The canonical command name (e.g., 'gear_up', 'set_autopilot_heading')
205
- * @param value The value to set (optional for toggle commands)
206
- */
207
- sendCommand(command: string, value?: unknown): Promise<CommandResult>;
208
-
209
- /**
210
- * Subscribe to additional fields dynamically
211
- * @param fields Array of field names to add
212
- */
213
- subscribe(fields: string[]): Promise<CommandResult>;
214
-
215
- /**
216
- * Unsubscribe from specific fields
217
- * @param fields Array of field names to remove
218
- */
219
- unsubscribe(fields: string[]): Promise<CommandResult>;
220
-
221
- /**
222
- * Get the current list of subscribed fields
223
- * @returns Array of field names, or null if receiving all fields
224
- */
225
- getFields(): string[] | null;
226
- }
227
-
228
- export interface PresenceListener {
229
- /**
230
- * Subscribe to presence update events
231
- * @param event Event name ('update')
232
- * @param callback Callback function receiving presence snapshot
233
- */
234
- on<T = Record<string, unknown>, R = Record<string, unknown>>(
235
- event: 'update',
236
- callback: (snapshot: PresenceSnapshot<T, R>) => void
237
- ): void;
238
-
239
- /**
240
- * Subscribe to presence removal events
241
- * @param event Event name ('remove')
242
- * @param callback Callback function receiving removed userId
243
- */
244
- on(event: 'remove', callback: (evt: { userId: string }) => void): void;
245
-
246
- /**
247
- * Subscribe to connection events
248
- */
249
- on(event: 'connect', callback: () => void): void;
250
- on(event: 'disconnect', callback: (reason?: string) => void): void;
251
-
252
- /**
253
- * Unsubscribe a callback from presence update events
254
- */
255
- off<T = Record<string, unknown>, R = Record<string, unknown>>(
256
- event: 'update',
257
- callback: (snapshot: PresenceSnapshot<T, R>) => void
258
- ): void;
259
-
260
- /**
261
- * Unsubscribe a callback from presence removal events
262
- */
263
- off(event: 'remove', callback: (evt: { userId: string }) => void): void;
264
-
265
- /**
266
- * Unsubscribe from connection events
267
- */
268
- off(event: 'connect', callback: () => void): void;
269
- off(event: 'disconnect', callback: (reason?: string) => void): void;
270
-
271
- /**
272
- * Get current list of broadcasters
273
- */
274
- getBroadcasters<T = Record<string, unknown>, R = Record<string, unknown>>(): PresenceSnapshot<T, R>[];
275
-
276
- /**
277
- * Disconnect the presence socket
278
- */
279
- disconnect(): void;
280
- }
281
-
282
- export interface LogoutOptions {
283
- /** If false, only clears local tokens without redirecting to Keycloak logout */
284
- redirect?: boolean;
285
- }
286
-
287
- export class GameGlue {
288
- constructor(config: GameGlueConfig);
289
-
290
- /**
291
- * Check if user is authenticated.
292
- * If OAuth callback params are in URL, processes them first.
293
- */
294
- isAuthenticated(): Promise<boolean>;
295
-
296
- /**
297
- * Redirect to OAuth login page.
298
- * Does not return - navigates away.
299
- */
300
- login(): void;
301
-
302
- /**
303
- * Log out the user.
304
- * Clears local tokens and optionally redirects to Keycloak logout.
305
- */
306
- logout(options?: LogoutOptions): void;
307
-
308
- /**
309
- * Get the current user's ID.
310
- * @throws Error if not authenticated
311
- */
312
- getUser(): string;
313
-
314
- /**
315
- * Get the access token for API calls.
316
- */
317
- getAccessToken(): string | undefined;
318
-
319
- /**
320
- * Create a listener for game telemetry.
321
- * Connects to socket server lazily on first call.
322
- */
323
- createListener(config: ListenerConfig): Promise<Listener>;
324
-
325
- /**
326
- * Create a presence listener for public broadcaster updates.
327
- * Does not require authentication.
328
- */
329
- createPresenceListener(config: PresenceListenerConfig): Promise<PresenceListener>;
330
-
331
- /**
332
- * Register callback for token refresh events.
333
- */
334
- onTokenRefreshed(callback: (token: string) => void): void;
335
- }
336
-
337
- export default GameGlue;
338
- }
1
+ declare module 'gameglue' {
2
+ export interface GameGlueConfig {
3
+ /** OAuth client ID registered with GameGlue */
4
+ clientId: string;
5
+ /** Scopes to request (e.g., ['msfs:read', 'msfs:write', 'xplane:read', 'xplane:write']) */
6
+ scopes?: string[];
7
+ /** OAuth redirect URI (defaults to window.location.href) */
8
+ redirect_uri?: string;
9
+ /** Custom socket server URL (defaults to https://socks.gameglue.gg) */
10
+ socketUrl?: string;
11
+ /** Custom auth server URL (defaults to https://auth.gameglue.gg/realms/GameGlue) */
12
+ authUrl?: string;
13
+ }
14
+
15
+ export interface ListenerConfig {
16
+ /** User ID to listen to (from getUser()) */
17
+ userId: string;
18
+ /** Game ID (e.g., 'msfs', 'xplane') */
19
+ gameId: string;
20
+ /** Optional list of fields to subscribe to */
21
+ fields?: string[];
22
+ }
23
+
24
+ export interface PresenceListenerConfig {
25
+ /** Client ID of the app (e.g., 'remote-pilot') */
26
+ clientId: string;
27
+ /** Game ID (e.g., 'msfs', 'xplane') */
28
+ gameId: string;
29
+ }
30
+
31
+ export interface PresenceSnapshot<T = Record<string, unknown>, R = Record<string, unknown>> {
32
+ userId: string;
33
+ username: string;
34
+ displayName: string;
35
+ gameId: string;
36
+ data: T;
37
+ raw?: R;
38
+ updatedAt: number;
39
+ }
40
+
41
+ export interface CommandResult {
42
+ status: 'success' | 'failed';
43
+ reason?: string;
44
+ }
45
+
46
+ export interface UpdateEvent<T = Record<string, unknown>, R = Record<string, unknown>> {
47
+ /** Normalized telemetry data (canonical field names) */
48
+ data: T;
49
+ /** Raw telemetry data (game-specific field names) */
50
+ raw: R;
51
+ }
52
+
53
+ // ===========================================
54
+ // DERIVED EVENTS
55
+ // ===========================================
56
+
57
+ /** Position coordinates */
58
+ export interface Position {
59
+ lat: number;
60
+ lon: number;
61
+ }
62
+
63
+ /** Landing quality rating based on touchdown rate */
64
+ export type LandingQuality = 'butter' | 'smooth' | 'normal' | 'firm' | 'hard' | 'crash';
65
+
66
+ /** Bounce data for tracking bounces before final landing */
67
+ export interface BounceData {
68
+ /** Vertical speed at this bounce (feet per minute) */
69
+ landing_rate: number;
70
+ /** Landing quality of this bounce */
71
+ quality: LandingQuality;
72
+ /** How long the aircraft was airborne during this bounce (ms) */
73
+ airborne_duration_ms: number;
74
+ }
75
+
76
+ /** Landing event - fired when aircraft touches down and stabilizes */
77
+ export interface LandingEvent {
78
+ /** Vertical speed at first touchdown (feet per minute, negative = descending) */
79
+ landing_rate: number;
80
+ /** Landing quality rating (based on first touchdown) */
81
+ quality: LandingQuality;
82
+ /** Pitch angle at touchdown (degrees) */
83
+ pitch_at_touchdown: number;
84
+ /** Roll angle at touchdown (degrees) */
85
+ roll_at_touchdown: number;
86
+ /** Indicated airspeed at touchdown (knots) */
87
+ speed_at_touchdown: number;
88
+ /** Heading at touchdown (degrees) */
89
+ heading_at_touchdown: number;
90
+ /** Touchdown position */
91
+ position: Position;
92
+ /** Number of bounces before landing stabilized (0 = clean landing) */
93
+ bounce_count: number;
94
+ /** Details of each bounce (if any) */
95
+ bounces: BounceData[];
96
+ /** Event timestamp (ms since epoch) */
97
+ timestamp: number;
98
+ }
99
+
100
+ /** Takeoff event - fired when aircraft leaves the ground */
101
+ export interface TakeoffEvent {
102
+ /** Speed at rotation (knots) */
103
+ rotation_speed: number;
104
+ /** Pitch angle at liftoff (degrees) */
105
+ pitch_at_liftoff: number;
106
+ /** Heading at liftoff (degrees) */
107
+ heading_at_liftoff: number;
108
+ /** Liftoff position */
109
+ position: Position;
110
+ /** Flap setting at liftoff (0-1 ratio) */
111
+ flaps_setting: number;
112
+ /** Event timestamp (ms since epoch) */
113
+ timestamp: number;
114
+ }
115
+
116
+ /** Flight phases */
117
+ export type FlightPhase =
118
+ | 'parked'
119
+ | 'taxi_out'
120
+ | 'takeoff_roll'
121
+ | 'initial_climb'
122
+ | 'climb'
123
+ | 'cruise'
124
+ | 'descent'
125
+ | 'approach'
126
+ | 'final'
127
+ | 'landing_roll'
128
+ | 'taxi_in';
129
+
130
+ /** Flight phase change event */
131
+ export interface FlightPhaseEvent {
132
+ /** Current flight phase */
133
+ phase: FlightPhase;
134
+ /** Previous flight phase */
135
+ previous_phase: FlightPhase;
136
+ /** Current altitude above ground level (feet AGL) */
137
+ altitude_agl: number;
138
+ /** Current altitude mean sea level (feet MSL) */
139
+ altitude_msl: number;
140
+ /** Current indicated airspeed (knots) */
141
+ speed: number;
142
+ /** Event timestamp (ms since epoch) */
143
+ timestamp: number;
144
+ }
145
+
146
+ export interface Listener {
147
+ /**
148
+ * Subscribe to telemetry update events
149
+ * @param event Event name ('update')
150
+ * @param callback Callback function receiving update data
151
+ */
152
+ on<T = Record<string, unknown>, R = Record<string, unknown>>(
153
+ event: 'update',
154
+ callback: (evt: UpdateEvent<T, R>) => void
155
+ ): void;
156
+
157
+ /**
158
+ * Subscribe to landing events
159
+ * @param event Event name ('landing')
160
+ * @param callback Callback function receiving landing data
161
+ */
162
+ on(event: 'landing', callback: (evt: LandingEvent) => void): void;
163
+
164
+ /**
165
+ * Subscribe to takeoff events
166
+ * @param event Event name ('takeoff')
167
+ * @param callback Callback function receiving takeoff data
168
+ */
169
+ on(event: 'takeoff', callback: (evt: TakeoffEvent) => void): void;
170
+
171
+ /**
172
+ * Subscribe to flight phase change events
173
+ * @param event Event name ('flight_phase')
174
+ * @param callback Callback function receiving flight phase data
175
+ */
176
+ on(event: 'flight_phase', callback: (evt: FlightPhaseEvent) => void): void;
177
+
178
+ /**
179
+ * Unsubscribe a callback from telemetry update events
180
+ */
181
+ off<T = Record<string, unknown>, R = Record<string, unknown>>(
182
+ event: 'update',
183
+ callback: (evt: UpdateEvent<T, R>) => void
184
+ ): void;
185
+
186
+ /**
187
+ * Unsubscribe a callback from landing events
188
+ */
189
+ off(event: 'landing', callback: (evt: LandingEvent) => void): void;
190
+
191
+ /**
192
+ * Unsubscribe a callback from takeoff events
193
+ */
194
+ off(event: 'takeoff', callback: (evt: TakeoffEvent) => void): void;
195
+
196
+ /**
197
+ * Unsubscribe a callback from flight phase change events
198
+ */
199
+ off(event: 'flight_phase', callback: (evt: FlightPhaseEvent) => void): void;
200
+
201
+ /**
202
+ * Send a command to the broadcaster (game client)
203
+ * Commands are sent as canonical names; the game client handles game-specific translation.
204
+ * @param command The canonical command name (e.g., 'gear_up', 'set_autopilot_heading')
205
+ * @param value The value to set (optional for toggle commands)
206
+ */
207
+ sendCommand(command: string, value?: unknown): Promise<CommandResult>;
208
+
209
+ /**
210
+ * Subscribe to additional fields dynamically
211
+ * @param fields Array of field names to add
212
+ */
213
+ subscribe(fields: string[]): Promise<CommandResult>;
214
+
215
+ /**
216
+ * Unsubscribe from specific fields
217
+ * @param fields Array of field names to remove
218
+ */
219
+ unsubscribe(fields: string[]): Promise<CommandResult>;
220
+
221
+ /**
222
+ * Get the current list of subscribed fields
223
+ * @returns Array of field names, or null if receiving all fields
224
+ */
225
+ getFields(): string[] | null;
226
+ }
227
+
228
+ export interface PresenceListener {
229
+ /**
230
+ * Subscribe to presence update events
231
+ * @param event Event name ('update')
232
+ * @param callback Callback function receiving presence snapshot
233
+ */
234
+ on<T = Record<string, unknown>, R = Record<string, unknown>>(
235
+ event: 'update',
236
+ callback: (snapshot: PresenceSnapshot<T, R>) => void
237
+ ): void;
238
+
239
+ /**
240
+ * Subscribe to presence removal events
241
+ * @param event Event name ('remove')
242
+ * @param callback Callback function receiving removed userId
243
+ */
244
+ on(event: 'remove', callback: (evt: { userId: string }) => void): void;
245
+
246
+ /**
247
+ * Subscribe to connection events
248
+ */
249
+ on(event: 'connect', callback: () => void): void;
250
+ on(event: 'disconnect', callback: (reason?: string) => void): void;
251
+
252
+ /**
253
+ * Unsubscribe a callback from presence update events
254
+ */
255
+ off<T = Record<string, unknown>, R = Record<string, unknown>>(
256
+ event: 'update',
257
+ callback: (snapshot: PresenceSnapshot<T, R>) => void
258
+ ): void;
259
+
260
+ /**
261
+ * Unsubscribe a callback from presence removal events
262
+ */
263
+ off(event: 'remove', callback: (evt: { userId: string }) => void): void;
264
+
265
+ /**
266
+ * Unsubscribe from connection events
267
+ */
268
+ off(event: 'connect', callback: () => void): void;
269
+ off(event: 'disconnect', callback: (reason?: string) => void): void;
270
+
271
+ /**
272
+ * Get current list of broadcasters
273
+ */
274
+ getBroadcasters<T = Record<string, unknown>, R = Record<string, unknown>>(): PresenceSnapshot<T, R>[];
275
+
276
+ /**
277
+ * Disconnect the presence socket
278
+ */
279
+ disconnect(): void;
280
+ }
281
+
282
+ export interface LogoutOptions {
283
+ /** If false, only clears local tokens without redirecting to Keycloak logout */
284
+ redirect?: boolean;
285
+ }
286
+
287
+ export class GameGlue {
288
+ constructor(config: GameGlueConfig);
289
+
290
+ /**
291
+ * Check if user is authenticated.
292
+ * If OAuth callback params are in URL, processes them first.
293
+ */
294
+ isAuthenticated(): Promise<boolean>;
295
+
296
+ /**
297
+ * Redirect to OAuth login page.
298
+ * Does not return - navigates away.
299
+ */
300
+ login(): void;
301
+
302
+ /**
303
+ * Log out the user.
304
+ * Clears local tokens and optionally redirects to Keycloak logout.
305
+ */
306
+ logout(options?: LogoutOptions): void;
307
+
308
+ /**
309
+ * Get the current user's ID.
310
+ * @throws Error if not authenticated
311
+ */
312
+ getUser(): string;
313
+
314
+ /**
315
+ * Get the access token for API calls.
316
+ */
317
+ getAccessToken(): string | undefined;
318
+
319
+ /**
320
+ * Create a listener for game telemetry.
321
+ * Connects to socket server lazily on first call.
322
+ */
323
+ createListener(config: ListenerConfig): Promise<Listener>;
324
+
325
+ /**
326
+ * Create a presence listener for public broadcaster updates.
327
+ * Does not require authentication.
328
+ */
329
+ createPresenceListener(config: PresenceListenerConfig): Promise<PresenceListener>;
330
+
331
+ /**
332
+ * Register callback for token refresh events.
333
+ */
334
+ onTokenRefreshed(callback: (token: string) => void): void;
335
+ }
336
+
337
+ export default GameGlue;
338
+ }