playcademy 0.22.1 → 0.22.2-beta.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cli.js +13 -2
- package/dist/constants.js +14 -1
- package/dist/db.js +14 -1
- package/dist/index.js +15 -2
- package/dist/runtime/backend-runtime/index.js +241 -114
- package/dist/runtime/backend-runtime/manifest.json +4 -4
- package/dist/templates/playcademy-env.d.ts.template +1 -0
- package/dist/utils.js +15 -2
- package/dist/version.js +1 -1
- package/package.json +1 -1
package/dist/cli.js
CHANGED
|
@@ -1065,7 +1065,7 @@ var SAMPLE_BUCKET_FILENAME = "bucket.ts";
|
|
|
1065
1065
|
// ../better-auth/package.json
|
|
1066
1066
|
var package_default = {
|
|
1067
1067
|
name: "@playcademy/better-auth",
|
|
1068
|
-
version: "0.0.
|
|
1068
|
+
version: "0.0.15-beta.2",
|
|
1069
1069
|
type: "module",
|
|
1070
1070
|
exports: {
|
|
1071
1071
|
"./server": {
|
|
@@ -1262,6 +1262,17 @@ var TIMEBACK_COMPONENT_RESOURCE_DEFAULTS = {
|
|
|
1262
1262
|
sortOrder: 1,
|
|
1263
1263
|
lessonType: "quiz"
|
|
1264
1264
|
};
|
|
1265
|
+
var TIMEBACK_GAME_METRIC_DECIMAL_PLACES = {
|
|
1266
|
+
xp: 1,
|
|
1267
|
+
mastery: 0,
|
|
1268
|
+
score: 2
|
|
1269
|
+
};
|
|
1270
|
+
var TIMEBACK_GAME_METRIC_COMPARISON_TOLERANCE = {
|
|
1271
|
+
xp: 0.5 / 10 ** TIMEBACK_GAME_METRIC_DECIMAL_PLACES.xp,
|
|
1272
|
+
mastery: 0,
|
|
1273
|
+
time: 60,
|
|
1274
|
+
score: 0.5 / 10 ** TIMEBACK_GAME_METRIC_DECIMAL_PLACES.score
|
|
1275
|
+
};
|
|
1265
1276
|
|
|
1266
1277
|
// ../constants/src/cloudflare.ts
|
|
1267
1278
|
var WORKER_NAMING = {
|
|
@@ -2909,7 +2920,7 @@ import { existsSync as existsSync11, mkdirSync as mkdirSync5, readFileSync as re
|
|
|
2909
2920
|
import { join as join13 } from "node:path";
|
|
2910
2921
|
|
|
2911
2922
|
// src/version.ts
|
|
2912
|
-
var cliVersion = false ? "0.0.0-dev" : "0.22.
|
|
2923
|
+
var cliVersion = false ? "0.0.0-dev" : "0.22.2-beta.2";
|
|
2913
2924
|
|
|
2914
2925
|
// src/lib/init/database.ts
|
|
2915
2926
|
var drizzleConfigTemplate = loadTemplateString("database/drizzle-config.ts");
|
package/dist/constants.js
CHANGED
|
@@ -20,7 +20,7 @@ var SAMPLE_BUCKET_FILENAME = "bucket.ts";
|
|
|
20
20
|
// ../better-auth/package.json
|
|
21
21
|
var package_default = {
|
|
22
22
|
name: "@playcademy/better-auth",
|
|
23
|
-
version: "0.0.
|
|
23
|
+
version: "0.0.15-beta.2",
|
|
24
24
|
type: "module",
|
|
25
25
|
exports: {
|
|
26
26
|
"./server": {
|
|
@@ -247,6 +247,19 @@ var GAME_WORKER_DOMAINS = {
|
|
|
247
247
|
staging: "staging.playcademy.gg"
|
|
248
248
|
};
|
|
249
249
|
|
|
250
|
+
// ../constants/src/timeback.ts
|
|
251
|
+
var TIMEBACK_GAME_METRIC_DECIMAL_PLACES = {
|
|
252
|
+
xp: 1,
|
|
253
|
+
mastery: 0,
|
|
254
|
+
score: 2
|
|
255
|
+
};
|
|
256
|
+
var TIMEBACK_GAME_METRIC_COMPARISON_TOLERANCE = {
|
|
257
|
+
xp: 0.5 / 10 ** TIMEBACK_GAME_METRIC_DECIMAL_PLACES.xp,
|
|
258
|
+
mastery: 0,
|
|
259
|
+
time: 60,
|
|
260
|
+
score: 0.5 / 10 ** TIMEBACK_GAME_METRIC_DECIMAL_PLACES.score
|
|
261
|
+
};
|
|
262
|
+
|
|
250
263
|
// src/constants/urls.ts
|
|
251
264
|
var DOCS_URL = "https://docs.dev.playcademy.net/platform";
|
|
252
265
|
export {
|
package/dist/db.js
CHANGED
|
@@ -36,7 +36,7 @@ var DEFAULT_API_ROUTES_DIRECTORY = join2(SERVER_ROOT_DIRECTORY, "api");
|
|
|
36
36
|
// ../better-auth/package.json
|
|
37
37
|
var package_default = {
|
|
38
38
|
name: "@playcademy/better-auth",
|
|
39
|
-
version: "0.0.
|
|
39
|
+
version: "0.0.15-beta.2",
|
|
40
40
|
type: "module",
|
|
41
41
|
exports: {
|
|
42
42
|
"./server": {
|
|
@@ -147,6 +147,19 @@ var CLI_FILES = {
|
|
|
147
147
|
INITIAL_DATABASE: "initial.sqlite"
|
|
148
148
|
};
|
|
149
149
|
|
|
150
|
+
// ../constants/src/timeback.ts
|
|
151
|
+
var TIMEBACK_GAME_METRIC_DECIMAL_PLACES = {
|
|
152
|
+
xp: 1,
|
|
153
|
+
mastery: 0,
|
|
154
|
+
score: 2
|
|
155
|
+
};
|
|
156
|
+
var TIMEBACK_GAME_METRIC_COMPARISON_TOLERANCE = {
|
|
157
|
+
xp: 0.5 / 10 ** TIMEBACK_GAME_METRIC_DECIMAL_PLACES.xp,
|
|
158
|
+
mastery: 0,
|
|
159
|
+
time: 60,
|
|
160
|
+
score: 0.5 / 10 ** TIMEBACK_GAME_METRIC_DECIMAL_PLACES.score
|
|
161
|
+
};
|
|
162
|
+
|
|
150
163
|
// src/lib/db/path.ts
|
|
151
164
|
var DB_DIRECTORY = CLI_DIRECTORIES.DATABASE;
|
|
152
165
|
var INITIAL_DB_NAME = CLI_FILES.INITIAL_DATABASE;
|
package/dist/index.js
CHANGED
|
@@ -326,7 +326,7 @@ var SAMPLE_BUCKET_FILENAME = "bucket.ts";
|
|
|
326
326
|
// ../better-auth/package.json
|
|
327
327
|
var package_default = {
|
|
328
328
|
name: "@playcademy/better-auth",
|
|
329
|
-
version: "0.0.
|
|
329
|
+
version: "0.0.15-beta.2",
|
|
330
330
|
type: "module",
|
|
331
331
|
exports: {
|
|
332
332
|
"./server": {
|
|
@@ -534,6 +534,7 @@ var LOG_COLLECTOR_URL = "https://logs.playcademy.gg";
|
|
|
534
534
|
var TIMEBACK_ROUTES = {
|
|
535
535
|
END_ACTIVITY: "/integrations/timeback/end-activity",
|
|
536
536
|
GET_XP: "/integrations/timeback/xp",
|
|
537
|
+
GET_MASTERY: "/integrations/timeback/mastery",
|
|
537
538
|
HEARTBEAT: "/integrations/timeback/heartbeat",
|
|
538
539
|
ADVANCE_COURSE: "/integrations/timeback/advance-course"
|
|
539
540
|
};
|
|
@@ -576,6 +577,17 @@ var TIMEBACK_COMPONENT_RESOURCE_DEFAULTS = {
|
|
|
576
577
|
sortOrder: 1,
|
|
577
578
|
lessonType: "quiz"
|
|
578
579
|
};
|
|
580
|
+
var TIMEBACK_GAME_METRIC_DECIMAL_PLACES = {
|
|
581
|
+
xp: 1,
|
|
582
|
+
mastery: 0,
|
|
583
|
+
score: 2
|
|
584
|
+
};
|
|
585
|
+
var TIMEBACK_GAME_METRIC_COMPARISON_TOLERANCE = {
|
|
586
|
+
xp: 0.5 / 10 ** TIMEBACK_GAME_METRIC_DECIMAL_PLACES.xp,
|
|
587
|
+
mastery: 0,
|
|
588
|
+
time: 60,
|
|
589
|
+
score: 0.5 / 10 ** TIMEBACK_GAME_METRIC_DECIMAL_PLACES.score
|
|
590
|
+
};
|
|
579
591
|
|
|
580
592
|
// ../constants/src/cloudflare.ts
|
|
581
593
|
var WORKER_NAMING = {
|
|
@@ -4171,7 +4183,7 @@ import { existsSync as existsSync9, mkdirSync as mkdirSync2, readFileSync as rea
|
|
|
4171
4183
|
import { join as join13 } from "node:path";
|
|
4172
4184
|
|
|
4173
4185
|
// src/version.ts
|
|
4174
|
-
var cliVersion = false ? "0.0.0-dev" : "0.22.
|
|
4186
|
+
var cliVersion = false ? "0.0.0-dev" : "0.22.2-beta.2";
|
|
4175
4187
|
|
|
4176
4188
|
// src/lib/init/database.ts
|
|
4177
4189
|
var drizzleConfigTemplate = loadTemplateString("database/drizzle-config.ts");
|
|
@@ -6612,6 +6624,7 @@ var ROUTES = {
|
|
|
6612
6624
|
TIMEBACK: {
|
|
6613
6625
|
END_ACTIVITY: `/api${TIMEBACK_ROUTES.END_ACTIVITY}`,
|
|
6614
6626
|
GET_XP: `/api${TIMEBACK_ROUTES.GET_XP}`,
|
|
6627
|
+
GET_MASTERY: `/api${TIMEBACK_ROUTES.GET_MASTERY}`,
|
|
6615
6628
|
HEARTBEAT: `/api${TIMEBACK_ROUTES.HEARTBEAT}`,
|
|
6616
6629
|
ADVANCE_COURSE: `/api${TIMEBACK_ROUTES.ADVANCE_COURSE}`
|
|
6617
6630
|
}
|
|
@@ -8,6 +8,75 @@ var __export = (target, all) => {
|
|
|
8
8
|
__defProp(target, name, { get: all[name], enumerable: true });
|
|
9
9
|
};
|
|
10
10
|
|
|
11
|
+
// ../utils/src/timeback.ts
|
|
12
|
+
function formatGradeLabel(grade) {
|
|
13
|
+
switch (grade) {
|
|
14
|
+
case -1: {
|
|
15
|
+
return "Pre-K";
|
|
16
|
+
}
|
|
17
|
+
case 0: {
|
|
18
|
+
return "Kindergarten";
|
|
19
|
+
}
|
|
20
|
+
case 13: {
|
|
21
|
+
return "AP";
|
|
22
|
+
}
|
|
23
|
+
default: {
|
|
24
|
+
return `Grade ${grade}`;
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
var init_timeback = __esm({
|
|
29
|
+
"../utils/src/timeback.ts"() {
|
|
30
|
+
}
|
|
31
|
+
});
|
|
32
|
+
|
|
33
|
+
// ../edge-play/src/lib/validation.ts
|
|
34
|
+
function isNonNegativeNumber(value) {
|
|
35
|
+
return typeof value === "number" && Number.isFinite(value) && value >= 0;
|
|
36
|
+
}
|
|
37
|
+
function isNonNegativeInteger(value) {
|
|
38
|
+
return isNonNegativeNumber(value) && Number.isInteger(value);
|
|
39
|
+
}
|
|
40
|
+
function isValidGrade(value) {
|
|
41
|
+
return typeof value === "number" && Number.isInteger(value) && VALID_GRADES.includes(value);
|
|
42
|
+
}
|
|
43
|
+
function isValidSubject(value) {
|
|
44
|
+
return typeof value === "string" && VALID_SUBJECTS.includes(value);
|
|
45
|
+
}
|
|
46
|
+
function validateCourseConfig(params) {
|
|
47
|
+
const { grade, subject, config } = params;
|
|
48
|
+
const timebackConfig = config.integrations?.timeback;
|
|
49
|
+
const configuredCourse = timebackConfig?.courses?.find(
|
|
50
|
+
(course) => course.grade === grade && course.subject === subject
|
|
51
|
+
);
|
|
52
|
+
if (!configuredCourse) {
|
|
53
|
+
const configured = timebackConfig?.courses?.map((c) => `${c.subject} (${formatGradeLabel(c.grade)})`).join(", ");
|
|
54
|
+
return {
|
|
55
|
+
error: `Invalid grade/subject combination: ${subject} (${formatGradeLabel(grade)}). Configured courses: ${configured || "none"}`
|
|
56
|
+
};
|
|
57
|
+
}
|
|
58
|
+
return null;
|
|
59
|
+
}
|
|
60
|
+
var VALID_GRADES, VALID_SUBJECTS;
|
|
61
|
+
var init_validation = __esm({
|
|
62
|
+
"../edge-play/src/lib/validation.ts"() {
|
|
63
|
+
"use strict";
|
|
64
|
+
init_timeback();
|
|
65
|
+
VALID_GRADES = [-1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13];
|
|
66
|
+
VALID_SUBJECTS = [
|
|
67
|
+
"Reading",
|
|
68
|
+
"Language",
|
|
69
|
+
"Vocabulary",
|
|
70
|
+
"Social Studies",
|
|
71
|
+
"Writing",
|
|
72
|
+
"Science",
|
|
73
|
+
"FastMath",
|
|
74
|
+
"Math",
|
|
75
|
+
"None"
|
|
76
|
+
];
|
|
77
|
+
}
|
|
78
|
+
});
|
|
79
|
+
|
|
11
80
|
// ../constants/src/auth.ts
|
|
12
81
|
var init_auth = __esm({
|
|
13
82
|
"../constants/src/auth.ts"() {
|
|
@@ -67,16 +136,28 @@ var init_system = __esm({
|
|
|
67
136
|
});
|
|
68
137
|
|
|
69
138
|
// ../constants/src/timeback.ts
|
|
70
|
-
var TIMEBACK_ROUTES;
|
|
71
|
-
var
|
|
139
|
+
var TIMEBACK_ROUTES, TIMEBACK_GAME_METRIC_DECIMAL_PLACES, TIMEBACK_GAME_METRIC_COMPARISON_TOLERANCE;
|
|
140
|
+
var init_timeback2 = __esm({
|
|
72
141
|
"../constants/src/timeback.ts"() {
|
|
73
142
|
"use strict";
|
|
74
143
|
TIMEBACK_ROUTES = {
|
|
75
144
|
END_ACTIVITY: "/integrations/timeback/end-activity",
|
|
76
145
|
GET_XP: "/integrations/timeback/xp",
|
|
146
|
+
GET_MASTERY: "/integrations/timeback/mastery",
|
|
77
147
|
HEARTBEAT: "/integrations/timeback/heartbeat",
|
|
78
148
|
ADVANCE_COURSE: "/integrations/timeback/advance-course"
|
|
79
149
|
};
|
|
150
|
+
TIMEBACK_GAME_METRIC_DECIMAL_PLACES = {
|
|
151
|
+
xp: 1,
|
|
152
|
+
mastery: 0,
|
|
153
|
+
score: 2
|
|
154
|
+
};
|
|
155
|
+
TIMEBACK_GAME_METRIC_COMPARISON_TOLERANCE = {
|
|
156
|
+
xp: 0.5 / 10 ** TIMEBACK_GAME_METRIC_DECIMAL_PLACES.xp,
|
|
157
|
+
mastery: 0,
|
|
158
|
+
time: 60,
|
|
159
|
+
score: 0.5 / 10 ** TIMEBACK_GAME_METRIC_DECIMAL_PLACES.score
|
|
160
|
+
};
|
|
80
161
|
}
|
|
81
162
|
});
|
|
82
163
|
|
|
@@ -100,7 +181,7 @@ var init_src = __esm({
|
|
|
100
181
|
init_game();
|
|
101
182
|
init_platform();
|
|
102
183
|
init_system();
|
|
103
|
-
|
|
184
|
+
init_timeback2();
|
|
104
185
|
init_cloudflare();
|
|
105
186
|
}
|
|
106
187
|
});
|
|
@@ -120,6 +201,7 @@ var init_constants = __esm({
|
|
|
120
201
|
TIMEBACK: {
|
|
121
202
|
END_ACTIVITY: `/api${TIMEBACK_ROUTES.END_ACTIVITY}`,
|
|
122
203
|
GET_XP: `/api${TIMEBACK_ROUTES.GET_XP}`,
|
|
204
|
+
GET_MASTERY: `/api${TIMEBACK_ROUTES.GET_MASTERY}`,
|
|
123
205
|
HEARTBEAT: `/api${TIMEBACK_ROUTES.HEARTBEAT}`,
|
|
124
206
|
ADVANCE_COURSE: `/api${TIMEBACK_ROUTES.ADVANCE_COURSE}`
|
|
125
207
|
}
|
|
@@ -212,9 +294,9 @@ var init_routes = __esm({
|
|
|
212
294
|
// ../edge-play/src/entry/metadata.ts
|
|
213
295
|
function getRuntimeMetadata() {
|
|
214
296
|
return {
|
|
215
|
-
cliVersion: true ? "0.22.
|
|
216
|
-
sdkVersion: true ? "0.10.
|
|
217
|
-
buildId: true ? "
|
|
297
|
+
cliVersion: true ? "0.22.2-beta.2" : "0.0.0-dev",
|
|
298
|
+
sdkVersion: true ? "0.10.1-beta.2" : "0.0.0-dev",
|
|
299
|
+
buildId: true ? "9c6fe529d1f4" : "dev-source"
|
|
218
300
|
};
|
|
219
301
|
}
|
|
220
302
|
var init_metadata = __esm({
|
|
@@ -364,69 +446,6 @@ var init_errors = __esm({
|
|
|
364
446
|
}
|
|
365
447
|
});
|
|
366
448
|
|
|
367
|
-
// ../utils/src/timeback.ts
|
|
368
|
-
function formatGradeLabel(grade) {
|
|
369
|
-
switch (grade) {
|
|
370
|
-
case -1: {
|
|
371
|
-
return "Pre-K";
|
|
372
|
-
}
|
|
373
|
-
case 0: {
|
|
374
|
-
return "Kindergarten";
|
|
375
|
-
}
|
|
376
|
-
case 13: {
|
|
377
|
-
return "AP";
|
|
378
|
-
}
|
|
379
|
-
default: {
|
|
380
|
-
return `Grade ${grade}`;
|
|
381
|
-
}
|
|
382
|
-
}
|
|
383
|
-
}
|
|
384
|
-
var init_timeback2 = __esm({
|
|
385
|
-
"../utils/src/timeback.ts"() {
|
|
386
|
-
}
|
|
387
|
-
});
|
|
388
|
-
|
|
389
|
-
// ../edge-play/src/lib/validation.ts
|
|
390
|
-
function isValidGrade2(value) {
|
|
391
|
-
return typeof value === "number" && Number.isInteger(value) && VALID_GRADES2.includes(value);
|
|
392
|
-
}
|
|
393
|
-
function isValidSubject2(value) {
|
|
394
|
-
return typeof value === "string" && VALID_SUBJECTS2.includes(value);
|
|
395
|
-
}
|
|
396
|
-
function validateCourseConfig(params) {
|
|
397
|
-
const { grade, subject, config } = params;
|
|
398
|
-
const timebackConfig = config.integrations?.timeback;
|
|
399
|
-
const configuredCourse = timebackConfig?.courses?.find(
|
|
400
|
-
(course) => course.grade === grade && course.subject === subject
|
|
401
|
-
);
|
|
402
|
-
if (!configuredCourse) {
|
|
403
|
-
const configured = timebackConfig?.courses?.map((c) => `${c.subject} (${formatGradeLabel(c.grade)})`).join(", ");
|
|
404
|
-
return {
|
|
405
|
-
error: `Invalid grade/subject combination: ${subject} (${formatGradeLabel(grade)}). Configured courses: ${configured || "none"}`
|
|
406
|
-
};
|
|
407
|
-
}
|
|
408
|
-
return null;
|
|
409
|
-
}
|
|
410
|
-
var VALID_GRADES2, VALID_SUBJECTS2;
|
|
411
|
-
var init_validation = __esm({
|
|
412
|
-
"../edge-play/src/lib/validation.ts"() {
|
|
413
|
-
"use strict";
|
|
414
|
-
init_timeback2();
|
|
415
|
-
VALID_GRADES2 = [-1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13];
|
|
416
|
-
VALID_SUBJECTS2 = [
|
|
417
|
-
"Reading",
|
|
418
|
-
"Language",
|
|
419
|
-
"Vocabulary",
|
|
420
|
-
"Social Studies",
|
|
421
|
-
"Writing",
|
|
422
|
-
"Science",
|
|
423
|
-
"FastMath",
|
|
424
|
-
"Math",
|
|
425
|
-
"None"
|
|
426
|
-
];
|
|
427
|
-
}
|
|
428
|
-
});
|
|
429
|
-
|
|
430
449
|
// ../edge-play/src/lib/index.ts
|
|
431
450
|
var init_lib = __esm({
|
|
432
451
|
"../edge-play/src/lib/index.ts"() {
|
|
@@ -495,12 +514,13 @@ async function POST(c) {
|
|
|
495
514
|
sessionTimingData,
|
|
496
515
|
xpEarned,
|
|
497
516
|
masteredUnits,
|
|
517
|
+
masteredUnitsAbsolute,
|
|
498
518
|
extensions
|
|
499
519
|
} = await c.req.json();
|
|
500
520
|
assertTimebackIntegrated(c);
|
|
501
521
|
const config = getConfig(c);
|
|
502
522
|
const structuredActivityData = isActivityDataInput(activityData) ? activityData : void 0;
|
|
503
|
-
if (structuredActivityData &&
|
|
523
|
+
if (structuredActivityData && isValidGrade(structuredActivityData.grade) && isValidSubject(structuredActivityData.subject)) {
|
|
504
524
|
const courseValidationError = validateCourseConfig({
|
|
505
525
|
grade: structuredActivityData.grade,
|
|
506
526
|
subject: structuredActivityData.subject,
|
|
@@ -532,6 +552,7 @@ async function POST(c) {
|
|
|
532
552
|
sessionTimingData,
|
|
533
553
|
xpEarned,
|
|
534
554
|
masteredUnits,
|
|
555
|
+
masteredUnitsAbsolute,
|
|
535
556
|
extensions
|
|
536
557
|
}
|
|
537
558
|
);
|
|
@@ -581,12 +602,12 @@ async function GET3(c) {
|
|
|
581
602
|
}
|
|
582
603
|
grade = parseInt(gradeParam, 10);
|
|
583
604
|
subject = subjectParam;
|
|
584
|
-
if (!
|
|
585
|
-
const message2 = `grade must be a valid grade level (${
|
|
605
|
+
if (!isValidGrade(grade)) {
|
|
606
|
+
const message2 = `grade must be a valid grade level (${VALID_GRADES.join(", ")})`;
|
|
586
607
|
return c.json(buildErrorResponse(c, message2, message2), 400);
|
|
587
608
|
}
|
|
588
|
-
if (!
|
|
589
|
-
const message2 = `subject must be a valid subject (${
|
|
609
|
+
if (!isValidSubject(subject)) {
|
|
610
|
+
const message2 = `subject must be a valid subject (${VALID_SUBJECTS.join(", ")})`;
|
|
590
611
|
return c.json(buildErrorResponse(c, message2, message2), 400);
|
|
591
612
|
}
|
|
592
613
|
const courseValidationError = validateCourseConfig({ grade, subject, config });
|
|
@@ -617,6 +638,74 @@ var init_get_xp = __esm({
|
|
|
617
638
|
}
|
|
618
639
|
});
|
|
619
640
|
|
|
641
|
+
// ../edge-play/src/routes/integrations/timeback/get-mastery.ts
|
|
642
|
+
var get_mastery_exports = {};
|
|
643
|
+
__export(get_mastery_exports, {
|
|
644
|
+
GET: () => GET4
|
|
645
|
+
});
|
|
646
|
+
async function GET4(c) {
|
|
647
|
+
try {
|
|
648
|
+
const user = c.get("playcademyUser");
|
|
649
|
+
if (!user) {
|
|
650
|
+
return c.json(buildErrorResponse(c, "Unauthorized", "Unauthorized"), 401);
|
|
651
|
+
}
|
|
652
|
+
if (!user.timeback_id) {
|
|
653
|
+
const message2 = "User does not have TimeBack integration";
|
|
654
|
+
console.error("[TimeBack Get Mastery] Error:", message2);
|
|
655
|
+
return c.json(buildErrorResponse(c, message2, message2), 400);
|
|
656
|
+
}
|
|
657
|
+
assertTimebackIntegrated(c);
|
|
658
|
+
const config = getConfig(c);
|
|
659
|
+
const url = new URL(c.req.url);
|
|
660
|
+
const gradeParam = url.searchParams.get("grade");
|
|
661
|
+
const subjectParam = url.searchParams.get("subject");
|
|
662
|
+
const includeParam = url.searchParams.get("include");
|
|
663
|
+
const include = includeParam ? includeParam.split(",").map((s) => s.trim()) : void 0;
|
|
664
|
+
let grade;
|
|
665
|
+
let subject;
|
|
666
|
+
if (gradeParam !== null || subjectParam !== null) {
|
|
667
|
+
if (gradeParam === null || subjectParam === null) {
|
|
668
|
+
const message2 = "Both grade and subject must be provided together";
|
|
669
|
+
return c.json(buildErrorResponse(c, message2, message2), 400);
|
|
670
|
+
}
|
|
671
|
+
grade = parseInt(gradeParam, 10);
|
|
672
|
+
subject = subjectParam;
|
|
673
|
+
if (!isValidGrade(grade)) {
|
|
674
|
+
const message2 = `grade must be a valid grade level (${VALID_GRADES.join(", ")})`;
|
|
675
|
+
return c.json(buildErrorResponse(c, message2, message2), 400);
|
|
676
|
+
}
|
|
677
|
+
if (!isValidSubject(subject)) {
|
|
678
|
+
const message2 = `subject must be a valid subject (${VALID_SUBJECTS.join(", ")})`;
|
|
679
|
+
return c.json(buildErrorResponse(c, message2, message2), 400);
|
|
680
|
+
}
|
|
681
|
+
const courseValidationError = validateCourseConfig({ grade, subject, config });
|
|
682
|
+
if (courseValidationError) {
|
|
683
|
+
return c.json(
|
|
684
|
+
buildErrorResponse(c, courseValidationError.error, courseValidationError.error),
|
|
685
|
+
400
|
|
686
|
+
);
|
|
687
|
+
}
|
|
688
|
+
}
|
|
689
|
+
const sdk = c.get("sdk");
|
|
690
|
+
const result = await sdk.timeback.getStudentMastery(user.timeback_id, {
|
|
691
|
+
grade,
|
|
692
|
+
subject,
|
|
693
|
+
include
|
|
694
|
+
});
|
|
695
|
+
return c.json(result);
|
|
696
|
+
} catch (error) {
|
|
697
|
+
logError("TimeBack Get Mastery", error);
|
|
698
|
+
return c.json(buildErrorResponse(c, error, "Failed to get mastery"), getErrorStatus(error));
|
|
699
|
+
}
|
|
700
|
+
}
|
|
701
|
+
var init_get_mastery = __esm({
|
|
702
|
+
"../edge-play/src/routes/integrations/timeback/get-mastery.ts"() {
|
|
703
|
+
"use strict";
|
|
704
|
+
init_lib();
|
|
705
|
+
init_shared();
|
|
706
|
+
}
|
|
707
|
+
});
|
|
708
|
+
|
|
620
709
|
// ../edge-play/src/routes/integrations/timeback/heartbeat.ts
|
|
621
710
|
var heartbeat_exports = {};
|
|
622
711
|
__export(heartbeat_exports, {
|
|
@@ -652,7 +741,7 @@ async function POST2(c) {
|
|
|
652
741
|
assertTimebackIntegrated(c);
|
|
653
742
|
const config = getConfig(c);
|
|
654
743
|
const structuredActivityData = isActivityDataInput(activityData) ? activityData : void 0;
|
|
655
|
-
if (structuredActivityData &&
|
|
744
|
+
if (structuredActivityData && isValidGrade(structuredActivityData.grade) && isValidSubject(structuredActivityData.subject)) {
|
|
656
745
|
const courseValidationError = validateCourseConfig({
|
|
657
746
|
grade: structuredActivityData.grade,
|
|
658
747
|
subject: structuredActivityData.subject,
|
|
@@ -716,7 +805,7 @@ async function POST3(c) {
|
|
|
716
805
|
}
|
|
717
806
|
const body = await c.req.json().catch(() => ({}));
|
|
718
807
|
const subject = body.subject;
|
|
719
|
-
if (subject !== void 0 && !
|
|
808
|
+
if (subject !== void 0 && !isValidSubject(subject)) {
|
|
720
809
|
const message2 = "Invalid subject: must be one of the supported TimeBack subjects";
|
|
721
810
|
console.error("[TimeBack Advance] Error:", message2);
|
|
722
811
|
return c.json(buildErrorResponse(c, message2, message2), 400);
|
|
@@ -3484,22 +3573,10 @@ function createLocalJWKSet(jwks) {
|
|
|
3484
3573
|
return localJWKSet;
|
|
3485
3574
|
}
|
|
3486
3575
|
|
|
3487
|
-
// ../edge-play/src/
|
|
3576
|
+
// ../edge-play/src/lib/jwt.ts
|
|
3488
3577
|
var SERVICE_JWT_ISSUER = "playcademy-platform";
|
|
3489
3578
|
var SERVICE_JWT_AUDIENCE = "playcademy-game-metrics";
|
|
3490
3579
|
var SERVICE_JWT_CLOCK_TOLERANCE = "10s";
|
|
3491
|
-
var TIMEBACK_GRADES = /* @__PURE__ */ new Set([-1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13]);
|
|
3492
|
-
var TIMEBACK_SUBJECTS = /* @__PURE__ */ new Set([
|
|
3493
|
-
"Reading",
|
|
3494
|
-
"Language",
|
|
3495
|
-
"Vocabulary",
|
|
3496
|
-
"Social Studies",
|
|
3497
|
-
"Writing",
|
|
3498
|
-
"Science",
|
|
3499
|
-
"FastMath",
|
|
3500
|
-
"Math",
|
|
3501
|
-
"None"
|
|
3502
|
-
]);
|
|
3503
3580
|
function getBearerToken(c) {
|
|
3504
3581
|
const header = c.req.header("Authorization");
|
|
3505
3582
|
if (!header?.startsWith("Bearer ")) {
|
|
@@ -3594,22 +3671,24 @@ async function verifyMetricsToken(c) {
|
|
|
3594
3671
|
return null;
|
|
3595
3672
|
}
|
|
3596
3673
|
}
|
|
3597
|
-
|
|
3598
|
-
|
|
3599
|
-
}
|
|
3600
|
-
function
|
|
3601
|
-
|
|
3602
|
-
|
|
3603
|
-
|
|
3604
|
-
return
|
|
3674
|
+
|
|
3675
|
+
// ../utils/src/uuid.ts
|
|
3676
|
+
var UUID_REGEX = /^[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}$/;
|
|
3677
|
+
function isValidUUID(value) {
|
|
3678
|
+
if (!value || typeof value !== "string") {
|
|
3679
|
+
return false;
|
|
3680
|
+
}
|
|
3681
|
+
return UUID_REGEX.test(value);
|
|
3605
3682
|
}
|
|
3606
|
-
|
|
3683
|
+
|
|
3684
|
+
// ../edge-play/src/lib/metrics.ts
|
|
3685
|
+
init_validation();
|
|
3686
|
+
function isValidRunMetrics(value) {
|
|
3607
3687
|
if (!value || typeof value !== "object") {
|
|
3608
3688
|
return false;
|
|
3609
3689
|
}
|
|
3610
3690
|
const activity = value;
|
|
3611
|
-
|
|
3612
|
-
return typeof activity.activityId === "string" && activity.activityId.length > 0 && (activity.activityName === void 0 || typeof activity.activityName === "string") && isNonNegativeNumber(activity.totalXp) && isNonNegativeInteger(activity.masteredUnits) && isNonNegativeNumber(activity.activeTimeSeconds) && Number.isInteger(completionCount) && typeof completionCount === "number" && completionCount >= 0 && (activity.lastCompletedAt === void 0 || isIsoDateString(activity.lastCompletedAt));
|
|
3691
|
+
return typeof activity.runId === "string" && isValidUUID(activity.runId) && typeof activity.activityId === "string" && activity.activityId.length > 0 && (activity.activityName === void 0 || typeof activity.activityName === "string") && (activity.totalXp === void 0 || isNonNegativeNumber(activity.totalXp)) && (activity.masteredUnits === void 0 || isNonNegativeInteger(activity.masteredUnits)) && (activity.activeTimeSeconds === void 0 || isNonNegativeNumber(activity.activeTimeSeconds)) && (activity.score === void 0 || isNonNegativeNumber(activity.score) && activity.score <= 100);
|
|
3613
3692
|
}
|
|
3614
3693
|
function isValidGameMetricsResponse(value) {
|
|
3615
3694
|
if (!value || typeof value !== "object") {
|
|
@@ -3626,9 +3705,15 @@ function isValidGameMetricsResponse(value) {
|
|
|
3626
3705
|
}
|
|
3627
3706
|
const metrics = course;
|
|
3628
3707
|
const activities = metrics.activities;
|
|
3629
|
-
return
|
|
3708
|
+
return isValidGrade(metrics.grade) && isValidSubject(metrics.subject) && (metrics.totalXp === void 0 || isNonNegativeNumber(metrics.totalXp)) && (metrics.masteredUnits === void 0 || isNonNegativeInteger(metrics.masteredUnits)) && (metrics.activeTimeSeconds === void 0 || isNonNegativeNumber(metrics.activeTimeSeconds)) && (activities === void 0 || Array.isArray(activities) && activities.every(isValidRunMetrics));
|
|
3630
3709
|
});
|
|
3631
3710
|
}
|
|
3711
|
+
function getRequestedRunIds(request) {
|
|
3712
|
+
const runIds = new URL(request.url).searchParams.getAll("runId").filter((runId) => isValidUUID(runId));
|
|
3713
|
+
return [...new Set(runIds)];
|
|
3714
|
+
}
|
|
3715
|
+
|
|
3716
|
+
// ../edge-play/src/entry/metrics.ts
|
|
3632
3717
|
function registerMetricsRoute(app, metricsModule) {
|
|
3633
3718
|
app.get("/__playcademy/metrics", async (c) => {
|
|
3634
3719
|
const claims = await verifyMetricsToken(c);
|
|
@@ -3645,6 +3730,7 @@ function registerMetricsRoute(app, metricsModule) {
|
|
|
3645
3730
|
try {
|
|
3646
3731
|
metrics = await metricsModule.getMetrics({
|
|
3647
3732
|
studentId: claims.studentId,
|
|
3733
|
+
runIds: getRequestedRunIds(c.req.raw),
|
|
3648
3734
|
env: c.env,
|
|
3649
3735
|
sdk: c.get("sdk"),
|
|
3650
3736
|
request: c.req.raw,
|
|
@@ -3746,8 +3832,8 @@ var cors = (options) => {
|
|
|
3746
3832
|
};
|
|
3747
3833
|
|
|
3748
3834
|
// ../sdk/src/core/guards.ts
|
|
3749
|
-
var
|
|
3750
|
-
var
|
|
3835
|
+
var VALID_GRADES2 = [-1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13];
|
|
3836
|
+
var VALID_SUBJECTS2 = [
|
|
3751
3837
|
"Reading",
|
|
3752
3838
|
"Language",
|
|
3753
3839
|
"Vocabulary",
|
|
@@ -3758,11 +3844,11 @@ var VALID_SUBJECTS = [
|
|
|
3758
3844
|
"Math",
|
|
3759
3845
|
"None"
|
|
3760
3846
|
];
|
|
3761
|
-
function
|
|
3762
|
-
return typeof value === "number" && Number.isInteger(value) &&
|
|
3847
|
+
function isValidGrade2(value) {
|
|
3848
|
+
return typeof value === "number" && Number.isInteger(value) && VALID_GRADES2.includes(value);
|
|
3763
3849
|
}
|
|
3764
|
-
function
|
|
3765
|
-
return typeof value === "string" &&
|
|
3850
|
+
function isValidSubject2(value) {
|
|
3851
|
+
return typeof value === "string" && VALID_SUBJECTS2.includes(value);
|
|
3766
3852
|
}
|
|
3767
3853
|
|
|
3768
3854
|
// ../sdk/src/server/namespaces/timeback.ts
|
|
@@ -3820,10 +3906,10 @@ function createTimebackNamespace(client) {
|
|
|
3820
3906
|
* ```
|
|
3821
3907
|
*/
|
|
3822
3908
|
endActivity: async (studentId, payload) => {
|
|
3823
|
-
if (!
|
|
3909
|
+
if (!isValidGrade2(payload.activityData.grade)) {
|
|
3824
3910
|
throw new Error("activityData.grade must be a valid grade level (-1 to 13)");
|
|
3825
3911
|
}
|
|
3826
|
-
if (!
|
|
3912
|
+
if (!isValidSubject2(payload.activityData.subject)) {
|
|
3827
3913
|
throw new Error("activityData.subject must be a valid subject");
|
|
3828
3914
|
}
|
|
3829
3915
|
const enrichedActivityData = enrichActivityData2(payload.activityData);
|
|
@@ -3879,14 +3965,14 @@ function createTimebackNamespace(client) {
|
|
|
3879
3965
|
if (hasGrade !== hasSubject) {
|
|
3880
3966
|
throw new Error("Both grade and subject must be provided together");
|
|
3881
3967
|
}
|
|
3882
|
-
if (hasGrade && !
|
|
3968
|
+
if (hasGrade && !isValidGrade2(options.grade)) {
|
|
3883
3969
|
throw new Error(
|
|
3884
|
-
`Invalid grade: ${options.grade}. Valid grades: ${
|
|
3970
|
+
`Invalid grade: ${options.grade}. Valid grades: ${VALID_GRADES2.join(", ")}`
|
|
3885
3971
|
);
|
|
3886
3972
|
}
|
|
3887
|
-
if (hasSubject && !
|
|
3973
|
+
if (hasSubject && !isValidSubject2(options.subject)) {
|
|
3888
3974
|
throw new Error(
|
|
3889
|
-
`Invalid subject: ${options.subject}. Valid subjects: ${
|
|
3975
|
+
`Invalid subject: ${options.subject}. Valid subjects: ${VALID_SUBJECTS2.join(", ")}`
|
|
3890
3976
|
);
|
|
3891
3977
|
}
|
|
3892
3978
|
const params = new URLSearchParams();
|
|
@@ -3903,6 +3989,37 @@ function createTimebackNamespace(client) {
|
|
|
3903
3989
|
const queryString = params.toString();
|
|
3904
3990
|
const endpoint = `/api/timeback/student-xp/${studentId}?${queryString}`;
|
|
3905
3991
|
return client["request"](endpoint, "GET");
|
|
3992
|
+
},
|
|
3993
|
+
getStudentMastery: async (studentId, options) => {
|
|
3994
|
+
const hasGrade = options?.grade !== void 0;
|
|
3995
|
+
const hasSubject = options?.subject !== void 0;
|
|
3996
|
+
if (hasGrade !== hasSubject) {
|
|
3997
|
+
throw new Error("Both grade and subject must be provided together");
|
|
3998
|
+
}
|
|
3999
|
+
if (hasGrade && !isValidGrade2(options.grade)) {
|
|
4000
|
+
throw new Error(
|
|
4001
|
+
`Invalid grade: ${options.grade}. Valid grades: ${VALID_GRADES2.join(", ")}`
|
|
4002
|
+
);
|
|
4003
|
+
}
|
|
4004
|
+
if (hasSubject && !isValidSubject2(options.subject)) {
|
|
4005
|
+
throw new Error(
|
|
4006
|
+
`Invalid subject: ${options.subject}. Valid subjects: ${VALID_SUBJECTS2.join(", ")}`
|
|
4007
|
+
);
|
|
4008
|
+
}
|
|
4009
|
+
const params = new URLSearchParams();
|
|
4010
|
+
params.set("gameId", client.gameId);
|
|
4011
|
+
if (options?.grade !== void 0) {
|
|
4012
|
+
params.set("grade", String(options.grade));
|
|
4013
|
+
}
|
|
4014
|
+
if (options?.subject) {
|
|
4015
|
+
params.set("subject", options.subject);
|
|
4016
|
+
}
|
|
4017
|
+
if (options?.include?.length) {
|
|
4018
|
+
params.set("include", options.include.join(","));
|
|
4019
|
+
}
|
|
4020
|
+
const queryString = params.toString();
|
|
4021
|
+
const endpoint = `/api/timeback/student-mastery/${studentId}?${queryString}`;
|
|
4022
|
+
return client["request"](endpoint, "GET");
|
|
3906
4023
|
}
|
|
3907
4024
|
};
|
|
3908
4025
|
}
|
|
@@ -4499,14 +4616,16 @@ async function registerBuiltinRoutes(app, integrations) {
|
|
|
4499
4616
|
const health = await Promise.resolve().then(() => (init_health(), health_exports));
|
|
4500
4617
|
app.get(ROUTES.HEALTH, health.GET);
|
|
4501
4618
|
if (integrations?.timeback) {
|
|
4502
|
-
const [endActivity, getXp, heartbeat, advanceCourse] = await Promise.all([
|
|
4619
|
+
const [endActivity, getXp, getMastery, heartbeat, advanceCourse] = await Promise.all([
|
|
4503
4620
|
Promise.resolve().then(() => (init_end_activity(), end_activity_exports)),
|
|
4504
4621
|
Promise.resolve().then(() => (init_get_xp(), get_xp_exports)),
|
|
4622
|
+
Promise.resolve().then(() => (init_get_mastery(), get_mastery_exports)),
|
|
4505
4623
|
Promise.resolve().then(() => (init_heartbeat(), heartbeat_exports)),
|
|
4506
4624
|
Promise.resolve().then(() => (init_advance_course(), advance_course_exports))
|
|
4507
4625
|
]);
|
|
4508
4626
|
app.post(ROUTES.TIMEBACK.END_ACTIVITY, endActivity.POST);
|
|
4509
4627
|
app.get(ROUTES.TIMEBACK.GET_XP, getXp.GET);
|
|
4628
|
+
app.get(ROUTES.TIMEBACK.GET_MASTERY, getMastery.GET);
|
|
4510
4629
|
app.post(ROUTES.TIMEBACK.HEARTBEAT, heartbeat.POST);
|
|
4511
4630
|
app.post(ROUTES.TIMEBACK.ADVANCE_COURSE, advanceCourse.POST);
|
|
4512
4631
|
} else if (integrations?.timeback === null) {
|
|
@@ -4525,6 +4644,14 @@ async function registerBuiltinRoutes(app, integrations) {
|
|
|
4525
4644
|
__playcademyDevWarning: "timeback-not-configured"
|
|
4526
4645
|
})
|
|
4527
4646
|
);
|
|
4647
|
+
app.get(
|
|
4648
|
+
"/api/integrations/timeback/mastery",
|
|
4649
|
+
async (c) => c.json({
|
|
4650
|
+
totalMasteredUnits: 0,
|
|
4651
|
+
totalMasterableUnits: 0,
|
|
4652
|
+
__playcademyDevWarning: "timeback-not-configured"
|
|
4653
|
+
})
|
|
4654
|
+
);
|
|
4528
4655
|
app.post(
|
|
4529
4656
|
"/api/integrations/timeback/heartbeat",
|
|
4530
4657
|
async (c) => c.json({
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
|
-
"cliVersion": "0.22.
|
|
3
|
-
"sdkVersion": "0.10.
|
|
4
|
-
"runtimeBuildId": "
|
|
5
|
-
"inputFingerprint": "
|
|
2
|
+
"cliVersion": "0.22.2-beta.2",
|
|
3
|
+
"sdkVersion": "0.10.1-beta.2",
|
|
4
|
+
"runtimeBuildId": "9c6fe529d1f4",
|
|
5
|
+
"inputFingerprint": "9c6fe529d1f48ee9088ace05896b75194ea23409008e5aa76a5d927ab95a919d",
|
|
6
6
|
"entry": "index.js"
|
|
7
7
|
}
|
package/dist/utils.js
CHANGED
|
@@ -305,9 +305,21 @@ import { dirname as dirname3, resolve as resolve3 } from "path";
|
|
|
305
305
|
var TIMEBACK_ROUTES = {
|
|
306
306
|
END_ACTIVITY: "/integrations/timeback/end-activity",
|
|
307
307
|
GET_XP: "/integrations/timeback/xp",
|
|
308
|
+
GET_MASTERY: "/integrations/timeback/mastery",
|
|
308
309
|
HEARTBEAT: "/integrations/timeback/heartbeat",
|
|
309
310
|
ADVANCE_COURSE: "/integrations/timeback/advance-course"
|
|
310
311
|
};
|
|
312
|
+
var TIMEBACK_GAME_METRIC_DECIMAL_PLACES = {
|
|
313
|
+
xp: 1,
|
|
314
|
+
mastery: 0,
|
|
315
|
+
score: 2
|
|
316
|
+
};
|
|
317
|
+
var TIMEBACK_GAME_METRIC_COMPARISON_TOLERANCE = {
|
|
318
|
+
xp: 0.5 / 10 ** TIMEBACK_GAME_METRIC_DECIMAL_PLACES.xp,
|
|
319
|
+
mastery: 0,
|
|
320
|
+
time: 60,
|
|
321
|
+
score: 0.5 / 10 ** TIMEBACK_GAME_METRIC_DECIMAL_PLACES.score
|
|
322
|
+
};
|
|
311
323
|
|
|
312
324
|
// ../constants/src/cloudflare.ts
|
|
313
325
|
var WORKER_NAMING = {
|
|
@@ -345,7 +357,7 @@ var DEFAULT_API_ROUTES_DIRECTORY = join2(SERVER_ROOT_DIRECTORY, "api");
|
|
|
345
357
|
// ../better-auth/package.json
|
|
346
358
|
var package_default = {
|
|
347
359
|
name: "@playcademy/better-auth",
|
|
348
|
-
version: "0.0.
|
|
360
|
+
version: "0.0.15-beta.2",
|
|
349
361
|
type: "module",
|
|
350
362
|
exports: {
|
|
351
363
|
"./server": {
|
|
@@ -1830,6 +1842,7 @@ var ROUTES = {
|
|
|
1830
1842
|
TIMEBACK: {
|
|
1831
1843
|
END_ACTIVITY: `/api${TIMEBACK_ROUTES.END_ACTIVITY}`,
|
|
1832
1844
|
GET_XP: `/api${TIMEBACK_ROUTES.GET_XP}`,
|
|
1845
|
+
GET_MASTERY: `/api${TIMEBACK_ROUTES.GET_MASTERY}`,
|
|
1833
1846
|
HEARTBEAT: `/api${TIMEBACK_ROUTES.HEARTBEAT}`,
|
|
1834
1847
|
ADVANCE_COURSE: `/api${TIMEBACK_ROUTES.ADVANCE_COURSE}`
|
|
1835
1848
|
}
|
|
@@ -2455,7 +2468,7 @@ import { existsSync as existsSync9, mkdirSync as mkdirSync2, writeFileSync as wr
|
|
|
2455
2468
|
import { dirname as dirname4, join as join14 } from "node:path";
|
|
2456
2469
|
|
|
2457
2470
|
// src/version.ts
|
|
2458
|
-
var cliVersion = false ? "0.0.0-dev" : "0.22.
|
|
2471
|
+
var cliVersion = false ? "0.0.0-dev" : "0.22.2-beta.2";
|
|
2459
2472
|
|
|
2460
2473
|
// src/lib/build/binary-resource.ts
|
|
2461
2474
|
function writeFileTree(baseDir, files) {
|
package/dist/version.js
CHANGED