@playcademy/sdk 0.0.8 → 0.1.0

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 CHANGED
@@ -1,7 +1,9 @@
1
1
  import * as _playcademy_realtime_server_types from '@playcademy/realtime/server/types';
2
+ import { InferSelectModel } from 'drizzle-orm';
2
3
  import * as drizzle_orm_pg_core from 'drizzle-orm/pg-core';
3
4
  import * as drizzle_zod from 'drizzle-zod';
4
5
  import { z } from 'zod';
6
+ import { OrganizationConfig, CourseConfig, ComponentConfig, ResourceConfig, ComponentResourceConfig } from '@playcademy/timeback/types';
5
7
 
6
8
  declare const users: drizzle_orm_pg_core.PgTableWithColumns<{
7
9
  name: "user";
@@ -1848,8 +1850,402 @@ declare const playerCharacterAccessories: drizzle_orm_pg_core.PgTableWithColumns
1848
1850
  };
1849
1851
  dialect: "pg";
1850
1852
  }>;
1853
+ declare const gameTimebackIntegrations: drizzle_orm_pg_core.PgTableWithColumns<{
1854
+ name: "game_timeback_integrations";
1855
+ schema: undefined;
1856
+ columns: {
1857
+ id: drizzle_orm_pg_core.PgColumn<{
1858
+ name: "id";
1859
+ tableName: "game_timeback_integrations";
1860
+ dataType: "string";
1861
+ columnType: "PgUUID";
1862
+ data: string;
1863
+ driverParam: string;
1864
+ notNull: true;
1865
+ hasDefault: true;
1866
+ isPrimaryKey: true;
1867
+ isAutoincrement: false;
1868
+ hasRuntimeDefault: false;
1869
+ enumValues: undefined;
1870
+ baseColumn: never;
1871
+ identity: undefined;
1872
+ generated: undefined;
1873
+ }, {}, {}>;
1874
+ gameId: drizzle_orm_pg_core.PgColumn<{
1875
+ name: "game_id";
1876
+ tableName: "game_timeback_integrations";
1877
+ dataType: "string";
1878
+ columnType: "PgUUID";
1879
+ data: string;
1880
+ driverParam: string;
1881
+ notNull: true;
1882
+ hasDefault: false;
1883
+ isPrimaryKey: false;
1884
+ isAutoincrement: false;
1885
+ hasRuntimeDefault: false;
1886
+ enumValues: undefined;
1887
+ baseColumn: never;
1888
+ identity: undefined;
1889
+ generated: undefined;
1890
+ }, {}, {}>;
1891
+ courseId: drizzle_orm_pg_core.PgColumn<{
1892
+ name: "course_id";
1893
+ tableName: "game_timeback_integrations";
1894
+ dataType: "string";
1895
+ columnType: "PgText";
1896
+ data: string;
1897
+ driverParam: string;
1898
+ notNull: true;
1899
+ hasDefault: false;
1900
+ isPrimaryKey: false;
1901
+ isAutoincrement: false;
1902
+ hasRuntimeDefault: false;
1903
+ enumValues: [string, ...string[]];
1904
+ baseColumn: never;
1905
+ identity: undefined;
1906
+ generated: undefined;
1907
+ }, {}, {}>;
1908
+ lastVerifiedAt: drizzle_orm_pg_core.PgColumn<{
1909
+ name: "last_verified_at";
1910
+ tableName: "game_timeback_integrations";
1911
+ dataType: "date";
1912
+ columnType: "PgTimestamp";
1913
+ data: Date;
1914
+ driverParam: string;
1915
+ notNull: false;
1916
+ hasDefault: false;
1917
+ isPrimaryKey: false;
1918
+ isAutoincrement: false;
1919
+ hasRuntimeDefault: false;
1920
+ enumValues: undefined;
1921
+ baseColumn: never;
1922
+ identity: undefined;
1923
+ generated: undefined;
1924
+ }, {}, {}>;
1925
+ createdAt: drizzle_orm_pg_core.PgColumn<{
1926
+ name: "created_at";
1927
+ tableName: "game_timeback_integrations";
1928
+ dataType: "date";
1929
+ columnType: "PgTimestamp";
1930
+ data: Date;
1931
+ driverParam: string;
1932
+ notNull: true;
1933
+ hasDefault: true;
1934
+ isPrimaryKey: false;
1935
+ isAutoincrement: false;
1936
+ hasRuntimeDefault: false;
1937
+ enumValues: undefined;
1938
+ baseColumn: never;
1939
+ identity: undefined;
1940
+ generated: undefined;
1941
+ }, {}, {}>;
1942
+ updatedAt: drizzle_orm_pg_core.PgColumn<{
1943
+ name: "updated_at";
1944
+ tableName: "game_timeback_integrations";
1945
+ dataType: "date";
1946
+ columnType: "PgTimestamp";
1947
+ data: Date;
1948
+ driverParam: string;
1949
+ notNull: true;
1950
+ hasDefault: true;
1951
+ isPrimaryKey: false;
1952
+ isAutoincrement: false;
1953
+ hasRuntimeDefault: false;
1954
+ enumValues: undefined;
1955
+ baseColumn: never;
1956
+ identity: undefined;
1957
+ generated: undefined;
1958
+ }, {}, {}>;
1959
+ };
1960
+ dialect: "pg";
1961
+ }>;
1851
1962
 
1852
- declare const achievementIntervalEnum: drizzle_orm_pg_core.PgEnum<["daily", "weekly"]>;
1963
+ declare const achievementScopeEnum: drizzle_orm_pg_core.PgEnum<["daily", "weekly", "monthly", "yearly", "game", "global", "map", "level", "event"]>;
1964
+ declare const notifications: drizzle_orm_pg_core.PgTableWithColumns<{
1965
+ name: "notifications";
1966
+ schema: undefined;
1967
+ columns: {
1968
+ id: drizzle_orm_pg_core.PgColumn<{
1969
+ name: "id";
1970
+ tableName: "notifications";
1971
+ dataType: "string";
1972
+ columnType: "PgUUID";
1973
+ data: string;
1974
+ driverParam: string;
1975
+ notNull: true;
1976
+ hasDefault: true;
1977
+ isPrimaryKey: true;
1978
+ isAutoincrement: false;
1979
+ hasRuntimeDefault: false;
1980
+ enumValues: undefined;
1981
+ baseColumn: never;
1982
+ identity: undefined;
1983
+ generated: undefined;
1984
+ }, {}, {}>;
1985
+ userId: drizzle_orm_pg_core.PgColumn<{
1986
+ name: "user_id";
1987
+ tableName: "notifications";
1988
+ dataType: "string";
1989
+ columnType: "PgText";
1990
+ data: string;
1991
+ driverParam: string;
1992
+ notNull: true;
1993
+ hasDefault: false;
1994
+ isPrimaryKey: false;
1995
+ isAutoincrement: false;
1996
+ hasRuntimeDefault: false;
1997
+ enumValues: [string, ...string[]];
1998
+ baseColumn: never;
1999
+ identity: undefined;
2000
+ generated: undefined;
2001
+ }, {}, {}>;
2002
+ type: drizzle_orm_pg_core.PgColumn<{
2003
+ name: "type";
2004
+ tableName: "notifications";
2005
+ dataType: "string";
2006
+ columnType: "PgVarchar";
2007
+ data: string;
2008
+ driverParam: string;
2009
+ notNull: true;
2010
+ hasDefault: false;
2011
+ isPrimaryKey: false;
2012
+ isAutoincrement: false;
2013
+ hasRuntimeDefault: false;
2014
+ enumValues: [string, ...string[]];
2015
+ baseColumn: never;
2016
+ identity: undefined;
2017
+ generated: undefined;
2018
+ }, {}, {
2019
+ length: 50;
2020
+ }>;
2021
+ title: drizzle_orm_pg_core.PgColumn<{
2022
+ name: "title";
2023
+ tableName: "notifications";
2024
+ dataType: "string";
2025
+ columnType: "PgVarchar";
2026
+ data: string;
2027
+ driverParam: string;
2028
+ notNull: true;
2029
+ hasDefault: false;
2030
+ isPrimaryKey: false;
2031
+ isAutoincrement: false;
2032
+ hasRuntimeDefault: false;
2033
+ enumValues: [string, ...string[]];
2034
+ baseColumn: never;
2035
+ identity: undefined;
2036
+ generated: undefined;
2037
+ }, {}, {
2038
+ length: 255;
2039
+ }>;
2040
+ message: drizzle_orm_pg_core.PgColumn<{
2041
+ name: "message";
2042
+ tableName: "notifications";
2043
+ dataType: "string";
2044
+ columnType: "PgText";
2045
+ data: string;
2046
+ driverParam: string;
2047
+ notNull: true;
2048
+ hasDefault: false;
2049
+ isPrimaryKey: false;
2050
+ isAutoincrement: false;
2051
+ hasRuntimeDefault: false;
2052
+ enumValues: [string, ...string[]];
2053
+ baseColumn: never;
2054
+ identity: undefined;
2055
+ generated: undefined;
2056
+ }, {}, {}>;
2057
+ data: drizzle_orm_pg_core.PgColumn<{
2058
+ name: "data";
2059
+ tableName: "notifications";
2060
+ dataType: "json";
2061
+ columnType: "PgJsonb";
2062
+ data: unknown;
2063
+ driverParam: unknown;
2064
+ notNull: true;
2065
+ hasDefault: true;
2066
+ isPrimaryKey: false;
2067
+ isAutoincrement: false;
2068
+ hasRuntimeDefault: false;
2069
+ enumValues: undefined;
2070
+ baseColumn: never;
2071
+ identity: undefined;
2072
+ generated: undefined;
2073
+ }, {}, {}>;
2074
+ priority: drizzle_orm_pg_core.PgColumn<{
2075
+ name: "priority";
2076
+ tableName: "notifications";
2077
+ dataType: "string";
2078
+ columnType: "PgEnumColumn";
2079
+ data: "low" | "normal" | "high" | "urgent";
2080
+ driverParam: string;
2081
+ notNull: true;
2082
+ hasDefault: true;
2083
+ isPrimaryKey: false;
2084
+ isAutoincrement: false;
2085
+ hasRuntimeDefault: false;
2086
+ enumValues: ["low", "normal", "high", "urgent"];
2087
+ baseColumn: never;
2088
+ identity: undefined;
2089
+ generated: undefined;
2090
+ }, {}, {}>;
2091
+ status: drizzle_orm_pg_core.PgColumn<{
2092
+ name: "status";
2093
+ tableName: "notifications";
2094
+ dataType: "string";
2095
+ columnType: "PgEnumColumn";
2096
+ data: "pending" | "delivered" | "seen" | "clicked" | "dismissed" | "expired";
2097
+ driverParam: string;
2098
+ notNull: true;
2099
+ hasDefault: true;
2100
+ isPrimaryKey: false;
2101
+ isAutoincrement: false;
2102
+ hasRuntimeDefault: false;
2103
+ enumValues: ["pending", "delivered", "seen", "clicked", "dismissed", "expired"];
2104
+ baseColumn: never;
2105
+ identity: undefined;
2106
+ generated: undefined;
2107
+ }, {}, {}>;
2108
+ createdAt: drizzle_orm_pg_core.PgColumn<{
2109
+ name: "created_at";
2110
+ tableName: "notifications";
2111
+ dataType: "date";
2112
+ columnType: "PgTimestamp";
2113
+ data: Date;
2114
+ driverParam: string;
2115
+ notNull: true;
2116
+ hasDefault: true;
2117
+ isPrimaryKey: false;
2118
+ isAutoincrement: false;
2119
+ hasRuntimeDefault: false;
2120
+ enumValues: undefined;
2121
+ baseColumn: never;
2122
+ identity: undefined;
2123
+ generated: undefined;
2124
+ }, {}, {}>;
2125
+ deliveredAt: drizzle_orm_pg_core.PgColumn<{
2126
+ name: "delivered_at";
2127
+ tableName: "notifications";
2128
+ dataType: "date";
2129
+ columnType: "PgTimestamp";
2130
+ data: Date;
2131
+ driverParam: string;
2132
+ notNull: false;
2133
+ hasDefault: false;
2134
+ isPrimaryKey: false;
2135
+ isAutoincrement: false;
2136
+ hasRuntimeDefault: false;
2137
+ enumValues: undefined;
2138
+ baseColumn: never;
2139
+ identity: undefined;
2140
+ generated: undefined;
2141
+ }, {}, {}>;
2142
+ seenAt: drizzle_orm_pg_core.PgColumn<{
2143
+ name: "seen_at";
2144
+ tableName: "notifications";
2145
+ dataType: "date";
2146
+ columnType: "PgTimestamp";
2147
+ data: Date;
2148
+ driverParam: string;
2149
+ notNull: false;
2150
+ hasDefault: false;
2151
+ isPrimaryKey: false;
2152
+ isAutoincrement: false;
2153
+ hasRuntimeDefault: false;
2154
+ enumValues: undefined;
2155
+ baseColumn: never;
2156
+ identity: undefined;
2157
+ generated: undefined;
2158
+ }, {}, {}>;
2159
+ clickedAt: drizzle_orm_pg_core.PgColumn<{
2160
+ name: "clicked_at";
2161
+ tableName: "notifications";
2162
+ dataType: "date";
2163
+ columnType: "PgTimestamp";
2164
+ data: Date;
2165
+ driverParam: string;
2166
+ notNull: false;
2167
+ hasDefault: false;
2168
+ isPrimaryKey: false;
2169
+ isAutoincrement: false;
2170
+ hasRuntimeDefault: false;
2171
+ enumValues: undefined;
2172
+ baseColumn: never;
2173
+ identity: undefined;
2174
+ generated: undefined;
2175
+ }, {}, {}>;
2176
+ expiresAt: drizzle_orm_pg_core.PgColumn<{
2177
+ name: "expires_at";
2178
+ tableName: "notifications";
2179
+ dataType: "date";
2180
+ columnType: "PgTimestamp";
2181
+ data: Date;
2182
+ driverParam: string;
2183
+ notNull: false;
2184
+ hasDefault: false;
2185
+ isPrimaryKey: false;
2186
+ isAutoincrement: false;
2187
+ hasRuntimeDefault: false;
2188
+ enumValues: undefined;
2189
+ baseColumn: never;
2190
+ identity: undefined;
2191
+ generated: undefined;
2192
+ }, {}, {}>;
2193
+ method: drizzle_orm_pg_core.PgColumn<{
2194
+ name: "method";
2195
+ tableName: "notifications";
2196
+ dataType: "string";
2197
+ columnType: "PgVarchar";
2198
+ data: string;
2199
+ driverParam: string;
2200
+ notNull: false;
2201
+ hasDefault: false;
2202
+ isPrimaryKey: false;
2203
+ isAutoincrement: false;
2204
+ hasRuntimeDefault: false;
2205
+ enumValues: [string, ...string[]];
2206
+ baseColumn: never;
2207
+ identity: undefined;
2208
+ generated: undefined;
2209
+ }, {}, {
2210
+ length: 50;
2211
+ }>;
2212
+ clickUrl: drizzle_orm_pg_core.PgColumn<{
2213
+ name: "click_url";
2214
+ tableName: "notifications";
2215
+ dataType: "string";
2216
+ columnType: "PgText";
2217
+ data: string;
2218
+ driverParam: string;
2219
+ notNull: false;
2220
+ hasDefault: false;
2221
+ isPrimaryKey: false;
2222
+ isAutoincrement: false;
2223
+ hasRuntimeDefault: false;
2224
+ enumValues: [string, ...string[]];
2225
+ baseColumn: never;
2226
+ identity: undefined;
2227
+ generated: undefined;
2228
+ }, {}, {}>;
2229
+ metadata: drizzle_orm_pg_core.PgColumn<{
2230
+ name: "metadata";
2231
+ tableName: "notifications";
2232
+ dataType: "json";
2233
+ columnType: "PgJsonb";
2234
+ data: unknown;
2235
+ driverParam: unknown;
2236
+ notNull: true;
2237
+ hasDefault: true;
2238
+ isPrimaryKey: false;
2239
+ isAutoincrement: false;
2240
+ hasRuntimeDefault: false;
2241
+ enumValues: undefined;
2242
+ baseColumn: never;
2243
+ identity: undefined;
2244
+ generated: undefined;
2245
+ }, {}, {}>;
2246
+ };
2247
+ dialect: "pg";
2248
+ }>;
1853
2249
  declare const DeveloperStatusResponseSchema: z.ZodObject<{
1854
2250
  status: z.ZodEnum<["none", "pending", "approved"]>;
1855
2251
  }, "strip", z.ZodTypeAny, {
@@ -2247,11 +2643,82 @@ declare const UpdateShopListingSchema: z.ZodObject<{
2247
2643
  availableFrom?: Date | null | undefined;
2248
2644
  availableUntil?: Date | null | undefined;
2249
2645
  }>;
2646
+
2647
+ declare enum AchievementCompletionType {
2648
+ TIME_PLAYED_SESSION = "time_played_session",
2649
+ INTERACTION = "interaction",
2650
+ LEADERBOARD_RANK = "leaderboard_rank",
2651
+ FIRST_SCORE = "first_score",
2652
+ PERSONAL_BEST = "personal_best"
2653
+ }
2654
+ type AchievementScopeType = (typeof achievementScopeEnum.enumValues)[number];
2250
2655
  /**
2251
- * Achievement Completion Types
2656
+ * Current-scope achievement with computed status and window metadata
2252
2657
  */
2253
- declare const ACHIEVEMENT_COMPLETION_TYPES: readonly ["time_played_session", "interaction", "leaderboard_rank"];
2254
- type AchievementCompletionType = (typeof ACHIEVEMENT_COMPLETION_TYPES)[number];
2658
+ interface AchievementCurrent {
2659
+ id: string;
2660
+ title: string;
2661
+ description?: string | null;
2662
+ scope: AchievementScopeType;
2663
+ rewardCredits: number;
2664
+ limit: number;
2665
+ completionType: AchievementCompletionType;
2666
+ completionConfig: Record<string, unknown>;
2667
+ target: Record<string, unknown>;
2668
+ active: boolean;
2669
+ createdAt?: Date;
2670
+ updatedAt?: Date;
2671
+ status: 'available' | 'completed';
2672
+ scopeKey: string;
2673
+ windowStart: string;
2674
+ windowEnd: string;
2675
+ }
2676
+ /**
2677
+ * Achievement claim history entry
2678
+ * Used in GET /api/achievements/history
2679
+ */
2680
+ interface AchievementHistoryEntry {
2681
+ achievementId: string;
2682
+ title: string;
2683
+ rewardCredits: number;
2684
+ createdAt: string;
2685
+ scopeKey: string;
2686
+ }
2687
+ /**
2688
+ * Achievement progress submission response
2689
+ * Used in POST /api/achievements/progress
2690
+ */
2691
+ interface AchievementProgressResponse {
2692
+ achievementId: string;
2693
+ status: 'completed' | 'already_completed';
2694
+ rewardCredits: number;
2695
+ scopeKey: string;
2696
+ createdAt: string;
2697
+ }
2698
+
2699
+ declare enum NotificationType {
2700
+ ACHIEVEMENT = "achievement",
2701
+ SYSTEM = "system",
2702
+ PROMO = "promo"
2703
+ }
2704
+ declare enum NotificationStatus {
2705
+ PENDING = "pending",
2706
+ DELIVERED = "delivered",
2707
+ SEEN = "seen",
2708
+ CLICKED = "clicked",
2709
+ DISMISSED = "dismissed",
2710
+ EXPIRED = "expired"
2711
+ }
2712
+ type Notification = InferSelectModel<typeof notifications>;
2713
+ interface NotificationStats {
2714
+ total: number;
2715
+ delivered: number;
2716
+ seen: number;
2717
+ clicked: number;
2718
+ dismissed: number;
2719
+ expired: number;
2720
+ clickThroughRate: number;
2721
+ }
2255
2722
 
2256
2723
  type CharacterComponent = typeof characterComponents.$inferSelect;
2257
2724
  type PlayerCharacter = typeof playerCharacters.$inferSelect & {
@@ -2273,6 +2740,17 @@ type ExternalGame = BaseGame & {
2273
2740
  type Game = HostedGame | ExternalGame;
2274
2741
  type GameStateData = Record<string, unknown>;
2275
2742
  type UpsertGameMetadataInput = z.infer<typeof UpsertGameMetadataSchema>;
2743
+ /**
2744
+ * Response from backend deployment API
2745
+ */
2746
+ interface BackendDeploymentResponse {
2747
+ /** Unique deployment ID */
2748
+ deploymentId: string;
2749
+ /** Backend API URL */
2750
+ url: string;
2751
+ /** Deployment timestamp */
2752
+ deployedAt: string;
2753
+ }
2276
2754
  type Item = typeof items.$inferSelect;
2277
2755
  type InventoryItem = typeof inventoryItems.$inferSelect;
2278
2756
  type ShopListing = typeof shopListings.$inferSelect;
@@ -2341,6 +2819,8 @@ interface UserInfo {
2341
2819
  given_name?: string;
2342
2820
  /** Optional family name (last name) */
2343
2821
  family_name?: string;
2822
+ /** TimeBack student ID (if user has TimeBack integration) */
2823
+ timeback_id?: string;
2344
2824
  /** Additional user attributes from the identity provider */
2345
2825
  [key: string]: unknown;
2346
2826
  }
@@ -2527,6 +3007,7 @@ interface SpriteTemplateData {
2527
3007
  };
2528
3008
  };
2529
3009
  }
3010
+ type GameTimebackIntegration = typeof gameTimebackIntegrations.$inferSelect;
2530
3011
  type TodayXpResponse = {
2531
3012
  xp: number;
2532
3013
  date: string;
@@ -2540,49 +3021,158 @@ type XpHistoryResponse = {
2540
3021
  xp: number;
2541
3022
  }>;
2542
3023
  };
2543
-
2544
- type AchievementIntervalType = (typeof achievementIntervalEnum.enumValues)[number];
2545
- /**
2546
- * Current-interval achievement with computed status and window metadata
2547
- */
2548
- interface AchievementCurrent {
2549
- id: string;
2550
- title: string;
2551
- description?: string | null;
2552
- intervalType: AchievementIntervalType;
2553
- rewardCredits: number;
2554
- limitPerInterval: number;
2555
- completionType: AchievementCompletionType;
2556
- completionConfig: Record<string, unknown>;
2557
- scope: Record<string, unknown>;
2558
- active: boolean;
2559
- createdAt?: Date;
2560
- updatedAt?: Date;
2561
- status: 'available' | 'completed';
2562
- intervalKey: string;
2563
- windowStart: string;
2564
- windowEnd: string;
2565
- }
2566
- /**
2567
- * Historical entry representing a prior claim within an interval
2568
- */
2569
- interface AchievementHistoryEntry {
2570
- achievementId: string;
2571
- title: string;
2572
- rewardCredits: number;
2573
- createdAt: string;
2574
- intervalKey: string;
2575
- }
2576
- /**
2577
- * Response returned when submitting achievement progress
2578
- */
2579
- interface AchievementProgressResponse {
2580
- achievementId: string;
2581
- status: 'completed' | 'already_completed';
2582
- rewardCredits: number;
2583
- intervalKey: string;
2584
- createdAt: string;
2585
- }
3024
+ type TimebackSubject = 'Reading' | 'Language' | 'Vocabulary' | 'Social Studies' | 'Writing' | 'Science' | 'FastMath' | 'Math' | 'None';
3025
+ type TimebackSetupRequest = {
3026
+ gameId: string;
3027
+ config: {
3028
+ organization: {
3029
+ name: string;
3030
+ type: string;
3031
+ identifier: string;
3032
+ };
3033
+ course: {
3034
+ title: string;
3035
+ subjects: string[];
3036
+ grades: number[];
3037
+ courseCode: string;
3038
+ level: string;
3039
+ gradingScheme: string;
3040
+ metadata?: Record<string, unknown>;
3041
+ };
3042
+ component: {
3043
+ title: string;
3044
+ sortOrder: number;
3045
+ prerequisites: string[];
3046
+ prerequisiteCriteria: string;
3047
+ };
3048
+ resource: {
3049
+ title: string;
3050
+ vendorResourceId: string;
3051
+ vendorId: string;
3052
+ applicationId: string;
3053
+ roles: string[];
3054
+ importance: string;
3055
+ metadata: {
3056
+ type?: string;
3057
+ launchUrl?: string;
3058
+ toolProvider?: string;
3059
+ instructionalMethod?: string;
3060
+ subject?: string;
3061
+ grades?: number[];
3062
+ language?: string;
3063
+ xp?: number;
3064
+ [key: string]: unknown;
3065
+ };
3066
+ };
3067
+ componentResource: {
3068
+ title: string;
3069
+ sortOrder: number;
3070
+ lessonType: string | null;
3071
+ };
3072
+ };
3073
+ verbose?: boolean;
3074
+ };
3075
+ type TimebackSetupResponse = {
3076
+ integration: GameTimebackIntegration;
3077
+ courseId: string;
3078
+ verbose?: {
3079
+ course: unknown;
3080
+ component: unknown;
3081
+ resource: unknown;
3082
+ componentResource: unknown;
3083
+ };
3084
+ };
3085
+ type TimebackVerifyResponse = {
3086
+ status: 'success' | 'error';
3087
+ integration: GameTimebackIntegration;
3088
+ resources: {
3089
+ course: {
3090
+ found: boolean;
3091
+ data?: unknown;
3092
+ };
3093
+ component: {
3094
+ found: boolean;
3095
+ data?: unknown;
3096
+ };
3097
+ resource: {
3098
+ found: boolean;
3099
+ data?: unknown;
3100
+ };
3101
+ componentResource: {
3102
+ found: boolean;
3103
+ data?: unknown;
3104
+ };
3105
+ };
3106
+ errors?: string[];
3107
+ };
3108
+ type RecordProgressRequest = {
3109
+ gameId: string;
3110
+ studentId: string;
3111
+ progressData: {
3112
+ sensorUrl?: string;
3113
+ subject?: TimebackSubject;
3114
+ appName?: string;
3115
+ score?: number;
3116
+ totalQuestions?: number;
3117
+ correctQuestions?: number;
3118
+ xpEarned?: number;
3119
+ masteredUnits?: number;
3120
+ attemptNumber?: number;
3121
+ activityId?: string;
3122
+ activityName?: string;
3123
+ courseId?: string;
3124
+ classId?: string;
3125
+ courseName?: string;
3126
+ studentEmail?: string;
3127
+ };
3128
+ };
3129
+ type RecordProgressResponse = {
3130
+ status: 'ok';
3131
+ courseId: string;
3132
+ };
3133
+ type RecordSessionEndRequest = {
3134
+ gameId: string;
3135
+ studentId: string;
3136
+ sessionData: {
3137
+ sensorUrl?: string;
3138
+ subject?: TimebackSubject;
3139
+ appName?: string;
3140
+ activeTimeSeconds: number;
3141
+ inactiveTimeSeconds?: number;
3142
+ wasteTimeSeconds?: number;
3143
+ activityId?: string;
3144
+ activityName?: string;
3145
+ courseId?: string;
3146
+ courseName?: string;
3147
+ studentEmail?: string;
3148
+ };
3149
+ };
3150
+ type RecordSessionEndResponse = {
3151
+ status: 'ok';
3152
+ courseId: string;
3153
+ };
3154
+ type AwardXpRequest = {
3155
+ gameId: string;
3156
+ studentId: string;
3157
+ xpAmount: number;
3158
+ metadata: {
3159
+ sensorUrl: string;
3160
+ subject: TimebackSubject;
3161
+ appName: string;
3162
+ reason: string;
3163
+ activityId?: string;
3164
+ activityName?: string;
3165
+ courseId?: string;
3166
+ courseName?: string;
3167
+ studentEmail?: string;
3168
+ bonusType?: string;
3169
+ };
3170
+ };
3171
+ type AwardXpResponse = {
3172
+ status: 'ok';
3173
+ courseId: string;
3174
+ xpAwarded: number;
3175
+ };
2586
3176
 
2587
3177
  /**
2588
3178
  * SDK Constants
@@ -2602,9 +3192,81 @@ declare const AuthProvider: {
2602
3192
  readonly TIMEBACK: "TIMEBACK";
2603
3193
  };
2604
3194
 
3195
+ /**
3196
+ * @fileoverview Server SDK Type Definitions
3197
+ *
3198
+ * TypeScript type definitions for the server-side Playcademy SDK.
3199
+ * Includes configuration types, client state, and re-exported TimeBack types.
3200
+ */
3201
+
3202
+ /**
3203
+ * TimeBack integration configuration for Playcademy config file
3204
+ */
3205
+ interface TimebackIntegrationConfig {
3206
+ /** Organization overrides */
3207
+ organization?: Partial<OrganizationConfig>;
3208
+ /** Course configuration (subjects and grades REQUIRED) */
3209
+ course: CourseConfig;
3210
+ /** Component overrides */
3211
+ component?: Partial<ComponentConfig>;
3212
+ /** Resource overrides */
3213
+ resource?: Partial<ResourceConfig>;
3214
+ /** Component-Resource link overrides */
3215
+ componentResource?: Partial<ComponentResourceConfig>;
3216
+ }
3217
+ /**
3218
+ * Integrations configuration
3219
+ */
3220
+ interface IntegrationsConfig {
3221
+ /** TimeBack integration (optional) */
3222
+ timeback?: TimebackIntegrationConfig;
3223
+ }
3224
+ /**
3225
+ * Unified Playcademy configuration
3226
+ * Used for playcademy.config.{js,json}
3227
+ */
3228
+ interface PlaycademyConfig {
3229
+ /** Game name */
3230
+ name: string;
3231
+ /** Game description */
3232
+ description?: string;
3233
+ /** Game emoji icon */
3234
+ emoji?: string;
3235
+ /** Build command to run before deployment */
3236
+ buildCommand?: string[];
3237
+ /** Path to build output */
3238
+ buildPath?: string;
3239
+ /** Game type */
3240
+ gameType?: 'hosted' | 'external';
3241
+ /** External URL (for external games) */
3242
+ externalUrl?: string;
3243
+ /** Game platform */
3244
+ platform?: 'web' | 'unity' | 'godot';
3245
+ /** Backend configuration */
3246
+ backend?: {
3247
+ /** Custom API routes directory (defaults to 'api') */
3248
+ directory?: string;
3249
+ };
3250
+ /** External integrations */
3251
+ integrations?: IntegrationsConfig;
3252
+ }
3253
+
3254
+ /**
3255
+ * Backend deployment bundle for uploading to Playcademy platform
3256
+ */
3257
+ interface BackendDeploymentBundle {
3258
+ /** Bundled JavaScript code ready for deployment */
3259
+ code: string;
3260
+ /** Game configuration */
3261
+ config: PlaycademyConfig;
3262
+ }
3263
+
3264
+ type TokenType = 'session' | 'apiKey' | 'gameJwt';
2605
3265
  interface ClientConfig {
2606
3266
  baseUrl: string;
3267
+ gameUrl?: string;
2607
3268
  token?: string;
3269
+ tokenType?: TokenType;
2608
3270
  gameId?: string;
2609
3271
  autoStartSession?: boolean;
2610
3272
  }
@@ -2767,6 +3429,32 @@ type DevUploadHooks = {
2767
3429
  onEvent?: (e: DevUploadEvent) => void;
2768
3430
  onClose?: () => void;
2769
3431
  };
3432
+ /**
3433
+ * Better-auth API key creation response
3434
+ */
3435
+ interface BetterAuthApiKeyResponse {
3436
+ apiKey: string;
3437
+ key: {
3438
+ id: string;
3439
+ name: string | null;
3440
+ expiresAt: string | null;
3441
+ createdAt: string;
3442
+ };
3443
+ }
3444
+ /**
3445
+ * Better-auth API key list item
3446
+ */
3447
+ interface BetterAuthApiKey {
3448
+ id: string;
3449
+ name: string | null;
3450
+ start: string;
3451
+ enabled: boolean;
3452
+ expiresAt: string | null;
3453
+ createdAt: string;
3454
+ updatedAt: string;
3455
+ lastRequest: string | null;
3456
+ requestCount: number;
3457
+ }
2770
3458
 
2771
3459
  /**
2772
3460
  * OAuth 2.0 implementation for the Playcademy SDK
@@ -2934,8 +3622,9 @@ type Method = 'GET' | 'POST' | 'PUT' | 'PATCH' | 'DELETE';
2934
3622
  * Provides namespaced access to all platform features including games, users, inventory, and more.
2935
3623
  */
2936
3624
  declare class PlaycademyClient {
2937
- private baseUrl;
2938
- private token?;
3625
+ baseUrl: string;
3626
+ gameUrl?: string;
3627
+ private authStrategy;
2939
3628
  private gameId?;
2940
3629
  private config;
2941
3630
  private listeners;
@@ -2946,8 +3635,9 @@ declare class PlaycademyClient {
2946
3635
  * Creates a new PlaycademyClient instance.
2947
3636
  *
2948
3637
  * @param config - Optional configuration object
2949
- * @param config.baseUrl - Base URL for API requests (defaults to '/api')
3638
+ * @param config.baseUrl - Base URL (e.g., 'https://hub.playcademy.com' or '/'). SDK automatically appends /api
2950
3639
  * @param config.token - Authentication token
3640
+ * @param config.tokenType - Optional token type (auto-detected if not provided)
2951
3641
  * @param config.gameId - Game ID for automatic session management
2952
3642
  * @param config.autoStartSession - Automatically start a game session?
2953
3643
  */
@@ -2955,10 +3645,19 @@ declare class PlaycademyClient {
2955
3645
  /**
2956
3646
  * Gets the effective base URL for API requests.
2957
3647
  * Converts relative URLs to absolute URLs in browser environments.
3648
+ * Note: baseUrl already includes /api suffix from constructor.
2958
3649
  *
2959
- * @returns The complete base URL for API requests
3650
+ * @returns The complete base URL for API requests (with /api suffix)
2960
3651
  */
2961
3652
  getBaseUrl(): string;
3653
+ /**
3654
+ * Gets the effective game backend URL for integration requests.
3655
+ * Throws if gameUrl is not configured.
3656
+ *
3657
+ * @returns The complete game backend URL for API requests (with /api suffix)
3658
+ * @throws PlaycademyError if gameUrl is not set
3659
+ */
3660
+ private getGameBackendUrl;
2962
3661
  /**
2963
3662
  * Simple ping method for testing connectivity.
2964
3663
  *
@@ -2970,8 +3669,15 @@ declare class PlaycademyClient {
2970
3669
  * Emits an 'authChange' event when the token changes.
2971
3670
  *
2972
3671
  * @param token - The authentication token, or null to clear
3672
+ * @param tokenType - Optional token type (auto-detected if not provided)
2973
3673
  */
2974
- setToken(token: string | null): void;
3674
+ setToken(token: string | null, tokenType?: TokenType): void;
3675
+ /**
3676
+ * Gets the current token type.
3677
+ *
3678
+ * @returns The token type
3679
+ */
3680
+ getTokenType(): TokenType;
2975
3681
  /**
2976
3682
  * Gets the current authentication token.
2977
3683
  *
@@ -3039,7 +3745,7 @@ declare class PlaycademyClient {
3039
3745
  */
3040
3746
  private emit;
3041
3747
  /**
3042
- * Makes an authenticated HTTP request to the API.
3748
+ * Makes an authenticated HTTP request to the platform API.
3043
3749
  *
3044
3750
  * @param path - API endpoint path
3045
3751
  * @param method - HTTP method
@@ -3048,6 +3754,17 @@ declare class PlaycademyClient {
3048
3754
  * @returns Promise resolving to the response data
3049
3755
  */
3050
3756
  protected request<T>(path: string, method: Method, body?: unknown, headers?: Record<string, string>): Promise<T>;
3757
+ /**
3758
+ * Makes an authenticated HTTP request to the game's backend Worker.
3759
+ * Uses gameUrl if set, otherwise falls back to platform API.
3760
+ *
3761
+ * @param path - API endpoint path
3762
+ * @param method - HTTP method
3763
+ * @param body - Request body (optional)
3764
+ * @param headers - Additional headers (optional)
3765
+ * @returns Promise resolving to the response data
3766
+ */
3767
+ protected requestGameBackend<T>(path: string, method: Method, body?: unknown, headers?: Record<string, string>): Promise<T>;
3051
3768
  /**
3052
3769
  * Ensures a gameId is available, throwing an error if not.
3053
3770
  *
@@ -3076,9 +3793,23 @@ declare class PlaycademyClient {
3076
3793
  }) => Promise<{
3077
3794
  success: boolean;
3078
3795
  token?: string;
3796
+ user?: {
3797
+ id: string;
3798
+ email: string;
3799
+ };
3800
+ expiresAt?: string;
3079
3801
  error?: string;
3080
3802
  }>;
3081
3803
  logout: () => Promise<void>;
3804
+ apiKeys: {
3805
+ create: (options?: {
3806
+ name?: string;
3807
+ expiresIn?: number | null;
3808
+ permissions?: Record<string, string[]>;
3809
+ }) => Promise<BetterAuthApiKeyResponse>;
3810
+ list: () => Promise<BetterAuthApiKey[]>;
3811
+ revoke: (keyId: string) => Promise<void>;
3812
+ };
3082
3813
  };
3083
3814
  /** Identity provider connection methods (connect external accounts) */
3084
3815
  identity: {
@@ -3129,7 +3860,7 @@ declare class PlaycademyClient {
3129
3860
  };
3130
3861
  leaderboard: {
3131
3862
  get: (gameId: string, options?: {
3132
- limit? /** Runtime methods (getGameToken, exit) */: number;
3863
+ limit?: number;
3133
3864
  offset?: number;
3134
3865
  }) => Promise<LeaderboardEntry[]>;
3135
3866
  };
@@ -3161,27 +3892,13 @@ declare class PlaycademyClient {
3161
3892
  get: () => Promise<DeveloperStatusValue>;
3162
3893
  };
3163
3894
  games: {
3164
- upsert: (slug: string, metadata: UpsertGameMetadataInput, file: File | Blob | null, hooks?: DevUploadHooks) => Promise<Game>;
3165
- update: (gameId: string, props: Partial<Game>) => Promise<void>;
3895
+ deploy: {
3896
+ frontend: (slug: string, metadata: UpsertGameMetadataInput, file: File | Blob | null, hooks?: DevUploadHooks) => Promise<Game>;
3897
+ backend: (slug: string, bundle: BackendDeploymentBundle) => Promise<BackendDeploymentResponse>;
3898
+ };
3899
+ upsert: (slug: string, metadata: UpsertGameMetadataInput) => Promise<Game>;
3166
3900
  delete: (gameId: string) => Promise<void>;
3167
3901
  };
3168
- keys: {
3169
- create: (label?: string) => Promise<{
3170
- id: string;
3171
- createdAt: Date;
3172
- userId: string;
3173
- label: string | null;
3174
- keyHash: string;
3175
- }>;
3176
- list: () => Promise<{
3177
- id: string;
3178
- createdAt: Date;
3179
- userId: string;
3180
- label: string | null;
3181
- keyHash: string;
3182
- }[]>;
3183
- revoke: (keyId: string) => Promise<void>;
3184
- };
3185
3902
  items: {
3186
3903
  create: (gameId: string, slug: string, itemData: Omit<InsertItemInput, "slug" | "gameId">) => Promise<Item>;
3187
3904
  update: (gameId: string, itemId: string, updates: UpdateItemInput) => Promise<Item>;
@@ -3201,8 +3918,8 @@ declare class PlaycademyClient {
3201
3918
  };
3202
3919
  /** Map methods (elements) */
3203
3920
  maps: {
3204
- get: (identifier: string) => Promise<MapData>;
3205
- elements: (mapId: string) => Promise<MapElementWithGame[]>;
3921
+ get: (identifier: string, options?: TTLCacheConfig) => Promise<MapData>;
3922
+ elements: (mapId: string, options?: TTLCacheConfig) => Promise<MapElementWithGame[]>;
3206
3923
  objects: {
3207
3924
  list: (mapId: string) => Promise<MapObjectWithItem[]>;
3208
3925
  create: (mapId: string, objectData: CreateMapObjectData) => Promise<MapObjectWithItem>;
@@ -3377,6 +4094,16 @@ declare class PlaycademyClient {
3377
4094
  };
3378
4095
  /** TimeBack XP methods (today, total, history) */
3379
4096
  timeback: {
4097
+ recordProgress: (progressData: RecordProgressRequest["progressData"]) => Promise<RecordProgressResponse>;
4098
+ recordSessionEnd: (sessionData: RecordSessionEndRequest["sessionData"]) => Promise<RecordSessionEndResponse>;
4099
+ awardXP: (xpAmount: number, metadata: AwardXpRequest["metadata"]) => Promise<AwardXpResponse>;
4100
+ management: {
4101
+ setup: (request: TimebackSetupRequest) => Promise<TimebackSetupResponse>;
4102
+ verify: (gameId: string) => Promise<TimebackVerifyResponse>;
4103
+ cleanup: (gameId: string) => Promise<void>;
4104
+ get: (gameId: string) => Promise<GameTimebackIntegration | null>;
4105
+ getConfig: (gameId: string) => Promise<TimebackSetupRequest["config"]>;
4106
+ };
3380
4107
  xp: {
3381
4108
  today: (options?: {
3382
4109
  date?: string;
@@ -3458,6 +4185,33 @@ declare class PlaycademyClient {
3458
4185
  submit: (achievementId: string) => Promise<AchievementProgressResponse>;
3459
4186
  };
3460
4187
  };
4188
+ /** Notifications methods (list, update status, stats) */
4189
+ notifications: {
4190
+ list: (queryOptions?: {
4191
+ status?: NotificationStatus;
4192
+ type?: NotificationType;
4193
+ limit?: number;
4194
+ offset?: number;
4195
+ }, cacheOptions?: TTLCacheConfig) => Promise<Notification[]>;
4196
+ markAsSeen: (notificationId: string) => Promise<Notification>;
4197
+ markAsClicked: (notificationId: string) => Promise<Notification>;
4198
+ dismiss: (notificationId: string) => Promise<Notification>;
4199
+ stats: {
4200
+ get: (queryOptions?: {
4201
+ from?: string;
4202
+ to?: string;
4203
+ }, cacheOptions?: TTLCacheConfig) => Promise<NotificationStats>;
4204
+ };
4205
+ };
4206
+ /** Backend methods for calling custom game API routes */
4207
+ backend: {
4208
+ get<T = unknown>(path: string, headers?: Record<string, string>): Promise<T>;
4209
+ post<T = unknown>(path: string, body?: unknown, headers?: Record<string, string>): Promise<T>;
4210
+ put<T = unknown>(path: string, body?: unknown, headers?: Record<string, string>): Promise<T>;
4211
+ patch<T = unknown>(path: string, body?: unknown, headers?: Record<string, string>): Promise<T>;
4212
+ delete<T = unknown>(path: string, headers?: Record<string, string>): Promise<T>;
4213
+ request<T = unknown>(path: string, method: Method, body?: unknown, headers?: Record<string, string>): Promise<T>;
4214
+ };
3461
4215
  /** Auto-initializes a PlaycademyClient with context from the environment */
3462
4216
  static init: typeof init;
3463
4217
  /** Authenticates a user with email and password */