@playcademy/sdk 0.2.1 → 0.2.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 +20 -17
- package/dist/index.d.ts +247 -202
- package/dist/index.js +1280 -1381
- package/dist/internal.d.ts +2337 -2124
- package/dist/internal.js +2455 -2600
- package/dist/server.d.ts +6 -5
- package/dist/server.js +14 -1
- package/dist/types.d.ts +432 -220
- package/package.json +3 -3
package/dist/index.d.ts
CHANGED
|
@@ -1,6 +1,5 @@
|
|
|
1
|
-
import * as _playcademy_realtime_server_types from '@playcademy/realtime/server/types';
|
|
2
|
-
import * as _playcademy_timeback_types from '@playcademy/timeback/types';
|
|
3
1
|
import * as drizzle_orm_pg_core from 'drizzle-orm/pg-core';
|
|
2
|
+
import * as _playcademy_timeback_types from '@playcademy/timeback/types';
|
|
4
3
|
import { AUTH_PROVIDER_IDS } from '@playcademy/constants';
|
|
5
4
|
|
|
6
5
|
/**
|
|
@@ -740,13 +739,66 @@ type Item = typeof items.$inferSelect;
|
|
|
740
739
|
type InventoryItem = typeof inventoryItems.$inferSelect;
|
|
741
740
|
|
|
742
741
|
type User = typeof users.$inferSelect;
|
|
742
|
+
/**
|
|
743
|
+
* TimeBack enrollment information for a game.
|
|
744
|
+
*/
|
|
745
|
+
type UserEnrollment = {
|
|
746
|
+
gameId?: string;
|
|
747
|
+
courseId: string;
|
|
748
|
+
grade: number;
|
|
749
|
+
subject: string;
|
|
750
|
+
orgId?: string;
|
|
751
|
+
};
|
|
752
|
+
/**
|
|
753
|
+
* TimeBack user role (matches OneRoster spec).
|
|
754
|
+
*/
|
|
755
|
+
type TimebackUserRole = 'administrator' | 'aide' | 'guardian' | 'parent' | 'proctor' | 'relative' | 'student' | 'teacher';
|
|
756
|
+
/**
|
|
757
|
+
* Organization type (matches OneRoster spec).
|
|
758
|
+
*/
|
|
759
|
+
type TimebackOrgType = 'department' | 'school' | 'district' | 'local' | 'state' | 'national';
|
|
760
|
+
/**
|
|
761
|
+
* TimeBack organization data for a user.
|
|
762
|
+
* Represents schools, districts, or other educational organizations.
|
|
763
|
+
*/
|
|
764
|
+
type UserOrganization = {
|
|
765
|
+
/** Organization ID (OneRoster sourcedId) */
|
|
766
|
+
id: string;
|
|
767
|
+
/** Organization name */
|
|
768
|
+
name: string | null;
|
|
769
|
+
/** Organization type (school, district, etc.) */
|
|
770
|
+
type: TimebackOrgType | string;
|
|
771
|
+
/** Whether this is the user's primary organization */
|
|
772
|
+
isPrimary: boolean;
|
|
773
|
+
};
|
|
774
|
+
/**
|
|
775
|
+
* TimeBack student profile (role + organizations).
|
|
776
|
+
* Subset of UserTimebackData returned by OneRoster API.
|
|
777
|
+
*/
|
|
778
|
+
type TimebackStudentProfile = {
|
|
779
|
+
/** User's primary role in TimeBack (student, parent, teacher, etc.) */
|
|
780
|
+
role: TimebackUserRole;
|
|
781
|
+
/** User's organizations (schools/districts) */
|
|
782
|
+
organizations: UserOrganization[];
|
|
783
|
+
};
|
|
784
|
+
/**
|
|
785
|
+
* TimeBack-related data for a user.
|
|
786
|
+
*/
|
|
787
|
+
type UserTimebackData = TimebackStudentProfile & {
|
|
788
|
+
/** User's TimeBack ID (sourcedId) */
|
|
789
|
+
id: string;
|
|
790
|
+
/** Course enrollments */
|
|
791
|
+
enrollments: UserEnrollment[];
|
|
792
|
+
};
|
|
743
793
|
/**
|
|
744
794
|
* User data with authentication provider information.
|
|
745
795
|
* Returned by the /users/me endpoint with additional auth context.
|
|
746
796
|
*/
|
|
747
|
-
type AuthenticatedUser = User & {
|
|
797
|
+
type AuthenticatedUser = Omit<User, 'timebackId'> & {
|
|
748
798
|
/** Whether the user authenticated via Timeback SSO */
|
|
749
799
|
hasTimebackAccount: boolean;
|
|
800
|
+
/** TimeBack data (id, role, enrollments, organizations) - only present if user has a timeback account */
|
|
801
|
+
timeback?: UserTimebackData;
|
|
750
802
|
};
|
|
751
803
|
/**
|
|
752
804
|
* Basic user information in the shape of the claims from identity providers
|
|
@@ -782,6 +834,9 @@ type EndActivityResponse = {
|
|
|
782
834
|
inProgress?: string;
|
|
783
835
|
};
|
|
784
836
|
|
|
837
|
+
/** Permitted HTTP verbs */
|
|
838
|
+
type Method = 'GET' | 'POST' | 'PUT' | 'PATCH' | 'DELETE';
|
|
839
|
+
|
|
785
840
|
/**
|
|
786
841
|
* Auto-initializes a PlaycademyClient with context from the environment.
|
|
787
842
|
* Works in both iframe mode (production/development) and standalone mode (local dev).
|
|
@@ -847,208 +902,103 @@ declare function init<T extends PlaycademyClient = PlaycademyClient>(this: new (
|
|
|
847
902
|
*/
|
|
848
903
|
declare function login(baseUrl: string, email: string, password: string): Promise<LoginResponse>;
|
|
849
904
|
|
|
850
|
-
/**
|
|
851
|
-
|
|
905
|
+
/**
|
|
906
|
+
* @fileoverview Authentication Strategy Pattern
|
|
907
|
+
*
|
|
908
|
+
* Provides different authentication strategies for the Playcademy SDK.
|
|
909
|
+
* Each strategy knows how to add its authentication headers to requests.
|
|
910
|
+
*/
|
|
911
|
+
|
|
912
|
+
/**
|
|
913
|
+
* Base interface for authentication strategies
|
|
914
|
+
*/
|
|
915
|
+
interface AuthStrategy {
|
|
916
|
+
/** Get the token value */
|
|
917
|
+
getToken(): string | null;
|
|
918
|
+
/** Get the token type */
|
|
919
|
+
getType(): TokenType;
|
|
920
|
+
/** Get authentication headers for a request */
|
|
921
|
+
getHeaders(): Record<string, string>;
|
|
922
|
+
}
|
|
852
923
|
|
|
853
924
|
/**
|
|
854
|
-
*
|
|
855
|
-
* Provides
|
|
925
|
+
* Base Playcademy SDK client with shared infrastructure.
|
|
926
|
+
* Provides authentication, HTTP requests, events, connection monitoring,
|
|
927
|
+
* and fundamental namespaces used by all clients.
|
|
928
|
+
*
|
|
929
|
+
* Extended by PlaycademyClient (game SDK) and PlaycademyInternalClient (platform SDK).
|
|
856
930
|
*/
|
|
857
|
-
declare class
|
|
931
|
+
declare abstract class PlaycademyBaseClient {
|
|
858
932
|
baseUrl: string;
|
|
859
933
|
gameUrl?: string;
|
|
860
|
-
|
|
861
|
-
|
|
862
|
-
|
|
863
|
-
|
|
864
|
-
|
|
865
|
-
|
|
866
|
-
|
|
867
|
-
|
|
934
|
+
protected authStrategy: AuthStrategy;
|
|
935
|
+
protected gameId?: string;
|
|
936
|
+
protected config: Partial<ClientConfig>;
|
|
937
|
+
protected listeners: EventListeners;
|
|
938
|
+
protected internalClientSessionId?: string;
|
|
939
|
+
protected authContext?: {
|
|
940
|
+
isInIframe: boolean;
|
|
941
|
+
};
|
|
942
|
+
protected initPayload?: InitPayload;
|
|
943
|
+
protected connectionManager?: ConnectionManager;
|
|
868
944
|
/**
|
|
869
945
|
* Internal session manager for automatic session lifecycle.
|
|
870
|
-
*
|
|
871
|
-
* This manager handles starting and ending game sessions automatically.
|
|
872
|
-
* Game developers don't need to call these methods directly - they're managed
|
|
873
|
-
* by the SDK during initialization and cleanup.
|
|
874
|
-
*
|
|
875
946
|
* @private
|
|
876
947
|
* @internal
|
|
877
948
|
*/
|
|
878
|
-
|
|
879
|
-
|
|
880
|
-
|
|
881
|
-
|
|
882
|
-
|
|
883
|
-
|
|
884
|
-
* @param config.token - Authentication token
|
|
885
|
-
* @param config.tokenType - Optional token type (auto-detected if not provided)
|
|
886
|
-
* @param config.gameId - Game ID for automatic session management
|
|
887
|
-
* @param config.autoStartSession - Automatically start a game session?
|
|
888
|
-
*/
|
|
949
|
+
protected _sessionManager: {
|
|
950
|
+
startSession: (gameId: string) => Promise<{
|
|
951
|
+
sessionId: string;
|
|
952
|
+
}>;
|
|
953
|
+
endSession: (sessionId: string, gameId: string) => Promise<void>;
|
|
954
|
+
};
|
|
889
955
|
constructor(config?: Partial<ClientConfig>);
|
|
890
956
|
/**
|
|
891
957
|
* Gets the effective base URL for API requests.
|
|
892
|
-
* Converts relative URLs to absolute URLs in browser environments.
|
|
893
|
-
* Note: baseUrl already includes /api suffix from constructor.
|
|
894
|
-
*
|
|
895
|
-
* @returns The complete base URL for API requests (with /api suffix)
|
|
896
958
|
*/
|
|
897
959
|
getBaseUrl(): string;
|
|
898
960
|
/**
|
|
899
961
|
* Gets the effective game backend URL for integration requests.
|
|
900
|
-
* Throws if gameUrl is not configured.
|
|
901
|
-
*
|
|
902
|
-
* @returns The complete game backend URL for API requests (with /api suffix)
|
|
903
|
-
* @throws PlaycademyError if gameUrl is not set
|
|
904
962
|
*/
|
|
905
|
-
|
|
963
|
+
protected getGameBackendUrl(): string;
|
|
906
964
|
/**
|
|
907
965
|
* Simple ping method for testing connectivity.
|
|
908
|
-
*
|
|
909
|
-
* @returns 'pong' string response
|
|
910
966
|
*/
|
|
911
967
|
ping(): string;
|
|
912
968
|
/**
|
|
913
969
|
* Sets the authentication token for API requests.
|
|
914
|
-
* Emits an 'authChange' event when the token changes.
|
|
915
|
-
*
|
|
916
|
-
* @param token - The authentication token, or null to clear
|
|
917
|
-
* @param tokenType - Optional token type (auto-detected if not provided)
|
|
918
970
|
*/
|
|
919
971
|
setToken(token: string | null, tokenType?: TokenType): void;
|
|
920
972
|
/**
|
|
921
973
|
* Gets the current token type.
|
|
922
|
-
*
|
|
923
|
-
* @returns The token type
|
|
924
974
|
*/
|
|
925
975
|
getTokenType(): TokenType;
|
|
926
976
|
/**
|
|
927
977
|
* Gets the current authentication token.
|
|
928
|
-
*
|
|
929
|
-
* @returns The current token or null if not authenticated
|
|
930
|
-
*
|
|
931
|
-
* @example
|
|
932
|
-
* ```typescript
|
|
933
|
-
* // Send token to your backend for verification
|
|
934
|
-
* const token = client.getToken()
|
|
935
|
-
* const response = await fetch('/api/auth/playcademy', {
|
|
936
|
-
* method: 'POST',
|
|
937
|
-
* body: JSON.stringify({ gameToken: token })
|
|
938
|
-
* })
|
|
939
|
-
* ```
|
|
940
978
|
*/
|
|
941
979
|
getToken(): string | null;
|
|
942
980
|
/**
|
|
943
|
-
* Checks if the client has a valid API token
|
|
944
|
-
*
|
|
945
|
-
* For games (iframe context): Checks if we have a valid token from the parent.
|
|
946
|
-
* For Cademy (standalone): Checks if we have a token from better-auth.
|
|
947
|
-
*
|
|
948
|
-
* Note: This checks for API authentication, not whether a user has linked
|
|
949
|
-
* their identity via OAuth.
|
|
950
|
-
*
|
|
951
|
-
* @returns true if API token exists, false otherwise
|
|
952
|
-
*
|
|
953
|
-
* @example
|
|
954
|
-
* ```typescript
|
|
955
|
-
* if (client.isAuthenticated()) {
|
|
956
|
-
* // Can make API calls
|
|
957
|
-
* const games = await client.games.list()
|
|
958
|
-
* } else {
|
|
959
|
-
* console.error('No API token available')
|
|
960
|
-
* }
|
|
961
|
-
* ```
|
|
981
|
+
* Checks if the client has a valid API token.
|
|
962
982
|
*/
|
|
963
983
|
isAuthenticated(): boolean;
|
|
964
984
|
/**
|
|
965
985
|
* Registers a callback to be called when authentication state changes.
|
|
966
|
-
*
|
|
967
|
-
* @param callback - Function to call when auth state changes
|
|
968
986
|
*/
|
|
969
987
|
onAuthChange(callback: (token: string | null) => void): void;
|
|
970
988
|
/**
|
|
971
989
|
* Registers a callback to be called when connection issues are detected.
|
|
972
|
-
*
|
|
973
|
-
* This is a convenience method that filters connection change events to only
|
|
974
|
-
* fire when the connection degrades (offline or degraded states). Use this
|
|
975
|
-
* when you want to handle disconnects without being notified of recoveries.
|
|
976
|
-
*
|
|
977
|
-
* For all connection state changes, use `client.on('connectionChange', ...)` instead.
|
|
978
|
-
*
|
|
979
|
-
* @param callback - Function to call when connection state changes to offline or degraded
|
|
980
|
-
* @returns Cleanup function to unregister the callback
|
|
981
|
-
*
|
|
982
|
-
* @example
|
|
983
|
-
* ```typescript
|
|
984
|
-
* const cleanup = client.onDisconnect(({ state, reason, displayAlert }) => {
|
|
985
|
-
* console.log(`Connection ${state}: ${reason}`)
|
|
986
|
-
*
|
|
987
|
-
* if (state === 'offline') {
|
|
988
|
-
* // Save state and return to game lobby
|
|
989
|
-
* displayAlert?.('Connection lost. Your progress has been saved.', { type: 'error' })
|
|
990
|
-
* saveGameState()
|
|
991
|
-
* returnToLobby()
|
|
992
|
-
* } else if (state === 'degraded') {
|
|
993
|
-
* displayAlert?.('Slow connection detected.', { type: 'warning' })
|
|
994
|
-
* }
|
|
995
|
-
* })
|
|
996
|
-
*
|
|
997
|
-
* // Later: cleanup() to unregister
|
|
998
|
-
* ```
|
|
999
|
-
*
|
|
1000
|
-
* @see Connection monitoring documentation in SDK Browser docs for detailed usage examples
|
|
1001
|
-
* @see {@link ConnectionManager.onDisconnect} for the underlying implementation
|
|
1002
990
|
*/
|
|
1003
991
|
onDisconnect(callback: (context: DisconnectContext) => void | Promise<void>): () => void;
|
|
1004
992
|
/**
|
|
1005
993
|
* Gets the current connection state.
|
|
1006
|
-
*
|
|
1007
|
-
* Returns the last known connection state without triggering a new check.
|
|
1008
|
-
* Use `checkConnection()` to force an immediate verification.
|
|
1009
|
-
*
|
|
1010
|
-
* @returns Current connection state ('online', 'offline', 'degraded') or 'unknown' if monitoring is disabled
|
|
1011
|
-
*
|
|
1012
|
-
* @example
|
|
1013
|
-
* ```typescript
|
|
1014
|
-
* const state = client.getConnectionState()
|
|
1015
|
-
* if (state === 'offline') {
|
|
1016
|
-
* console.log('No connection available')
|
|
1017
|
-
* }
|
|
1018
|
-
* ```
|
|
1019
|
-
*
|
|
1020
|
-
* @see {@link checkConnection} to trigger an immediate connection check
|
|
1021
|
-
* @see {@link ConnectionManager.getState} for the underlying implementation
|
|
1022
994
|
*/
|
|
1023
995
|
getConnectionState(): ConnectionState | 'unknown';
|
|
1024
996
|
/**
|
|
1025
997
|
* Manually triggers a connection check immediately.
|
|
1026
|
-
*
|
|
1027
|
-
* Forces a heartbeat ping to verify connectivity right now, bypassing the normal
|
|
1028
|
-
* interval. Useful when you need to verify connection status before a critical
|
|
1029
|
-
* operation (e.g., saving important game state).
|
|
1030
|
-
*
|
|
1031
|
-
* @returns Promise resolving to the current connection state after verification
|
|
1032
|
-
*
|
|
1033
|
-
* @example
|
|
1034
|
-
* ```typescript
|
|
1035
|
-
* // Check before critical operation
|
|
1036
|
-
* const state = await client.checkConnection()
|
|
1037
|
-
* if (state !== 'online') {
|
|
1038
|
-
* alert('Please check your internet connection before saving')
|
|
1039
|
-
* return
|
|
1040
|
-
* }
|
|
1041
|
-
*
|
|
1042
|
-
* await client.games.saveState(importantData)
|
|
1043
|
-
* ```
|
|
1044
|
-
*
|
|
1045
|
-
* @see {@link getConnectionState} to get the last known state without checking
|
|
1046
|
-
* @see {@link ConnectionManager.checkNow} for the underlying implementation
|
|
1047
998
|
*/
|
|
1048
999
|
checkConnection(): Promise<ConnectionState | 'unknown'>;
|
|
1049
1000
|
/**
|
|
1050
1001
|
* Sets the authentication context for the client.
|
|
1051
|
-
* This is called during initialization to store environment info.
|
|
1052
1002
|
* @internal
|
|
1053
1003
|
*/
|
|
1054
1004
|
_setAuthContext(context: {
|
|
@@ -1056,28 +1006,14 @@ declare class PlaycademyClient {
|
|
|
1056
1006
|
}): void;
|
|
1057
1007
|
/**
|
|
1058
1008
|
* Registers an event listener for client events.
|
|
1059
|
-
*
|
|
1060
|
-
* @param event - The event type to listen for
|
|
1061
|
-
* @param callback - Function to call when the event is emitted
|
|
1062
1009
|
*/
|
|
1063
1010
|
on<E extends keyof ClientEvents>(event: E, callback: (payload: ClientEvents[E]) => void): void;
|
|
1064
1011
|
/**
|
|
1065
1012
|
* Emits an event to all registered listeners.
|
|
1066
|
-
*
|
|
1067
|
-
* @param event - The event type to emit
|
|
1068
|
-
* @param payload - The event payload
|
|
1069
1013
|
*/
|
|
1070
|
-
|
|
1014
|
+
protected emit<E extends keyof ClientEvents>(event: E, payload: ClientEvents[E]): void;
|
|
1071
1015
|
/**
|
|
1072
1016
|
* Makes an authenticated HTTP request to the platform API.
|
|
1073
|
-
*
|
|
1074
|
-
* @param path - API endpoint path
|
|
1075
|
-
* @param method - HTTP method
|
|
1076
|
-
* @param options - Optional request configuration
|
|
1077
|
-
* @param options.body - Request body
|
|
1078
|
-
* @param options.headers - Additional headers
|
|
1079
|
-
* @param options.raw - If true, returns raw Response instead of parsing
|
|
1080
|
-
* @returns Promise resolving to the response data or raw Response
|
|
1081
1017
|
*/
|
|
1082
1018
|
protected request<T>(path: string, method: Method, options?: {
|
|
1083
1019
|
body?: unknown;
|
|
@@ -1086,49 +1022,64 @@ declare class PlaycademyClient {
|
|
|
1086
1022
|
}): Promise<T>;
|
|
1087
1023
|
/**
|
|
1088
1024
|
* Makes an authenticated HTTP request to the game's backend Worker.
|
|
1089
|
-
* Uses gameUrl if set, otherwise falls back to platform API.
|
|
1090
|
-
*
|
|
1091
|
-
* @param path - API endpoint path
|
|
1092
|
-
* @param method - HTTP method
|
|
1093
|
-
* @param body - Request body (optional)
|
|
1094
|
-
* @param headers - Additional headers (optional)
|
|
1095
|
-
* @param raw - If true, returns raw Response instead of parsing (optional)
|
|
1096
|
-
* @returns Promise resolving to the response data or raw Response
|
|
1097
1025
|
*/
|
|
1098
1026
|
protected requestGameBackend<T>(path: string, method: Method, body?: unknown, headers?: Record<string, string>, raw?: boolean): Promise<T>;
|
|
1099
1027
|
/**
|
|
1100
1028
|
* Ensures a gameId is available, throwing an error if not.
|
|
1101
|
-
*
|
|
1102
|
-
* @returns The gameId
|
|
1103
|
-
* @throws PlaycademyError if no gameId is configured
|
|
1104
1029
|
*/
|
|
1105
|
-
|
|
1030
|
+
protected _ensureGameId(): string;
|
|
1106
1031
|
/**
|
|
1107
1032
|
* Detects and sets the authentication context (iframe vs standalone).
|
|
1108
|
-
* Safe to call in any environment - isInIframe handles browser detection.
|
|
1109
1033
|
*/
|
|
1110
1034
|
private _detectAuthContext;
|
|
1111
1035
|
/**
|
|
1112
1036
|
* Initializes connection monitoring if enabled.
|
|
1113
|
-
* Safe to call in any environment - only runs in browser.
|
|
1114
1037
|
*/
|
|
1115
1038
|
private _initializeConnectionMonitor;
|
|
1116
1039
|
/**
|
|
1117
1040
|
* Initializes an internal game session for automatic session management.
|
|
1118
|
-
* Only starts a session if:
|
|
1119
|
-
* 1. A gameId is configured
|
|
1120
|
-
* 2. No session already exists
|
|
1121
|
-
* 3. autoStartSession is enabled (defaults to false)
|
|
1122
1041
|
*/
|
|
1123
1042
|
private _initializeInternalSession;
|
|
1124
|
-
/**
|
|
1043
|
+
/**
|
|
1044
|
+
* Current user data and inventory management.
|
|
1045
|
+
* - `me()` - Get authenticated user profile
|
|
1046
|
+
* - `inventory.get()` - List user's items
|
|
1047
|
+
* - `inventory.add(slug, qty)` - Award items to user
|
|
1048
|
+
*/
|
|
1049
|
+
users: {
|
|
1050
|
+
me: () => Promise<AuthenticatedUser>;
|
|
1051
|
+
inventory: {
|
|
1052
|
+
get: () => Promise<InventoryItemWithItem[]>;
|
|
1053
|
+
add: (identifier: string, qty: number) => Promise<InventoryMutationResponse>;
|
|
1054
|
+
remove: (identifier: string, qty: number) => Promise<InventoryMutationResponse>;
|
|
1055
|
+
quantity: (identifier: string) => Promise<number>;
|
|
1056
|
+
has: (identifier: string, minQuantity?: number) => Promise<boolean>;
|
|
1057
|
+
};
|
|
1058
|
+
};
|
|
1059
|
+
}
|
|
1060
|
+
|
|
1061
|
+
/**
|
|
1062
|
+
* Playcademy SDK client for game developers.
|
|
1063
|
+
* Provides namespaced access to platform features for games running inside Cademy.
|
|
1064
|
+
*/
|
|
1065
|
+
declare class PlaycademyClient extends PlaycademyBaseClient {
|
|
1066
|
+
/**
|
|
1067
|
+
* Connect external identity providers to the user's Playcademy account.
|
|
1068
|
+
* - `connect(provider)` - Link Discord, Google, etc. via OAuth popup
|
|
1069
|
+
*/
|
|
1125
1070
|
identity: {
|
|
1126
1071
|
connect: (options: AuthOptions) => Promise<AuthResult>;
|
|
1127
1072
|
_getContext: () => {
|
|
1128
1073
|
isInIframe: boolean;
|
|
1129
1074
|
};
|
|
1130
1075
|
};
|
|
1131
|
-
/**
|
|
1076
|
+
/**
|
|
1077
|
+
* Game runtime lifecycle and asset loading.
|
|
1078
|
+
* - `exit()` - Return to Cademy hub
|
|
1079
|
+
* - `getGameToken()` - Get short-lived auth token
|
|
1080
|
+
* - `assets.url()`, `assets.json()`, `assets.fetch()` - Load game assets
|
|
1081
|
+
* - `on('pause')`, `on('resume')` - Handle visibility changes
|
|
1082
|
+
*/
|
|
1132
1083
|
runtime: {
|
|
1133
1084
|
getGameToken: (gameId: string, options?: {
|
|
1134
1085
|
apply?: boolean;
|
|
@@ -1163,42 +1114,58 @@ declare class PlaycademyClient {
|
|
|
1163
1114
|
arrayBuffer: (path: string) => Promise<ArrayBuffer>;
|
|
1164
1115
|
};
|
|
1165
1116
|
};
|
|
1166
|
-
/**
|
|
1167
|
-
|
|
1168
|
-
|
|
1169
|
-
|
|
1170
|
-
|
|
1171
|
-
|
|
1172
|
-
|
|
1173
|
-
|
|
1174
|
-
|
|
1175
|
-
|
|
1176
|
-
|
|
1177
|
-
|
|
1117
|
+
/**
|
|
1118
|
+
* TimeBack integration for activity tracking and user context.
|
|
1119
|
+
*
|
|
1120
|
+
* User context (cached from init, refreshable):
|
|
1121
|
+
* - `user.role` - User's role (student, parent, teacher, etc.)
|
|
1122
|
+
* - `user.enrollments` - Courses the player is enrolled in for this game
|
|
1123
|
+
* - `user.organizations` - Schools/districts the player belongs to
|
|
1124
|
+
* - `user.fetch()` - Refresh user context from server
|
|
1125
|
+
*
|
|
1126
|
+
* Activity tracking:
|
|
1127
|
+
* - `startActivity(metadata)` - Begin tracking an activity
|
|
1128
|
+
* - `pauseActivity()` / `resumeActivity()` - Pause/resume timer
|
|
1129
|
+
* - `endActivity(scoreData)` - Submit activity results to TimeBack
|
|
1130
|
+
*/
|
|
1178
1131
|
timeback: {
|
|
1132
|
+
readonly user: TimebackUser;
|
|
1179
1133
|
startActivity: (metadata: _playcademy_timeback_types.ActivityData) => void;
|
|
1180
1134
|
pauseActivity: () => void;
|
|
1181
1135
|
resumeActivity: () => void;
|
|
1182
1136
|
endActivity: (data: _playcademy_timeback_types.EndActivityScoreData) => Promise<EndActivityResponse>;
|
|
1183
1137
|
};
|
|
1184
|
-
/**
|
|
1138
|
+
/**
|
|
1139
|
+
* Playcademy Credits (platform currency) management.
|
|
1140
|
+
* - `get()` - Get user's credit balance
|
|
1141
|
+
* - `add(amount)` - Award credits to user
|
|
1142
|
+
*/
|
|
1185
1143
|
credits: {
|
|
1186
1144
|
balance: () => Promise<number>;
|
|
1187
1145
|
add: (amount: number) => Promise<number>;
|
|
1188
1146
|
spend: (amount: number) => Promise<number>;
|
|
1189
1147
|
};
|
|
1190
|
-
/**
|
|
1148
|
+
/**
|
|
1149
|
+
* Game score submission and leaderboards.
|
|
1150
|
+
* - `submit(gameId, score, metadata?)` - Record a game score
|
|
1151
|
+
*/
|
|
1191
1152
|
scores: {
|
|
1192
1153
|
submit: (gameId: string, score: number, metadata?: Record<string, unknown>) => Promise<ScoreSubmission>;
|
|
1193
1154
|
};
|
|
1194
|
-
/**
|
|
1155
|
+
/**
|
|
1156
|
+
* Realtime multiplayer authentication.
|
|
1157
|
+
* - `getToken()` - Get token for WebSocket/realtime connections
|
|
1158
|
+
*/
|
|
1195
1159
|
realtime: {
|
|
1196
1160
|
token: {
|
|
1197
1161
|
get: () => Promise<RealtimeTokenResponse>;
|
|
1198
1162
|
};
|
|
1199
|
-
open(channel?: string, url?: string): Promise<_playcademy_realtime_server_types.RealtimeChannel>;
|
|
1200
1163
|
};
|
|
1201
|
-
/**
|
|
1164
|
+
/**
|
|
1165
|
+
* Make requests to your game's custom backend API routes.
|
|
1166
|
+
* - `get(path)`, `post(path, body)`, `put()`, `delete()` - HTTP methods
|
|
1167
|
+
* - Routes are relative to your game's deployment (e.g., '/hello' → your-game.playcademy.gg/api/hello)
|
|
1168
|
+
*/
|
|
1202
1169
|
backend: {
|
|
1203
1170
|
get<T = unknown>(path: string, headers?: Record<string, string>): Promise<T>;
|
|
1204
1171
|
post<T = unknown>(path: string, body?: unknown, headers?: Record<string, string>): Promise<T>;
|
|
@@ -1219,9 +1186,70 @@ declare class PlaycademyClient {
|
|
|
1219
1186
|
};
|
|
1220
1187
|
}
|
|
1221
1188
|
|
|
1189
|
+
/**
|
|
1190
|
+
* Type definitions for the game timeback namespace.
|
|
1191
|
+
*
|
|
1192
|
+
* Re-exports core types from @playcademy/data for SDK consumers,
|
|
1193
|
+
* plus SDK-specific types like TimebackInitContext.
|
|
1194
|
+
*/
|
|
1195
|
+
|
|
1196
|
+
/**
|
|
1197
|
+
* A TimeBack enrollment for the current game session.
|
|
1198
|
+
* Alias for UserEnrollment without the optional gameId.
|
|
1199
|
+
*/
|
|
1200
|
+
type TimebackEnrollment = Omit<UserEnrollment, 'gameId'>;
|
|
1201
|
+
/**
|
|
1202
|
+
* A TimeBack organization (school/district) for the current user.
|
|
1203
|
+
* Alias for UserOrganization.
|
|
1204
|
+
*/
|
|
1205
|
+
type TimebackOrganization = UserOrganization;
|
|
1206
|
+
/**
|
|
1207
|
+
* TimeBack context passed during game initialization.
|
|
1208
|
+
* This is sent from the platform (cademy) to the game iframe via postMessage.
|
|
1209
|
+
*/
|
|
1210
|
+
interface TimebackInitContext {
|
|
1211
|
+
/** User's TimeBack ID */
|
|
1212
|
+
id: string;
|
|
1213
|
+
/** User's role in TimeBack (student, parent, teacher, etc.) */
|
|
1214
|
+
role: TimebackUserRole;
|
|
1215
|
+
/** User's enrollments for this game (one per grade/subject combo) */
|
|
1216
|
+
enrollments: TimebackEnrollment[];
|
|
1217
|
+
/** User's organizations (schools/districts) */
|
|
1218
|
+
organizations: TimebackOrganization[];
|
|
1219
|
+
}
|
|
1220
|
+
/**
|
|
1221
|
+
* TimeBack user context with current data (may be stale from init).
|
|
1222
|
+
* Use `fetch()` to get fresh data from the server.
|
|
1223
|
+
*/
|
|
1224
|
+
interface TimebackUserContext {
|
|
1225
|
+
/** User's TimeBack ID */
|
|
1226
|
+
id: string | undefined;
|
|
1227
|
+
/** User's role in TimeBack (student, parent, teacher, etc.) */
|
|
1228
|
+
role: TimebackUserRole | undefined;
|
|
1229
|
+
/** User's enrollments for this game */
|
|
1230
|
+
enrollments: TimebackEnrollment[];
|
|
1231
|
+
/** User's organizations (schools/districts) */
|
|
1232
|
+
organizations: TimebackOrganization[];
|
|
1233
|
+
}
|
|
1234
|
+
/**
|
|
1235
|
+
* TimeBack user object with both cached getters and fetch method.
|
|
1236
|
+
*/
|
|
1237
|
+
interface TimebackUser extends TimebackUserContext {
|
|
1238
|
+
/**
|
|
1239
|
+
* Fetch TimeBack data from the server (cached for 5 min).
|
|
1240
|
+
* Updates the cached values so subsequent property access returns fresh data.
|
|
1241
|
+
* @param options - Cache options (pass { force: true } to bypass cache)
|
|
1242
|
+
* @returns Promise resolving to fresh user context
|
|
1243
|
+
*/
|
|
1244
|
+
fetch(options?: {
|
|
1245
|
+
force?: boolean;
|
|
1246
|
+
}): Promise<TimebackUserContext>;
|
|
1247
|
+
}
|
|
1248
|
+
|
|
1222
1249
|
/**
|
|
1223
1250
|
* Core client configuration and lifecycle types
|
|
1224
1251
|
*/
|
|
1252
|
+
|
|
1225
1253
|
type TokenType = 'session' | 'apiKey' | 'gameJwt';
|
|
1226
1254
|
interface ClientConfig {
|
|
1227
1255
|
baseUrl: string;
|
|
@@ -1254,6 +1282,20 @@ interface DisconnectContext {
|
|
|
1254
1282
|
duration?: number;
|
|
1255
1283
|
}) => void;
|
|
1256
1284
|
}
|
|
1285
|
+
interface InitPayload {
|
|
1286
|
+
/** Hub API base URL */
|
|
1287
|
+
baseUrl: string;
|
|
1288
|
+
/** Game deployment URL (serves both frontend assets and backend API) */
|
|
1289
|
+
gameUrl?: string;
|
|
1290
|
+
/** Short-lived game token */
|
|
1291
|
+
token: string;
|
|
1292
|
+
/** Game ID */
|
|
1293
|
+
gameId: string;
|
|
1294
|
+
/** Realtime WebSocket URL */
|
|
1295
|
+
realtimeUrl?: string;
|
|
1296
|
+
/** Timeback context (if user has a Timeback account) */
|
|
1297
|
+
timeback?: TimebackInitContext;
|
|
1298
|
+
}
|
|
1257
1299
|
type GameContextPayload = {
|
|
1258
1300
|
token: string;
|
|
1259
1301
|
baseUrl: string;
|
|
@@ -1261,6 +1303,9 @@ type GameContextPayload = {
|
|
|
1261
1303
|
gameId: string;
|
|
1262
1304
|
forwardKeys?: string[];
|
|
1263
1305
|
};
|
|
1306
|
+
type EventListeners = {
|
|
1307
|
+
[E in keyof ClientEvents]?: Array<(payload: ClientEvents[E]) => void>;
|
|
1308
|
+
};
|
|
1264
1309
|
interface ClientEvents {
|
|
1265
1310
|
authChange: {
|
|
1266
1311
|
token: string | null;
|