@playcademy/sdk 0.9.0 → 0.9.1-beta.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +5 -2
- package/dist/index.d.ts +408 -367
- package/dist/index.js +53 -3
- package/dist/internal.d.ts +5567 -5328
- package/dist/internal.js +89 -18
- package/dist/server/edge.d.ts +8 -0
- package/dist/server.d.ts +8 -0
- package/dist/types.d.ts +1228 -1186
- package/package.json +1 -1
package/dist/types.d.ts
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
|
+
import { UserRole, AUTH_PROVIDER_IDS } from '@playcademy/constants';
|
|
1
2
|
import { InferSelectModel } from 'drizzle-orm';
|
|
2
3
|
import * as drizzle_orm_pg_core from 'drizzle-orm/pg-core';
|
|
3
4
|
import * as drizzle_zod from 'drizzle-zod';
|
|
4
5
|
import { z } from 'zod';
|
|
5
|
-
import { AUTH_PROVIDER_IDS } from '@playcademy/constants';
|
|
6
6
|
|
|
7
7
|
/**
|
|
8
8
|
* OAuth 2.0 implementation for the Playcademy SDK
|
|
@@ -26,105 +26,378 @@ interface RetryPolicy {
|
|
|
26
26
|
}
|
|
27
27
|
|
|
28
28
|
/**
|
|
29
|
-
*
|
|
29
|
+
* User Types
|
|
30
30
|
*
|
|
31
|
-
*
|
|
31
|
+
* Enums, DTOs and API response types. Database row types are in @playcademy/data/types.
|
|
32
32
|
*
|
|
33
|
-
* @module 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
|
-
|
|
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
|
-
*
|
|
47
|
-
* Matches OneRoster subjects, with "None" as a Caliper-specific fallback.
|
|
67
|
+
* OpenID Connect UserInfo claims (NOT a database row).
|
|
48
68
|
*/
|
|
49
|
-
|
|
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
|
-
*
|
|
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
|
-
|
|
99
|
+
interface DemoProfileUpdate {
|
|
100
|
+
displayName: string;
|
|
101
|
+
}
|
|
54
102
|
/**
|
|
55
|
-
*
|
|
103
|
+
* Authenticated user for API responses.
|
|
104
|
+
* Differs from UserRow: omits timebackId, adds hasTimebackAccount and timeback.
|
|
56
105
|
*/
|
|
57
|
-
|
|
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
|
-
*
|
|
131
|
+
* Game Types
|
|
61
132
|
*
|
|
62
|
-
*
|
|
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/
|
|
135
|
+
* @module types/game
|
|
66
136
|
*/
|
|
67
137
|
|
|
138
|
+
type GameType = 'hosted' | 'external';
|
|
139
|
+
type GamePlatform = 'web' | 'godot' | 'unity' | (string & {});
|
|
68
140
|
/**
|
|
69
|
-
*
|
|
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
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
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;
|
|
78
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
|
+
}[];
|
|
174
|
+
}
|
|
175
|
+
|
|
79
176
|
/**
|
|
80
|
-
*
|
|
177
|
+
* Leaderboard Types
|
|
178
|
+
*
|
|
179
|
+
* @module types/leaderboard
|
|
81
180
|
*/
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
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
|
-
*
|
|
221
|
+
* Leaderboard entry with required game context.
|
|
222
|
+
* Used when fetching leaderboards for a specific game.
|
|
96
223
|
*/
|
|
97
|
-
interface
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
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
|
-
*
|
|
238
|
+
* Achievement Types
|
|
239
|
+
*
|
|
240
|
+
* @module types/achievement
|
|
111
241
|
*/
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
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 */
|
|
397
|
+
contactEmail?: string;
|
|
398
|
+
/** Primary app identifier */
|
|
399
|
+
primaryApp?: string;
|
|
400
|
+
/** Learning goals for students */
|
|
128
401
|
goals?: CourseGoals;
|
|
129
402
|
/** Course metrics and totals */
|
|
130
403
|
metrics?: CourseMetrics;
|
|
@@ -451,705 +724,804 @@ type GameMetricsProxyResponse = {
|
|
|
451
724
|
};
|
|
452
725
|
|
|
453
726
|
/**
|
|
454
|
-
*
|
|
727
|
+
* Inventory & Shop Types
|
|
455
728
|
*
|
|
456
|
-
*
|
|
457
|
-
*
|
|
729
|
+
* Literal types for inventory system. Database row types are in @playcademy/data/types.
|
|
730
|
+
*
|
|
731
|
+
* @module types/inventory
|
|
732
|
+
*/
|
|
733
|
+
/**
|
|
734
|
+
* Item categories available on the platform.
|
|
458
735
|
*/
|
|
736
|
+
type ItemType = 'currency' | 'badge' | 'trophy' | 'collectible' | 'consumable' | 'unlock' | 'upgrade' | 'accessory' | 'other';
|
|
459
737
|
|
|
460
738
|
/**
|
|
461
|
-
*
|
|
462
|
-
* References upstream TimeBack types from @playcademy/timeback.
|
|
739
|
+
* Map & Placement Types
|
|
463
740
|
*
|
|
464
|
-
*
|
|
741
|
+
* Literal types and JSON shapes for maps. Database row types are in @playcademy/data/types.
|
|
742
|
+
*
|
|
743
|
+
* @module types/map
|
|
465
744
|
*/
|
|
466
|
-
interface TimebackBaseConfig {
|
|
467
|
-
/** Organization configuration (shared across all courses) */
|
|
468
|
-
organization?: Partial<OrganizationConfig>;
|
|
469
|
-
/** Course defaults (can be overridden per-course) */
|
|
470
|
-
course?: Partial<CourseConfig>;
|
|
471
|
-
/** Component defaults */
|
|
472
|
-
component?: Partial<ComponentConfig>;
|
|
473
|
-
/** Resource defaults */
|
|
474
|
-
resource?: Partial<ResourceConfig>;
|
|
475
|
-
/** ComponentResource defaults */
|
|
476
|
-
componentResource?: Partial<ComponentResourceConfig>;
|
|
477
|
-
}
|
|
478
745
|
/**
|
|
479
|
-
*
|
|
480
|
-
* Used in playcademy.config.* to allow per-course customization.
|
|
746
|
+
* Allowed map interaction types.
|
|
481
747
|
*/
|
|
482
|
-
|
|
748
|
+
type InteractionType = 'game_entry' | 'game_registry' | 'info' | 'teleport' | 'door_in' | 'door_out' | 'npc_interaction' | 'quest_trigger';
|
|
749
|
+
/**
|
|
750
|
+
* Metadata for interactive map elements.
|
|
751
|
+
*/
|
|
752
|
+
interface MapElementMetadata {
|
|
753
|
+
description?: string;
|
|
483
754
|
title?: string;
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
755
|
+
targetMapIdentifier?: string;
|
|
756
|
+
targetSpawnTileX?: number;
|
|
757
|
+
targetSpawnTileY?: number;
|
|
758
|
+
sourceTiledObjects?: Record<string, unknown>[];
|
|
759
|
+
[key: string]: unknown;
|
|
489
760
|
}
|
|
490
761
|
/**
|
|
491
|
-
*
|
|
492
|
-
*
|
|
493
|
-
* Supports two levels of customization:
|
|
494
|
-
* 1. `base`: Shared defaults for all courses (organization, course, component, resource, componentResource)
|
|
495
|
-
* 2. Per-course overrides in the `courses` array (title, courseCode, level, gradingScheme, metadata)
|
|
496
|
-
*
|
|
497
|
-
* Template variables ({grade}, {subject}, {gameSlug}) can be used in string fields.
|
|
762
|
+
* Metadata describing how an item should be placed on the map.
|
|
498
763
|
*/
|
|
499
|
-
interface
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
764
|
+
interface PlaceableItemMetadata {
|
|
765
|
+
tilesWide?: number;
|
|
766
|
+
tilesHigh?: number;
|
|
767
|
+
flippable?: boolean;
|
|
768
|
+
[key: string]: unknown;
|
|
504
769
|
}
|
|
505
770
|
/**
|
|
506
|
-
*
|
|
771
|
+
* Simplified map data for API responses.
|
|
507
772
|
*/
|
|
508
|
-
interface
|
|
509
|
-
|
|
510
|
-
|
|
773
|
+
interface MapData {
|
|
774
|
+
id: string;
|
|
775
|
+
identifier: string;
|
|
776
|
+
displayName: string;
|
|
777
|
+
description?: string | null;
|
|
778
|
+
metadata?: Record<string, unknown> | null;
|
|
511
779
|
}
|
|
512
780
|
/**
|
|
513
|
-
*
|
|
781
|
+
* Input for creating a map object.
|
|
514
782
|
*/
|
|
515
|
-
interface
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
maxRetries?: number;
|
|
525
|
-
maxBatchTimeout?: number;
|
|
526
|
-
maxConcurrency?: number;
|
|
527
|
-
retryDelay?: number;
|
|
528
|
-
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>;
|
|
529
792
|
}
|
|
793
|
+
|
|
530
794
|
/**
|
|
531
|
-
*
|
|
532
|
-
*
|
|
795
|
+
* Character & Avatar Types
|
|
796
|
+
*
|
|
797
|
+
* Literal types for character system. Database row types are in @playcademy/data/types.
|
|
798
|
+
*
|
|
799
|
+
* @module types/character
|
|
533
800
|
*/
|
|
534
|
-
interface IntegrationsConfig {
|
|
535
|
-
/** TimeBack integration (optional) */
|
|
536
|
-
timeback?: TimebackIntegrationConfig | null;
|
|
537
|
-
/** Custom API routes (optional) */
|
|
538
|
-
customRoutes?: CustomRoutesIntegration | boolean;
|
|
539
|
-
/** Database (optional) */
|
|
540
|
-
database?: DatabaseIntegration | boolean;
|
|
541
|
-
/** Key-Value storage (optional) */
|
|
542
|
-
kv?: boolean;
|
|
543
|
-
/** Bucket storage (optional) */
|
|
544
|
-
bucket?: boolean;
|
|
545
|
-
/** Authentication (optional) */
|
|
546
|
-
auth?: boolean;
|
|
547
|
-
/** Queues (optional) */
|
|
548
|
-
queues?: Record<string, QueueConfig | boolean>;
|
|
549
|
-
}
|
|
550
801
|
/**
|
|
551
|
-
*
|
|
552
|
-
* Used for playcademy.config.{js,json}
|
|
802
|
+
* Character component categories.
|
|
553
803
|
*/
|
|
554
|
-
|
|
555
|
-
/** Game name */
|
|
556
|
-
name: string;
|
|
557
|
-
/** Game description */
|
|
558
|
-
description?: string;
|
|
559
|
-
/** Game emoji icon */
|
|
560
|
-
emoji?: string;
|
|
561
|
-
/** Build command to run before deployment */
|
|
562
|
-
buildCommand?: string[];
|
|
563
|
-
/** Path to build output */
|
|
564
|
-
buildPath?: string;
|
|
565
|
-
/** Game type */
|
|
566
|
-
gameType?: 'hosted' | 'external';
|
|
567
|
-
/** External URL (for external games) */
|
|
568
|
-
externalUrl?: string;
|
|
569
|
-
/** Game platform */
|
|
570
|
-
platform?: 'web' | 'unity' | 'godot';
|
|
571
|
-
/** Integrations (database, custom routes, external services) */
|
|
572
|
-
integrations?: IntegrationsConfig;
|
|
573
|
-
}
|
|
804
|
+
type CharacterComponentType = 'body' | 'outfit' | 'hairstyle' | 'eyes' | 'accessory';
|
|
574
805
|
|
|
575
806
|
/**
|
|
576
|
-
*
|
|
807
|
+
* Level & Progression Types
|
|
577
808
|
*
|
|
578
|
-
* @
|
|
579
|
-
*
|
|
580
|
-
*
|
|
581
|
-
* apiKey: process.env.PLAYCADEMY_API_KEY!,
|
|
582
|
-
* gameId: 'my-math-game',
|
|
583
|
-
* configPath: './playcademy.config.js'
|
|
584
|
-
* }
|
|
585
|
-
* ```
|
|
809
|
+
* API response DTOs for level system. Database row types are in @playcademy/data/types.
|
|
810
|
+
*
|
|
811
|
+
* @module types/level
|
|
586
812
|
*/
|
|
587
|
-
interface PlaycademyServerClientConfig {
|
|
588
|
-
/**
|
|
589
|
-
* Playcademy API key for server-to-server authentication.
|
|
590
|
-
* Obtain from the Playcademy developer dashboard.
|
|
591
|
-
*/
|
|
592
|
-
apiKey: string;
|
|
593
|
-
/**
|
|
594
|
-
* Optional path to playcademy.config.js file.
|
|
595
|
-
* If not provided, searches current directory and up to 3 parent directories.
|
|
596
|
-
* Ignored if `config` is provided directly.
|
|
597
|
-
*
|
|
598
|
-
* @example './config/playcademy.config.js'
|
|
599
|
-
*/
|
|
600
|
-
configPath?: string;
|
|
601
|
-
/**
|
|
602
|
-
* Optional config object (for edge environments without filesystem).
|
|
603
|
-
* If provided, skips filesystem-based config loading.
|
|
604
|
-
*
|
|
605
|
-
* @example { name: 'My Game', integrations: { timeback: {...} } }
|
|
606
|
-
*/
|
|
607
|
-
config?: PlaycademyConfig;
|
|
608
|
-
/**
|
|
609
|
-
* Optional base URL for Playcademy API.
|
|
610
|
-
* Defaults to environment variables or 'https://hub.playcademy.net'.
|
|
611
|
-
*
|
|
612
|
-
* @example 'http://localhost:3000' for local development
|
|
613
|
-
*/
|
|
614
|
-
baseUrl?: string;
|
|
615
|
-
/**
|
|
616
|
-
* Optional game ID.
|
|
617
|
-
* If not provided, will attempt to fetch from API using the API token.
|
|
618
|
-
*
|
|
619
|
-
* @example 'my-math-game'
|
|
620
|
-
*/
|
|
621
|
-
gameId?: string;
|
|
622
|
-
}
|
|
623
813
|
/**
|
|
624
|
-
*
|
|
625
|
-
*
|
|
626
|
-
* @internal
|
|
814
|
+
* Result of adding XP to a user.
|
|
627
815
|
*/
|
|
628
|
-
interface
|
|
629
|
-
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
gameId: string;
|
|
635
|
-
/** Loaded game configuration from playcademy.config.js */
|
|
636
|
-
config: PlaycademyConfig;
|
|
637
|
-
/**
|
|
638
|
-
* TimeBack course ID fetched from the Playcademy API.
|
|
639
|
-
* Used for all TimeBack event recording.
|
|
640
|
-
*/
|
|
641
|
-
courseId?: string;
|
|
816
|
+
interface XPAddResult {
|
|
817
|
+
totalXP: number;
|
|
818
|
+
newLevel: number;
|
|
819
|
+
leveledUp: boolean;
|
|
820
|
+
creditsAwarded: number;
|
|
821
|
+
xpToNextLevel: number;
|
|
642
822
|
}
|
|
643
|
-
|
|
644
823
|
/**
|
|
645
|
-
*
|
|
646
|
-
*
|
|
647
|
-
* Enums, DTOs and API response types. Database row types are in @playcademy/data/types.
|
|
648
|
-
*
|
|
649
|
-
* @module types/user
|
|
824
|
+
* Result of checking whether a level up occurred.
|
|
650
825
|
*/
|
|
651
|
-
|
|
652
|
-
|
|
653
|
-
|
|
654
|
-
|
|
655
|
-
|
|
656
|
-
|
|
657
|
-
gameId?: string;
|
|
658
|
-
courseId: string;
|
|
659
|
-
grade: number;
|
|
660
|
-
subject: string;
|
|
661
|
-
orgId?: string;
|
|
662
|
-
}
|
|
663
|
-
interface UserOrganization {
|
|
664
|
-
id: string;
|
|
665
|
-
name: string | null;
|
|
666
|
-
type: TimebackOrgType | string;
|
|
667
|
-
isPrimary: boolean;
|
|
668
|
-
}
|
|
669
|
-
interface TimebackStudentProfile {
|
|
670
|
-
role: TimebackUserRole;
|
|
671
|
-
organizations: UserOrganization[];
|
|
672
|
-
}
|
|
673
|
-
interface UserTimebackData extends TimebackStudentProfile {
|
|
674
|
-
id: string;
|
|
675
|
-
enrollments: UserEnrollment[];
|
|
826
|
+
interface LevelUpCheckResult {
|
|
827
|
+
newLevel: number;
|
|
828
|
+
remainingXp: number;
|
|
829
|
+
leveledUp: boolean;
|
|
830
|
+
creditsAwarded: number;
|
|
831
|
+
xpToNextLevel: number;
|
|
676
832
|
}
|
|
677
833
|
/**
|
|
678
|
-
*
|
|
834
|
+
* Level progress API response.
|
|
679
835
|
*/
|
|
680
|
-
interface
|
|
681
|
-
|
|
682
|
-
|
|
683
|
-
|
|
684
|
-
|
|
685
|
-
given_name?: string;
|
|
686
|
-
family_name?: string;
|
|
687
|
-
issuer?: string;
|
|
688
|
-
lti_roles?: unknown;
|
|
689
|
-
lti_context?: unknown;
|
|
690
|
-
lti_resource_link?: unknown;
|
|
691
|
-
timeback_id?: string;
|
|
692
|
-
}
|
|
693
|
-
interface DeveloperStatusResponse {
|
|
694
|
-
status: DeveloperStatusEnumType;
|
|
695
|
-
}
|
|
696
|
-
interface DemoProfile {
|
|
697
|
-
displayName: string;
|
|
698
|
-
isDefault: boolean;
|
|
836
|
+
interface LevelProgressResponse {
|
|
837
|
+
level: number;
|
|
838
|
+
currentXp: number;
|
|
839
|
+
xpToNextLevel: number;
|
|
840
|
+
totalXP: number;
|
|
699
841
|
}
|
|
842
|
+
|
|
700
843
|
/**
|
|
701
|
-
*
|
|
844
|
+
* Notification Types
|
|
702
845
|
*
|
|
703
|
-
*
|
|
704
|
-
* automatically, but `displayName` is the only updatable field today and
|
|
705
|
-
* the server's `DemoProfileSchema` requires it — a no-field payload would
|
|
706
|
-
* 400 at runtime, so we model that at the type level too. When additional
|
|
707
|
-
* fields land, make them required/optional individually based on server
|
|
708
|
-
* validation, rather than blanket-optional.
|
|
846
|
+
* @module types/notification
|
|
709
847
|
*/
|
|
710
|
-
|
|
711
|
-
|
|
848
|
+
|
|
849
|
+
declare enum NotificationType {
|
|
850
|
+
ACHIEVEMENT = "achievement",
|
|
851
|
+
SYSTEM = "system",
|
|
852
|
+
PROMO = "promo"
|
|
712
853
|
}
|
|
713
|
-
|
|
714
|
-
|
|
715
|
-
|
|
716
|
-
|
|
717
|
-
|
|
718
|
-
|
|
719
|
-
|
|
720
|
-
emailVerified: boolean;
|
|
721
|
-
name: string | null;
|
|
722
|
-
image: string | null;
|
|
723
|
-
username: string | null;
|
|
724
|
-
role: UserRoleEnumType;
|
|
725
|
-
developerStatus: DeveloperStatusEnumType;
|
|
726
|
-
characterCreated: boolean;
|
|
727
|
-
createdAt: Date;
|
|
728
|
-
updatedAt: Date;
|
|
729
|
-
hasTimebackAccount: boolean;
|
|
730
|
-
timeback?: UserTimebackData;
|
|
854
|
+
declare enum NotificationStatus {
|
|
855
|
+
PENDING = "pending",
|
|
856
|
+
DELIVERED = "delivered",
|
|
857
|
+
SEEN = "seen",
|
|
858
|
+
CLICKED = "clicked",
|
|
859
|
+
DISMISSED = "dismissed",
|
|
860
|
+
EXPIRED = "expired"
|
|
731
861
|
}
|
|
732
|
-
interface
|
|
733
|
-
|
|
734
|
-
|
|
735
|
-
|
|
736
|
-
|
|
737
|
-
|
|
738
|
-
|
|
862
|
+
interface NotificationStats {
|
|
863
|
+
total: number;
|
|
864
|
+
delivered: number;
|
|
865
|
+
seen: number;
|
|
866
|
+
clicked: number;
|
|
867
|
+
dismissed: number;
|
|
868
|
+
expired: number;
|
|
869
|
+
clickThroughRate: number;
|
|
739
870
|
}
|
|
740
871
|
|
|
741
872
|
/**
|
|
742
|
-
*
|
|
743
|
-
*
|
|
744
|
-
* Literal types and API DTOs. Database row types are in @playcademy/data/types.
|
|
873
|
+
* Shop Types
|
|
745
874
|
*
|
|
746
|
-
* @module types/
|
|
875
|
+
* @module types/shop
|
|
747
876
|
*/
|
|
748
|
-
type GameType = 'hosted' | 'external';
|
|
749
|
-
type GamePlatform = 'web' | 'godot' | 'unity' | (string & {});
|
|
750
877
|
/**
|
|
751
|
-
*
|
|
752
|
-
* Note: createdAt is a string here because it's parsed from JSON file.
|
|
878
|
+
* Currency display info for shop UI.
|
|
753
879
|
*/
|
|
754
|
-
interface
|
|
755
|
-
|
|
756
|
-
|
|
757
|
-
|
|
758
|
-
|
|
759
|
-
|
|
760
|
-
vitePlugin?: string;
|
|
761
|
-
sdk?: string;
|
|
762
|
-
cli?: string;
|
|
763
|
-
vite?: string;
|
|
764
|
-
godotSdk?: string;
|
|
765
|
-
godot?: string;
|
|
766
|
-
}
|
|
767
|
-
interface ManifestV2 {
|
|
768
|
-
version: '2';
|
|
769
|
-
platform: string;
|
|
770
|
-
createdAt: string;
|
|
771
|
-
versions: ManifestVersions;
|
|
772
|
-
}
|
|
773
|
-
type GameManifest = ManifestV1 | ManifestV2;
|
|
774
|
-
interface DomainValidationRecords {
|
|
775
|
-
ownership?: {
|
|
776
|
-
name?: string;
|
|
777
|
-
value?: string;
|
|
778
|
-
type?: string;
|
|
779
|
-
};
|
|
780
|
-
ssl?: {
|
|
781
|
-
txt_name?: string;
|
|
782
|
-
txt_value?: string;
|
|
783
|
-
}[];
|
|
880
|
+
interface ShopCurrency {
|
|
881
|
+
id: string;
|
|
882
|
+
symbol: string | null;
|
|
883
|
+
isPrimary: boolean;
|
|
884
|
+
displayName?: string | null;
|
|
885
|
+
imageUrl?: string | null;
|
|
784
886
|
}
|
|
785
|
-
|
|
786
887
|
/**
|
|
787
|
-
*
|
|
788
|
-
*
|
|
789
|
-
* @module types/leaderboard
|
|
888
|
+
* Shop item for display.
|
|
889
|
+
* Combines Item fields (excluding createdAt) with shop listing data.
|
|
790
890
|
*/
|
|
791
|
-
|
|
792
|
-
interface LeaderboardOptions {
|
|
793
|
-
timeframe?: LeaderboardTimeframe;
|
|
794
|
-
limit?: number;
|
|
795
|
-
offset?: number;
|
|
796
|
-
gameId?: string;
|
|
797
|
-
}
|
|
798
|
-
interface LeaderboardEntry {
|
|
799
|
-
rank: number;
|
|
800
|
-
userId: string;
|
|
801
|
-
username: string;
|
|
802
|
-
userImage?: string | null;
|
|
803
|
-
score: number;
|
|
804
|
-
achievedAt: Date;
|
|
805
|
-
metadata?: Record<string, unknown>;
|
|
806
|
-
gameId?: string;
|
|
807
|
-
gameTitle?: string;
|
|
808
|
-
gameSlug?: string;
|
|
809
|
-
}
|
|
810
|
-
interface UserRank {
|
|
811
|
-
rank: number;
|
|
812
|
-
totalPlayers: number;
|
|
813
|
-
score: number;
|
|
814
|
-
percentile: number;
|
|
815
|
-
}
|
|
816
|
-
interface UserRankResponse {
|
|
817
|
-
rank: number;
|
|
818
|
-
score: number;
|
|
819
|
-
userId: string;
|
|
820
|
-
}
|
|
821
|
-
interface UserScore {
|
|
891
|
+
interface ShopDisplayItem {
|
|
822
892
|
id: string;
|
|
823
|
-
|
|
824
|
-
|
|
825
|
-
|
|
826
|
-
|
|
827
|
-
|
|
828
|
-
|
|
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;
|
|
829
909
|
}
|
|
830
910
|
/**
|
|
831
|
-
*
|
|
832
|
-
* Used when fetching leaderboards for a specific game.
|
|
911
|
+
* Complete shop view response.
|
|
833
912
|
*/
|
|
834
|
-
interface
|
|
835
|
-
|
|
836
|
-
|
|
837
|
-
username: string;
|
|
838
|
-
userImage?: string | null;
|
|
839
|
-
score: number;
|
|
840
|
-
achievedAt: Date;
|
|
841
|
-
metadata?: Record<string, unknown>;
|
|
842
|
-
gameId: string;
|
|
843
|
-
gameTitle: string;
|
|
844
|
-
gameSlug: string;
|
|
913
|
+
interface ShopViewResponse {
|
|
914
|
+
shopItems: ShopDisplayItem[];
|
|
915
|
+
currencies: ShopCurrency[];
|
|
845
916
|
}
|
|
846
917
|
|
|
847
918
|
/**
|
|
848
|
-
*
|
|
919
|
+
* Sprite Types
|
|
849
920
|
*
|
|
850
|
-
*
|
|
921
|
+
* JSON shapes for sprite configuration. Database row types are in @playcademy/data/types.
|
|
922
|
+
*
|
|
923
|
+
* @module types/sprite
|
|
851
924
|
*/
|
|
852
|
-
|
|
853
|
-
|
|
854
|
-
|
|
855
|
-
|
|
856
|
-
|
|
857
|
-
|
|
858
|
-
|
|
859
|
-
|
|
860
|
-
interface AchievementCurrent {
|
|
861
|
-
id: string;
|
|
862
|
-
title: string;
|
|
863
|
-
description?: string | null;
|
|
864
|
-
scope: AchievementScopeType;
|
|
865
|
-
rewardCredits: number;
|
|
866
|
-
limit: number;
|
|
867
|
-
completionType: string;
|
|
868
|
-
completionConfig: unknown;
|
|
869
|
-
target: unknown;
|
|
870
|
-
active: boolean;
|
|
871
|
-
createdAt?: Date | null;
|
|
872
|
-
updatedAt?: Date | null;
|
|
873
|
-
status: 'available' | 'completed';
|
|
874
|
-
scopeKey: string;
|
|
875
|
-
windowStart: string;
|
|
876
|
-
windowEnd: string;
|
|
877
|
-
}
|
|
878
|
-
interface AchievementWithStatus {
|
|
879
|
-
id: string;
|
|
880
|
-
title: string;
|
|
881
|
-
description: string | null;
|
|
882
|
-
scope: AchievementScopeType;
|
|
883
|
-
rewardCredits: number;
|
|
884
|
-
limit: number;
|
|
885
|
-
completionType: string;
|
|
886
|
-
completionConfig: unknown;
|
|
887
|
-
target: unknown;
|
|
888
|
-
active: boolean;
|
|
889
|
-
createdAt: Date | null;
|
|
890
|
-
updatedAt: Date | null;
|
|
891
|
-
status: 'available' | 'completed';
|
|
892
|
-
scopeKey: string;
|
|
893
|
-
windowStart?: string;
|
|
894
|
-
windowEnd?: string;
|
|
925
|
+
/**
|
|
926
|
+
* Animation frame configuration.
|
|
927
|
+
*/
|
|
928
|
+
interface SpriteAnimationFrame {
|
|
929
|
+
row: number;
|
|
930
|
+
frameStart: number;
|
|
931
|
+
numFrames: number;
|
|
932
|
+
fps: number;
|
|
895
933
|
}
|
|
896
|
-
|
|
897
|
-
|
|
898
|
-
|
|
899
|
-
|
|
900
|
-
|
|
901
|
-
|
|
934
|
+
/**
|
|
935
|
+
* Sprite template data structure (stored in JSONB).
|
|
936
|
+
*/
|
|
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
|
+
};
|
|
902
957
|
}
|
|
903
|
-
|
|
904
|
-
|
|
905
|
-
|
|
906
|
-
|
|
907
|
-
|
|
908
|
-
|
|
958
|
+
/**
|
|
959
|
+
* Sprite sheet configuration with precomputed dimensions.
|
|
960
|
+
*/
|
|
961
|
+
interface SpriteConfigWithDimensions {
|
|
962
|
+
textureUrl: string;
|
|
963
|
+
columns: number;
|
|
964
|
+
rows: number;
|
|
965
|
+
spriteWidth: number;
|
|
966
|
+
spriteHeight: number;
|
|
967
|
+
animations: Record<string, SpriteAnimationFrame>;
|
|
909
968
|
}
|
|
910
969
|
|
|
911
970
|
/**
|
|
912
|
-
*
|
|
913
|
-
*
|
|
914
|
-
* Literal types for inventory system. Database row types are in @playcademy/data/types.
|
|
971
|
+
* Connection monitoring types
|
|
915
972
|
*
|
|
916
|
-
*
|
|
973
|
+
* Type definitions for connection state, configuration, and callbacks.
|
|
917
974
|
*/
|
|
918
975
|
/**
|
|
919
|
-
*
|
|
976
|
+
* Possible connection states.
|
|
977
|
+
*
|
|
978
|
+
* - **online**: Connection is stable and healthy
|
|
979
|
+
* - **offline**: Complete loss of network connectivity
|
|
980
|
+
* - **degraded**: Connection is slow or experiencing intermittent issues
|
|
920
981
|
*/
|
|
921
|
-
type
|
|
982
|
+
type ConnectionState = 'online' | 'offline' | 'degraded';
|
|
922
983
|
|
|
923
984
|
/**
|
|
924
|
-
*
|
|
985
|
+
* Connection Manager
|
|
925
986
|
*
|
|
926
|
-
*
|
|
987
|
+
* Manages connection monitoring and integrates it with the Playcademy client.
|
|
988
|
+
* Handles event wiring, state management, and disconnect callbacks.
|
|
927
989
|
*
|
|
928
|
-
*
|
|
990
|
+
* In iframe mode, disables local monitoring and listens to platform connection
|
|
991
|
+
* state broadcasts instead (avoids duplicate heartbeats).
|
|
929
992
|
*/
|
|
993
|
+
|
|
930
994
|
/**
|
|
931
|
-
*
|
|
995
|
+
* Configuration for the ConnectionManager.
|
|
932
996
|
*/
|
|
933
|
-
|
|
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;
|
|
1008
|
+
}
|
|
934
1009
|
/**
|
|
935
|
-
*
|
|
936
|
-
|
|
937
|
-
|
|
938
|
-
|
|
939
|
-
|
|
940
|
-
|
|
941
|
-
|
|
942
|
-
|
|
943
|
-
|
|
944
|
-
|
|
945
|
-
|
|
946
|
-
|
|
947
|
-
*
|
|
948
|
-
|
|
949
|
-
interface PlaceableItemMetadata {
|
|
950
|
-
tilesWide?: number;
|
|
951
|
-
tilesHigh?: number;
|
|
952
|
-
flippable?: boolean;
|
|
953
|
-
[key: string]: unknown;
|
|
954
|
-
}
|
|
955
|
-
/**
|
|
956
|
-
* Simplified map data for API responses.
|
|
957
|
-
*/
|
|
958
|
-
interface MapData {
|
|
959
|
-
id: string;
|
|
960
|
-
identifier: string;
|
|
961
|
-
displayName: string;
|
|
962
|
-
description?: string | null;
|
|
963
|
-
metadata?: Record<string, unknown> | null;
|
|
964
|
-
}
|
|
965
|
-
/**
|
|
966
|
-
* 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
|
|
967
1024
|
*/
|
|
968
|
-
|
|
969
|
-
|
|
970
|
-
|
|
971
|
-
|
|
972
|
-
|
|
973
|
-
|
|
974
|
-
|
|
975
|
-
|
|
976
|
-
|
|
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;
|
|
977
1156
|
}
|
|
978
1157
|
|
|
979
1158
|
/**
|
|
980
|
-
*
|
|
1159
|
+
* @fileoverview Playcademy Messaging System
|
|
981
1160
|
*
|
|
982
|
-
*
|
|
1161
|
+
* This file implements a unified messaging system for the Playcademy platform that handles
|
|
1162
|
+
* communication between different contexts:
|
|
983
1163
|
*
|
|
984
|
-
*
|
|
985
|
-
|
|
986
|
-
/**
|
|
987
|
-
* Character component categories.
|
|
988
|
-
*/
|
|
989
|
-
type CharacterComponentType = 'body' | 'outfit' | 'hairstyle' | 'eyes' | 'accessory';
|
|
990
|
-
|
|
991
|
-
/**
|
|
992
|
-
* 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
|
|
993
1166
|
*
|
|
994
|
-
*
|
|
1167
|
+
* 2. **Local Communication**: When games run in the same context (local development),
|
|
1168
|
+
* they use CustomEvents for internal messaging
|
|
995
1169
|
*
|
|
996
|
-
*
|
|
997
|
-
|
|
998
|
-
|
|
999
|
-
*
|
|
1000
|
-
|
|
1001
|
-
|
|
1002
|
-
|
|
1003
|
-
|
|
1004
|
-
leveledUp: boolean;
|
|
1005
|
-
creditsAwarded: number;
|
|
1006
|
-
xpToNextLevel: number;
|
|
1007
|
-
}
|
|
1008
|
-
/**
|
|
1009
|
-
* Result of checking whether a level up occurred.
|
|
1010
|
-
*/
|
|
1011
|
-
interface LevelUpCheckResult {
|
|
1012
|
-
newLevel: number;
|
|
1013
|
-
remainingXp: number;
|
|
1014
|
-
leveledUp: boolean;
|
|
1015
|
-
creditsAwarded: number;
|
|
1016
|
-
xpToNextLevel: number;
|
|
1017
|
-
}
|
|
1018
|
-
/**
|
|
1019
|
-
* 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
|
|
1020
1178
|
*/
|
|
1021
|
-
interface LevelProgressResponse {
|
|
1022
|
-
level: number;
|
|
1023
|
-
currentXp: number;
|
|
1024
|
-
xpToNextLevel: number;
|
|
1025
|
-
totalXP: number;
|
|
1026
|
-
}
|
|
1027
1179
|
|
|
1028
1180
|
/**
|
|
1029
|
-
*
|
|
1181
|
+
* Enumeration of all message types used in the Playcademy messaging system.
|
|
1030
1182
|
*
|
|
1031
|
-
*
|
|
1032
|
-
|
|
1033
|
-
|
|
1034
|
-
|
|
1035
|
-
|
|
1036
|
-
|
|
1037
|
-
|
|
1038
|
-
|
|
1039
|
-
|
|
1040
|
-
|
|
1041
|
-
|
|
1042
|
-
|
|
1043
|
-
|
|
1044
|
-
|
|
1045
|
-
|
|
1046
|
-
|
|
1047
|
-
|
|
1048
|
-
|
|
1049
|
-
|
|
1050
|
-
|
|
1051
|
-
|
|
1052
|
-
|
|
1053
|
-
|
|
1054
|
-
|
|
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"
|
|
1055
1319
|
}
|
|
1056
1320
|
|
|
1057
1321
|
/**
|
|
1058
|
-
*
|
|
1059
|
-
*
|
|
1060
|
-
* @module types/shop
|
|
1322
|
+
* Cache configuration types for runtime customization
|
|
1061
1323
|
*/
|
|
1062
1324
|
/**
|
|
1063
|
-
*
|
|
1325
|
+
* Runtime configuration for TTL cache behavior
|
|
1064
1326
|
*/
|
|
1065
|
-
interface
|
|
1066
|
-
|
|
1067
|
-
|
|
1068
|
-
|
|
1069
|
-
|
|
1070
|
-
|
|
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;
|
|
1071
1334
|
}
|
|
1335
|
+
|
|
1072
1336
|
/**
|
|
1073
|
-
*
|
|
1074
|
-
*
|
|
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.
|
|
1075
1341
|
*/
|
|
1076
|
-
|
|
1077
|
-
|
|
1078
|
-
|
|
1079
|
-
|
|
1080
|
-
|
|
1081
|
-
|
|
1082
|
-
|
|
1083
|
-
|
|
1084
|
-
|
|
1085
|
-
|
|
1086
|
-
|
|
1087
|
-
|
|
1088
|
-
|
|
1089
|
-
|
|
1090
|
-
|
|
1091
|
-
|
|
1092
|
-
|
|
1093
|
-
|
|
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>;
|
|
1094
1360
|
}
|
|
1095
1361
|
/**
|
|
1096
|
-
*
|
|
1362
|
+
* Extended course configuration that merges TimebackCourseConfig with per-course overrides.
|
|
1363
|
+
* Used in playcademy.config.* to allow per-course customization.
|
|
1097
1364
|
*/
|
|
1098
|
-
interface
|
|
1099
|
-
|
|
1100
|
-
|
|
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;
|
|
1101
1372
|
}
|
|
1102
|
-
|
|
1103
1373
|
/**
|
|
1104
|
-
*
|
|
1374
|
+
* TimeBack integration configuration for Playcademy config file.
|
|
1105
1375
|
*
|
|
1106
|
-
*
|
|
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)
|
|
1107
1379
|
*
|
|
1108
|
-
*
|
|
1380
|
+
* Template variables ({grade}, {subject}, {gameSlug}) can be used in string fields.
|
|
1109
1381
|
*/
|
|
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;
|
|
1387
|
+
}
|
|
1110
1388
|
/**
|
|
1111
|
-
*
|
|
1389
|
+
* Custom API routes integration
|
|
1112
1390
|
*/
|
|
1113
|
-
interface
|
|
1114
|
-
|
|
1115
|
-
|
|
1116
|
-
numFrames: number;
|
|
1117
|
-
fps: number;
|
|
1391
|
+
interface CustomRoutesIntegration {
|
|
1392
|
+
/** Directory for custom API routes (defaults to 'server/api') */
|
|
1393
|
+
directory?: string;
|
|
1118
1394
|
}
|
|
1119
1395
|
/**
|
|
1120
|
-
*
|
|
1396
|
+
* Database integration
|
|
1121
1397
|
*/
|
|
1122
|
-
interface
|
|
1123
|
-
|
|
1124
|
-
|
|
1125
|
-
|
|
1126
|
-
|
|
1127
|
-
|
|
1128
|
-
|
|
1129
|
-
|
|
1130
|
-
|
|
1131
|
-
|
|
1132
|
-
|
|
1133
|
-
|
|
1134
|
-
|
|
1135
|
-
|
|
1136
|
-
walk_up: SpriteAnimationFrame;
|
|
1137
|
-
idle_left: SpriteAnimationFrame;
|
|
1138
|
-
walk_left: SpriteAnimationFrame;
|
|
1139
|
-
idle_down: SpriteAnimationFrame;
|
|
1140
|
-
walk_down: SpriteAnimationFrame;
|
|
1141
|
-
};
|
|
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;
|
|
1142
1412
|
}
|
|
1143
1413
|
/**
|
|
1144
|
-
*
|
|
1414
|
+
* Integrations configuration
|
|
1415
|
+
* All backend features (database, custom routes, external services) are configured here
|
|
1145
1416
|
*/
|
|
1146
|
-
interface
|
|
1147
|
-
|
|
1148
|
-
|
|
1149
|
-
|
|
1150
|
-
|
|
1151
|
-
|
|
1152
|
-
|
|
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;
|
|
1153
1525
|
}
|
|
1154
1526
|
|
|
1155
1527
|
declare const users: drizzle_orm_pg_core.PgTableWithColumns<{
|
|
@@ -3970,7 +4342,7 @@ declare const UpsertGameMetadataSchema: z.ZodEffects<z.ZodObject<{
|
|
|
3970
4342
|
displayName: z.ZodString;
|
|
3971
4343
|
mapElementId: z.ZodNullable<z.ZodOptional<z.ZodString>>;
|
|
3972
4344
|
platform: z.ZodEnum<["web", "godot", "unity"]>;
|
|
3973
|
-
metadata: z.ZodDefault<z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnknown
|
|
4345
|
+
metadata: z.ZodDefault<z.ZodOptional<z.ZodEffects<z.ZodRecord<z.ZodString, z.ZodUnknown>, Record<string, unknown>, Record<string, unknown>>>>;
|
|
3974
4346
|
gameType: z.ZodDefault<z.ZodOptional<z.ZodEnum<["hosted", "external"]>>>;
|
|
3975
4347
|
visibility: z.ZodOptional<z.ZodEnum<["visible", "unlisted", "internal"]>>;
|
|
3976
4348
|
externalUrl: z.ZodOptional<z.ZodString>;
|
|
@@ -4648,480 +5020,64 @@ interface PlayerInventoryItem {
|
|
|
4648
5020
|
inventoryItemEntryId: InventoryItemRow['id'];
|
|
4649
5021
|
item: ItemRow;
|
|
4650
5022
|
quantity: InventoryItemRow['quantity'];
|
|
4651
|
-
updatedAt: InventoryItemRow['updatedAt'];
|
|
4652
|
-
}
|
|
4653
|
-
interface PlayerLocation {
|
|
4654
|
-
mapIdentifier: MapRow['identifier'];
|
|
4655
|
-
mapDisplayName: MapRow['displayName'];
|
|
4656
|
-
tileX?: number;
|
|
4657
|
-
tileY?: number;
|
|
4658
|
-
worldX?: number;
|
|
4659
|
-
worldY?: number;
|
|
4660
|
-
direction?: 'up' | 'down' | 'left' | 'right';
|
|
4661
|
-
}
|
|
4662
|
-
interface PlayerSessionPayload {
|
|
4663
|
-
profile: PlayerProfile;
|
|
4664
|
-
currencies: PlayerCurrency[];
|
|
4665
|
-
inventory: PlayerInventoryItem[];
|
|
4666
|
-
ownedGameIds: Game['id'][];
|
|
4667
|
-
currentLocation?: PlayerLocation;
|
|
4668
|
-
characterCreated?: UserRow['characterCreated'];
|
|
4669
|
-
playerCharacter?: PlayerCharacterRow | null;
|
|
4670
|
-
}
|
|
4671
|
-
/**
|
|
4672
|
-
* Map-related Composite Types
|
|
4673
|
-
* DB row + joined game/item data
|
|
4674
|
-
*/
|
|
4675
|
-
type MapElementWithGame = MapElementRow & {
|
|
4676
|
-
game: {
|
|
4677
|
-
id: string;
|
|
4678
|
-
displayName: string;
|
|
4679
|
-
} | null;
|
|
4680
|
-
};
|
|
4681
|
-
type MapObjectWithItem = MapObjectRow & {
|
|
4682
|
-
item: {
|
|
4683
|
-
id: string;
|
|
4684
|
-
slug: string;
|
|
4685
|
-
displayName: string;
|
|
4686
|
-
description?: string | null;
|
|
4687
|
-
imageUrl?: string | null;
|
|
4688
|
-
isPlaceable: boolean;
|
|
4689
|
-
metadata?: PlaceableItemMetadata | null;
|
|
4690
|
-
};
|
|
4691
|
-
};
|
|
4692
|
-
/**
|
|
4693
|
-
* Game custom hostname with validation records
|
|
4694
|
-
*/
|
|
4695
|
-
type GameCustomHostname = GameCustomHostnameRow & {
|
|
4696
|
-
validationRecords?: DomainValidationRecords;
|
|
4697
|
-
};
|
|
4698
|
-
|
|
4699
|
-
type UserLevelRow = typeof userLevels.$inferSelect;
|
|
4700
|
-
type LevelConfigRow = typeof levelConfigs.$inferSelect;
|
|
4701
|
-
type UserLevelWithConfig = UserLevelRow & {
|
|
4702
|
-
xpToNextLevel: number;
|
|
4703
|
-
nextLevelConfig?: LevelConfigRow;
|
|
4704
|
-
};
|
|
4705
|
-
|
|
4706
|
-
type SpriteTemplateRow = typeof spriteTemplates.$inferSelect;
|
|
4707
|
-
|
|
4708
|
-
type NotificationRow = InferSelectModel<typeof notifications>;
|
|
4709
|
-
|
|
4710
|
-
/**
|
|
4711
|
-
* Connection monitoring types
|
|
4712
|
-
*
|
|
4713
|
-
* Type definitions for connection state, configuration, and callbacks.
|
|
4714
|
-
*/
|
|
4715
|
-
/**
|
|
4716
|
-
* Possible connection states.
|
|
4717
|
-
*
|
|
4718
|
-
* - **online**: Connection is stable and healthy
|
|
4719
|
-
* - **offline**: Complete loss of network connectivity
|
|
4720
|
-
* - **degraded**: Connection is slow or experiencing intermittent issues
|
|
4721
|
-
*/
|
|
4722
|
-
type ConnectionState = 'online' | 'offline' | 'degraded';
|
|
4723
|
-
|
|
4724
|
-
/**
|
|
4725
|
-
* Connection Manager
|
|
4726
|
-
*
|
|
4727
|
-
* Manages connection monitoring and integrates it with the Playcademy client.
|
|
4728
|
-
* Handles event wiring, state management, and disconnect callbacks.
|
|
4729
|
-
*
|
|
4730
|
-
* In iframe mode, disables local monitoring and listens to platform connection
|
|
4731
|
-
* state broadcasts instead (avoids duplicate heartbeats).
|
|
4732
|
-
*/
|
|
4733
|
-
|
|
4734
|
-
/**
|
|
4735
|
-
* Configuration for the ConnectionManager.
|
|
4736
|
-
*/
|
|
4737
|
-
interface ConnectionManagerConfig {
|
|
4738
|
-
/** Base URL for API requests (used for heartbeat pings) */
|
|
4739
|
-
baseUrl: string;
|
|
4740
|
-
/** Authentication context (iframe vs standalone) for alert routing */
|
|
4741
|
-
authContext?: {
|
|
4742
|
-
isInIframe: boolean;
|
|
4743
|
-
};
|
|
4744
|
-
/** Handler to call when connection issues are detected */
|
|
4745
|
-
onDisconnect?: DisconnectHandler;
|
|
4746
|
-
/** Callback to emit connection change events to the client */
|
|
4747
|
-
onConnectionChange?: (state: ConnectionState, reason: string) => void;
|
|
4748
|
-
}
|
|
4749
|
-
/**
|
|
4750
|
-
* Manages connection monitoring for the Playcademy client.
|
|
4751
|
-
*
|
|
4752
|
-
* The ConnectionManager serves as an integration layer between the low-level
|
|
4753
|
-
* ConnectionMonitor and the PlaycademyClient. It handles:
|
|
4754
|
-
* - Event wiring and coordination
|
|
4755
|
-
* - Disconnect callbacks with context
|
|
4756
|
-
* - Platform-level alert integration
|
|
4757
|
-
* - Request success/failure tracking
|
|
4758
|
-
*
|
|
4759
|
-
* This class is used internally by PlaycademyClient and typically not
|
|
4760
|
-
* instantiated directly by game developers.
|
|
4761
|
-
*
|
|
4762
|
-
* @see {@link ConnectionMonitor} for the underlying monitoring implementation
|
|
4763
|
-
* @see {@link PlaycademyClient.onDisconnect} for the public API
|
|
4764
|
-
*/
|
|
4765
|
-
declare class ConnectionManager {
|
|
4766
|
-
private monitor?;
|
|
4767
|
-
private authContext?;
|
|
4768
|
-
private disconnectHandler?;
|
|
4769
|
-
private connectionChangeCallback?;
|
|
4770
|
-
private currentState;
|
|
4771
|
-
private additionalDisconnectHandlers;
|
|
4772
|
-
/**
|
|
4773
|
-
* Creates a new ConnectionManager instance.
|
|
4774
|
-
*
|
|
4775
|
-
* @param config - Configuration options for the manager
|
|
4776
|
-
*
|
|
4777
|
-
* @example
|
|
4778
|
-
* ```typescript
|
|
4779
|
-
* const manager = new ConnectionManager({
|
|
4780
|
-
* baseUrl: 'https://api.playcademy.com',
|
|
4781
|
-
* authContext: { isInIframe: false },
|
|
4782
|
-
* onDisconnect: (context) => {
|
|
4783
|
-
* console.log(`Disconnected: ${context.state}`)
|
|
4784
|
-
* },
|
|
4785
|
-
* onConnectionChange: (state, reason) => {
|
|
4786
|
-
* console.log(`Connection changed: ${state}`)
|
|
4787
|
-
* }
|
|
4788
|
-
* })
|
|
4789
|
-
* ```
|
|
4790
|
-
*/
|
|
4791
|
-
constructor(config: ConnectionManagerConfig);
|
|
4792
|
-
/**
|
|
4793
|
-
* Gets the current connection state.
|
|
4794
|
-
*
|
|
4795
|
-
* @returns The current connection state ('online', 'offline', or 'degraded')
|
|
4796
|
-
*
|
|
4797
|
-
* @example
|
|
4798
|
-
* ```typescript
|
|
4799
|
-
* const state = manager.getState()
|
|
4800
|
-
* if (state === 'offline') {
|
|
4801
|
-
* console.log('No connection')
|
|
4802
|
-
* }
|
|
4803
|
-
* ```
|
|
4804
|
-
*/
|
|
4805
|
-
getState(): ConnectionState;
|
|
4806
|
-
/**
|
|
4807
|
-
* Manually triggers a connection check immediately.
|
|
4808
|
-
*
|
|
4809
|
-
* Forces a heartbeat ping to verify the current connection status.
|
|
4810
|
-
* Useful when you need to check connectivity before a critical operation.
|
|
4811
|
-
*
|
|
4812
|
-
* In iframe mode, this returns the last known state from platform.
|
|
4813
|
-
*
|
|
4814
|
-
* @returns Promise resolving to the current connection state
|
|
4815
|
-
*
|
|
4816
|
-
* @example
|
|
4817
|
-
* ```typescript
|
|
4818
|
-
* const state = await manager.checkNow()
|
|
4819
|
-
* if (state === 'online') {
|
|
4820
|
-
* await performCriticalOperation()
|
|
4821
|
-
* }
|
|
4822
|
-
* ```
|
|
4823
|
-
*/
|
|
4824
|
-
checkNow(): Promise<ConnectionState>;
|
|
4825
|
-
/**
|
|
4826
|
-
* Reports a successful API request to the connection monitor.
|
|
4827
|
-
*
|
|
4828
|
-
* This resets the consecutive failure counter and transitions from
|
|
4829
|
-
* 'degraded' to 'online' state if applicable.
|
|
4830
|
-
*
|
|
4831
|
-
* Typically called automatically by the SDK's request wrapper.
|
|
4832
|
-
* No-op in iframe mode (platform handles monitoring).
|
|
4833
|
-
*/
|
|
4834
|
-
reportRequestSuccess(): void;
|
|
4835
|
-
/**
|
|
4836
|
-
* Reports a failed API request to the connection monitor.
|
|
4837
|
-
*
|
|
4838
|
-
* Only network errors are tracked (not 4xx/5xx HTTP responses).
|
|
4839
|
-
* After consecutive failures exceed the threshold, the state transitions
|
|
4840
|
-
* to 'degraded' or 'offline'.
|
|
4841
|
-
*
|
|
4842
|
-
* Typically called automatically by the SDK's request wrapper.
|
|
4843
|
-
* No-op in iframe mode (platform handles monitoring).
|
|
4844
|
-
*
|
|
4845
|
-
* @param error - The error from the failed request
|
|
4846
|
-
*/
|
|
4847
|
-
reportRequestFailure(error: unknown): void;
|
|
4848
|
-
/**
|
|
4849
|
-
* Registers a callback to be called when connection issues are detected.
|
|
4850
|
-
*
|
|
4851
|
-
* The callback only fires for 'offline' and 'degraded' states, not when
|
|
4852
|
-
* recovering to 'online'. This provides a clean API for games to handle
|
|
4853
|
-
* disconnect scenarios without being notified of every state change.
|
|
4854
|
-
*
|
|
4855
|
-
* Works in both iframe and standalone modes transparently.
|
|
4856
|
-
*
|
|
4857
|
-
* @param callback - Function to call when connection degrades
|
|
4858
|
-
* @returns Cleanup function to unregister the callback
|
|
4859
|
-
*
|
|
4860
|
-
* @example
|
|
4861
|
-
* ```typescript
|
|
4862
|
-
* const cleanup = manager.onDisconnect(({ state, reason, displayAlert }) => {
|
|
4863
|
-
* if (state === 'offline') {
|
|
4864
|
-
* displayAlert?.('Connection lost. Saving your progress...', { type: 'error' })
|
|
4865
|
-
* saveGameState()
|
|
4866
|
-
* }
|
|
4867
|
-
* })
|
|
4868
|
-
*
|
|
4869
|
-
* // Later: cleanup() to unregister
|
|
4870
|
-
* ```
|
|
4871
|
-
*/
|
|
4872
|
-
onDisconnect(callback: DisconnectHandler): () => void;
|
|
4873
|
-
/**
|
|
4874
|
-
* Stops connection monitoring and performs cleanup.
|
|
4875
|
-
*
|
|
4876
|
-
* Removes event listeners and clears heartbeat intervals.
|
|
4877
|
-
* Should be called when the client is being destroyed.
|
|
4878
|
-
*/
|
|
4879
|
-
stop(): void;
|
|
4880
|
-
/**
|
|
4881
|
-
* Sets up listener for platform connection state broadcasts (iframe mode only).
|
|
4882
|
-
*/
|
|
4883
|
-
private _setupPlatformListener;
|
|
4884
|
-
/**
|
|
4885
|
-
* Handles connection state changes from the monitor or platform.
|
|
4886
|
-
*
|
|
4887
|
-
* Coordinates between:
|
|
4888
|
-
* 1. Emitting events to the client (for client.on('connectionChange'))
|
|
4889
|
-
* 2. Calling the disconnect handler if configured
|
|
4890
|
-
* 3. Calling any additional handlers registered via onDisconnect()
|
|
4891
|
-
*
|
|
4892
|
-
* @param state - The new connection state
|
|
4893
|
-
* @param reason - Human-readable reason for the state change
|
|
4894
|
-
*/
|
|
4895
|
-
private _handleConnectionChange;
|
|
4896
|
-
}
|
|
4897
|
-
|
|
4898
|
-
/**
|
|
4899
|
-
* @fileoverview Playcademy Messaging System
|
|
4900
|
-
*
|
|
4901
|
-
* This file implements a unified messaging system for the Playcademy platform that handles
|
|
4902
|
-
* communication between different contexts:
|
|
4903
|
-
*
|
|
4904
|
-
* 1. **Iframe-to-Parent Communication**: When games run inside iframes (production/development),
|
|
4905
|
-
* they need to communicate with the parent window using postMessage API
|
|
4906
|
-
*
|
|
4907
|
-
* 2. **Local Communication**: When games run in the same context (local development),
|
|
4908
|
-
* they use CustomEvents for internal messaging
|
|
4909
|
-
*
|
|
4910
|
-
* The system automatically detects the runtime environment and chooses the appropriate
|
|
4911
|
-
* transport method, abstracting this complexity from the developer.
|
|
4912
|
-
*
|
|
4913
|
-
* **Architecture Overview**:
|
|
4914
|
-
* - Games run in iframes for security and isolation
|
|
4915
|
-
* - Parent window (Playcademy shell) manages game lifecycle
|
|
4916
|
-
* - Messages flow bidirectionally between parent and iframe
|
|
4917
|
-
* - Local development mode simulates this architecture without iframes
|
|
4918
|
-
*/
|
|
4919
|
-
|
|
4920
|
-
/**
|
|
4921
|
-
* Enumeration of all message types used in the Playcademy messaging system.
|
|
4922
|
-
*
|
|
4923
|
-
* **Message Flow Patterns**:
|
|
4924
|
-
*
|
|
4925
|
-
* **Parent → Game (Overworld → Game)**:
|
|
4926
|
-
* - INIT: Provides game with authentication token and configuration
|
|
4927
|
-
* - TOKEN_REFRESH: Updates game's authentication token before expiry
|
|
4928
|
-
* - PAUSE/RESUME: Controls game execution state
|
|
4929
|
-
* - FORCE_EXIT: Immediately terminates the game
|
|
4930
|
-
* - OVERLAY: Shows/hides UI overlays over the game
|
|
4931
|
-
*
|
|
4932
|
-
* **Game → Parent (Game → Overworld)**:
|
|
4933
|
-
* - READY: Game has loaded and is ready to receive messages
|
|
4934
|
-
* - EXIT: Game requests to be closed (user clicked exit, game ended, etc.)
|
|
4935
|
-
* - TELEMETRY: Game reports performance metrics (FPS, memory usage, etc.)
|
|
4936
|
-
*/
|
|
4937
|
-
declare enum MessageEvents {
|
|
4938
|
-
/**
|
|
4939
|
-
* Initializes the game with authentication context and configuration.
|
|
4940
|
-
* Sent immediately after game iframe loads.
|
|
4941
|
-
* Payload:
|
|
4942
|
-
* - `baseUrl`: string
|
|
4943
|
-
* - `token`: string
|
|
4944
|
-
* - `gameId`: string
|
|
4945
|
-
*/
|
|
4946
|
-
INIT = "PLAYCADEMY_INIT",
|
|
4947
|
-
/**
|
|
4948
|
-
* Updates the game's authentication token before it expires.
|
|
4949
|
-
* Sent periodically to maintain valid authentication.
|
|
4950
|
-
* Payload:
|
|
4951
|
-
* - `token`: string
|
|
4952
|
-
* - `exp`: number
|
|
4953
|
-
*/
|
|
4954
|
-
TOKEN_REFRESH = "PLAYCADEMY_TOKEN_REFRESH",
|
|
4955
|
-
/**
|
|
4956
|
-
* Pauses game execution (e.g., when user switches tabs).
|
|
4957
|
-
* Game should pause timers, animations, and user input.
|
|
4958
|
-
* Payload: void
|
|
4959
|
-
*/
|
|
4960
|
-
PAUSE = "PLAYCADEMY_PAUSE",
|
|
4961
|
-
/**
|
|
4962
|
-
* Resumes game execution after being paused.
|
|
4963
|
-
* Game should restore timers, animations, and user input.
|
|
4964
|
-
* Payload: void
|
|
4965
|
-
*/
|
|
4966
|
-
RESUME = "PLAYCADEMY_RESUME",
|
|
4967
|
-
/**
|
|
4968
|
-
* Forces immediate game termination (emergency exit).
|
|
4969
|
-
* Game should clean up resources and exit immediately.
|
|
4970
|
-
* Payload: void
|
|
4971
|
-
*/
|
|
4972
|
-
FORCE_EXIT = "PLAYCADEMY_FORCE_EXIT",
|
|
4973
|
-
/**
|
|
4974
|
-
* Shows or hides UI overlays over the game.
|
|
4975
|
-
* Game may need to pause or adjust rendering accordingly.
|
|
4976
|
-
* Payload: boolean (true = show overlay, false = hide overlay)
|
|
4977
|
-
*/
|
|
4978
|
-
OVERLAY = "PLAYCADEMY_OVERLAY",
|
|
4979
|
-
/**
|
|
4980
|
-
* Broadcasts connection state changes to games.
|
|
4981
|
-
* Sent by platform when network connectivity changes.
|
|
4982
|
-
* Payload:
|
|
4983
|
-
* - `state`: 'online' | 'offline' | 'degraded'
|
|
4984
|
-
* - `reason`: string
|
|
4985
|
-
*/
|
|
4986
|
-
CONNECTION_STATE = "PLAYCADEMY_CONNECTION_STATE",
|
|
4987
|
-
/**
|
|
4988
|
-
* Game has finished loading and is ready to receive messages.
|
|
4989
|
-
* Sent once after game initialization is complete.
|
|
4990
|
-
* Payload: void
|
|
4991
|
-
*/
|
|
4992
|
-
READY = "PLAYCADEMY_READY",
|
|
4993
|
-
/**
|
|
4994
|
-
* Game SDK initialization failed.
|
|
4995
|
-
* Sent when the game iframe fails to complete SDK init (e.g.
|
|
4996
|
-
* origin validation failure, INIT timeout, client creation error).
|
|
4997
|
-
* Payload:
|
|
4998
|
-
* - `reason`: string — human-readable failure description
|
|
4999
|
-
*/
|
|
5000
|
-
INIT_ERROR = "PLAYCADEMY_INIT_ERROR",
|
|
5001
|
-
/**
|
|
5002
|
-
* Game requests to be closed/exited.
|
|
5003
|
-
* Sent when user clicks exit button or game naturally ends.
|
|
5004
|
-
* Payload: void
|
|
5005
|
-
*/
|
|
5006
|
-
EXIT = "PLAYCADEMY_EXIT",
|
|
5007
|
-
/**
|
|
5008
|
-
* Game reports performance telemetry data.
|
|
5009
|
-
* Sent periodically for monitoring and analytics.
|
|
5010
|
-
* Payload:
|
|
5011
|
-
* - `fps`: number
|
|
5012
|
-
* - `mem`: number
|
|
5013
|
-
*/
|
|
5014
|
-
TELEMETRY = "PLAYCADEMY_TELEMETRY",
|
|
5015
|
-
/**
|
|
5016
|
-
* Game reports key events to parent.
|
|
5017
|
-
* Sent when certain keys are pressed within the game iframe.
|
|
5018
|
-
* Payload:
|
|
5019
|
-
* - `key`: string
|
|
5020
|
-
* - `code?`: string
|
|
5021
|
-
* - `type`: 'keydown' | 'keyup'
|
|
5022
|
-
*/
|
|
5023
|
-
KEY_EVENT = "PLAYCADEMY_KEY_EVENT",
|
|
5024
|
-
/**
|
|
5025
|
-
* Game requests platform to display an alert.
|
|
5026
|
-
* Sent when connection issues are detected or other important events occur.
|
|
5027
|
-
* Payload:
|
|
5028
|
-
* - `message`: string
|
|
5029
|
-
* - `options`: `{ type?: 'info' | 'warning' | 'error', duration?: number }`
|
|
5030
|
-
*/
|
|
5031
|
-
DISPLAY_ALERT = "PLAYCADEMY_DISPLAY_ALERT",
|
|
5032
|
-
/**
|
|
5033
|
-
* Game signals that demo mode has ended.
|
|
5034
|
-
* Sent when a demo experience reaches its CTA/upgrade boundary.
|
|
5035
|
-
* Payload:
|
|
5036
|
-
* - `score?`: number
|
|
5037
|
-
* - `durationMs?`: number
|
|
5038
|
-
* - `metadata?`: `Record<string, unknown>`
|
|
5039
|
-
*/
|
|
5040
|
-
DEMO_END = "PLAYCADEMY_DEMO_END",
|
|
5041
|
-
/**
|
|
5042
|
-
* Notifies about authentication state changes.
|
|
5043
|
-
* Can be sent in both directions depending on auth flow.
|
|
5044
|
-
* Payload:
|
|
5045
|
-
* - `authenticated`: boolean
|
|
5046
|
-
* - `user`: UserInfo | null
|
|
5047
|
-
* - `error`: Error | null
|
|
5048
|
-
*/
|
|
5049
|
-
AUTH_STATE_CHANGE = "PLAYCADEMY_AUTH_STATE_CHANGE",
|
|
5050
|
-
/**
|
|
5051
|
-
* OAuth callback data from popup/new-tab windows.
|
|
5052
|
-
* Sent from popup window back to parent after OAuth completes.
|
|
5053
|
-
* Payload:
|
|
5054
|
-
* - `code`: string (OAuth authorization code)
|
|
5055
|
-
* - `state`: string (OAuth state for CSRF protection)
|
|
5056
|
-
* - `error`: string | null (OAuth error if any)
|
|
5057
|
-
*/
|
|
5058
|
-
AUTH_CALLBACK = "PLAYCADEMY_AUTH_CALLBACK"
|
|
5059
|
-
}
|
|
5060
|
-
|
|
5061
|
-
/**
|
|
5062
|
-
* Auto-initializes a PlaycademyClient with context from the environment.
|
|
5063
|
-
* Works in both iframe mode (production/development) and standalone mode (local dev).
|
|
5064
|
-
*
|
|
5065
|
-
* This is the recommended way to initialize the SDK as it automatically:
|
|
5066
|
-
* - Detects the runtime environment (iframe vs standalone)
|
|
5067
|
-
* - Configures the client with the appropriate context
|
|
5068
|
-
* - Sets up event listeners for token refresh
|
|
5069
|
-
* - Exposes the client for debugging in development mode
|
|
5070
|
-
*
|
|
5071
|
-
* @param options - Optional configuration overrides
|
|
5072
|
-
* @param options.baseUrl - Override the base URL for API requests
|
|
5073
|
-
* @returns Promise resolving to a fully initialized PlaycademyClient
|
|
5074
|
-
* @throws Error if not running in a browser context
|
|
5075
|
-
*
|
|
5076
|
-
* @example
|
|
5077
|
-
* ```typescript
|
|
5078
|
-
* // Default initialization
|
|
5079
|
-
* const client = await PlaycademyClient.init()
|
|
5080
|
-
*
|
|
5081
|
-
* // With custom base URL
|
|
5082
|
-
* const client = await PlaycademyClient.init({ baseUrl: 'https://custom.api.com' })
|
|
5083
|
-
* ```
|
|
5023
|
+
updatedAt: InventoryItemRow['updatedAt'];
|
|
5024
|
+
}
|
|
5025
|
+
interface PlayerLocation {
|
|
5026
|
+
mapIdentifier: MapRow['identifier'];
|
|
5027
|
+
mapDisplayName: MapRow['displayName'];
|
|
5028
|
+
tileX?: number;
|
|
5029
|
+
tileY?: number;
|
|
5030
|
+
worldX?: number;
|
|
5031
|
+
worldY?: number;
|
|
5032
|
+
direction?: 'up' | 'down' | 'left' | 'right';
|
|
5033
|
+
}
|
|
5034
|
+
interface PlayerSessionPayload {
|
|
5035
|
+
profile: PlayerProfile;
|
|
5036
|
+
currencies: PlayerCurrency[];
|
|
5037
|
+
inventory: PlayerInventoryItem[];
|
|
5038
|
+
ownedGameIds: Game['id'][];
|
|
5039
|
+
currentLocation?: PlayerLocation;
|
|
5040
|
+
characterCreated?: UserRow['characterCreated'];
|
|
5041
|
+
playerCharacter?: PlayerCharacterRow | null;
|
|
5042
|
+
}
|
|
5043
|
+
/**
|
|
5044
|
+
* Map-related Composite Types
|
|
5045
|
+
* DB row + joined game/item data
|
|
5084
5046
|
*/
|
|
5085
|
-
|
|
5086
|
-
|
|
5087
|
-
|
|
5088
|
-
|
|
5089
|
-
|
|
5090
|
-
}
|
|
5091
|
-
|
|
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
|
+
};
|
|
5092
5064
|
/**
|
|
5093
|
-
*
|
|
5094
|
-
*
|
|
5095
|
-
* This is a standalone authentication method that doesn't require an initialized client.
|
|
5096
|
-
* Use this for login flows before creating a client instance.
|
|
5097
|
-
*
|
|
5098
|
-
* @deprecated Use client.auth.login() instead for better error handling and automatic token management
|
|
5099
|
-
*
|
|
5100
|
-
* @param baseUrl - The base URL of the Playcademy API
|
|
5101
|
-
* @param email - User's email address
|
|
5102
|
-
* @param password - User's password
|
|
5103
|
-
* @returns Promise resolving to authentication response with token
|
|
5104
|
-
* @throws PlaycademyError if authentication fails or network error occurs
|
|
5105
|
-
*
|
|
5106
|
-
* @example
|
|
5107
|
-
* ```typescript
|
|
5108
|
-
* // Preferred approach:
|
|
5109
|
-
* const client = new PlaycademyClient({ baseUrl: '/api' })
|
|
5110
|
-
* const result = await client.auth.login({
|
|
5111
|
-
* email: 'user@example.com',
|
|
5112
|
-
* password: 'password'
|
|
5113
|
-
* })
|
|
5114
|
-
*
|
|
5115
|
-
* // Legacy approach (still works):
|
|
5116
|
-
* try {
|
|
5117
|
-
* const response = await PlaycademyClient.login('/api', 'user@example.com', 'password')
|
|
5118
|
-
* const client = new PlaycademyClient({ token: response.token })
|
|
5119
|
-
* } catch (error) {
|
|
5120
|
-
* console.error('Login failed:', error.message)
|
|
5121
|
-
* }
|
|
5122
|
-
* ```
|
|
5065
|
+
* Game custom hostname with validation records
|
|
5123
5066
|
*/
|
|
5124
|
-
|
|
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>;
|
|
5125
5081
|
|
|
5126
5082
|
/**
|
|
5127
5083
|
* @fileoverview Authentication Strategy Pattern
|
|
@@ -5295,52 +5251,69 @@ declare abstract class PlaycademyBaseClient {
|
|
|
5295
5251
|
}
|
|
5296
5252
|
|
|
5297
5253
|
/**
|
|
5298
|
-
*
|
|
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
|
+
* ```
|
|
5299
5276
|
*/
|
|
5300
|
-
|
|
5301
|
-
|
|
5302
|
-
|
|
5303
|
-
|
|
5304
|
-
|
|
5305
|
-
|
|
5306
|
-
|
|
5307
|
-
|
|
5308
|
-
|
|
5309
|
-
|
|
5310
|
-
|
|
5311
|
-
|
|
5312
|
-
|
|
5313
|
-
|
|
5314
|
-
|
|
5315
|
-
|
|
5316
|
-
|
|
5317
|
-
|
|
5318
|
-
|
|
5319
|
-
|
|
5320
|
-
|
|
5321
|
-
|
|
5322
|
-
|
|
5323
|
-
|
|
5324
|
-
|
|
5325
|
-
|
|
5326
|
-
|
|
5327
|
-
|
|
5328
|
-
|
|
5329
|
-
|
|
5330
|
-
|
|
5331
|
-
|
|
5332
|
-
|
|
5333
|
-
|
|
5334
|
-
|
|
5335
|
-
|
|
5336
|
-
|
|
5337
|
-
|
|
5338
|
-
|
|
5339
|
-
|
|
5340
|
-
* which means every session is treated as its own run.
|
|
5341
|
-
*/
|
|
5342
|
-
runId?: string;
|
|
5343
|
-
}
|
|
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>;
|
|
5344
5317
|
|
|
5345
5318
|
/**
|
|
5346
5319
|
* Playcademy SDK client for game developers.
|
|
@@ -5404,19 +5377,22 @@ declare class PlaycademyClient extends PlaycademyBaseClient {
|
|
|
5404
5377
|
* User context (cached from init, refreshable):
|
|
5405
5378
|
* - `user.role` - User's role (student, parent, teacher, etc.)
|
|
5406
5379
|
* - `user.enrollments` - Courses the player is enrolled in for this game
|
|
5380
|
+
* - `user.refresh({ only: ['enrollments'] })` - Refresh enrollments from server
|
|
5407
5381
|
* - `user.organizations` - Schools/districts the player belongs to
|
|
5408
5382
|
* - `user.fetch()` - Refresh user context from server
|
|
5409
5383
|
*
|
|
5410
5384
|
* Activity tracking:
|
|
5411
|
-
* - `
|
|
5412
|
-
*
|
|
5413
|
-
*
|
|
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
|
|
5414
5389
|
* - `pauseActivity()` / `resumeActivity()` - Pause/resume timer
|
|
5415
5390
|
* - `endActivity(scoreData)` - Submit activity results to TimeBack
|
|
5416
5391
|
*/
|
|
5417
5392
|
timeback: {
|
|
5418
5393
|
readonly user: TimebackUser;
|
|
5419
|
-
|
|
5394
|
+
readonly currentRunId: string | undefined;
|
|
5395
|
+
startActivity: (metadata: ActivityData, options?: StartActivityOptions) => StartActivityResult;
|
|
5420
5396
|
pauseActivity: () => void;
|
|
5421
5397
|
resumeActivity: () => void;
|
|
5422
5398
|
endActivity: (data: EndActivityScoreData) => Promise<EndActivityResponse>;
|
|
@@ -5496,6 +5472,57 @@ declare class PlaycademyClient extends PlaycademyBaseClient {
|
|
|
5496
5472
|
};
|
|
5497
5473
|
}
|
|
5498
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
|
+
|
|
5499
5526
|
/**
|
|
5500
5527
|
* Type definitions for the game timeback namespace.
|
|
5501
5528
|
*
|
|
@@ -5505,7 +5532,9 @@ declare class PlaycademyClient extends PlaycademyBaseClient {
|
|
|
5505
5532
|
|
|
5506
5533
|
/**
|
|
5507
5534
|
* A TimeBack enrollment for the current game session.
|
|
5508
|
-
* Alias for UserEnrollment without the optional gameId.
|
|
5535
|
+
* Alias for UserEnrollment without the optional gameId. Active enrollment IDs
|
|
5536
|
+
* are available at `enrollment.enrollmentIds?.active` when supplied by the
|
|
5537
|
+
* platform.
|
|
5509
5538
|
*/
|
|
5510
5539
|
type TimebackEnrollment = Omit<UserEnrollment, 'gameId'>;
|
|
5511
5540
|
/**
|
|
@@ -5541,6 +5570,14 @@ interface TimebackUserContext {
|
|
|
5541
5570
|
/** User's organizations (schools/districts) */
|
|
5542
5571
|
organizations: TimebackOrganization[];
|
|
5543
5572
|
}
|
|
5573
|
+
/**
|
|
5574
|
+
* Slice options for refreshing the cached TimeBack user context.
|
|
5575
|
+
*/
|
|
5576
|
+
type TimebackUserRefreshField = 'enrollments';
|
|
5577
|
+
interface TimebackUserRefreshOptions extends TTLCacheConfig {
|
|
5578
|
+
/** Refresh only these user data fields */
|
|
5579
|
+
only: readonly TimebackUserRefreshField[];
|
|
5580
|
+
}
|
|
5544
5581
|
/**
|
|
5545
5582
|
* XP data access for the current user.
|
|
5546
5583
|
* Results are cached for 5 seconds to avoid redundant network requests.
|
|
@@ -5581,7 +5618,7 @@ interface TimebackUserXp {
|
|
|
5581
5618
|
fetch(options?: GetXpOptions): Promise<XpResponse>;
|
|
5582
5619
|
}
|
|
5583
5620
|
/**
|
|
5584
|
-
* TimeBack user object with
|
|
5621
|
+
* TimeBack user object with cached getters, fetch, and targeted refresh methods.
|
|
5585
5622
|
*/
|
|
5586
5623
|
interface TimebackUser extends TimebackUserContext {
|
|
5587
5624
|
/**
|
|
@@ -5590,9 +5627,14 @@ interface TimebackUser extends TimebackUserContext {
|
|
|
5590
5627
|
* @param options - Cache options (pass { force: true } to bypass cache)
|
|
5591
5628
|
* @returns Promise resolving to fresh user context
|
|
5592
5629
|
*/
|
|
5593
|
-
fetch(options?:
|
|
5594
|
-
|
|
5595
|
-
|
|
5630
|
+
fetch(options?: TTLCacheConfig): Promise<TimebackUserContext>;
|
|
5631
|
+
/**
|
|
5632
|
+
* Refresh selected TimeBack user data from the server.
|
|
5633
|
+
* Updates the cached user snapshot used by the synchronous getters.
|
|
5634
|
+
* @param options - Refresh fields and cache options
|
|
5635
|
+
* @returns Promise resolving to the updated user context
|
|
5636
|
+
*/
|
|
5637
|
+
refresh(options: TimebackUserRefreshOptions): Promise<TimebackUserContext>;
|
|
5596
5638
|
/**
|
|
5597
5639
|
* XP data for the current user.
|
|
5598
5640
|
* Call `xp.fetch()` to get XP from the server.
|
|
@@ -6167,4 +6209,4 @@ interface AssessmentBankStatus {
|
|
|
6167
6209
|
}
|
|
6168
6210
|
|
|
6169
6211
|
export { AchievementCompletionType, NotificationStatus, NotificationType, PlaycademyClient };
|
|
6170
|
-
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, 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 };
|