gameglue 4.0.1 → 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.
- package/LICENSE +21 -21
- package/README.md +275 -275
- package/babel.config.cjs +5 -5
- package/coverage/auth.js.html +525 -525
- package/coverage/base.css +224 -224
- package/coverage/block-navigation.js +87 -87
- package/coverage/favicon.png +0 -0
- package/coverage/index.html +175 -175
- package/coverage/index.js.html +309 -309
- package/coverage/lcov-report/auth.js.html +525 -525
- package/coverage/lcov-report/base.css +224 -224
- package/coverage/lcov-report/block-navigation.js +87 -87
- package/coverage/lcov-report/favicon.png +0 -0
- package/coverage/lcov-report/index.html +175 -175
- package/coverage/lcov-report/index.js.html +309 -309
- package/coverage/lcov-report/listener.js.html +528 -528
- package/coverage/lcov-report/prettify.css +1 -1
- package/coverage/lcov-report/prettify.js +2 -2
- package/coverage/lcov-report/sort-arrow-sprite.png +0 -0
- package/coverage/lcov-report/sorter.js +210 -210
- package/coverage/lcov-report/user.js.html +117 -117
- package/coverage/lcov-report/utils.js.html +117 -117
- package/coverage/lcov.info +391 -391
- package/coverage/listener.js.html +528 -528
- package/coverage/prettify.css +1 -1
- package/coverage/prettify.js +2 -2
- package/coverage/sort-arrow-sprite.png +0 -0
- package/coverage/sorter.js +210 -210
- package/coverage/user.js.html +117 -117
- package/coverage/utils.js.html +117 -117
- package/dist/gg.cjs.js +1 -1
- package/dist/gg.cjs.js.map +1 -1
- package/dist/gg.esm.js +1 -1
- package/dist/gg.esm.js.map +1 -1
- package/dist/gg.umd.js +1 -1
- package/dist/gg.umd.js.map +1 -1
- package/examples/certs/cert.pem +19 -19
- package/examples/certs/key.pem +28 -28
- package/examples/flight-dashboard.html +431 -431
- package/examples/server.js +99 -99
- package/examples/telemetry-validator.html +1410 -1410
- package/jest.config.cjs +33 -33
- package/package.json +56 -56
- package/rollup.config.js +57 -57
- package/src/auth.js +255 -255
- package/src/auth.spec.js +481 -481
- package/src/index.js +168 -168
- package/src/listener.js +196 -196
- package/src/listener.spec.js +598 -598
- package/src/presence_listener.js +112 -112
- package/src/test/fixtures.js +106 -106
- package/src/test/setup.js +51 -51
- package/src/utils.js +63 -63
- package/src/utils.spec.js +78 -78
- package/types/index.d.ts +338 -338
- 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
|
+
}
|