@playcademy/sdk 0.1.14 → 0.1.16
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/README.md +38 -1
- package/dist/index.d.ts +886 -340
- package/dist/index.js +405 -117
- package/dist/types.d.ts +185 -17
- package/package.json +3 -3
package/dist/index.d.ts
CHANGED
|
@@ -1,12 +1,250 @@
|
|
|
1
|
-
import
|
|
1
|
+
import { AUTH_PROVIDER_IDS } from '@playcademy/constants';
|
|
2
2
|
import { InferSelectModel } from 'drizzle-orm';
|
|
3
3
|
import * as drizzle_orm_pg_core from 'drizzle-orm/pg-core';
|
|
4
4
|
import * as drizzle_zod from 'drizzle-zod';
|
|
5
5
|
import { z } from 'zod';
|
|
6
|
+
import * as _playcademy_realtime_server_types from '@playcademy/realtime/server/types';
|
|
6
7
|
import * as _playcademy_timeback_types from '@playcademy/timeback/types';
|
|
7
8
|
import { OrganizationConfig, CourseConfig, ComponentConfig, ResourceConfig, ComponentResourceConfig } from '@playcademy/timeback/types';
|
|
8
9
|
import { SchemaInfo } from '@playcademy/cloudflare';
|
|
9
|
-
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* Base error class for Cademy SDK specific errors.
|
|
13
|
+
*/
|
|
14
|
+
declare class PlaycademyError extends Error {
|
|
15
|
+
constructor(message: string);
|
|
16
|
+
}
|
|
17
|
+
declare class ApiError extends Error {
|
|
18
|
+
status: number;
|
|
19
|
+
details: unknown;
|
|
20
|
+
constructor(status: number, message: string, details: unknown);
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* Extract useful error information from an API error
|
|
24
|
+
* Useful for displaying errors to users in a friendly way
|
|
25
|
+
*/
|
|
26
|
+
interface ApiErrorInfo {
|
|
27
|
+
status: number;
|
|
28
|
+
statusText: string;
|
|
29
|
+
error?: string;
|
|
30
|
+
message?: string;
|
|
31
|
+
details?: unknown;
|
|
32
|
+
}
|
|
33
|
+
declare function extractApiErrorInfo(error: unknown): ApiErrorInfo | null;
|
|
34
|
+
|
|
35
|
+
/**
|
|
36
|
+
* Connection monitoring types
|
|
37
|
+
*
|
|
38
|
+
* Type definitions for connection state, configuration, and callbacks.
|
|
39
|
+
*/
|
|
40
|
+
/**
|
|
41
|
+
* Possible connection states.
|
|
42
|
+
*
|
|
43
|
+
* - **online**: Connection is stable and healthy
|
|
44
|
+
* - **offline**: Complete loss of network connectivity
|
|
45
|
+
* - **degraded**: Connection is slow or experiencing intermittent issues
|
|
46
|
+
*/
|
|
47
|
+
type ConnectionState = 'online' | 'offline' | 'degraded';
|
|
48
|
+
/**
|
|
49
|
+
* Configuration options for ConnectionMonitor.
|
|
50
|
+
*
|
|
51
|
+
* @see {@link ConnectionMonitor} for usage
|
|
52
|
+
*/
|
|
53
|
+
interface ConnectionMonitorConfig {
|
|
54
|
+
/** Base URL for heartbeat pings (e.g., 'https://api.playcademy.com') */
|
|
55
|
+
baseUrl: string;
|
|
56
|
+
/** How often to send heartbeat pings in milliseconds (default: 10000) */
|
|
57
|
+
heartbeatInterval?: number;
|
|
58
|
+
/** How long to wait for heartbeat response in milliseconds (default: 5000) */
|
|
59
|
+
heartbeatTimeout?: number;
|
|
60
|
+
/** Number of consecutive failures before triggering disconnect (default: 2) */
|
|
61
|
+
failureThreshold?: number;
|
|
62
|
+
/** Enable periodic heartbeat monitoring (default: true) */
|
|
63
|
+
enableHeartbeat?: boolean;
|
|
64
|
+
/** Enable browser online/offline event listeners (default: true) */
|
|
65
|
+
enableOfflineEvents?: boolean;
|
|
66
|
+
}
|
|
67
|
+
/**
|
|
68
|
+
* Callback function signature for connection state changes.
|
|
69
|
+
*
|
|
70
|
+
* @param state - The new connection state
|
|
71
|
+
* @param reason - Human-readable reason for the state change
|
|
72
|
+
*/
|
|
73
|
+
type ConnectionChangeCallback = (state: ConnectionState, reason: string) => void;
|
|
74
|
+
|
|
75
|
+
/**
|
|
76
|
+
* Connection Monitor
|
|
77
|
+
*
|
|
78
|
+
* Monitors network connectivity using multiple signals:
|
|
79
|
+
* 1. navigator.onLine - Instant offline detection
|
|
80
|
+
* 2. Periodic heartbeat - Detects slow/degraded connections
|
|
81
|
+
* 3. Request failure tracking - Piggybacks on actual API calls
|
|
82
|
+
*
|
|
83
|
+
* Designed for school WiFi environments where connections may be
|
|
84
|
+
* unstable or degraded without fully disconnecting.
|
|
85
|
+
*/
|
|
86
|
+
|
|
87
|
+
/**
|
|
88
|
+
* Monitors network connectivity using multiple signals and notifies callbacks of state changes.
|
|
89
|
+
*
|
|
90
|
+
* The ConnectionMonitor uses a multi-signal approach to detect connection issues:
|
|
91
|
+
*
|
|
92
|
+
* 1. **navigator.onLine events** - Instant detection of hard disconnects
|
|
93
|
+
* 2. **Heartbeat pings** - Periodic checks to detect slow/degraded connections
|
|
94
|
+
* 3. **Request failure tracking** - Piggybacks on actual API calls
|
|
95
|
+
*
|
|
96
|
+
* This comprehensive approach ensures reliable detection across different network
|
|
97
|
+
* failure modes common in school WiFi environments (hard disconnect, slow connection,
|
|
98
|
+
* intermittent failures).
|
|
99
|
+
*
|
|
100
|
+
* @example
|
|
101
|
+
* ```typescript
|
|
102
|
+
* const monitor = new ConnectionMonitor({
|
|
103
|
+
* baseUrl: 'https://api.playcademy.com',
|
|
104
|
+
* heartbeatInterval: 10000, // Check every 10s
|
|
105
|
+
* failureThreshold: 2 // Trigger after 2 failures
|
|
106
|
+
* })
|
|
107
|
+
*
|
|
108
|
+
* monitor.onChange((state, reason) => {
|
|
109
|
+
* console.log(`Connection: ${state} - ${reason}`)
|
|
110
|
+
* })
|
|
111
|
+
*
|
|
112
|
+
* monitor.start()
|
|
113
|
+
* ```
|
|
114
|
+
*
|
|
115
|
+
* @see {@link ConnectionManagerConfig} for configuration options
|
|
116
|
+
*/
|
|
117
|
+
declare class ConnectionMonitor {
|
|
118
|
+
private state;
|
|
119
|
+
private callbacks;
|
|
120
|
+
private heartbeatInterval?;
|
|
121
|
+
private consecutiveFailures;
|
|
122
|
+
private isMonitoring;
|
|
123
|
+
private config;
|
|
124
|
+
/**
|
|
125
|
+
* Creates a new ConnectionMonitor instance.
|
|
126
|
+
*
|
|
127
|
+
* The monitor starts in a stopped state. Call `start()` to begin monitoring.
|
|
128
|
+
*
|
|
129
|
+
* @param config - Configuration options
|
|
130
|
+
* @param config.baseUrl - Base URL for heartbeat pings
|
|
131
|
+
* @param config.heartbeatInterval - How often to check (default: 10000ms)
|
|
132
|
+
* @param config.heartbeatTimeout - Request timeout (default: 5000ms)
|
|
133
|
+
* @param config.failureThreshold - Failures before triggering disconnect (default: 2)
|
|
134
|
+
* @param config.enableHeartbeat - Enable periodic checks (default: true)
|
|
135
|
+
* @param config.enableOfflineEvents - Listen to browser events (default: true)
|
|
136
|
+
*/
|
|
137
|
+
constructor(config: ConnectionMonitorConfig);
|
|
138
|
+
/**
|
|
139
|
+
* Starts monitoring the connection state.
|
|
140
|
+
*
|
|
141
|
+
* Sets up event listeners and begins heartbeat checks based on configuration.
|
|
142
|
+
* Idempotent - safe to call multiple times.
|
|
143
|
+
*/
|
|
144
|
+
start(): void;
|
|
145
|
+
/**
|
|
146
|
+
* Stops monitoring the connection state and cleans up resources.
|
|
147
|
+
*
|
|
148
|
+
* Removes event listeners and clears heartbeat intervals.
|
|
149
|
+
* Idempotent - safe to call multiple times.
|
|
150
|
+
*/
|
|
151
|
+
stop(): void;
|
|
152
|
+
/**
|
|
153
|
+
* Registers a callback to be notified of all connection state changes.
|
|
154
|
+
*
|
|
155
|
+
* The callback fires for all state transitions: online → offline,
|
|
156
|
+
* offline → degraded, degraded → online, etc.
|
|
157
|
+
*
|
|
158
|
+
* @param callback - Function called with (state, reason) when connection changes
|
|
159
|
+
* @returns Cleanup function to unregister the callback
|
|
160
|
+
*
|
|
161
|
+
* @example
|
|
162
|
+
* ```typescript
|
|
163
|
+
* const cleanup = monitor.onChange((state, reason) => {
|
|
164
|
+
* console.log(`Connection: ${state}`)
|
|
165
|
+
* if (state === 'offline') {
|
|
166
|
+
* showReconnectingUI()
|
|
167
|
+
* }
|
|
168
|
+
* })
|
|
169
|
+
*
|
|
170
|
+
* // Later: cleanup() to unregister
|
|
171
|
+
* ```
|
|
172
|
+
*/
|
|
173
|
+
onChange(callback: ConnectionChangeCallback): () => void;
|
|
174
|
+
/**
|
|
175
|
+
* Gets the current connection state.
|
|
176
|
+
*
|
|
177
|
+
* @returns The current state ('online', 'offline', or 'degraded')
|
|
178
|
+
*/
|
|
179
|
+
getState(): ConnectionState;
|
|
180
|
+
/**
|
|
181
|
+
* Manually triggers an immediate connection check.
|
|
182
|
+
*
|
|
183
|
+
* Forces a heartbeat ping to verify connectivity right now, bypassing
|
|
184
|
+
* the normal interval. Useful before critical operations.
|
|
185
|
+
*
|
|
186
|
+
* @returns Promise resolving to the current connection state after the check
|
|
187
|
+
*
|
|
188
|
+
* @example
|
|
189
|
+
* ```typescript
|
|
190
|
+
* const state = await monitor.checkNow()
|
|
191
|
+
* if (state !== 'online') {
|
|
192
|
+
* alert('Please check your internet connection')
|
|
193
|
+
* }
|
|
194
|
+
* ```
|
|
195
|
+
*/
|
|
196
|
+
checkNow(): Promise<ConnectionState>;
|
|
197
|
+
/**
|
|
198
|
+
* Reports a request failure for tracking.
|
|
199
|
+
*
|
|
200
|
+
* This should be called from your request wrapper whenever an API call fails.
|
|
201
|
+
* Only network errors are tracked (TypeError, fetch failures) - HTTP error
|
|
202
|
+
* responses (4xx, 5xx) are ignored.
|
|
203
|
+
*
|
|
204
|
+
* After consecutive failures exceed the threshold, the monitor transitions
|
|
205
|
+
* to 'degraded' or 'offline' state.
|
|
206
|
+
*
|
|
207
|
+
* @param error - The error from the failed request
|
|
208
|
+
*
|
|
209
|
+
* @example
|
|
210
|
+
* ```typescript
|
|
211
|
+
* try {
|
|
212
|
+
* await fetch('/api/data')
|
|
213
|
+
* } catch (error) {
|
|
214
|
+
* monitor.reportRequestFailure(error)
|
|
215
|
+
* throw error
|
|
216
|
+
* }
|
|
217
|
+
* ```
|
|
218
|
+
*/
|
|
219
|
+
reportRequestFailure(error: unknown): void;
|
|
220
|
+
/**
|
|
221
|
+
* Reports a successful request.
|
|
222
|
+
*
|
|
223
|
+
* This should be called from your request wrapper whenever an API call succeeds.
|
|
224
|
+
* Resets the consecutive failure counter and transitions from 'degraded' to
|
|
225
|
+
* 'online' if the connection has recovered.
|
|
226
|
+
*
|
|
227
|
+
* @example
|
|
228
|
+
* ```typescript
|
|
229
|
+
* try {
|
|
230
|
+
* const result = await fetch('/api/data')
|
|
231
|
+
* monitor.reportRequestSuccess()
|
|
232
|
+
* return result
|
|
233
|
+
* } catch (error) {
|
|
234
|
+
* monitor.reportRequestFailure(error)
|
|
235
|
+
* throw error
|
|
236
|
+
* }
|
|
237
|
+
* ```
|
|
238
|
+
*/
|
|
239
|
+
reportRequestSuccess(): void;
|
|
240
|
+
private _detectInitialState;
|
|
241
|
+
private _handleOnline;
|
|
242
|
+
private _handleOffline;
|
|
243
|
+
private _startHeartbeat;
|
|
244
|
+
private _performHeartbeat;
|
|
245
|
+
private _handleHeartbeatFailure;
|
|
246
|
+
private _setState;
|
|
247
|
+
}
|
|
10
248
|
|
|
11
249
|
declare const users: drizzle_orm_pg_core.PgTableWithColumns<{
|
|
12
250
|
name: "user";
|
|
@@ -3289,6 +3527,91 @@ type EndActivityResponse = {
|
|
|
3289
3527
|
xpAwarded: number;
|
|
3290
3528
|
};
|
|
3291
3529
|
|
|
3530
|
+
/**
|
|
3531
|
+
* OAuth 2.0 implementation for the Playcademy SDK
|
|
3532
|
+
*/
|
|
3533
|
+
|
|
3534
|
+
/**
|
|
3535
|
+
* Parses an OAuth state parameter to extract CSRF token and any encoded data.
|
|
3536
|
+
*
|
|
3537
|
+
* @param state - The OAuth state parameter to parse
|
|
3538
|
+
* @returns Object containing CSRF token and optional decoded data
|
|
3539
|
+
*/
|
|
3540
|
+
declare function parseOAuthState(state: string): {
|
|
3541
|
+
csrfToken: string;
|
|
3542
|
+
data?: Record<string, string>;
|
|
3543
|
+
};
|
|
3544
|
+
|
|
3545
|
+
/**
|
|
3546
|
+
* Response type for the realtime token API
|
|
3547
|
+
*/
|
|
3548
|
+
interface RealtimeTokenResponse {
|
|
3549
|
+
token: string;
|
|
3550
|
+
}
|
|
3551
|
+
|
|
3552
|
+
/**
|
|
3553
|
+
* Cache configuration types for runtime customization
|
|
3554
|
+
*/
|
|
3555
|
+
/**
|
|
3556
|
+
* Runtime configuration for TTL cache behavior
|
|
3557
|
+
*/
|
|
3558
|
+
interface TTLCacheConfig {
|
|
3559
|
+
/** Time-to-live in milliseconds. Set to 0 to disable caching for this call. */
|
|
3560
|
+
ttl?: number;
|
|
3561
|
+
/** Force refresh, bypassing cache */
|
|
3562
|
+
force?: boolean;
|
|
3563
|
+
/** Skip cache and fetch fresh data (alias for force) */
|
|
3564
|
+
skipCache?: boolean;
|
|
3565
|
+
}
|
|
3566
|
+
/**
|
|
3567
|
+
* Runtime configuration for cooldown cache behavior
|
|
3568
|
+
*/
|
|
3569
|
+
interface CooldownCacheConfig {
|
|
3570
|
+
/** Cooldown period in milliseconds. Set to 0 to disable cooldown for this call. */
|
|
3571
|
+
cooldown?: number;
|
|
3572
|
+
/** Force refresh, bypassing cooldown */
|
|
3573
|
+
force?: boolean;
|
|
3574
|
+
}
|
|
3575
|
+
|
|
3576
|
+
interface CharacterComponentsOptions {
|
|
3577
|
+
/**
|
|
3578
|
+
* Optional level filter for components
|
|
3579
|
+
* When provided, only components available at this level or below are returned
|
|
3580
|
+
*/
|
|
3581
|
+
level?: number;
|
|
3582
|
+
/**
|
|
3583
|
+
* Whether to bypass the cache and force a fresh API request
|
|
3584
|
+
* Default: false (use cache when available)
|
|
3585
|
+
*/
|
|
3586
|
+
skipCache?: boolean;
|
|
3587
|
+
}
|
|
3588
|
+
interface CreateCharacterData {
|
|
3589
|
+
bodyComponentId: string;
|
|
3590
|
+
eyesComponentId: string;
|
|
3591
|
+
hairstyleComponentId: string;
|
|
3592
|
+
outfitComponentId: string;
|
|
3593
|
+
}
|
|
3594
|
+
interface UpdateCharacterData {
|
|
3595
|
+
bodyComponentId?: string;
|
|
3596
|
+
eyesComponentId?: string;
|
|
3597
|
+
hairstyleComponentId?: string;
|
|
3598
|
+
outfitComponentId?: string;
|
|
3599
|
+
}
|
|
3600
|
+
|
|
3601
|
+
interface ScoreSubmission {
|
|
3602
|
+
id: string;
|
|
3603
|
+
score: number;
|
|
3604
|
+
achievedAt: Date;
|
|
3605
|
+
}
|
|
3606
|
+
|
|
3607
|
+
/**
|
|
3608
|
+
* Combined response type for summary method
|
|
3609
|
+
*/
|
|
3610
|
+
type XpSummaryResponse = {
|
|
3611
|
+
today: TodayXpResponse;
|
|
3612
|
+
total: TotalXpResponse;
|
|
3613
|
+
};
|
|
3614
|
+
|
|
3292
3615
|
/**
|
|
3293
3616
|
* @fileoverview Server SDK Type Definitions
|
|
3294
3617
|
*
|
|
@@ -3396,303 +3719,14 @@ interface BackendDeploymentBundle {
|
|
|
3396
3719
|
secrets?: Record<string, string>;
|
|
3397
3720
|
}
|
|
3398
3721
|
|
|
3399
|
-
|
|
3400
|
-
|
|
3401
|
-
|
|
3402
|
-
|
|
3403
|
-
|
|
3404
|
-
|
|
3405
|
-
|
|
3406
|
-
|
|
3407
|
-
}
|
|
3408
|
-
type AuthProviderType = (typeof AUTH_PROVIDER_IDS)[keyof typeof AUTH_PROVIDER_IDS];
|
|
3409
|
-
interface AuthOptions {
|
|
3410
|
-
/** The identity provider to use for authentication */
|
|
3411
|
-
provider: AuthProviderType;
|
|
3412
|
-
/** The OAuth callback URL where your server handles the callback */
|
|
3413
|
-
callbackUrl: string;
|
|
3414
|
-
/** Authentication mode - auto detects best option based on context */
|
|
3415
|
-
mode?: 'auto' | 'popup' | 'redirect';
|
|
3416
|
-
/** Callback for authentication state changes */
|
|
3417
|
-
onStateChange?: (state: AuthStateUpdate) => void;
|
|
3418
|
-
/** Custom OAuth configuration (for users embedding the SDK outside of the Playcademy platform) */
|
|
3419
|
-
oauth?: {
|
|
3420
|
-
clientId: string;
|
|
3421
|
-
authorizationEndpoint?: string;
|
|
3422
|
-
tokenEndpoint?: string;
|
|
3423
|
-
scope?: string;
|
|
3424
|
-
};
|
|
3425
|
-
/**
|
|
3426
|
-
* Optional custom data to encode in OAuth state parameter.
|
|
3427
|
-
* By default, the SDK automatically includes playcademy_user_id and game_id.
|
|
3428
|
-
* Use this to add additional custom data if needed.
|
|
3429
|
-
*/
|
|
3430
|
-
stateData?: Record<string, string>;
|
|
3431
|
-
}
|
|
3432
|
-
interface AuthStateUpdate {
|
|
3433
|
-
/** Current status of the authentication flow */
|
|
3434
|
-
status: 'opening_popup' | 'exchanging_token' | 'complete' | 'error';
|
|
3435
|
-
/** Human-readable message about the current state */
|
|
3436
|
-
message: string;
|
|
3437
|
-
/** Error details if status is 'error' */
|
|
3438
|
-
error?: Error;
|
|
3439
|
-
}
|
|
3440
|
-
interface AuthResult {
|
|
3441
|
-
/** Whether authentication was successful */
|
|
3442
|
-
success: boolean;
|
|
3443
|
-
/** User information if authentication was successful */
|
|
3444
|
-
user?: UserInfo;
|
|
3445
|
-
/** Error if authentication failed */
|
|
3446
|
-
error?: Error;
|
|
3447
|
-
}
|
|
3448
|
-
/**
|
|
3449
|
-
* Authentication state change event payload.
|
|
3450
|
-
* Used when authentication state changes in the application.
|
|
3451
|
-
*/
|
|
3452
|
-
interface AuthStateChangePayload {
|
|
3453
|
-
/** Whether the user is currently authenticated */
|
|
3454
|
-
authenticated: boolean;
|
|
3455
|
-
/** User information if authenticated, null otherwise */
|
|
3456
|
-
user: UserInfo | null;
|
|
3457
|
-
/** Error information if authentication failed */
|
|
3458
|
-
error: Error | null;
|
|
3459
|
-
}
|
|
3460
|
-
/**
|
|
3461
|
-
* OAuth callback event payload.
|
|
3462
|
-
* Used when OAuth flow completes in popup/new-tab windows.
|
|
3463
|
-
*/
|
|
3464
|
-
interface AuthCallbackPayload {
|
|
3465
|
-
/** OAuth authorization code */
|
|
3466
|
-
code: string;
|
|
3467
|
-
/** OAuth state parameter for CSRF protection */
|
|
3468
|
-
state: string;
|
|
3469
|
-
/** Error message if OAuth flow failed */
|
|
3470
|
-
error: string | null;
|
|
3471
|
-
}
|
|
3472
|
-
/**
|
|
3473
|
-
* Token refresh event payload.
|
|
3474
|
-
* Sent when authentication token is updated.
|
|
3475
|
-
*/
|
|
3476
|
-
interface TokenRefreshPayload {
|
|
3477
|
-
/** New authentication token */
|
|
3478
|
-
token: string;
|
|
3479
|
-
/** Token expiration timestamp */
|
|
3480
|
-
exp: number;
|
|
3481
|
-
}
|
|
3482
|
-
/**
|
|
3483
|
-
* Telemetry event payload.
|
|
3484
|
-
* Performance metrics sent from the game.
|
|
3485
|
-
*/
|
|
3486
|
-
interface TelemetryPayload {
|
|
3487
|
-
/** Frames per second */
|
|
3488
|
-
fps: number;
|
|
3489
|
-
/** Memory usage in MB */
|
|
3490
|
-
mem: number;
|
|
3491
|
-
}
|
|
3492
|
-
/**
|
|
3493
|
-
* Keyboard event payload.
|
|
3494
|
-
* Key events forwarded from the game.
|
|
3495
|
-
*/
|
|
3496
|
-
interface KeyEventPayload {
|
|
3497
|
-
/** Key value (e.g., 'Escape', 'F1') */
|
|
3498
|
-
key: string;
|
|
3499
|
-
/** Key code (optional) */
|
|
3500
|
-
code?: string;
|
|
3501
|
-
/** Event type */
|
|
3502
|
-
type: 'keydown' | 'keyup';
|
|
3503
|
-
}
|
|
3504
|
-
interface ClientEvents {
|
|
3505
|
-
authChange: {
|
|
3506
|
-
token: string | null;
|
|
3507
|
-
};
|
|
3508
|
-
inventoryChange: {
|
|
3509
|
-
itemId: string;
|
|
3510
|
-
delta: number;
|
|
3511
|
-
newTotal: number;
|
|
3512
|
-
};
|
|
3513
|
-
levelUp: {
|
|
3514
|
-
oldLevel: number;
|
|
3515
|
-
newLevel: number;
|
|
3516
|
-
creditsAwarded: number;
|
|
3517
|
-
};
|
|
3518
|
-
xpGained: {
|
|
3519
|
-
amount: number;
|
|
3520
|
-
totalXP: number;
|
|
3521
|
-
leveledUp: boolean;
|
|
3522
|
-
};
|
|
3523
|
-
}
|
|
3524
|
-
type GameContextPayload = {
|
|
3525
|
-
token: string;
|
|
3526
|
-
baseUrl: string;
|
|
3527
|
-
realtimeUrl: string;
|
|
3528
|
-
gameId: string;
|
|
3529
|
-
forwardKeys?: string[];
|
|
3530
|
-
};
|
|
3531
|
-
type LoginResponse = {
|
|
3532
|
-
token: string;
|
|
3533
|
-
};
|
|
3534
|
-
type GameTokenResponse = {
|
|
3535
|
-
token: string;
|
|
3536
|
-
exp: number;
|
|
3537
|
-
};
|
|
3538
|
-
type StartSessionResponse = {
|
|
3539
|
-
sessionId: string;
|
|
3540
|
-
};
|
|
3541
|
-
type InventoryMutationResponse = {
|
|
3542
|
-
newTotal: number;
|
|
3543
|
-
};
|
|
3544
|
-
type DevUploadEvent = {
|
|
3545
|
-
type: 'init';
|
|
3546
|
-
} | {
|
|
3547
|
-
type: 's3Progress';
|
|
3548
|
-
loaded: number;
|
|
3549
|
-
total: number;
|
|
3550
|
-
percent: number;
|
|
3551
|
-
} | {
|
|
3552
|
-
type: 'finalizeStart';
|
|
3553
|
-
} | {
|
|
3554
|
-
type: 'finalizeProgress';
|
|
3555
|
-
percent: number;
|
|
3556
|
-
currentFileLabel?: string;
|
|
3557
|
-
} | {
|
|
3558
|
-
type: 'finalizeStatus';
|
|
3559
|
-
message: string;
|
|
3560
|
-
} | {
|
|
3561
|
-
type: 'close';
|
|
3562
|
-
};
|
|
3563
|
-
type DevUploadHooks = {
|
|
3564
|
-
onEvent?: (e: DevUploadEvent) => void;
|
|
3565
|
-
onClose?: () => void;
|
|
3566
|
-
};
|
|
3567
|
-
/**
|
|
3568
|
-
* Better-auth API key creation response
|
|
3569
|
-
*/
|
|
3570
|
-
interface BetterAuthApiKeyResponse {
|
|
3571
|
-
apiKey: string;
|
|
3572
|
-
key: {
|
|
3573
|
-
id: string;
|
|
3574
|
-
name: string | null;
|
|
3575
|
-
expiresAt: string | null;
|
|
3576
|
-
createdAt: string;
|
|
3577
|
-
};
|
|
3578
|
-
}
|
|
3579
|
-
/**
|
|
3580
|
-
* Better-auth API key list item
|
|
3581
|
-
*/
|
|
3582
|
-
interface BetterAuthApiKey {
|
|
3583
|
-
id: string;
|
|
3584
|
-
name: string | null;
|
|
3585
|
-
start: string;
|
|
3586
|
-
enabled: boolean;
|
|
3587
|
-
expiresAt: string | null;
|
|
3588
|
-
createdAt: string;
|
|
3589
|
-
updatedAt: string;
|
|
3590
|
-
lastRequest: string | null;
|
|
3591
|
-
requestCount: number;
|
|
3592
|
-
}
|
|
3593
|
-
/**
|
|
3594
|
-
* Bucket file metadata
|
|
3595
|
-
*/
|
|
3596
|
-
interface BucketFile {
|
|
3597
|
-
key: string;
|
|
3598
|
-
size: number;
|
|
3599
|
-
uploaded: string;
|
|
3600
|
-
contentType?: string;
|
|
3601
|
-
}
|
|
3602
|
-
|
|
3603
|
-
/**
|
|
3604
|
-
* OAuth 2.0 implementation for the Playcademy SDK
|
|
3605
|
-
*/
|
|
3606
|
-
|
|
3607
|
-
/**
|
|
3608
|
-
* Parses an OAuth state parameter to extract CSRF token and any encoded data.
|
|
3609
|
-
*
|
|
3610
|
-
* @param state - The OAuth state parameter to parse
|
|
3611
|
-
* @returns Object containing CSRF token and optional decoded data
|
|
3612
|
-
*/
|
|
3613
|
-
declare function parseOAuthState(state: string): {
|
|
3614
|
-
csrfToken: string;
|
|
3615
|
-
data?: Record<string, string>;
|
|
3616
|
-
};
|
|
3617
|
-
|
|
3618
|
-
/**
|
|
3619
|
-
* Response type for the realtime token API
|
|
3620
|
-
*/
|
|
3621
|
-
interface RealtimeTokenResponse {
|
|
3622
|
-
token: string;
|
|
3623
|
-
}
|
|
3624
|
-
|
|
3625
|
-
/**
|
|
3626
|
-
* Cache configuration types for runtime customization
|
|
3627
|
-
*/
|
|
3628
|
-
/**
|
|
3629
|
-
* Runtime configuration for TTL cache behavior
|
|
3630
|
-
*/
|
|
3631
|
-
interface TTLCacheConfig {
|
|
3632
|
-
/** Time-to-live in milliseconds. Set to 0 to disable caching for this call. */
|
|
3633
|
-
ttl?: number;
|
|
3634
|
-
/** Force refresh, bypassing cache */
|
|
3635
|
-
force?: boolean;
|
|
3636
|
-
/** Skip cache and fetch fresh data (alias for force) */
|
|
3637
|
-
skipCache?: boolean;
|
|
3638
|
-
}
|
|
3639
|
-
/**
|
|
3640
|
-
* Runtime configuration for cooldown cache behavior
|
|
3641
|
-
*/
|
|
3642
|
-
interface CooldownCacheConfig {
|
|
3643
|
-
/** Cooldown period in milliseconds. Set to 0 to disable cooldown for this call. */
|
|
3644
|
-
cooldown?: number;
|
|
3645
|
-
/** Force refresh, bypassing cooldown */
|
|
3646
|
-
force?: boolean;
|
|
3647
|
-
}
|
|
3648
|
-
|
|
3649
|
-
interface CharacterComponentsOptions {
|
|
3650
|
-
/**
|
|
3651
|
-
* Optional level filter for components
|
|
3652
|
-
* When provided, only components available at this level or below are returned
|
|
3653
|
-
*/
|
|
3654
|
-
level?: number;
|
|
3655
|
-
/**
|
|
3656
|
-
* Whether to bypass the cache and force a fresh API request
|
|
3657
|
-
* Default: false (use cache when available)
|
|
3658
|
-
*/
|
|
3659
|
-
skipCache?: boolean;
|
|
3660
|
-
}
|
|
3661
|
-
interface CreateCharacterData {
|
|
3662
|
-
bodyComponentId: string;
|
|
3663
|
-
eyesComponentId: string;
|
|
3664
|
-
hairstyleComponentId: string;
|
|
3665
|
-
outfitComponentId: string;
|
|
3666
|
-
}
|
|
3667
|
-
interface UpdateCharacterData {
|
|
3668
|
-
bodyComponentId?: string;
|
|
3669
|
-
eyesComponentId?: string;
|
|
3670
|
-
hairstyleComponentId?: string;
|
|
3671
|
-
outfitComponentId?: string;
|
|
3672
|
-
}
|
|
3673
|
-
|
|
3674
|
-
interface ScoreSubmission {
|
|
3675
|
-
id: string;
|
|
3676
|
-
score: number;
|
|
3677
|
-
achievedAt: Date;
|
|
3678
|
-
}
|
|
3679
|
-
|
|
3680
|
-
/**
|
|
3681
|
-
* Combined response type for summary method
|
|
3682
|
-
*/
|
|
3683
|
-
type XpSummaryResponse = {
|
|
3684
|
-
today: TodayXpResponse;
|
|
3685
|
-
total: TotalXpResponse;
|
|
3686
|
-
};
|
|
3687
|
-
|
|
3688
|
-
interface UserScore {
|
|
3689
|
-
id: string;
|
|
3690
|
-
score: number;
|
|
3691
|
-
achievedAt: Date;
|
|
3692
|
-
metadata?: Record<string, unknown>;
|
|
3693
|
-
gameId: string;
|
|
3694
|
-
gameTitle: string;
|
|
3695
|
-
gameSlug: string;
|
|
3722
|
+
interface UserScore {
|
|
3723
|
+
id: string;
|
|
3724
|
+
score: number;
|
|
3725
|
+
achievedAt: Date;
|
|
3726
|
+
metadata?: Record<string, unknown>;
|
|
3727
|
+
gameId: string;
|
|
3728
|
+
gameTitle: string;
|
|
3729
|
+
gameSlug: string;
|
|
3696
3730
|
}
|
|
3697
3731
|
|
|
3698
3732
|
/**
|
|
@@ -3722,6 +3756,8 @@ interface UserScore {
|
|
|
3722
3756
|
declare function init(options?: {
|
|
3723
3757
|
baseUrl?: string;
|
|
3724
3758
|
allowedParentOrigins?: string[];
|
|
3759
|
+
onDisconnect?: DisconnectHandler;
|
|
3760
|
+
enableConnectionMonitoring?: boolean;
|
|
3725
3761
|
}): Promise<PlaycademyClient>;
|
|
3726
3762
|
|
|
3727
3763
|
/**
|
|
@@ -3775,6 +3811,7 @@ declare class PlaycademyClient {
|
|
|
3775
3811
|
private internalClientSessionId?;
|
|
3776
3812
|
private authContext?;
|
|
3777
3813
|
private initPayload?;
|
|
3814
|
+
private connectionManager?;
|
|
3778
3815
|
/**
|
|
3779
3816
|
* Creates a new PlaycademyClient instance.
|
|
3780
3817
|
*
|
|
@@ -3867,13 +3904,92 @@ declare class PlaycademyClient {
|
|
|
3867
3904
|
*/
|
|
3868
3905
|
onAuthChange(callback: (token: string | null) => void): void;
|
|
3869
3906
|
/**
|
|
3870
|
-
*
|
|
3871
|
-
*
|
|
3872
|
-
*
|
|
3873
|
-
|
|
3874
|
-
|
|
3875
|
-
|
|
3876
|
-
|
|
3907
|
+
* Registers a callback to be called when connection issues are detected.
|
|
3908
|
+
*
|
|
3909
|
+
* This is a convenience method that filters connection change events to only
|
|
3910
|
+
* fire when the connection degrades (offline or degraded states). Use this
|
|
3911
|
+
* when you want to handle disconnects without being notified of recoveries.
|
|
3912
|
+
*
|
|
3913
|
+
* For all connection state changes, use `client.on('connectionChange', ...)` instead.
|
|
3914
|
+
*
|
|
3915
|
+
* @param callback - Function to call when connection state changes to offline or degraded
|
|
3916
|
+
* @returns Cleanup function to unregister the callback
|
|
3917
|
+
*
|
|
3918
|
+
* @example
|
|
3919
|
+
* ```typescript
|
|
3920
|
+
* const cleanup = client.onDisconnect(({ state, reason, displayAlert }) => {
|
|
3921
|
+
* console.log(`Connection ${state}: ${reason}`)
|
|
3922
|
+
*
|
|
3923
|
+
* if (state === 'offline') {
|
|
3924
|
+
* // Save state and return to game lobby
|
|
3925
|
+
* displayAlert?.('Connection lost. Your progress has been saved.', { type: 'error' })
|
|
3926
|
+
* saveGameState()
|
|
3927
|
+
* returnToLobby()
|
|
3928
|
+
* } else if (state === 'degraded') {
|
|
3929
|
+
* displayAlert?.('Slow connection detected.', { type: 'warning' })
|
|
3930
|
+
* }
|
|
3931
|
+
* })
|
|
3932
|
+
*
|
|
3933
|
+
* // Later: cleanup() to unregister
|
|
3934
|
+
* ```
|
|
3935
|
+
*
|
|
3936
|
+
* @see {@link DISCONNECT_HANDLING.md} for detailed usage examples
|
|
3937
|
+
* @see {@link ConnectionManager.onDisconnect} for the underlying implementation
|
|
3938
|
+
*/
|
|
3939
|
+
onDisconnect(callback: (context: DisconnectContext) => void | Promise<void>): () => void;
|
|
3940
|
+
/**
|
|
3941
|
+
* Gets the current connection state.
|
|
3942
|
+
*
|
|
3943
|
+
* Returns the last known connection state without triggering a new check.
|
|
3944
|
+
* Use `checkConnection()` to force an immediate verification.
|
|
3945
|
+
*
|
|
3946
|
+
* @returns Current connection state ('online', 'offline', 'degraded') or 'unknown' if monitoring is disabled
|
|
3947
|
+
*
|
|
3948
|
+
* @example
|
|
3949
|
+
* ```typescript
|
|
3950
|
+
* const state = client.getConnectionState()
|
|
3951
|
+
* if (state === 'offline') {
|
|
3952
|
+
* console.log('No connection available')
|
|
3953
|
+
* }
|
|
3954
|
+
* ```
|
|
3955
|
+
*
|
|
3956
|
+
* @see {@link checkConnection} to trigger an immediate connection check
|
|
3957
|
+
* @see {@link ConnectionManager.getState} for the underlying implementation
|
|
3958
|
+
*/
|
|
3959
|
+
getConnectionState(): ConnectionState | 'unknown';
|
|
3960
|
+
/**
|
|
3961
|
+
* Manually triggers a connection check immediately.
|
|
3962
|
+
*
|
|
3963
|
+
* Forces a heartbeat ping to verify connectivity right now, bypassing the normal
|
|
3964
|
+
* interval. Useful when you need to verify connection status before a critical
|
|
3965
|
+
* operation (e.g., saving important game state).
|
|
3966
|
+
*
|
|
3967
|
+
* @returns Promise resolving to the current connection state after verification
|
|
3968
|
+
*
|
|
3969
|
+
* @example
|
|
3970
|
+
* ```typescript
|
|
3971
|
+
* // Check before critical operation
|
|
3972
|
+
* const state = await client.checkConnection()
|
|
3973
|
+
* if (state !== 'online') {
|
|
3974
|
+
* alert('Please check your internet connection before saving')
|
|
3975
|
+
* return
|
|
3976
|
+
* }
|
|
3977
|
+
*
|
|
3978
|
+
* await client.games.saveState(importantData)
|
|
3979
|
+
* ```
|
|
3980
|
+
*
|
|
3981
|
+
* @see {@link getConnectionState} to get the last known state without checking
|
|
3982
|
+
* @see {@link ConnectionManager.checkNow} for the underlying implementation
|
|
3983
|
+
*/
|
|
3984
|
+
checkConnection(): Promise<ConnectionState | 'unknown'>;
|
|
3985
|
+
/**
|
|
3986
|
+
* Sets the authentication context for the client.
|
|
3987
|
+
* This is called during initialization to store environment info.
|
|
3988
|
+
* @internal
|
|
3989
|
+
*/
|
|
3990
|
+
_setAuthContext(context: {
|
|
3991
|
+
isInIframe: boolean;
|
|
3992
|
+
}): void;
|
|
3877
3993
|
/**
|
|
3878
3994
|
* Registers an event listener for client events.
|
|
3879
3995
|
*
|
|
@@ -3928,6 +4044,11 @@ declare class PlaycademyClient {
|
|
|
3928
4044
|
* Safe to call in any environment - isInIframe handles browser detection.
|
|
3929
4045
|
*/
|
|
3930
4046
|
private _detectAuthContext;
|
|
4047
|
+
/**
|
|
4048
|
+
* Initializes connection monitoring if enabled.
|
|
4049
|
+
* Safe to call in any environment - only runs in browser.
|
|
4050
|
+
*/
|
|
4051
|
+
private _initializeConnectionMonitor;
|
|
3931
4052
|
/**
|
|
3932
4053
|
* Initializes an internal game session for automatic session management.
|
|
3933
4054
|
* Only starts a session if:
|
|
@@ -3995,7 +4116,7 @@ declare class PlaycademyClient {
|
|
|
3995
4116
|
}) => void) | (() => void) | ((isVisible: boolean) => void)) => void;
|
|
3996
4117
|
removeAllListeners: () => void;
|
|
3997
4118
|
getListenerCounts: () => Record<string, number>;
|
|
3998
|
-
|
|
4119
|
+
assets: {
|
|
3999
4120
|
url(pathOrStrings: string | TemplateStringsArray, ...values: unknown[]): string;
|
|
4000
4121
|
fetch: (path: string, options?: RequestInit) => Promise<Response>;
|
|
4001
4122
|
json: <T = unknown>(path: string) => Promise<T>;
|
|
@@ -4129,50 +4250,50 @@ declare class PlaycademyClient {
|
|
|
4129
4250
|
};
|
|
4130
4251
|
items: {
|
|
4131
4252
|
create: (props: InsertItemInput) => Promise<{
|
|
4132
|
-
type: "accessory" | "currency" | "badge" | "trophy" | "collectible" | "consumable" | "unlock" | "upgrade" | "other";
|
|
4133
4253
|
id: string;
|
|
4134
|
-
metadata: unknown;
|
|
4135
|
-
slug: string;
|
|
4136
4254
|
createdAt: Date;
|
|
4137
4255
|
gameId: string | null;
|
|
4256
|
+
slug: string;
|
|
4138
4257
|
displayName: string;
|
|
4258
|
+
metadata: unknown;
|
|
4139
4259
|
description: string | null;
|
|
4260
|
+
type: "accessory" | "currency" | "badge" | "trophy" | "collectible" | "consumable" | "unlock" | "upgrade" | "other";
|
|
4140
4261
|
isPlaceable: boolean;
|
|
4141
4262
|
imageUrl: string | null;
|
|
4142
4263
|
}>;
|
|
4143
4264
|
get: (itemId: string) => Promise<{
|
|
4144
|
-
type: "accessory" | "currency" | "badge" | "trophy" | "collectible" | "consumable" | "unlock" | "upgrade" | "other";
|
|
4145
4265
|
id: string;
|
|
4146
|
-
metadata: unknown;
|
|
4147
|
-
slug: string;
|
|
4148
4266
|
createdAt: Date;
|
|
4149
4267
|
gameId: string | null;
|
|
4268
|
+
slug: string;
|
|
4150
4269
|
displayName: string;
|
|
4270
|
+
metadata: unknown;
|
|
4151
4271
|
description: string | null;
|
|
4272
|
+
type: "accessory" | "currency" | "badge" | "trophy" | "collectible" | "consumable" | "unlock" | "upgrade" | "other";
|
|
4152
4273
|
isPlaceable: boolean;
|
|
4153
4274
|
imageUrl: string | null;
|
|
4154
4275
|
}>;
|
|
4155
4276
|
list: () => Promise<{
|
|
4156
|
-
type: "accessory" | "currency" | "badge" | "trophy" | "collectible" | "consumable" | "unlock" | "upgrade" | "other";
|
|
4157
4277
|
id: string;
|
|
4158
|
-
metadata: unknown;
|
|
4159
|
-
slug: string;
|
|
4160
4278
|
createdAt: Date;
|
|
4161
4279
|
gameId: string | null;
|
|
4280
|
+
slug: string;
|
|
4162
4281
|
displayName: string;
|
|
4282
|
+
metadata: unknown;
|
|
4163
4283
|
description: string | null;
|
|
4284
|
+
type: "accessory" | "currency" | "badge" | "trophy" | "collectible" | "consumable" | "unlock" | "upgrade" | "other";
|
|
4164
4285
|
isPlaceable: boolean;
|
|
4165
4286
|
imageUrl: string | null;
|
|
4166
4287
|
}[]>;
|
|
4167
4288
|
update: (itemId: string, props: UpdateItemInput) => Promise<{
|
|
4168
|
-
type: "accessory" | "currency" | "badge" | "trophy" | "collectible" | "consumable" | "unlock" | "upgrade" | "other";
|
|
4169
4289
|
id: string;
|
|
4170
|
-
metadata: unknown;
|
|
4171
|
-
slug: string;
|
|
4172
4290
|
createdAt: Date;
|
|
4173
4291
|
gameId: string | null;
|
|
4292
|
+
slug: string;
|
|
4174
4293
|
displayName: string;
|
|
4294
|
+
metadata: unknown;
|
|
4175
4295
|
description: string | null;
|
|
4296
|
+
type: "accessory" | "currency" | "badge" | "trophy" | "collectible" | "consumable" | "unlock" | "upgrade" | "other";
|
|
4176
4297
|
isPlaceable: boolean;
|
|
4177
4298
|
imageUrl: string | null;
|
|
4178
4299
|
}>;
|
|
@@ -4307,9 +4428,7 @@ declare class PlaycademyClient {
|
|
|
4307
4428
|
}) => Promise<TodayXpResponse>;
|
|
4308
4429
|
total: () => Promise<TotalXpResponse>;
|
|
4309
4430
|
history: (options?: {
|
|
4310
|
-
startDate
|
|
4311
|
-
/** Auto-initializes a PlaycademyClient with context from the environment */
|
|
4312
|
-
?: string;
|
|
4431
|
+
startDate?: string;
|
|
4313
4432
|
endDate?: string;
|
|
4314
4433
|
}) => Promise<XpHistoryResponse>;
|
|
4315
4434
|
summary: (options?: {
|
|
@@ -4422,29 +4541,436 @@ declare class PlaycademyClient {
|
|
|
4422
4541
|
};
|
|
4423
4542
|
}
|
|
4424
4543
|
|
|
4544
|
+
type TokenType = 'session' | 'apiKey' | 'gameJwt';
|
|
4545
|
+
interface ClientConfig {
|
|
4546
|
+
baseUrl: string;
|
|
4547
|
+
gameUrl?: string;
|
|
4548
|
+
token?: string;
|
|
4549
|
+
tokenType?: TokenType;
|
|
4550
|
+
gameId?: string;
|
|
4551
|
+
autoStartSession?: boolean;
|
|
4552
|
+
onDisconnect?: DisconnectHandler;
|
|
4553
|
+
enableConnectionMonitoring?: boolean;
|
|
4554
|
+
}
|
|
4425
4555
|
/**
|
|
4426
|
-
*
|
|
4556
|
+
* Handler called when connection state changes to offline or degraded.
|
|
4557
|
+
* Games can implement this to handle disconnects gracefully.
|
|
4427
4558
|
*/
|
|
4428
|
-
|
|
4429
|
-
|
|
4559
|
+
type DisconnectHandler = (context: DisconnectContext) => void | Promise<void>;
|
|
4560
|
+
/**
|
|
4561
|
+
* Context provided to disconnect handlers
|
|
4562
|
+
*/
|
|
4563
|
+
interface DisconnectContext {
|
|
4564
|
+
/** Current connection state */
|
|
4565
|
+
state: 'offline' | 'degraded';
|
|
4566
|
+
/** Reason for the disconnect */
|
|
4567
|
+
reason: string;
|
|
4568
|
+
/** Timestamp when disconnect was detected */
|
|
4569
|
+
timestamp: number;
|
|
4570
|
+
/** Utility to display a platform-level alert */
|
|
4571
|
+
displayAlert: (message: string, options?: {
|
|
4572
|
+
type?: 'info' | 'warning' | 'error';
|
|
4573
|
+
duration?: number;
|
|
4574
|
+
}) => void;
|
|
4430
4575
|
}
|
|
4431
|
-
|
|
4432
|
-
|
|
4433
|
-
|
|
4434
|
-
|
|
4576
|
+
type AuthProviderType = (typeof AUTH_PROVIDER_IDS)[keyof typeof AUTH_PROVIDER_IDS];
|
|
4577
|
+
interface AuthOptions {
|
|
4578
|
+
/** The identity provider to use for authentication */
|
|
4579
|
+
provider: AuthProviderType;
|
|
4580
|
+
/** The OAuth callback URL where your server handles the callback */
|
|
4581
|
+
callbackUrl: string;
|
|
4582
|
+
/** Authentication mode - auto detects best option based on context */
|
|
4583
|
+
mode?: 'auto' | 'popup' | 'redirect';
|
|
4584
|
+
/** Callback for authentication state changes */
|
|
4585
|
+
onStateChange?: (state: AuthStateUpdate) => void;
|
|
4586
|
+
/** Custom OAuth configuration (for users embedding the SDK outside of the Playcademy platform) */
|
|
4587
|
+
oauth?: {
|
|
4588
|
+
clientId: string;
|
|
4589
|
+
authorizationEndpoint?: string;
|
|
4590
|
+
tokenEndpoint?: string;
|
|
4591
|
+
scope?: string;
|
|
4592
|
+
};
|
|
4593
|
+
/**
|
|
4594
|
+
* Optional custom data to encode in OAuth state parameter.
|
|
4595
|
+
* By default, the SDK automatically includes playcademy_user_id and game_id.
|
|
4596
|
+
* Use this to add additional custom data if needed.
|
|
4597
|
+
*/
|
|
4598
|
+
stateData?: Record<string, string>;
|
|
4599
|
+
}
|
|
4600
|
+
interface AuthStateUpdate {
|
|
4601
|
+
/** Current status of the authentication flow */
|
|
4602
|
+
status: 'opening_popup' | 'exchanging_token' | 'complete' | 'error';
|
|
4603
|
+
/** Human-readable message about the current state */
|
|
4604
|
+
message: string;
|
|
4605
|
+
/** Error details if status is 'error' */
|
|
4606
|
+
error?: Error;
|
|
4607
|
+
}
|
|
4608
|
+
interface AuthResult {
|
|
4609
|
+
/** Whether authentication was successful */
|
|
4610
|
+
success: boolean;
|
|
4611
|
+
/** User information if authentication was successful */
|
|
4612
|
+
user?: UserInfo;
|
|
4613
|
+
/** Error if authentication failed */
|
|
4614
|
+
error?: Error;
|
|
4435
4615
|
}
|
|
4436
4616
|
/**
|
|
4437
|
-
*
|
|
4438
|
-
*
|
|
4617
|
+
* Authentication state change event payload.
|
|
4618
|
+
* Used when authentication state changes in the application.
|
|
4439
4619
|
*/
|
|
4440
|
-
interface
|
|
4441
|
-
|
|
4442
|
-
|
|
4443
|
-
|
|
4444
|
-
|
|
4445
|
-
|
|
4620
|
+
interface AuthStateChangePayload {
|
|
4621
|
+
/** Whether the user is currently authenticated */
|
|
4622
|
+
authenticated: boolean;
|
|
4623
|
+
/** User information if authenticated, null otherwise */
|
|
4624
|
+
user: UserInfo | null;
|
|
4625
|
+
/** Error information if authentication failed */
|
|
4626
|
+
error: Error | null;
|
|
4627
|
+
}
|
|
4628
|
+
/**
|
|
4629
|
+
* OAuth callback event payload.
|
|
4630
|
+
* Used when OAuth flow completes in popup/new-tab windows.
|
|
4631
|
+
*/
|
|
4632
|
+
interface AuthCallbackPayload {
|
|
4633
|
+
/** OAuth authorization code */
|
|
4634
|
+
code: string;
|
|
4635
|
+
/** OAuth state parameter for CSRF protection */
|
|
4636
|
+
state: string;
|
|
4637
|
+
/** Error message if OAuth flow failed */
|
|
4638
|
+
error: string | null;
|
|
4639
|
+
}
|
|
4640
|
+
/**
|
|
4641
|
+
* Token refresh event payload.
|
|
4642
|
+
* Sent when authentication token is updated.
|
|
4643
|
+
*/
|
|
4644
|
+
interface TokenRefreshPayload {
|
|
4645
|
+
/** New authentication token */
|
|
4646
|
+
token: string;
|
|
4647
|
+
/** Token expiration timestamp */
|
|
4648
|
+
exp: number;
|
|
4649
|
+
}
|
|
4650
|
+
/**
|
|
4651
|
+
* Telemetry event payload.
|
|
4652
|
+
* Performance metrics sent from the game.
|
|
4653
|
+
*/
|
|
4654
|
+
interface TelemetryPayload {
|
|
4655
|
+
/** Frames per second */
|
|
4656
|
+
fps: number;
|
|
4657
|
+
/** Memory usage in MB */
|
|
4658
|
+
mem: number;
|
|
4659
|
+
}
|
|
4660
|
+
/**
|
|
4661
|
+
* Keyboard event payload.
|
|
4662
|
+
* Key events forwarded from the game.
|
|
4663
|
+
*/
|
|
4664
|
+
interface KeyEventPayload {
|
|
4665
|
+
/** Key value (e.g., 'Escape', 'F1') */
|
|
4666
|
+
key: string;
|
|
4667
|
+
/** Key code (optional) */
|
|
4668
|
+
code?: string;
|
|
4669
|
+
/** Event type */
|
|
4670
|
+
type: 'keydown' | 'keyup';
|
|
4671
|
+
}
|
|
4672
|
+
interface DisplayAlertPayload {
|
|
4673
|
+
message: string;
|
|
4674
|
+
options?: {
|
|
4675
|
+
type?: 'info' | 'warning' | 'error';
|
|
4676
|
+
duration?: number;
|
|
4677
|
+
};
|
|
4678
|
+
}
|
|
4679
|
+
/**
|
|
4680
|
+
* Display alert payload.
|
|
4681
|
+
* Request from game to show platform-level alert.
|
|
4682
|
+
*/
|
|
4683
|
+
interface DisplayAlertPayload {
|
|
4684
|
+
message: string;
|
|
4685
|
+
options?: {
|
|
4686
|
+
type?: 'info' | 'warning' | 'error';
|
|
4687
|
+
duration?: number;
|
|
4688
|
+
};
|
|
4689
|
+
}
|
|
4690
|
+
/**
|
|
4691
|
+
* Connection state payload.
|
|
4692
|
+
* Broadcast from platform to games when connection changes.
|
|
4693
|
+
*/
|
|
4694
|
+
interface ConnectionStatePayload {
|
|
4695
|
+
state: 'online' | 'offline' | 'degraded';
|
|
4696
|
+
reason: string;
|
|
4697
|
+
}
|
|
4698
|
+
interface ClientEvents {
|
|
4699
|
+
authChange: {
|
|
4700
|
+
token: string | null;
|
|
4701
|
+
};
|
|
4702
|
+
inventoryChange: {
|
|
4703
|
+
itemId: string;
|
|
4704
|
+
delta: number;
|
|
4705
|
+
newTotal: number;
|
|
4706
|
+
};
|
|
4707
|
+
levelUp: {
|
|
4708
|
+
oldLevel: number;
|
|
4709
|
+
newLevel: number;
|
|
4710
|
+
creditsAwarded: number;
|
|
4711
|
+
};
|
|
4712
|
+
xpGained: {
|
|
4713
|
+
amount: number;
|
|
4714
|
+
totalXP: number;
|
|
4715
|
+
leveledUp: boolean;
|
|
4716
|
+
};
|
|
4717
|
+
connectionChange: {
|
|
4718
|
+
state: 'online' | 'offline' | 'degraded';
|
|
4719
|
+
reason: string;
|
|
4720
|
+
};
|
|
4721
|
+
}
|
|
4722
|
+
type GameContextPayload = {
|
|
4723
|
+
token: string;
|
|
4724
|
+
baseUrl: string;
|
|
4725
|
+
realtimeUrl: string;
|
|
4726
|
+
gameId: string;
|
|
4727
|
+
forwardKeys?: string[];
|
|
4728
|
+
};
|
|
4729
|
+
type LoginResponse = {
|
|
4730
|
+
token: string;
|
|
4731
|
+
};
|
|
4732
|
+
type GameTokenResponse = {
|
|
4733
|
+
token: string;
|
|
4734
|
+
exp: number;
|
|
4735
|
+
};
|
|
4736
|
+
type StartSessionResponse = {
|
|
4737
|
+
sessionId: string;
|
|
4738
|
+
};
|
|
4739
|
+
type InventoryMutationResponse = {
|
|
4740
|
+
newTotal: number;
|
|
4741
|
+
};
|
|
4742
|
+
type DevUploadEvent = {
|
|
4743
|
+
type: 'init';
|
|
4744
|
+
} | {
|
|
4745
|
+
type: 's3Progress';
|
|
4746
|
+
loaded: number;
|
|
4747
|
+
total: number;
|
|
4748
|
+
percent: number;
|
|
4749
|
+
} | {
|
|
4750
|
+
type: 'finalizeStart';
|
|
4751
|
+
} | {
|
|
4752
|
+
type: 'finalizeProgress';
|
|
4753
|
+
percent: number;
|
|
4754
|
+
currentFileLabel?: string;
|
|
4755
|
+
} | {
|
|
4756
|
+
type: 'finalizeStatus';
|
|
4757
|
+
message: string;
|
|
4758
|
+
} | {
|
|
4759
|
+
type: 'close';
|
|
4760
|
+
};
|
|
4761
|
+
type DevUploadHooks = {
|
|
4762
|
+
onEvent?: (e: DevUploadEvent) => void;
|
|
4763
|
+
onClose?: () => void;
|
|
4764
|
+
};
|
|
4765
|
+
/**
|
|
4766
|
+
* Better-auth API key creation response
|
|
4767
|
+
*/
|
|
4768
|
+
interface BetterAuthApiKeyResponse {
|
|
4769
|
+
apiKey: string;
|
|
4770
|
+
key: {
|
|
4771
|
+
id: string;
|
|
4772
|
+
name: string | null;
|
|
4773
|
+
expiresAt: string | null;
|
|
4774
|
+
createdAt: string;
|
|
4775
|
+
};
|
|
4776
|
+
}
|
|
4777
|
+
/**
|
|
4778
|
+
* Better-auth API key list item
|
|
4779
|
+
*/
|
|
4780
|
+
interface BetterAuthApiKey {
|
|
4781
|
+
id: string;
|
|
4782
|
+
name: string | null;
|
|
4783
|
+
start: string;
|
|
4784
|
+
enabled: boolean;
|
|
4785
|
+
expiresAt: string | null;
|
|
4786
|
+
createdAt: string;
|
|
4787
|
+
updatedAt: string;
|
|
4788
|
+
lastRequest: string | null;
|
|
4789
|
+
requestCount: number;
|
|
4790
|
+
}
|
|
4791
|
+
/**
|
|
4792
|
+
* Bucket file metadata
|
|
4793
|
+
*/
|
|
4794
|
+
interface BucketFile {
|
|
4795
|
+
key: string;
|
|
4796
|
+
size: number;
|
|
4797
|
+
uploaded: string;
|
|
4798
|
+
contentType?: string;
|
|
4799
|
+
}
|
|
4800
|
+
|
|
4801
|
+
/**
|
|
4802
|
+
* Connection Manager
|
|
4803
|
+
*
|
|
4804
|
+
* Manages connection monitoring and integrates it with the Playcademy client.
|
|
4805
|
+
* Handles event wiring, state management, and disconnect callbacks.
|
|
4806
|
+
*
|
|
4807
|
+
* In iframe mode, disables local monitoring and listens to platform connection
|
|
4808
|
+
* state broadcasts instead (avoids duplicate heartbeats).
|
|
4809
|
+
*/
|
|
4810
|
+
|
|
4811
|
+
/**
|
|
4812
|
+
* Configuration for the ConnectionManager.
|
|
4813
|
+
*/
|
|
4814
|
+
interface ConnectionManagerConfig {
|
|
4815
|
+
/** Base URL for API requests (used for heartbeat pings) */
|
|
4816
|
+
baseUrl: string;
|
|
4817
|
+
/** Authentication context (iframe vs standalone) for alert routing */
|
|
4818
|
+
authContext?: {
|
|
4819
|
+
isInIframe: boolean;
|
|
4820
|
+
};
|
|
4821
|
+
/** Handler to call when connection issues are detected */
|
|
4822
|
+
onDisconnect?: DisconnectHandler;
|
|
4823
|
+
/** Callback to emit connection change events to the client */
|
|
4824
|
+
onConnectionChange?: (state: ConnectionState, reason: string) => void;
|
|
4825
|
+
}
|
|
4826
|
+
/**
|
|
4827
|
+
* Manages connection monitoring for the Playcademy client.
|
|
4828
|
+
*
|
|
4829
|
+
* The ConnectionManager serves as an integration layer between the low-level
|
|
4830
|
+
* ConnectionMonitor and the PlaycademyClient. It handles:
|
|
4831
|
+
* - Event wiring and coordination
|
|
4832
|
+
* - Disconnect callbacks with context
|
|
4833
|
+
* - Platform-level alert integration
|
|
4834
|
+
* - Request success/failure tracking
|
|
4835
|
+
*
|
|
4836
|
+
* This class is used internally by PlaycademyClient and typically not
|
|
4837
|
+
* instantiated directly by game developers.
|
|
4838
|
+
*
|
|
4839
|
+
* @see {@link ConnectionMonitor} for the underlying monitoring implementation
|
|
4840
|
+
* @see {@link PlaycademyClient.onDisconnect} for the public API
|
|
4841
|
+
*/
|
|
4842
|
+
declare class ConnectionManager {
|
|
4843
|
+
private monitor?;
|
|
4844
|
+
private authContext?;
|
|
4845
|
+
private disconnectHandler?;
|
|
4846
|
+
private connectionChangeCallback?;
|
|
4847
|
+
private currentState;
|
|
4848
|
+
private additionalDisconnectHandlers;
|
|
4849
|
+
/**
|
|
4850
|
+
* Creates a new ConnectionManager instance.
|
|
4851
|
+
*
|
|
4852
|
+
* @param config - Configuration options for the manager
|
|
4853
|
+
*
|
|
4854
|
+
* @example
|
|
4855
|
+
* ```typescript
|
|
4856
|
+
* const manager = new ConnectionManager({
|
|
4857
|
+
* baseUrl: 'https://api.playcademy.com',
|
|
4858
|
+
* authContext: { isInIframe: false },
|
|
4859
|
+
* onDisconnect: (context) => {
|
|
4860
|
+
* console.log(`Disconnected: ${context.state}`)
|
|
4861
|
+
* },
|
|
4862
|
+
* onConnectionChange: (state, reason) => {
|
|
4863
|
+
* console.log(`Connection changed: ${state}`)
|
|
4864
|
+
* }
|
|
4865
|
+
* })
|
|
4866
|
+
* ```
|
|
4867
|
+
*/
|
|
4868
|
+
constructor(config: ConnectionManagerConfig);
|
|
4869
|
+
/**
|
|
4870
|
+
* Gets the current connection state.
|
|
4871
|
+
*
|
|
4872
|
+
* @returns The current connection state ('online', 'offline', or 'degraded')
|
|
4873
|
+
*
|
|
4874
|
+
* @example
|
|
4875
|
+
* ```typescript
|
|
4876
|
+
* const state = manager.getState()
|
|
4877
|
+
* if (state === 'offline') {
|
|
4878
|
+
* console.log('No connection')
|
|
4879
|
+
* }
|
|
4880
|
+
* ```
|
|
4881
|
+
*/
|
|
4882
|
+
getState(): ConnectionState;
|
|
4883
|
+
/**
|
|
4884
|
+
* Manually triggers a connection check immediately.
|
|
4885
|
+
*
|
|
4886
|
+
* Forces a heartbeat ping to verify the current connection status.
|
|
4887
|
+
* Useful when you need to check connectivity before a critical operation.
|
|
4888
|
+
*
|
|
4889
|
+
* In iframe mode, this returns the last known state from platform.
|
|
4890
|
+
*
|
|
4891
|
+
* @returns Promise resolving to the current connection state
|
|
4892
|
+
*
|
|
4893
|
+
* @example
|
|
4894
|
+
* ```typescript
|
|
4895
|
+
* const state = await manager.checkNow()
|
|
4896
|
+
* if (state === 'online') {
|
|
4897
|
+
* await performCriticalOperation()
|
|
4898
|
+
* }
|
|
4899
|
+
* ```
|
|
4900
|
+
*/
|
|
4901
|
+
checkNow(): Promise<ConnectionState>;
|
|
4902
|
+
/**
|
|
4903
|
+
* Reports a successful API request to the connection monitor.
|
|
4904
|
+
*
|
|
4905
|
+
* This resets the consecutive failure counter and transitions from
|
|
4906
|
+
* 'degraded' to 'online' state if applicable.
|
|
4907
|
+
*
|
|
4908
|
+
* Typically called automatically by the SDK's request wrapper.
|
|
4909
|
+
* No-op in iframe mode (platform handles monitoring).
|
|
4910
|
+
*/
|
|
4911
|
+
reportRequestSuccess(): void;
|
|
4912
|
+
/**
|
|
4913
|
+
* Reports a failed API request to the connection monitor.
|
|
4914
|
+
*
|
|
4915
|
+
* Only network errors are tracked (not 4xx/5xx HTTP responses).
|
|
4916
|
+
* After consecutive failures exceed the threshold, the state transitions
|
|
4917
|
+
* to 'degraded' or 'offline'.
|
|
4918
|
+
*
|
|
4919
|
+
* Typically called automatically by the SDK's request wrapper.
|
|
4920
|
+
* No-op in iframe mode (platform handles monitoring).
|
|
4921
|
+
*
|
|
4922
|
+
* @param error - The error from the failed request
|
|
4923
|
+
*/
|
|
4924
|
+
reportRequestFailure(error: unknown): void;
|
|
4925
|
+
/**
|
|
4926
|
+
* Registers a callback to be called when connection issues are detected.
|
|
4927
|
+
*
|
|
4928
|
+
* The callback only fires for 'offline' and 'degraded' states, not when
|
|
4929
|
+
* recovering to 'online'. This provides a clean API for games to handle
|
|
4930
|
+
* disconnect scenarios without being notified of every state change.
|
|
4931
|
+
*
|
|
4932
|
+
* Works in both iframe and standalone modes transparently.
|
|
4933
|
+
*
|
|
4934
|
+
* @param callback - Function to call when connection degrades
|
|
4935
|
+
* @returns Cleanup function to unregister the callback
|
|
4936
|
+
*
|
|
4937
|
+
* @example
|
|
4938
|
+
* ```typescript
|
|
4939
|
+
* const cleanup = manager.onDisconnect(({ state, reason, displayAlert }) => {
|
|
4940
|
+
* if (state === 'offline') {
|
|
4941
|
+
* displayAlert?.('Connection lost. Saving your progress...', { type: 'error' })
|
|
4942
|
+
* saveGameState()
|
|
4943
|
+
* }
|
|
4944
|
+
* })
|
|
4945
|
+
*
|
|
4946
|
+
* // Later: cleanup() to unregister
|
|
4947
|
+
* ```
|
|
4948
|
+
*/
|
|
4949
|
+
onDisconnect(callback: DisconnectHandler): () => void;
|
|
4950
|
+
/**
|
|
4951
|
+
* Stops connection monitoring and performs cleanup.
|
|
4952
|
+
*
|
|
4953
|
+
* Removes event listeners and clears heartbeat intervals.
|
|
4954
|
+
* Should be called when the client is being destroyed.
|
|
4955
|
+
*/
|
|
4956
|
+
stop(): void;
|
|
4957
|
+
/**
|
|
4958
|
+
* Sets up listener for platform connection state broadcasts (iframe mode only).
|
|
4959
|
+
*/
|
|
4960
|
+
private _setupPlatformListener;
|
|
4961
|
+
/**
|
|
4962
|
+
* Handles connection state changes from the monitor or platform.
|
|
4963
|
+
*
|
|
4964
|
+
* Coordinates between:
|
|
4965
|
+
* 1. Emitting events to the client (for client.on('connectionChange'))
|
|
4966
|
+
* 2. Calling the disconnect handler if configured
|
|
4967
|
+
* 3. Calling any additional handlers registered via onDisconnect()
|
|
4968
|
+
*
|
|
4969
|
+
* @param state - The new connection state
|
|
4970
|
+
* @param reason - Human-readable reason for the state change
|
|
4971
|
+
*/
|
|
4972
|
+
private _handleConnectionChange;
|
|
4446
4973
|
}
|
|
4447
|
-
declare function extractApiErrorInfo(error: unknown): ApiErrorInfo | null;
|
|
4448
4974
|
|
|
4449
4975
|
/**
|
|
4450
4976
|
* @fileoverview Playcademy Messaging System
|
|
@@ -4527,6 +5053,14 @@ declare enum MessageEvents {
|
|
|
4527
5053
|
* Payload: boolean (true = show overlay, false = hide overlay)
|
|
4528
5054
|
*/
|
|
4529
5055
|
OVERLAY = "PLAYCADEMY_OVERLAY",
|
|
5056
|
+
/**
|
|
5057
|
+
* Broadcasts connection state changes to games.
|
|
5058
|
+
* Sent by platform when network connectivity changes.
|
|
5059
|
+
* Payload:
|
|
5060
|
+
* - `state`: 'online' | 'offline' | 'degraded'
|
|
5061
|
+
* - `reason`: string
|
|
5062
|
+
*/
|
|
5063
|
+
CONNECTION_STATE = "PLAYCADEMY_CONNECTION_STATE",
|
|
4530
5064
|
/**
|
|
4531
5065
|
* Game has finished loading and is ready to receive messages.
|
|
4532
5066
|
* Sent once after game initialization is complete.
|
|
@@ -4556,6 +5090,14 @@ declare enum MessageEvents {
|
|
|
4556
5090
|
* - `type`: 'keydown' | 'keyup'
|
|
4557
5091
|
*/
|
|
4558
5092
|
KEY_EVENT = "PLAYCADEMY_KEY_EVENT",
|
|
5093
|
+
/**
|
|
5094
|
+
* Game requests platform to display an alert.
|
|
5095
|
+
* Sent when connection issues are detected or other important events occur.
|
|
5096
|
+
* Payload:
|
|
5097
|
+
* - `message`: string
|
|
5098
|
+
* - `options`: { type?: 'info' | 'warning' | 'error', duration?: number }
|
|
5099
|
+
*/
|
|
5100
|
+
DISPLAY_ALERT = "PLAYCADEMY_DISPLAY_ALERT",
|
|
4559
5101
|
/**
|
|
4560
5102
|
* Notifies about authentication state changes.
|
|
4561
5103
|
* Can be sent in both directions depending on auth flow.
|
|
@@ -4611,6 +5153,8 @@ type MessageEventMap = {
|
|
|
4611
5153
|
[MessageEvents.FORCE_EXIT]: void;
|
|
4612
5154
|
/** Overlay visibility state (true = show, false = hide) */
|
|
4613
5155
|
[MessageEvents.OVERLAY]: boolean;
|
|
5156
|
+
/** Connection state change from platform */
|
|
5157
|
+
[MessageEvents.CONNECTION_STATE]: ConnectionStatePayload;
|
|
4614
5158
|
/** Ready message has no payload data */
|
|
4615
5159
|
[MessageEvents.READY]: void;
|
|
4616
5160
|
/** Exit message has no payload data */
|
|
@@ -4619,6 +5163,8 @@ type MessageEventMap = {
|
|
|
4619
5163
|
[MessageEvents.TELEMETRY]: TelemetryPayload;
|
|
4620
5164
|
/** Key event data */
|
|
4621
5165
|
[MessageEvents.KEY_EVENT]: KeyEventPayload;
|
|
5166
|
+
/** Display alert request from game */
|
|
5167
|
+
[MessageEvents.DISPLAY_ALERT]: DisplayAlertPayload;
|
|
4622
5168
|
/** Authentication state change notification */
|
|
4623
5169
|
[MessageEvents.AUTH_STATE_CHANGE]: AuthStateChangePayload;
|
|
4624
5170
|
/** OAuth callback data from popup/new-tab windows */
|
|
@@ -4990,5 +5536,5 @@ declare class PlaycademyMessaging {
|
|
|
4990
5536
|
*/
|
|
4991
5537
|
declare const messaging: PlaycademyMessaging;
|
|
4992
5538
|
|
|
4993
|
-
export { ApiError, MessageEvents, PlaycademyClient, PlaycademyError, extractApiErrorInfo, messaging };
|
|
4994
|
-
export type { ApiErrorInfo, DevUploadEvent, DevUploadHooks };
|
|
5539
|
+
export { ApiError, ConnectionManager, ConnectionMonitor, MessageEvents, PlaycademyClient, PlaycademyError, extractApiErrorInfo, messaging };
|
|
5540
|
+
export type { ApiErrorInfo, ConnectionMonitorConfig, ConnectionState, ConnectionStatePayload, DevUploadEvent, DevUploadHooks, DisconnectContext, DisconnectHandler, DisplayAlertPayload };
|