@playcademy/sandbox 0.3.17-beta.10 → 0.3.17-beta.11

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 CHANGED
@@ -1311,7 +1311,7 @@ var package_default;
1311
1311
  var init_package = __esm(() => {
1312
1312
  package_default = {
1313
1313
  name: "@playcademy/sandbox",
1314
- version: "0.3.17-beta.10",
1314
+ version: "0.3.17-beta.11",
1315
1315
  description: "Local development server for Playcademy game development",
1316
1316
  type: "module",
1317
1317
  exports: {
@@ -31808,7 +31808,8 @@ var init_timeback_service = __esm(() => {
31808
31808
  }) {
31809
31809
  const client = this.requireClient();
31810
31810
  const db2 = this.deps.db;
31811
- const extensionsWithResumeId = TimebackService.addResumeIdToExtensions(extensions, resumeId);
31811
+ const effectiveResumeId = resumeId ?? runId ?? crypto.randomUUID();
31812
+ const extensionsWithResumeId = TimebackService.addResumeIdToExtensions(extensions, effectiveResumeId);
31812
31813
  await this.deps.validateDeveloperAccess(user, gameId);
31813
31814
  const integration = await db2.query.gameTimebackIntegrations.findFirst({
31814
31815
  where: and(eq(gameTimebackIntegrations.gameId, gameId), eq(gameTimebackIntegrations.grade, activityData.grade), eq(gameTimebackIntegrations.subject, activityData.subject))
@@ -31881,18 +31882,26 @@ var init_timeback_service = __esm(() => {
31881
31882
  activityData,
31882
31883
  timingData,
31883
31884
  windowStartedAtMs,
31885
+ windowSequence,
31884
31886
  isFinal,
31885
31887
  user
31886
31888
  }) {
31887
31889
  const client = this.requireClient();
31888
31890
  const db2 = this.deps.db;
31889
- const heartbeatWindowKey = `${runId}:${windowStartedAtMs}`;
31891
+ const hasWindowStartedAtMs = windowStartedAtMs !== undefined;
31892
+ const hasWindowSequence = windowSequence !== undefined;
31893
+ if (hasWindowStartedAtMs === hasWindowSequence) {
31894
+ throw new ValidationError("Provide exactly one of windowStartedAtMs or windowSequence");
31895
+ }
31896
+ const heartbeatWindowKey = hasWindowStartedAtMs ? `${runId}:t:${windowStartedAtMs}` : `${runId}:s:${windowSequence}`;
31897
+ const effectiveResumeId = resumeId ?? runId;
31890
31898
  if (TimebackService.isDuplicateHeartbeatWindow(heartbeatWindowKey)) {
31891
31899
  logger17.debug("Skipping duplicate heartbeat window", {
31892
31900
  gameId,
31893
31901
  studentId,
31894
31902
  runId,
31895
31903
  windowStartedAtMs,
31904
+ windowSequence,
31896
31905
  isFinal
31897
31906
  });
31898
31907
  return { status: "ok" };
@@ -31905,6 +31914,7 @@ var init_timeback_service = __esm(() => {
31905
31914
  studentId,
31906
31915
  runId,
31907
31916
  windowStartedAtMs,
31917
+ windowSequence,
31908
31918
  isFinal
31909
31919
  });
31910
31920
  return inFlightHeartbeat;
@@ -31931,7 +31941,7 @@ var init_timeback_service = __esm(() => {
31931
31941
  courseId: activityData.courseId,
31932
31942
  courseName: activityData.courseName,
31933
31943
  studentEmail: activityData.studentEmail,
31934
- extensions: TimebackService.addResumeIdToExtensions(undefined, resumeId),
31944
+ extensions: TimebackService.addResumeIdToExtensions(undefined, effectiveResumeId),
31935
31945
  ...runId ? { runId } : {}
31936
31946
  });
31937
31947
  }
@@ -31942,6 +31952,7 @@ var init_timeback_service = __esm(() => {
31942
31952
  studentId,
31943
31953
  runId,
31944
31954
  windowStartedAtMs,
31955
+ windowSequence,
31945
31956
  activeTimeSeconds,
31946
31957
  isFinal
31947
31958
  });
@@ -93846,7 +93857,7 @@ var init_schemas11 = __esm(() => {
93846
93857
  gameId: exports_external.string().uuid(),
93847
93858
  studentId: exports_external.string().min(1),
93848
93859
  runId: exports_external.string().uuid().optional(),
93849
- resumeId: exports_external.string().uuid(),
93860
+ resumeId: exports_external.string().uuid().optional(),
93850
93861
  activityData: TimebackActivityDataSchema,
93851
93862
  scoreData: exports_external.object({
93852
93863
  correctQuestions: exports_external.number().int().min(0),
@@ -93867,14 +93878,18 @@ var init_schemas11 = __esm(() => {
93867
93878
  gameId: exports_external.string().uuid(),
93868
93879
  studentId: exports_external.string().min(1),
93869
93880
  runId: exports_external.string().uuid(),
93870
- resumeId: exports_external.string().uuid(),
93881
+ resumeId: exports_external.string().uuid().optional(),
93871
93882
  activityData: TimebackActivityDataSchema,
93872
93883
  timingData: exports_external.object({
93873
93884
  activeMs: exports_external.number().nonnegative(),
93874
93885
  pausedMs: exports_external.number().nonnegative()
93875
93886
  }),
93876
- windowStartedAtMs: exports_external.number().int().nonnegative(),
93887
+ windowStartedAtMs: exports_external.number().int().nonnegative().optional(),
93888
+ windowSequence: exports_external.number().int().nonnegative().optional(),
93877
93889
  isFinal: exports_external.boolean().optional()
93890
+ }).refine((value) => value.windowStartedAtMs !== undefined !== (value.windowSequence !== undefined), {
93891
+ message: "Provide exactly one of windowStartedAtMs or windowSequence",
93892
+ path: ["windowStartedAtMs"]
93878
93893
  });
93879
93894
  PopulateStudentRequestSchema = exports_external.object({
93880
93895
  firstName: exports_external.string().min(1).optional(),
@@ -96321,6 +96336,7 @@ var init_timeback_controller = __esm(() => {
96321
96336
  activityData,
96322
96337
  timingData,
96323
96338
  windowStartedAtMs,
96339
+ windowSequence,
96324
96340
  isFinal
96325
96341
  } = body2;
96326
96342
  logger63.debug("Recording heartbeat", {
@@ -96329,6 +96345,7 @@ var init_timeback_controller = __esm(() => {
96329
96345
  runId,
96330
96346
  resumeId,
96331
96347
  windowStartedAtMs,
96348
+ windowSequence,
96332
96349
  activeMs: timingData.activeMs,
96333
96350
  isFinal
96334
96351
  });
@@ -96340,6 +96357,7 @@ var init_timeback_controller = __esm(() => {
96340
96357
  activityData,
96341
96358
  timingData,
96342
96359
  windowStartedAtMs,
96360
+ windowSequence,
96343
96361
  isFinal,
96344
96362
  user: ctx.user
96345
96363
  });
package/dist/server.js CHANGED
@@ -1310,7 +1310,7 @@ var package_default;
1310
1310
  var init_package = __esm(() => {
1311
1311
  package_default = {
1312
1312
  name: "@playcademy/sandbox",
1313
- version: "0.3.17-beta.10",
1313
+ version: "0.3.17-beta.11",
1314
1314
  description: "Local development server for Playcademy game development",
1315
1315
  type: "module",
1316
1316
  exports: {
@@ -31807,7 +31807,8 @@ var init_timeback_service = __esm(() => {
31807
31807
  }) {
31808
31808
  const client = this.requireClient();
31809
31809
  const db2 = this.deps.db;
31810
- const extensionsWithResumeId = TimebackService.addResumeIdToExtensions(extensions, resumeId);
31810
+ const effectiveResumeId = resumeId ?? runId ?? crypto.randomUUID();
31811
+ const extensionsWithResumeId = TimebackService.addResumeIdToExtensions(extensions, effectiveResumeId);
31811
31812
  await this.deps.validateDeveloperAccess(user, gameId);
31812
31813
  const integration = await db2.query.gameTimebackIntegrations.findFirst({
31813
31814
  where: and(eq(gameTimebackIntegrations.gameId, gameId), eq(gameTimebackIntegrations.grade, activityData.grade), eq(gameTimebackIntegrations.subject, activityData.subject))
@@ -31880,18 +31881,26 @@ var init_timeback_service = __esm(() => {
31880
31881
  activityData,
31881
31882
  timingData,
31882
31883
  windowStartedAtMs,
31884
+ windowSequence,
31883
31885
  isFinal,
31884
31886
  user
31885
31887
  }) {
31886
31888
  const client = this.requireClient();
31887
31889
  const db2 = this.deps.db;
31888
- const heartbeatWindowKey = `${runId}:${windowStartedAtMs}`;
31890
+ const hasWindowStartedAtMs = windowStartedAtMs !== undefined;
31891
+ const hasWindowSequence = windowSequence !== undefined;
31892
+ if (hasWindowStartedAtMs === hasWindowSequence) {
31893
+ throw new ValidationError("Provide exactly one of windowStartedAtMs or windowSequence");
31894
+ }
31895
+ const heartbeatWindowKey = hasWindowStartedAtMs ? `${runId}:t:${windowStartedAtMs}` : `${runId}:s:${windowSequence}`;
31896
+ const effectiveResumeId = resumeId ?? runId;
31889
31897
  if (TimebackService.isDuplicateHeartbeatWindow(heartbeatWindowKey)) {
31890
31898
  logger17.debug("Skipping duplicate heartbeat window", {
31891
31899
  gameId,
31892
31900
  studentId,
31893
31901
  runId,
31894
31902
  windowStartedAtMs,
31903
+ windowSequence,
31895
31904
  isFinal
31896
31905
  });
31897
31906
  return { status: "ok" };
@@ -31904,6 +31913,7 @@ var init_timeback_service = __esm(() => {
31904
31913
  studentId,
31905
31914
  runId,
31906
31915
  windowStartedAtMs,
31916
+ windowSequence,
31907
31917
  isFinal
31908
31918
  });
31909
31919
  return inFlightHeartbeat;
@@ -31930,7 +31940,7 @@ var init_timeback_service = __esm(() => {
31930
31940
  courseId: activityData.courseId,
31931
31941
  courseName: activityData.courseName,
31932
31942
  studentEmail: activityData.studentEmail,
31933
- extensions: TimebackService.addResumeIdToExtensions(undefined, resumeId),
31943
+ extensions: TimebackService.addResumeIdToExtensions(undefined, effectiveResumeId),
31934
31944
  ...runId ? { runId } : {}
31935
31945
  });
31936
31946
  }
@@ -31941,6 +31951,7 @@ var init_timeback_service = __esm(() => {
31941
31951
  studentId,
31942
31952
  runId,
31943
31953
  windowStartedAtMs,
31954
+ windowSequence,
31944
31955
  activeTimeSeconds,
31945
31956
  isFinal
31946
31957
  });
@@ -93845,7 +93856,7 @@ var init_schemas11 = __esm(() => {
93845
93856
  gameId: exports_external.string().uuid(),
93846
93857
  studentId: exports_external.string().min(1),
93847
93858
  runId: exports_external.string().uuid().optional(),
93848
- resumeId: exports_external.string().uuid(),
93859
+ resumeId: exports_external.string().uuid().optional(),
93849
93860
  activityData: TimebackActivityDataSchema,
93850
93861
  scoreData: exports_external.object({
93851
93862
  correctQuestions: exports_external.number().int().min(0),
@@ -93866,14 +93877,18 @@ var init_schemas11 = __esm(() => {
93866
93877
  gameId: exports_external.string().uuid(),
93867
93878
  studentId: exports_external.string().min(1),
93868
93879
  runId: exports_external.string().uuid(),
93869
- resumeId: exports_external.string().uuid(),
93880
+ resumeId: exports_external.string().uuid().optional(),
93870
93881
  activityData: TimebackActivityDataSchema,
93871
93882
  timingData: exports_external.object({
93872
93883
  activeMs: exports_external.number().nonnegative(),
93873
93884
  pausedMs: exports_external.number().nonnegative()
93874
93885
  }),
93875
- windowStartedAtMs: exports_external.number().int().nonnegative(),
93886
+ windowStartedAtMs: exports_external.number().int().nonnegative().optional(),
93887
+ windowSequence: exports_external.number().int().nonnegative().optional(),
93876
93888
  isFinal: exports_external.boolean().optional()
93889
+ }).refine((value) => value.windowStartedAtMs !== undefined !== (value.windowSequence !== undefined), {
93890
+ message: "Provide exactly one of windowStartedAtMs or windowSequence",
93891
+ path: ["windowStartedAtMs"]
93877
93892
  });
93878
93893
  PopulateStudentRequestSchema = exports_external.object({
93879
93894
  firstName: exports_external.string().min(1).optional(),
@@ -96320,6 +96335,7 @@ var init_timeback_controller = __esm(() => {
96320
96335
  activityData,
96321
96336
  timingData,
96322
96337
  windowStartedAtMs,
96338
+ windowSequence,
96323
96339
  isFinal
96324
96340
  } = body2;
96325
96341
  logger63.debug("Recording heartbeat", {
@@ -96328,6 +96344,7 @@ var init_timeback_controller = __esm(() => {
96328
96344
  runId,
96329
96345
  resumeId,
96330
96346
  windowStartedAtMs,
96347
+ windowSequence,
96331
96348
  activeMs: timingData.activeMs,
96332
96349
  isFinal
96333
96350
  });
@@ -96339,6 +96356,7 @@ var init_timeback_controller = __esm(() => {
96339
96356
  activityData,
96340
96357
  timingData,
96341
96358
  windowStartedAtMs,
96359
+ windowSequence,
96342
96360
  isFinal,
96343
96361
  user: ctx.user
96344
96362
  });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@playcademy/sandbox",
3
- "version": "0.3.17-beta.10",
3
+ "version": "0.3.17-beta.11",
4
4
  "description": "Local development server for Playcademy game development",
5
5
  "type": "module",
6
6
  "exports": {