@playcademy/sdk 0.9.1-beta.1 → 0.9.1-beta.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/types.d.ts CHANGED
@@ -26,101 +26,374 @@ interface RetryPolicy {
26
26
  }
27
27
 
28
28
  /**
29
- * TimeBack Enums & Literal Types
29
+ * User Types
30
30
  *
31
- * Basic type definitions used throughout the TimeBack integration.
31
+ * Enums, DTOs and API response types. Database row types are in @playcademy/data/types.
32
32
  *
33
- * @module types/timeback/types
34
- */
35
- /**
36
- * Valid TimeBack subject values for course configuration.
37
- * These are the supported subject values for OneRoster courses.
38
- */
39
- type TimebackSubject = 'Reading' | 'Language' | 'Vocabulary' | 'Social Studies' | 'Writing' | 'Science' | 'FastMath' | 'Math' | 'None';
40
- /**
41
- * Grade levels per AE OneRoster GradeEnum.
42
- * -1 = Pre-K, 0 = Kindergarten, 1-12 = Grades 1-12, 13 = AP
33
+ * @module types/user
43
34
  */
44
- type TimebackGrade = -1 | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13;
35
+
36
+ type UserRoleEnumType = UserRole;
37
+ type DeveloperStatusEnumType = 'none' | 'pending' | 'approved';
38
+ type DeveloperStatusValue = DeveloperStatusEnumType;
39
+ type TimebackUserRole = 'administrator' | 'aide' | 'guardian' | 'parent' | 'proctor' | 'relative' | 'student' | 'teacher';
40
+ type TimebackOrgType = 'department' | 'school' | 'district' | 'local' | 'state' | 'national';
41
+ interface UserEnrollment {
42
+ gameId?: string;
43
+ courseId: string;
44
+ enrollmentIds?: {
45
+ active: string;
46
+ inactive?: string[];
47
+ };
48
+ grade: number;
49
+ subject: string;
50
+ orgId?: string;
51
+ }
52
+ interface UserOrganization {
53
+ id: string;
54
+ name: string | null;
55
+ type: TimebackOrgType | string;
56
+ isPrimary: boolean;
57
+ }
58
+ interface TimebackStudentProfile {
59
+ role: TimebackUserRole;
60
+ organizations: UserOrganization[];
61
+ }
62
+ interface UserTimebackData extends TimebackStudentProfile {
63
+ id: string;
64
+ enrollments: UserEnrollment[];
65
+ }
45
66
  /**
46
- * Valid Caliper subject values.
47
- * Matches OneRoster subjects, with "None" as a Caliper-specific fallback.
67
+ * OpenID Connect UserInfo claims (NOT a database row).
48
68
  */
49
- type CaliperSubject = 'Reading' | 'Language' | 'Vocabulary' | 'Social Studies' | 'Writing' | 'Science' | 'FastMath' | 'Math' | 'None';
69
+ interface UserInfo {
70
+ sub: string;
71
+ email: string;
72
+ name: string | null;
73
+ email_verified?: boolean;
74
+ given_name?: string;
75
+ family_name?: string;
76
+ issuer?: string;
77
+ lti_roles?: unknown;
78
+ lti_context?: unknown;
79
+ lti_resource_link?: unknown;
80
+ timeback_id?: string;
81
+ }
82
+ interface DeveloperStatusResponse {
83
+ status: DeveloperStatusEnumType;
84
+ }
85
+ interface DemoProfile {
86
+ displayName: string;
87
+ isDefault: boolean;
88
+ }
50
89
  /**
51
- * OneRoster organization types.
90
+ * Update shape for `client.demo.profile.update(...)`.
91
+ *
92
+ * Kept as a named type so callers typed against it pick up new fields
93
+ * automatically, but `displayName` is the only updatable field today and
94
+ * the server's `DemoProfileSchema` requires it — a no-field payload would
95
+ * 400 at runtime, so we model that at the type level too. When additional
96
+ * fields land, make them required/optional individually based on server
97
+ * validation, rather than blanket-optional.
52
98
  */
53
- type OrganizationType = 'department' | 'school' | 'district' | 'local' | 'state' | 'national';
99
+ interface DemoProfileUpdate {
100
+ displayName: string;
101
+ }
54
102
  /**
55
- * Lesson types for PowerPath integration.
103
+ * Authenticated user for API responses.
104
+ * Differs from UserRow: omits timebackId, adds hasTimebackAccount and timeback.
56
105
  */
57
- type LessonType = 'powerpath-100' | 'quiz' | 'test-out' | 'placement' | 'unit-test' | 'alpha-read-article' | null;
106
+ interface AuthenticatedUser {
107
+ id: string;
108
+ email: string;
109
+ emailVerified: boolean;
110
+ name: string | null;
111
+ image: string | null;
112
+ username: string | null;
113
+ role: UserRoleEnumType;
114
+ developerStatus: DeveloperStatusEnumType;
115
+ characterCreated: boolean;
116
+ createdAt: Date;
117
+ updatedAt: Date;
118
+ hasTimebackAccount: boolean;
119
+ timeback?: UserTimebackData;
120
+ }
121
+ interface GameUser {
122
+ id: string;
123
+ name: string | null;
124
+ role: UserRoleEnumType;
125
+ username: string | null;
126
+ email: string | null;
127
+ timeback?: UserTimebackData;
128
+ }
58
129
 
59
130
  /**
60
- * TimeBack Configuration Types
131
+ * Game Types
61
132
  *
62
- * Configuration interfaces for Organization, Course, Component,
63
- * Resource, and complete TimeBack setup.
133
+ * Literal types and API DTOs. Database row types are in @playcademy/data/types.
64
134
  *
65
- * @module types/timeback/config
135
+ * @module types/game
66
136
  */
67
137
 
138
+ type GameType = 'hosted' | 'external';
139
+ type GamePlatform = 'web' | 'godot' | 'unity' | (string & {});
68
140
  /**
69
- * Organization configuration for TimeBack (user input - optionals allowed)
141
+ * Game manifest file format (manifest.json).
142
+ * Note: createdAt is a string here because it's parsed from JSON file.
70
143
  */
71
- interface OrganizationConfig {
72
- /** Display name for your organization */
73
- name?: string;
74
- /** Organization type */
75
- type?: OrganizationType;
76
- /** Unique identifier (defaults to Playcademy's org) */
77
- identifier?: string;
144
+ interface ManifestV1 {
145
+ version: '1';
146
+ platform: string;
147
+ createdAt: string;
148
+ }
149
+ interface ManifestVersions {
150
+ vitePlugin?: string;
151
+ sdk?: string;
152
+ cli?: string;
153
+ vite?: string;
154
+ godotSdk?: string;
155
+ godot?: string;
156
+ }
157
+ interface ManifestV2 {
158
+ version: '2';
159
+ platform: string;
160
+ createdAt: string;
161
+ versions: ManifestVersions;
162
+ }
163
+ type GameManifest = ManifestV1 | ManifestV2;
164
+ interface DomainValidationRecords {
165
+ ownership?: {
166
+ name?: string;
167
+ value?: string;
168
+ type?: string;
169
+ };
170
+ ssl?: {
171
+ txt_name?: string;
172
+ txt_value?: string;
173
+ }[];
78
174
  }
175
+
79
176
  /**
80
- * Course goals for daily student targets
177
+ * Leaderboard Types
178
+ *
179
+ * @module types/leaderboard
81
180
  */
82
- interface CourseGoals {
83
- /** Target XP students should earn per day */
84
- dailyXp?: number;
85
- /** Target lessons per day */
86
- dailyLessons?: number;
87
- /** Target active minutes per day */
88
- dailyActiveMinutes?: number;
89
- /** Target accuracy percentage */
90
- dailyAccuracy?: number;
91
- /** Target mastered units per day */
92
- dailyMasteredUnits?: number;
181
+ type LeaderboardTimeframe = 'all_time' | 'monthly' | 'weekly' | 'daily';
182
+ interface LeaderboardOptions {
183
+ timeframe?: LeaderboardTimeframe;
184
+ limit?: number;
185
+ offset?: number;
186
+ gameId?: string;
187
+ }
188
+ interface LeaderboardEntry {
189
+ rank: number;
190
+ userId: string;
191
+ username: string;
192
+ userImage?: string | null;
193
+ score: number;
194
+ achievedAt: Date;
195
+ metadata?: Record<string, unknown>;
196
+ gameId?: string;
197
+ gameTitle?: string;
198
+ gameSlug?: string;
199
+ }
200
+ interface UserRank {
201
+ rank: number;
202
+ totalPlayers: number;
203
+ score: number;
204
+ percentile: number;
205
+ }
206
+ interface UserRankResponse {
207
+ rank: number;
208
+ score: number;
209
+ userId: string;
210
+ }
211
+ interface UserScore {
212
+ id: string;
213
+ score: number;
214
+ achievedAt: Date;
215
+ metadata?: Record<string, unknown>;
216
+ gameId: string;
217
+ gameTitle: string;
218
+ gameSlug: string;
93
219
  }
94
220
  /**
95
- * Course metrics and totals
221
+ * Leaderboard entry with required game context.
222
+ * Used when fetching leaderboards for a specific game.
96
223
  */
97
- interface CourseMetrics {
98
- /** Total XP available in the course */
99
- totalXp?: number;
100
- /** Total lessons/activities in the course */
101
- totalLessons?: number;
102
- /** Total number of grade levels covered by this course */
103
- totalGrades?: number;
104
- /** The type of course (e.g. 'optional', 'hole-filling', 'base') */
105
- courseType?: 'base' | 'hole-filling' | 'optional' | 'Base' | 'Hole-Filling' | 'Optional';
106
- /** Indicates whether the course is supplemental content */
107
- isSupplemental?: boolean;
224
+ interface GameLeaderboardEntry {
225
+ rank: number;
226
+ userId: string;
227
+ username: string;
228
+ userImage?: string | null;
229
+ score: number;
230
+ achievedAt: Date;
231
+ metadata?: Record<string, unknown>;
232
+ gameId: string;
233
+ gameTitle: string;
234
+ gameSlug: string;
108
235
  }
236
+
109
237
  /**
110
- * Complete course metadata structure
238
+ * Achievement Types
239
+ *
240
+ * @module types/achievement
111
241
  */
112
- interface CourseMetadata {
113
- /** Define the type of course and priority for the student */
114
- courseType?: 'base' | 'hole-filling' | 'optional';
115
- /** Boolean value to determine if a course is supplemental to a base course */
116
- isSupplemental?: boolean;
117
- /** Boolean value to determine if a course is custom to an individual student */
118
- isCustom?: boolean;
119
- /** Signals whether a course is in production with students */
120
- publishStatus?: 'draft' | 'testing' | 'published' | 'deactivated';
121
- /** Whether this course appears in the TimeBack catalog for teachers and parents */
122
- timebackVisible?: boolean;
123
- /** Who to contact when issues reported with questions */
242
+ type AchievementScopeType = 'daily' | 'weekly' | 'monthly' | 'yearly' | 'game' | 'global' | 'map' | 'level' | 'event';
243
+ declare enum AchievementCompletionType {
244
+ TIME_PLAYED_SESSION = "time_played_session",
245
+ INTERACTION = "interaction",
246
+ LEADERBOARD_RANK = "leaderboard_rank",
247
+ FIRST_SCORE = "first_score",
248
+ PERSONAL_BEST = "personal_best"
249
+ }
250
+ interface AchievementCurrent {
251
+ id: string;
252
+ title: string;
253
+ description?: string | null;
254
+ scope: AchievementScopeType;
255
+ rewardCredits: number;
256
+ limit: number;
257
+ completionType: string;
258
+ completionConfig: unknown;
259
+ target: unknown;
260
+ active: boolean;
261
+ createdAt?: Date | null;
262
+ updatedAt?: Date | null;
263
+ status: 'available' | 'completed';
264
+ scopeKey: string;
265
+ windowStart: string;
266
+ windowEnd: string;
267
+ }
268
+ interface AchievementWithStatus {
269
+ id: string;
270
+ title: string;
271
+ description: string | null;
272
+ scope: AchievementScopeType;
273
+ rewardCredits: number;
274
+ limit: number;
275
+ completionType: string;
276
+ completionConfig: unknown;
277
+ target: unknown;
278
+ active: boolean;
279
+ createdAt: Date | null;
280
+ updatedAt: Date | null;
281
+ status: 'available' | 'completed';
282
+ scopeKey: string;
283
+ windowStart?: string;
284
+ windowEnd?: string;
285
+ }
286
+ interface AchievementHistoryEntry {
287
+ achievementId: string;
288
+ title: string;
289
+ rewardCredits: number;
290
+ createdAt: Date;
291
+ scopeKey: string;
292
+ }
293
+ interface AchievementProgressResponse {
294
+ achievementId: string;
295
+ status: 'completed' | 'already_completed';
296
+ rewardCredits: number;
297
+ scopeKey: string;
298
+ createdAt: Date;
299
+ }
300
+
301
+ /**
302
+ * TimeBack Enums & Literal Types
303
+ *
304
+ * Basic type definitions used throughout the TimeBack integration.
305
+ *
306
+ * @module types/timeback/types
307
+ */
308
+ /**
309
+ * Valid TimeBack subject values for course configuration.
310
+ * These are the supported subject values for OneRoster courses.
311
+ */
312
+ type TimebackSubject = 'Reading' | 'Language' | 'Vocabulary' | 'Social Studies' | 'Writing' | 'Science' | 'FastMath' | 'Math' | 'None';
313
+ /**
314
+ * Grade levels per AE OneRoster GradeEnum.
315
+ * -1 = Pre-K, 0 = Kindergarten, 1-12 = Grades 1-12, 13 = AP
316
+ */
317
+ type TimebackGrade = -1 | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13;
318
+ /**
319
+ * Valid Caliper subject values.
320
+ * Matches OneRoster subjects, with "None" as a Caliper-specific fallback.
321
+ */
322
+ type CaliperSubject = 'Reading' | 'Language' | 'Vocabulary' | 'Social Studies' | 'Writing' | 'Science' | 'FastMath' | 'Math' | 'None';
323
+ /**
324
+ * OneRoster organization types.
325
+ */
326
+ type OrganizationType = 'department' | 'school' | 'district' | 'local' | 'state' | 'national';
327
+ /**
328
+ * Lesson types for PowerPath integration.
329
+ */
330
+ type LessonType = 'powerpath-100' | 'quiz' | 'test-out' | 'placement' | 'unit-test' | 'alpha-read-article' | null;
331
+
332
+ /**
333
+ * TimeBack Configuration Types
334
+ *
335
+ * Configuration interfaces for Organization, Course, Component,
336
+ * Resource, and complete TimeBack setup.
337
+ *
338
+ * @module types/timeback/config
339
+ */
340
+
341
+ /**
342
+ * Organization configuration for TimeBack (user input - optionals allowed)
343
+ */
344
+ interface OrganizationConfig {
345
+ /** Display name for your organization */
346
+ name?: string;
347
+ /** Organization type */
348
+ type?: OrganizationType;
349
+ /** Unique identifier (defaults to Playcademy's org) */
350
+ identifier?: string;
351
+ }
352
+ /**
353
+ * Course goals for daily student targets
354
+ */
355
+ interface CourseGoals {
356
+ /** Target XP students should earn per day */
357
+ dailyXp?: number;
358
+ /** Target lessons per day */
359
+ dailyLessons?: number;
360
+ /** Target active minutes per day */
361
+ dailyActiveMinutes?: number;
362
+ /** Target accuracy percentage */
363
+ dailyAccuracy?: number;
364
+ /** Target mastered units per day */
365
+ dailyMasteredUnits?: number;
366
+ }
367
+ /**
368
+ * Course metrics and totals
369
+ */
370
+ interface CourseMetrics {
371
+ /** Total XP available in the course */
372
+ totalXp?: number;
373
+ /** Total lessons/activities in the course */
374
+ totalLessons?: number;
375
+ /** Total number of grade levels covered by this course */
376
+ totalGrades?: number;
377
+ /** The type of course (e.g. 'optional', 'hole-filling', 'base') */
378
+ courseType?: 'base' | 'hole-filling' | 'optional' | 'Base' | 'Hole-Filling' | 'Optional';
379
+ /** Indicates whether the course is supplemental content */
380
+ isSupplemental?: boolean;
381
+ }
382
+ /**
383
+ * Complete course metadata structure
384
+ */
385
+ interface CourseMetadata {
386
+ /** Define the type of course and priority for the student */
387
+ courseType?: 'base' | 'hole-filling' | 'optional';
388
+ /** Boolean value to determine if a course is supplemental to a base course */
389
+ isSupplemental?: boolean;
390
+ /** Boolean value to determine if a course is custom to an individual student */
391
+ isCustom?: boolean;
392
+ /** Signals whether a course is in production with students */
393
+ publishStatus?: 'draft' | 'testing' | 'published' | 'deactivated';
394
+ /** Whether this course appears in the TimeBack catalog for teachers and parents */
395
+ timebackVisible?: boolean;
396
+ /** Who to contact when issues reported with questions */
124
397
  contactEmail?: string;
125
398
  /** Primary app identifier */
126
399
  primaryApp?: string;
@@ -451,726 +724,804 @@ type GameMetricsProxyResponse = {
451
724
  };
452
725
 
453
726
  /**
454
- * Cache configuration types for runtime customization
727
+ * Inventory & Shop Types
728
+ *
729
+ * Literal types for inventory system. Database row types are in @playcademy/data/types.
730
+ *
731
+ * @module types/inventory
455
732
  */
456
733
  /**
457
- * Runtime configuration for TTL cache behavior
734
+ * Item categories available on the platform.
458
735
  */
459
- interface TTLCacheConfig {
460
- /** Time-to-live in milliseconds. Set to 0 to disable caching for this call. */
461
- ttl?: number;
462
- /** Force refresh, bypassing cache */
463
- force?: boolean;
464
- /** Skip cache and fetch fresh data (alias for force) */
465
- skipCache?: boolean;
466
- }
736
+ type ItemType = 'currency' | 'badge' | 'trophy' | 'collectible' | 'consumable' | 'unlock' | 'upgrade' | 'accessory' | 'other';
467
737
 
468
738
  /**
469
- * @fileoverview Server SDK Type Definitions
739
+ * Map & Placement Types
470
740
  *
471
- * TypeScript type definitions for the server-side Playcademy SDK.
472
- * Includes configuration types, client state, and re-exported TimeBack types.
741
+ * Literal types and JSON shapes for maps. Database row types are in @playcademy/data/types.
742
+ *
743
+ * @module types/map
473
744
  */
474
-
475
745
  /**
476
- * Base configuration for TimeBack integration (shared across all courses).
477
- * References upstream TimeBack types from @playcademy/timeback.
478
- *
479
- * All fields are optional and support template variables: {grade}, {subject}, {gameSlug}
746
+ * Allowed map interaction types.
480
747
  */
481
- interface TimebackBaseConfig {
482
- /** Organization configuration (shared across all courses) */
483
- organization?: Partial<OrganizationConfig>;
484
- /** Course defaults (can be overridden per-course) */
485
- course?: Partial<CourseConfig>;
486
- /** Component defaults */
487
- component?: Partial<ComponentConfig>;
488
- /** Resource defaults */
489
- resource?: Partial<ResourceConfig>;
490
- /** ComponentResource defaults */
491
- componentResource?: Partial<ComponentResourceConfig>;
492
- }
748
+ type InteractionType = 'game_entry' | 'game_registry' | 'info' | 'teleport' | 'door_in' | 'door_out' | 'npc_interaction' | 'quest_trigger';
493
749
  /**
494
- * Extended course configuration that merges TimebackCourseConfig with per-course overrides.
495
- * Used in playcademy.config.* to allow per-course customization.
750
+ * Metadata for interactive map elements.
496
751
  */
497
- interface TimebackCourseConfigWithOverrides extends TimebackCourseConfig {
752
+ interface MapElementMetadata {
753
+ description?: string;
498
754
  title?: string;
499
- courseCode?: string;
500
- level?: string;
501
- metadata?: CourseConfig['metadata'];
502
- totalXp?: number | null;
503
- masterableUnits?: number | null;
755
+ targetMapIdentifier?: string;
756
+ targetSpawnTileX?: number;
757
+ targetSpawnTileY?: number;
758
+ sourceTiledObjects?: Record<string, unknown>[];
759
+ [key: string]: unknown;
504
760
  }
505
761
  /**
506
- * TimeBack integration configuration for Playcademy config file.
507
- *
508
- * Supports two levels of customization:
509
- * 1. `base`: Shared defaults for all courses (organization, course, component, resource, componentResource)
510
- * 2. Per-course overrides in the `courses` array (title, courseCode, level, gradingScheme, metadata)
511
- *
512
- * Template variables ({grade}, {subject}, {gameSlug}) can be used in string fields.
762
+ * Metadata describing how an item should be placed on the map.
513
763
  */
514
- interface TimebackIntegrationConfig {
515
- /** Multi-grade course configuration (array of grade/subject/totalXp with optional per-course overrides) */
516
- courses: TimebackCourseConfigWithOverrides[];
517
- /** Optional base configuration (shared across all courses, can be overridden per-course) */
518
- base?: TimebackBaseConfig;
764
+ interface PlaceableItemMetadata {
765
+ tilesWide?: number;
766
+ tilesHigh?: number;
767
+ flippable?: boolean;
768
+ [key: string]: unknown;
519
769
  }
520
770
  /**
521
- * Custom API routes integration
771
+ * Simplified map data for API responses.
522
772
  */
523
- interface CustomRoutesIntegration {
524
- /** Directory for custom API routes (defaults to 'server/api') */
525
- directory?: string;
773
+ interface MapData {
774
+ id: string;
775
+ identifier: string;
776
+ displayName: string;
777
+ description?: string | null;
778
+ metadata?: Record<string, unknown> | null;
526
779
  }
527
780
  /**
528
- * Database integration
781
+ * Input for creating a map object.
529
782
  */
530
- interface DatabaseIntegration {
531
- /** Database directory (defaults to 'db') */
532
- directory?: string;
533
- /** Schema strategy: 'push' uses drizzle-kit push-style diffing, 'migrate' uses migration files.
534
- * When omitted, auto-detects based on presence of a migrations directory with _journal.json. */
535
- strategy?: 'push' | 'migrate';
536
- }
537
- interface QueueConfig {
538
- maxBatchSize?: number;
539
- maxRetries?: number;
540
- maxBatchTimeout?: number;
541
- maxConcurrency?: number;
542
- retryDelay?: number;
543
- deadLetterQueue?: string;
783
+ interface CreateMapObjectData {
784
+ itemId: string;
785
+ worldX: number;
786
+ worldY: number;
787
+ width?: number;
788
+ height?: number;
789
+ rotation?: number;
790
+ scale?: number;
791
+ metadata?: Record<string, unknown>;
544
792
  }
793
+
545
794
  /**
546
- * Integrations configuration
547
- * All backend features (database, custom routes, external services) are configured here
795
+ * Character & Avatar Types
796
+ *
797
+ * Literal types for character system. Database row types are in @playcademy/data/types.
798
+ *
799
+ * @module types/character
548
800
  */
549
- interface IntegrationsConfig {
550
- /** TimeBack integration (optional) */
551
- timeback?: TimebackIntegrationConfig | null;
552
- /** Custom API routes (optional) */
553
- customRoutes?: CustomRoutesIntegration | boolean;
554
- /** Database (optional) */
555
- database?: DatabaseIntegration | boolean;
556
- /** Key-Value storage (optional) */
557
- kv?: boolean;
558
- /** Bucket storage (optional) */
559
- bucket?: boolean;
560
- /** Authentication (optional) */
561
- auth?: boolean;
562
- /** Queues (optional) */
563
- queues?: Record<string, QueueConfig | boolean>;
564
- }
565
801
  /**
566
- * Unified Playcademy configuration
567
- * Used for playcademy.config.{js,json}
802
+ * Character component categories.
568
803
  */
569
- interface PlaycademyConfig {
570
- /** Game name */
571
- name: string;
572
- /** Game description */
573
- description?: string;
574
- /** Game emoji icon */
575
- emoji?: string;
576
- /** Build command to run before deployment */
577
- buildCommand?: string[];
578
- /** Path to build output */
579
- buildPath?: string;
580
- /** Game type */
581
- gameType?: 'hosted' | 'external';
582
- /** External URL (for external games) */
583
- externalUrl?: string;
584
- /** Game platform */
585
- platform?: 'web' | 'unity' | 'godot';
586
- /** Integrations (database, custom routes, external services) */
587
- integrations?: IntegrationsConfig;
588
- }
804
+ type CharacterComponentType = 'body' | 'outfit' | 'hairstyle' | 'eyes' | 'accessory';
589
805
 
590
806
  /**
591
- * Configuration options for initializing a PlaycademyClient instance.
807
+ * Level & Progression Types
592
808
  *
593
- * @example
594
- * ```typescript
595
- * const config: PlaycademyServerClientConfig = {
596
- * apiKey: process.env.PLAYCADEMY_API_KEY!,
597
- * gameId: 'my-math-game',
598
- * configPath: './playcademy.config.js'
599
- * }
600
- * ```
809
+ * API response DTOs for level system. Database row types are in @playcademy/data/types.
810
+ *
811
+ * @module types/level
601
812
  */
602
- interface PlaycademyServerClientConfig {
603
- /**
604
- * Playcademy API key for server-to-server authentication.
605
- * Obtain from the Playcademy developer dashboard.
606
- */
607
- apiKey: string;
608
- /**
609
- * Optional path to playcademy.config.js file.
610
- * If not provided, searches current directory and up to 3 parent directories.
611
- * Ignored if `config` is provided directly.
612
- *
613
- * @example './config/playcademy.config.js'
614
- */
615
- configPath?: string;
616
- /**
617
- * Optional config object (for edge environments without filesystem).
618
- * If provided, skips filesystem-based config loading.
619
- *
620
- * @example { name: 'My Game', integrations: { timeback: {...} } }
621
- */
622
- config?: PlaycademyConfig;
623
- /**
624
- * Optional base URL for Playcademy API.
625
- * Defaults to environment variables or 'https://hub.playcademy.net'.
626
- *
627
- * @example 'http://localhost:3000' for local development
628
- */
629
- baseUrl?: string;
630
- /**
631
- * Optional game ID.
632
- * If not provided, will attempt to fetch from API using the API token.
633
- *
634
- * @example 'my-math-game'
635
- */
636
- gameId?: string;
813
+ /**
814
+ * Result of adding XP to a user.
815
+ */
816
+ interface XPAddResult {
817
+ totalXP: number;
818
+ newLevel: number;
819
+ leveledUp: boolean;
820
+ creditsAwarded: number;
821
+ xpToNextLevel: number;
637
822
  }
638
823
  /**
639
- * Internal state maintained by the PlaycademyClient instance.
640
- *
641
- * @internal
824
+ * Result of checking whether a level up occurred.
642
825
  */
643
- interface PlaycademyServerClientState {
644
- /** API key for authentication */
645
- apiKey: string;
646
- /** Base URL for API requests */
647
- baseUrl: string;
648
- /** Game identifier */
649
- gameId: string;
650
- /** Loaded game configuration from playcademy.config.js */
651
- config: PlaycademyConfig;
652
- /**
653
- * TimeBack course ID fetched from the Playcademy API.
654
- * Used for all TimeBack event recording.
655
- */
656
- courseId?: string;
826
+ interface LevelUpCheckResult {
827
+ newLevel: number;
828
+ remainingXp: number;
829
+ leveledUp: boolean;
830
+ creditsAwarded: number;
831
+ xpToNextLevel: number;
832
+ }
833
+ /**
834
+ * Level progress API response.
835
+ */
836
+ interface LevelProgressResponse {
837
+ level: number;
838
+ currentXp: number;
839
+ xpToNextLevel: number;
840
+ totalXP: number;
657
841
  }
658
842
 
659
843
  /**
660
- * User Types
661
- *
662
- * Enums, DTOs and API response types. Database row types are in @playcademy/data/types.
844
+ * Notification Types
663
845
  *
664
- * @module types/user
846
+ * @module types/notification
665
847
  */
666
848
 
667
- type UserRoleEnumType = UserRole;
668
- type DeveloperStatusEnumType = 'none' | 'pending' | 'approved';
669
- type DeveloperStatusValue = DeveloperStatusEnumType;
670
- type TimebackUserRole = 'administrator' | 'aide' | 'guardian' | 'parent' | 'proctor' | 'relative' | 'student' | 'teacher';
671
- type TimebackOrgType = 'department' | 'school' | 'district' | 'local' | 'state' | 'national';
672
- interface UserEnrollment {
673
- gameId?: string;
674
- courseId: string;
675
- enrollmentIds?: {
676
- active: string;
677
- inactive?: string[];
678
- };
679
- grade: number;
680
- subject: string;
681
- orgId?: string;
682
- }
683
- interface UserOrganization {
684
- id: string;
685
- name: string | null;
686
- type: TimebackOrgType | string;
687
- isPrimary: boolean;
849
+ declare enum NotificationType {
850
+ ACHIEVEMENT = "achievement",
851
+ SYSTEM = "system",
852
+ PROMO = "promo"
688
853
  }
689
- interface TimebackStudentProfile {
690
- role: TimebackUserRole;
691
- organizations: UserOrganization[];
854
+ declare enum NotificationStatus {
855
+ PENDING = "pending",
856
+ DELIVERED = "delivered",
857
+ SEEN = "seen",
858
+ CLICKED = "clicked",
859
+ DISMISSED = "dismissed",
860
+ EXPIRED = "expired"
692
861
  }
693
- interface UserTimebackData extends TimebackStudentProfile {
694
- id: string;
695
- enrollments: UserEnrollment[];
862
+ interface NotificationStats {
863
+ total: number;
864
+ delivered: number;
865
+ seen: number;
866
+ clicked: number;
867
+ dismissed: number;
868
+ expired: number;
869
+ clickThroughRate: number;
696
870
  }
871
+
697
872
  /**
698
- * OpenID Connect UserInfo claims (NOT a database row).
873
+ * Shop Types
874
+ *
875
+ * @module types/shop
699
876
  */
700
- interface UserInfo {
701
- sub: string;
702
- email: string;
703
- name: string | null;
704
- email_verified?: boolean;
705
- given_name?: string;
706
- family_name?: string;
707
- issuer?: string;
708
- lti_roles?: unknown;
709
- lti_context?: unknown;
710
- lti_resource_link?: unknown;
711
- timeback_id?: string;
712
- }
713
- interface DeveloperStatusResponse {
714
- status: DeveloperStatusEnumType;
715
- }
716
- interface DemoProfile {
717
- displayName: string;
718
- isDefault: boolean;
719
- }
720
877
  /**
721
- * Update shape for `client.demo.profile.update(...)`.
722
- *
723
- * Kept as a named type so callers typed against it pick up new fields
724
- * automatically, but `displayName` is the only updatable field today and
725
- * the server's `DemoProfileSchema` requires it — a no-field payload would
726
- * 400 at runtime, so we model that at the type level too. When additional
727
- * fields land, make them required/optional individually based on server
728
- * validation, rather than blanket-optional.
878
+ * Currency display info for shop UI.
729
879
  */
730
- interface DemoProfileUpdate {
731
- displayName: string;
880
+ interface ShopCurrency {
881
+ id: string;
882
+ symbol: string | null;
883
+ isPrimary: boolean;
884
+ displayName?: string | null;
885
+ imageUrl?: string | null;
732
886
  }
733
887
  /**
734
- * Authenticated user for API responses.
735
- * Differs from UserRow: omits timebackId, adds hasTimebackAccount and timeback.
888
+ * Shop item for display.
889
+ * Combines Item fields (excluding createdAt) with shop listing data.
736
890
  */
737
- interface AuthenticatedUser {
891
+ interface ShopDisplayItem {
738
892
  id: string;
739
- email: string;
740
- emailVerified: boolean;
741
- name: string | null;
742
- image: string | null;
743
- username: string | null;
744
- role: UserRoleEnumType;
745
- developerStatus: DeveloperStatusEnumType;
746
- characterCreated: boolean;
747
- createdAt: Date;
748
- updatedAt: Date;
749
- hasTimebackAccount: boolean;
750
- timeback?: UserTimebackData;
893
+ slug: string;
894
+ gameId?: string | null;
895
+ displayName: string;
896
+ description?: string | null;
897
+ type: string;
898
+ isPlaceable: boolean;
899
+ imageUrl?: string | null;
900
+ metadata?: unknown;
901
+ listingId: string;
902
+ shopPrice: number;
903
+ currencyId: string;
904
+ currencySymbol?: string | null;
905
+ currencyDisplayName?: string | null;
906
+ currencyImageUrl?: string | null;
907
+ stock?: number | null;
908
+ sellBackPercentage?: number | null;
751
909
  }
752
- interface GameUser {
753
- id: string;
754
- name: string | null;
755
- role: UserRoleEnumType;
756
- username: string | null;
757
- email: string | null;
758
- timeback?: UserTimebackData;
910
+ /**
911
+ * Complete shop view response.
912
+ */
913
+ interface ShopViewResponse {
914
+ shopItems: ShopDisplayItem[];
915
+ currencies: ShopCurrency[];
759
916
  }
760
917
 
761
918
  /**
762
- * Game Types
919
+ * Sprite Types
763
920
  *
764
- * Literal types and API DTOs. Database row types are in @playcademy/data/types.
921
+ * JSON shapes for sprite configuration. Database row types are in @playcademy/data/types.
765
922
  *
766
- * @module types/game
923
+ * @module types/sprite
767
924
  */
768
-
769
- type GameType = 'hosted' | 'external';
770
- type GamePlatform = 'web' | 'godot' | 'unity' | (string & {});
771
925
  /**
772
- * Game manifest file format (manifest.json).
773
- * Note: createdAt is a string here because it's parsed from JSON file.
926
+ * Animation frame configuration.
774
927
  */
775
- interface ManifestV1 {
776
- version: '1';
777
- platform: string;
778
- createdAt: string;
779
- }
780
- interface ManifestVersions {
781
- vitePlugin?: string;
782
- sdk?: string;
783
- cli?: string;
784
- vite?: string;
785
- godotSdk?: string;
786
- godot?: string;
787
- }
788
- interface ManifestV2 {
789
- version: '2';
790
- platform: string;
791
- createdAt: string;
792
- versions: ManifestVersions;
793
- }
794
- type GameManifest = ManifestV1 | ManifestV2;
795
- interface DomainValidationRecords {
796
- ownership?: {
797
- name?: string;
798
- value?: string;
799
- type?: string;
800
- };
801
- ssl?: {
802
- txt_name?: string;
803
- txt_value?: string;
804
- }[];
928
+ interface SpriteAnimationFrame {
929
+ row: number;
930
+ frameStart: number;
931
+ numFrames: number;
932
+ fps: number;
805
933
  }
806
-
807
934
  /**
808
- * Leaderboard Types
809
- *
810
- * @module types/leaderboard
935
+ * Sprite template data structure (stored in JSONB).
811
936
  */
812
- type LeaderboardTimeframe = 'all_time' | 'monthly' | 'weekly' | 'daily';
813
- interface LeaderboardOptions {
814
- timeframe?: LeaderboardTimeframe;
815
- limit?: number;
816
- offset?: number;
817
- gameId?: string;
818
- }
819
- interface LeaderboardEntry {
820
- rank: number;
821
- userId: string;
822
- username: string;
823
- userImage?: string | null;
824
- score: number;
825
- achievedAt: Date;
826
- metadata?: Record<string, unknown>;
827
- gameId?: string;
828
- gameTitle?: string;
829
- gameSlug?: string;
830
- }
831
- interface UserRank {
832
- rank: number;
833
- totalPlayers: number;
834
- score: number;
835
- percentile: number;
836
- }
837
- interface UserRankResponse {
838
- rank: number;
839
- score: number;
840
- userId: string;
841
- }
842
- interface UserScore {
843
- id: string;
844
- score: number;
845
- achievedAt: Date;
846
- metadata?: Record<string, unknown>;
847
- gameId: string;
848
- gameTitle: string;
849
- gameSlug: string;
937
+ interface SpriteTemplateData {
938
+ tileSize: number;
939
+ tileHeight: number;
940
+ columns: number;
941
+ rows: number;
942
+ spacing: number;
943
+ animations: {
944
+ base_right: SpriteAnimationFrame;
945
+ base_up: SpriteAnimationFrame;
946
+ base_left: SpriteAnimationFrame;
947
+ base_down: SpriteAnimationFrame;
948
+ idle_right: SpriteAnimationFrame;
949
+ walk_right: SpriteAnimationFrame;
950
+ idle_up: SpriteAnimationFrame;
951
+ walk_up: SpriteAnimationFrame;
952
+ idle_left: SpriteAnimationFrame;
953
+ walk_left: SpriteAnimationFrame;
954
+ idle_down: SpriteAnimationFrame;
955
+ walk_down: SpriteAnimationFrame;
956
+ };
850
957
  }
851
958
  /**
852
- * Leaderboard entry with required game context.
853
- * Used when fetching leaderboards for a specific game.
959
+ * Sprite sheet configuration with precomputed dimensions.
854
960
  */
855
- interface GameLeaderboardEntry {
856
- rank: number;
857
- userId: string;
858
- username: string;
859
- userImage?: string | null;
860
- score: number;
861
- achievedAt: Date;
862
- metadata?: Record<string, unknown>;
863
- gameId: string;
864
- gameTitle: string;
865
- gameSlug: string;
961
+ interface SpriteConfigWithDimensions {
962
+ textureUrl: string;
963
+ columns: number;
964
+ rows: number;
965
+ spriteWidth: number;
966
+ spriteHeight: number;
967
+ animations: Record<string, SpriteAnimationFrame>;
866
968
  }
867
969
 
868
970
  /**
869
- * Achievement Types
971
+ * Connection monitoring types
870
972
  *
871
- * @module types/achievement
973
+ * Type definitions for connection state, configuration, and callbacks.
872
974
  */
873
- type AchievementScopeType = 'daily' | 'weekly' | 'monthly' | 'yearly' | 'game' | 'global' | 'map' | 'level' | 'event';
874
- declare enum AchievementCompletionType {
875
- TIME_PLAYED_SESSION = "time_played_session",
876
- INTERACTION = "interaction",
877
- LEADERBOARD_RANK = "leaderboard_rank",
878
- FIRST_SCORE = "first_score",
879
- PERSONAL_BEST = "personal_best"
880
- }
881
- interface AchievementCurrent {
882
- id: string;
883
- title: string;
884
- description?: string | null;
885
- scope: AchievementScopeType;
886
- rewardCredits: number;
887
- limit: number;
888
- completionType: string;
889
- completionConfig: unknown;
890
- target: unknown;
891
- active: boolean;
892
- createdAt?: Date | null;
893
- updatedAt?: Date | null;
894
- status: 'available' | 'completed';
895
- scopeKey: string;
896
- windowStart: string;
897
- windowEnd: string;
898
- }
899
- interface AchievementWithStatus {
900
- id: string;
901
- title: string;
902
- description: string | null;
903
- scope: AchievementScopeType;
904
- rewardCredits: number;
905
- limit: number;
906
- completionType: string;
907
- completionConfig: unknown;
908
- target: unknown;
909
- active: boolean;
910
- createdAt: Date | null;
911
- updatedAt: Date | null;
912
- status: 'available' | 'completed';
913
- scopeKey: string;
914
- windowStart?: string;
915
- windowEnd?: string;
916
- }
917
- interface AchievementHistoryEntry {
918
- achievementId: string;
919
- title: string;
920
- rewardCredits: number;
921
- createdAt: Date;
922
- scopeKey: string;
923
- }
924
- interface AchievementProgressResponse {
925
- achievementId: string;
926
- status: 'completed' | 'already_completed';
927
- rewardCredits: number;
928
- scopeKey: string;
929
- createdAt: Date;
930
- }
931
-
932
975
  /**
933
- * Inventory & Shop Types
934
- *
935
- * Literal types for inventory system. Database row types are in @playcademy/data/types.
976
+ * Possible connection states.
936
977
  *
937
- * @module types/inventory
938
- */
939
- /**
940
- * Item categories available on the platform.
978
+ * - **online**: Connection is stable and healthy
979
+ * - **offline**: Complete loss of network connectivity
980
+ * - **degraded**: Connection is slow or experiencing intermittent issues
941
981
  */
942
- type ItemType = 'currency' | 'badge' | 'trophy' | 'collectible' | 'consumable' | 'unlock' | 'upgrade' | 'accessory' | 'other';
982
+ type ConnectionState = 'online' | 'offline' | 'degraded';
943
983
 
944
984
  /**
945
- * Map & Placement Types
985
+ * Connection Manager
946
986
  *
947
- * Literal types and JSON shapes for maps. Database row types are in @playcademy/data/types.
987
+ * Manages connection monitoring and integrates it with the Playcademy client.
988
+ * Handles event wiring, state management, and disconnect callbacks.
948
989
  *
949
- * @module types/map
990
+ * In iframe mode, disables local monitoring and listens to platform connection
991
+ * state broadcasts instead (avoids duplicate heartbeats).
950
992
  */
993
+
951
994
  /**
952
- * Allowed map interaction types.
995
+ * Configuration for the ConnectionManager.
953
996
  */
954
- type InteractionType = 'game_entry' | 'game_registry' | 'info' | 'teleport' | 'door_in' | 'door_out' | 'npc_interaction' | 'quest_trigger';
955
- /**
956
- * Metadata for interactive map elements.
957
- */
958
- interface MapElementMetadata {
959
- description?: string;
960
- title?: string;
961
- targetMapIdentifier?: string;
962
- targetSpawnTileX?: number;
963
- targetSpawnTileY?: number;
964
- sourceTiledObjects?: Record<string, unknown>[];
965
- [key: string]: unknown;
966
- }
967
- /**
968
- * Metadata describing how an item should be placed on the map.
969
- */
970
- interface PlaceableItemMetadata {
971
- tilesWide?: number;
972
- tilesHigh?: number;
973
- flippable?: boolean;
974
- [key: string]: unknown;
975
- }
976
- /**
977
- * Simplified map data for API responses.
978
- */
979
- interface MapData {
980
- id: string;
981
- identifier: string;
982
- displayName: string;
983
- description?: string | null;
984
- metadata?: Record<string, unknown> | null;
997
+ interface ConnectionManagerConfig {
998
+ /** Base URL for API requests (used for heartbeat pings) */
999
+ baseUrl: string;
1000
+ /** Authentication context (iframe vs standalone) for alert routing */
1001
+ authContext?: {
1002
+ isInIframe: boolean;
1003
+ };
1004
+ /** Handler to call when connection issues are detected */
1005
+ onDisconnect?: DisconnectHandler;
1006
+ /** Callback to emit connection change events to the client */
1007
+ onConnectionChange?: (state: ConnectionState, reason: string) => void;
985
1008
  }
986
1009
  /**
987
- * Input for creating a map object.
1010
+ * Manages connection monitoring for the Playcademy client.
1011
+ *
1012
+ * The ConnectionManager serves as an integration layer between the low-level
1013
+ * ConnectionMonitor and the PlaycademyClient. It handles:
1014
+ * - Event wiring and coordination
1015
+ * - Disconnect callbacks with context
1016
+ * - Platform-level alert integration
1017
+ * - Request success/failure tracking
1018
+ *
1019
+ * This class is used internally by PlaycademyClient and typically not
1020
+ * instantiated directly by game developers.
1021
+ *
1022
+ * @see {@link ConnectionMonitor} for the underlying monitoring implementation
1023
+ * @see {@link PlaycademyClient.onDisconnect} for the public API
988
1024
  */
989
- interface CreateMapObjectData {
990
- itemId: string;
991
- worldX: number;
992
- worldY: number;
993
- width?: number;
994
- height?: number;
995
- rotation?: number;
996
- scale?: number;
997
- metadata?: Record<string, unknown>;
1025
+ declare class ConnectionManager {
1026
+ private monitor?;
1027
+ private authContext?;
1028
+ private disconnectHandler?;
1029
+ private connectionChangeCallback?;
1030
+ private currentState;
1031
+ private additionalDisconnectHandlers;
1032
+ /**
1033
+ * Creates a new ConnectionManager instance.
1034
+ *
1035
+ * @param config - Configuration options for the manager
1036
+ *
1037
+ * @example
1038
+ * ```typescript
1039
+ * const manager = new ConnectionManager({
1040
+ * baseUrl: 'https://api.playcademy.com',
1041
+ * authContext: { isInIframe: false },
1042
+ * onDisconnect: (context) => {
1043
+ * console.log(`Disconnected: ${context.state}`)
1044
+ * },
1045
+ * onConnectionChange: (state, reason) => {
1046
+ * console.log(`Connection changed: ${state}`)
1047
+ * }
1048
+ * })
1049
+ * ```
1050
+ */
1051
+ constructor(config: ConnectionManagerConfig);
1052
+ /**
1053
+ * Gets the current connection state.
1054
+ *
1055
+ * @returns The current connection state ('online', 'offline', or 'degraded')
1056
+ *
1057
+ * @example
1058
+ * ```typescript
1059
+ * const state = manager.getState()
1060
+ * if (state === 'offline') {
1061
+ * console.log('No connection')
1062
+ * }
1063
+ * ```
1064
+ */
1065
+ getState(): ConnectionState;
1066
+ /**
1067
+ * Manually triggers a connection check immediately.
1068
+ *
1069
+ * Forces a heartbeat ping to verify the current connection status.
1070
+ * Useful when you need to check connectivity before a critical operation.
1071
+ *
1072
+ * In iframe mode, this returns the last known state from platform.
1073
+ *
1074
+ * @returns Promise resolving to the current connection state
1075
+ *
1076
+ * @example
1077
+ * ```typescript
1078
+ * const state = await manager.checkNow()
1079
+ * if (state === 'online') {
1080
+ * await performCriticalOperation()
1081
+ * }
1082
+ * ```
1083
+ */
1084
+ checkNow(): Promise<ConnectionState>;
1085
+ /**
1086
+ * Reports a successful API request to the connection monitor.
1087
+ *
1088
+ * This resets the consecutive failure counter and transitions from
1089
+ * 'degraded' to 'online' state if applicable.
1090
+ *
1091
+ * Typically called automatically by the SDK's request wrapper.
1092
+ * No-op in iframe mode (platform handles monitoring).
1093
+ */
1094
+ reportRequestSuccess(): void;
1095
+ /**
1096
+ * Reports a failed API request to the connection monitor.
1097
+ *
1098
+ * Only network errors are tracked (not 4xx/5xx HTTP responses).
1099
+ * After consecutive failures exceed the threshold, the state transitions
1100
+ * to 'degraded' or 'offline'.
1101
+ *
1102
+ * Typically called automatically by the SDK's request wrapper.
1103
+ * No-op in iframe mode (platform handles monitoring).
1104
+ *
1105
+ * @param error - The error from the failed request
1106
+ */
1107
+ reportRequestFailure(error: unknown): void;
1108
+ /**
1109
+ * Registers a callback to be called when connection issues are detected.
1110
+ *
1111
+ * The callback only fires for 'offline' and 'degraded' states, not when
1112
+ * recovering to 'online'. This provides a clean API for games to handle
1113
+ * disconnect scenarios without being notified of every state change.
1114
+ *
1115
+ * Works in both iframe and standalone modes transparently.
1116
+ *
1117
+ * @param callback - Function to call when connection degrades
1118
+ * @returns Cleanup function to unregister the callback
1119
+ *
1120
+ * @example
1121
+ * ```typescript
1122
+ * const cleanup = manager.onDisconnect(({ state, reason, displayAlert }) => {
1123
+ * if (state === 'offline') {
1124
+ * displayAlert?.('Connection lost. Saving your progress...', { type: 'error' })
1125
+ * saveGameState()
1126
+ * }
1127
+ * })
1128
+ *
1129
+ * // Later: cleanup() to unregister
1130
+ * ```
1131
+ */
1132
+ onDisconnect(callback: DisconnectHandler): () => void;
1133
+ /**
1134
+ * Stops connection monitoring and performs cleanup.
1135
+ *
1136
+ * Removes event listeners and clears heartbeat intervals.
1137
+ * Should be called when the client is being destroyed.
1138
+ */
1139
+ stop(): void;
1140
+ /**
1141
+ * Sets up listener for platform connection state broadcasts (iframe mode only).
1142
+ */
1143
+ private _setupPlatformListener;
1144
+ /**
1145
+ * Handles connection state changes from the monitor or platform.
1146
+ *
1147
+ * Coordinates between:
1148
+ * 1. Emitting events to the client (for client.on('connectionChange'))
1149
+ * 2. Calling the disconnect handler if configured
1150
+ * 3. Calling any additional handlers registered via onDisconnect()
1151
+ *
1152
+ * @param state - The new connection state
1153
+ * @param reason - Human-readable reason for the state change
1154
+ */
1155
+ private _handleConnectionChange;
998
1156
  }
999
1157
 
1000
1158
  /**
1001
- * Character & Avatar Types
1159
+ * @fileoverview Playcademy Messaging System
1002
1160
  *
1003
- * Literal types for character system. Database row types are in @playcademy/data/types.
1161
+ * This file implements a unified messaging system for the Playcademy platform that handles
1162
+ * communication between different contexts:
1004
1163
  *
1005
- * @module types/character
1006
- */
1007
- /**
1008
- * Character component categories.
1009
- */
1010
- type CharacterComponentType = 'body' | 'outfit' | 'hairstyle' | 'eyes' | 'accessory';
1011
-
1012
- /**
1013
- * Level & Progression Types
1164
+ * 1. **Iframe-to-Parent Communication**: When games run inside iframes (production/development),
1165
+ * they need to communicate with the parent window using postMessage API
1014
1166
  *
1015
- * API response DTOs for level system. Database row types are in @playcademy/data/types.
1167
+ * 2. **Local Communication**: When games run in the same context (local development),
1168
+ * they use CustomEvents for internal messaging
1016
1169
  *
1017
- * @module types/level
1018
- */
1019
- /**
1020
- * Result of adding XP to a user.
1021
- */
1022
- interface XPAddResult {
1023
- totalXP: number;
1024
- newLevel: number;
1025
- leveledUp: boolean;
1026
- creditsAwarded: number;
1027
- xpToNextLevel: number;
1028
- }
1029
- /**
1030
- * Result of checking whether a level up occurred.
1031
- */
1032
- interface LevelUpCheckResult {
1033
- newLevel: number;
1034
- remainingXp: number;
1035
- leveledUp: boolean;
1036
- creditsAwarded: number;
1037
- xpToNextLevel: number;
1038
- }
1039
- /**
1040
- * Level progress API response.
1170
+ * The system automatically detects the runtime environment and chooses the appropriate
1171
+ * transport method, abstracting this complexity from the developer.
1172
+ *
1173
+ * **Architecture Overview**:
1174
+ * - Games run in iframes for security and isolation
1175
+ * - Parent window (Playcademy shell) manages game lifecycle
1176
+ * - Messages flow bidirectionally between parent and iframe
1177
+ * - Local development mode simulates this architecture without iframes
1041
1178
  */
1042
- interface LevelProgressResponse {
1043
- level: number;
1044
- currentXp: number;
1045
- xpToNextLevel: number;
1046
- totalXP: number;
1047
- }
1048
1179
 
1049
1180
  /**
1050
- * Notification Types
1181
+ * Enumeration of all message types used in the Playcademy messaging system.
1051
1182
  *
1052
- * @module types/notification
1053
- */
1054
-
1055
- declare enum NotificationType {
1056
- ACHIEVEMENT = "achievement",
1057
- SYSTEM = "system",
1058
- PROMO = "promo"
1059
- }
1060
- declare enum NotificationStatus {
1061
- PENDING = "pending",
1062
- DELIVERED = "delivered",
1063
- SEEN = "seen",
1064
- CLICKED = "clicked",
1065
- DISMISSED = "dismissed",
1066
- EXPIRED = "expired"
1067
- }
1068
- interface NotificationStats {
1069
- total: number;
1070
- delivered: number;
1071
- seen: number;
1072
- clicked: number;
1073
- dismissed: number;
1074
- expired: number;
1075
- clickThroughRate: number;
1183
+ * **Message Flow Patterns**:
1184
+ *
1185
+ * **Parent → Game (Overworld → Game)**:
1186
+ * - INIT: Provides game with authentication token and configuration
1187
+ * - TOKEN_REFRESH: Updates game's authentication token before expiry
1188
+ * - PAUSE/RESUME: Controls game execution state
1189
+ * - FORCE_EXIT: Immediately terminates the game
1190
+ * - OVERLAY: Shows/hides UI overlays over the game
1191
+ *
1192
+ * **Game → Parent (Game → Overworld)**:
1193
+ * - READY: Game has loaded and is ready to receive messages
1194
+ * - EXIT: Game requests to be closed (user clicked exit, game ended, etc.)
1195
+ * - TELEMETRY: Game reports performance metrics (FPS, memory usage, etc.)
1196
+ */
1197
+ declare enum MessageEvents {
1198
+ /**
1199
+ * Initializes the game with authentication context and configuration.
1200
+ * Sent immediately after game iframe loads.
1201
+ * Payload:
1202
+ * - `baseUrl`: string
1203
+ * - `token`: string
1204
+ * - `gameId`: string
1205
+ */
1206
+ INIT = "PLAYCADEMY_INIT",
1207
+ /**
1208
+ * Updates the game's authentication token before it expires.
1209
+ * Sent periodically to maintain valid authentication.
1210
+ * Payload:
1211
+ * - `token`: string
1212
+ * - `exp`: number
1213
+ */
1214
+ TOKEN_REFRESH = "PLAYCADEMY_TOKEN_REFRESH",
1215
+ /**
1216
+ * Pauses game execution (e.g., when user switches tabs).
1217
+ * Game should pause timers, animations, and user input.
1218
+ * Payload: void
1219
+ */
1220
+ PAUSE = "PLAYCADEMY_PAUSE",
1221
+ /**
1222
+ * Resumes game execution after being paused.
1223
+ * Game should restore timers, animations, and user input.
1224
+ * Payload: void
1225
+ */
1226
+ RESUME = "PLAYCADEMY_RESUME",
1227
+ /**
1228
+ * Forces immediate game termination (emergency exit).
1229
+ * Game should clean up resources and exit immediately.
1230
+ * Payload: void
1231
+ */
1232
+ FORCE_EXIT = "PLAYCADEMY_FORCE_EXIT",
1233
+ /**
1234
+ * Shows or hides UI overlays over the game.
1235
+ * Game may need to pause or adjust rendering accordingly.
1236
+ * Payload: boolean (true = show overlay, false = hide overlay)
1237
+ */
1238
+ OVERLAY = "PLAYCADEMY_OVERLAY",
1239
+ /**
1240
+ * Broadcasts connection state changes to games.
1241
+ * Sent by platform when network connectivity changes.
1242
+ * Payload:
1243
+ * - `state`: 'online' | 'offline' | 'degraded'
1244
+ * - `reason`: string
1245
+ */
1246
+ CONNECTION_STATE = "PLAYCADEMY_CONNECTION_STATE",
1247
+ /**
1248
+ * Game has finished loading and is ready to receive messages.
1249
+ * Sent once after game initialization is complete.
1250
+ * Payload: void
1251
+ */
1252
+ READY = "PLAYCADEMY_READY",
1253
+ /**
1254
+ * Game SDK initialization failed.
1255
+ * Sent when the game iframe fails to complete SDK init (e.g.
1256
+ * origin validation failure, INIT timeout, client creation error).
1257
+ * Payload:
1258
+ * - `reason`: string — human-readable failure description
1259
+ */
1260
+ INIT_ERROR = "PLAYCADEMY_INIT_ERROR",
1261
+ /**
1262
+ * Game requests to be closed/exited.
1263
+ * Sent when user clicks exit button or game naturally ends.
1264
+ * Payload: void
1265
+ */
1266
+ EXIT = "PLAYCADEMY_EXIT",
1267
+ /**
1268
+ * Game reports performance telemetry data.
1269
+ * Sent periodically for monitoring and analytics.
1270
+ * Payload:
1271
+ * - `fps`: number
1272
+ * - `mem`: number
1273
+ */
1274
+ TELEMETRY = "PLAYCADEMY_TELEMETRY",
1275
+ /**
1276
+ * Game reports key events to parent.
1277
+ * Sent when certain keys are pressed within the game iframe.
1278
+ * Payload:
1279
+ * - `key`: string
1280
+ * - `code?`: string
1281
+ * - `type`: 'keydown' | 'keyup'
1282
+ */
1283
+ KEY_EVENT = "PLAYCADEMY_KEY_EVENT",
1284
+ /**
1285
+ * Game requests platform to display an alert.
1286
+ * Sent when connection issues are detected or other important events occur.
1287
+ * Payload:
1288
+ * - `message`: string
1289
+ * - `options`: `{ type?: 'info' | 'warning' | 'error', duration?: number }`
1290
+ */
1291
+ DISPLAY_ALERT = "PLAYCADEMY_DISPLAY_ALERT",
1292
+ /**
1293
+ * Game signals that demo mode has ended.
1294
+ * Sent when a demo experience reaches its CTA/upgrade boundary.
1295
+ * Payload:
1296
+ * - `score?`: number
1297
+ * - `durationMs?`: number
1298
+ * - `metadata?`: `Record<string, unknown>`
1299
+ */
1300
+ DEMO_END = "PLAYCADEMY_DEMO_END",
1301
+ /**
1302
+ * Notifies about authentication state changes.
1303
+ * Can be sent in both directions depending on auth flow.
1304
+ * Payload:
1305
+ * - `authenticated`: boolean
1306
+ * - `user`: UserInfo | null
1307
+ * - `error`: Error | null
1308
+ */
1309
+ AUTH_STATE_CHANGE = "PLAYCADEMY_AUTH_STATE_CHANGE",
1310
+ /**
1311
+ * OAuth callback data from popup/new-tab windows.
1312
+ * Sent from popup window back to parent after OAuth completes.
1313
+ * Payload:
1314
+ * - `code`: string (OAuth authorization code)
1315
+ * - `state`: string (OAuth state for CSRF protection)
1316
+ * - `error`: string | null (OAuth error if any)
1317
+ */
1318
+ AUTH_CALLBACK = "PLAYCADEMY_AUTH_CALLBACK"
1076
1319
  }
1077
1320
 
1078
1321
  /**
1079
- * Shop Types
1080
- *
1081
- * @module types/shop
1322
+ * Cache configuration types for runtime customization
1082
1323
  */
1083
1324
  /**
1084
- * Currency display info for shop UI.
1325
+ * Runtime configuration for TTL cache behavior
1085
1326
  */
1086
- interface ShopCurrency {
1087
- id: string;
1088
- symbol: string | null;
1089
- isPrimary: boolean;
1090
- displayName?: string | null;
1091
- imageUrl?: string | null;
1327
+ interface TTLCacheConfig {
1328
+ /** Time-to-live in milliseconds. Set to 0 to disable caching for this call. */
1329
+ ttl?: number;
1330
+ /** Force refresh, bypassing cache */
1331
+ force?: boolean;
1332
+ /** Skip cache and fetch fresh data (alias for force) */
1333
+ skipCache?: boolean;
1092
1334
  }
1335
+
1093
1336
  /**
1094
- * Shop item for display.
1095
- * Combines Item fields (excluding createdAt) with shop listing data.
1337
+ * @fileoverview Server SDK Type Definitions
1338
+ *
1339
+ * TypeScript type definitions for the server-side Playcademy SDK.
1340
+ * Includes configuration types, client state, and re-exported TimeBack types.
1096
1341
  */
1097
- interface ShopDisplayItem {
1098
- id: string;
1099
- slug: string;
1100
- gameId?: string | null;
1101
- displayName: string;
1102
- description?: string | null;
1103
- type: string;
1104
- isPlaceable: boolean;
1105
- imageUrl?: string | null;
1106
- metadata?: unknown;
1107
- listingId: string;
1108
- shopPrice: number;
1109
- currencyId: string;
1110
- currencySymbol?: string | null;
1111
- currencyDisplayName?: string | null;
1112
- currencyImageUrl?: string | null;
1113
- stock?: number | null;
1114
- sellBackPercentage?: number | null;
1342
+
1343
+ /**
1344
+ * Base configuration for TimeBack integration (shared across all courses).
1345
+ * References upstream TimeBack types from @playcademy/timeback.
1346
+ *
1347
+ * All fields are optional and support template variables: {grade}, {subject}, {gameSlug}
1348
+ */
1349
+ interface TimebackBaseConfig {
1350
+ /** Organization configuration (shared across all courses) */
1351
+ organization?: Partial<OrganizationConfig>;
1352
+ /** Course defaults (can be overridden per-course) */
1353
+ course?: Partial<CourseConfig>;
1354
+ /** Component defaults */
1355
+ component?: Partial<ComponentConfig>;
1356
+ /** Resource defaults */
1357
+ resource?: Partial<ResourceConfig>;
1358
+ /** ComponentResource defaults */
1359
+ componentResource?: Partial<ComponentResourceConfig>;
1115
1360
  }
1116
1361
  /**
1117
- * Complete shop view response.
1362
+ * Extended course configuration that merges TimebackCourseConfig with per-course overrides.
1363
+ * Used in playcademy.config.* to allow per-course customization.
1118
1364
  */
1119
- interface ShopViewResponse {
1120
- shopItems: ShopDisplayItem[];
1121
- currencies: ShopCurrency[];
1365
+ interface TimebackCourseConfigWithOverrides extends TimebackCourseConfig {
1366
+ title?: string;
1367
+ courseCode?: string;
1368
+ level?: string;
1369
+ metadata?: CourseConfig['metadata'];
1370
+ totalXp?: number | null;
1371
+ masterableUnits?: number | null;
1122
1372
  }
1123
-
1124
1373
  /**
1125
- * Sprite Types
1374
+ * TimeBack integration configuration for Playcademy config file.
1126
1375
  *
1127
- * JSON shapes for sprite configuration. Database row types are in @playcademy/data/types.
1376
+ * Supports two levels of customization:
1377
+ * 1. `base`: Shared defaults for all courses (organization, course, component, resource, componentResource)
1378
+ * 2. Per-course overrides in the `courses` array (title, courseCode, level, gradingScheme, metadata)
1128
1379
  *
1129
- * @module types/sprite
1130
- */
1131
- /**
1132
- * Animation frame configuration.
1380
+ * Template variables ({grade}, {subject}, {gameSlug}) can be used in string fields.
1133
1381
  */
1134
- interface SpriteAnimationFrame {
1135
- row: number;
1136
- frameStart: number;
1137
- numFrames: number;
1138
- fps: number;
1382
+ interface TimebackIntegrationConfig {
1383
+ /** Multi-grade course configuration (array of grade/subject/totalXp with optional per-course overrides) */
1384
+ courses: TimebackCourseConfigWithOverrides[];
1385
+ /** Optional base configuration (shared across all courses, can be overridden per-course) */
1386
+ base?: TimebackBaseConfig;
1139
1387
  }
1140
1388
  /**
1141
- * Sprite template data structure (stored in JSONB).
1389
+ * Custom API routes integration
1142
1390
  */
1143
- interface SpriteTemplateData {
1144
- tileSize: number;
1145
- tileHeight: number;
1146
- columns: number;
1147
- rows: number;
1148
- spacing: number;
1149
- animations: {
1150
- base_right: SpriteAnimationFrame;
1151
- base_up: SpriteAnimationFrame;
1152
- base_left: SpriteAnimationFrame;
1153
- base_down: SpriteAnimationFrame;
1154
- idle_right: SpriteAnimationFrame;
1155
- walk_right: SpriteAnimationFrame;
1156
- idle_up: SpriteAnimationFrame;
1157
- walk_up: SpriteAnimationFrame;
1158
- idle_left: SpriteAnimationFrame;
1159
- walk_left: SpriteAnimationFrame;
1160
- idle_down: SpriteAnimationFrame;
1161
- walk_down: SpriteAnimationFrame;
1162
- };
1391
+ interface CustomRoutesIntegration {
1392
+ /** Directory for custom API routes (defaults to 'server/api') */
1393
+ directory?: string;
1163
1394
  }
1164
1395
  /**
1165
- * Sprite sheet configuration with precomputed dimensions.
1396
+ * Database integration
1166
1397
  */
1167
- interface SpriteConfigWithDimensions {
1168
- textureUrl: string;
1169
- columns: number;
1170
- rows: number;
1171
- spriteWidth: number;
1172
- spriteHeight: number;
1173
- animations: Record<string, SpriteAnimationFrame>;
1398
+ interface DatabaseIntegration {
1399
+ /** Database directory (defaults to 'db') */
1400
+ directory?: string;
1401
+ /** Schema strategy: 'push' uses drizzle-kit push-style diffing, 'migrate' uses migration files.
1402
+ * When omitted, auto-detects based on presence of a migrations directory with _journal.json. */
1403
+ strategy?: 'push' | 'migrate';
1404
+ }
1405
+ interface QueueConfig {
1406
+ maxBatchSize?: number;
1407
+ maxRetries?: number;
1408
+ maxBatchTimeout?: number;
1409
+ maxConcurrency?: number;
1410
+ retryDelay?: number;
1411
+ deadLetterQueue?: string;
1412
+ }
1413
+ /**
1414
+ * Integrations configuration
1415
+ * All backend features (database, custom routes, external services) are configured here
1416
+ */
1417
+ interface IntegrationsConfig {
1418
+ /** TimeBack integration (optional) */
1419
+ timeback?: TimebackIntegrationConfig | null;
1420
+ /** Custom API routes (optional) */
1421
+ customRoutes?: CustomRoutesIntegration | boolean;
1422
+ /** Database (optional) */
1423
+ database?: DatabaseIntegration | boolean;
1424
+ /** Key-Value storage (optional) */
1425
+ kv?: boolean;
1426
+ /** Bucket storage (optional) */
1427
+ bucket?: boolean;
1428
+ /** Authentication (optional) */
1429
+ auth?: boolean;
1430
+ /** Queues (optional) */
1431
+ queues?: Record<string, QueueConfig | boolean>;
1432
+ }
1433
+ /**
1434
+ * Unified Playcademy configuration
1435
+ * Used for playcademy.config.{js,json}
1436
+ */
1437
+ interface PlaycademyConfig {
1438
+ /** Game name */
1439
+ name: string;
1440
+ /** Game description */
1441
+ description?: string;
1442
+ /** Game emoji icon */
1443
+ emoji?: string;
1444
+ /** Build command to run before deployment */
1445
+ buildCommand?: string[];
1446
+ /** Path to build output */
1447
+ buildPath?: string;
1448
+ /** Game type */
1449
+ gameType?: 'hosted' | 'external';
1450
+ /** External URL (for external games) */
1451
+ externalUrl?: string;
1452
+ /** Game platform */
1453
+ platform?: 'web' | 'unity' | 'godot';
1454
+ /** Integrations (database, custom routes, external services) */
1455
+ integrations?: IntegrationsConfig;
1456
+ }
1457
+
1458
+ /**
1459
+ * Configuration options for initializing a PlaycademyClient instance.
1460
+ *
1461
+ * @example
1462
+ * ```typescript
1463
+ * const config: PlaycademyServerClientConfig = {
1464
+ * apiKey: process.env.PLAYCADEMY_API_KEY!,
1465
+ * gameId: 'my-math-game',
1466
+ * configPath: './playcademy.config.js'
1467
+ * }
1468
+ * ```
1469
+ */
1470
+ interface PlaycademyServerClientConfig {
1471
+ /**
1472
+ * Playcademy API key for server-to-server authentication.
1473
+ * Obtain from the Playcademy developer dashboard.
1474
+ */
1475
+ apiKey: string;
1476
+ /**
1477
+ * Optional path to playcademy.config.js file.
1478
+ * If not provided, searches current directory and up to 3 parent directories.
1479
+ * Ignored if `config` is provided directly.
1480
+ *
1481
+ * @example './config/playcademy.config.js'
1482
+ */
1483
+ configPath?: string;
1484
+ /**
1485
+ * Optional config object (for edge environments without filesystem).
1486
+ * If provided, skips filesystem-based config loading.
1487
+ *
1488
+ * @example { name: 'My Game', integrations: { timeback: {...} } }
1489
+ */
1490
+ config?: PlaycademyConfig;
1491
+ /**
1492
+ * Optional base URL for Playcademy API.
1493
+ * Defaults to environment variables or 'https://hub.playcademy.net'.
1494
+ *
1495
+ * @example 'http://localhost:3000' for local development
1496
+ */
1497
+ baseUrl?: string;
1498
+ /**
1499
+ * Optional game ID.
1500
+ * If not provided, will attempt to fetch from API using the API token.
1501
+ *
1502
+ * @example 'my-math-game'
1503
+ */
1504
+ gameId?: string;
1505
+ }
1506
+ /**
1507
+ * Internal state maintained by the PlaycademyClient instance.
1508
+ *
1509
+ * @internal
1510
+ */
1511
+ interface PlaycademyServerClientState {
1512
+ /** API key for authentication */
1513
+ apiKey: string;
1514
+ /** Base URL for API requests */
1515
+ baseUrl: string;
1516
+ /** Game identifier */
1517
+ gameId: string;
1518
+ /** Loaded game configuration from playcademy.config.js */
1519
+ config: PlaycademyConfig;
1520
+ /**
1521
+ * TimeBack course ID fetched from the Playcademy API.
1522
+ * Used for all TimeBack event recording.
1523
+ */
1524
+ courseId?: string;
1174
1525
  }
1175
1526
 
1176
1527
  declare const users: drizzle_orm_pg_core.PgTableWithColumns<{
@@ -4683,466 +5034,50 @@ interface PlayerLocation {
4683
5034
  interface PlayerSessionPayload {
4684
5035
  profile: PlayerProfile;
4685
5036
  currencies: PlayerCurrency[];
4686
- inventory: PlayerInventoryItem[];
4687
- ownedGameIds: Game['id'][];
4688
- currentLocation?: PlayerLocation;
4689
- characterCreated?: UserRow['characterCreated'];
4690
- playerCharacter?: PlayerCharacterRow | null;
4691
- }
4692
- /**
4693
- * Map-related Composite Types
4694
- * DB row + joined game/item data
4695
- */
4696
- type MapElementWithGame = MapElementRow & {
4697
- game: {
4698
- id: string;
4699
- displayName: string;
4700
- } | null;
4701
- };
4702
- type MapObjectWithItem = MapObjectRow & {
4703
- item: {
4704
- id: string;
4705
- slug: string;
4706
- displayName: string;
4707
- description?: string | null;
4708
- imageUrl?: string | null;
4709
- isPlaceable: boolean;
4710
- metadata?: PlaceableItemMetadata | null;
4711
- };
4712
- };
4713
- /**
4714
- * Game custom hostname with validation records
4715
- */
4716
- type GameCustomHostname = GameCustomHostnameRow & {
4717
- validationRecords?: DomainValidationRecords;
4718
- };
4719
-
4720
- type UserLevelRow = typeof userLevels.$inferSelect;
4721
- type LevelConfigRow = typeof levelConfigs.$inferSelect;
4722
- type UserLevelWithConfig = UserLevelRow & {
4723
- xpToNextLevel: number;
4724
- nextLevelConfig?: LevelConfigRow;
4725
- };
4726
-
4727
- type SpriteTemplateRow = typeof spriteTemplates.$inferSelect;
4728
-
4729
- type NotificationRow = InferSelectModel<typeof notifications>;
4730
-
4731
- /**
4732
- * Connection monitoring types
4733
- *
4734
- * Type definitions for connection state, configuration, and callbacks.
4735
- */
4736
- /**
4737
- * Possible connection states.
4738
- *
4739
- * - **online**: Connection is stable and healthy
4740
- * - **offline**: Complete loss of network connectivity
4741
- * - **degraded**: Connection is slow or experiencing intermittent issues
4742
- */
4743
- type ConnectionState = 'online' | 'offline' | 'degraded';
4744
-
4745
- /**
4746
- * Connection Manager
4747
- *
4748
- * Manages connection monitoring and integrates it with the Playcademy client.
4749
- * Handles event wiring, state management, and disconnect callbacks.
4750
- *
4751
- * In iframe mode, disables local monitoring and listens to platform connection
4752
- * state broadcasts instead (avoids duplicate heartbeats).
4753
- */
4754
-
4755
- /**
4756
- * Configuration for the ConnectionManager.
4757
- */
4758
- interface ConnectionManagerConfig {
4759
- /** Base URL for API requests (used for heartbeat pings) */
4760
- baseUrl: string;
4761
- /** Authentication context (iframe vs standalone) for alert routing */
4762
- authContext?: {
4763
- isInIframe: boolean;
4764
- };
4765
- /** Handler to call when connection issues are detected */
4766
- onDisconnect?: DisconnectHandler;
4767
- /** Callback to emit connection change events to the client */
4768
- onConnectionChange?: (state: ConnectionState, reason: string) => void;
4769
- }
4770
- /**
4771
- * Manages connection monitoring for the Playcademy client.
4772
- *
4773
- * The ConnectionManager serves as an integration layer between the low-level
4774
- * ConnectionMonitor and the PlaycademyClient. It handles:
4775
- * - Event wiring and coordination
4776
- * - Disconnect callbacks with context
4777
- * - Platform-level alert integration
4778
- * - Request success/failure tracking
4779
- *
4780
- * This class is used internally by PlaycademyClient and typically not
4781
- * instantiated directly by game developers.
4782
- *
4783
- * @see {@link ConnectionMonitor} for the underlying monitoring implementation
4784
- * @see {@link PlaycademyClient.onDisconnect} for the public API
4785
- */
4786
- declare class ConnectionManager {
4787
- private monitor?;
4788
- private authContext?;
4789
- private disconnectHandler?;
4790
- private connectionChangeCallback?;
4791
- private currentState;
4792
- private additionalDisconnectHandlers;
4793
- /**
4794
- * Creates a new ConnectionManager instance.
4795
- *
4796
- * @param config - Configuration options for the manager
4797
- *
4798
- * @example
4799
- * ```typescript
4800
- * const manager = new ConnectionManager({
4801
- * baseUrl: 'https://api.playcademy.com',
4802
- * authContext: { isInIframe: false },
4803
- * onDisconnect: (context) => {
4804
- * console.log(`Disconnected: ${context.state}`)
4805
- * },
4806
- * onConnectionChange: (state, reason) => {
4807
- * console.log(`Connection changed: ${state}`)
4808
- * }
4809
- * })
4810
- * ```
4811
- */
4812
- constructor(config: ConnectionManagerConfig);
4813
- /**
4814
- * Gets the current connection state.
4815
- *
4816
- * @returns The current connection state ('online', 'offline', or 'degraded')
4817
- *
4818
- * @example
4819
- * ```typescript
4820
- * const state = manager.getState()
4821
- * if (state === 'offline') {
4822
- * console.log('No connection')
4823
- * }
4824
- * ```
4825
- */
4826
- getState(): ConnectionState;
4827
- /**
4828
- * Manually triggers a connection check immediately.
4829
- *
4830
- * Forces a heartbeat ping to verify the current connection status.
4831
- * Useful when you need to check connectivity before a critical operation.
4832
- *
4833
- * In iframe mode, this returns the last known state from platform.
4834
- *
4835
- * @returns Promise resolving to the current connection state
4836
- *
4837
- * @example
4838
- * ```typescript
4839
- * const state = await manager.checkNow()
4840
- * if (state === 'online') {
4841
- * await performCriticalOperation()
4842
- * }
4843
- * ```
4844
- */
4845
- checkNow(): Promise<ConnectionState>;
4846
- /**
4847
- * Reports a successful API request to the connection monitor.
4848
- *
4849
- * This resets the consecutive failure counter and transitions from
4850
- * 'degraded' to 'online' state if applicable.
4851
- *
4852
- * Typically called automatically by the SDK's request wrapper.
4853
- * No-op in iframe mode (platform handles monitoring).
4854
- */
4855
- reportRequestSuccess(): void;
4856
- /**
4857
- * Reports a failed API request to the connection monitor.
4858
- *
4859
- * Only network errors are tracked (not 4xx/5xx HTTP responses).
4860
- * After consecutive failures exceed the threshold, the state transitions
4861
- * to 'degraded' or 'offline'.
4862
- *
4863
- * Typically called automatically by the SDK's request wrapper.
4864
- * No-op in iframe mode (platform handles monitoring).
4865
- *
4866
- * @param error - The error from the failed request
4867
- */
4868
- reportRequestFailure(error: unknown): void;
4869
- /**
4870
- * Registers a callback to be called when connection issues are detected.
4871
- *
4872
- * The callback only fires for 'offline' and 'degraded' states, not when
4873
- * recovering to 'online'. This provides a clean API for games to handle
4874
- * disconnect scenarios without being notified of every state change.
4875
- *
4876
- * Works in both iframe and standalone modes transparently.
4877
- *
4878
- * @param callback - Function to call when connection degrades
4879
- * @returns Cleanup function to unregister the callback
4880
- *
4881
- * @example
4882
- * ```typescript
4883
- * const cleanup = manager.onDisconnect(({ state, reason, displayAlert }) => {
4884
- * if (state === 'offline') {
4885
- * displayAlert?.('Connection lost. Saving your progress...', { type: 'error' })
4886
- * saveGameState()
4887
- * }
4888
- * })
4889
- *
4890
- * // Later: cleanup() to unregister
4891
- * ```
4892
- */
4893
- onDisconnect(callback: DisconnectHandler): () => void;
4894
- /**
4895
- * Stops connection monitoring and performs cleanup.
4896
- *
4897
- * Removes event listeners and clears heartbeat intervals.
4898
- * Should be called when the client is being destroyed.
4899
- */
4900
- stop(): void;
4901
- /**
4902
- * Sets up listener for platform connection state broadcasts (iframe mode only).
4903
- */
4904
- private _setupPlatformListener;
4905
- /**
4906
- * Handles connection state changes from the monitor or platform.
4907
- *
4908
- * Coordinates between:
4909
- * 1. Emitting events to the client (for client.on('connectionChange'))
4910
- * 2. Calling the disconnect handler if configured
4911
- * 3. Calling any additional handlers registered via onDisconnect()
4912
- *
4913
- * @param state - The new connection state
4914
- * @param reason - Human-readable reason for the state change
4915
- */
4916
- private _handleConnectionChange;
4917
- }
4918
-
4919
- /**
4920
- * @fileoverview Playcademy Messaging System
4921
- *
4922
- * This file implements a unified messaging system for the Playcademy platform that handles
4923
- * communication between different contexts:
4924
- *
4925
- * 1. **Iframe-to-Parent Communication**: When games run inside iframes (production/development),
4926
- * they need to communicate with the parent window using postMessage API
4927
- *
4928
- * 2. **Local Communication**: When games run in the same context (local development),
4929
- * they use CustomEvents for internal messaging
4930
- *
4931
- * The system automatically detects the runtime environment and chooses the appropriate
4932
- * transport method, abstracting this complexity from the developer.
4933
- *
4934
- * **Architecture Overview**:
4935
- * - Games run in iframes for security and isolation
4936
- * - Parent window (Playcademy shell) manages game lifecycle
4937
- * - Messages flow bidirectionally between parent and iframe
4938
- * - Local development mode simulates this architecture without iframes
4939
- */
4940
-
4941
- /**
4942
- * Enumeration of all message types used in the Playcademy messaging system.
4943
- *
4944
- * **Message Flow Patterns**:
4945
- *
4946
- * **Parent → Game (Overworld → Game)**:
4947
- * - INIT: Provides game with authentication token and configuration
4948
- * - TOKEN_REFRESH: Updates game's authentication token before expiry
4949
- * - PAUSE/RESUME: Controls game execution state
4950
- * - FORCE_EXIT: Immediately terminates the game
4951
- * - OVERLAY: Shows/hides UI overlays over the game
4952
- *
4953
- * **Game → Parent (Game → Overworld)**:
4954
- * - READY: Game has loaded and is ready to receive messages
4955
- * - EXIT: Game requests to be closed (user clicked exit, game ended, etc.)
4956
- * - TELEMETRY: Game reports performance metrics (FPS, memory usage, etc.)
4957
- */
4958
- declare enum MessageEvents {
4959
- /**
4960
- * Initializes the game with authentication context and configuration.
4961
- * Sent immediately after game iframe loads.
4962
- * Payload:
4963
- * - `baseUrl`: string
4964
- * - `token`: string
4965
- * - `gameId`: string
4966
- */
4967
- INIT = "PLAYCADEMY_INIT",
4968
- /**
4969
- * Updates the game's authentication token before it expires.
4970
- * Sent periodically to maintain valid authentication.
4971
- * Payload:
4972
- * - `token`: string
4973
- * - `exp`: number
4974
- */
4975
- TOKEN_REFRESH = "PLAYCADEMY_TOKEN_REFRESH",
4976
- /**
4977
- * Pauses game execution (e.g., when user switches tabs).
4978
- * Game should pause timers, animations, and user input.
4979
- * Payload: void
4980
- */
4981
- PAUSE = "PLAYCADEMY_PAUSE",
4982
- /**
4983
- * Resumes game execution after being paused.
4984
- * Game should restore timers, animations, and user input.
4985
- * Payload: void
4986
- */
4987
- RESUME = "PLAYCADEMY_RESUME",
4988
- /**
4989
- * Forces immediate game termination (emergency exit).
4990
- * Game should clean up resources and exit immediately.
4991
- * Payload: void
4992
- */
4993
- FORCE_EXIT = "PLAYCADEMY_FORCE_EXIT",
4994
- /**
4995
- * Shows or hides UI overlays over the game.
4996
- * Game may need to pause or adjust rendering accordingly.
4997
- * Payload: boolean (true = show overlay, false = hide overlay)
4998
- */
4999
- OVERLAY = "PLAYCADEMY_OVERLAY",
5000
- /**
5001
- * Broadcasts connection state changes to games.
5002
- * Sent by platform when network connectivity changes.
5003
- * Payload:
5004
- * - `state`: 'online' | 'offline' | 'degraded'
5005
- * - `reason`: string
5006
- */
5007
- CONNECTION_STATE = "PLAYCADEMY_CONNECTION_STATE",
5008
- /**
5009
- * Game has finished loading and is ready to receive messages.
5010
- * Sent once after game initialization is complete.
5011
- * Payload: void
5012
- */
5013
- READY = "PLAYCADEMY_READY",
5014
- /**
5015
- * Game SDK initialization failed.
5016
- * Sent when the game iframe fails to complete SDK init (e.g.
5017
- * origin validation failure, INIT timeout, client creation error).
5018
- * Payload:
5019
- * - `reason`: string — human-readable failure description
5020
- */
5021
- INIT_ERROR = "PLAYCADEMY_INIT_ERROR",
5022
- /**
5023
- * Game requests to be closed/exited.
5024
- * Sent when user clicks exit button or game naturally ends.
5025
- * Payload: void
5026
- */
5027
- EXIT = "PLAYCADEMY_EXIT",
5028
- /**
5029
- * Game reports performance telemetry data.
5030
- * Sent periodically for monitoring and analytics.
5031
- * Payload:
5032
- * - `fps`: number
5033
- * - `mem`: number
5034
- */
5035
- TELEMETRY = "PLAYCADEMY_TELEMETRY",
5036
- /**
5037
- * Game reports key events to parent.
5038
- * Sent when certain keys are pressed within the game iframe.
5039
- * Payload:
5040
- * - `key`: string
5041
- * - `code?`: string
5042
- * - `type`: 'keydown' | 'keyup'
5043
- */
5044
- KEY_EVENT = "PLAYCADEMY_KEY_EVENT",
5045
- /**
5046
- * Game requests platform to display an alert.
5047
- * Sent when connection issues are detected or other important events occur.
5048
- * Payload:
5049
- * - `message`: string
5050
- * - `options`: `{ type?: 'info' | 'warning' | 'error', duration?: number }`
5051
- */
5052
- DISPLAY_ALERT = "PLAYCADEMY_DISPLAY_ALERT",
5053
- /**
5054
- * Game signals that demo mode has ended.
5055
- * Sent when a demo experience reaches its CTA/upgrade boundary.
5056
- * Payload:
5057
- * - `score?`: number
5058
- * - `durationMs?`: number
5059
- * - `metadata?`: `Record<string, unknown>`
5060
- */
5061
- DEMO_END = "PLAYCADEMY_DEMO_END",
5062
- /**
5063
- * Notifies about authentication state changes.
5064
- * Can be sent in both directions depending on auth flow.
5065
- * Payload:
5066
- * - `authenticated`: boolean
5067
- * - `user`: UserInfo | null
5068
- * - `error`: Error | null
5069
- */
5070
- AUTH_STATE_CHANGE = "PLAYCADEMY_AUTH_STATE_CHANGE",
5071
- /**
5072
- * OAuth callback data from popup/new-tab windows.
5073
- * Sent from popup window back to parent after OAuth completes.
5074
- * Payload:
5075
- * - `code`: string (OAuth authorization code)
5076
- * - `state`: string (OAuth state for CSRF protection)
5077
- * - `error`: string | null (OAuth error if any)
5078
- */
5079
- AUTH_CALLBACK = "PLAYCADEMY_AUTH_CALLBACK"
5037
+ inventory: PlayerInventoryItem[];
5038
+ ownedGameIds: Game['id'][];
5039
+ currentLocation?: PlayerLocation;
5040
+ characterCreated?: UserRow['characterCreated'];
5041
+ playerCharacter?: PlayerCharacterRow | null;
5080
5042
  }
5081
-
5082
5043
  /**
5083
- * Auto-initializes a PlaycademyClient with context from the environment.
5084
- * Works in both iframe mode (production/development) and standalone mode (local dev).
5085
- *
5086
- * This is the recommended way to initialize the SDK as it automatically:
5087
- * - Detects the runtime environment (iframe vs standalone)
5088
- * - Configures the client with the appropriate context
5089
- * - Sets up event listeners for token refresh
5090
- * - Exposes the client for debugging in development mode
5091
- *
5092
- * @param options - Optional configuration overrides
5093
- * @param options.baseUrl - Override the base URL for API requests
5094
- * @returns Promise resolving to a fully initialized PlaycademyClient
5095
- * @throws Error if not running in a browser context
5096
- *
5097
- * @example
5098
- * ```typescript
5099
- * // Default initialization
5100
- * const client = await PlaycademyClient.init()
5101
- *
5102
- * // With custom base URL
5103
- * const client = await PlaycademyClient.init({ baseUrl: 'https://custom.api.com' })
5104
- * ```
5044
+ * Map-related Composite Types
5045
+ * DB row + joined game/item data
5105
5046
  */
5106
- declare function init<T extends PlaycademyBaseClient = PlaycademyBaseClient>(this: new (config?: Partial<ClientConfig>) => T, options?: {
5107
- baseUrl?: string;
5108
- allowedParentOrigins?: string[];
5109
- onDisconnect?: DisconnectHandler;
5110
- enableConnectionMonitoring?: boolean;
5111
- }): Promise<T>;
5112
-
5047
+ type MapElementWithGame = MapElementRow & {
5048
+ game: {
5049
+ id: string;
5050
+ displayName: string;
5051
+ } | null;
5052
+ };
5053
+ type MapObjectWithItem = MapObjectRow & {
5054
+ item: {
5055
+ id: string;
5056
+ slug: string;
5057
+ displayName: string;
5058
+ description?: string | null;
5059
+ imageUrl?: string | null;
5060
+ isPlaceable: boolean;
5061
+ metadata?: PlaceableItemMetadata | null;
5062
+ };
5063
+ };
5113
5064
  /**
5114
- * Authenticates a user with email and password.
5115
- *
5116
- * This is a standalone authentication method that doesn't require an initialized client.
5117
- * Use this for login flows before creating a client instance.
5118
- *
5119
- * @deprecated Use client.auth.login() instead for better error handling and automatic token management
5120
- *
5121
- * @param baseUrl - The base URL of the Playcademy API
5122
- * @param email - User's email address
5123
- * @param password - User's password
5124
- * @returns Promise resolving to authentication response with token
5125
- * @throws PlaycademyError if authentication fails or network error occurs
5126
- *
5127
- * @example
5128
- * ```typescript
5129
- * // Preferred approach:
5130
- * const client = new PlaycademyClient({ baseUrl: '/api' })
5131
- * const result = await client.auth.login({
5132
- * email: 'user@example.com',
5133
- * password: 'password'
5134
- * })
5135
- *
5136
- * // Legacy approach (still works):
5137
- * try {
5138
- * const response = await PlaycademyClient.login('/api', 'user@example.com', 'password')
5139
- * const client = new PlaycademyClient({ token: response.token })
5140
- * } catch (error) {
5141
- * console.error('Login failed:', error.message)
5142
- * }
5143
- * ```
5065
+ * Game custom hostname with validation records
5144
5066
  */
5145
- declare function login(baseUrl: string, email: string, password: string): Promise<LoginResponse>;
5067
+ type GameCustomHostname = GameCustomHostnameRow & {
5068
+ validationRecords?: DomainValidationRecords;
5069
+ };
5070
+
5071
+ type UserLevelRow = typeof userLevels.$inferSelect;
5072
+ type LevelConfigRow = typeof levelConfigs.$inferSelect;
5073
+ type UserLevelWithConfig = UserLevelRow & {
5074
+ xpToNextLevel: number;
5075
+ nextLevelConfig?: LevelConfigRow;
5076
+ };
5077
+
5078
+ type SpriteTemplateRow = typeof spriteTemplates.$inferSelect;
5079
+
5080
+ type NotificationRow = InferSelectModel<typeof notifications>;
5146
5081
 
5147
5082
  /**
5148
5083
  * @fileoverview Authentication Strategy Pattern
@@ -5316,52 +5251,69 @@ declare abstract class PlaycademyBaseClient {
5316
5251
  }
5317
5252
 
5318
5253
  /**
5319
- * Options for configuring activity tracking behavior.
5254
+ * Auto-initializes a PlaycademyClient with context from the environment.
5255
+ * Works in both iframe mode (production/development) and standalone mode (local dev).
5256
+ *
5257
+ * This is the recommended way to initialize the SDK as it automatically:
5258
+ * - Detects the runtime environment (iframe vs standalone)
5259
+ * - Configures the client with the appropriate context
5260
+ * - Sets up event listeners for token refresh
5261
+ * - Exposes the client for debugging in development mode
5262
+ *
5263
+ * @param options - Optional configuration overrides
5264
+ * @param options.baseUrl - Override the base URL for API requests
5265
+ * @returns Promise resolving to a fully initialized PlaycademyClient
5266
+ * @throws Error if not running in a browser context
5267
+ *
5268
+ * @example
5269
+ * ```typescript
5270
+ * // Default initialization
5271
+ * const client = await PlaycademyClient.init()
5272
+ *
5273
+ * // With custom base URL
5274
+ * const client = await PlaycademyClient.init({ baseUrl: 'https://custom.api.com' })
5275
+ * ```
5320
5276
  */
5321
- interface StartActivityOptions {
5322
- /**
5323
- * How long heartbeats continue after the activity is automatically paused
5324
- * because the tab is hidden or the player is inactive while visible.
5325
- * Defaults to 10 minutes. Set to `Infinity` to keep heartbeats running
5326
- * indefinitely during automatic pauses. Invalid values fall back to the
5327
- * 10-minute default.
5328
- */
5329
- pausedHeartbeatTimeoutMs?: number;
5330
- /**
5331
- * @deprecated Use `pausedHeartbeatTimeoutMs` instead.
5332
- *
5333
- * Backward-compatible alias for callers that still use the old option
5334
- * name from earlier SDK releases.
5335
- */
5336
- hiddenTimeoutMs?: number;
5337
- /**
5338
- * How often to flush periodic heartbeats with accumulated time data.
5339
- * Defaults to 15 seconds. Set to `Infinity` to disable the interval;
5340
- * final unload/endActivity flushes still run. Values must be greater than
5341
- * 0 or `Infinity`; invalid values fall back to the 15-second default.
5342
- */
5343
- heartbeatIntervalMs?: number;
5344
- /**
5345
- * How long the tab can remain visible without keyboard or mouse activity
5346
- * before the activity is marked inactive. Defaults to 10 minutes. Set to
5347
- * `Infinity` to disable keyboard/mouse inactivity tracking. Invalid values
5348
- * fall back to the 10-minute default.
5349
- */
5350
- inactivityTimeoutMs?: number;
5351
- /**
5352
- * Stable identifier for this activity run. When provided, it is used on
5353
- * every heartbeat and on endActivity instead of a freshly-generated UUID.
5354
- *
5355
- * Pass the same `runId` across multiple `startActivity()` calls (for
5356
- * example, after the player closes and reopens a resumable activity) so
5357
- * downstream systems can correlate related sessions into a single run.
5358
- *
5359
- * Must be a UUID (the backend validates it as such) and unique per
5360
- * logical run. If omitted, the SDK generates a new UUID on each call,
5361
- * which means every session is treated as its own run.
5362
- */
5363
- runId?: string;
5364
- }
5277
+ declare function init<T extends PlaycademyBaseClient = PlaycademyBaseClient>(this: new (config?: Partial<ClientConfig>) => T, options?: {
5278
+ baseUrl?: string;
5279
+ allowedParentOrigins?: string[];
5280
+ onDisconnect?: DisconnectHandler;
5281
+ enableConnectionMonitoring?: boolean;
5282
+ }): Promise<T>;
5283
+
5284
+ /**
5285
+ * Authenticates a user with email and password.
5286
+ *
5287
+ * This is a standalone authentication method that doesn't require an initialized client.
5288
+ * Use this for login flows before creating a client instance.
5289
+ *
5290
+ * @deprecated Use client.auth.login() instead for better error handling and automatic token management
5291
+ *
5292
+ * @param baseUrl - The base URL of the Playcademy API
5293
+ * @param email - User's email address
5294
+ * @param password - User's password
5295
+ * @returns Promise resolving to authentication response with token
5296
+ * @throws PlaycademyError if authentication fails or network error occurs
5297
+ *
5298
+ * @example
5299
+ * ```typescript
5300
+ * // Preferred approach:
5301
+ * const client = new PlaycademyClient({ baseUrl: '/api' })
5302
+ * const result = await client.auth.login({
5303
+ * email: 'user@example.com',
5304
+ * password: 'password'
5305
+ * })
5306
+ *
5307
+ * // Legacy approach (still works):
5308
+ * try {
5309
+ * const response = await PlaycademyClient.login('/api', 'user@example.com', 'password')
5310
+ * const client = new PlaycademyClient({ token: response.token })
5311
+ * } catch (error) {
5312
+ * console.error('Login failed:', error.message)
5313
+ * }
5314
+ * ```
5315
+ */
5316
+ declare function login(baseUrl: string, email: string, password: string): Promise<LoginResponse>;
5365
5317
 
5366
5318
  /**
5367
5319
  * Playcademy SDK client for game developers.
@@ -5430,15 +5382,17 @@ declare class PlaycademyClient extends PlaycademyBaseClient {
5430
5382
  * - `user.fetch()` - Refresh user context from server
5431
5383
  *
5432
5384
  * Activity tracking:
5433
- * - `startActivity(metadata)` - Begin tracking an activity with automatic
5434
- * hidden-tab and visible-tab inactivity handling, plus configurable
5435
- * paused-heartbeat timeout behavior
5385
+ * - `currentRunId` - Current activity run ID, or undefined when inactive
5386
+ * - `startActivity(metadata)` - Begin tracking an activity, return its run
5387
+ * ID, and automatically handle hidden-tab and visible-tab inactivity
5388
+ * with configurable paused-heartbeat timeout behavior
5436
5389
  * - `pauseActivity()` / `resumeActivity()` - Pause/resume timer
5437
5390
  * - `endActivity(scoreData)` - Submit activity results to TimeBack
5438
5391
  */
5439
5392
  timeback: {
5440
5393
  readonly user: TimebackUser;
5441
- startActivity: (metadata: ActivityData, options?: StartActivityOptions) => void;
5394
+ readonly currentRunId: string | undefined;
5395
+ startActivity: (metadata: ActivityData, options?: StartActivityOptions) => StartActivityResult;
5442
5396
  pauseActivity: () => void;
5443
5397
  resumeActivity: () => void;
5444
5398
  endActivity: (data: EndActivityScoreData) => Promise<EndActivityResponse>;
@@ -5518,6 +5472,57 @@ declare class PlaycademyClient extends PlaycademyBaseClient {
5518
5472
  };
5519
5473
  }
5520
5474
 
5475
+ /**
5476
+ * Options for configuring activity tracking behavior.
5477
+ */
5478
+ interface StartActivityOptions {
5479
+ /**
5480
+ * How long heartbeats continue after the activity is automatically paused
5481
+ * because the tab is hidden or the player is inactive while visible.
5482
+ * Defaults to 10 minutes. Set to `Infinity` to keep heartbeats running
5483
+ * indefinitely during automatic pauses. Invalid values fall back to the
5484
+ * 10-minute default.
5485
+ */
5486
+ pausedHeartbeatTimeoutMs?: number;
5487
+ /**
5488
+ * @deprecated Use `pausedHeartbeatTimeoutMs` instead.
5489
+ *
5490
+ * Backward-compatible alias for callers that still use the old option
5491
+ * name from earlier SDK releases.
5492
+ */
5493
+ hiddenTimeoutMs?: number;
5494
+ /**
5495
+ * How often to flush periodic heartbeats with accumulated time data.
5496
+ * Defaults to 15 seconds. Set to `Infinity` to disable the interval;
5497
+ * final unload/endActivity flushes still run. Values must be greater than
5498
+ * 0 or `Infinity`; invalid values fall back to the 15-second default.
5499
+ */
5500
+ heartbeatIntervalMs?: number;
5501
+ /**
5502
+ * How long the tab can remain visible without keyboard or mouse activity
5503
+ * before the activity is marked inactive. Defaults to 10 minutes. Set to
5504
+ * `Infinity` to disable keyboard/mouse inactivity tracking. Invalid values
5505
+ * fall back to the 10-minute default.
5506
+ */
5507
+ inactivityTimeoutMs?: number;
5508
+ /**
5509
+ * Stable identifier for this activity run. When provided, it is used on
5510
+ * every heartbeat and on endActivity instead of a freshly-generated UUID.
5511
+ *
5512
+ * Pass the same `runId` across multiple `startActivity()` calls (for
5513
+ * example, after the player closes and reopens a resumable activity) so
5514
+ * downstream systems can correlate related sessions into a single run.
5515
+ *
5516
+ * Must be a UUID (the backend validates it as such) and unique per
5517
+ * logical run. If omitted, the SDK generates a new UUID on each call,
5518
+ * which means every session is treated as its own run.
5519
+ */
5520
+ runId?: string;
5521
+ }
5522
+ interface StartActivityResult {
5523
+ runId: string;
5524
+ }
5525
+
5521
5526
  /**
5522
5527
  * Type definitions for the game timeback namespace.
5523
5528
  *
@@ -6204,4 +6209,4 @@ interface AssessmentBankStatus {
6204
6209
  }
6205
6210
 
6206
6211
  export { AchievementCompletionType, NotificationStatus, NotificationType, PlaycademyClient };
6207
- export type { AchievementCurrent, AchievementHistoryEntry, AchievementProgressResponse, AchievementScopeType, AchievementWithStatus, AssessmentBankStatus, AssessmentRow, AssessmentSummary, AuthCallbackPayload, AuthOptions, AuthProviderType, AuthResult, AuthServerMessage, AuthStateChangePayload, AuthStateUpdate, AuthenticatedUser, BetterAuthApiKey, BetterAuthApiKeyResponse, BetterAuthSignInResponse, BucketFile, CharacterComponentRow as CharacterComponent, CharacterComponentType, CharacterComponentWithSpriteUrl, CharacterComponentsOptions, ClientConfig, ClientEvents, ConnectionStatePayload, CourseXp, CreateCharacterData, CreateMapObjectData, CurrencyRow as Currency, DemoEndOptions, DemoEndPayload, DevUploadEvent, DevUploadHooks, DeveloperStatusEnumType, DeveloperStatusResponse, DeveloperStatusValue, DisconnectContext, DisconnectHandler, DisplayAlertPayload, EventListeners, ExternalGame, FetchedGame, Game, GameActivityMetrics, GameContextPayload, GameCourseMetrics, GameCustomHostname, GameInitUser, GameLeaderboardEntry, GameManifest, MapRow as GameMap, GameMetricsProxyResponse, GameMetricsResponse, GameMetricsUnsupportedReason, GamePlatform, GameRow as GameRecord, GameSessionRow as GameSession, GameTimebackIntegration, GameTokenResponse, GameType, GameUser, GetXpOptions, HostedGame, InitErrorPayload, InitPayload, InsertCurrencyInput, InsertItemInput, InsertShopListingInput, InteractionType, InventoryItemRow as InventoryItem, InventoryItemWithItem, InventoryMutationResponse, ItemRow as Item, ItemType, KVKeyEntry, KVKeyMetadata, KVSeedEntry, KVStatsResponse, KeyEventPayload, LeaderboardEntry, LeaderboardOptions, LeaderboardTimeframe, LevelConfigRow as LevelConfig, LevelProgressResponse, LevelUpCheckResult, LoginResponse, ManifestV1, ManifestV2, ManifestVersions, MapData, MapElementRow as MapElement, MapElementMetadata, MapElementWithGame, MapObjectRow as MapObject, MapObjectWithItem, NotificationRow as Notification, NotificationStats, PlaceableItemMetadata, PlatformTimebackUser, PlatformTimebackUserContext, PlaycademyMode, PlaycademyServerClientConfig, PlaycademyServerClientState, PlayerCharacterRow as PlayerCharacter, PlayerCharacterAccessoryRow as PlayerCharacterAccessory, PlayerCurrency, PlayerInventoryItem, PlayerProfile, PlayerSessionPayload, PopulateStudentResponse, QtiTestQuestionRef, QtiTestQuestionsResponse, RealtimeTokenResponse, ScoreSubmission, ShopCurrency, ShopDisplayItem, ShopListingRow as ShopListing, ShopViewResponse, SpriteAnimationFrame, SpriteConfigWithDimensions, SpriteTemplateRow as SpriteTemplate, SpriteTemplateData, StartSessionResponse, TelemetryPayload, TimebackEnrollment, TimebackInitContext, TimebackOrganization, TimebackUser, TimebackUserContext, TimebackUserRefreshField, TimebackUserRefreshOptions, TimebackUserXp, TodayXpResponse, TokenRefreshPayload, TokenType, TotalXpResponse, UpdateCharacterData, UpdateCurrencyInput, UpdateItemInput, UpdateShopListingInput, UpsertGameMetadataInput, UserRow as User, UserEnrollment, UserInfo, UserLevelRow as UserLevel, UserLevelWithConfig, UserOrganization, UserRank, UserRankResponse, UserRoleEnumType, UserScore, UserTimebackData, XPAddResult, XpHistoryResponse, XpResponse, XpSummaryResponse };
6212
+ export type { AchievementCurrent, AchievementHistoryEntry, AchievementProgressResponse, AchievementScopeType, AchievementWithStatus, AssessmentBankStatus, AssessmentRow, AssessmentSummary, AuthCallbackPayload, AuthOptions, AuthProviderType, AuthResult, AuthServerMessage, AuthStateChangePayload, AuthStateUpdate, AuthenticatedUser, BetterAuthApiKey, BetterAuthApiKeyResponse, BetterAuthSignInResponse, BucketFile, CharacterComponentRow as CharacterComponent, CharacterComponentType, CharacterComponentWithSpriteUrl, CharacterComponentsOptions, ClientConfig, ClientEvents, ConnectionStatePayload, CourseXp, CreateCharacterData, CreateMapObjectData, CurrencyRow as Currency, DemoEndOptions, DemoEndPayload, DevUploadEvent, DevUploadHooks, DeveloperStatusEnumType, DeveloperStatusResponse, DeveloperStatusValue, DisconnectContext, DisconnectHandler, DisplayAlertPayload, EventListeners, ExternalGame, FetchedGame, Game, GameActivityMetrics, GameContextPayload, GameCourseMetrics, GameCustomHostname, GameInitUser, GameLeaderboardEntry, GameManifest, MapRow as GameMap, GameMetricsProxyResponse, GameMetricsResponse, GameMetricsUnsupportedReason, GamePlatform, GameRow as GameRecord, GameSessionRow as GameSession, GameTimebackIntegration, GameTokenResponse, GameType, GameUser, GetXpOptions, HostedGame, InitErrorPayload, InitPayload, InsertCurrencyInput, InsertItemInput, InsertShopListingInput, InteractionType, InventoryItemRow as InventoryItem, InventoryItemWithItem, InventoryMutationResponse, ItemRow as Item, ItemType, KVKeyEntry, KVKeyMetadata, KVSeedEntry, KVStatsResponse, KeyEventPayload, LeaderboardEntry, LeaderboardOptions, LeaderboardTimeframe, LevelConfigRow as LevelConfig, LevelProgressResponse, LevelUpCheckResult, LoginResponse, ManifestV1, ManifestV2, ManifestVersions, MapData, MapElementRow as MapElement, MapElementMetadata, MapElementWithGame, MapObjectRow as MapObject, MapObjectWithItem, NotificationRow as Notification, NotificationStats, PlaceableItemMetadata, PlatformTimebackUser, PlatformTimebackUserContext, PlaycademyMode, PlaycademyServerClientConfig, PlaycademyServerClientState, PlayerCharacterRow as PlayerCharacter, PlayerCharacterAccessoryRow as PlayerCharacterAccessory, PlayerCurrency, PlayerInventoryItem, PlayerProfile, PlayerSessionPayload, PopulateStudentResponse, QtiTestQuestionRef, QtiTestQuestionsResponse, RealtimeTokenResponse, ScoreSubmission, ShopCurrency, ShopDisplayItem, ShopListingRow as ShopListing, ShopViewResponse, SpriteAnimationFrame, SpriteConfigWithDimensions, SpriteTemplateRow as SpriteTemplate, SpriteTemplateData, StartActivityOptions, StartActivityResult, StartSessionResponse, TelemetryPayload, TimebackEnrollment, TimebackInitContext, TimebackOrganization, TimebackUser, TimebackUserContext, TimebackUserRefreshField, TimebackUserRefreshOptions, TimebackUserXp, TodayXpResponse, TokenRefreshPayload, TokenType, TotalXpResponse, UpdateCharacterData, UpdateCurrencyInput, UpdateItemInput, UpdateShopListingInput, UpsertGameMetadataInput, UserRow as User, UserEnrollment, UserInfo, UserLevelRow as UserLevel, UserLevelWithConfig, UserOrganization, UserRank, UserRankResponse, UserRoleEnumType, UserScore, UserTimebackData, XPAddResult, XpHistoryResponse, XpResponse, XpSummaryResponse };