@playcademy/sdk 0.2.11 → 0.2.12
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.d.ts +107 -12
- package/dist/index.js +70 -2
- package/dist/internal.d.ts +351 -596
- package/dist/internal.js +70 -2
- package/dist/server.d.ts +33 -0
- package/dist/server.js +28 -2
- package/dist/types.d.ts +135 -57
- package/package.json +3 -3
package/dist/index.d.ts
CHANGED
|
@@ -450,6 +450,23 @@ interface AuthenticatedUser {
|
|
|
450
450
|
timeback?: UserTimebackData;
|
|
451
451
|
}
|
|
452
452
|
|
|
453
|
+
/**
|
|
454
|
+
* TimeBack Enums & Literal Types
|
|
455
|
+
*
|
|
456
|
+
* Basic type definitions used throughout the TimeBack integration.
|
|
457
|
+
*
|
|
458
|
+
* @module types/timeback/types
|
|
459
|
+
*/
|
|
460
|
+
/**
|
|
461
|
+
* Valid TimeBack subject values for course configuration.
|
|
462
|
+
* These are the supported subject values for OneRoster courses.
|
|
463
|
+
*/
|
|
464
|
+
type TimebackSubject = 'Reading' | 'Language' | 'Vocabulary' | 'Social Studies' | 'Writing' | 'Science' | 'FastMath' | 'Math' | 'None';
|
|
465
|
+
/**
|
|
466
|
+
* Grade levels per AE OneRoster GradeEnum.
|
|
467
|
+
* -1 = Pre-K, 0 = Kindergarten, 1-12 = Grades 1-12, 13 = AP
|
|
468
|
+
*/
|
|
469
|
+
type TimebackGrade = -1 | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13;
|
|
453
470
|
/**
|
|
454
471
|
* Valid Caliper subject values.
|
|
455
472
|
* Matches OneRoster subjects, with "None" as a Caliper-specific fallback.
|
|
@@ -618,7 +635,7 @@ declare const items: drizzle_orm_pg_core.PgTableWithColumns<{
|
|
|
618
635
|
tableName: "items";
|
|
619
636
|
dataType: "string";
|
|
620
637
|
columnType: "PgEnumColumn";
|
|
621
|
-
data: "
|
|
638
|
+
data: "currency" | "badge" | "trophy" | "collectible" | "consumable" | "unlock" | "upgrade" | "accessory" | "other";
|
|
622
639
|
driverParam: string;
|
|
623
640
|
notNull: true;
|
|
624
641
|
hasDefault: true;
|
|
@@ -999,6 +1016,9 @@ declare abstract class PlaycademyBaseClient {
|
|
|
999
1016
|
* Initializes connection monitoring if enabled.
|
|
1000
1017
|
*/
|
|
1001
1018
|
private _initializeConnectionMonitor;
|
|
1019
|
+
/**
|
|
1020
|
+
* Initializes an internal game session for automatic session management.
|
|
1021
|
+
*/
|
|
1002
1022
|
private _initializeInternalSession;
|
|
1003
1023
|
/**
|
|
1004
1024
|
* Current user data and inventory management.
|
|
@@ -1042,8 +1062,8 @@ declare class PlaycademyClient extends PlaycademyBaseClient {
|
|
|
1042
1062
|
*/
|
|
1043
1063
|
runtime: {
|
|
1044
1064
|
getGameToken: (gameId: string, options?: {
|
|
1045
|
-
apply?: boolean
|
|
1046
|
-
}
|
|
1065
|
+
apply?: boolean;
|
|
1066
|
+
}) => Promise<GameTokenResponse>;
|
|
1047
1067
|
exit: () => Promise<void>;
|
|
1048
1068
|
onInit: (handler: (context: GameContextPayload) => void) => void;
|
|
1049
1069
|
onTokenRefresh: (handler: (data: {
|
|
@@ -1067,7 +1087,7 @@ declare class PlaycademyClient extends PlaycademyBaseClient {
|
|
|
1067
1087
|
getListenerCounts: () => Record<string, number>;
|
|
1068
1088
|
assets: {
|
|
1069
1089
|
url(pathOrStrings: string | TemplateStringsArray, ...values: unknown[]): string;
|
|
1070
|
-
fetch: (path: string, options?: RequestInit
|
|
1090
|
+
fetch: (path: string, options?: RequestInit) => Promise<Response>;
|
|
1071
1091
|
json: <T = unknown>(path: string) => Promise<T>;
|
|
1072
1092
|
blob: (path: string) => Promise<Blob>;
|
|
1073
1093
|
text: (path: string) => Promise<string>;
|
|
@@ -1110,7 +1130,7 @@ declare class PlaycademyClient extends PlaycademyBaseClient {
|
|
|
1110
1130
|
* - `submit(gameId, score, metadata?)` - Record a game score
|
|
1111
1131
|
*/
|
|
1112
1132
|
scores: {
|
|
1113
|
-
submit: (gameId: string, score: number, metadata?: Record<string, unknown>
|
|
1133
|
+
submit: (gameId: string, score: number, metadata?: Record<string, unknown>) => Promise<ScoreSubmission>;
|
|
1114
1134
|
};
|
|
1115
1135
|
/**
|
|
1116
1136
|
* Realtime multiplayer authentication.
|
|
@@ -1127,13 +1147,13 @@ declare class PlaycademyClient extends PlaycademyBaseClient {
|
|
|
1127
1147
|
* - Routes are relative to your game's deployment (e.g., '/hello' → your-game.playcademy.gg/api/hello)
|
|
1128
1148
|
*/
|
|
1129
1149
|
backend: {
|
|
1130
|
-
get<T = unknown>(path: string, headers?: Record<string, string>
|
|
1131
|
-
post<T = unknown>(path: string, body?: unknown, headers?: Record<string, string>
|
|
1132
|
-
put<T = unknown>(path: string, body?: unknown, headers?: Record<string, string>
|
|
1133
|
-
patch<T = unknown>(path: string, body?: unknown, headers?: Record<string, string>
|
|
1134
|
-
delete<T = unknown>(path: string, headers?: Record<string, string>
|
|
1135
|
-
request<T = unknown>(path: string, method: Method, body?: unknown, headers?: Record<string, string>
|
|
1136
|
-
download(path: string, method?: Method, body?: unknown, headers?: Record<string, string>
|
|
1150
|
+
get<T = unknown>(path: string, headers?: Record<string, string>): Promise<T>;
|
|
1151
|
+
post<T = unknown>(path: string, body?: unknown, headers?: Record<string, string>): Promise<T>;
|
|
1152
|
+
put<T = unknown>(path: string, body?: unknown, headers?: Record<string, string>): Promise<T>;
|
|
1153
|
+
patch<T = unknown>(path: string, body?: unknown, headers?: Record<string, string>): Promise<T>;
|
|
1154
|
+
delete<T = unknown>(path: string, headers?: Record<string, string>): Promise<T>;
|
|
1155
|
+
request<T = unknown>(path: string, method: Method, body?: unknown, headers?: Record<string, string>): Promise<T>;
|
|
1156
|
+
download(path: string, method?: Method, body?: unknown, headers?: Record<string, string>): Promise<Response>;
|
|
1137
1157
|
url(pathOrStrings: string | TemplateStringsArray, ...values: unknown[]): string;
|
|
1138
1158
|
};
|
|
1139
1159
|
/** Auto-initializes a PlaycademyClient with context from the environment */
|
|
@@ -1191,6 +1211,45 @@ interface TimebackUserContext {
|
|
|
1191
1211
|
/** User's organizations (schools/districts) */
|
|
1192
1212
|
organizations: TimebackOrganization[];
|
|
1193
1213
|
}
|
|
1214
|
+
/**
|
|
1215
|
+
* XP data access for the current user.
|
|
1216
|
+
* Results are cached for 5 seconds to avoid redundant network requests.
|
|
1217
|
+
*/
|
|
1218
|
+
interface TimebackUserXp {
|
|
1219
|
+
/**
|
|
1220
|
+
* Fetch XP data from the server.
|
|
1221
|
+
* Returns XP for all courses in this game, or filter by grade/subject.
|
|
1222
|
+
* Results are cached for 5 seconds (use `force: true` to bypass).
|
|
1223
|
+
*
|
|
1224
|
+
* @param options - Query options
|
|
1225
|
+
* @param options.grade - Grade level to filter (must be used with subject)
|
|
1226
|
+
* @param options.subject - Subject to filter (must be used with grade)
|
|
1227
|
+
* @param options.include - Additional data to include: 'perCourse', 'today'
|
|
1228
|
+
* @param options.force - Bypass cache and fetch fresh data (default: false)
|
|
1229
|
+
* @returns Promise resolving to XP data
|
|
1230
|
+
*
|
|
1231
|
+
* @example
|
|
1232
|
+
* ```typescript
|
|
1233
|
+
* // Get total XP for all game courses
|
|
1234
|
+
* const xp = await client.timeback.user.xp.fetch()
|
|
1235
|
+
*
|
|
1236
|
+
* // Get XP for a specific grade/subject
|
|
1237
|
+
* const xp = await client.timeback.user.xp.fetch({
|
|
1238
|
+
* grade: 3,
|
|
1239
|
+
* subject: 'Math'
|
|
1240
|
+
* })
|
|
1241
|
+
*
|
|
1242
|
+
* // Get XP with per-course breakdown
|
|
1243
|
+
* const xp = await client.timeback.user.xp.fetch({
|
|
1244
|
+
* include: ['perCourse', 'today']
|
|
1245
|
+
* })
|
|
1246
|
+
*
|
|
1247
|
+
* // Force fresh data
|
|
1248
|
+
* const xp = await client.timeback.user.xp.fetch({ force: true })
|
|
1249
|
+
* ```
|
|
1250
|
+
*/
|
|
1251
|
+
fetch(options?: GetXpOptions): Promise<XpResponse>;
|
|
1252
|
+
}
|
|
1194
1253
|
/**
|
|
1195
1254
|
* TimeBack user object with both cached getters and fetch method.
|
|
1196
1255
|
*/
|
|
@@ -1204,6 +1263,42 @@ interface TimebackUser extends TimebackUserContext {
|
|
|
1204
1263
|
fetch(options?: {
|
|
1205
1264
|
force?: boolean;
|
|
1206
1265
|
}): Promise<TimebackUserContext>;
|
|
1266
|
+
/**
|
|
1267
|
+
* XP data for the current user.
|
|
1268
|
+
* Call `xp.fetch()` to get XP from the server.
|
|
1269
|
+
*/
|
|
1270
|
+
xp: TimebackUserXp;
|
|
1271
|
+
}
|
|
1272
|
+
/**
|
|
1273
|
+
* Options for querying student XP.
|
|
1274
|
+
*/
|
|
1275
|
+
interface GetXpOptions {
|
|
1276
|
+
/** Grade level to filter (must be used with subject) */
|
|
1277
|
+
grade?: TimebackGrade;
|
|
1278
|
+
/** Subject to filter (must be used with grade) */
|
|
1279
|
+
subject?: TimebackSubject;
|
|
1280
|
+
/** Additional data to include: 'perCourse', 'today' */
|
|
1281
|
+
include?: ('perCourse' | 'today')[];
|
|
1282
|
+
/** Bypass cache and fetch fresh data (default: false) */
|
|
1283
|
+
force?: boolean;
|
|
1284
|
+
}
|
|
1285
|
+
/**
|
|
1286
|
+
* XP data for a single course.
|
|
1287
|
+
*/
|
|
1288
|
+
interface CourseXp {
|
|
1289
|
+
grade: TimebackGrade;
|
|
1290
|
+
subject: TimebackSubject;
|
|
1291
|
+
title: string;
|
|
1292
|
+
totalXp: number;
|
|
1293
|
+
todayXp?: number;
|
|
1294
|
+
}
|
|
1295
|
+
/**
|
|
1296
|
+
* Response from XP query.
|
|
1297
|
+
*/
|
|
1298
|
+
interface XpResponse {
|
|
1299
|
+
totalXp: number;
|
|
1300
|
+
todayXp?: number;
|
|
1301
|
+
courses?: CourseXp[];
|
|
1207
1302
|
}
|
|
1208
1303
|
|
|
1209
1304
|
/**
|
package/dist/index.js
CHANGED
|
@@ -1185,7 +1185,7 @@ var ACHIEVEMENT_DEFINITIONS = [
|
|
|
1185
1185
|
}
|
|
1186
1186
|
];
|
|
1187
1187
|
// ../constants/src/typescript.ts
|
|
1188
|
-
var TSC_PACKAGE = "
|
|
1188
|
+
var TSC_PACKAGE = "typescript";
|
|
1189
1189
|
var USE_NATIVE_TSC = TSC_PACKAGE.includes("native-preview");
|
|
1190
1190
|
// ../constants/src/overworld.ts
|
|
1191
1191
|
var ITEM_SLUGS = {
|
|
@@ -1212,7 +1212,8 @@ var BADGES = {
|
|
|
1212
1212
|
};
|
|
1213
1213
|
// ../constants/src/timeback.ts
|
|
1214
1214
|
var TIMEBACK_ROUTES = {
|
|
1215
|
-
END_ACTIVITY: "/integrations/timeback/end-activity"
|
|
1215
|
+
END_ACTIVITY: "/integrations/timeback/end-activity",
|
|
1216
|
+
GET_XP: "/integrations/timeback/xp"
|
|
1216
1217
|
};
|
|
1217
1218
|
// src/core/cache/singleton-cache.ts
|
|
1218
1219
|
function createSingletonCache() {
|
|
@@ -1390,6 +1391,26 @@ function createTTLCache(options) {
|
|
|
1390
1391
|
return { get, clear, size, prune, getKeys, has };
|
|
1391
1392
|
}
|
|
1392
1393
|
|
|
1394
|
+
// src/core/guards.ts
|
|
1395
|
+
var VALID_GRADES = [-1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13];
|
|
1396
|
+
var VALID_SUBJECTS = [
|
|
1397
|
+
"Reading",
|
|
1398
|
+
"Language",
|
|
1399
|
+
"Vocabulary",
|
|
1400
|
+
"Social Studies",
|
|
1401
|
+
"Writing",
|
|
1402
|
+
"Science",
|
|
1403
|
+
"FastMath",
|
|
1404
|
+
"Math",
|
|
1405
|
+
"None"
|
|
1406
|
+
];
|
|
1407
|
+
function isValidGrade(value) {
|
|
1408
|
+
return typeof value === "number" && Number.isInteger(value) && VALID_GRADES.includes(value);
|
|
1409
|
+
}
|
|
1410
|
+
function isValidSubject(value) {
|
|
1411
|
+
return typeof value === "string" && VALID_SUBJECTS.includes(value);
|
|
1412
|
+
}
|
|
1413
|
+
|
|
1393
1414
|
// src/namespaces/game/timeback.ts
|
|
1394
1415
|
function createTimebackNamespace(client) {
|
|
1395
1416
|
let currentActivity = null;
|
|
@@ -1397,6 +1418,10 @@ function createTimebackNamespace(client) {
|
|
|
1397
1418
|
ttl: 5 * 60 * 1000,
|
|
1398
1419
|
keyPrefix: "game.timeback.user"
|
|
1399
1420
|
});
|
|
1421
|
+
const xpCache = createTTLCache({
|
|
1422
|
+
ttl: 5000,
|
|
1423
|
+
keyPrefix: "game.timeback.xp"
|
|
1424
|
+
});
|
|
1400
1425
|
const getTimeback = () => client["initPayload"]?.timeback;
|
|
1401
1426
|
return {
|
|
1402
1427
|
get user() {
|
|
@@ -1427,6 +1452,49 @@ function createTimebackNamespace(client) {
|
|
|
1427
1452
|
organizations: response.organizations
|
|
1428
1453
|
};
|
|
1429
1454
|
}, options);
|
|
1455
|
+
},
|
|
1456
|
+
xp: {
|
|
1457
|
+
fetch: async (options) => {
|
|
1458
|
+
const hasGrade = options?.grade !== undefined;
|
|
1459
|
+
const hasSubject = options?.subject !== undefined;
|
|
1460
|
+
if (hasGrade !== hasSubject) {
|
|
1461
|
+
throw new Error("Both grade and subject must be provided together");
|
|
1462
|
+
}
|
|
1463
|
+
if (hasGrade && !isValidGrade(options.grade)) {
|
|
1464
|
+
throw new Error(`Invalid grade: ${options.grade}. Valid grades: ${VALID_GRADES.join(", ")}`);
|
|
1465
|
+
}
|
|
1466
|
+
if (hasSubject && !isValidSubject(options.subject)) {
|
|
1467
|
+
throw new Error(`Invalid subject: ${options.subject}. Valid subjects: ${VALID_SUBJECTS.join(", ")}`);
|
|
1468
|
+
}
|
|
1469
|
+
const validIncludeOptions = ["perCourse", "today"];
|
|
1470
|
+
if (options?.include?.length) {
|
|
1471
|
+
for (const opt of options.include) {
|
|
1472
|
+
if (!validIncludeOptions.includes(opt)) {
|
|
1473
|
+
throw new Error(`Invalid include option: ${opt}. Valid options: ${validIncludeOptions.join(", ")}`);
|
|
1474
|
+
}
|
|
1475
|
+
}
|
|
1476
|
+
}
|
|
1477
|
+
const cacheKey = [
|
|
1478
|
+
options?.grade ?? "",
|
|
1479
|
+
options?.subject ?? "",
|
|
1480
|
+
options?.include?.sort().join(",") ?? ""
|
|
1481
|
+
].join(":");
|
|
1482
|
+
return xpCache.get(cacheKey, async () => {
|
|
1483
|
+
const params = new URLSearchParams;
|
|
1484
|
+
if (hasGrade) {
|
|
1485
|
+
params.set("grade", String(options.grade));
|
|
1486
|
+
}
|
|
1487
|
+
if (hasSubject) {
|
|
1488
|
+
params.set("subject", options.subject);
|
|
1489
|
+
}
|
|
1490
|
+
if (options?.include?.length) {
|
|
1491
|
+
params.set("include", options.include.join(","));
|
|
1492
|
+
}
|
|
1493
|
+
const queryString = params.toString();
|
|
1494
|
+
const endpoint = `${TIMEBACK_ROUTES.GET_XP}${queryString ? `?${queryString}` : ""}`;
|
|
1495
|
+
return client["requestGameBackend"](endpoint, "GET");
|
|
1496
|
+
}, { force: options?.force });
|
|
1497
|
+
}
|
|
1430
1498
|
}
|
|
1431
1499
|
};
|
|
1432
1500
|
},
|