@playcademy/sdk 0.16.0 → 0.16.1-beta.10

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.
@@ -1,4 +1,5 @@
1
1
  import { SchemaInfo } from '@playcademy/cloudflare';
2
+ import { GamePermission } from '@playcademy/constants';
2
3
  import { TimebackCourseConfig, CourseConfig, OrganizationConfig, ComponentConfig, ResourceConfig, ComponentResourceConfig } from '@playcademy/types/timeback';
3
4
  export { ActivityData, ComponentConfig, ComponentResourceConfig, EndActivityPayload, OrganizationConfig, ResourceConfig, TimebackGrade, TimebackSubject } from '@playcademy/types/timeback';
4
5
  import { UserInfo } from '@playcademy/types/user';
@@ -152,6 +153,13 @@ interface PlaycademyConfig {
152
153
  description?: string;
153
154
  /** Game emoji icon */
154
155
  emoji?: string;
156
+ /**
157
+ * Browser permissions to request for the game's iframe (e.g.
158
+ * `['microphone']`). Opt-in per game; only `microphone` and `camera` are
159
+ * delegated this way. Fullscreen, autoplay, and gamepad are granted to
160
+ * every game automatically.
161
+ */
162
+ permissions?: GamePermission[];
155
163
  /** Build command to run before deployment */
156
164
  buildCommand?: string[];
157
165
  /** Path to build output */
@@ -346,6 +354,15 @@ declare class PlaycademyClient {
346
354
  get config(): PlaycademyServerClientState['config'];
347
355
  /** TimeBack integration methods (endActivity) */
348
356
  timeback: {
357
+ assessments: {
358
+ start: (studentId: string, input: _playcademy_types.StartAssessmentInput) => Promise<_playcademy_types.AssessmentAttemptSnapshot>;
359
+ latest: (studentId: string, options: _playcademy_types.GetLatestAssessmentOptions) => Promise<_playcademy_types.LatestAssessmentResult | null>;
360
+ get: (studentId: string, attemptId: string) => Promise<_playcademy_types.AssessmentAttemptSnapshot>;
361
+ save: (studentId: string, attemptId: string, input: _playcademy_types.SaveAssessmentInput) => Promise<_playcademy_types.AssessmentSaveResult>;
362
+ submit: (studentId: string, attemptId: string, input: _playcademy_types.SubmitAssessmentInput, context: {
363
+ sensorUrl: string;
364
+ }) => Promise<_playcademy_types.AssessmentSubmitResult>;
365
+ };
349
366
  endActivity: (studentId: string, payload: _playcademy_types.EndActivityPayload) => Promise<_playcademy_types.EndActivityResponse>;
350
367
  getStudentXp: (studentId: string, options?: {
351
368
  grade?: number;
@@ -10,9 +10,27 @@ var __export = (target, all) => {
10
10
  };
11
11
  var __esm = (fn, res) => () => (fn && (res = fn(fn = 0)), res);
12
12
 
13
- // src/core/guards.ts
14
- var VALID_GRADES = [-1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13];
15
- var VALID_SUBJECTS = [
13
+ // ../constants/src/auth.ts
14
+ var DEFAULT_PERSONAL_API_KEY_PERMISSIONS = {
15
+ games: ["read", "write", "delete"],
16
+ users: ["read:self", "write:self"],
17
+ dev: ["read", "write"]
18
+ };
19
+ // ../constants/src/platform.ts
20
+ var PLAYCADEMY_BROWSER_TIME_ZONE_HEADER = "x-playcademy-browser-time-zone";
21
+ // ../constants/src/timeback.ts
22
+ var TIMEBACK_ROUTES = {
23
+ END_ACTIVITY: "/integrations/timeback/end-activity",
24
+ GET_XP: "/integrations/timeback/xp",
25
+ GET_MASTERY: "/integrations/timeback/mastery",
26
+ GET_HIGHEST_GRADE_MASTERED: "/integrations/timeback/highest-grade-mastered",
27
+ HEARTBEAT: "/integrations/timeback/heartbeat",
28
+ ADVANCE_COURSE: "/integrations/timeback/advance-course",
29
+ UNENROLL_COURSE: "/integrations/timeback/unenroll-course",
30
+ ASSESSMENTS: "/integrations/timeback/assessments"
31
+ };
32
+ var TIMEBACK_GRADES = [-1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13];
33
+ var TIMEBACK_SUBJECTS = [
16
34
  "Reading",
17
35
  "Language",
18
36
  "Vocabulary",
@@ -23,12 +41,39 @@ var VALID_SUBJECTS = [
23
41
  "Math",
24
42
  "None"
25
43
  ];
44
+ var ASSESSMENT_PURPOSES = ["end_of_course", "diagnostic", "review", "mastery"];
45
+ var TIMEBACK_ASSESSMENT_REVIEW_REQUEST_LIMITS = {
46
+ standards: 20,
47
+ itemsPerStandard: 5,
48
+ standardFieldLength: 128
49
+ };
50
+ var VALID_E_LEVELS = ["E1", "E2", "E3", "E4"];
51
+ var TIMEBACK_GAME_METRIC_DECIMAL_PLACES = {
52
+ xp: 1,
53
+ mastery: 0,
54
+ score: 2
55
+ };
56
+ var TIMEBACK_GAME_METRIC_COMPARISON_TOLERANCE = {
57
+ xp: 0.5 / 10 ** TIMEBACK_GAME_METRIC_DECIMAL_PLACES.xp,
58
+ mastery: 0,
59
+ time: 60,
60
+ score: 0.5 / 10 ** TIMEBACK_GAME_METRIC_DECIMAL_PLACES.score
61
+ };
62
+ // src/core/guards.ts
63
+ var VALID_GRADES = TIMEBACK_GRADES;
64
+ var VALID_SUBJECTS = TIMEBACK_SUBJECTS;
26
65
  function isValidGrade(value) {
27
66
  return typeof value === "number" && Number.isInteger(value) && VALID_GRADES.includes(value);
28
67
  }
29
68
  function isValidSubject(value) {
30
69
  return typeof value === "string" && VALID_SUBJECTS.includes(value);
31
70
  }
71
+ function isAssessmentPurpose(value) {
72
+ return typeof value === "string" && ASSESSMENT_PURPOSES.includes(value);
73
+ }
74
+ function isValidELevel(value) {
75
+ return typeof value === "string" && VALID_E_LEVELS.includes(value);
76
+ }
32
77
  // src/server/namespaces/timeback.ts
33
78
  function createTimebackNamespace(client) {
34
79
  function enrichActivityData(data) {
@@ -38,6 +83,39 @@ function createTimebackNamespace(client) {
38
83
  };
39
84
  }
40
85
  return {
86
+ assessments: {
87
+ start: (studentId, input) => client["request"]("/api/timeback/assessments/start", "POST", { ...input, gameId: client.gameId, studentId }),
88
+ latest: (studentId, options) => {
89
+ const params = new URLSearchParams({
90
+ gameId: client.gameId,
91
+ studentId,
92
+ purpose: options.purpose
93
+ });
94
+ if (options.subject !== undefined) {
95
+ params.set("subject", options.subject);
96
+ }
97
+ if (options.grade !== undefined) {
98
+ params.set("grade", String(options.grade));
99
+ }
100
+ if (options.purpose === "mastery") {
101
+ params.set("standardFramework", options.standard.framework);
102
+ params.set("standardIdentifier", options.standard.identifier);
103
+ }
104
+ return client["request"](`/api/timeback/assessments/latest?${params.toString()}`, "GET");
105
+ },
106
+ get: (studentId, attemptId) => {
107
+ const params = new URLSearchParams({ gameId: client.gameId, studentId });
108
+ return client["request"](`/api/timeback/assessments/${encodeURIComponent(attemptId)}?${params.toString()}`, "GET");
109
+ },
110
+ save: (studentId, attemptId, input) => client["request"](`/api/timeback/assessments/${encodeURIComponent(attemptId)}/save`, "POST", { ...input, gameId: client.gameId, studentId }),
111
+ submit: (studentId, attemptId, input, context) => client["request"](`/api/timeback/assessments/${encodeURIComponent(attemptId)}/submit`, "POST", {
112
+ ...input,
113
+ gameId: client.gameId,
114
+ studentId,
115
+ appName: client.config.name,
116
+ sensorUrl: context.sensorUrl
117
+ })
118
+ },
41
119
  endActivity: async (studentId, payload) => {
42
120
  if (!isValidGrade(payload.activityData.grade)) {
43
121
  throw new Error("activityData.grade must be a valid grade level (-1 to 13)");
@@ -234,7 +312,7 @@ function extractApiErrorInfo(error) {
234
312
  }
235
313
 
236
314
  // src/version.ts
237
- var SDK_VERSION = "0.16.0";
315
+ var SDK_VERSION = "0.16.1-beta.10";
238
316
 
239
317
  // src/server/request.ts
240
318
  async function makeApiRequest(opts) {
package/dist/server.d.ts CHANGED
@@ -1,4 +1,5 @@
1
1
  import { SchemaInfo } from '@playcademy/cloudflare';
2
+ import { GamePermission } from '@playcademy/constants';
2
3
  import { TimebackCourseConfig, CourseConfig, OrganizationConfig, ComponentConfig, ResourceConfig, ComponentResourceConfig } from '@playcademy/types/timeback';
3
4
  export { ActivityData, ComponentConfig, ComponentResourceConfig, EndActivityPayload, OrganizationConfig, ResourceConfig, TimebackGrade, TimebackSubject } from '@playcademy/types/timeback';
4
5
  import { UserInfo } from '@playcademy/types/user';
@@ -152,6 +153,13 @@ interface PlaycademyConfig {
152
153
  description?: string;
153
154
  /** Game emoji icon */
154
155
  emoji?: string;
156
+ /**
157
+ * Browser permissions to request for the game's iframe (e.g.
158
+ * `['microphone']`). Opt-in per game; only `microphone` and `camera` are
159
+ * delegated this way. Fullscreen, autoplay, and gamepad are granted to
160
+ * every game automatically.
161
+ */
162
+ permissions?: GamePermission[];
155
163
  /** Build command to run before deployment */
156
164
  buildCommand?: string[];
157
165
  /** Path to build output */
@@ -346,6 +354,15 @@ declare class PlaycademyClient$1 {
346
354
  get config(): PlaycademyServerClientState['config'];
347
355
  /** TimeBack integration methods (endActivity) */
348
356
  timeback: {
357
+ assessments: {
358
+ start: (studentId: string, input: _playcademy_types.StartAssessmentInput) => Promise<_playcademy_types.AssessmentAttemptSnapshot>;
359
+ latest: (studentId: string, options: _playcademy_types.GetLatestAssessmentOptions) => Promise<_playcademy_types.LatestAssessmentResult | null>;
360
+ get: (studentId: string, attemptId: string) => Promise<_playcademy_types.AssessmentAttemptSnapshot>;
361
+ save: (studentId: string, attemptId: string, input: _playcademy_types.SaveAssessmentInput) => Promise<_playcademy_types.AssessmentSaveResult>;
362
+ submit: (studentId: string, attemptId: string, input: _playcademy_types.SubmitAssessmentInput, context: {
363
+ sensorUrl: string;
364
+ }) => Promise<_playcademy_types.AssessmentSubmitResult>;
365
+ };
349
366
  endActivity: (studentId: string, payload: _playcademy_types.EndActivityPayload) => Promise<_playcademy_types.EndActivityResponse>;
350
367
  getStudentXp: (studentId: string, options?: {
351
368
  grade?: number;
package/dist/server.js CHANGED
@@ -199,9 +199,27 @@ var init_config_loader = __esm(() => {
199
199
  init_file_loader();
200
200
  });
201
201
 
202
- // src/core/guards.ts
203
- var VALID_GRADES = [-1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13];
204
- var VALID_SUBJECTS = [
202
+ // ../constants/src/auth.ts
203
+ var DEFAULT_PERSONAL_API_KEY_PERMISSIONS = {
204
+ games: ["read", "write", "delete"],
205
+ users: ["read:self", "write:self"],
206
+ dev: ["read", "write"]
207
+ };
208
+ // ../constants/src/platform.ts
209
+ var PLAYCADEMY_BROWSER_TIME_ZONE_HEADER = "x-playcademy-browser-time-zone";
210
+ // ../constants/src/timeback.ts
211
+ var TIMEBACK_ROUTES = {
212
+ END_ACTIVITY: "/integrations/timeback/end-activity",
213
+ GET_XP: "/integrations/timeback/xp",
214
+ GET_MASTERY: "/integrations/timeback/mastery",
215
+ GET_HIGHEST_GRADE_MASTERED: "/integrations/timeback/highest-grade-mastered",
216
+ HEARTBEAT: "/integrations/timeback/heartbeat",
217
+ ADVANCE_COURSE: "/integrations/timeback/advance-course",
218
+ UNENROLL_COURSE: "/integrations/timeback/unenroll-course",
219
+ ASSESSMENTS: "/integrations/timeback/assessments"
220
+ };
221
+ var TIMEBACK_GRADES = [-1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13];
222
+ var TIMEBACK_SUBJECTS = [
205
223
  "Reading",
206
224
  "Language",
207
225
  "Vocabulary",
@@ -212,12 +230,39 @@ var VALID_SUBJECTS = [
212
230
  "Math",
213
231
  "None"
214
232
  ];
233
+ var ASSESSMENT_PURPOSES = ["end_of_course", "diagnostic", "review", "mastery"];
234
+ var TIMEBACK_ASSESSMENT_REVIEW_REQUEST_LIMITS = {
235
+ standards: 20,
236
+ itemsPerStandard: 5,
237
+ standardFieldLength: 128
238
+ };
239
+ var VALID_E_LEVELS = ["E1", "E2", "E3", "E4"];
240
+ var TIMEBACK_GAME_METRIC_DECIMAL_PLACES = {
241
+ xp: 1,
242
+ mastery: 0,
243
+ score: 2
244
+ };
245
+ var TIMEBACK_GAME_METRIC_COMPARISON_TOLERANCE = {
246
+ xp: 0.5 / 10 ** TIMEBACK_GAME_METRIC_DECIMAL_PLACES.xp,
247
+ mastery: 0,
248
+ time: 60,
249
+ score: 0.5 / 10 ** TIMEBACK_GAME_METRIC_DECIMAL_PLACES.score
250
+ };
251
+ // src/core/guards.ts
252
+ var VALID_GRADES = TIMEBACK_GRADES;
253
+ var VALID_SUBJECTS = TIMEBACK_SUBJECTS;
215
254
  function isValidGrade(value) {
216
255
  return typeof value === "number" && Number.isInteger(value) && VALID_GRADES.includes(value);
217
256
  }
218
257
  function isValidSubject(value) {
219
258
  return typeof value === "string" && VALID_SUBJECTS.includes(value);
220
259
  }
260
+ function isAssessmentPurpose(value) {
261
+ return typeof value === "string" && ASSESSMENT_PURPOSES.includes(value);
262
+ }
263
+ function isValidELevel(value) {
264
+ return typeof value === "string" && VALID_E_LEVELS.includes(value);
265
+ }
221
266
  // src/server/namespaces/timeback.ts
222
267
  function createTimebackNamespace(client) {
223
268
  function enrichActivityData(data) {
@@ -227,6 +272,39 @@ function createTimebackNamespace(client) {
227
272
  };
228
273
  }
229
274
  return {
275
+ assessments: {
276
+ start: (studentId, input) => client["request"]("/api/timeback/assessments/start", "POST", { ...input, gameId: client.gameId, studentId }),
277
+ latest: (studentId, options) => {
278
+ const params = new URLSearchParams({
279
+ gameId: client.gameId,
280
+ studentId,
281
+ purpose: options.purpose
282
+ });
283
+ if (options.subject !== undefined) {
284
+ params.set("subject", options.subject);
285
+ }
286
+ if (options.grade !== undefined) {
287
+ params.set("grade", String(options.grade));
288
+ }
289
+ if (options.purpose === "mastery") {
290
+ params.set("standardFramework", options.standard.framework);
291
+ params.set("standardIdentifier", options.standard.identifier);
292
+ }
293
+ return client["request"](`/api/timeback/assessments/latest?${params.toString()}`, "GET");
294
+ },
295
+ get: (studentId, attemptId) => {
296
+ const params = new URLSearchParams({ gameId: client.gameId, studentId });
297
+ return client["request"](`/api/timeback/assessments/${encodeURIComponent(attemptId)}?${params.toString()}`, "GET");
298
+ },
299
+ save: (studentId, attemptId, input) => client["request"](`/api/timeback/assessments/${encodeURIComponent(attemptId)}/save`, "POST", { ...input, gameId: client.gameId, studentId }),
300
+ submit: (studentId, attemptId, input, context) => client["request"](`/api/timeback/assessments/${encodeURIComponent(attemptId)}/submit`, "POST", {
301
+ ...input,
302
+ gameId: client.gameId,
303
+ studentId,
304
+ appName: client.config.name,
305
+ sensorUrl: context.sensorUrl
306
+ })
307
+ },
230
308
  endActivity: async (studentId, payload) => {
231
309
  if (!isValidGrade(payload.activityData.grade)) {
232
310
  throw new Error("activityData.grade must be a valid grade level (-1 to 13)");
@@ -423,7 +501,7 @@ function extractApiErrorInfo(error) {
423
501
  }
424
502
 
425
503
  // src/version.ts
426
- var SDK_VERSION = "0.16.0";
504
+ var SDK_VERSION = "0.16.1-beta.10";
427
505
 
428
506
  // src/server/request.ts
429
507
  async function makeApiRequest(opts) {