@playcademy/sdk 0.3.7-beta.1 → 0.4.0-beta.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.js +12 -0
- package/dist/internal.d.ts +2 -0
- package/dist/internal.js +14 -1
- package/dist/server/edge.d.ts +701 -0
- package/dist/server/edge.js +323 -0
- package/dist/server.d.ts +61 -46
- package/dist/server.js +222 -189
- package/package.json +6 -1
|
@@ -0,0 +1,701 @@
|
|
|
1
|
+
import { SchemaInfo } from '@playcademy/cloudflare';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* TimeBack Enums & Literal Types
|
|
5
|
+
*
|
|
6
|
+
* Basic type definitions used throughout the TimeBack integration.
|
|
7
|
+
*
|
|
8
|
+
* @module types/timeback/types
|
|
9
|
+
*/
|
|
10
|
+
/**
|
|
11
|
+
* Valid TimeBack subject values for course configuration.
|
|
12
|
+
* These are the supported subject values for OneRoster courses.
|
|
13
|
+
*/
|
|
14
|
+
type TimebackSubject = 'Reading' | 'Language' | 'Vocabulary' | 'Social Studies' | 'Writing' | 'Science' | 'FastMath' | 'Math' | 'None';
|
|
15
|
+
/**
|
|
16
|
+
* Grade levels per AE OneRoster GradeEnum.
|
|
17
|
+
* -1 = Pre-K, 0 = Kindergarten, 1-12 = Grades 1-12, 13 = AP
|
|
18
|
+
*/
|
|
19
|
+
type TimebackGrade = -1 | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13;
|
|
20
|
+
/**
|
|
21
|
+
* Valid Caliper subject values.
|
|
22
|
+
* Matches OneRoster subjects, with "None" as a Caliper-specific fallback.
|
|
23
|
+
*/
|
|
24
|
+
type CaliperSubject = 'Reading' | 'Language' | 'Vocabulary' | 'Social Studies' | 'Writing' | 'Science' | 'FastMath' | 'Math' | 'None';
|
|
25
|
+
/**
|
|
26
|
+
* OneRoster organization types.
|
|
27
|
+
*/
|
|
28
|
+
type OrganizationType = 'department' | 'school' | 'district' | 'local' | 'state' | 'national';
|
|
29
|
+
/**
|
|
30
|
+
* Lesson types for PowerPath integration.
|
|
31
|
+
*/
|
|
32
|
+
type LessonType = 'powerpath-100' | 'quiz' | 'test-out' | 'placement' | 'unit-test' | 'alpha-read-article' | null;
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
* TimeBack Configuration Types
|
|
36
|
+
*
|
|
37
|
+
* Configuration interfaces for Organization, Course, Component,
|
|
38
|
+
* Resource, and complete TimeBack setup.
|
|
39
|
+
*
|
|
40
|
+
* @module types/timeback/config
|
|
41
|
+
*/
|
|
42
|
+
|
|
43
|
+
/**
|
|
44
|
+
* Organization configuration for TimeBack (user input - optionals allowed)
|
|
45
|
+
*/
|
|
46
|
+
interface OrganizationConfig {
|
|
47
|
+
/** Display name for your organization */
|
|
48
|
+
name?: string;
|
|
49
|
+
/** Organization type */
|
|
50
|
+
type?: OrganizationType;
|
|
51
|
+
/** Unique identifier (defaults to Playcademy's org) */
|
|
52
|
+
identifier?: string;
|
|
53
|
+
}
|
|
54
|
+
/**
|
|
55
|
+
* Course goals for daily student targets
|
|
56
|
+
*/
|
|
57
|
+
interface CourseGoals {
|
|
58
|
+
/** Target XP students should earn per day */
|
|
59
|
+
dailyXp?: number;
|
|
60
|
+
/** Target lessons per day */
|
|
61
|
+
dailyLessons?: number;
|
|
62
|
+
/** Target active minutes per day */
|
|
63
|
+
dailyActiveMinutes?: number;
|
|
64
|
+
/** Target accuracy percentage */
|
|
65
|
+
dailyAccuracy?: number;
|
|
66
|
+
/** Target mastered units per day */
|
|
67
|
+
dailyMasteredUnits?: number;
|
|
68
|
+
}
|
|
69
|
+
/**
|
|
70
|
+
* Course metrics and totals
|
|
71
|
+
*/
|
|
72
|
+
interface CourseMetrics {
|
|
73
|
+
/** Total XP available in the course */
|
|
74
|
+
totalXp?: number;
|
|
75
|
+
/** Total lessons/activities in the course */
|
|
76
|
+
totalLessons?: number;
|
|
77
|
+
/** Total number of grade levels covered by this course */
|
|
78
|
+
totalGrades?: number;
|
|
79
|
+
/** The type of course (e.g. 'optional', 'hole-filling', 'base') */
|
|
80
|
+
courseType?: 'base' | 'hole-filling' | 'optional' | 'Base' | 'Hole-Filling' | 'Optional';
|
|
81
|
+
/** Indicates whether the course is supplemental content */
|
|
82
|
+
isSupplemental?: boolean;
|
|
83
|
+
}
|
|
84
|
+
/**
|
|
85
|
+
* Complete course metadata structure
|
|
86
|
+
*/
|
|
87
|
+
interface CourseMetadata {
|
|
88
|
+
/** Define the type of course and priority for the student */
|
|
89
|
+
courseType?: 'base' | 'hole-filling' | 'optional';
|
|
90
|
+
/** Boolean value to determine if a course is supplemental to a base course */
|
|
91
|
+
isSupplemental?: boolean;
|
|
92
|
+
/** Boolean value to determine if a course is custom to an individual student */
|
|
93
|
+
isCustom?: boolean;
|
|
94
|
+
/** Signals whether a course is in production with students */
|
|
95
|
+
publishStatus?: 'draft' | 'testing' | 'published' | 'deactivated';
|
|
96
|
+
/** Who to contact when issues reported with questions */
|
|
97
|
+
contactEmail?: string;
|
|
98
|
+
/** Primary app identifier */
|
|
99
|
+
primaryApp?: string;
|
|
100
|
+
/** Learning goals for students */
|
|
101
|
+
goals?: CourseGoals;
|
|
102
|
+
/** Course metrics and totals */
|
|
103
|
+
metrics?: CourseMetrics;
|
|
104
|
+
/** Vendor-specific metadata (e.g., AlphaLearn) */
|
|
105
|
+
[key: string]: unknown;
|
|
106
|
+
}
|
|
107
|
+
/**
|
|
108
|
+
* Course configuration for TimeBack (user input)
|
|
109
|
+
*/
|
|
110
|
+
interface CourseConfig {
|
|
111
|
+
/** Allocated OneRoster sourcedId (set after creation) */
|
|
112
|
+
sourcedId?: string;
|
|
113
|
+
/** Course title (defaults to game name) */
|
|
114
|
+
title?: string;
|
|
115
|
+
/** Subjects (REQUIRED for TimeBack integration) */
|
|
116
|
+
subjects: TimebackSubject[];
|
|
117
|
+
/** Used when recording progress/sessions if not explicitly specified per event. */
|
|
118
|
+
defaultSubject?: TimebackSubject;
|
|
119
|
+
/** Grade levels (REQUIRED for TimeBack integration) */
|
|
120
|
+
grades: TimebackGrade[];
|
|
121
|
+
/** Short course code (optional, auto-generated) */
|
|
122
|
+
courseCode?: string;
|
|
123
|
+
/** Course level (auto-derived from grades) */
|
|
124
|
+
level?: 'Elementary' | 'Middle' | 'High' | 'AP' | string;
|
|
125
|
+
/** Grading system */
|
|
126
|
+
gradingScheme?: 'STANDARD';
|
|
127
|
+
/** Total XP available in this course (REQUIRED before setup) */
|
|
128
|
+
totalXp?: number | null;
|
|
129
|
+
/** Total masterable units in this course (REQUIRED before setup) */
|
|
130
|
+
masterableUnits?: number | null;
|
|
131
|
+
/** Custom Playcademy metadata */
|
|
132
|
+
metadata?: CourseMetadata;
|
|
133
|
+
}
|
|
134
|
+
/**
|
|
135
|
+
* Component configuration for TimeBack (user input)
|
|
136
|
+
*/
|
|
137
|
+
interface ComponentConfig {
|
|
138
|
+
/** Component title (defaults to "{course.title} Activities") */
|
|
139
|
+
title?: string;
|
|
140
|
+
/** Display order */
|
|
141
|
+
sortOrder?: number;
|
|
142
|
+
/** Required prior components */
|
|
143
|
+
prerequisites?: string[];
|
|
144
|
+
/** How prerequisites work */
|
|
145
|
+
prerequisiteCriteria?: 'ALL' | 'ANY';
|
|
146
|
+
}
|
|
147
|
+
/**
|
|
148
|
+
* Playcademy-specific resource extensions
|
|
149
|
+
*/
|
|
150
|
+
interface PlaycademyResourceMetadata {
|
|
151
|
+
/** Mastery configuration for tracking discrete learning units */
|
|
152
|
+
mastery?: {
|
|
153
|
+
/** Total number of masterable units in the resource */
|
|
154
|
+
masterableUnits: number;
|
|
155
|
+
/** Type of mastery unit for semantic clarity */
|
|
156
|
+
unitType?: 'level' | 'rank' | 'skill' | 'module';
|
|
157
|
+
};
|
|
158
|
+
}
|
|
159
|
+
/**
|
|
160
|
+
* Resource configuration for TimeBack (user input)
|
|
161
|
+
*/
|
|
162
|
+
interface ResourceConfig {
|
|
163
|
+
/** Resource title (defaults to "{course.title} Game") */
|
|
164
|
+
title?: string;
|
|
165
|
+
/** Internal resource ID (auto-generated from package.json) */
|
|
166
|
+
vendorResourceId?: string;
|
|
167
|
+
/** Vendor identifier */
|
|
168
|
+
vendorId?: string;
|
|
169
|
+
/** Application identifier */
|
|
170
|
+
applicationId?: string;
|
|
171
|
+
/** Resource roles */
|
|
172
|
+
roles?: ('primary' | 'secondary')[];
|
|
173
|
+
/** Resource importance */
|
|
174
|
+
importance?: 'primary' | 'secondary';
|
|
175
|
+
/** Interactive resource metadata */
|
|
176
|
+
metadata?: {
|
|
177
|
+
/** Resource type */
|
|
178
|
+
type?: 'interactive';
|
|
179
|
+
/** Launch URL (defaults to Playcademy game URL) */
|
|
180
|
+
launchUrl?: string;
|
|
181
|
+
/** Platform name */
|
|
182
|
+
toolProvider?: string;
|
|
183
|
+
/** Teaching method */
|
|
184
|
+
instructionalMethod?: 'exploratory' | 'direct-instruction';
|
|
185
|
+
/** Subject area */
|
|
186
|
+
subject?: TimebackSubject;
|
|
187
|
+
/** Target grades */
|
|
188
|
+
grades?: TimebackGrade[];
|
|
189
|
+
/** Content language */
|
|
190
|
+
language?: string;
|
|
191
|
+
/** Base XP for completion */
|
|
192
|
+
xp?: number;
|
|
193
|
+
/** Playcademy-specific extensions */
|
|
194
|
+
playcademy?: PlaycademyResourceMetadata;
|
|
195
|
+
};
|
|
196
|
+
}
|
|
197
|
+
/**
|
|
198
|
+
* Component Resource link configuration (user input)
|
|
199
|
+
*/
|
|
200
|
+
interface ComponentResourceConfig {
|
|
201
|
+
/** Link title (defaults to "{resource.title} Activity") */
|
|
202
|
+
title?: string;
|
|
203
|
+
/** Display order */
|
|
204
|
+
sortOrder?: number;
|
|
205
|
+
/** Lesson type for PowerPath integration */
|
|
206
|
+
lessonType?: LessonType;
|
|
207
|
+
}
|
|
208
|
+
interface TimebackCourseConfig {
|
|
209
|
+
subject: string;
|
|
210
|
+
grade: number;
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
/**
|
|
214
|
+
* TimeBack Client SDK DTOs
|
|
215
|
+
*
|
|
216
|
+
* Data transfer objects for the TimeBack client SDK including
|
|
217
|
+
* progress tracking, session management, and activity completion.
|
|
218
|
+
*
|
|
219
|
+
* Note: TimebackClientConfig lives in @playcademy/timeback as it's
|
|
220
|
+
* SDK configuration, not a DTO.
|
|
221
|
+
*
|
|
222
|
+
* @module types/timeback/client
|
|
223
|
+
*/
|
|
224
|
+
|
|
225
|
+
/**
|
|
226
|
+
* Known extensions for TimeBack Activity Metrics Collection
|
|
227
|
+
*/
|
|
228
|
+
interface TimebackActivityExtensions {
|
|
229
|
+
/** Percentage complete (0-100) for the app course */
|
|
230
|
+
pctCompleteApp?: number;
|
|
231
|
+
/** Allow other arbitrary extensions */
|
|
232
|
+
[key: string]: unknown;
|
|
233
|
+
}
|
|
234
|
+
/**
|
|
235
|
+
* Activity data for ending an activity
|
|
236
|
+
*/
|
|
237
|
+
interface ActivityData {
|
|
238
|
+
/** Unique activity identifier (required) */
|
|
239
|
+
activityId: string;
|
|
240
|
+
/** Grade level for this activity (required for multi-grade course routing) */
|
|
241
|
+
grade: number;
|
|
242
|
+
/** Subject area (required for multi-grade course routing) */
|
|
243
|
+
subject: CaliperSubject;
|
|
244
|
+
/** Activity display name (optional) */
|
|
245
|
+
activityName?: string;
|
|
246
|
+
/** Course identifier (auto-filled from config if not provided) */
|
|
247
|
+
courseId?: string;
|
|
248
|
+
/** Course display name (auto-filled from config if not provided) */
|
|
249
|
+
courseName?: string;
|
|
250
|
+
/** Student email address (optional) */
|
|
251
|
+
studentEmail?: string;
|
|
252
|
+
/** Application name for Caliper events (defaults to 'Game') */
|
|
253
|
+
appName?: string;
|
|
254
|
+
/** Sensor URL for Caliper events (defaults to baseUrl) */
|
|
255
|
+
sensorUrl?: string;
|
|
256
|
+
}
|
|
257
|
+
/**
|
|
258
|
+
* Score data for activity completion
|
|
259
|
+
*/
|
|
260
|
+
interface ScoreData {
|
|
261
|
+
/** Number of questions answered correctly */
|
|
262
|
+
correctQuestions: number;
|
|
263
|
+
/** Total number of questions */
|
|
264
|
+
totalQuestions: number;
|
|
265
|
+
}
|
|
266
|
+
/**
|
|
267
|
+
* Timing data for activity completion
|
|
268
|
+
*/
|
|
269
|
+
interface TimingData {
|
|
270
|
+
/** Duration of the activity in seconds */
|
|
271
|
+
durationSeconds: number;
|
|
272
|
+
}
|
|
273
|
+
/**
|
|
274
|
+
* Complete payload for ending an activity
|
|
275
|
+
*/
|
|
276
|
+
interface EndActivityPayload {
|
|
277
|
+
/** Activity metadata */
|
|
278
|
+
activityData: ActivityData;
|
|
279
|
+
/** Score information */
|
|
280
|
+
scoreData: ScoreData;
|
|
281
|
+
/** Timing information */
|
|
282
|
+
timingData: TimingData;
|
|
283
|
+
/** Explicit XP value to override automatic calculation */
|
|
284
|
+
xpEarned?: number;
|
|
285
|
+
/** Number of learning units mastered */
|
|
286
|
+
masteredUnits?: number;
|
|
287
|
+
/** Optional arbitrary extensions to include in the Caliper event */
|
|
288
|
+
extensions?: TimebackActivityExtensions;
|
|
289
|
+
}
|
|
290
|
+
|
|
291
|
+
/**
|
|
292
|
+
* TimeBack API Request/Response Types
|
|
293
|
+
*
|
|
294
|
+
* Types for TimeBack API endpoints including XP tracking,
|
|
295
|
+
* setup, verification, and activity completion.
|
|
296
|
+
*
|
|
297
|
+
* @module types/timeback/api
|
|
298
|
+
*/
|
|
299
|
+
|
|
300
|
+
interface EndActivityResponse {
|
|
301
|
+
status: 'ok';
|
|
302
|
+
courseId: string;
|
|
303
|
+
xpAwarded: number;
|
|
304
|
+
masteredUnits?: number;
|
|
305
|
+
pctCompleteApp?: number;
|
|
306
|
+
scoreStatus?: string;
|
|
307
|
+
inProgress?: string;
|
|
308
|
+
}
|
|
309
|
+
/**
|
|
310
|
+
* XP data for a single course.
|
|
311
|
+
*/
|
|
312
|
+
interface StudentCourseXp {
|
|
313
|
+
grade: number;
|
|
314
|
+
subject: string;
|
|
315
|
+
title: string;
|
|
316
|
+
totalXp: number;
|
|
317
|
+
todayXp?: number;
|
|
318
|
+
}
|
|
319
|
+
/**
|
|
320
|
+
* Response from student XP query.
|
|
321
|
+
*/
|
|
322
|
+
interface StudentXpResponse {
|
|
323
|
+
/** Total XP across all queried courses */
|
|
324
|
+
totalXp: number;
|
|
325
|
+
/** Today's XP (if requested) */
|
|
326
|
+
todayXp?: number;
|
|
327
|
+
/** Per-course XP breakdown (if requested) */
|
|
328
|
+
courses?: StudentCourseXp[];
|
|
329
|
+
}
|
|
330
|
+
|
|
331
|
+
/**
|
|
332
|
+
* @fileoverview Server SDK Type Definitions
|
|
333
|
+
*
|
|
334
|
+
* TypeScript type definitions for the server-side Playcademy SDK.
|
|
335
|
+
* Includes configuration types, client state, and re-exported TimeBack types.
|
|
336
|
+
*/
|
|
337
|
+
|
|
338
|
+
/**
|
|
339
|
+
* Base configuration for TimeBack integration (shared across all courses).
|
|
340
|
+
* References upstream TimeBack types from @playcademy/timeback.
|
|
341
|
+
*
|
|
342
|
+
* All fields are optional and support template variables: {grade}, {subject}, {gameSlug}
|
|
343
|
+
*/
|
|
344
|
+
interface TimebackBaseConfig {
|
|
345
|
+
/** Organization configuration (shared across all courses) */
|
|
346
|
+
organization?: Partial<OrganizationConfig>;
|
|
347
|
+
/** Course defaults (can be overridden per-course) */
|
|
348
|
+
course?: Partial<CourseConfig>;
|
|
349
|
+
/** Component defaults */
|
|
350
|
+
component?: Partial<ComponentConfig>;
|
|
351
|
+
/** Resource defaults */
|
|
352
|
+
resource?: Partial<ResourceConfig>;
|
|
353
|
+
/** ComponentResource defaults */
|
|
354
|
+
componentResource?: Partial<ComponentResourceConfig>;
|
|
355
|
+
}
|
|
356
|
+
/**
|
|
357
|
+
* Extended course configuration that merges TimebackCourseConfig with per-course overrides.
|
|
358
|
+
* Used in playcademy.config.* to allow per-course customization.
|
|
359
|
+
*/
|
|
360
|
+
interface TimebackCourseConfigWithOverrides extends TimebackCourseConfig {
|
|
361
|
+
title?: string;
|
|
362
|
+
courseCode?: string;
|
|
363
|
+
level?: string;
|
|
364
|
+
metadata?: CourseConfig['metadata'];
|
|
365
|
+
totalXp?: number | null;
|
|
366
|
+
masterableUnits?: number | null;
|
|
367
|
+
}
|
|
368
|
+
/**
|
|
369
|
+
* TimeBack integration configuration for Playcademy config file.
|
|
370
|
+
*
|
|
371
|
+
* Supports two levels of customization:
|
|
372
|
+
* 1. `base`: Shared defaults for all courses (organization, course, component, resource, componentResource)
|
|
373
|
+
* 2. Per-course overrides in the `courses` array (title, courseCode, level, gradingScheme, metadata)
|
|
374
|
+
*
|
|
375
|
+
* Template variables ({grade}, {subject}, {gameSlug}) can be used in string fields.
|
|
376
|
+
*/
|
|
377
|
+
interface TimebackIntegrationConfig {
|
|
378
|
+
/** Multi-grade course configuration (array of grade/subject/totalXp with optional per-course overrides) */
|
|
379
|
+
courses: TimebackCourseConfigWithOverrides[];
|
|
380
|
+
/** Optional base configuration (shared across all courses, can be overridden per-course) */
|
|
381
|
+
base?: TimebackBaseConfig;
|
|
382
|
+
}
|
|
383
|
+
/**
|
|
384
|
+
* Custom API routes integration
|
|
385
|
+
*/
|
|
386
|
+
interface CustomRoutesIntegration {
|
|
387
|
+
/** Directory for custom API routes (defaults to 'server/api') */
|
|
388
|
+
directory?: string;
|
|
389
|
+
}
|
|
390
|
+
/**
|
|
391
|
+
* Database integration
|
|
392
|
+
*/
|
|
393
|
+
interface DatabaseIntegration {
|
|
394
|
+
/** Database directory (defaults to 'db') */
|
|
395
|
+
directory?: string;
|
|
396
|
+
/** Schema strategy: 'push' uses drizzle-kit push-style diffing, 'migrate' uses migration files.
|
|
397
|
+
* When omitted, auto-detects based on presence of a migrations directory with _journal.json. */
|
|
398
|
+
strategy?: 'push' | 'migrate';
|
|
399
|
+
}
|
|
400
|
+
interface QueueConfig {
|
|
401
|
+
maxBatchSize?: number;
|
|
402
|
+
maxRetries?: number;
|
|
403
|
+
maxBatchTimeout?: number;
|
|
404
|
+
maxConcurrency?: number;
|
|
405
|
+
retryDelay?: number;
|
|
406
|
+
deadLetterQueue?: string;
|
|
407
|
+
}
|
|
408
|
+
/**
|
|
409
|
+
* Integrations configuration
|
|
410
|
+
* All backend features (database, custom routes, external services) are configured here
|
|
411
|
+
*/
|
|
412
|
+
interface IntegrationsConfig {
|
|
413
|
+
/** TimeBack integration (optional) */
|
|
414
|
+
timeback?: TimebackIntegrationConfig | null;
|
|
415
|
+
/** Custom API routes (optional) */
|
|
416
|
+
customRoutes?: CustomRoutesIntegration | boolean;
|
|
417
|
+
/** Database (optional) */
|
|
418
|
+
database?: DatabaseIntegration | boolean;
|
|
419
|
+
/** Key-Value storage (optional) */
|
|
420
|
+
kv?: boolean;
|
|
421
|
+
/** Bucket storage (optional) */
|
|
422
|
+
bucket?: boolean;
|
|
423
|
+
/** Authentication (optional) */
|
|
424
|
+
auth?: boolean;
|
|
425
|
+
/** Queues (optional) */
|
|
426
|
+
queues?: Record<string, QueueConfig | boolean>;
|
|
427
|
+
}
|
|
428
|
+
/**
|
|
429
|
+
* Unified Playcademy configuration
|
|
430
|
+
* Used for playcademy.config.{js,json}
|
|
431
|
+
*/
|
|
432
|
+
interface PlaycademyConfig {
|
|
433
|
+
/** Game name */
|
|
434
|
+
name: string;
|
|
435
|
+
/** Game description */
|
|
436
|
+
description?: string;
|
|
437
|
+
/** Game emoji icon */
|
|
438
|
+
emoji?: string;
|
|
439
|
+
/** Build command to run before deployment */
|
|
440
|
+
buildCommand?: string[];
|
|
441
|
+
/** Path to build output */
|
|
442
|
+
buildPath?: string;
|
|
443
|
+
/** Game type */
|
|
444
|
+
gameType?: 'hosted' | 'external';
|
|
445
|
+
/** External URL (for external games) */
|
|
446
|
+
externalUrl?: string;
|
|
447
|
+
/** Game platform */
|
|
448
|
+
platform?: 'web' | 'unity' | 'godot';
|
|
449
|
+
/** Integrations (database, custom routes, external services) */
|
|
450
|
+
integrations?: IntegrationsConfig;
|
|
451
|
+
}
|
|
452
|
+
|
|
453
|
+
/**
|
|
454
|
+
* Configuration options for initializing a PlaycademyClient instance.
|
|
455
|
+
*
|
|
456
|
+
* @example
|
|
457
|
+
* ```typescript
|
|
458
|
+
* const config: PlaycademyServerClientConfig = {
|
|
459
|
+
* apiKey: process.env.PLAYCADEMY_API_KEY!,
|
|
460
|
+
* gameId: 'my-math-game',
|
|
461
|
+
* configPath: './playcademy.config.js'
|
|
462
|
+
* }
|
|
463
|
+
* ```
|
|
464
|
+
*/
|
|
465
|
+
interface PlaycademyServerClientConfig {
|
|
466
|
+
/**
|
|
467
|
+
* Playcademy API key for server-to-server authentication.
|
|
468
|
+
* Obtain from the Playcademy developer dashboard.
|
|
469
|
+
*/
|
|
470
|
+
apiKey: string;
|
|
471
|
+
/**
|
|
472
|
+
* Optional path to playcademy.config.js file.
|
|
473
|
+
* If not provided, searches current directory and up to 3 parent directories.
|
|
474
|
+
* Ignored if `config` is provided directly.
|
|
475
|
+
*
|
|
476
|
+
* @example './config/playcademy.config.js'
|
|
477
|
+
*/
|
|
478
|
+
configPath?: string;
|
|
479
|
+
/**
|
|
480
|
+
* Optional config object (for edge environments without filesystem).
|
|
481
|
+
* If provided, skips filesystem-based config loading.
|
|
482
|
+
*
|
|
483
|
+
* @example { name: 'My Game', integrations: { timeback: {...} } }
|
|
484
|
+
*/
|
|
485
|
+
config?: PlaycademyConfig;
|
|
486
|
+
/**
|
|
487
|
+
* Optional base URL for Playcademy API.
|
|
488
|
+
* Defaults to environment variables or 'https://hub.playcademy.net'.
|
|
489
|
+
*
|
|
490
|
+
* @example 'http://localhost:3000' for local development
|
|
491
|
+
*/
|
|
492
|
+
baseUrl?: string;
|
|
493
|
+
/**
|
|
494
|
+
* Optional game ID.
|
|
495
|
+
* If not provided, will attempt to fetch from API using the API token.
|
|
496
|
+
*
|
|
497
|
+
* @example 'my-math-game'
|
|
498
|
+
*/
|
|
499
|
+
gameId?: string;
|
|
500
|
+
}
|
|
501
|
+
/**
|
|
502
|
+
* Internal state maintained by the PlaycademyClient instance.
|
|
503
|
+
*
|
|
504
|
+
* @internal
|
|
505
|
+
*/
|
|
506
|
+
interface PlaycademyServerClientState {
|
|
507
|
+
/** API key for authentication */
|
|
508
|
+
apiKey: string;
|
|
509
|
+
/** Base URL for API requests */
|
|
510
|
+
baseUrl: string;
|
|
511
|
+
/** Game identifier */
|
|
512
|
+
gameId: string;
|
|
513
|
+
/** Loaded game configuration from playcademy.config.js */
|
|
514
|
+
config: PlaycademyConfig;
|
|
515
|
+
/**
|
|
516
|
+
* TimeBack course ID fetched from the Playcademy API.
|
|
517
|
+
* Used for all TimeBack event recording.
|
|
518
|
+
*/
|
|
519
|
+
courseId?: string;
|
|
520
|
+
}
|
|
521
|
+
|
|
522
|
+
/**
|
|
523
|
+
* Resource bindings for backend deployment
|
|
524
|
+
* Provider-agnostic abstraction for cloud resources
|
|
525
|
+
*/
|
|
526
|
+
interface BackendResourceBindings {
|
|
527
|
+
/** SQL database instances to create and bind (maps to D1 on Cloudflare) */
|
|
528
|
+
database?: string[];
|
|
529
|
+
/** Key-value store namespaces to create and bind (maps to KV on Cloudflare) */
|
|
530
|
+
keyValue?: string[];
|
|
531
|
+
/** Object storage buckets to bind (maps to R2 on Cloudflare) */
|
|
532
|
+
bucket?: string[];
|
|
533
|
+
/** Queue bindings to create and bind */
|
|
534
|
+
queues?: Record<string, QueueConfig | boolean>;
|
|
535
|
+
}
|
|
536
|
+
/**
|
|
537
|
+
* Backend deployment bundle for uploading to Playcademy platform
|
|
538
|
+
*/
|
|
539
|
+
interface BackendDeploymentBundle {
|
|
540
|
+
/** Bundled JavaScript code ready for deployment */
|
|
541
|
+
code: string;
|
|
542
|
+
/** Game configuration */
|
|
543
|
+
config: PlaycademyConfig;
|
|
544
|
+
/** Optional resource bindings (database, storage, etc.) */
|
|
545
|
+
bindings?: BackendResourceBindings;
|
|
546
|
+
/** Optional schema information for database setup */
|
|
547
|
+
schema?: SchemaInfo;
|
|
548
|
+
/** Optional Cloudflare Worker compatibility flags */
|
|
549
|
+
compatibilityFlags?: string[];
|
|
550
|
+
}
|
|
551
|
+
|
|
552
|
+
/**
|
|
553
|
+
* OpenID Connect UserInfo claims (NOT a database row).
|
|
554
|
+
*/
|
|
555
|
+
interface UserInfo {
|
|
556
|
+
sub: string;
|
|
557
|
+
email: string;
|
|
558
|
+
name: string | null;
|
|
559
|
+
email_verified?: boolean;
|
|
560
|
+
given_name?: string;
|
|
561
|
+
family_name?: string;
|
|
562
|
+
issuer?: string;
|
|
563
|
+
lti_roles?: unknown;
|
|
564
|
+
lti_context?: unknown;
|
|
565
|
+
lti_resource_link?: unknown;
|
|
566
|
+
timeback_id?: string;
|
|
567
|
+
}
|
|
568
|
+
|
|
569
|
+
/**
|
|
570
|
+
* Server-side Playcademy client for recording student activity to TimeBack.
|
|
571
|
+
*
|
|
572
|
+
* This client works in any edge runtime. Config must be provided directly
|
|
573
|
+
* via the `config` option — there is no filesystem-based config discovery.
|
|
574
|
+
*
|
|
575
|
+
* @example
|
|
576
|
+
* ```typescript
|
|
577
|
+
* const client = await PlaycademyClient.init({
|
|
578
|
+
* apiKey: env.PLAYCADEMY_API_KEY,
|
|
579
|
+
* gameId: env.GAME_ID,
|
|
580
|
+
* config: { name: 'My Game', integrations: { timeback: {...} } }
|
|
581
|
+
* })
|
|
582
|
+
*
|
|
583
|
+
* await client.timeback.endActivity(studentId, { ... })
|
|
584
|
+
* ```
|
|
585
|
+
*/
|
|
586
|
+
declare class PlaycademyClient {
|
|
587
|
+
private state;
|
|
588
|
+
protected constructor(state: PlaycademyServerClientState);
|
|
589
|
+
/**
|
|
590
|
+
* Initialize a new PlaycademyClient instance.
|
|
591
|
+
*
|
|
592
|
+
* Requires `config` to be provided directly. For automatic config file
|
|
593
|
+
* discovery from the filesystem, use `PlaycademyClient` from `@playcademy/sdk/server`.
|
|
594
|
+
*
|
|
595
|
+
* @param config - Client configuration options
|
|
596
|
+
* @param config.apiKey - Playcademy API key for authentication
|
|
597
|
+
* @param config.config - Game configuration object (required)
|
|
598
|
+
* @param config.gameId - Optional game ID (will be fetched from API if not provided)
|
|
599
|
+
* @param config.baseUrl - Optional base URL for Playcademy API (defaults to production)
|
|
600
|
+
* @returns Promise resolving to initialized PlaycademyClient instance
|
|
601
|
+
* @throws {Error} If apiKey is missing or invalid
|
|
602
|
+
* @throws {Error} If config is not provided
|
|
603
|
+
*/
|
|
604
|
+
static init(config: PlaycademyServerClientConfig): Promise<PlaycademyClient>;
|
|
605
|
+
private fetchGameId;
|
|
606
|
+
/**
|
|
607
|
+
* Makes an authenticated HTTP request to the API.
|
|
608
|
+
*
|
|
609
|
+
* @param path - API endpoint path
|
|
610
|
+
* @param method - HTTP method
|
|
611
|
+
* @param body - Request body (optional)
|
|
612
|
+
* @returns Promise resolving to the response data
|
|
613
|
+
* @protected
|
|
614
|
+
*/
|
|
615
|
+
protected request<T>(path: string, method?: 'GET' | 'POST' | 'PUT' | 'DELETE', body?: unknown): Promise<T>;
|
|
616
|
+
/**
|
|
617
|
+
* Gets the current game ID.
|
|
618
|
+
*
|
|
619
|
+
* @returns The game ID
|
|
620
|
+
*/
|
|
621
|
+
get gameId(): string;
|
|
622
|
+
/**
|
|
623
|
+
* Gets the loaded game configuration.
|
|
624
|
+
*
|
|
625
|
+
* Returns the configuration loaded from playcademy.config.js during
|
|
626
|
+
* client initialization.
|
|
627
|
+
*
|
|
628
|
+
* @returns The loaded configuration object
|
|
629
|
+
*/
|
|
630
|
+
get config(): PlaycademyServerClientState['config'];
|
|
631
|
+
/** TimeBack integration methods (endActivity) */
|
|
632
|
+
timeback: {
|
|
633
|
+
endActivity: (studentId: string, payload: EndActivityPayload) => Promise<EndActivityResponse>;
|
|
634
|
+
getStudentXp: (studentId: string, options?: {
|
|
635
|
+
grade?: number | undefined;
|
|
636
|
+
subject?: string | undefined;
|
|
637
|
+
include?: ("perCourse" | "today")[] | undefined;
|
|
638
|
+
} | undefined) => Promise<StudentXpResponse>;
|
|
639
|
+
};
|
|
640
|
+
}
|
|
641
|
+
|
|
642
|
+
/**
|
|
643
|
+
* @fileoverview Game Token Verification Utilities
|
|
644
|
+
*
|
|
645
|
+
* Utilities for verifying Playcademy game tokens sent from external games.
|
|
646
|
+
*/
|
|
647
|
+
|
|
648
|
+
interface VerifyGameTokenResponse {
|
|
649
|
+
claims: Record<string, unknown>;
|
|
650
|
+
gameId: string;
|
|
651
|
+
user: UserInfo;
|
|
652
|
+
}
|
|
653
|
+
/**
|
|
654
|
+
* Verifies a short-lived Playcademy Game Token and returns verified identity claims.
|
|
655
|
+
*
|
|
656
|
+
* Game tokens are JWT tokens minted by Playcademy and sent to external games
|
|
657
|
+
* running in iframes. They contain verified user identity information and can
|
|
658
|
+
* be validated server-side to securely identify players.
|
|
659
|
+
*
|
|
660
|
+
* This function calls the Playcademy API's `/api/games/verify` endpoint to
|
|
661
|
+
* cryptographically verify the token and extract the user information.
|
|
662
|
+
*
|
|
663
|
+
* @param gameToken - The game JWT token string to verify
|
|
664
|
+
* @param options - Optional configuration
|
|
665
|
+
* @param options.baseUrl - Optional base URL override (defaults to env vars or production)
|
|
666
|
+
* @returns Promise resolving to verified token payload
|
|
667
|
+
* @returns claims - Arbitrary claims from the JWT payload
|
|
668
|
+
* @returns gameId - The game ID this token was issued for
|
|
669
|
+
* @returns user - Verified user information (id, email, name, etc.)
|
|
670
|
+
* @throws {Error} If gameToken is not a valid string
|
|
671
|
+
* @throws {Error} If PLAYCADEMY_BASE_URL is not set and no baseUrl provided
|
|
672
|
+
* @throws {Error} If token verification fails (invalid/expired token)
|
|
673
|
+
* @throws {Error} If network request fails
|
|
674
|
+
*
|
|
675
|
+
* @example
|
|
676
|
+
* ```typescript
|
|
677
|
+
* // In your game server
|
|
678
|
+
* import { verifyGameToken } from '@playcademy/sdk/server'
|
|
679
|
+
*
|
|
680
|
+
* app.post('/api/auth/playcademy', async (req, res) => {
|
|
681
|
+
* const { gameToken } = req.body
|
|
682
|
+
*
|
|
683
|
+
* try {
|
|
684
|
+
* const { user, gameId, claims } = await verifyGameToken(gameToken)
|
|
685
|
+
*
|
|
686
|
+
* // Create session for the verified user
|
|
687
|
+
* const session = await createSession(user.id)
|
|
688
|
+
*
|
|
689
|
+
* res.json({ success: true, user, session })
|
|
690
|
+
* } catch (error) {
|
|
691
|
+
* res.status(401).json({ error: 'Invalid token' })
|
|
692
|
+
* }
|
|
693
|
+
* })
|
|
694
|
+
* ```
|
|
695
|
+
*/
|
|
696
|
+
declare function verifyGameToken(gameToken: string, options?: {
|
|
697
|
+
baseUrl?: string;
|
|
698
|
+
}): Promise<VerifyGameTokenResponse>;
|
|
699
|
+
|
|
700
|
+
export { PlaycademyClient, verifyGameToken };
|
|
701
|
+
export type { ActivityData, BackendDeploymentBundle, BackendResourceBindings, ComponentConfig, ComponentResourceConfig, EndActivityPayload, IntegrationsConfig, OrganizationConfig, PlaycademyConfig, PlaycademyServerClientConfig, PlaycademyServerClientState, QueueConfig, ResourceConfig, TimebackBaseConfig, TimebackCourseConfigWithOverrides, TimebackGrade, TimebackIntegrationConfig, TimebackSubject, UserInfo };
|