@playcademy/sdk 0.9.0 → 0.9.1-beta.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/README.md +5 -2
- package/dist/index.d.ts +408 -367
- package/dist/index.js +53 -3
- package/dist/internal.d.ts +5567 -5328
- package/dist/internal.js +89 -18
- package/dist/server/edge.d.ts +8 -0
- package/dist/server.d.ts +8 -0
- package/dist/types.d.ts +1228 -1186
- package/package.json +1 -1
package/dist/index.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
+
import { UserRole, AUTH_PROVIDER_IDS } from '@playcademy/constants';
|
|
1
2
|
import * as drizzle_orm_pg_core from 'drizzle-orm/pg-core';
|
|
2
|
-
import { AUTH_PROVIDER_IDS } from '@playcademy/constants';
|
|
3
3
|
|
|
4
4
|
/**
|
|
5
5
|
* Base error class for Cademy SDK specific errors.
|
|
@@ -384,6 +384,125 @@ interface RetryPolicy {
|
|
|
384
384
|
retryableMethods?: readonly Method[];
|
|
385
385
|
}
|
|
386
386
|
|
|
387
|
+
/**
|
|
388
|
+
* User Types
|
|
389
|
+
*
|
|
390
|
+
* Enums, DTOs and API response types. Database row types are in @playcademy/data/types.
|
|
391
|
+
*
|
|
392
|
+
* @module types/user
|
|
393
|
+
*/
|
|
394
|
+
|
|
395
|
+
type UserRoleEnumType = UserRole;
|
|
396
|
+
type DeveloperStatusEnumType = 'none' | 'pending' | 'approved';
|
|
397
|
+
type TimebackUserRole = 'administrator' | 'aide' | 'guardian' | 'parent' | 'proctor' | 'relative' | 'student' | 'teacher';
|
|
398
|
+
type TimebackOrgType = 'department' | 'school' | 'district' | 'local' | 'state' | 'national';
|
|
399
|
+
interface UserEnrollment {
|
|
400
|
+
gameId?: string;
|
|
401
|
+
courseId: string;
|
|
402
|
+
enrollmentIds?: {
|
|
403
|
+
active: string;
|
|
404
|
+
inactive?: string[];
|
|
405
|
+
};
|
|
406
|
+
grade: number;
|
|
407
|
+
subject: string;
|
|
408
|
+
orgId?: string;
|
|
409
|
+
}
|
|
410
|
+
interface UserOrganization {
|
|
411
|
+
id: string;
|
|
412
|
+
name: string | null;
|
|
413
|
+
type: TimebackOrgType | string;
|
|
414
|
+
isPrimary: boolean;
|
|
415
|
+
}
|
|
416
|
+
interface TimebackStudentProfile {
|
|
417
|
+
role: TimebackUserRole;
|
|
418
|
+
organizations: UserOrganization[];
|
|
419
|
+
}
|
|
420
|
+
interface UserTimebackData extends TimebackStudentProfile {
|
|
421
|
+
id: string;
|
|
422
|
+
enrollments: UserEnrollment[];
|
|
423
|
+
}
|
|
424
|
+
/**
|
|
425
|
+
* OpenID Connect UserInfo claims (NOT a database row).
|
|
426
|
+
*/
|
|
427
|
+
interface UserInfo {
|
|
428
|
+
sub: string;
|
|
429
|
+
email: string;
|
|
430
|
+
name: string | null;
|
|
431
|
+
email_verified?: boolean;
|
|
432
|
+
given_name?: string;
|
|
433
|
+
family_name?: string;
|
|
434
|
+
issuer?: string;
|
|
435
|
+
lti_roles?: unknown;
|
|
436
|
+
lti_context?: unknown;
|
|
437
|
+
lti_resource_link?: unknown;
|
|
438
|
+
timeback_id?: string;
|
|
439
|
+
}
|
|
440
|
+
interface DemoProfile {
|
|
441
|
+
displayName: string;
|
|
442
|
+
isDefault: boolean;
|
|
443
|
+
}
|
|
444
|
+
/**
|
|
445
|
+
* Update shape for `client.demo.profile.update(...)`.
|
|
446
|
+
*
|
|
447
|
+
* Kept as a named type so callers typed against it pick up new fields
|
|
448
|
+
* automatically, but `displayName` is the only updatable field today and
|
|
449
|
+
* the server's `DemoProfileSchema` requires it — a no-field payload would
|
|
450
|
+
* 400 at runtime, so we model that at the type level too. When additional
|
|
451
|
+
* fields land, make them required/optional individually based on server
|
|
452
|
+
* validation, rather than blanket-optional.
|
|
453
|
+
*/
|
|
454
|
+
interface DemoProfileUpdate {
|
|
455
|
+
displayName: string;
|
|
456
|
+
}
|
|
457
|
+
/**
|
|
458
|
+
* Authenticated user for API responses.
|
|
459
|
+
* Differs from UserRow: omits timebackId, adds hasTimebackAccount and timeback.
|
|
460
|
+
*/
|
|
461
|
+
interface AuthenticatedUser {
|
|
462
|
+
id: string;
|
|
463
|
+
email: string;
|
|
464
|
+
emailVerified: boolean;
|
|
465
|
+
name: string | null;
|
|
466
|
+
image: string | null;
|
|
467
|
+
username: string | null;
|
|
468
|
+
role: UserRoleEnumType;
|
|
469
|
+
developerStatus: DeveloperStatusEnumType;
|
|
470
|
+
characterCreated: boolean;
|
|
471
|
+
createdAt: Date;
|
|
472
|
+
updatedAt: Date;
|
|
473
|
+
hasTimebackAccount: boolean;
|
|
474
|
+
timeback?: UserTimebackData;
|
|
475
|
+
}
|
|
476
|
+
|
|
477
|
+
/**
|
|
478
|
+
* Leaderboard Types
|
|
479
|
+
*
|
|
480
|
+
* @module types/leaderboard
|
|
481
|
+
*/
|
|
482
|
+
type LeaderboardTimeframe = 'all_time' | 'monthly' | 'weekly' | 'daily';
|
|
483
|
+
interface LeaderboardOptions {
|
|
484
|
+
timeframe?: LeaderboardTimeframe;
|
|
485
|
+
limit?: number;
|
|
486
|
+
offset?: number;
|
|
487
|
+
gameId?: string;
|
|
488
|
+
}
|
|
489
|
+
/**
|
|
490
|
+
* Leaderboard entry with required game context.
|
|
491
|
+
* Used when fetching leaderboards for a specific game.
|
|
492
|
+
*/
|
|
493
|
+
interface GameLeaderboardEntry {
|
|
494
|
+
rank: number;
|
|
495
|
+
userId: string;
|
|
496
|
+
username: string;
|
|
497
|
+
userImage?: string | null;
|
|
498
|
+
score: number;
|
|
499
|
+
achievedAt: Date;
|
|
500
|
+
metadata?: Record<string, unknown>;
|
|
501
|
+
gameId: string;
|
|
502
|
+
gameTitle: string;
|
|
503
|
+
gameSlug: string;
|
|
504
|
+
}
|
|
505
|
+
|
|
387
506
|
/**
|
|
388
507
|
* TimeBack Enums & Literal Types
|
|
389
508
|
*
|
|
@@ -499,117 +618,18 @@ interface AdvanceCourseResponse {
|
|
|
499
618
|
}
|
|
500
619
|
|
|
501
620
|
/**
|
|
502
|
-
*
|
|
503
|
-
*
|
|
504
|
-
* Enums, DTOs and API response types. Database row types are in @playcademy/data/types.
|
|
505
|
-
*
|
|
506
|
-
* @module types/user
|
|
507
|
-
*/
|
|
508
|
-
type UserRoleEnumType = 'admin' | 'player' | 'developer' | 'teacher';
|
|
509
|
-
type DeveloperStatusEnumType = 'none' | 'pending' | 'approved';
|
|
510
|
-
type TimebackUserRole = 'administrator' | 'aide' | 'guardian' | 'parent' | 'proctor' | 'relative' | 'student' | 'teacher';
|
|
511
|
-
type TimebackOrgType = 'department' | 'school' | 'district' | 'local' | 'state' | 'national';
|
|
512
|
-
interface UserEnrollment {
|
|
513
|
-
gameId?: string;
|
|
514
|
-
courseId: string;
|
|
515
|
-
grade: number;
|
|
516
|
-
subject: string;
|
|
517
|
-
orgId?: string;
|
|
518
|
-
}
|
|
519
|
-
interface UserOrganization {
|
|
520
|
-
id: string;
|
|
521
|
-
name: string | null;
|
|
522
|
-
type: TimebackOrgType | string;
|
|
523
|
-
isPrimary: boolean;
|
|
524
|
-
}
|
|
525
|
-
interface TimebackStudentProfile {
|
|
526
|
-
role: TimebackUserRole;
|
|
527
|
-
organizations: UserOrganization[];
|
|
528
|
-
}
|
|
529
|
-
interface UserTimebackData extends TimebackStudentProfile {
|
|
530
|
-
id: string;
|
|
531
|
-
enrollments: UserEnrollment[];
|
|
532
|
-
}
|
|
533
|
-
/**
|
|
534
|
-
* OpenID Connect UserInfo claims (NOT a database row).
|
|
535
|
-
*/
|
|
536
|
-
interface UserInfo {
|
|
537
|
-
sub: string;
|
|
538
|
-
email: string;
|
|
539
|
-
name: string | null;
|
|
540
|
-
email_verified?: boolean;
|
|
541
|
-
given_name?: string;
|
|
542
|
-
family_name?: string;
|
|
543
|
-
issuer?: string;
|
|
544
|
-
lti_roles?: unknown;
|
|
545
|
-
lti_context?: unknown;
|
|
546
|
-
lti_resource_link?: unknown;
|
|
547
|
-
timeback_id?: string;
|
|
548
|
-
}
|
|
549
|
-
interface DemoProfile {
|
|
550
|
-
displayName: string;
|
|
551
|
-
isDefault: boolean;
|
|
552
|
-
}
|
|
553
|
-
/**
|
|
554
|
-
* Update shape for `client.demo.profile.update(...)`.
|
|
555
|
-
*
|
|
556
|
-
* Kept as a named type so callers typed against it pick up new fields
|
|
557
|
-
* automatically, but `displayName` is the only updatable field today and
|
|
558
|
-
* the server's `DemoProfileSchema` requires it — a no-field payload would
|
|
559
|
-
* 400 at runtime, so we model that at the type level too. When additional
|
|
560
|
-
* fields land, make them required/optional individually based on server
|
|
561
|
-
* validation, rather than blanket-optional.
|
|
562
|
-
*/
|
|
563
|
-
interface DemoProfileUpdate {
|
|
564
|
-
displayName: string;
|
|
565
|
-
}
|
|
566
|
-
/**
|
|
567
|
-
* Authenticated user for API responses.
|
|
568
|
-
* Differs from UserRow: omits timebackId, adds hasTimebackAccount and timeback.
|
|
569
|
-
*/
|
|
570
|
-
interface AuthenticatedUser {
|
|
571
|
-
id: string;
|
|
572
|
-
email: string;
|
|
573
|
-
emailVerified: boolean;
|
|
574
|
-
name: string | null;
|
|
575
|
-
image: string | null;
|
|
576
|
-
username: string | null;
|
|
577
|
-
role: UserRoleEnumType;
|
|
578
|
-
developerStatus: DeveloperStatusEnumType;
|
|
579
|
-
characterCreated: boolean;
|
|
580
|
-
createdAt: Date;
|
|
581
|
-
updatedAt: Date;
|
|
582
|
-
hasTimebackAccount: boolean;
|
|
583
|
-
timeback?: UserTimebackData;
|
|
584
|
-
}
|
|
585
|
-
|
|
586
|
-
/**
|
|
587
|
-
* Leaderboard Types
|
|
588
|
-
*
|
|
589
|
-
* @module types/leaderboard
|
|
621
|
+
* Cache configuration types for runtime customization
|
|
590
622
|
*/
|
|
591
|
-
type LeaderboardTimeframe = 'all_time' | 'monthly' | 'weekly' | 'daily';
|
|
592
|
-
interface LeaderboardOptions {
|
|
593
|
-
timeframe?: LeaderboardTimeframe;
|
|
594
|
-
limit?: number;
|
|
595
|
-
offset?: number;
|
|
596
|
-
gameId?: string;
|
|
597
|
-
}
|
|
598
623
|
/**
|
|
599
|
-
*
|
|
600
|
-
* Used when fetching leaderboards for a specific game.
|
|
624
|
+
* Runtime configuration for TTL cache behavior
|
|
601
625
|
*/
|
|
602
|
-
interface
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
metadata?: Record<string, unknown>;
|
|
610
|
-
gameId: string;
|
|
611
|
-
gameTitle: string;
|
|
612
|
-
gameSlug: string;
|
|
626
|
+
interface TTLCacheConfig {
|
|
627
|
+
/** Time-to-live in milliseconds. Set to 0 to disable caching for this call. */
|
|
628
|
+
ttl?: number;
|
|
629
|
+
/** Force refresh, bypassing cache */
|
|
630
|
+
force?: boolean;
|
|
631
|
+
/** Skip cache and fetch fresh data (alias for force) */
|
|
632
|
+
skipCache?: boolean;
|
|
613
633
|
}
|
|
614
634
|
|
|
615
635
|
declare const items: drizzle_orm_pg_core.PgTableWithColumns<{
|
|
@@ -889,40 +909,211 @@ type InventoryItemWithItem = InventoryItemRow & {
|
|
|
889
909
|
};
|
|
890
910
|
|
|
891
911
|
/**
|
|
892
|
-
*
|
|
893
|
-
* Works in both iframe mode (production/development) and standalone mode (local dev).
|
|
894
|
-
*
|
|
895
|
-
* This is the recommended way to initialize the SDK as it automatically:
|
|
896
|
-
* - Detects the runtime environment (iframe vs standalone)
|
|
897
|
-
* - Configures the client with the appropriate context
|
|
898
|
-
* - Sets up event listeners for token refresh
|
|
899
|
-
* - Exposes the client for debugging in development mode
|
|
900
|
-
*
|
|
901
|
-
* @param options - Optional configuration overrides
|
|
902
|
-
* @param options.baseUrl - Override the base URL for API requests
|
|
903
|
-
* @returns Promise resolving to a fully initialized PlaycademyClient
|
|
904
|
-
* @throws Error if not running in a browser context
|
|
905
|
-
*
|
|
906
|
-
* @example
|
|
907
|
-
* ```typescript
|
|
908
|
-
* // Default initialization
|
|
909
|
-
* const client = await PlaycademyClient.init()
|
|
912
|
+
* @fileoverview Authentication Strategy Pattern
|
|
910
913
|
*
|
|
911
|
-
*
|
|
912
|
-
*
|
|
913
|
-
* ```
|
|
914
|
+
* Provides different authentication strategies for the Playcademy SDK.
|
|
915
|
+
* Each strategy knows how to add its authentication headers to requests.
|
|
914
916
|
*/
|
|
915
|
-
declare function init<T extends PlaycademyBaseClient = PlaycademyBaseClient>(this: new (config?: Partial<ClientConfig>) => T, options?: {
|
|
916
|
-
baseUrl?: string;
|
|
917
|
-
allowedParentOrigins?: string[];
|
|
918
|
-
onDisconnect?: DisconnectHandler;
|
|
919
|
-
enableConnectionMonitoring?: boolean;
|
|
920
|
-
}): Promise<T>;
|
|
921
917
|
|
|
922
918
|
/**
|
|
923
|
-
*
|
|
924
|
-
|
|
925
|
-
|
|
919
|
+
* Base interface for authentication strategies
|
|
920
|
+
*/
|
|
921
|
+
interface AuthStrategy {
|
|
922
|
+
/** Get the token value */
|
|
923
|
+
getToken(): string | null;
|
|
924
|
+
/** Get the token type */
|
|
925
|
+
getType(): TokenType;
|
|
926
|
+
/** Get authentication headers for a request */
|
|
927
|
+
getHeaders(): Record<string, string>;
|
|
928
|
+
}
|
|
929
|
+
|
|
930
|
+
/**
|
|
931
|
+
* Base Playcademy SDK client with shared infrastructure.
|
|
932
|
+
* Provides authentication, HTTP requests, events, connection monitoring,
|
|
933
|
+
* and fundamental namespaces used by all clients.
|
|
934
|
+
*
|
|
935
|
+
* Extended by PlaycademyClient (game SDK) and PlaycademyInternalClient (platform SDK).
|
|
936
|
+
*/
|
|
937
|
+
declare abstract class PlaycademyBaseClient {
|
|
938
|
+
baseUrl: string;
|
|
939
|
+
gameUrl?: string;
|
|
940
|
+
mode: PlaycademyMode;
|
|
941
|
+
protected authStrategy: AuthStrategy;
|
|
942
|
+
protected gameId?: string;
|
|
943
|
+
protected config: Partial<ClientConfig>;
|
|
944
|
+
protected listeners: EventListeners;
|
|
945
|
+
protected internalClientSessionId?: string;
|
|
946
|
+
protected authContext?: {
|
|
947
|
+
isInIframe: boolean;
|
|
948
|
+
};
|
|
949
|
+
protected initPayload?: InitPayload;
|
|
950
|
+
protected connectionManager?: ConnectionManager;
|
|
951
|
+
protected launchId?: string;
|
|
952
|
+
/**
|
|
953
|
+
* Internal session manager for automatic session lifecycle.
|
|
954
|
+
* @private
|
|
955
|
+
* @internal
|
|
956
|
+
*/
|
|
957
|
+
protected _sessionManager: {
|
|
958
|
+
startSession: (gameId: string) => Promise<{
|
|
959
|
+
sessionId: string;
|
|
960
|
+
}>;
|
|
961
|
+
endSession: (sessionId: string, gameId: string) => Promise<void>;
|
|
962
|
+
};
|
|
963
|
+
constructor(config?: Partial<ClientConfig>);
|
|
964
|
+
/**
|
|
965
|
+
* Gets the effective base URL for API requests.
|
|
966
|
+
*/
|
|
967
|
+
getBaseUrl(): string;
|
|
968
|
+
/**
|
|
969
|
+
* Gets the effective game backend URL for integration requests.
|
|
970
|
+
*/
|
|
971
|
+
protected getGameBackendUrl(): string;
|
|
972
|
+
/**
|
|
973
|
+
* Simple ping method for testing connectivity.
|
|
974
|
+
*/
|
|
975
|
+
ping(): string;
|
|
976
|
+
/**
|
|
977
|
+
* Sets the authentication token for API requests.
|
|
978
|
+
*/
|
|
979
|
+
setToken(token: string | null, tokenType?: TokenType): void;
|
|
980
|
+
setLaunchId(launchId: string | null | undefined): void;
|
|
981
|
+
/**
|
|
982
|
+
* Gets the current token type.
|
|
983
|
+
*/
|
|
984
|
+
getTokenType(): TokenType;
|
|
985
|
+
/**
|
|
986
|
+
* Gets the current authentication token.
|
|
987
|
+
*/
|
|
988
|
+
getToken(): string | null;
|
|
989
|
+
/**
|
|
990
|
+
* Checks if the client has a valid API token.
|
|
991
|
+
*/
|
|
992
|
+
isAuthenticated(): boolean;
|
|
993
|
+
/**
|
|
994
|
+
* Registers a callback to be called when authentication state changes.
|
|
995
|
+
*/
|
|
996
|
+
onAuthChange(callback: (token: string | null) => void): void;
|
|
997
|
+
/**
|
|
998
|
+
* Registers a callback to be called when connection issues are detected.
|
|
999
|
+
*/
|
|
1000
|
+
onDisconnect(callback: (context: DisconnectContext) => void | Promise<void>): () => void;
|
|
1001
|
+
/**
|
|
1002
|
+
* Gets the current connection state.
|
|
1003
|
+
*/
|
|
1004
|
+
getConnectionState(): ConnectionState | 'unknown';
|
|
1005
|
+
/**
|
|
1006
|
+
* Manually triggers a connection check immediately.
|
|
1007
|
+
*/
|
|
1008
|
+
checkConnection(): Promise<ConnectionState | 'unknown'>;
|
|
1009
|
+
/**
|
|
1010
|
+
* Sets the authentication context for the client.
|
|
1011
|
+
* @internal
|
|
1012
|
+
*/
|
|
1013
|
+
_setAuthContext(context: {
|
|
1014
|
+
isInIframe: boolean;
|
|
1015
|
+
}): void;
|
|
1016
|
+
/**
|
|
1017
|
+
* Registers an event listener for client events.
|
|
1018
|
+
*
|
|
1019
|
+
* @param event - The event name to listen for.
|
|
1020
|
+
* @param callback - The handler invoked when the event fires.
|
|
1021
|
+
* @returns A cleanup function that removes this specific listener.
|
|
1022
|
+
*/
|
|
1023
|
+
on<E extends keyof ClientEvents>(event: E, callback: (payload: ClientEvents[E]) => void): () => void;
|
|
1024
|
+
/**
|
|
1025
|
+
* Removes a previously registered event listener.
|
|
1026
|
+
*
|
|
1027
|
+
* @param event - The event name to stop listening for.
|
|
1028
|
+
* @param callback - The exact function reference passed to {@link on}.
|
|
1029
|
+
*/
|
|
1030
|
+
off<E extends keyof ClientEvents>(event: E, callback: (payload: ClientEvents[E]) => void): void;
|
|
1031
|
+
/**
|
|
1032
|
+
* Emits an event to all registered listeners.
|
|
1033
|
+
*/
|
|
1034
|
+
protected emit<E extends keyof ClientEvents>(event: E, payload: ClientEvents[E]): void;
|
|
1035
|
+
/**
|
|
1036
|
+
* Makes an authenticated HTTP request to the platform API.
|
|
1037
|
+
*/
|
|
1038
|
+
protected request<T>(path: string, method: Method, options?: {
|
|
1039
|
+
body?: unknown;
|
|
1040
|
+
headers?: Record<string, string>;
|
|
1041
|
+
raw?: boolean;
|
|
1042
|
+
retryPolicy?: RetryPolicy;
|
|
1043
|
+
}): Promise<T>;
|
|
1044
|
+
/**
|
|
1045
|
+
* Makes an authenticated HTTP request to the game's backend Worker.
|
|
1046
|
+
*/
|
|
1047
|
+
protected requestGameBackend<T>(path: string, method: Method, body?: unknown, headers?: Record<string, string>, options?: {
|
|
1048
|
+
raw?: boolean;
|
|
1049
|
+
retryPolicy?: RetryPolicy;
|
|
1050
|
+
}): Promise<T>;
|
|
1051
|
+
/**
|
|
1052
|
+
* Ensures a gameId is available, throwing an error if not.
|
|
1053
|
+
*/
|
|
1054
|
+
protected _ensureGameId(): string;
|
|
1055
|
+
/**
|
|
1056
|
+
* Detects and sets the authentication context (iframe vs standalone).
|
|
1057
|
+
*/
|
|
1058
|
+
private _detectAuthContext;
|
|
1059
|
+
/**
|
|
1060
|
+
* Initializes connection monitoring if enabled.
|
|
1061
|
+
*/
|
|
1062
|
+
private _initializeConnectionMonitor;
|
|
1063
|
+
private _initializeInternalSession;
|
|
1064
|
+
/**
|
|
1065
|
+
* Current user data and inventory management.
|
|
1066
|
+
* - `me()` - Get authenticated user profile
|
|
1067
|
+
* - `inventory.get()` - List user's items
|
|
1068
|
+
* - `inventory.add(slug, qty)` - Award items to user
|
|
1069
|
+
*/
|
|
1070
|
+
users: {
|
|
1071
|
+
me: () => Promise<AuthenticatedUser>;
|
|
1072
|
+
inventory: {
|
|
1073
|
+
get: () => Promise<InventoryItemWithItem[]>;
|
|
1074
|
+
add: (identifier: string, qty: number) => Promise<InventoryMutationResponse>;
|
|
1075
|
+
remove: (identifier: string, qty: number) => Promise<InventoryMutationResponse>;
|
|
1076
|
+
quantity: (identifier: string) => Promise<number>;
|
|
1077
|
+
has: (identifier: string, minQuantity?: number) => Promise<boolean>;
|
|
1078
|
+
};
|
|
1079
|
+
};
|
|
1080
|
+
}
|
|
1081
|
+
|
|
1082
|
+
/**
|
|
1083
|
+
* Auto-initializes a PlaycademyClient with context from the environment.
|
|
1084
|
+
* Works in both iframe mode (production/development) and standalone mode (local dev).
|
|
1085
|
+
*
|
|
1086
|
+
* This is the recommended way to initialize the SDK as it automatically:
|
|
1087
|
+
* - Detects the runtime environment (iframe vs standalone)
|
|
1088
|
+
* - Configures the client with the appropriate context
|
|
1089
|
+
* - Sets up event listeners for token refresh
|
|
1090
|
+
* - Exposes the client for debugging in development mode
|
|
1091
|
+
*
|
|
1092
|
+
* @param options - Optional configuration overrides
|
|
1093
|
+
* @param options.baseUrl - Override the base URL for API requests
|
|
1094
|
+
* @returns Promise resolving to a fully initialized PlaycademyClient
|
|
1095
|
+
* @throws Error if not running in a browser context
|
|
1096
|
+
*
|
|
1097
|
+
* @example
|
|
1098
|
+
* ```typescript
|
|
1099
|
+
* // Default initialization
|
|
1100
|
+
* const client = await PlaycademyClient.init()
|
|
1101
|
+
*
|
|
1102
|
+
* // With custom base URL
|
|
1103
|
+
* const client = await PlaycademyClient.init({ baseUrl: 'https://custom.api.com' })
|
|
1104
|
+
* ```
|
|
1105
|
+
*/
|
|
1106
|
+
declare function init<T extends PlaycademyBaseClient = PlaycademyBaseClient>(this: new (config?: Partial<ClientConfig>) => T, options?: {
|
|
1107
|
+
baseUrl?: string;
|
|
1108
|
+
allowedParentOrigins?: string[];
|
|
1109
|
+
onDisconnect?: DisconnectHandler;
|
|
1110
|
+
enableConnectionMonitoring?: boolean;
|
|
1111
|
+
}): Promise<T>;
|
|
1112
|
+
|
|
1113
|
+
/**
|
|
1114
|
+
* Authenticates a user with email and password.
|
|
1115
|
+
*
|
|
1116
|
+
* This is a standalone authentication method that doesn't require an initialized client.
|
|
926
1117
|
* Use this for login flows before creating a client instance.
|
|
927
1118
|
*
|
|
928
1119
|
* @deprecated Use client.auth.login() instead for better error handling and automatic token management
|
|
@@ -1538,225 +1729,6 @@ declare class PlaycademyMessaging {
|
|
|
1538
1729
|
*/
|
|
1539
1730
|
declare const messaging: PlaycademyMessaging;
|
|
1540
1731
|
|
|
1541
|
-
/**
|
|
1542
|
-
* @fileoverview Authentication Strategy Pattern
|
|
1543
|
-
*
|
|
1544
|
-
* Provides different authentication strategies for the Playcademy SDK.
|
|
1545
|
-
* Each strategy knows how to add its authentication headers to requests.
|
|
1546
|
-
*/
|
|
1547
|
-
|
|
1548
|
-
/**
|
|
1549
|
-
* Base interface for authentication strategies
|
|
1550
|
-
*/
|
|
1551
|
-
interface AuthStrategy {
|
|
1552
|
-
/** Get the token value */
|
|
1553
|
-
getToken(): string | null;
|
|
1554
|
-
/** Get the token type */
|
|
1555
|
-
getType(): TokenType;
|
|
1556
|
-
/** Get authentication headers for a request */
|
|
1557
|
-
getHeaders(): Record<string, string>;
|
|
1558
|
-
}
|
|
1559
|
-
|
|
1560
|
-
/**
|
|
1561
|
-
* Base Playcademy SDK client with shared infrastructure.
|
|
1562
|
-
* Provides authentication, HTTP requests, events, connection monitoring,
|
|
1563
|
-
* and fundamental namespaces used by all clients.
|
|
1564
|
-
*
|
|
1565
|
-
* Extended by PlaycademyClient (game SDK) and PlaycademyInternalClient (platform SDK).
|
|
1566
|
-
*/
|
|
1567
|
-
declare abstract class PlaycademyBaseClient {
|
|
1568
|
-
baseUrl: string;
|
|
1569
|
-
gameUrl?: string;
|
|
1570
|
-
mode: PlaycademyMode;
|
|
1571
|
-
protected authStrategy: AuthStrategy;
|
|
1572
|
-
protected gameId?: string;
|
|
1573
|
-
protected config: Partial<ClientConfig>;
|
|
1574
|
-
protected listeners: EventListeners;
|
|
1575
|
-
protected internalClientSessionId?: string;
|
|
1576
|
-
protected authContext?: {
|
|
1577
|
-
isInIframe: boolean;
|
|
1578
|
-
};
|
|
1579
|
-
protected initPayload?: InitPayload;
|
|
1580
|
-
protected connectionManager?: ConnectionManager;
|
|
1581
|
-
protected launchId?: string;
|
|
1582
|
-
/**
|
|
1583
|
-
* Internal session manager for automatic session lifecycle.
|
|
1584
|
-
* @private
|
|
1585
|
-
* @internal
|
|
1586
|
-
*/
|
|
1587
|
-
protected _sessionManager: {
|
|
1588
|
-
startSession: (gameId: string) => Promise<{
|
|
1589
|
-
sessionId: string;
|
|
1590
|
-
}>;
|
|
1591
|
-
endSession: (sessionId: string, gameId: string) => Promise<void>;
|
|
1592
|
-
};
|
|
1593
|
-
constructor(config?: Partial<ClientConfig>);
|
|
1594
|
-
/**
|
|
1595
|
-
* Gets the effective base URL for API requests.
|
|
1596
|
-
*/
|
|
1597
|
-
getBaseUrl(): string;
|
|
1598
|
-
/**
|
|
1599
|
-
* Gets the effective game backend URL for integration requests.
|
|
1600
|
-
*/
|
|
1601
|
-
protected getGameBackendUrl(): string;
|
|
1602
|
-
/**
|
|
1603
|
-
* Simple ping method for testing connectivity.
|
|
1604
|
-
*/
|
|
1605
|
-
ping(): string;
|
|
1606
|
-
/**
|
|
1607
|
-
* Sets the authentication token for API requests.
|
|
1608
|
-
*/
|
|
1609
|
-
setToken(token: string | null, tokenType?: TokenType): void;
|
|
1610
|
-
setLaunchId(launchId: string | null | undefined): void;
|
|
1611
|
-
/**
|
|
1612
|
-
* Gets the current token type.
|
|
1613
|
-
*/
|
|
1614
|
-
getTokenType(): TokenType;
|
|
1615
|
-
/**
|
|
1616
|
-
* Gets the current authentication token.
|
|
1617
|
-
*/
|
|
1618
|
-
getToken(): string | null;
|
|
1619
|
-
/**
|
|
1620
|
-
* Checks if the client has a valid API token.
|
|
1621
|
-
*/
|
|
1622
|
-
isAuthenticated(): boolean;
|
|
1623
|
-
/**
|
|
1624
|
-
* Registers a callback to be called when authentication state changes.
|
|
1625
|
-
*/
|
|
1626
|
-
onAuthChange(callback: (token: string | null) => void): void;
|
|
1627
|
-
/**
|
|
1628
|
-
* Registers a callback to be called when connection issues are detected.
|
|
1629
|
-
*/
|
|
1630
|
-
onDisconnect(callback: (context: DisconnectContext) => void | Promise<void>): () => void;
|
|
1631
|
-
/**
|
|
1632
|
-
* Gets the current connection state.
|
|
1633
|
-
*/
|
|
1634
|
-
getConnectionState(): ConnectionState | 'unknown';
|
|
1635
|
-
/**
|
|
1636
|
-
* Manually triggers a connection check immediately.
|
|
1637
|
-
*/
|
|
1638
|
-
checkConnection(): Promise<ConnectionState | 'unknown'>;
|
|
1639
|
-
/**
|
|
1640
|
-
* Sets the authentication context for the client.
|
|
1641
|
-
* @internal
|
|
1642
|
-
*/
|
|
1643
|
-
_setAuthContext(context: {
|
|
1644
|
-
isInIframe: boolean;
|
|
1645
|
-
}): void;
|
|
1646
|
-
/**
|
|
1647
|
-
* Registers an event listener for client events.
|
|
1648
|
-
*
|
|
1649
|
-
* @param event - The event name to listen for.
|
|
1650
|
-
* @param callback - The handler invoked when the event fires.
|
|
1651
|
-
* @returns A cleanup function that removes this specific listener.
|
|
1652
|
-
*/
|
|
1653
|
-
on<E extends keyof ClientEvents>(event: E, callback: (payload: ClientEvents[E]) => void): () => void;
|
|
1654
|
-
/**
|
|
1655
|
-
* Removes a previously registered event listener.
|
|
1656
|
-
*
|
|
1657
|
-
* @param event - The event name to stop listening for.
|
|
1658
|
-
* @param callback - The exact function reference passed to {@link on}.
|
|
1659
|
-
*/
|
|
1660
|
-
off<E extends keyof ClientEvents>(event: E, callback: (payload: ClientEvents[E]) => void): void;
|
|
1661
|
-
/**
|
|
1662
|
-
* Emits an event to all registered listeners.
|
|
1663
|
-
*/
|
|
1664
|
-
protected emit<E extends keyof ClientEvents>(event: E, payload: ClientEvents[E]): void;
|
|
1665
|
-
/**
|
|
1666
|
-
* Makes an authenticated HTTP request to the platform API.
|
|
1667
|
-
*/
|
|
1668
|
-
protected request<T>(path: string, method: Method, options?: {
|
|
1669
|
-
body?: unknown;
|
|
1670
|
-
headers?: Record<string, string>;
|
|
1671
|
-
raw?: boolean;
|
|
1672
|
-
retryPolicy?: RetryPolicy;
|
|
1673
|
-
}): Promise<T>;
|
|
1674
|
-
/**
|
|
1675
|
-
* Makes an authenticated HTTP request to the game's backend Worker.
|
|
1676
|
-
*/
|
|
1677
|
-
protected requestGameBackend<T>(path: string, method: Method, body?: unknown, headers?: Record<string, string>, options?: {
|
|
1678
|
-
raw?: boolean;
|
|
1679
|
-
retryPolicy?: RetryPolicy;
|
|
1680
|
-
}): Promise<T>;
|
|
1681
|
-
/**
|
|
1682
|
-
* Ensures a gameId is available, throwing an error if not.
|
|
1683
|
-
*/
|
|
1684
|
-
protected _ensureGameId(): string;
|
|
1685
|
-
/**
|
|
1686
|
-
* Detects and sets the authentication context (iframe vs standalone).
|
|
1687
|
-
*/
|
|
1688
|
-
private _detectAuthContext;
|
|
1689
|
-
/**
|
|
1690
|
-
* Initializes connection monitoring if enabled.
|
|
1691
|
-
*/
|
|
1692
|
-
private _initializeConnectionMonitor;
|
|
1693
|
-
private _initializeInternalSession;
|
|
1694
|
-
/**
|
|
1695
|
-
* Current user data and inventory management.
|
|
1696
|
-
* - `me()` - Get authenticated user profile
|
|
1697
|
-
* - `inventory.get()` - List user's items
|
|
1698
|
-
* - `inventory.add(slug, qty)` - Award items to user
|
|
1699
|
-
*/
|
|
1700
|
-
users: {
|
|
1701
|
-
me: () => Promise<AuthenticatedUser>;
|
|
1702
|
-
inventory: {
|
|
1703
|
-
get: () => Promise<InventoryItemWithItem[]>;
|
|
1704
|
-
add: (identifier: string, qty: number) => Promise<InventoryMutationResponse>;
|
|
1705
|
-
remove: (identifier: string, qty: number) => Promise<InventoryMutationResponse>;
|
|
1706
|
-
quantity: (identifier: string) => Promise<number>;
|
|
1707
|
-
has: (identifier: string, minQuantity?: number) => Promise<boolean>;
|
|
1708
|
-
};
|
|
1709
|
-
};
|
|
1710
|
-
}
|
|
1711
|
-
|
|
1712
|
-
/**
|
|
1713
|
-
* Options for configuring activity tracking behavior.
|
|
1714
|
-
*/
|
|
1715
|
-
interface StartActivityOptions {
|
|
1716
|
-
/**
|
|
1717
|
-
* How long heartbeats continue after the activity is automatically paused
|
|
1718
|
-
* because the tab is hidden or the player is inactive while visible.
|
|
1719
|
-
* Defaults to 10 minutes. Set to `Infinity` to keep heartbeats running
|
|
1720
|
-
* indefinitely during automatic pauses. Invalid values fall back to the
|
|
1721
|
-
* 10-minute default.
|
|
1722
|
-
*/
|
|
1723
|
-
pausedHeartbeatTimeoutMs?: number;
|
|
1724
|
-
/**
|
|
1725
|
-
* @deprecated Use `pausedHeartbeatTimeoutMs` instead.
|
|
1726
|
-
*
|
|
1727
|
-
* Backward-compatible alias for callers that still use the old option
|
|
1728
|
-
* name from earlier SDK releases.
|
|
1729
|
-
*/
|
|
1730
|
-
hiddenTimeoutMs?: number;
|
|
1731
|
-
/**
|
|
1732
|
-
* How often to flush periodic heartbeats with accumulated time data.
|
|
1733
|
-
* Defaults to 15 seconds. Set to `Infinity` to disable the interval;
|
|
1734
|
-
* final unload/endActivity flushes still run. Values must be greater than
|
|
1735
|
-
* 0 or `Infinity`; invalid values fall back to the 15-second default.
|
|
1736
|
-
*/
|
|
1737
|
-
heartbeatIntervalMs?: number;
|
|
1738
|
-
/**
|
|
1739
|
-
* How long the tab can remain visible without keyboard or mouse activity
|
|
1740
|
-
* before the activity is marked inactive. Defaults to 10 minutes. Set to
|
|
1741
|
-
* `Infinity` to disable keyboard/mouse inactivity tracking. Invalid values
|
|
1742
|
-
* fall back to the 10-minute default.
|
|
1743
|
-
*/
|
|
1744
|
-
inactivityTimeoutMs?: number;
|
|
1745
|
-
/**
|
|
1746
|
-
* Stable identifier for this activity run. When provided, it is used on
|
|
1747
|
-
* every heartbeat and on endActivity instead of a freshly-generated UUID.
|
|
1748
|
-
*
|
|
1749
|
-
* Pass the same `runId` across multiple `startActivity()` calls (for
|
|
1750
|
-
* example, after the player closes and reopens a resumable activity) so
|
|
1751
|
-
* downstream systems can correlate related sessions into a single run.
|
|
1752
|
-
*
|
|
1753
|
-
* Must be a UUID (the backend validates it as such) and unique per
|
|
1754
|
-
* logical run. If omitted, the SDK generates a new UUID on each call,
|
|
1755
|
-
* which means every session is treated as its own run.
|
|
1756
|
-
*/
|
|
1757
|
-
runId?: string;
|
|
1758
|
-
}
|
|
1759
|
-
|
|
1760
1732
|
/**
|
|
1761
1733
|
* Playcademy SDK client for game developers.
|
|
1762
1734
|
* Provides namespaced access to platform features for games running inside Cademy.
|
|
@@ -1819,19 +1791,22 @@ declare class PlaycademyClient extends PlaycademyBaseClient {
|
|
|
1819
1791
|
* User context (cached from init, refreshable):
|
|
1820
1792
|
* - `user.role` - User's role (student, parent, teacher, etc.)
|
|
1821
1793
|
* - `user.enrollments` - Courses the player is enrolled in for this game
|
|
1794
|
+
* - `user.refresh({ only: ['enrollments'] })` - Refresh enrollments from server
|
|
1822
1795
|
* - `user.organizations` - Schools/districts the player belongs to
|
|
1823
1796
|
* - `user.fetch()` - Refresh user context from server
|
|
1824
1797
|
*
|
|
1825
1798
|
* Activity tracking:
|
|
1826
|
-
* - `
|
|
1827
|
-
*
|
|
1828
|
-
*
|
|
1799
|
+
* - `currentRunId` - Current activity run ID, or undefined when inactive
|
|
1800
|
+
* - `startActivity(metadata)` - Begin tracking an activity, return its run
|
|
1801
|
+
* ID, and automatically handle hidden-tab and visible-tab inactivity
|
|
1802
|
+
* with configurable paused-heartbeat timeout behavior
|
|
1829
1803
|
* - `pauseActivity()` / `resumeActivity()` - Pause/resume timer
|
|
1830
1804
|
* - `endActivity(scoreData)` - Submit activity results to TimeBack
|
|
1831
1805
|
*/
|
|
1832
1806
|
timeback: {
|
|
1833
1807
|
readonly user: TimebackUser;
|
|
1834
|
-
|
|
1808
|
+
readonly currentRunId: string | undefined;
|
|
1809
|
+
startActivity: (metadata: ActivityData, options?: StartActivityOptions) => StartActivityResult;
|
|
1835
1810
|
pauseActivity: () => void;
|
|
1836
1811
|
resumeActivity: () => void;
|
|
1837
1812
|
endActivity: (data: EndActivityScoreData) => Promise<EndActivityResponse>;
|
|
@@ -1911,6 +1886,57 @@ declare class PlaycademyClient extends PlaycademyBaseClient {
|
|
|
1911
1886
|
};
|
|
1912
1887
|
}
|
|
1913
1888
|
|
|
1889
|
+
/**
|
|
1890
|
+
* Options for configuring activity tracking behavior.
|
|
1891
|
+
*/
|
|
1892
|
+
interface StartActivityOptions {
|
|
1893
|
+
/**
|
|
1894
|
+
* How long heartbeats continue after the activity is automatically paused
|
|
1895
|
+
* because the tab is hidden or the player is inactive while visible.
|
|
1896
|
+
* Defaults to 10 minutes. Set to `Infinity` to keep heartbeats running
|
|
1897
|
+
* indefinitely during automatic pauses. Invalid values fall back to the
|
|
1898
|
+
* 10-minute default.
|
|
1899
|
+
*/
|
|
1900
|
+
pausedHeartbeatTimeoutMs?: number;
|
|
1901
|
+
/**
|
|
1902
|
+
* @deprecated Use `pausedHeartbeatTimeoutMs` instead.
|
|
1903
|
+
*
|
|
1904
|
+
* Backward-compatible alias for callers that still use the old option
|
|
1905
|
+
* name from earlier SDK releases.
|
|
1906
|
+
*/
|
|
1907
|
+
hiddenTimeoutMs?: number;
|
|
1908
|
+
/**
|
|
1909
|
+
* How often to flush periodic heartbeats with accumulated time data.
|
|
1910
|
+
* Defaults to 15 seconds. Set to `Infinity` to disable the interval;
|
|
1911
|
+
* final unload/endActivity flushes still run. Values must be greater than
|
|
1912
|
+
* 0 or `Infinity`; invalid values fall back to the 15-second default.
|
|
1913
|
+
*/
|
|
1914
|
+
heartbeatIntervalMs?: number;
|
|
1915
|
+
/**
|
|
1916
|
+
* How long the tab can remain visible without keyboard or mouse activity
|
|
1917
|
+
* before the activity is marked inactive. Defaults to 10 minutes. Set to
|
|
1918
|
+
* `Infinity` to disable keyboard/mouse inactivity tracking. Invalid values
|
|
1919
|
+
* fall back to the 10-minute default.
|
|
1920
|
+
*/
|
|
1921
|
+
inactivityTimeoutMs?: number;
|
|
1922
|
+
/**
|
|
1923
|
+
* Stable identifier for this activity run. When provided, it is used on
|
|
1924
|
+
* every heartbeat and on endActivity instead of a freshly-generated UUID.
|
|
1925
|
+
*
|
|
1926
|
+
* Pass the same `runId` across multiple `startActivity()` calls (for
|
|
1927
|
+
* example, after the player closes and reopens a resumable activity) so
|
|
1928
|
+
* downstream systems can correlate related sessions into a single run.
|
|
1929
|
+
*
|
|
1930
|
+
* Must be a UUID (the backend validates it as such) and unique per
|
|
1931
|
+
* logical run. If omitted, the SDK generates a new UUID on each call,
|
|
1932
|
+
* which means every session is treated as its own run.
|
|
1933
|
+
*/
|
|
1934
|
+
runId?: string;
|
|
1935
|
+
}
|
|
1936
|
+
interface StartActivityResult {
|
|
1937
|
+
runId: string;
|
|
1938
|
+
}
|
|
1939
|
+
|
|
1914
1940
|
/**
|
|
1915
1941
|
* Type definitions for the game timeback namespace.
|
|
1916
1942
|
*
|
|
@@ -1920,7 +1946,9 @@ declare class PlaycademyClient extends PlaycademyBaseClient {
|
|
|
1920
1946
|
|
|
1921
1947
|
/**
|
|
1922
1948
|
* A TimeBack enrollment for the current game session.
|
|
1923
|
-
* Alias for UserEnrollment without the optional gameId.
|
|
1949
|
+
* Alias for UserEnrollment without the optional gameId. Active enrollment IDs
|
|
1950
|
+
* are available at `enrollment.enrollmentIds?.active` when supplied by the
|
|
1951
|
+
* platform.
|
|
1924
1952
|
*/
|
|
1925
1953
|
type TimebackEnrollment = Omit<UserEnrollment, 'gameId'>;
|
|
1926
1954
|
/**
|
|
@@ -1956,6 +1984,14 @@ interface TimebackUserContext {
|
|
|
1956
1984
|
/** User's organizations (schools/districts) */
|
|
1957
1985
|
organizations: TimebackOrganization[];
|
|
1958
1986
|
}
|
|
1987
|
+
/**
|
|
1988
|
+
* Slice options for refreshing the cached TimeBack user context.
|
|
1989
|
+
*/
|
|
1990
|
+
type TimebackUserRefreshField = 'enrollments';
|
|
1991
|
+
interface TimebackUserRefreshOptions extends TTLCacheConfig {
|
|
1992
|
+
/** Refresh only these user data fields */
|
|
1993
|
+
only: readonly TimebackUserRefreshField[];
|
|
1994
|
+
}
|
|
1959
1995
|
/**
|
|
1960
1996
|
* XP data access for the current user.
|
|
1961
1997
|
* Results are cached for 5 seconds to avoid redundant network requests.
|
|
@@ -1996,7 +2032,7 @@ interface TimebackUserXp {
|
|
|
1996
2032
|
fetch(options?: GetXpOptions): Promise<XpResponse>;
|
|
1997
2033
|
}
|
|
1998
2034
|
/**
|
|
1999
|
-
* TimeBack user object with
|
|
2035
|
+
* TimeBack user object with cached getters, fetch, and targeted refresh methods.
|
|
2000
2036
|
*/
|
|
2001
2037
|
interface TimebackUser extends TimebackUserContext {
|
|
2002
2038
|
/**
|
|
@@ -2005,9 +2041,14 @@ interface TimebackUser extends TimebackUserContext {
|
|
|
2005
2041
|
* @param options - Cache options (pass { force: true } to bypass cache)
|
|
2006
2042
|
* @returns Promise resolving to fresh user context
|
|
2007
2043
|
*/
|
|
2008
|
-
fetch(options?:
|
|
2009
|
-
|
|
2010
|
-
|
|
2044
|
+
fetch(options?: TTLCacheConfig): Promise<TimebackUserContext>;
|
|
2045
|
+
/**
|
|
2046
|
+
* Refresh selected TimeBack user data from the server.
|
|
2047
|
+
* Updates the cached user snapshot used by the synchronous getters.
|
|
2048
|
+
* @param options - Refresh fields and cache options
|
|
2049
|
+
* @returns Promise resolving to the updated user context
|
|
2050
|
+
*/
|
|
2051
|
+
refresh(options: TimebackUserRefreshOptions): Promise<TimebackUserContext>;
|
|
2011
2052
|
/**
|
|
2012
2053
|
* XP data for the current user.
|
|
2013
2054
|
* Call `xp.fetch()` to get XP from the server.
|