@playcademy/sdk 0.14.0 → 0.14.1-beta.1
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/dist/index.d.ts +9 -0
- package/dist/index.js +31 -2
- package/dist/internal.d.ts +1112 -1070
- package/dist/internal.js +31 -2
- package/dist/server/edge.js +1 -1
- package/dist/server.js +1 -1
- package/dist/types.d.ts +44 -2
- package/package.json +1 -1
package/dist/internal.d.ts
CHANGED
|
@@ -2,8 +2,8 @@ import { SchemaInfo } from '@playcademy/cloudflare';
|
|
|
2
2
|
import { TimebackGrade, TimebackSubject, HeartbeatRequest, TimebackCourseConfig, CourseConfig, OrganizationConfig, ComponentConfig, ResourceConfig, ComponentResourceConfig } from '@playcademy/types/timeback';
|
|
3
3
|
export { QtiTestQuestionRef, QtiTestQuestionsResponse } from '@playcademy/types/timeback';
|
|
4
4
|
import * as _playcademy_types from '@playcademy/types';
|
|
5
|
-
import { GameManifest } from '@playcademy/types';
|
|
6
|
-
export { AuthenticatedUser, DeveloperStatusEnumType, DeveloperStatusResponse, DeveloperStatusValue, GameCourseMetrics, GameLeaderboardEntry, GameManifest, GameMetricComparisonKind, GameMetricComparisonMetric, GameMetricComparisonRow, GameMetricComparisonRowStatus, GameMetricsProxyResponse, GameMetricsResponse, GameMetricsUnsupportedReason, GamePlatform, GameRunMetrics, GameRunMetricsComparison, GameRunMetricsComparisonStatus, GameRunMetricsComparisonSummary, GameTimebackIntegration, GameType, GameUser, LeaderboardEntry, LeaderboardOptions, LeaderboardTimeframe, ManifestV1, ManifestV2, ManifestVersions, PopulateStudentResponse, UserEnrollment, UserInfo, UserOrganization, UserRank, UserRankResponse, UserRoleEnumType, UserScore, UserTimebackData } from '@playcademy/types';
|
|
5
|
+
import { GameManifest, LocalDayContext } from '@playcademy/types';
|
|
6
|
+
export { AuthenticatedUser, DeveloperStatusEnumType, DeveloperStatusResponse, DeveloperStatusValue, GameCourseMetrics, GameLeaderboardEntry, GameManifest, GameMetricComparisonKind, GameMetricComparisonMetric, GameMetricComparisonRow, GameMetricComparisonRowStatus, GameMetricsProxyResponse, GameMetricsResponse, GameMetricsUnsupportedReason, GamePlatform, GameRunMetrics, GameRunMetricsComparison, GameRunMetricsComparisonStatus, GameRunMetricsComparisonSummary, GameTimebackIntegration, GameType, GameUser, LeaderboardEntry, LeaderboardOptions, LeaderboardTimeframe, LocalDayContext, LocalDaySource, ManifestV1, ManifestV2, ManifestVersions, PopulateStudentResponse, UserEnrollment, UserInfo, UserOrganization, UserRank, UserRankResponse, UserRoleEnumType, UserScore, UserTimebackData } from '@playcademy/types';
|
|
7
7
|
import * as drizzle_orm_pg_core from 'drizzle-orm/pg-core';
|
|
8
8
|
import { z } from 'zod';
|
|
9
9
|
import { DomainValidationRecords } from '@playcademy/types/game';
|
|
@@ -756,951 +756,273 @@ interface AuthStrategy {
|
|
|
756
756
|
getHeaders(): Record<string, string>;
|
|
757
757
|
}
|
|
758
758
|
|
|
759
|
+
declare const users: drizzle_orm_pg_core.PgTableWithColumns<{
|
|
760
|
+
name: "user";
|
|
761
|
+
schema: undefined;
|
|
762
|
+
columns: {
|
|
763
|
+
id: drizzle_orm_pg_core.PgColumn<{
|
|
764
|
+
name: "id";
|
|
765
|
+
tableName: "user";
|
|
766
|
+
dataType: "string";
|
|
767
|
+
columnType: "PgText";
|
|
768
|
+
data: string;
|
|
769
|
+
driverParam: string;
|
|
770
|
+
notNull: true;
|
|
771
|
+
hasDefault: true;
|
|
772
|
+
isPrimaryKey: true;
|
|
773
|
+
isAutoincrement: false;
|
|
774
|
+
hasRuntimeDefault: true;
|
|
775
|
+
enumValues: [string, ...string[]];
|
|
776
|
+
baseColumn: never;
|
|
777
|
+
identity: undefined;
|
|
778
|
+
generated: undefined;
|
|
779
|
+
}, {}, {}>;
|
|
780
|
+
name: drizzle_orm_pg_core.PgColumn<{
|
|
781
|
+
name: "name";
|
|
782
|
+
tableName: "user";
|
|
783
|
+
dataType: "string";
|
|
784
|
+
columnType: "PgText";
|
|
785
|
+
data: string;
|
|
786
|
+
driverParam: string;
|
|
787
|
+
notNull: true;
|
|
788
|
+
hasDefault: false;
|
|
789
|
+
isPrimaryKey: false;
|
|
790
|
+
isAutoincrement: false;
|
|
791
|
+
hasRuntimeDefault: false;
|
|
792
|
+
enumValues: [string, ...string[]];
|
|
793
|
+
baseColumn: never;
|
|
794
|
+
identity: undefined;
|
|
795
|
+
generated: undefined;
|
|
796
|
+
}, {}, {}>;
|
|
797
|
+
username: drizzle_orm_pg_core.PgColumn<{
|
|
798
|
+
name: "username";
|
|
799
|
+
tableName: "user";
|
|
800
|
+
dataType: "string";
|
|
801
|
+
columnType: "PgText";
|
|
802
|
+
data: string;
|
|
803
|
+
driverParam: string;
|
|
804
|
+
notNull: false;
|
|
805
|
+
hasDefault: false;
|
|
806
|
+
isPrimaryKey: false;
|
|
807
|
+
isAutoincrement: false;
|
|
808
|
+
hasRuntimeDefault: false;
|
|
809
|
+
enumValues: [string, ...string[]];
|
|
810
|
+
baseColumn: never;
|
|
811
|
+
identity: undefined;
|
|
812
|
+
generated: undefined;
|
|
813
|
+
}, {}, {}>;
|
|
814
|
+
email: drizzle_orm_pg_core.PgColumn<{
|
|
815
|
+
name: "email";
|
|
816
|
+
tableName: "user";
|
|
817
|
+
dataType: "string";
|
|
818
|
+
columnType: "PgText";
|
|
819
|
+
data: string;
|
|
820
|
+
driverParam: string;
|
|
821
|
+
notNull: true;
|
|
822
|
+
hasDefault: false;
|
|
823
|
+
isPrimaryKey: false;
|
|
824
|
+
isAutoincrement: false;
|
|
825
|
+
hasRuntimeDefault: false;
|
|
826
|
+
enumValues: [string, ...string[]];
|
|
827
|
+
baseColumn: never;
|
|
828
|
+
identity: undefined;
|
|
829
|
+
generated: undefined;
|
|
830
|
+
}, {}, {}>;
|
|
831
|
+
isAnonymous: drizzle_orm_pg_core.PgColumn<{
|
|
832
|
+
name: "is_anonymous";
|
|
833
|
+
tableName: "user";
|
|
834
|
+
dataType: "boolean";
|
|
835
|
+
columnType: "PgBoolean";
|
|
836
|
+
data: boolean;
|
|
837
|
+
driverParam: boolean;
|
|
838
|
+
notNull: true;
|
|
839
|
+
hasDefault: true;
|
|
840
|
+
isPrimaryKey: false;
|
|
841
|
+
isAutoincrement: false;
|
|
842
|
+
hasRuntimeDefault: false;
|
|
843
|
+
enumValues: undefined;
|
|
844
|
+
baseColumn: never;
|
|
845
|
+
identity: undefined;
|
|
846
|
+
generated: undefined;
|
|
847
|
+
}, {}, {}>;
|
|
848
|
+
timebackId: drizzle_orm_pg_core.PgColumn<{
|
|
849
|
+
name: "timeback_id";
|
|
850
|
+
tableName: "user";
|
|
851
|
+
dataType: "string";
|
|
852
|
+
columnType: "PgText";
|
|
853
|
+
data: string;
|
|
854
|
+
driverParam: string;
|
|
855
|
+
notNull: false;
|
|
856
|
+
hasDefault: false;
|
|
857
|
+
isPrimaryKey: false;
|
|
858
|
+
isAutoincrement: false;
|
|
859
|
+
hasRuntimeDefault: false;
|
|
860
|
+
enumValues: [string, ...string[]];
|
|
861
|
+
baseColumn: never;
|
|
862
|
+
identity: undefined;
|
|
863
|
+
generated: undefined;
|
|
864
|
+
}, {}, {}>;
|
|
865
|
+
learningTimeZone: drizzle_orm_pg_core.PgColumn<{
|
|
866
|
+
name: "learning_time_zone";
|
|
867
|
+
tableName: "user";
|
|
868
|
+
dataType: "string";
|
|
869
|
+
columnType: "PgText";
|
|
870
|
+
data: string;
|
|
871
|
+
driverParam: string;
|
|
872
|
+
notNull: false;
|
|
873
|
+
hasDefault: false;
|
|
874
|
+
isPrimaryKey: false;
|
|
875
|
+
isAutoincrement: false;
|
|
876
|
+
hasRuntimeDefault: false;
|
|
877
|
+
enumValues: [string, ...string[]];
|
|
878
|
+
baseColumn: never;
|
|
879
|
+
identity: undefined;
|
|
880
|
+
generated: undefined;
|
|
881
|
+
}, {}, {}>;
|
|
882
|
+
learningTimeZoneUpdatedAt: drizzle_orm_pg_core.PgColumn<{
|
|
883
|
+
name: "learning_time_zone_updated_at";
|
|
884
|
+
tableName: "user";
|
|
885
|
+
dataType: "date";
|
|
886
|
+
columnType: "PgTimestamp";
|
|
887
|
+
data: Date;
|
|
888
|
+
driverParam: string;
|
|
889
|
+
notNull: false;
|
|
890
|
+
hasDefault: false;
|
|
891
|
+
isPrimaryKey: false;
|
|
892
|
+
isAutoincrement: false;
|
|
893
|
+
hasRuntimeDefault: false;
|
|
894
|
+
enumValues: undefined;
|
|
895
|
+
baseColumn: never;
|
|
896
|
+
identity: undefined;
|
|
897
|
+
generated: undefined;
|
|
898
|
+
}, {}, {}>;
|
|
899
|
+
emailVerified: drizzle_orm_pg_core.PgColumn<{
|
|
900
|
+
name: "email_verified";
|
|
901
|
+
tableName: "user";
|
|
902
|
+
dataType: "boolean";
|
|
903
|
+
columnType: "PgBoolean";
|
|
904
|
+
data: boolean;
|
|
905
|
+
driverParam: boolean;
|
|
906
|
+
notNull: true;
|
|
907
|
+
hasDefault: true;
|
|
908
|
+
isPrimaryKey: false;
|
|
909
|
+
isAutoincrement: false;
|
|
910
|
+
hasRuntimeDefault: false;
|
|
911
|
+
enumValues: undefined;
|
|
912
|
+
baseColumn: never;
|
|
913
|
+
identity: undefined;
|
|
914
|
+
generated: undefined;
|
|
915
|
+
}, {}, {}>;
|
|
916
|
+
image: drizzle_orm_pg_core.PgColumn<{
|
|
917
|
+
name: "image";
|
|
918
|
+
tableName: "user";
|
|
919
|
+
dataType: "string";
|
|
920
|
+
columnType: "PgText";
|
|
921
|
+
data: string;
|
|
922
|
+
driverParam: string;
|
|
923
|
+
notNull: false;
|
|
924
|
+
hasDefault: false;
|
|
925
|
+
isPrimaryKey: false;
|
|
926
|
+
isAutoincrement: false;
|
|
927
|
+
hasRuntimeDefault: false;
|
|
928
|
+
enumValues: [string, ...string[]];
|
|
929
|
+
baseColumn: never;
|
|
930
|
+
identity: undefined;
|
|
931
|
+
generated: undefined;
|
|
932
|
+
}, {}, {}>;
|
|
933
|
+
role: drizzle_orm_pg_core.PgColumn<{
|
|
934
|
+
name: "role";
|
|
935
|
+
tableName: "user";
|
|
936
|
+
dataType: "string";
|
|
937
|
+
columnType: "PgEnumColumn";
|
|
938
|
+
data: "admin" | "developer" | "player" | "teacher";
|
|
939
|
+
driverParam: string;
|
|
940
|
+
notNull: true;
|
|
941
|
+
hasDefault: true;
|
|
942
|
+
isPrimaryKey: false;
|
|
943
|
+
isAutoincrement: false;
|
|
944
|
+
hasRuntimeDefault: false;
|
|
945
|
+
enumValues: ["admin", "player", "developer", "teacher"];
|
|
946
|
+
baseColumn: never;
|
|
947
|
+
identity: undefined;
|
|
948
|
+
generated: undefined;
|
|
949
|
+
}, {}, {}>;
|
|
950
|
+
developerStatus: drizzle_orm_pg_core.PgColumn<{
|
|
951
|
+
name: "developer_status";
|
|
952
|
+
tableName: "user";
|
|
953
|
+
dataType: "string";
|
|
954
|
+
columnType: "PgEnumColumn";
|
|
955
|
+
data: "approved" | "none" | "pending";
|
|
956
|
+
driverParam: string;
|
|
957
|
+
notNull: true;
|
|
958
|
+
hasDefault: true;
|
|
959
|
+
isPrimaryKey: false;
|
|
960
|
+
isAutoincrement: false;
|
|
961
|
+
hasRuntimeDefault: false;
|
|
962
|
+
enumValues: ["none", "pending", "approved"];
|
|
963
|
+
baseColumn: never;
|
|
964
|
+
identity: undefined;
|
|
965
|
+
generated: undefined;
|
|
966
|
+
}, {}, {}>;
|
|
967
|
+
createdAt: drizzle_orm_pg_core.PgColumn<{
|
|
968
|
+
name: "created_at";
|
|
969
|
+
tableName: "user";
|
|
970
|
+
dataType: "date";
|
|
971
|
+
columnType: "PgTimestamp";
|
|
972
|
+
data: Date;
|
|
973
|
+
driverParam: string;
|
|
974
|
+
notNull: true;
|
|
975
|
+
hasDefault: false;
|
|
976
|
+
isPrimaryKey: false;
|
|
977
|
+
isAutoincrement: false;
|
|
978
|
+
hasRuntimeDefault: false;
|
|
979
|
+
enumValues: undefined;
|
|
980
|
+
baseColumn: never;
|
|
981
|
+
identity: undefined;
|
|
982
|
+
generated: undefined;
|
|
983
|
+
}, {}, {}>;
|
|
984
|
+
updatedAt: drizzle_orm_pg_core.PgColumn<{
|
|
985
|
+
name: "updated_at";
|
|
986
|
+
tableName: "user";
|
|
987
|
+
dataType: "date";
|
|
988
|
+
columnType: "PgTimestamp";
|
|
989
|
+
data: Date;
|
|
990
|
+
driverParam: string;
|
|
991
|
+
notNull: true;
|
|
992
|
+
hasDefault: false;
|
|
993
|
+
isPrimaryKey: false;
|
|
994
|
+
isAutoincrement: false;
|
|
995
|
+
hasRuntimeDefault: false;
|
|
996
|
+
enumValues: undefined;
|
|
997
|
+
baseColumn: never;
|
|
998
|
+
identity: undefined;
|
|
999
|
+
generated: undefined;
|
|
1000
|
+
}, {}, {}>;
|
|
1001
|
+
};
|
|
1002
|
+
dialect: 'pg';
|
|
1003
|
+
}>;
|
|
1004
|
+
|
|
1005
|
+
interface GameMetadata {
|
|
1006
|
+
description?: string;
|
|
1007
|
+
emoji?: string;
|
|
1008
|
+
[key: string]: unknown;
|
|
1009
|
+
}
|
|
759
1010
|
/**
|
|
760
|
-
*
|
|
761
|
-
*
|
|
762
|
-
* and fundamental namespaces used by all clients.
|
|
763
|
-
*
|
|
764
|
-
* Extended by PlaycademyClient (game SDK) and PlaycademyInternalClient (platform SDK).
|
|
1011
|
+
* DNS validation records for custom hostname
|
|
1012
|
+
* Structure for the validationRecords JSON field in game_custom_hostnames table
|
|
765
1013
|
*/
|
|
766
|
-
|
|
767
|
-
|
|
768
|
-
|
|
769
|
-
|
|
770
|
-
|
|
771
|
-
|
|
772
|
-
protected config: Partial<ClientConfig>;
|
|
773
|
-
protected listeners: EventListeners;
|
|
774
|
-
protected authContext?: {
|
|
775
|
-
isInIframe: boolean;
|
|
776
|
-
};
|
|
777
|
-
protected initPayload?: InitPayload;
|
|
778
|
-
protected launchId?: string;
|
|
779
|
-
protected gameOrigin?: string;
|
|
780
|
-
constructor(config?: Partial<ClientConfig>);
|
|
781
|
-
/**
|
|
782
|
-
* Gets the effective base URL for API requests.
|
|
783
|
-
*/
|
|
784
|
-
getBaseUrl(): string;
|
|
785
|
-
/**
|
|
786
|
-
* Gets the effective game backend URL for integration requests.
|
|
787
|
-
*/
|
|
788
|
-
protected getGameBackendUrl(): string;
|
|
789
|
-
/**
|
|
790
|
-
* Simple ping method for testing connectivity.
|
|
791
|
-
*/
|
|
792
|
-
ping(): string;
|
|
793
|
-
/**
|
|
794
|
-
* Sets the authentication token for API requests.
|
|
795
|
-
*/
|
|
796
|
-
setToken(token: string | null, tokenType?: TokenType): void;
|
|
797
|
-
setLaunchId(launchId: string | null | undefined): void;
|
|
798
|
-
/**
|
|
799
|
-
* Gets the current token type.
|
|
800
|
-
*/
|
|
801
|
-
getTokenType(): TokenType;
|
|
802
|
-
/**
|
|
803
|
-
* Gets the current authentication token.
|
|
804
|
-
*/
|
|
805
|
-
getToken(): string | null;
|
|
806
|
-
/**
|
|
807
|
-
* Checks if the client has a valid API token.
|
|
808
|
-
*/
|
|
809
|
-
isAuthenticated(): boolean;
|
|
810
|
-
/**
|
|
811
|
-
* Registers a callback to be called when authentication state changes.
|
|
812
|
-
*/
|
|
813
|
-
onAuthChange(callback: (token: string | null) => void): void;
|
|
814
|
-
/**
|
|
815
|
-
* Sets the authentication context for the client.
|
|
816
|
-
* @internal
|
|
817
|
-
*/
|
|
818
|
-
_setAuthContext(context: {
|
|
819
|
-
isInIframe: boolean;
|
|
820
|
-
}): void;
|
|
821
|
-
/**
|
|
822
|
-
* Registers an event listener for client events.
|
|
823
|
-
*
|
|
824
|
-
* @param event - The event name to listen for.
|
|
825
|
-
* @param callback - The handler invoked when the event fires.
|
|
826
|
-
* @returns A cleanup function that removes this specific listener.
|
|
827
|
-
*/
|
|
828
|
-
on<E extends keyof ClientEvents>(event: E, callback: (payload: ClientEvents[E]) => void): () => void;
|
|
829
|
-
/**
|
|
830
|
-
* Removes a previously registered event listener.
|
|
831
|
-
*
|
|
832
|
-
* @param event - The event name to stop listening for.
|
|
833
|
-
* @param callback - The exact function reference passed to {@link on}.
|
|
834
|
-
*/
|
|
835
|
-
off<E extends keyof ClientEvents>(event: E, callback: (payload: ClientEvents[E]) => void): void;
|
|
836
|
-
/**
|
|
837
|
-
* Emits an event to all registered listeners.
|
|
838
|
-
*/
|
|
839
|
-
protected emit<E extends keyof ClientEvents>(event: E, payload: ClientEvents[E]): void;
|
|
840
|
-
/**
|
|
841
|
-
* Makes an authenticated HTTP request to the platform API.
|
|
842
|
-
*/
|
|
843
|
-
protected request<T>(path: string, method: Method, options?: {
|
|
844
|
-
body?: unknown;
|
|
845
|
-
headers?: Record<string, string>;
|
|
846
|
-
raw?: boolean;
|
|
847
|
-
retryPolicy?: RetryPolicy;
|
|
848
|
-
}): Promise<T>;
|
|
849
|
-
/**
|
|
850
|
-
* Makes an authenticated HTTP request to the game's backend Worker.
|
|
851
|
-
*/
|
|
852
|
-
protected requestGameBackend<T>(path: string, method: Method, body?: unknown, headers?: Record<string, string>, options?: {
|
|
853
|
-
raw?: boolean;
|
|
854
|
-
retryPolicy?: RetryPolicy;
|
|
855
|
-
}): Promise<T>;
|
|
856
|
-
/**
|
|
857
|
-
* Ensures a gameId is available, throwing an error if not.
|
|
858
|
-
*/
|
|
859
|
-
protected _ensureGameId(): string;
|
|
860
|
-
private _parseOrigin;
|
|
861
|
-
/**
|
|
862
|
-
* Detects and sets the authentication context (iframe vs standalone).
|
|
863
|
-
*/
|
|
864
|
-
private _detectAuthContext;
|
|
865
|
-
/**
|
|
866
|
-
* Current user data.
|
|
867
|
-
* - `me()` - Get authenticated user profile
|
|
868
|
-
*/
|
|
869
|
-
users: {
|
|
870
|
-
me: () => Promise<_playcademy_types.AuthenticatedUser>;
|
|
1014
|
+
interface CustomHostnameValidationRecords {
|
|
1015
|
+
/** TXT record for ownership verification */
|
|
1016
|
+
ownership?: {
|
|
1017
|
+
name?: string;
|
|
1018
|
+
value?: string;
|
|
1019
|
+
type?: string;
|
|
871
1020
|
};
|
|
872
|
-
|
|
873
|
-
|
|
874
|
-
|
|
875
|
-
|
|
876
|
-
|
|
877
|
-
*
|
|
878
|
-
* This is the recommended way to initialize the SDK as it automatically:
|
|
879
|
-
* - Detects the runtime environment (iframe vs standalone)
|
|
880
|
-
* - Configures the client with the appropriate context
|
|
881
|
-
* - Sets up event listeners for token refresh
|
|
882
|
-
* - Exposes the client for debugging in development mode
|
|
883
|
-
*
|
|
884
|
-
* @param options - Optional configuration overrides
|
|
885
|
-
* @param options.baseUrl - Override the base URL for API requests
|
|
886
|
-
* @returns Promise resolving to a fully initialized PlaycademyClient
|
|
887
|
-
* @throws Error if not running in a browser context
|
|
888
|
-
*
|
|
889
|
-
* @example
|
|
890
|
-
* ```typescript
|
|
891
|
-
* // Default initialization
|
|
892
|
-
* const client = await PlaycademyClient.init()
|
|
893
|
-
*
|
|
894
|
-
* // With custom base URL
|
|
895
|
-
* const client = await PlaycademyClient.init({ baseUrl: 'https://custom.api.com' })
|
|
896
|
-
* ```
|
|
897
|
-
*/
|
|
898
|
-
declare function init<T extends PlaycademyBaseClient = PlaycademyBaseClient>(this: new (config?: Partial<ClientConfig>) => T, options?: {
|
|
899
|
-
baseUrl?: string;
|
|
900
|
-
allowedParentOrigins?: string[];
|
|
901
|
-
}): Promise<T>;
|
|
902
|
-
|
|
903
|
-
/**
|
|
904
|
-
* Authenticates a user with email and password.
|
|
905
|
-
*
|
|
906
|
-
* This is a standalone authentication method that doesn't require an initialized client.
|
|
907
|
-
* Use this for login flows before creating a client instance.
|
|
908
|
-
*
|
|
909
|
-
* @deprecated Use client.auth.login() instead for better error handling and automatic token management
|
|
910
|
-
*
|
|
911
|
-
* @param baseUrl - The base URL of the Playcademy API
|
|
912
|
-
* @param email - User's email address
|
|
913
|
-
* @param password - User's password
|
|
914
|
-
* @returns Promise resolving to authentication response with token
|
|
915
|
-
* @throws PlaycademyError if authentication fails or network error occurs
|
|
916
|
-
*
|
|
917
|
-
* @example
|
|
918
|
-
* ```typescript
|
|
919
|
-
* // Preferred approach:
|
|
920
|
-
* const client = new PlaycademyClient({ baseUrl: '/api' })
|
|
921
|
-
* const result = await client.auth.login({
|
|
922
|
-
* email: 'user@example.com',
|
|
923
|
-
* password: 'password'
|
|
924
|
-
* })
|
|
925
|
-
*
|
|
926
|
-
* // Legacy approach (still works):
|
|
927
|
-
* try {
|
|
928
|
-
* const response = await PlaycademyClient.login('/api', 'user@example.com', 'password')
|
|
929
|
-
* const client = new PlaycademyClient({ token: response.token })
|
|
930
|
-
* } catch (error) {
|
|
931
|
-
* console.error('Login failed:', error.message)
|
|
932
|
-
* }
|
|
933
|
-
* ```
|
|
934
|
-
*/
|
|
935
|
-
declare function login(baseUrl: string, email: string, password: string): Promise<LoginResponse>;
|
|
936
|
-
|
|
937
|
-
/**
|
|
938
|
-
* Cache configuration types for runtime customization
|
|
939
|
-
*/
|
|
940
|
-
/**
|
|
941
|
-
* Runtime configuration for TTL cache behavior
|
|
942
|
-
*/
|
|
943
|
-
interface TTLCacheConfig {
|
|
944
|
-
/** Time-to-live in milliseconds. Set to 0 to disable caching for this call. */
|
|
945
|
-
ttl?: number;
|
|
946
|
-
/** Force refresh, bypassing cache */
|
|
947
|
-
force?: boolean;
|
|
948
|
-
/** Skip cache and fetch fresh data (alias for force) */
|
|
949
|
-
skipCache?: boolean;
|
|
950
|
-
}
|
|
951
|
-
|
|
952
|
-
/**
|
|
953
|
-
* Options for configuring activity tracking behavior.
|
|
954
|
-
*/
|
|
955
|
-
interface StartActivityOptions {
|
|
956
|
-
/**
|
|
957
|
-
* How long heartbeats continue after the activity is automatically paused
|
|
958
|
-
* because the tab is hidden or the player is inactive while visible.
|
|
959
|
-
* Defaults to 10 minutes. Set to `Infinity` to keep heartbeats running
|
|
960
|
-
* indefinitely during automatic pauses. Invalid values fall back to the
|
|
961
|
-
* 10-minute default.
|
|
962
|
-
*/
|
|
963
|
-
pausedHeartbeatTimeoutMs?: number;
|
|
964
|
-
/**
|
|
965
|
-
* @deprecated Use `pausedHeartbeatTimeoutMs` instead.
|
|
966
|
-
*
|
|
967
|
-
* Backward-compatible alias for callers that still use the old option
|
|
968
|
-
* name from earlier SDK releases.
|
|
969
|
-
*/
|
|
970
|
-
hiddenTimeoutMs?: number;
|
|
971
|
-
/**
|
|
972
|
-
* How often to flush periodic heartbeats with accumulated time data.
|
|
973
|
-
* Defaults to 15 seconds. Set to `Infinity` to disable the interval;
|
|
974
|
-
* final unload/endActivity flushes still run. Values must be greater than
|
|
975
|
-
* 0 or `Infinity`; invalid values fall back to the 15-second default.
|
|
976
|
-
*/
|
|
977
|
-
heartbeatIntervalMs?: number;
|
|
978
|
-
/**
|
|
979
|
-
* How long the tab can remain visible without keyboard or mouse activity
|
|
980
|
-
* before the activity is marked inactive. Defaults to 10 minutes. Set to
|
|
981
|
-
* `Infinity` to disable keyboard/mouse inactivity tracking. Invalid values
|
|
982
|
-
* fall back to the 10-minute default.
|
|
983
|
-
*/
|
|
984
|
-
inactivityTimeoutMs?: number;
|
|
985
|
-
/**
|
|
986
|
-
* Stable identifier for this activity run. When provided, it is used on
|
|
987
|
-
* every heartbeat and on endActivity instead of a freshly-generated UUID.
|
|
988
|
-
*
|
|
989
|
-
* Pass the same `runId` across multiple `startActivity()` calls (for
|
|
990
|
-
* example, after the player closes and reopens a resumable activity) so
|
|
991
|
-
* downstream systems can correlate related sessions into a single run.
|
|
992
|
-
*
|
|
993
|
-
* Must be a UUID (the backend validates it as such) and unique per
|
|
994
|
-
* logical run. If omitted, the SDK generates a new UUID on each call,
|
|
995
|
-
* which means every session is treated as its own run.
|
|
996
|
-
*/
|
|
997
|
-
runId?: string;
|
|
998
|
-
}
|
|
999
|
-
interface StartActivityResult {
|
|
1000
|
-
runId: string;
|
|
1001
|
-
}
|
|
1002
|
-
|
|
1003
|
-
/**
|
|
1004
|
-
* Type definitions for the game timeback namespace.
|
|
1005
|
-
*
|
|
1006
|
-
* SDK-specific types like TimebackInitContext that wrap the core types
|
|
1007
|
-
* from @playcademy/types/user (which are re-exported via types/data.ts).
|
|
1008
|
-
*/
|
|
1009
|
-
|
|
1010
|
-
/**
|
|
1011
|
-
* A TimeBack enrollment for the current game session.
|
|
1012
|
-
* Alias for UserEnrollment without the optional gameId.
|
|
1013
|
-
*/
|
|
1014
|
-
type TimebackEnrollment = Omit<UserEnrollment, 'gameId'>;
|
|
1015
|
-
/**
|
|
1016
|
-
* A TimeBack organization (school/district) for the current user.
|
|
1017
|
-
* Alias for UserOrganization.
|
|
1018
|
-
*/
|
|
1019
|
-
type TimebackOrganization = UserOrganization;
|
|
1020
|
-
/**
|
|
1021
|
-
* TimeBack context passed during game initialization.
|
|
1022
|
-
* This is sent from the platform (cademy) to the game iframe via postMessage.
|
|
1023
|
-
*/
|
|
1024
|
-
interface TimebackInitContext {
|
|
1025
|
-
/** User's TimeBack ID */
|
|
1026
|
-
id: string;
|
|
1027
|
-
/** User's role in TimeBack (student, parent, teacher, etc.) */
|
|
1028
|
-
role: TimebackUserRole;
|
|
1029
|
-
/** User's enrollments for this game (one per grade/subject combo) */
|
|
1030
|
-
enrollments: TimebackEnrollment[];
|
|
1031
|
-
/** User's organizations (schools/districts) */
|
|
1032
|
-
organizations: TimebackOrganization[];
|
|
1033
|
-
}
|
|
1034
|
-
/**
|
|
1035
|
-
* TimeBack user context with current data (may be stale from init).
|
|
1036
|
-
* Use `fetch()` to get fresh data from the server.
|
|
1037
|
-
*/
|
|
1038
|
-
interface TimebackUserContext {
|
|
1039
|
-
/** User's TimeBack ID */
|
|
1040
|
-
id: string | undefined;
|
|
1041
|
-
/** User's role in TimeBack (student, parent, teacher, etc.) */
|
|
1042
|
-
role: TimebackUserRole | undefined;
|
|
1043
|
-
/** User's enrollments for this game */
|
|
1044
|
-
enrollments: TimebackEnrollment[];
|
|
1045
|
-
/** User's organizations (schools/districts) */
|
|
1046
|
-
organizations: TimebackOrganization[];
|
|
1047
|
-
}
|
|
1048
|
-
/**
|
|
1049
|
-
* Slice options for refreshing the cached TimeBack user context.
|
|
1050
|
-
*/
|
|
1051
|
-
type TimebackUserRefreshField = 'enrollments';
|
|
1052
|
-
interface TimebackUserRefreshOptions extends TTLCacheConfig {
|
|
1053
|
-
/** Refresh only these user data fields */
|
|
1054
|
-
only: readonly TimebackUserRefreshField[];
|
|
1055
|
-
}
|
|
1056
|
-
/**
|
|
1057
|
-
* XP data access for the current user.
|
|
1058
|
-
* Results are cached for 5 seconds to avoid redundant network requests.
|
|
1059
|
-
*/
|
|
1060
|
-
interface TimebackUserXp {
|
|
1061
|
-
/**
|
|
1062
|
-
* Fetch XP data from the server.
|
|
1063
|
-
* Returns XP for all courses in this game, or filter by grade/subject.
|
|
1064
|
-
* Results are cached for 5 seconds (use `force: true` to bypass).
|
|
1065
|
-
*
|
|
1066
|
-
* @param options - Query options
|
|
1067
|
-
* @param options.grade - Grade level to filter (must be used with subject)
|
|
1068
|
-
* @param options.subject - Subject to filter (must be used with grade)
|
|
1069
|
-
* @param options.include - Additional data to include: 'perCourse', 'today'
|
|
1070
|
-
* @param options.force - Bypass cache and fetch fresh data (default: false)
|
|
1071
|
-
* @returns Promise resolving to XP data
|
|
1072
|
-
*
|
|
1073
|
-
* @example
|
|
1074
|
-
* ```typescript
|
|
1075
|
-
* // Get total XP for all game courses
|
|
1076
|
-
* const xp = await client.timeback.user.xp.fetch()
|
|
1077
|
-
*
|
|
1078
|
-
* // Get XP for a specific grade/subject
|
|
1079
|
-
* const xp = await client.timeback.user.xp.fetch({
|
|
1080
|
-
* grade: 3,
|
|
1081
|
-
* subject: 'Math'
|
|
1082
|
-
* })
|
|
1083
|
-
*
|
|
1084
|
-
* // Get XP with per-course breakdown
|
|
1085
|
-
* const xp = await client.timeback.user.xp.fetch({
|
|
1086
|
-
* include: ['perCourse', 'today']
|
|
1087
|
-
* })
|
|
1088
|
-
*
|
|
1089
|
-
* // Force fresh data
|
|
1090
|
-
* const xp = await client.timeback.user.xp.fetch({ force: true })
|
|
1091
|
-
* ```
|
|
1092
|
-
*/
|
|
1093
|
-
fetch(options?: GetXpOptions): Promise<XpResponse>;
|
|
1094
|
-
}
|
|
1095
|
-
/**
|
|
1096
|
-
* TimeBack user object with cached getters, fetch, and targeted refresh methods.
|
|
1097
|
-
*/
|
|
1098
|
-
interface TimebackUser extends TimebackUserContext {
|
|
1099
|
-
/**
|
|
1100
|
-
* Fetch TimeBack data from the server (cached for 5 min).
|
|
1101
|
-
* Updates the cached values so subsequent property access returns fresh data.
|
|
1102
|
-
* @param options - Cache options (pass { force: true } to bypass cache)
|
|
1103
|
-
* @returns Promise resolving to fresh user context
|
|
1104
|
-
*/
|
|
1105
|
-
fetch(options?: TTLCacheConfig): Promise<TimebackUserContext>;
|
|
1106
|
-
/**
|
|
1107
|
-
* Refresh selected TimeBack user data from the server.
|
|
1108
|
-
* Updates the cached user snapshot used by the synchronous getters.
|
|
1109
|
-
* @param options - Refresh fields and cache options
|
|
1110
|
-
* @returns Promise resolving to the updated user context
|
|
1111
|
-
*/
|
|
1112
|
-
refresh(options: TimebackUserRefreshOptions): Promise<TimebackUserContext>;
|
|
1113
|
-
/**
|
|
1114
|
-
* XP data for the current user.
|
|
1115
|
-
* Call `xp.fetch()` to get XP from the server.
|
|
1116
|
-
*/
|
|
1117
|
-
xp: TimebackUserXp;
|
|
1118
|
-
/**
|
|
1119
|
-
* Mastery data for the current user.
|
|
1120
|
-
* Call `mastery.fetch()` to get mastery progress from the server.
|
|
1121
|
-
*/
|
|
1122
|
-
mastery: TimebackUserMastery;
|
|
1123
|
-
/**
|
|
1124
|
-
* Highest-grade-mastered data for the current user.
|
|
1125
|
-
* Call `highestGradeMastered.fetch({ subject })` to get the student's
|
|
1126
|
-
* highest mastered grade for a subject.
|
|
1127
|
-
*/
|
|
1128
|
-
highestGradeMastered: TimebackUserHighestGradeMastered;
|
|
1129
|
-
}
|
|
1130
|
-
/**
|
|
1131
|
-
* Mastery data access for the current user.
|
|
1132
|
-
* Results are cached for 5 seconds to avoid redundant network requests.
|
|
1133
|
-
*/
|
|
1134
|
-
interface TimebackUserMastery {
|
|
1135
|
-
/**
|
|
1136
|
-
* Fetch mastery data from the server.
|
|
1137
|
-
* Returns mastery for all courses in this game, or filter by grade/subject.
|
|
1138
|
-
* Returned masteredUnits values are true analytics values and may exceed
|
|
1139
|
-
* the course masterableUnits maximum when historical data violates the
|
|
1140
|
-
* expected invariant.
|
|
1141
|
-
* Results are cached for 5 seconds (use `force: true` to bypass).
|
|
1142
|
-
*
|
|
1143
|
-
* @param options - Query options
|
|
1144
|
-
* @param options.grade - Grade level to filter (must be used with subject)
|
|
1145
|
-
* @param options.subject - Subject to filter (must be used with grade)
|
|
1146
|
-
* @param options.include - Additional data to include: 'perCourse'
|
|
1147
|
-
* @param options.force - Bypass cache and fetch fresh data (default: false)
|
|
1148
|
-
* @returns Promise resolving to mastery data
|
|
1149
|
-
*
|
|
1150
|
-
* @example
|
|
1151
|
-
* ```typescript
|
|
1152
|
-
* // Get total mastery for all game courses
|
|
1153
|
-
* const mastery = await client.timeback.user.mastery.fetch()
|
|
1154
|
-
*
|
|
1155
|
-
* // Get mastery for a specific grade/subject
|
|
1156
|
-
* const mastery = await client.timeback.user.mastery.fetch({
|
|
1157
|
-
* grade: 3,
|
|
1158
|
-
* subject: 'Math'
|
|
1159
|
-
* })
|
|
1160
|
-
*
|
|
1161
|
-
* // Get mastery with per-course breakdown
|
|
1162
|
-
* const mastery = await client.timeback.user.mastery.fetch({
|
|
1163
|
-
* include: ['perCourse']
|
|
1164
|
-
* })
|
|
1165
|
-
*
|
|
1166
|
-
* // Force fresh data
|
|
1167
|
-
* const mastery = await client.timeback.user.mastery.fetch({ force: true })
|
|
1168
|
-
* ```
|
|
1169
|
-
*/
|
|
1170
|
-
fetch(options?: GetMasteryOptions): Promise<MasteryResponse>;
|
|
1171
|
-
}
|
|
1172
|
-
/**
|
|
1173
|
-
* Highest-grade-mastered data access for the current user.
|
|
1174
|
-
* Results are cached for 5 seconds to avoid redundant network requests.
|
|
1175
|
-
*/
|
|
1176
|
-
interface TimebackUserHighestGradeMastered {
|
|
1177
|
-
/**
|
|
1178
|
-
* Fetch the highest grade the current student has mastered for a subject.
|
|
1179
|
-
* Results are cached for 5 seconds (use `force: true` to bypass).
|
|
1180
|
-
*/
|
|
1181
|
-
fetch(options: GetHighestGradeMasteredOptions): Promise<HighestGradeMasteredResponse>;
|
|
1182
|
-
}
|
|
1183
|
-
/**
|
|
1184
|
-
* Options for querying student XP.
|
|
1185
|
-
*/
|
|
1186
|
-
interface GetXpOptions {
|
|
1187
|
-
/** Grade level to filter (must be used with subject) */
|
|
1188
|
-
grade?: TimebackGrade;
|
|
1189
|
-
/** Subject to filter (must be used with grade) */
|
|
1190
|
-
subject?: TimebackSubject;
|
|
1191
|
-
/** Additional data to include: 'perCourse', 'today' */
|
|
1192
|
-
include?: ('perCourse' | 'today')[];
|
|
1193
|
-
/** Bypass cache and fetch fresh data (default: false) */
|
|
1194
|
-
force?: boolean;
|
|
1195
|
-
}
|
|
1196
|
-
/**
|
|
1197
|
-
* Options for querying student mastery.
|
|
1198
|
-
*/
|
|
1199
|
-
interface GetMasteryOptions {
|
|
1200
|
-
/** Grade level to filter (must be used with subject) */
|
|
1201
|
-
grade?: TimebackGrade;
|
|
1202
|
-
/** Subject to filter (must be used with grade) */
|
|
1203
|
-
subject?: TimebackSubject;
|
|
1204
|
-
/** Additional data to include: 'perCourse' */
|
|
1205
|
-
include?: 'perCourse'[];
|
|
1206
|
-
/** Bypass cache and fetch fresh data (default: false) */
|
|
1207
|
-
force?: boolean;
|
|
1208
|
-
}
|
|
1209
|
-
/**
|
|
1210
|
-
* Options for querying highest grade mastered.
|
|
1211
|
-
*/
|
|
1212
|
-
interface GetHighestGradeMasteredOptions {
|
|
1213
|
-
/** Subject to query */
|
|
1214
|
-
subject: TimebackSubject;
|
|
1215
|
-
/** Bypass cache and fetch fresh data (default: false) */
|
|
1216
|
-
force?: boolean;
|
|
1217
|
-
}
|
|
1218
|
-
/**
|
|
1219
|
-
* XP data for a single course.
|
|
1220
|
-
*/
|
|
1221
|
-
interface CourseXp {
|
|
1222
|
-
grade: TimebackGrade;
|
|
1223
|
-
subject: TimebackSubject;
|
|
1224
|
-
title: string;
|
|
1225
|
-
totalXp: number;
|
|
1226
|
-
todayXp?: number;
|
|
1227
|
-
}
|
|
1228
|
-
/**
|
|
1229
|
-
* Response from XP query.
|
|
1230
|
-
*/
|
|
1231
|
-
interface XpResponse {
|
|
1232
|
-
totalXp: number;
|
|
1233
|
-
todayXp?: number;
|
|
1234
|
-
courses?: CourseXp[];
|
|
1235
|
-
}
|
|
1236
|
-
interface CourseMastery {
|
|
1237
|
-
grade: TimebackGrade;
|
|
1238
|
-
subject: TimebackSubject;
|
|
1239
|
-
title: string;
|
|
1240
|
-
/** True mastered units from analytics. May exceed masterableUnits for historical data. */
|
|
1241
|
-
masteredUnits: number;
|
|
1242
|
-
/** Configured mastery ceiling for the course. */
|
|
1243
|
-
masterableUnits: number;
|
|
1244
|
-
/** Clamped course completion percentage from 0..100. */
|
|
1245
|
-
pctComplete: number;
|
|
1246
|
-
isComplete: boolean;
|
|
1247
|
-
}
|
|
1248
|
-
/**
|
|
1249
|
-
* Response from mastery query.
|
|
1250
|
-
*/
|
|
1251
|
-
interface MasteryResponse {
|
|
1252
|
-
/** True mastered units across all queried courses. */
|
|
1253
|
-
totalMasteredUnits: number;
|
|
1254
|
-
/** Configured mastery ceiling across all queried courses. */
|
|
1255
|
-
totalMasterableUnits: number;
|
|
1256
|
-
courses?: CourseMastery[];
|
|
1257
|
-
}
|
|
1258
|
-
/**
|
|
1259
|
-
* Response from highest-grade-mastered query.
|
|
1260
|
-
*/
|
|
1261
|
-
interface HighestGradeMasteredResponse {
|
|
1262
|
-
subject: TimebackSubject;
|
|
1263
|
-
highestGradeMastered: TimebackGrade | null;
|
|
1264
|
-
}
|
|
1265
|
-
|
|
1266
|
-
/**
|
|
1267
|
-
* Core client configuration and lifecycle types
|
|
1268
|
-
*/
|
|
1269
|
-
|
|
1270
|
-
type TokenType = 'session' | 'apiKey' | 'gameJwt';
|
|
1271
|
-
/**
|
|
1272
|
-
* Runtime mode for a Playcademy game client.
|
|
1273
|
-
*
|
|
1274
|
-
* - `'platform'` — game is embedded in the platform (e.g. the cademy hub)
|
|
1275
|
-
* with a real authenticated user and full access to SDK namespaces.
|
|
1276
|
-
* - `'demo'` — game is embedded in the landing page demo shell with an
|
|
1277
|
-
* anonymous user; platform-only namespaces throw, and `client.demo.*`
|
|
1278
|
-
* is the supported surface for signaling demo lifecycle events and
|
|
1279
|
-
* reading/updating the anonymous profile.
|
|
1280
|
-
* - `'standalone'` — game is running outside any iframe (e.g. `bun run dev`
|
|
1281
|
-
* or direct-deploy preview) with a mock token and no real platform
|
|
1282
|
-
* context. API calls will not succeed; use this to branch UX locally.
|
|
1283
|
-
*/
|
|
1284
|
-
type PlaycademyMode = 'platform' | 'demo' | 'standalone';
|
|
1285
|
-
interface ClientConfig {
|
|
1286
|
-
baseUrl: string;
|
|
1287
|
-
gameUrl?: string;
|
|
1288
|
-
token?: string;
|
|
1289
|
-
tokenType?: TokenType;
|
|
1290
|
-
gameId?: string;
|
|
1291
|
-
launchId?: string;
|
|
1292
|
-
mode?: PlaycademyMode;
|
|
1293
|
-
}
|
|
1294
|
-
interface InitPayload {
|
|
1295
|
-
/** Hub API base URL */
|
|
1296
|
-
baseUrl: string;
|
|
1297
|
-
/** Game deployment URL (serves both frontend assets and backend API) */
|
|
1298
|
-
gameUrl?: string;
|
|
1299
|
-
/** Short-lived game token */
|
|
1300
|
-
token: string;
|
|
1301
|
-
/** Game ID */
|
|
1302
|
-
gameId: string;
|
|
1303
|
-
/** Timeback context (if user has a Timeback account) */
|
|
1304
|
-
timeback?: TimebackInitContext;
|
|
1305
|
-
/** Runtime mode for the game client */
|
|
1306
|
-
mode?: PlaycademyMode;
|
|
1307
|
-
/** Launch session correlation ID (UUID, set by platform on game launch) */
|
|
1308
|
-
launchId?: string;
|
|
1309
|
-
/** When `true`, the parent shell provides a heartbeat relay via postMessage, so the SDK can skip its own `fetch({ keepalive })` beacon on pagehide. Defaults to `false`. */
|
|
1310
|
-
hasHeartbeatRelay?: boolean;
|
|
1311
|
-
}
|
|
1312
|
-
/**
|
|
1313
|
-
* Simplified user data passed to games via InitPayload
|
|
1314
|
-
* This is a subset of AuthenticatedUser suitable for external game consumption
|
|
1315
|
-
*
|
|
1316
|
-
* Note: Named GameInitUser to distinguish from the cross-game GameUser DTO
|
|
1317
|
-
* exported from @playcademy/types
|
|
1318
|
-
*/
|
|
1319
|
-
interface GameInitUser {
|
|
1320
|
-
/** Playcademy user ID */
|
|
1321
|
-
id: string;
|
|
1322
|
-
/** Unique username */
|
|
1323
|
-
username: string | null;
|
|
1324
|
-
/** Display name */
|
|
1325
|
-
name: string | null;
|
|
1326
|
-
/** Email address */
|
|
1327
|
-
email: string | null;
|
|
1328
|
-
/** Profile image URL */
|
|
1329
|
-
image: string | null;
|
|
1330
|
-
/** Whether the user has a Timeback account */
|
|
1331
|
-
hasTimebackAccount: boolean;
|
|
1332
|
-
}
|
|
1333
|
-
interface GameContextPayload {
|
|
1334
|
-
token: string;
|
|
1335
|
-
baseUrl: string;
|
|
1336
|
-
gameId: string;
|
|
1337
|
-
forwardKeys?: string[];
|
|
1338
|
-
mode?: PlaycademyMode;
|
|
1339
|
-
}
|
|
1340
|
-
type EventListeners = {
|
|
1341
|
-
[E in keyof ClientEvents]?: ((payload: ClientEvents[E]) => void)[];
|
|
1342
|
-
};
|
|
1343
|
-
interface ClientEvents {
|
|
1344
|
-
authChange: {
|
|
1345
|
-
token: string | null;
|
|
1346
|
-
};
|
|
1347
|
-
}
|
|
1348
|
-
|
|
1349
|
-
/**
|
|
1350
|
-
* Event and message payload types for SDK messaging system
|
|
1351
|
-
*/
|
|
1352
|
-
|
|
1353
|
-
/**
|
|
1354
|
-
* Authentication state change event payload.
|
|
1355
|
-
* Used when authentication state changes in the application.
|
|
1356
|
-
*/
|
|
1357
|
-
interface AuthStateChangePayload {
|
|
1358
|
-
/** Whether the user is currently authenticated */
|
|
1359
|
-
authenticated: boolean;
|
|
1360
|
-
/** User information if authenticated, null otherwise */
|
|
1361
|
-
user: UserInfo | null;
|
|
1362
|
-
/** Error information if authentication failed */
|
|
1363
|
-
error: Error | null;
|
|
1364
|
-
}
|
|
1365
|
-
/**
|
|
1366
|
-
* OAuth callback event payload.
|
|
1367
|
-
* Used when OAuth flow completes in popup/new-tab windows.
|
|
1368
|
-
*/
|
|
1369
|
-
interface AuthCallbackPayload {
|
|
1370
|
-
/** OAuth authorization code */
|
|
1371
|
-
code: string;
|
|
1372
|
-
/** OAuth state parameter for CSRF protection */
|
|
1373
|
-
state: string;
|
|
1374
|
-
/** Error message if OAuth flow failed */
|
|
1375
|
-
error: string | null;
|
|
1376
|
-
}
|
|
1377
|
-
/**
|
|
1378
|
-
* Message sent from server callback to opener window.
|
|
1379
|
-
* This is the standardized format from our server-first architecture.
|
|
1380
|
-
*/
|
|
1381
|
-
interface AuthServerMessage {
|
|
1382
|
-
/** Type of the message */
|
|
1383
|
-
type: 'PLAYCADEMY_AUTH_STATE_CHANGE';
|
|
1384
|
-
/** Whether the user is currently authenticated */
|
|
1385
|
-
authenticated: boolean;
|
|
1386
|
-
/** Whether the authentication was successful */
|
|
1387
|
-
success: boolean;
|
|
1388
|
-
/** Timestamp of the message */
|
|
1389
|
-
ts: number;
|
|
1390
|
-
/** User information if authentication was successful */
|
|
1391
|
-
user?: UserInfo;
|
|
1392
|
-
/** Error message if authentication failed */
|
|
1393
|
-
error?: string;
|
|
1394
|
-
}
|
|
1395
|
-
/**
|
|
1396
|
-
* Token refresh event payload.
|
|
1397
|
-
* Sent when authentication token is updated.
|
|
1398
|
-
*/
|
|
1399
|
-
interface TokenRefreshPayload {
|
|
1400
|
-
/** New authentication token */
|
|
1401
|
-
token: string;
|
|
1402
|
-
/** Token expiration timestamp */
|
|
1403
|
-
exp: number;
|
|
1404
|
-
}
|
|
1405
|
-
/**
|
|
1406
|
-
* Telemetry event payload.
|
|
1407
|
-
* Performance metrics sent from the game.
|
|
1408
|
-
*/
|
|
1409
|
-
interface TelemetryPayload {
|
|
1410
|
-
/** Frames per second */
|
|
1411
|
-
fps: number;
|
|
1412
|
-
/** Memory usage in MB */
|
|
1413
|
-
mem: number;
|
|
1414
|
-
}
|
|
1415
|
-
/**
|
|
1416
|
-
* Keyboard event payload.
|
|
1417
|
-
* Key events forwarded from the game.
|
|
1418
|
-
*/
|
|
1419
|
-
interface KeyEventPayload {
|
|
1420
|
-
/** Key value (e.g., 'Escape', 'F1') */
|
|
1421
|
-
key: string;
|
|
1422
|
-
/** Key code (optional) */
|
|
1423
|
-
code?: string;
|
|
1424
|
-
/** Event type */
|
|
1425
|
-
type: 'keydown' | 'keyup';
|
|
1426
|
-
}
|
|
1427
|
-
/**
|
|
1428
|
-
* Init error payload.
|
|
1429
|
-
* Sent from game iframe to parent when SDK initialization fails
|
|
1430
|
-
* (e.g. origin validation failure, INIT timeout, client creation error).
|
|
1431
|
-
*/
|
|
1432
|
-
interface InitErrorPayload {
|
|
1433
|
-
reason: string;
|
|
1434
|
-
}
|
|
1435
|
-
/**
|
|
1436
|
-
* Options for `client.demo.end(score, options?)`.
|
|
1437
|
-
*
|
|
1438
|
-
* All optional. The landing-page demo shell can render a meaningful CTA
|
|
1439
|
-
* from `score` alone, but `durationMs` enables a nicer summary and
|
|
1440
|
-
* `metadata` lets games pass any extra context they want to surface.
|
|
1441
|
-
*/
|
|
1442
|
-
interface DemoEndOptions {
|
|
1443
|
-
durationMs?: number;
|
|
1444
|
-
metadata?: Record<string, unknown>;
|
|
1445
|
-
}
|
|
1446
|
-
/**
|
|
1447
|
-
* Wire payload for the `PLAYCADEMY_DEMO_END` message.
|
|
1448
|
-
*
|
|
1449
|
-
* `score` is required — the demo shell always needs something to display
|
|
1450
|
-
* when the round ends. `durationMs` and `metadata` are optional.
|
|
1451
|
-
*/
|
|
1452
|
-
interface DemoEndPayload extends DemoEndOptions {
|
|
1453
|
-
score: number;
|
|
1454
|
-
}
|
|
1455
|
-
type TimebackHeartbeatRelayRequest = Omit<HeartbeatRequest, 'gameId' | 'studentId' | 'windowStartedAtMs' | 'windowSequence'> & {
|
|
1456
|
-
windowStartedAtMs: number;
|
|
1457
|
-
};
|
|
1458
|
-
|
|
1459
|
-
/**
|
|
1460
|
-
* SDK-specific API response types
|
|
1461
|
-
*/
|
|
1462
|
-
interface LoginResponse {
|
|
1463
|
-
token: string;
|
|
1464
|
-
}
|
|
1465
|
-
interface GameTokenResponse {
|
|
1466
|
-
token: string;
|
|
1467
|
-
exp: number;
|
|
1468
|
-
baseUrl?: string;
|
|
1469
|
-
}
|
|
1470
|
-
|
|
1471
|
-
declare const users: drizzle_orm_pg_core.PgTableWithColumns<{
|
|
1472
|
-
name: "user";
|
|
1473
|
-
schema: undefined;
|
|
1474
|
-
columns: {
|
|
1475
|
-
id: drizzle_orm_pg_core.PgColumn<{
|
|
1476
|
-
name: "id";
|
|
1477
|
-
tableName: "user";
|
|
1478
|
-
dataType: "string";
|
|
1479
|
-
columnType: "PgText";
|
|
1480
|
-
data: string;
|
|
1481
|
-
driverParam: string;
|
|
1482
|
-
notNull: true;
|
|
1483
|
-
hasDefault: true;
|
|
1484
|
-
isPrimaryKey: true;
|
|
1485
|
-
isAutoincrement: false;
|
|
1486
|
-
hasRuntimeDefault: true;
|
|
1487
|
-
enumValues: [string, ...string[]];
|
|
1488
|
-
baseColumn: never;
|
|
1489
|
-
identity: undefined;
|
|
1490
|
-
generated: undefined;
|
|
1491
|
-
}, {}, {}>;
|
|
1492
|
-
name: drizzle_orm_pg_core.PgColumn<{
|
|
1493
|
-
name: "name";
|
|
1494
|
-
tableName: "user";
|
|
1495
|
-
dataType: "string";
|
|
1496
|
-
columnType: "PgText";
|
|
1497
|
-
data: string;
|
|
1498
|
-
driverParam: string;
|
|
1499
|
-
notNull: true;
|
|
1500
|
-
hasDefault: false;
|
|
1501
|
-
isPrimaryKey: false;
|
|
1502
|
-
isAutoincrement: false;
|
|
1503
|
-
hasRuntimeDefault: false;
|
|
1504
|
-
enumValues: [string, ...string[]];
|
|
1505
|
-
baseColumn: never;
|
|
1506
|
-
identity: undefined;
|
|
1507
|
-
generated: undefined;
|
|
1508
|
-
}, {}, {}>;
|
|
1509
|
-
username: drizzle_orm_pg_core.PgColumn<{
|
|
1510
|
-
name: "username";
|
|
1511
|
-
tableName: "user";
|
|
1512
|
-
dataType: "string";
|
|
1513
|
-
columnType: "PgText";
|
|
1514
|
-
data: string;
|
|
1515
|
-
driverParam: string;
|
|
1516
|
-
notNull: false;
|
|
1517
|
-
hasDefault: false;
|
|
1518
|
-
isPrimaryKey: false;
|
|
1519
|
-
isAutoincrement: false;
|
|
1520
|
-
hasRuntimeDefault: false;
|
|
1521
|
-
enumValues: [string, ...string[]];
|
|
1522
|
-
baseColumn: never;
|
|
1523
|
-
identity: undefined;
|
|
1524
|
-
generated: undefined;
|
|
1525
|
-
}, {}, {}>;
|
|
1526
|
-
email: drizzle_orm_pg_core.PgColumn<{
|
|
1527
|
-
name: "email";
|
|
1528
|
-
tableName: "user";
|
|
1529
|
-
dataType: "string";
|
|
1530
|
-
columnType: "PgText";
|
|
1531
|
-
data: string;
|
|
1532
|
-
driverParam: string;
|
|
1533
|
-
notNull: true;
|
|
1534
|
-
hasDefault: false;
|
|
1535
|
-
isPrimaryKey: false;
|
|
1536
|
-
isAutoincrement: false;
|
|
1537
|
-
hasRuntimeDefault: false;
|
|
1538
|
-
enumValues: [string, ...string[]];
|
|
1539
|
-
baseColumn: never;
|
|
1540
|
-
identity: undefined;
|
|
1541
|
-
generated: undefined;
|
|
1542
|
-
}, {}, {}>;
|
|
1543
|
-
isAnonymous: drizzle_orm_pg_core.PgColumn<{
|
|
1544
|
-
name: "is_anonymous";
|
|
1545
|
-
tableName: "user";
|
|
1546
|
-
dataType: "boolean";
|
|
1547
|
-
columnType: "PgBoolean";
|
|
1548
|
-
data: boolean;
|
|
1549
|
-
driverParam: boolean;
|
|
1550
|
-
notNull: true;
|
|
1551
|
-
hasDefault: true;
|
|
1552
|
-
isPrimaryKey: false;
|
|
1553
|
-
isAutoincrement: false;
|
|
1554
|
-
hasRuntimeDefault: false;
|
|
1555
|
-
enumValues: undefined;
|
|
1556
|
-
baseColumn: never;
|
|
1557
|
-
identity: undefined;
|
|
1558
|
-
generated: undefined;
|
|
1559
|
-
}, {}, {}>;
|
|
1560
|
-
timebackId: drizzle_orm_pg_core.PgColumn<{
|
|
1561
|
-
name: "timeback_id";
|
|
1562
|
-
tableName: "user";
|
|
1563
|
-
dataType: "string";
|
|
1564
|
-
columnType: "PgText";
|
|
1565
|
-
data: string;
|
|
1566
|
-
driverParam: string;
|
|
1567
|
-
notNull: false;
|
|
1568
|
-
hasDefault: false;
|
|
1569
|
-
isPrimaryKey: false;
|
|
1570
|
-
isAutoincrement: false;
|
|
1571
|
-
hasRuntimeDefault: false;
|
|
1572
|
-
enumValues: [string, ...string[]];
|
|
1573
|
-
baseColumn: never;
|
|
1574
|
-
identity: undefined;
|
|
1575
|
-
generated: undefined;
|
|
1576
|
-
}, {}, {}>;
|
|
1577
|
-
emailVerified: drizzle_orm_pg_core.PgColumn<{
|
|
1578
|
-
name: "email_verified";
|
|
1579
|
-
tableName: "user";
|
|
1580
|
-
dataType: "boolean";
|
|
1581
|
-
columnType: "PgBoolean";
|
|
1582
|
-
data: boolean;
|
|
1583
|
-
driverParam: boolean;
|
|
1584
|
-
notNull: true;
|
|
1585
|
-
hasDefault: true;
|
|
1586
|
-
isPrimaryKey: false;
|
|
1587
|
-
isAutoincrement: false;
|
|
1588
|
-
hasRuntimeDefault: false;
|
|
1589
|
-
enumValues: undefined;
|
|
1590
|
-
baseColumn: never;
|
|
1591
|
-
identity: undefined;
|
|
1592
|
-
generated: undefined;
|
|
1593
|
-
}, {}, {}>;
|
|
1594
|
-
image: drizzle_orm_pg_core.PgColumn<{
|
|
1595
|
-
name: "image";
|
|
1596
|
-
tableName: "user";
|
|
1597
|
-
dataType: "string";
|
|
1598
|
-
columnType: "PgText";
|
|
1599
|
-
data: string;
|
|
1600
|
-
driverParam: string;
|
|
1601
|
-
notNull: false;
|
|
1602
|
-
hasDefault: false;
|
|
1603
|
-
isPrimaryKey: false;
|
|
1604
|
-
isAutoincrement: false;
|
|
1605
|
-
hasRuntimeDefault: false;
|
|
1606
|
-
enumValues: [string, ...string[]];
|
|
1607
|
-
baseColumn: never;
|
|
1608
|
-
identity: undefined;
|
|
1609
|
-
generated: undefined;
|
|
1610
|
-
}, {}, {}>;
|
|
1611
|
-
role: drizzle_orm_pg_core.PgColumn<{
|
|
1612
|
-
name: "role";
|
|
1613
|
-
tableName: "user";
|
|
1614
|
-
dataType: "string";
|
|
1615
|
-
columnType: "PgEnumColumn";
|
|
1616
|
-
data: "admin" | "developer" | "player" | "teacher";
|
|
1617
|
-
driverParam: string;
|
|
1618
|
-
notNull: true;
|
|
1619
|
-
hasDefault: true;
|
|
1620
|
-
isPrimaryKey: false;
|
|
1621
|
-
isAutoincrement: false;
|
|
1622
|
-
hasRuntimeDefault: false;
|
|
1623
|
-
enumValues: ["admin", "player", "developer", "teacher"];
|
|
1624
|
-
baseColumn: never;
|
|
1625
|
-
identity: undefined;
|
|
1626
|
-
generated: undefined;
|
|
1627
|
-
}, {}, {}>;
|
|
1628
|
-
developerStatus: drizzle_orm_pg_core.PgColumn<{
|
|
1629
|
-
name: "developer_status";
|
|
1630
|
-
tableName: "user";
|
|
1631
|
-
dataType: "string";
|
|
1632
|
-
columnType: "PgEnumColumn";
|
|
1633
|
-
data: "approved" | "none" | "pending";
|
|
1634
|
-
driverParam: string;
|
|
1635
|
-
notNull: true;
|
|
1636
|
-
hasDefault: true;
|
|
1637
|
-
isPrimaryKey: false;
|
|
1638
|
-
isAutoincrement: false;
|
|
1639
|
-
hasRuntimeDefault: false;
|
|
1640
|
-
enumValues: ["none", "pending", "approved"];
|
|
1641
|
-
baseColumn: never;
|
|
1642
|
-
identity: undefined;
|
|
1643
|
-
generated: undefined;
|
|
1644
|
-
}, {}, {}>;
|
|
1645
|
-
createdAt: drizzle_orm_pg_core.PgColumn<{
|
|
1646
|
-
name: "created_at";
|
|
1647
|
-
tableName: "user";
|
|
1648
|
-
dataType: "date";
|
|
1649
|
-
columnType: "PgTimestamp";
|
|
1650
|
-
data: Date;
|
|
1651
|
-
driverParam: string;
|
|
1652
|
-
notNull: true;
|
|
1653
|
-
hasDefault: false;
|
|
1654
|
-
isPrimaryKey: false;
|
|
1655
|
-
isAutoincrement: false;
|
|
1656
|
-
hasRuntimeDefault: false;
|
|
1657
|
-
enumValues: undefined;
|
|
1658
|
-
baseColumn: never;
|
|
1659
|
-
identity: undefined;
|
|
1660
|
-
generated: undefined;
|
|
1661
|
-
}, {}, {}>;
|
|
1662
|
-
updatedAt: drizzle_orm_pg_core.PgColumn<{
|
|
1663
|
-
name: "updated_at";
|
|
1664
|
-
tableName: "user";
|
|
1665
|
-
dataType: "date";
|
|
1666
|
-
columnType: "PgTimestamp";
|
|
1667
|
-
data: Date;
|
|
1668
|
-
driverParam: string;
|
|
1669
|
-
notNull: true;
|
|
1670
|
-
hasDefault: false;
|
|
1671
|
-
isPrimaryKey: false;
|
|
1672
|
-
isAutoincrement: false;
|
|
1673
|
-
hasRuntimeDefault: false;
|
|
1674
|
-
enumValues: undefined;
|
|
1675
|
-
baseColumn: never;
|
|
1676
|
-
identity: undefined;
|
|
1677
|
-
generated: undefined;
|
|
1678
|
-
}, {}, {}>;
|
|
1679
|
-
};
|
|
1680
|
-
dialect: 'pg';
|
|
1681
|
-
}>;
|
|
1682
|
-
|
|
1683
|
-
interface GameMetadata {
|
|
1684
|
-
description?: string;
|
|
1685
|
-
emoji?: string;
|
|
1686
|
-
[key: string]: unknown;
|
|
1687
|
-
}
|
|
1688
|
-
/**
|
|
1689
|
-
* DNS validation records for custom hostname
|
|
1690
|
-
* Structure for the validationRecords JSON field in game_custom_hostnames table
|
|
1691
|
-
*/
|
|
1692
|
-
interface CustomHostnameValidationRecords {
|
|
1693
|
-
/** TXT record for ownership verification */
|
|
1694
|
-
ownership?: {
|
|
1695
|
-
name?: string;
|
|
1696
|
-
value?: string;
|
|
1697
|
-
type?: string;
|
|
1698
|
-
};
|
|
1699
|
-
/** TXT records for SSL certificate validation */
|
|
1700
|
-
ssl?: {
|
|
1701
|
-
txt_name?: string;
|
|
1702
|
-
txt_value?: string;
|
|
1703
|
-
}[];
|
|
1021
|
+
/** TXT records for SSL certificate validation */
|
|
1022
|
+
ssl?: {
|
|
1023
|
+
txt_name?: string;
|
|
1024
|
+
txt_value?: string;
|
|
1025
|
+
}[];
|
|
1704
1026
|
}
|
|
1705
1027
|
declare const games: drizzle_orm_pg_core.PgTableWithColumns<{
|
|
1706
1028
|
name: "games";
|
|
@@ -2212,146 +1534,866 @@ declare const gameCustomHostnames: drizzle_orm_pg_core.PgTableWithColumns<{
|
|
|
2212
1534
|
generated: undefined;
|
|
2213
1535
|
}, {}, {}>;
|
|
2214
1536
|
};
|
|
2215
|
-
dialect: 'pg';
|
|
2216
|
-
}>;
|
|
2217
|
-
declare const UpsertGameMetadataSchema: z.ZodEffects<z.ZodObject<{
|
|
2218
|
-
displayName: z.ZodString;
|
|
2219
|
-
platform: z.ZodEnum<["web", "godot", "unity"]>;
|
|
2220
|
-
metadata: z.ZodDefault<z.ZodOptional<z.ZodEffects<z.ZodRecord<z.ZodString, z.ZodUnknown>, Record<string, unknown>, Record<string, unknown>>>>;
|
|
2221
|
-
gameType: z.ZodDefault<z.ZodOptional<z.ZodEnum<["hosted", "external"]>>>;
|
|
2222
|
-
visibility: z.ZodOptional<z.ZodEnum<["visible", "unlisted", "internal"]>>;
|
|
2223
|
-
externalUrl: z.ZodOptional<z.ZodEffects<z.ZodString, string, string>>;
|
|
2224
|
-
}, "strip", z.ZodTypeAny, {
|
|
2225
|
-
displayName: string;
|
|
2226
|
-
platform: "godot" | "unity" | "web";
|
|
2227
|
-
metadata: Record<string, unknown>;
|
|
2228
|
-
gameType: "external" | "hosted";
|
|
2229
|
-
visibility?: "internal" | "unlisted" | "visible" | undefined;
|
|
2230
|
-
externalUrl?: string | undefined;
|
|
2231
|
-
}, {
|
|
2232
|
-
displayName: string;
|
|
2233
|
-
platform: "godot" | "unity" | "web";
|
|
2234
|
-
metadata?: Record<string, unknown> | undefined;
|
|
2235
|
-
gameType?: "external" | "hosted" | undefined;
|
|
2236
|
-
visibility?: "internal" | "unlisted" | "visible" | undefined;
|
|
2237
|
-
externalUrl?: string | undefined;
|
|
2238
|
-
}>, {
|
|
2239
|
-
displayName: string;
|
|
2240
|
-
platform: "godot" | "unity" | "web";
|
|
2241
|
-
metadata: Record<string, unknown>;
|
|
2242
|
-
gameType: "external" | "hosted";
|
|
2243
|
-
visibility?: "internal" | "unlisted" | "visible" | undefined;
|
|
2244
|
-
externalUrl?: string | undefined;
|
|
2245
|
-
}, {
|
|
2246
|
-
displayName: string;
|
|
2247
|
-
platform: "godot" | "unity" | "web";
|
|
2248
|
-
metadata?: Record<string, unknown> | undefined;
|
|
2249
|
-
gameType?: "external" | "hosted" | undefined;
|
|
2250
|
-
visibility?: "internal" | "unlisted" | "visible" | undefined;
|
|
2251
|
-
externalUrl?: string | undefined;
|
|
2252
|
-
}>;
|
|
2253
|
-
declare const PatchGameMetadataSchema: z.ZodObject<{
|
|
2254
|
-
displayName: z.ZodOptional<z.ZodString>;
|
|
2255
|
-
visibility: z.ZodOptional<z.ZodEnum<["visible", "unlisted", "internal"]>>;
|
|
2256
|
-
platform: z.ZodOptional<z.ZodEnum<["web", "godot", "unity"]>>;
|
|
2257
|
-
metadata: z.ZodOptional<z.ZodObject<{
|
|
2258
|
-
description: z.ZodOptional<z.ZodString>;
|
|
2259
|
-
emoji: z.ZodOptional<z.ZodEffects<z.ZodString, string, string>>;
|
|
2260
|
-
}, "strip", z.ZodTypeAny, {
|
|
2261
|
-
description?: string | undefined;
|
|
2262
|
-
emoji?: string | undefined;
|
|
2263
|
-
}, {
|
|
2264
|
-
description?: string | undefined;
|
|
2265
|
-
emoji?: string | undefined;
|
|
2266
|
-
}>>;
|
|
2267
|
-
}, "strip", z.ZodTypeAny, {
|
|
2268
|
-
displayName?: string | undefined;
|
|
2269
|
-
visibility?: "internal" | "unlisted" | "visible" | undefined;
|
|
2270
|
-
platform?: "godot" | "unity" | "web" | undefined;
|
|
2271
|
-
metadata?: {
|
|
2272
|
-
description?: string | undefined;
|
|
2273
|
-
emoji?: string | undefined;
|
|
2274
|
-
} | undefined;
|
|
2275
|
-
}, {
|
|
2276
|
-
displayName?: string | undefined;
|
|
2277
|
-
visibility?: "internal" | "unlisted" | "visible" | undefined;
|
|
2278
|
-
platform?: "godot" | "unity" | "web" | undefined;
|
|
2279
|
-
metadata?: {
|
|
2280
|
-
description?: string | undefined;
|
|
2281
|
-
emoji?: string | undefined;
|
|
2282
|
-
} | undefined;
|
|
2283
|
-
}>;
|
|
2284
|
-
declare const AddGameMemberSchema: z.ZodObject<{
|
|
2285
|
-
userId: z.ZodString;
|
|
2286
|
-
role: z.ZodDefault<z.ZodOptional<z.ZodLiteral<"collaborator">>>;
|
|
2287
|
-
}, "strict", z.ZodTypeAny, {
|
|
2288
|
-
userId: string;
|
|
2289
|
-
role: "collaborator";
|
|
2290
|
-
}, {
|
|
2291
|
-
userId: string;
|
|
2292
|
-
role?: "collaborator" | undefined;
|
|
2293
|
-
}>;
|
|
2294
|
-
declare const UpdateGameMemberRoleSchema: z.ZodObject<{
|
|
2295
|
-
role: z.ZodEnum<["owner", "collaborator"]>;
|
|
2296
|
-
}, "strict", z.ZodTypeAny, {
|
|
2297
|
-
role: "collaborator" | "owner";
|
|
2298
|
-
}, {
|
|
2299
|
-
role: "collaborator" | "owner";
|
|
2300
|
-
}>;
|
|
1537
|
+
dialect: 'pg';
|
|
1538
|
+
}>;
|
|
1539
|
+
declare const UpsertGameMetadataSchema: z.ZodEffects<z.ZodObject<{
|
|
1540
|
+
displayName: z.ZodString;
|
|
1541
|
+
platform: z.ZodEnum<["web", "godot", "unity"]>;
|
|
1542
|
+
metadata: z.ZodDefault<z.ZodOptional<z.ZodEffects<z.ZodRecord<z.ZodString, z.ZodUnknown>, Record<string, unknown>, Record<string, unknown>>>>;
|
|
1543
|
+
gameType: z.ZodDefault<z.ZodOptional<z.ZodEnum<["hosted", "external"]>>>;
|
|
1544
|
+
visibility: z.ZodOptional<z.ZodEnum<["visible", "unlisted", "internal"]>>;
|
|
1545
|
+
externalUrl: z.ZodOptional<z.ZodEffects<z.ZodString, string, string>>;
|
|
1546
|
+
}, "strip", z.ZodTypeAny, {
|
|
1547
|
+
displayName: string;
|
|
1548
|
+
platform: "godot" | "unity" | "web";
|
|
1549
|
+
metadata: Record<string, unknown>;
|
|
1550
|
+
gameType: "external" | "hosted";
|
|
1551
|
+
visibility?: "internal" | "unlisted" | "visible" | undefined;
|
|
1552
|
+
externalUrl?: string | undefined;
|
|
1553
|
+
}, {
|
|
1554
|
+
displayName: string;
|
|
1555
|
+
platform: "godot" | "unity" | "web";
|
|
1556
|
+
metadata?: Record<string, unknown> | undefined;
|
|
1557
|
+
gameType?: "external" | "hosted" | undefined;
|
|
1558
|
+
visibility?: "internal" | "unlisted" | "visible" | undefined;
|
|
1559
|
+
externalUrl?: string | undefined;
|
|
1560
|
+
}>, {
|
|
1561
|
+
displayName: string;
|
|
1562
|
+
platform: "godot" | "unity" | "web";
|
|
1563
|
+
metadata: Record<string, unknown>;
|
|
1564
|
+
gameType: "external" | "hosted";
|
|
1565
|
+
visibility?: "internal" | "unlisted" | "visible" | undefined;
|
|
1566
|
+
externalUrl?: string | undefined;
|
|
1567
|
+
}, {
|
|
1568
|
+
displayName: string;
|
|
1569
|
+
platform: "godot" | "unity" | "web";
|
|
1570
|
+
metadata?: Record<string, unknown> | undefined;
|
|
1571
|
+
gameType?: "external" | "hosted" | undefined;
|
|
1572
|
+
visibility?: "internal" | "unlisted" | "visible" | undefined;
|
|
1573
|
+
externalUrl?: string | undefined;
|
|
1574
|
+
}>;
|
|
1575
|
+
declare const PatchGameMetadataSchema: z.ZodObject<{
|
|
1576
|
+
displayName: z.ZodOptional<z.ZodString>;
|
|
1577
|
+
visibility: z.ZodOptional<z.ZodEnum<["visible", "unlisted", "internal"]>>;
|
|
1578
|
+
platform: z.ZodOptional<z.ZodEnum<["web", "godot", "unity"]>>;
|
|
1579
|
+
metadata: z.ZodOptional<z.ZodObject<{
|
|
1580
|
+
description: z.ZodOptional<z.ZodString>;
|
|
1581
|
+
emoji: z.ZodOptional<z.ZodEffects<z.ZodString, string, string>>;
|
|
1582
|
+
}, "strip", z.ZodTypeAny, {
|
|
1583
|
+
description?: string | undefined;
|
|
1584
|
+
emoji?: string | undefined;
|
|
1585
|
+
}, {
|
|
1586
|
+
description?: string | undefined;
|
|
1587
|
+
emoji?: string | undefined;
|
|
1588
|
+
}>>;
|
|
1589
|
+
}, "strip", z.ZodTypeAny, {
|
|
1590
|
+
displayName?: string | undefined;
|
|
1591
|
+
visibility?: "internal" | "unlisted" | "visible" | undefined;
|
|
1592
|
+
platform?: "godot" | "unity" | "web" | undefined;
|
|
1593
|
+
metadata?: {
|
|
1594
|
+
description?: string | undefined;
|
|
1595
|
+
emoji?: string | undefined;
|
|
1596
|
+
} | undefined;
|
|
1597
|
+
}, {
|
|
1598
|
+
displayName?: string | undefined;
|
|
1599
|
+
visibility?: "internal" | "unlisted" | "visible" | undefined;
|
|
1600
|
+
platform?: "godot" | "unity" | "web" | undefined;
|
|
1601
|
+
metadata?: {
|
|
1602
|
+
description?: string | undefined;
|
|
1603
|
+
emoji?: string | undefined;
|
|
1604
|
+
} | undefined;
|
|
1605
|
+
}>;
|
|
1606
|
+
declare const AddGameMemberSchema: z.ZodObject<{
|
|
1607
|
+
userId: z.ZodString;
|
|
1608
|
+
role: z.ZodDefault<z.ZodOptional<z.ZodLiteral<"collaborator">>>;
|
|
1609
|
+
}, "strict", z.ZodTypeAny, {
|
|
1610
|
+
userId: string;
|
|
1611
|
+
role: "collaborator";
|
|
1612
|
+
}, {
|
|
1613
|
+
userId: string;
|
|
1614
|
+
role?: "collaborator" | undefined;
|
|
1615
|
+
}>;
|
|
1616
|
+
declare const UpdateGameMemberRoleSchema: z.ZodObject<{
|
|
1617
|
+
role: z.ZodEnum<["owner", "collaborator"]>;
|
|
1618
|
+
}, "strict", z.ZodTypeAny, {
|
|
1619
|
+
role: "collaborator" | "owner";
|
|
1620
|
+
}, {
|
|
1621
|
+
role: "collaborator" | "owner";
|
|
1622
|
+
}>;
|
|
1623
|
+
|
|
1624
|
+
type GameRow = typeof games.$inferSelect;
|
|
1625
|
+
type BaseGame = Omit<GameRow, 'gameType' | 'deploymentUrl' | 'externalUrl'>;
|
|
1626
|
+
type HostedGame = BaseGame & {
|
|
1627
|
+
gameType: 'hosted';
|
|
1628
|
+
deploymentUrl: string;
|
|
1629
|
+
externalUrl: null;
|
|
1630
|
+
};
|
|
1631
|
+
type ExternalGame = BaseGame & {
|
|
1632
|
+
gameType: 'external';
|
|
1633
|
+
deploymentUrl: null;
|
|
1634
|
+
externalUrl: string;
|
|
1635
|
+
};
|
|
1636
|
+
type Game = HostedGame | ExternalGame;
|
|
1637
|
+
type GameMemberRow = typeof gameMembers.$inferSelect;
|
|
1638
|
+
type GameMemberWithUser = GameMemberRow & {
|
|
1639
|
+
user: {
|
|
1640
|
+
id: string;
|
|
1641
|
+
name: string;
|
|
1642
|
+
email: string;
|
|
1643
|
+
image: string | null;
|
|
1644
|
+
};
|
|
1645
|
+
};
|
|
1646
|
+
interface GameMemberSearchResult {
|
|
1647
|
+
id: string;
|
|
1648
|
+
name: string;
|
|
1649
|
+
email: string;
|
|
1650
|
+
image: string | null;
|
|
1651
|
+
}
|
|
1652
|
+
type GameCustomHostnameRow = typeof gameCustomHostnames.$inferSelect;
|
|
1653
|
+
|
|
1654
|
+
type UpsertGameMetadataInput = z.infer<typeof UpsertGameMetadataSchema>;
|
|
1655
|
+
type PatchGameMetadataInput = z.infer<typeof PatchGameMetadataSchema>;
|
|
1656
|
+
type AddGameMemberInput = z.infer<typeof AddGameMemberSchema>;
|
|
1657
|
+
type UpdateGameMemberRoleInput = z.infer<typeof UpdateGameMemberRoleSchema>;
|
|
1658
|
+
|
|
1659
|
+
type UserRow = typeof users.$inferSelect;
|
|
1660
|
+
|
|
1661
|
+
/**
|
|
1662
|
+
* Cross-Domain Composite Types
|
|
1663
|
+
*/
|
|
1664
|
+
/**
|
|
1665
|
+
* Game with optional manifest metadata from build tools
|
|
1666
|
+
*/
|
|
1667
|
+
type FetchedGame = (HostedGame | ExternalGame | GameRow) & {
|
|
1668
|
+
manifest?: GameManifest;
|
|
1669
|
+
};
|
|
1670
|
+
/**
|
|
1671
|
+
* Game custom hostname with validation records
|
|
1672
|
+
*/
|
|
1673
|
+
type GameCustomHostname = GameCustomHostnameRow & {
|
|
1674
|
+
validationRecords?: DomainValidationRecords;
|
|
1675
|
+
};
|
|
1676
|
+
|
|
1677
|
+
/**
|
|
1678
|
+
* Base Playcademy SDK client with shared infrastructure.
|
|
1679
|
+
* Provides authentication, HTTP requests, events,
|
|
1680
|
+
* and fundamental namespaces used by all clients.
|
|
1681
|
+
*
|
|
1682
|
+
* Extended by PlaycademyClient (game SDK) and PlaycademyInternalClient (platform SDK).
|
|
1683
|
+
*/
|
|
1684
|
+
declare abstract class PlaycademyBaseClient {
|
|
1685
|
+
baseUrl: string;
|
|
1686
|
+
gameUrl?: string;
|
|
1687
|
+
mode: PlaycademyMode;
|
|
1688
|
+
protected authStrategy: AuthStrategy;
|
|
1689
|
+
protected gameId?: string;
|
|
1690
|
+
protected config: Partial<ClientConfig>;
|
|
1691
|
+
protected listeners: EventListeners;
|
|
1692
|
+
protected authContext?: {
|
|
1693
|
+
isInIframe: boolean;
|
|
1694
|
+
};
|
|
1695
|
+
protected initPayload?: InitPayload;
|
|
1696
|
+
protected launchId?: string;
|
|
1697
|
+
protected gameOrigin?: string;
|
|
1698
|
+
private browserTimeZone?;
|
|
1699
|
+
constructor(config?: Partial<ClientConfig>);
|
|
1700
|
+
/**
|
|
1701
|
+
* Gets the effective base URL for API requests.
|
|
1702
|
+
*/
|
|
1703
|
+
getBaseUrl(): string;
|
|
1704
|
+
/**
|
|
1705
|
+
* Gets the effective game backend URL for integration requests.
|
|
1706
|
+
*/
|
|
1707
|
+
protected getGameBackendUrl(): string;
|
|
1708
|
+
/**
|
|
1709
|
+
* Simple ping method for testing connectivity.
|
|
1710
|
+
*/
|
|
1711
|
+
ping(): string;
|
|
1712
|
+
/**
|
|
1713
|
+
* Local day context supplied by the platform during iframe initialization.
|
|
1714
|
+
*/
|
|
1715
|
+
get localDay(): LocalDayContext | undefined;
|
|
1716
|
+
/**
|
|
1717
|
+
* Sets the authentication token for API requests.
|
|
1718
|
+
*/
|
|
1719
|
+
setToken(token: string | null, tokenType?: TokenType): void;
|
|
1720
|
+
setLaunchId(launchId: string | null | undefined): void;
|
|
1721
|
+
/**
|
|
1722
|
+
* Gets the current token type.
|
|
1723
|
+
*/
|
|
1724
|
+
getTokenType(): TokenType;
|
|
1725
|
+
/**
|
|
1726
|
+
* Gets the current authentication token.
|
|
1727
|
+
*/
|
|
1728
|
+
getToken(): string | null;
|
|
1729
|
+
/**
|
|
1730
|
+
* Checks if the client has a valid API token.
|
|
1731
|
+
*/
|
|
1732
|
+
isAuthenticated(): boolean;
|
|
1733
|
+
/**
|
|
1734
|
+
* Registers a callback to be called when authentication state changes.
|
|
1735
|
+
*/
|
|
1736
|
+
onAuthChange(callback: (token: string | null) => void): void;
|
|
1737
|
+
/**
|
|
1738
|
+
* Sets the authentication context for the client.
|
|
1739
|
+
* @internal
|
|
1740
|
+
*/
|
|
1741
|
+
_setAuthContext(context: {
|
|
1742
|
+
isInIframe: boolean;
|
|
1743
|
+
}): void;
|
|
1744
|
+
/**
|
|
1745
|
+
* Registers an event listener for client events.
|
|
1746
|
+
*
|
|
1747
|
+
* @param event - The event name to listen for.
|
|
1748
|
+
* @param callback - The handler invoked when the event fires.
|
|
1749
|
+
* @returns A cleanup function that removes this specific listener.
|
|
1750
|
+
*/
|
|
1751
|
+
on<E extends keyof ClientEvents>(event: E, callback: (payload: ClientEvents[E]) => void): () => void;
|
|
1752
|
+
/**
|
|
1753
|
+
* Removes a previously registered event listener.
|
|
1754
|
+
*
|
|
1755
|
+
* @param event - The event name to stop listening for.
|
|
1756
|
+
* @param callback - The exact function reference passed to {@link on}.
|
|
1757
|
+
*/
|
|
1758
|
+
off<E extends keyof ClientEvents>(event: E, callback: (payload: ClientEvents[E]) => void): void;
|
|
1759
|
+
/**
|
|
1760
|
+
* Emits an event to all registered listeners.
|
|
1761
|
+
*/
|
|
1762
|
+
protected emit<E extends keyof ClientEvents>(event: E, payload: ClientEvents[E]): void;
|
|
1763
|
+
/**
|
|
1764
|
+
* Makes an authenticated HTTP request to the platform API.
|
|
1765
|
+
*/
|
|
1766
|
+
protected request<T>(path: string, method: Method, options?: {
|
|
1767
|
+
body?: unknown;
|
|
1768
|
+
headers?: Record<string, string>;
|
|
1769
|
+
raw?: boolean;
|
|
1770
|
+
retryPolicy?: RetryPolicy;
|
|
1771
|
+
}): Promise<T>;
|
|
1772
|
+
private getBrowserTimeZone;
|
|
1773
|
+
/**
|
|
1774
|
+
* Makes an authenticated HTTP request to the game's backend Worker.
|
|
1775
|
+
*/
|
|
1776
|
+
protected requestGameBackend<T>(path: string, method: Method, body?: unknown, headers?: Record<string, string>, options?: {
|
|
1777
|
+
raw?: boolean;
|
|
1778
|
+
retryPolicy?: RetryPolicy;
|
|
1779
|
+
}): Promise<T>;
|
|
1780
|
+
/**
|
|
1781
|
+
* Ensures a gameId is available, throwing an error if not.
|
|
1782
|
+
*/
|
|
1783
|
+
protected _ensureGameId(): string;
|
|
1784
|
+
private _parseOrigin;
|
|
1785
|
+
/**
|
|
1786
|
+
* Detects and sets the authentication context (iframe vs standalone).
|
|
1787
|
+
*/
|
|
1788
|
+
private _detectAuthContext;
|
|
1789
|
+
/**
|
|
1790
|
+
* Current user data.
|
|
1791
|
+
* - `me()` - Get authenticated user profile
|
|
1792
|
+
*/
|
|
1793
|
+
users: {
|
|
1794
|
+
me: () => Promise<_playcademy_types.AuthenticatedUser>;
|
|
1795
|
+
};
|
|
1796
|
+
}
|
|
1797
|
+
|
|
1798
|
+
/**
|
|
1799
|
+
* Auto-initializes a PlaycademyClient with context from the environment.
|
|
1800
|
+
* Works in both iframe mode (production/development) and standalone mode (local dev).
|
|
1801
|
+
*
|
|
1802
|
+
* This is the recommended way to initialize the SDK as it automatically:
|
|
1803
|
+
* - Detects the runtime environment (iframe vs standalone)
|
|
1804
|
+
* - Configures the client with the appropriate context
|
|
1805
|
+
* - Sets up event listeners for token refresh
|
|
1806
|
+
* - Exposes the client for debugging in development mode
|
|
1807
|
+
*
|
|
1808
|
+
* @param options - Optional configuration overrides
|
|
1809
|
+
* @param options.baseUrl - Override the base URL for API requests
|
|
1810
|
+
* @returns Promise resolving to a fully initialized PlaycademyClient
|
|
1811
|
+
* @throws Error if not running in a browser context
|
|
1812
|
+
*
|
|
1813
|
+
* @example
|
|
1814
|
+
* ```typescript
|
|
1815
|
+
* // Default initialization
|
|
1816
|
+
* const client = await PlaycademyClient.init()
|
|
1817
|
+
*
|
|
1818
|
+
* // With custom base URL
|
|
1819
|
+
* const client = await PlaycademyClient.init({ baseUrl: 'https://custom.api.com' })
|
|
1820
|
+
* ```
|
|
1821
|
+
*/
|
|
1822
|
+
declare function init<T extends PlaycademyBaseClient = PlaycademyBaseClient>(this: new (config?: Partial<ClientConfig>) => T, options?: {
|
|
1823
|
+
baseUrl?: string;
|
|
1824
|
+
allowedParentOrigins?: string[];
|
|
1825
|
+
}): Promise<T>;
|
|
1826
|
+
|
|
1827
|
+
/**
|
|
1828
|
+
* Authenticates a user with email and password.
|
|
1829
|
+
*
|
|
1830
|
+
* This is a standalone authentication method that doesn't require an initialized client.
|
|
1831
|
+
* Use this for login flows before creating a client instance.
|
|
1832
|
+
*
|
|
1833
|
+
* @deprecated Use client.auth.login() instead for better error handling and automatic token management
|
|
1834
|
+
*
|
|
1835
|
+
* @param baseUrl - The base URL of the Playcademy API
|
|
1836
|
+
* @param email - User's email address
|
|
1837
|
+
* @param password - User's password
|
|
1838
|
+
* @returns Promise resolving to authentication response with token
|
|
1839
|
+
* @throws PlaycademyError if authentication fails or network error occurs
|
|
1840
|
+
*
|
|
1841
|
+
* @example
|
|
1842
|
+
* ```typescript
|
|
1843
|
+
* // Preferred approach:
|
|
1844
|
+
* const client = new PlaycademyClient({ baseUrl: '/api' })
|
|
1845
|
+
* const result = await client.auth.login({
|
|
1846
|
+
* email: 'user@example.com',
|
|
1847
|
+
* password: 'password'
|
|
1848
|
+
* })
|
|
1849
|
+
*
|
|
1850
|
+
* // Legacy approach (still works):
|
|
1851
|
+
* try {
|
|
1852
|
+
* const response = await PlaycademyClient.login('/api', 'user@example.com', 'password')
|
|
1853
|
+
* const client = new PlaycademyClient({ token: response.token })
|
|
1854
|
+
* } catch (error) {
|
|
1855
|
+
* console.error('Login failed:', error.message)
|
|
1856
|
+
* }
|
|
1857
|
+
* ```
|
|
1858
|
+
*/
|
|
1859
|
+
declare function login(baseUrl: string, email: string, password: string): Promise<LoginResponse>;
|
|
1860
|
+
|
|
1861
|
+
/**
|
|
1862
|
+
* Cache configuration types for runtime customization
|
|
1863
|
+
*/
|
|
1864
|
+
/**
|
|
1865
|
+
* Runtime configuration for TTL cache behavior
|
|
1866
|
+
*/
|
|
1867
|
+
interface TTLCacheConfig {
|
|
1868
|
+
/** Time-to-live in milliseconds. Set to 0 to disable caching for this call. */
|
|
1869
|
+
ttl?: number;
|
|
1870
|
+
/** Force refresh, bypassing cache */
|
|
1871
|
+
force?: boolean;
|
|
1872
|
+
/** Skip cache and fetch fresh data (alias for force) */
|
|
1873
|
+
skipCache?: boolean;
|
|
1874
|
+
}
|
|
1875
|
+
|
|
1876
|
+
/**
|
|
1877
|
+
* Options for configuring activity tracking behavior.
|
|
1878
|
+
*/
|
|
1879
|
+
interface StartActivityOptions {
|
|
1880
|
+
/**
|
|
1881
|
+
* How long heartbeats continue after the activity is automatically paused
|
|
1882
|
+
* because the tab is hidden or the player is inactive while visible.
|
|
1883
|
+
* Defaults to 10 minutes. Set to `Infinity` to keep heartbeats running
|
|
1884
|
+
* indefinitely during automatic pauses. Invalid values fall back to the
|
|
1885
|
+
* 10-minute default.
|
|
1886
|
+
*/
|
|
1887
|
+
pausedHeartbeatTimeoutMs?: number;
|
|
1888
|
+
/**
|
|
1889
|
+
* @deprecated Use `pausedHeartbeatTimeoutMs` instead.
|
|
1890
|
+
*
|
|
1891
|
+
* Backward-compatible alias for callers that still use the old option
|
|
1892
|
+
* name from earlier SDK releases.
|
|
1893
|
+
*/
|
|
1894
|
+
hiddenTimeoutMs?: number;
|
|
1895
|
+
/**
|
|
1896
|
+
* How often to flush periodic heartbeats with accumulated time data.
|
|
1897
|
+
* Defaults to 15 seconds. Set to `Infinity` to disable the interval;
|
|
1898
|
+
* final unload/endActivity flushes still run. Values must be greater than
|
|
1899
|
+
* 0 or `Infinity`; invalid values fall back to the 15-second default.
|
|
1900
|
+
*/
|
|
1901
|
+
heartbeatIntervalMs?: number;
|
|
1902
|
+
/**
|
|
1903
|
+
* How long the tab can remain visible without keyboard or mouse activity
|
|
1904
|
+
* before the activity is marked inactive. Defaults to 10 minutes. Set to
|
|
1905
|
+
* `Infinity` to disable keyboard/mouse inactivity tracking. Invalid values
|
|
1906
|
+
* fall back to the 10-minute default.
|
|
1907
|
+
*/
|
|
1908
|
+
inactivityTimeoutMs?: number;
|
|
1909
|
+
/**
|
|
1910
|
+
* Stable identifier for this activity run. When provided, it is used on
|
|
1911
|
+
* every heartbeat and on endActivity instead of a freshly-generated UUID.
|
|
1912
|
+
*
|
|
1913
|
+
* Pass the same `runId` across multiple `startActivity()` calls (for
|
|
1914
|
+
* example, after the player closes and reopens a resumable activity) so
|
|
1915
|
+
* downstream systems can correlate related sessions into a single run.
|
|
1916
|
+
*
|
|
1917
|
+
* Must be a UUID (the backend validates it as such) and unique per
|
|
1918
|
+
* logical run. If omitted, the SDK generates a new UUID on each call,
|
|
1919
|
+
* which means every session is treated as its own run.
|
|
1920
|
+
*/
|
|
1921
|
+
runId?: string;
|
|
1922
|
+
}
|
|
1923
|
+
interface StartActivityResult {
|
|
1924
|
+
runId: string;
|
|
1925
|
+
}
|
|
1926
|
+
|
|
1927
|
+
/**
|
|
1928
|
+
* Type definitions for the game timeback namespace.
|
|
1929
|
+
*
|
|
1930
|
+
* SDK-specific types like TimebackInitContext that wrap the core types
|
|
1931
|
+
* from @playcademy/types/user (which are re-exported via types/data.ts).
|
|
1932
|
+
*/
|
|
1933
|
+
|
|
1934
|
+
/**
|
|
1935
|
+
* A TimeBack enrollment for the current game session.
|
|
1936
|
+
* Alias for UserEnrollment without the optional gameId.
|
|
1937
|
+
*/
|
|
1938
|
+
type TimebackEnrollment = Omit<UserEnrollment, 'gameId'>;
|
|
1939
|
+
/**
|
|
1940
|
+
* A TimeBack organization (school/district) for the current user.
|
|
1941
|
+
* Alias for UserOrganization.
|
|
1942
|
+
*/
|
|
1943
|
+
type TimebackOrganization = UserOrganization;
|
|
1944
|
+
/**
|
|
1945
|
+
* TimeBack context passed during game initialization.
|
|
1946
|
+
* This is sent from the platform (cademy) to the game iframe via postMessage.
|
|
1947
|
+
*/
|
|
1948
|
+
interface TimebackInitContext {
|
|
1949
|
+
/** User's TimeBack ID */
|
|
1950
|
+
id: string;
|
|
1951
|
+
/** User's role in TimeBack (student, parent, teacher, etc.) */
|
|
1952
|
+
role: TimebackUserRole;
|
|
1953
|
+
/** User's enrollments for this game (one per grade/subject combo) */
|
|
1954
|
+
enrollments: TimebackEnrollment[];
|
|
1955
|
+
/** User's organizations (schools/districts) */
|
|
1956
|
+
organizations: TimebackOrganization[];
|
|
1957
|
+
}
|
|
1958
|
+
/**
|
|
1959
|
+
* TimeBack user context with current data (may be stale from init).
|
|
1960
|
+
* Use `fetch()` to get fresh data from the server.
|
|
1961
|
+
*/
|
|
1962
|
+
interface TimebackUserContext {
|
|
1963
|
+
/** User's TimeBack ID */
|
|
1964
|
+
id: string | undefined;
|
|
1965
|
+
/** User's role in TimeBack (student, parent, teacher, etc.) */
|
|
1966
|
+
role: TimebackUserRole | undefined;
|
|
1967
|
+
/** User's enrollments for this game */
|
|
1968
|
+
enrollments: TimebackEnrollment[];
|
|
1969
|
+
/** User's organizations (schools/districts) */
|
|
1970
|
+
organizations: TimebackOrganization[];
|
|
1971
|
+
}
|
|
1972
|
+
/**
|
|
1973
|
+
* Slice options for refreshing the cached TimeBack user context.
|
|
1974
|
+
*/
|
|
1975
|
+
type TimebackUserRefreshField = 'enrollments';
|
|
1976
|
+
interface TimebackUserRefreshOptions extends TTLCacheConfig {
|
|
1977
|
+
/** Refresh only these user data fields */
|
|
1978
|
+
only: readonly TimebackUserRefreshField[];
|
|
1979
|
+
}
|
|
1980
|
+
/**
|
|
1981
|
+
* XP data access for the current user.
|
|
1982
|
+
* Results are cached for 5 seconds to avoid redundant network requests.
|
|
1983
|
+
*/
|
|
1984
|
+
interface TimebackUserXp {
|
|
1985
|
+
/**
|
|
1986
|
+
* Fetch XP data from the server.
|
|
1987
|
+
* Returns XP for all courses in this game, or filter by grade/subject.
|
|
1988
|
+
* Results are cached for 5 seconds (use `force: true` to bypass).
|
|
1989
|
+
*
|
|
1990
|
+
* @param options - Query options
|
|
1991
|
+
* @param options.grade - Grade level to filter (must be used with subject)
|
|
1992
|
+
* @param options.subject - Subject to filter (must be used with grade)
|
|
1993
|
+
* @param options.include - Additional data to include: 'perCourse', 'today'
|
|
1994
|
+
* @param options.force - Bypass cache and fetch fresh data (default: false)
|
|
1995
|
+
* @returns Promise resolving to XP data
|
|
1996
|
+
*
|
|
1997
|
+
* @example
|
|
1998
|
+
* ```typescript
|
|
1999
|
+
* // Get total XP for all game courses
|
|
2000
|
+
* const xp = await client.timeback.user.xp.fetch()
|
|
2001
|
+
*
|
|
2002
|
+
* // Get XP for a specific grade/subject
|
|
2003
|
+
* const xp = await client.timeback.user.xp.fetch({
|
|
2004
|
+
* grade: 3,
|
|
2005
|
+
* subject: 'Math'
|
|
2006
|
+
* })
|
|
2007
|
+
*
|
|
2008
|
+
* // Get XP with per-course breakdown
|
|
2009
|
+
* const xp = await client.timeback.user.xp.fetch({
|
|
2010
|
+
* include: ['perCourse', 'today']
|
|
2011
|
+
* })
|
|
2012
|
+
*
|
|
2013
|
+
* // Force fresh data
|
|
2014
|
+
* const xp = await client.timeback.user.xp.fetch({ force: true })
|
|
2015
|
+
* ```
|
|
2016
|
+
*/
|
|
2017
|
+
fetch(options?: GetXpOptions): Promise<XpResponse>;
|
|
2018
|
+
}
|
|
2019
|
+
/**
|
|
2020
|
+
* TimeBack user object with cached getters, fetch, and targeted refresh methods.
|
|
2021
|
+
*/
|
|
2022
|
+
interface TimebackUser extends TimebackUserContext {
|
|
2023
|
+
/**
|
|
2024
|
+
* Fetch TimeBack data from the server (cached for 5 min).
|
|
2025
|
+
* Updates the cached values so subsequent property access returns fresh data.
|
|
2026
|
+
* @param options - Cache options (pass { force: true } to bypass cache)
|
|
2027
|
+
* @returns Promise resolving to fresh user context
|
|
2028
|
+
*/
|
|
2029
|
+
fetch(options?: TTLCacheConfig): Promise<TimebackUserContext>;
|
|
2030
|
+
/**
|
|
2031
|
+
* Refresh selected TimeBack user data from the server.
|
|
2032
|
+
* Updates the cached user snapshot used by the synchronous getters.
|
|
2033
|
+
* @param options - Refresh fields and cache options
|
|
2034
|
+
* @returns Promise resolving to the updated user context
|
|
2035
|
+
*/
|
|
2036
|
+
refresh(options: TimebackUserRefreshOptions): Promise<TimebackUserContext>;
|
|
2037
|
+
/**
|
|
2038
|
+
* XP data for the current user.
|
|
2039
|
+
* Call `xp.fetch()` to get XP from the server.
|
|
2040
|
+
*/
|
|
2041
|
+
xp: TimebackUserXp;
|
|
2042
|
+
/**
|
|
2043
|
+
* Mastery data for the current user.
|
|
2044
|
+
* Call `mastery.fetch()` to get mastery progress from the server.
|
|
2045
|
+
*/
|
|
2046
|
+
mastery: TimebackUserMastery;
|
|
2047
|
+
/**
|
|
2048
|
+
* Highest-grade-mastered data for the current user.
|
|
2049
|
+
* Call `highestGradeMastered.fetch({ subject })` to get the student's
|
|
2050
|
+
* highest mastered grade for a subject.
|
|
2051
|
+
*/
|
|
2052
|
+
highestGradeMastered: TimebackUserHighestGradeMastered;
|
|
2053
|
+
}
|
|
2054
|
+
/**
|
|
2055
|
+
* Mastery data access for the current user.
|
|
2056
|
+
* Results are cached for 5 seconds to avoid redundant network requests.
|
|
2057
|
+
*/
|
|
2058
|
+
interface TimebackUserMastery {
|
|
2059
|
+
/**
|
|
2060
|
+
* Fetch mastery data from the server.
|
|
2061
|
+
* Returns mastery for all courses in this game, or filter by grade/subject.
|
|
2062
|
+
* Returned masteredUnits values are true analytics values and may exceed
|
|
2063
|
+
* the course masterableUnits maximum when historical data violates the
|
|
2064
|
+
* expected invariant.
|
|
2065
|
+
* Results are cached for 5 seconds (use `force: true` to bypass).
|
|
2066
|
+
*
|
|
2067
|
+
* @param options - Query options
|
|
2068
|
+
* @param options.grade - Grade level to filter (must be used with subject)
|
|
2069
|
+
* @param options.subject - Subject to filter (must be used with grade)
|
|
2070
|
+
* @param options.include - Additional data to include: 'perCourse'
|
|
2071
|
+
* @param options.force - Bypass cache and fetch fresh data (default: false)
|
|
2072
|
+
* @returns Promise resolving to mastery data
|
|
2073
|
+
*
|
|
2074
|
+
* @example
|
|
2075
|
+
* ```typescript
|
|
2076
|
+
* // Get total mastery for all game courses
|
|
2077
|
+
* const mastery = await client.timeback.user.mastery.fetch()
|
|
2078
|
+
*
|
|
2079
|
+
* // Get mastery for a specific grade/subject
|
|
2080
|
+
* const mastery = await client.timeback.user.mastery.fetch({
|
|
2081
|
+
* grade: 3,
|
|
2082
|
+
* subject: 'Math'
|
|
2083
|
+
* })
|
|
2084
|
+
*
|
|
2085
|
+
* // Get mastery with per-course breakdown
|
|
2086
|
+
* const mastery = await client.timeback.user.mastery.fetch({
|
|
2087
|
+
* include: ['perCourse']
|
|
2088
|
+
* })
|
|
2089
|
+
*
|
|
2090
|
+
* // Force fresh data
|
|
2091
|
+
* const mastery = await client.timeback.user.mastery.fetch({ force: true })
|
|
2092
|
+
* ```
|
|
2093
|
+
*/
|
|
2094
|
+
fetch(options?: GetMasteryOptions): Promise<MasteryResponse>;
|
|
2095
|
+
}
|
|
2096
|
+
/**
|
|
2097
|
+
* Highest-grade-mastered data access for the current user.
|
|
2098
|
+
* Results are cached for 5 seconds to avoid redundant network requests.
|
|
2099
|
+
*/
|
|
2100
|
+
interface TimebackUserHighestGradeMastered {
|
|
2101
|
+
/**
|
|
2102
|
+
* Fetch the highest grade the current student has mastered for a subject.
|
|
2103
|
+
* Results are cached for 5 seconds (use `force: true` to bypass).
|
|
2104
|
+
*/
|
|
2105
|
+
fetch(options: GetHighestGradeMasteredOptions): Promise<HighestGradeMasteredResponse>;
|
|
2106
|
+
}
|
|
2107
|
+
/**
|
|
2108
|
+
* Options for querying student XP.
|
|
2109
|
+
*/
|
|
2110
|
+
interface GetXpOptions {
|
|
2111
|
+
/** Grade level to filter (must be used with subject) */
|
|
2112
|
+
grade?: TimebackGrade;
|
|
2113
|
+
/** Subject to filter (must be used with grade) */
|
|
2114
|
+
subject?: TimebackSubject;
|
|
2115
|
+
/** Additional data to include: 'perCourse', 'today' */
|
|
2116
|
+
include?: ('perCourse' | 'today')[];
|
|
2117
|
+
/** Bypass cache and fetch fresh data (default: false) */
|
|
2118
|
+
force?: boolean;
|
|
2119
|
+
}
|
|
2120
|
+
/**
|
|
2121
|
+
* Options for querying student mastery.
|
|
2122
|
+
*/
|
|
2123
|
+
interface GetMasteryOptions {
|
|
2124
|
+
/** Grade level to filter (must be used with subject) */
|
|
2125
|
+
grade?: TimebackGrade;
|
|
2126
|
+
/** Subject to filter (must be used with grade) */
|
|
2127
|
+
subject?: TimebackSubject;
|
|
2128
|
+
/** Additional data to include: 'perCourse' */
|
|
2129
|
+
include?: 'perCourse'[];
|
|
2130
|
+
/** Bypass cache and fetch fresh data (default: false) */
|
|
2131
|
+
force?: boolean;
|
|
2132
|
+
}
|
|
2133
|
+
/**
|
|
2134
|
+
* Options for querying highest grade mastered.
|
|
2135
|
+
*/
|
|
2136
|
+
interface GetHighestGradeMasteredOptions {
|
|
2137
|
+
/** Subject to query */
|
|
2138
|
+
subject: TimebackSubject;
|
|
2139
|
+
/** Bypass cache and fetch fresh data (default: false) */
|
|
2140
|
+
force?: boolean;
|
|
2141
|
+
}
|
|
2142
|
+
/**
|
|
2143
|
+
* XP data for a single course.
|
|
2144
|
+
*/
|
|
2145
|
+
interface CourseXp {
|
|
2146
|
+
grade: TimebackGrade;
|
|
2147
|
+
subject: TimebackSubject;
|
|
2148
|
+
title: string;
|
|
2149
|
+
totalXp: number;
|
|
2150
|
+
todayXp?: number;
|
|
2151
|
+
}
|
|
2152
|
+
/**
|
|
2153
|
+
* Response from XP query.
|
|
2154
|
+
*/
|
|
2155
|
+
interface XpResponse {
|
|
2156
|
+
totalXp: number;
|
|
2157
|
+
todayXp?: number;
|
|
2158
|
+
courses?: CourseXp[];
|
|
2159
|
+
}
|
|
2160
|
+
interface CourseMastery {
|
|
2161
|
+
grade: TimebackGrade;
|
|
2162
|
+
subject: TimebackSubject;
|
|
2163
|
+
title: string;
|
|
2164
|
+
/** True mastered units from analytics. May exceed masterableUnits for historical data. */
|
|
2165
|
+
masteredUnits: number;
|
|
2166
|
+
/** Configured mastery ceiling for the course. */
|
|
2167
|
+
masterableUnits: number;
|
|
2168
|
+
/** Clamped course completion percentage from 0..100. */
|
|
2169
|
+
pctComplete: number;
|
|
2170
|
+
isComplete: boolean;
|
|
2171
|
+
}
|
|
2172
|
+
/**
|
|
2173
|
+
* Response from mastery query.
|
|
2174
|
+
*/
|
|
2175
|
+
interface MasteryResponse {
|
|
2176
|
+
/** True mastered units across all queried courses. */
|
|
2177
|
+
totalMasteredUnits: number;
|
|
2178
|
+
/** Configured mastery ceiling across all queried courses. */
|
|
2179
|
+
totalMasterableUnits: number;
|
|
2180
|
+
courses?: CourseMastery[];
|
|
2181
|
+
}
|
|
2182
|
+
/**
|
|
2183
|
+
* Response from highest-grade-mastered query.
|
|
2184
|
+
*/
|
|
2185
|
+
interface HighestGradeMasteredResponse {
|
|
2186
|
+
subject: TimebackSubject;
|
|
2187
|
+
highestGradeMastered: TimebackGrade | null;
|
|
2188
|
+
}
|
|
2301
2189
|
|
|
2302
|
-
|
|
2303
|
-
|
|
2304
|
-
|
|
2305
|
-
|
|
2306
|
-
|
|
2307
|
-
|
|
2308
|
-
|
|
2309
|
-
|
|
2310
|
-
|
|
2311
|
-
|
|
2312
|
-
|
|
2313
|
-
|
|
2314
|
-
|
|
2315
|
-
|
|
2316
|
-
|
|
2317
|
-
|
|
2318
|
-
|
|
2319
|
-
|
|
2320
|
-
|
|
2321
|
-
|
|
2322
|
-
|
|
2323
|
-
|
|
2324
|
-
|
|
2190
|
+
/**
|
|
2191
|
+
* Core client configuration and lifecycle types
|
|
2192
|
+
*/
|
|
2193
|
+
|
|
2194
|
+
type TokenType = 'session' | 'apiKey' | 'gameJwt';
|
|
2195
|
+
/**
|
|
2196
|
+
* Runtime mode for a Playcademy game client.
|
|
2197
|
+
*
|
|
2198
|
+
* - `'platform'` — game is embedded in the platform (e.g. the cademy hub)
|
|
2199
|
+
* with a real authenticated user and full access to SDK namespaces.
|
|
2200
|
+
* - `'demo'` — game is embedded in the landing page demo shell with an
|
|
2201
|
+
* anonymous user; platform-only namespaces throw, and `client.demo.*`
|
|
2202
|
+
* is the supported surface for signaling demo lifecycle events and
|
|
2203
|
+
* reading/updating the anonymous profile.
|
|
2204
|
+
* - `'standalone'` — game is running outside any iframe (e.g. `bun run dev`
|
|
2205
|
+
* or direct-deploy preview) with a mock token and no real platform
|
|
2206
|
+
* context. API calls will not succeed; use this to branch UX locally.
|
|
2207
|
+
*/
|
|
2208
|
+
type PlaycademyMode = 'platform' | 'demo' | 'standalone';
|
|
2209
|
+
interface ClientConfig {
|
|
2210
|
+
baseUrl: string;
|
|
2211
|
+
gameUrl?: string;
|
|
2212
|
+
token?: string;
|
|
2213
|
+
tokenType?: TokenType;
|
|
2214
|
+
gameId?: string;
|
|
2215
|
+
launchId?: string;
|
|
2216
|
+
mode?: PlaycademyMode;
|
|
2217
|
+
}
|
|
2218
|
+
interface InitPayload {
|
|
2219
|
+
/** Hub API base URL */
|
|
2220
|
+
baseUrl: string;
|
|
2221
|
+
/** Game deployment URL (serves both frontend assets and backend API) */
|
|
2222
|
+
gameUrl?: string;
|
|
2223
|
+
/** Short-lived game token */
|
|
2224
|
+
token: string;
|
|
2225
|
+
/** Game ID */
|
|
2226
|
+
gameId: string;
|
|
2227
|
+
/** Timeback context (if user has a Timeback account) */
|
|
2228
|
+
timeback?: TimebackInitContext;
|
|
2229
|
+
/** Playcademy context for resolving the student's local learning day */
|
|
2230
|
+
localDay?: LocalDayContext;
|
|
2231
|
+
/** Runtime mode for the game client */
|
|
2232
|
+
mode?: PlaycademyMode;
|
|
2233
|
+
/** Launch session correlation ID (UUID, set by platform on game launch) */
|
|
2234
|
+
launchId?: string;
|
|
2235
|
+
/** When `true`, the parent shell provides a heartbeat relay via postMessage, so the SDK can skip its own `fetch({ keepalive })` beacon on pagehide. Defaults to `false`. */
|
|
2236
|
+
hasHeartbeatRelay?: boolean;
|
|
2237
|
+
}
|
|
2238
|
+
/**
|
|
2239
|
+
* Simplified user data passed to games via InitPayload
|
|
2240
|
+
* This is a subset of AuthenticatedUser suitable for external game consumption
|
|
2241
|
+
*
|
|
2242
|
+
* Note: Named GameInitUser to distinguish from the cross-game GameUser DTO
|
|
2243
|
+
* exported from @playcademy/types
|
|
2244
|
+
*/
|
|
2245
|
+
interface GameInitUser {
|
|
2246
|
+
/** Playcademy user ID */
|
|
2325
2247
|
id: string;
|
|
2326
|
-
|
|
2327
|
-
|
|
2248
|
+
/** Unique username */
|
|
2249
|
+
username: string | null;
|
|
2250
|
+
/** Display name */
|
|
2251
|
+
name: string | null;
|
|
2252
|
+
/** Email address */
|
|
2253
|
+
email: string | null;
|
|
2254
|
+
/** Profile image URL */
|
|
2328
2255
|
image: string | null;
|
|
2256
|
+
/** Whether the user has a Timeback account */
|
|
2257
|
+
hasTimebackAccount: boolean;
|
|
2258
|
+
}
|
|
2259
|
+
interface GameContextPayload {
|
|
2260
|
+
token: string;
|
|
2261
|
+
baseUrl: string;
|
|
2262
|
+
gameId: string;
|
|
2263
|
+
forwardKeys?: string[];
|
|
2264
|
+
mode?: PlaycademyMode;
|
|
2265
|
+
}
|
|
2266
|
+
type EventListeners = {
|
|
2267
|
+
[E in keyof ClientEvents]?: ((payload: ClientEvents[E]) => void)[];
|
|
2268
|
+
};
|
|
2269
|
+
interface ClientEvents {
|
|
2270
|
+
authChange: {
|
|
2271
|
+
token: string | null;
|
|
2272
|
+
};
|
|
2329
2273
|
}
|
|
2330
|
-
type GameCustomHostnameRow = typeof gameCustomHostnames.$inferSelect;
|
|
2331
|
-
|
|
2332
|
-
type UpsertGameMetadataInput = z.infer<typeof UpsertGameMetadataSchema>;
|
|
2333
|
-
type PatchGameMetadataInput = z.infer<typeof PatchGameMetadataSchema>;
|
|
2334
|
-
type AddGameMemberInput = z.infer<typeof AddGameMemberSchema>;
|
|
2335
|
-
type UpdateGameMemberRoleInput = z.infer<typeof UpdateGameMemberRoleSchema>;
|
|
2336
2274
|
|
|
2337
|
-
|
|
2275
|
+
/**
|
|
2276
|
+
* Event and message payload types for SDK messaging system
|
|
2277
|
+
*/
|
|
2338
2278
|
|
|
2339
2279
|
/**
|
|
2340
|
-
*
|
|
2280
|
+
* Authentication state change event payload.
|
|
2281
|
+
* Used when authentication state changes in the application.
|
|
2341
2282
|
*/
|
|
2283
|
+
interface AuthStateChangePayload {
|
|
2284
|
+
/** Whether the user is currently authenticated */
|
|
2285
|
+
authenticated: boolean;
|
|
2286
|
+
/** User information if authenticated, null otherwise */
|
|
2287
|
+
user: UserInfo | null;
|
|
2288
|
+
/** Error information if authentication failed */
|
|
2289
|
+
error: Error | null;
|
|
2290
|
+
}
|
|
2342
2291
|
/**
|
|
2343
|
-
*
|
|
2292
|
+
* OAuth callback event payload.
|
|
2293
|
+
* Used when OAuth flow completes in popup/new-tab windows.
|
|
2344
2294
|
*/
|
|
2345
|
-
|
|
2346
|
-
|
|
2347
|
-
|
|
2295
|
+
interface AuthCallbackPayload {
|
|
2296
|
+
/** OAuth authorization code */
|
|
2297
|
+
code: string;
|
|
2298
|
+
/** OAuth state parameter for CSRF protection */
|
|
2299
|
+
state: string;
|
|
2300
|
+
/** Error message if OAuth flow failed */
|
|
2301
|
+
error: string | null;
|
|
2302
|
+
}
|
|
2348
2303
|
/**
|
|
2349
|
-
*
|
|
2304
|
+
* Message sent from server callback to opener window.
|
|
2305
|
+
* This is the standardized format from our server-first architecture.
|
|
2350
2306
|
*/
|
|
2351
|
-
|
|
2352
|
-
|
|
2307
|
+
interface AuthServerMessage {
|
|
2308
|
+
/** Type of the message */
|
|
2309
|
+
type: 'PLAYCADEMY_AUTH_STATE_CHANGE';
|
|
2310
|
+
/** Whether the user is currently authenticated */
|
|
2311
|
+
authenticated: boolean;
|
|
2312
|
+
/** Whether the authentication was successful */
|
|
2313
|
+
success: boolean;
|
|
2314
|
+
/** Timestamp of the message */
|
|
2315
|
+
ts: number;
|
|
2316
|
+
/** User information if authentication was successful */
|
|
2317
|
+
user?: UserInfo;
|
|
2318
|
+
/** Error message if authentication failed */
|
|
2319
|
+
error?: string;
|
|
2320
|
+
}
|
|
2321
|
+
/**
|
|
2322
|
+
* Token refresh event payload.
|
|
2323
|
+
* Sent when authentication token is updated.
|
|
2324
|
+
*/
|
|
2325
|
+
interface TokenRefreshPayload {
|
|
2326
|
+
/** New authentication token */
|
|
2327
|
+
token: string;
|
|
2328
|
+
/** Token expiration timestamp */
|
|
2329
|
+
exp: number;
|
|
2330
|
+
}
|
|
2331
|
+
/**
|
|
2332
|
+
* Telemetry event payload.
|
|
2333
|
+
* Performance metrics sent from the game.
|
|
2334
|
+
*/
|
|
2335
|
+
interface TelemetryPayload {
|
|
2336
|
+
/** Frames per second */
|
|
2337
|
+
fps: number;
|
|
2338
|
+
/** Memory usage in MB */
|
|
2339
|
+
mem: number;
|
|
2340
|
+
}
|
|
2341
|
+
/**
|
|
2342
|
+
* Keyboard event payload.
|
|
2343
|
+
* Key events forwarded from the game.
|
|
2344
|
+
*/
|
|
2345
|
+
interface KeyEventPayload {
|
|
2346
|
+
/** Key value (e.g., 'Escape', 'F1') */
|
|
2347
|
+
key: string;
|
|
2348
|
+
/** Key code (optional) */
|
|
2349
|
+
code?: string;
|
|
2350
|
+
/** Event type */
|
|
2351
|
+
type: 'keydown' | 'keyup';
|
|
2352
|
+
}
|
|
2353
|
+
/**
|
|
2354
|
+
* Init error payload.
|
|
2355
|
+
* Sent from game iframe to parent when SDK initialization fails
|
|
2356
|
+
* (e.g. origin validation failure, INIT timeout, client creation error).
|
|
2357
|
+
*/
|
|
2358
|
+
interface InitErrorPayload {
|
|
2359
|
+
reason: string;
|
|
2360
|
+
}
|
|
2361
|
+
/**
|
|
2362
|
+
* Options for `client.demo.end(score, options?)`.
|
|
2363
|
+
*
|
|
2364
|
+
* All optional. The landing-page demo shell can render a meaningful CTA
|
|
2365
|
+
* from `score` alone, but `durationMs` enables a nicer summary and
|
|
2366
|
+
* `metadata` lets games pass any extra context they want to surface.
|
|
2367
|
+
*/
|
|
2368
|
+
interface DemoEndOptions {
|
|
2369
|
+
durationMs?: number;
|
|
2370
|
+
metadata?: Record<string, unknown>;
|
|
2371
|
+
}
|
|
2372
|
+
/**
|
|
2373
|
+
* Wire payload for the `PLAYCADEMY_DEMO_END` message.
|
|
2374
|
+
*
|
|
2375
|
+
* `score` is required — the demo shell always needs something to display
|
|
2376
|
+
* when the round ends. `durationMs` and `metadata` are optional.
|
|
2377
|
+
*/
|
|
2378
|
+
interface DemoEndPayload extends DemoEndOptions {
|
|
2379
|
+
score: number;
|
|
2380
|
+
}
|
|
2381
|
+
type TimebackHeartbeatRelayRequest = Omit<HeartbeatRequest, 'gameId' | 'studentId' | 'windowStartedAtMs' | 'windowSequence'> & {
|
|
2382
|
+
windowStartedAtMs: number;
|
|
2353
2383
|
};
|
|
2354
2384
|
|
|
2385
|
+
/**
|
|
2386
|
+
* SDK-specific API response types
|
|
2387
|
+
*/
|
|
2388
|
+
interface LoginResponse {
|
|
2389
|
+
token: string;
|
|
2390
|
+
}
|
|
2391
|
+
interface GameTokenResponse {
|
|
2392
|
+
token: string;
|
|
2393
|
+
exp: number;
|
|
2394
|
+
baseUrl?: string;
|
|
2395
|
+
}
|
|
2396
|
+
|
|
2355
2397
|
/**
|
|
2356
2398
|
* Scores namespace types
|
|
2357
2399
|
*/
|