@timeback/sdk 0.1.5 → 0.1.6

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 CHANGED
@@ -14949,7 +14949,7 @@ var TimebackSubject = exports_external.enum([
14949
14949
  "Math",
14950
14950
  "None",
14951
14951
  "Other"
14952
- ]);
14952
+ ]).meta({ id: "TimebackSubject", description: "Subject area" });
14953
14953
  var TimebackGrade = exports_external.union([
14954
14954
  exports_external.literal(-1),
14955
14955
  exports_external.literal(0),
@@ -14966,7 +14966,10 @@ var TimebackGrade = exports_external.union([
14966
14966
  exports_external.literal(11),
14967
14967
  exports_external.literal(12),
14968
14968
  exports_external.literal(13)
14969
- ]);
14969
+ ]).meta({
14970
+ id: "TimebackGrade",
14971
+ description: "Grade level (-1 = Pre-K, 0 = K, 1-12 = grades, 13 = AP)"
14972
+ });
14970
14973
  var ScoreStatus = exports_external.enum([
14971
14974
  "exempt",
14972
14975
  "fully graded",
@@ -15196,62 +15199,84 @@ var CaliperListEventsParams = exports_external.object({
15196
15199
  actorEmail: exports_external.email().optional()
15197
15200
  }).strict();
15198
15201
  var CourseIds = exports_external.object({
15199
- staging: exports_external.string().optional(),
15200
- production: exports_external.string().optional()
15201
- });
15202
- var CourseType = exports_external.enum(["base", "hole-filling", "optional"]);
15203
- var PublishStatus = exports_external.enum(["draft", "testing", "published", "deactivated"]);
15202
+ staging: exports_external.string().meta({ description: "Course ID in staging environment" }).optional(),
15203
+ production: exports_external.string().meta({ description: "Course ID in production environment" }).optional()
15204
+ }).meta({ id: "CourseIds", description: "Environment-specific course IDs (populated by sync)" });
15205
+ var CourseType = exports_external.enum(["base", "hole-filling", "optional"]).meta({ id: "CourseType", description: "Course classification type" });
15206
+ var PublishStatus = exports_external.enum(["draft", "testing", "published", "deactivated"]).meta({ id: "PublishStatus", description: "Course publication status" });
15204
15207
  var CourseGoals = exports_external.object({
15205
- dailyXp: exports_external.number().int().positive().optional(),
15206
- dailyLessons: exports_external.number().int().positive().optional(),
15207
- dailyActiveMinutes: exports_external.number().int().positive().optional(),
15208
- dailyAccuracy: exports_external.number().int().min(0).max(100).optional(),
15209
- dailyMasteredUnits: exports_external.number().int().positive().optional()
15210
- });
15208
+ dailyXp: exports_external.number().int().positive().meta({ description: "Target XP to earn per day" }).optional(),
15209
+ dailyLessons: exports_external.number().int().positive().meta({ description: "Target lessons to complete per day" }).optional(),
15210
+ dailyActiveMinutes: exports_external.number().int().positive().meta({ description: "Target active learning minutes per day" }).optional(),
15211
+ dailyAccuracy: exports_external.number().int().min(0).max(100).meta({ description: "Target accuracy percentage (0-100)" }).optional(),
15212
+ dailyMasteredUnits: exports_external.number().int().positive().meta({ description: "Target units to master per day" }).optional()
15213
+ }).meta({ id: "CourseGoals", description: "Daily learning goals for a course" });
15211
15214
  var CourseMetrics = exports_external.object({
15212
- totalXp: exports_external.number().int().positive().optional(),
15213
- totalLessons: exports_external.number().int().positive().optional(),
15214
- totalGrades: exports_external.number().int().positive().optional()
15215
- });
15215
+ totalXp: exports_external.number().int().positive().meta({ description: "Total XP available in the course" }).optional(),
15216
+ totalLessons: exports_external.number().int().positive().meta({ description: "Total number of lessons/activities" }).optional(),
15217
+ totalGrades: exports_external.number().int().positive().meta({ description: "Total grade levels covered" }).optional()
15218
+ }).meta({ id: "CourseMetrics", description: "Aggregate metrics for a course" });
15216
15219
  var CourseMetadata = exports_external.object({
15217
15220
  courseType: CourseType.optional(),
15218
- isSupplemental: exports_external.boolean().optional(),
15219
- isCustom: exports_external.boolean().optional(),
15221
+ isSupplemental: exports_external.boolean().meta({ description: "Whether this is supplemental to a base course" }).optional(),
15222
+ isCustom: exports_external.boolean().meta({ description: "Whether this is a custom course for an individual student" }).optional(),
15220
15223
  publishStatus: PublishStatus.optional(),
15221
- contactEmail: exports_external.email().optional(),
15222
- primaryApp: exports_external.string().optional(),
15224
+ contactEmail: exports_external.email().meta({ description: "Contact email for course issues" }).optional(),
15225
+ primaryApp: exports_external.string().meta({ description: "Primary application identifier" }).optional(),
15223
15226
  goals: CourseGoals.optional(),
15224
15227
  metrics: CourseMetrics.optional()
15225
- });
15228
+ }).meta({ id: "CourseMetadata", description: "Course metadata (matches API metadata object)" });
15226
15229
  var CourseDefaults = exports_external.object({
15227
- courseCode: exports_external.string().optional(),
15228
- level: exports_external.string().optional(),
15230
+ courseCode: exports_external.string().meta({ description: "Course code (e.g., 'MATH101')" }).optional(),
15231
+ level: exports_external.string().meta({ description: "Course level (e.g., 'AP', 'Honors')" }).optional(),
15229
15232
  metadata: CourseMetadata.optional()
15233
+ }).meta({
15234
+ id: "CourseDefaults",
15235
+ description: "Default properties that apply to all courses unless overridden"
15230
15236
  });
15231
15237
  var CourseEnvOverrides = exports_external.object({
15232
- level: exports_external.string().optional(),
15233
- sensor: exports_external.string().url().optional(),
15234
- launchUrl: exports_external.string().url().optional(),
15238
+ level: exports_external.string().meta({ description: "Course level for this environment" }).optional(),
15239
+ sensor: exports_external.url().meta({ description: "Caliper sensor endpoint URL for this environment" }).optional(),
15240
+ launchUrl: exports_external.url().meta({ description: "LTI launch URL for this environment" }).optional(),
15235
15241
  metadata: CourseMetadata.optional()
15242
+ }).meta({
15243
+ id: "CourseEnvOverrides",
15244
+ description: "Environment-specific course overrides (non-identity fields)"
15236
15245
  });
15237
15246
  var CourseOverrides = exports_external.object({
15238
- staging: CourseEnvOverrides.optional(),
15239
- production: CourseEnvOverrides.optional()
15240
- });
15247
+ staging: CourseEnvOverrides.meta({
15248
+ description: "Overrides for staging environment"
15249
+ }).optional(),
15250
+ production: CourseEnvOverrides.meta({
15251
+ description: "Overrides for production environment"
15252
+ }).optional()
15253
+ }).meta({ id: "CourseOverrides", description: "Per-environment course overrides" });
15241
15254
  var CourseConfig = CourseDefaults.extend({
15242
- subject: TimebackSubject,
15243
- grade: TimebackGrade.optional(),
15255
+ subject: TimebackSubject.meta({ description: "Subject area for this course" }),
15256
+ grade: TimebackGrade.meta({
15257
+ description: "Grade level (-1 = Pre-K, 0 = K, 1-12 = grades, 13 = AP)"
15258
+ }).optional(),
15244
15259
  ids: CourseIds.nullable().optional(),
15245
- sensor: exports_external.string().url().optional(),
15246
- launchUrl: exports_external.string().url().optional(),
15260
+ sensor: exports_external.url().meta({ description: "Caliper sensor endpoint URL for this course" }).optional(),
15261
+ launchUrl: exports_external.url().meta({ description: "LTI launch URL for this course" }).optional(),
15247
15262
  overrides: CourseOverrides.optional()
15263
+ }).meta({
15264
+ id: "CourseConfig",
15265
+ description: "Configuration for a single course. Must have either grade or courseCode (or both)."
15248
15266
  });
15249
15267
  var TimebackConfig = exports_external.object({
15250
- name: exports_external.string().min(1, "App name is required"),
15251
- defaults: CourseDefaults.optional(),
15252
- courses: exports_external.array(CourseConfig).min(1, "At least one course is required"),
15253
- sensor: exports_external.string().url().optional(),
15254
- launchUrl: exports_external.string().url().optional()
15268
+ $schema: exports_external.string().meta({ description: "JSON Schema reference for editor support" }).optional(),
15269
+ name: exports_external.string().min(1, "App name is required").meta({ description: "Display name for your app" }),
15270
+ defaults: CourseDefaults.meta({
15271
+ description: "Default properties applied to all courses"
15272
+ }).optional(),
15273
+ courses: exports_external.array(CourseConfig).min(1, "At least one course is required").meta({ description: "Courses available in this app" }),
15274
+ sensor: exports_external.url().meta({ description: "Default Caliper sensor endpoint URL for all courses" }).optional(),
15275
+ launchUrl: exports_external.url().meta({ description: "Default LTI launch URL for all courses" }).optional()
15276
+ }).meta({
15277
+ id: "TimebackConfig",
15278
+ title: "Timeback Config",
15279
+ description: "Configuration schema for timeback.config.json files"
15255
15280
  }).refine((config2) => {
15256
15281
  return config2.courses.every((c) => c.grade !== undefined || c.courseCode !== undefined);
15257
15282
  }, {
@@ -31327,7 +31352,7 @@ var TimebackSubject2 = exports_external2.enum([
31327
31352
  "Math",
31328
31353
  "None",
31329
31354
  "Other"
31330
- ]);
31355
+ ]).meta({ id: "TimebackSubject", description: "Subject area" });
31331
31356
  var TimebackGrade2 = exports_external2.union([
31332
31357
  exports_external2.literal(-1),
31333
31358
  exports_external2.literal(0),
@@ -31344,7 +31369,10 @@ var TimebackGrade2 = exports_external2.union([
31344
31369
  exports_external2.literal(11),
31345
31370
  exports_external2.literal(12),
31346
31371
  exports_external2.literal(13)
31347
- ]);
31372
+ ]).meta({
31373
+ id: "TimebackGrade",
31374
+ description: "Grade level (-1 = Pre-K, 0 = K, 1-12 = grades, 13 = AP)"
31375
+ });
31348
31376
  var ScoreStatus2 = exports_external2.enum([
31349
31377
  "exempt",
31350
31378
  "fully graded",
@@ -31574,62 +31602,84 @@ var CaliperListEventsParams2 = exports_external2.object({
31574
31602
  actorEmail: exports_external2.email().optional()
31575
31603
  }).strict();
31576
31604
  var CourseIds2 = exports_external2.object({
31577
- staging: exports_external2.string().optional(),
31578
- production: exports_external2.string().optional()
31579
- });
31580
- var CourseType2 = exports_external2.enum(["base", "hole-filling", "optional"]);
31581
- var PublishStatus2 = exports_external2.enum(["draft", "testing", "published", "deactivated"]);
31605
+ staging: exports_external2.string().meta({ description: "Course ID in staging environment" }).optional(),
31606
+ production: exports_external2.string().meta({ description: "Course ID in production environment" }).optional()
31607
+ }).meta({ id: "CourseIds", description: "Environment-specific course IDs (populated by sync)" });
31608
+ var CourseType2 = exports_external2.enum(["base", "hole-filling", "optional"]).meta({ id: "CourseType", description: "Course classification type" });
31609
+ var PublishStatus2 = exports_external2.enum(["draft", "testing", "published", "deactivated"]).meta({ id: "PublishStatus", description: "Course publication status" });
31582
31610
  var CourseGoals2 = exports_external2.object({
31583
- dailyXp: exports_external2.number().int().positive().optional(),
31584
- dailyLessons: exports_external2.number().int().positive().optional(),
31585
- dailyActiveMinutes: exports_external2.number().int().positive().optional(),
31586
- dailyAccuracy: exports_external2.number().int().min(0).max(100).optional(),
31587
- dailyMasteredUnits: exports_external2.number().int().positive().optional()
31588
- });
31611
+ dailyXp: exports_external2.number().int().positive().meta({ description: "Target XP to earn per day" }).optional(),
31612
+ dailyLessons: exports_external2.number().int().positive().meta({ description: "Target lessons to complete per day" }).optional(),
31613
+ dailyActiveMinutes: exports_external2.number().int().positive().meta({ description: "Target active learning minutes per day" }).optional(),
31614
+ dailyAccuracy: exports_external2.number().int().min(0).max(100).meta({ description: "Target accuracy percentage (0-100)" }).optional(),
31615
+ dailyMasteredUnits: exports_external2.number().int().positive().meta({ description: "Target units to master per day" }).optional()
31616
+ }).meta({ id: "CourseGoals", description: "Daily learning goals for a course" });
31589
31617
  var CourseMetrics2 = exports_external2.object({
31590
- totalXp: exports_external2.number().int().positive().optional(),
31591
- totalLessons: exports_external2.number().int().positive().optional(),
31592
- totalGrades: exports_external2.number().int().positive().optional()
31593
- });
31618
+ totalXp: exports_external2.number().int().positive().meta({ description: "Total XP available in the course" }).optional(),
31619
+ totalLessons: exports_external2.number().int().positive().meta({ description: "Total number of lessons/activities" }).optional(),
31620
+ totalGrades: exports_external2.number().int().positive().meta({ description: "Total grade levels covered" }).optional()
31621
+ }).meta({ id: "CourseMetrics", description: "Aggregate metrics for a course" });
31594
31622
  var CourseMetadata2 = exports_external2.object({
31595
31623
  courseType: CourseType2.optional(),
31596
- isSupplemental: exports_external2.boolean().optional(),
31597
- isCustom: exports_external2.boolean().optional(),
31624
+ isSupplemental: exports_external2.boolean().meta({ description: "Whether this is supplemental to a base course" }).optional(),
31625
+ isCustom: exports_external2.boolean().meta({ description: "Whether this is a custom course for an individual student" }).optional(),
31598
31626
  publishStatus: PublishStatus2.optional(),
31599
- contactEmail: exports_external2.email().optional(),
31600
- primaryApp: exports_external2.string().optional(),
31627
+ contactEmail: exports_external2.email().meta({ description: "Contact email for course issues" }).optional(),
31628
+ primaryApp: exports_external2.string().meta({ description: "Primary application identifier" }).optional(),
31601
31629
  goals: CourseGoals2.optional(),
31602
31630
  metrics: CourseMetrics2.optional()
31603
- });
31631
+ }).meta({ id: "CourseMetadata", description: "Course metadata (matches API metadata object)" });
31604
31632
  var CourseDefaults2 = exports_external2.object({
31605
- courseCode: exports_external2.string().optional(),
31606
- level: exports_external2.string().optional(),
31633
+ courseCode: exports_external2.string().meta({ description: "Course code (e.g., 'MATH101')" }).optional(),
31634
+ level: exports_external2.string().meta({ description: "Course level (e.g., 'AP', 'Honors')" }).optional(),
31607
31635
  metadata: CourseMetadata2.optional()
31636
+ }).meta({
31637
+ id: "CourseDefaults",
31638
+ description: "Default properties that apply to all courses unless overridden"
31608
31639
  });
31609
31640
  var CourseEnvOverrides2 = exports_external2.object({
31610
- level: exports_external2.string().optional(),
31611
- sensor: exports_external2.string().url().optional(),
31612
- launchUrl: exports_external2.string().url().optional(),
31641
+ level: exports_external2.string().meta({ description: "Course level for this environment" }).optional(),
31642
+ sensor: exports_external2.url().meta({ description: "Caliper sensor endpoint URL for this environment" }).optional(),
31643
+ launchUrl: exports_external2.url().meta({ description: "LTI launch URL for this environment" }).optional(),
31613
31644
  metadata: CourseMetadata2.optional()
31645
+ }).meta({
31646
+ id: "CourseEnvOverrides",
31647
+ description: "Environment-specific course overrides (non-identity fields)"
31614
31648
  });
31615
31649
  var CourseOverrides2 = exports_external2.object({
31616
- staging: CourseEnvOverrides2.optional(),
31617
- production: CourseEnvOverrides2.optional()
31618
- });
31650
+ staging: CourseEnvOverrides2.meta({
31651
+ description: "Overrides for staging environment"
31652
+ }).optional(),
31653
+ production: CourseEnvOverrides2.meta({
31654
+ description: "Overrides for production environment"
31655
+ }).optional()
31656
+ }).meta({ id: "CourseOverrides", description: "Per-environment course overrides" });
31619
31657
  var CourseConfig2 = CourseDefaults2.extend({
31620
- subject: TimebackSubject2,
31621
- grade: TimebackGrade2.optional(),
31658
+ subject: TimebackSubject2.meta({ description: "Subject area for this course" }),
31659
+ grade: TimebackGrade2.meta({
31660
+ description: "Grade level (-1 = Pre-K, 0 = K, 1-12 = grades, 13 = AP)"
31661
+ }).optional(),
31622
31662
  ids: CourseIds2.nullable().optional(),
31623
- sensor: exports_external2.string().url().optional(),
31624
- launchUrl: exports_external2.string().url().optional(),
31663
+ sensor: exports_external2.url().meta({ description: "Caliper sensor endpoint URL for this course" }).optional(),
31664
+ launchUrl: exports_external2.url().meta({ description: "LTI launch URL for this course" }).optional(),
31625
31665
  overrides: CourseOverrides2.optional()
31666
+ }).meta({
31667
+ id: "CourseConfig",
31668
+ description: "Configuration for a single course. Must have either grade or courseCode (or both)."
31626
31669
  });
31627
31670
  var TimebackConfig2 = exports_external2.object({
31628
- name: exports_external2.string().min(1, "App name is required"),
31629
- defaults: CourseDefaults2.optional(),
31630
- courses: exports_external2.array(CourseConfig2).min(1, "At least one course is required"),
31631
- sensor: exports_external2.string().url().optional(),
31632
- launchUrl: exports_external2.string().url().optional()
31671
+ $schema: exports_external2.string().meta({ description: "JSON Schema reference for editor support" }).optional(),
31672
+ name: exports_external2.string().min(1, "App name is required").meta({ description: "Display name for your app" }),
31673
+ defaults: CourseDefaults2.meta({
31674
+ description: "Default properties applied to all courses"
31675
+ }).optional(),
31676
+ courses: exports_external2.array(CourseConfig2).min(1, "At least one course is required").meta({ description: "Courses available in this app" }),
31677
+ sensor: exports_external2.url().meta({ description: "Default Caliper sensor endpoint URL for all courses" }).optional(),
31678
+ launchUrl: exports_external2.url().meta({ description: "Default LTI launch URL for all courses" }).optional()
31679
+ }).meta({
31680
+ id: "TimebackConfig",
31681
+ title: "Timeback Config",
31682
+ description: "Configuration schema for timeback.config.json files"
31633
31683
  }).refine((config22) => {
31634
31684
  return config22.courses.every((c) => c.grade !== undefined || c.courseCode !== undefined);
31635
31685
  }, {
@@ -48735,7 +48785,7 @@ var TimebackSubject3 = exports_external3.enum([
48735
48785
  "Math",
48736
48786
  "None",
48737
48787
  "Other"
48738
- ]);
48788
+ ]).meta({ id: "TimebackSubject", description: "Subject area" });
48739
48789
  var TimebackGrade3 = exports_external3.union([
48740
48790
  exports_external3.literal(-1),
48741
48791
  exports_external3.literal(0),
@@ -48752,7 +48802,10 @@ var TimebackGrade3 = exports_external3.union([
48752
48802
  exports_external3.literal(11),
48753
48803
  exports_external3.literal(12),
48754
48804
  exports_external3.literal(13)
48755
- ]);
48805
+ ]).meta({
48806
+ id: "TimebackGrade",
48807
+ description: "Grade level (-1 = Pre-K, 0 = K, 1-12 = grades, 13 = AP)"
48808
+ });
48756
48809
  var ScoreStatus3 = exports_external3.enum([
48757
48810
  "exempt",
48758
48811
  "fully graded",
@@ -48982,62 +49035,84 @@ var CaliperListEventsParams3 = exports_external3.object({
48982
49035
  actorEmail: exports_external3.email().optional()
48983
49036
  }).strict();
48984
49037
  var CourseIds3 = exports_external3.object({
48985
- staging: exports_external3.string().optional(),
48986
- production: exports_external3.string().optional()
48987
- });
48988
- var CourseType3 = exports_external3.enum(["base", "hole-filling", "optional"]);
48989
- var PublishStatus3 = exports_external3.enum(["draft", "testing", "published", "deactivated"]);
49038
+ staging: exports_external3.string().meta({ description: "Course ID in staging environment" }).optional(),
49039
+ production: exports_external3.string().meta({ description: "Course ID in production environment" }).optional()
49040
+ }).meta({ id: "CourseIds", description: "Environment-specific course IDs (populated by sync)" });
49041
+ var CourseType3 = exports_external3.enum(["base", "hole-filling", "optional"]).meta({ id: "CourseType", description: "Course classification type" });
49042
+ var PublishStatus3 = exports_external3.enum(["draft", "testing", "published", "deactivated"]).meta({ id: "PublishStatus", description: "Course publication status" });
48990
49043
  var CourseGoals3 = exports_external3.object({
48991
- dailyXp: exports_external3.number().int().positive().optional(),
48992
- dailyLessons: exports_external3.number().int().positive().optional(),
48993
- dailyActiveMinutes: exports_external3.number().int().positive().optional(),
48994
- dailyAccuracy: exports_external3.number().int().min(0).max(100).optional(),
48995
- dailyMasteredUnits: exports_external3.number().int().positive().optional()
48996
- });
49044
+ dailyXp: exports_external3.number().int().positive().meta({ description: "Target XP to earn per day" }).optional(),
49045
+ dailyLessons: exports_external3.number().int().positive().meta({ description: "Target lessons to complete per day" }).optional(),
49046
+ dailyActiveMinutes: exports_external3.number().int().positive().meta({ description: "Target active learning minutes per day" }).optional(),
49047
+ dailyAccuracy: exports_external3.number().int().min(0).max(100).meta({ description: "Target accuracy percentage (0-100)" }).optional(),
49048
+ dailyMasteredUnits: exports_external3.number().int().positive().meta({ description: "Target units to master per day" }).optional()
49049
+ }).meta({ id: "CourseGoals", description: "Daily learning goals for a course" });
48997
49050
  var CourseMetrics3 = exports_external3.object({
48998
- totalXp: exports_external3.number().int().positive().optional(),
48999
- totalLessons: exports_external3.number().int().positive().optional(),
49000
- totalGrades: exports_external3.number().int().positive().optional()
49001
- });
49051
+ totalXp: exports_external3.number().int().positive().meta({ description: "Total XP available in the course" }).optional(),
49052
+ totalLessons: exports_external3.number().int().positive().meta({ description: "Total number of lessons/activities" }).optional(),
49053
+ totalGrades: exports_external3.number().int().positive().meta({ description: "Total grade levels covered" }).optional()
49054
+ }).meta({ id: "CourseMetrics", description: "Aggregate metrics for a course" });
49002
49055
  var CourseMetadata3 = exports_external3.object({
49003
49056
  courseType: CourseType3.optional(),
49004
- isSupplemental: exports_external3.boolean().optional(),
49005
- isCustom: exports_external3.boolean().optional(),
49057
+ isSupplemental: exports_external3.boolean().meta({ description: "Whether this is supplemental to a base course" }).optional(),
49058
+ isCustom: exports_external3.boolean().meta({ description: "Whether this is a custom course for an individual student" }).optional(),
49006
49059
  publishStatus: PublishStatus3.optional(),
49007
- contactEmail: exports_external3.email().optional(),
49008
- primaryApp: exports_external3.string().optional(),
49060
+ contactEmail: exports_external3.email().meta({ description: "Contact email for course issues" }).optional(),
49061
+ primaryApp: exports_external3.string().meta({ description: "Primary application identifier" }).optional(),
49009
49062
  goals: CourseGoals3.optional(),
49010
49063
  metrics: CourseMetrics3.optional()
49011
- });
49064
+ }).meta({ id: "CourseMetadata", description: "Course metadata (matches API metadata object)" });
49012
49065
  var CourseDefaults3 = exports_external3.object({
49013
- courseCode: exports_external3.string().optional(),
49014
- level: exports_external3.string().optional(),
49066
+ courseCode: exports_external3.string().meta({ description: "Course code (e.g., 'MATH101')" }).optional(),
49067
+ level: exports_external3.string().meta({ description: "Course level (e.g., 'AP', 'Honors')" }).optional(),
49015
49068
  metadata: CourseMetadata3.optional()
49069
+ }).meta({
49070
+ id: "CourseDefaults",
49071
+ description: "Default properties that apply to all courses unless overridden"
49016
49072
  });
49017
49073
  var CourseEnvOverrides3 = exports_external3.object({
49018
- level: exports_external3.string().optional(),
49019
- sensor: exports_external3.string().url().optional(),
49020
- launchUrl: exports_external3.string().url().optional(),
49074
+ level: exports_external3.string().meta({ description: "Course level for this environment" }).optional(),
49075
+ sensor: exports_external3.url().meta({ description: "Caliper sensor endpoint URL for this environment" }).optional(),
49076
+ launchUrl: exports_external3.url().meta({ description: "LTI launch URL for this environment" }).optional(),
49021
49077
  metadata: CourseMetadata3.optional()
49078
+ }).meta({
49079
+ id: "CourseEnvOverrides",
49080
+ description: "Environment-specific course overrides (non-identity fields)"
49022
49081
  });
49023
49082
  var CourseOverrides3 = exports_external3.object({
49024
- staging: CourseEnvOverrides3.optional(),
49025
- production: CourseEnvOverrides3.optional()
49026
- });
49083
+ staging: CourseEnvOverrides3.meta({
49084
+ description: "Overrides for staging environment"
49085
+ }).optional(),
49086
+ production: CourseEnvOverrides3.meta({
49087
+ description: "Overrides for production environment"
49088
+ }).optional()
49089
+ }).meta({ id: "CourseOverrides", description: "Per-environment course overrides" });
49027
49090
  var CourseConfig3 = CourseDefaults3.extend({
49028
- subject: TimebackSubject3,
49029
- grade: TimebackGrade3.optional(),
49091
+ subject: TimebackSubject3.meta({ description: "Subject area for this course" }),
49092
+ grade: TimebackGrade3.meta({
49093
+ description: "Grade level (-1 = Pre-K, 0 = K, 1-12 = grades, 13 = AP)"
49094
+ }).optional(),
49030
49095
  ids: CourseIds3.nullable().optional(),
49031
- sensor: exports_external3.string().url().optional(),
49032
- launchUrl: exports_external3.string().url().optional(),
49096
+ sensor: exports_external3.url().meta({ description: "Caliper sensor endpoint URL for this course" }).optional(),
49097
+ launchUrl: exports_external3.url().meta({ description: "LTI launch URL for this course" }).optional(),
49033
49098
  overrides: CourseOverrides3.optional()
49099
+ }).meta({
49100
+ id: "CourseConfig",
49101
+ description: "Configuration for a single course. Must have either grade or courseCode (or both)."
49034
49102
  });
49035
49103
  var TimebackConfig3 = exports_external3.object({
49036
- name: exports_external3.string().min(1, "App name is required"),
49037
- defaults: CourseDefaults3.optional(),
49038
- courses: exports_external3.array(CourseConfig3).min(1, "At least one course is required"),
49039
- sensor: exports_external3.string().url().optional(),
49040
- launchUrl: exports_external3.string().url().optional()
49104
+ $schema: exports_external3.string().meta({ description: "JSON Schema reference for editor support" }).optional(),
49105
+ name: exports_external3.string().min(1, "App name is required").meta({ description: "Display name for your app" }),
49106
+ defaults: CourseDefaults3.meta({
49107
+ description: "Default properties applied to all courses"
49108
+ }).optional(),
49109
+ courses: exports_external3.array(CourseConfig3).min(1, "At least one course is required").meta({ description: "Courses available in this app" }),
49110
+ sensor: exports_external3.url().meta({ description: "Default Caliper sensor endpoint URL for all courses" }).optional(),
49111
+ launchUrl: exports_external3.url().meta({ description: "Default LTI launch URL for all courses" }).optional()
49112
+ }).meta({
49113
+ id: "TimebackConfig",
49114
+ title: "Timeback Config",
49115
+ description: "Configuration schema for timeback.config.json files"
49041
49116
  }).refine((config22) => {
49042
49117
  return config22.courses.every((c) => c.grade !== undefined || c.courseCode !== undefined);
49043
49118
  }, {
@@ -66342,7 +66417,7 @@ var TimebackSubject4 = exports_external4.enum([
66342
66417
  "Math",
66343
66418
  "None",
66344
66419
  "Other"
66345
- ]);
66420
+ ]).meta({ id: "TimebackSubject", description: "Subject area" });
66346
66421
  var TimebackGrade4 = exports_external4.union([
66347
66422
  exports_external4.literal(-1),
66348
66423
  exports_external4.literal(0),
@@ -66359,7 +66434,10 @@ var TimebackGrade4 = exports_external4.union([
66359
66434
  exports_external4.literal(11),
66360
66435
  exports_external4.literal(12),
66361
66436
  exports_external4.literal(13)
66362
- ]);
66437
+ ]).meta({
66438
+ id: "TimebackGrade",
66439
+ description: "Grade level (-1 = Pre-K, 0 = K, 1-12 = grades, 13 = AP)"
66440
+ });
66363
66441
  var ScoreStatus4 = exports_external4.enum([
66364
66442
  "exempt",
66365
66443
  "fully graded",
@@ -66589,62 +66667,84 @@ var CaliperListEventsParams4 = exports_external4.object({
66589
66667
  actorEmail: exports_external4.email().optional()
66590
66668
  }).strict();
66591
66669
  var CourseIds4 = exports_external4.object({
66592
- staging: exports_external4.string().optional(),
66593
- production: exports_external4.string().optional()
66594
- });
66595
- var CourseType4 = exports_external4.enum(["base", "hole-filling", "optional"]);
66596
- var PublishStatus4 = exports_external4.enum(["draft", "testing", "published", "deactivated"]);
66670
+ staging: exports_external4.string().meta({ description: "Course ID in staging environment" }).optional(),
66671
+ production: exports_external4.string().meta({ description: "Course ID in production environment" }).optional()
66672
+ }).meta({ id: "CourseIds", description: "Environment-specific course IDs (populated by sync)" });
66673
+ var CourseType4 = exports_external4.enum(["base", "hole-filling", "optional"]).meta({ id: "CourseType", description: "Course classification type" });
66674
+ var PublishStatus4 = exports_external4.enum(["draft", "testing", "published", "deactivated"]).meta({ id: "PublishStatus", description: "Course publication status" });
66597
66675
  var CourseGoals4 = exports_external4.object({
66598
- dailyXp: exports_external4.number().int().positive().optional(),
66599
- dailyLessons: exports_external4.number().int().positive().optional(),
66600
- dailyActiveMinutes: exports_external4.number().int().positive().optional(),
66601
- dailyAccuracy: exports_external4.number().int().min(0).max(100).optional(),
66602
- dailyMasteredUnits: exports_external4.number().int().positive().optional()
66603
- });
66676
+ dailyXp: exports_external4.number().int().positive().meta({ description: "Target XP to earn per day" }).optional(),
66677
+ dailyLessons: exports_external4.number().int().positive().meta({ description: "Target lessons to complete per day" }).optional(),
66678
+ dailyActiveMinutes: exports_external4.number().int().positive().meta({ description: "Target active learning minutes per day" }).optional(),
66679
+ dailyAccuracy: exports_external4.number().int().min(0).max(100).meta({ description: "Target accuracy percentage (0-100)" }).optional(),
66680
+ dailyMasteredUnits: exports_external4.number().int().positive().meta({ description: "Target units to master per day" }).optional()
66681
+ }).meta({ id: "CourseGoals", description: "Daily learning goals for a course" });
66604
66682
  var CourseMetrics4 = exports_external4.object({
66605
- totalXp: exports_external4.number().int().positive().optional(),
66606
- totalLessons: exports_external4.number().int().positive().optional(),
66607
- totalGrades: exports_external4.number().int().positive().optional()
66608
- });
66683
+ totalXp: exports_external4.number().int().positive().meta({ description: "Total XP available in the course" }).optional(),
66684
+ totalLessons: exports_external4.number().int().positive().meta({ description: "Total number of lessons/activities" }).optional(),
66685
+ totalGrades: exports_external4.number().int().positive().meta({ description: "Total grade levels covered" }).optional()
66686
+ }).meta({ id: "CourseMetrics", description: "Aggregate metrics for a course" });
66609
66687
  var CourseMetadata4 = exports_external4.object({
66610
66688
  courseType: CourseType4.optional(),
66611
- isSupplemental: exports_external4.boolean().optional(),
66612
- isCustom: exports_external4.boolean().optional(),
66689
+ isSupplemental: exports_external4.boolean().meta({ description: "Whether this is supplemental to a base course" }).optional(),
66690
+ isCustom: exports_external4.boolean().meta({ description: "Whether this is a custom course for an individual student" }).optional(),
66613
66691
  publishStatus: PublishStatus4.optional(),
66614
- contactEmail: exports_external4.email().optional(),
66615
- primaryApp: exports_external4.string().optional(),
66692
+ contactEmail: exports_external4.email().meta({ description: "Contact email for course issues" }).optional(),
66693
+ primaryApp: exports_external4.string().meta({ description: "Primary application identifier" }).optional(),
66616
66694
  goals: CourseGoals4.optional(),
66617
66695
  metrics: CourseMetrics4.optional()
66618
- });
66696
+ }).meta({ id: "CourseMetadata", description: "Course metadata (matches API metadata object)" });
66619
66697
  var CourseDefaults4 = exports_external4.object({
66620
- courseCode: exports_external4.string().optional(),
66621
- level: exports_external4.string().optional(),
66698
+ courseCode: exports_external4.string().meta({ description: "Course code (e.g., 'MATH101')" }).optional(),
66699
+ level: exports_external4.string().meta({ description: "Course level (e.g., 'AP', 'Honors')" }).optional(),
66622
66700
  metadata: CourseMetadata4.optional()
66701
+ }).meta({
66702
+ id: "CourseDefaults",
66703
+ description: "Default properties that apply to all courses unless overridden"
66623
66704
  });
66624
66705
  var CourseEnvOverrides4 = exports_external4.object({
66625
- level: exports_external4.string().optional(),
66626
- sensor: exports_external4.string().url().optional(),
66627
- launchUrl: exports_external4.string().url().optional(),
66706
+ level: exports_external4.string().meta({ description: "Course level for this environment" }).optional(),
66707
+ sensor: exports_external4.url().meta({ description: "Caliper sensor endpoint URL for this environment" }).optional(),
66708
+ launchUrl: exports_external4.url().meta({ description: "LTI launch URL for this environment" }).optional(),
66628
66709
  metadata: CourseMetadata4.optional()
66710
+ }).meta({
66711
+ id: "CourseEnvOverrides",
66712
+ description: "Environment-specific course overrides (non-identity fields)"
66629
66713
  });
66630
66714
  var CourseOverrides4 = exports_external4.object({
66631
- staging: CourseEnvOverrides4.optional(),
66632
- production: CourseEnvOverrides4.optional()
66633
- });
66715
+ staging: CourseEnvOverrides4.meta({
66716
+ description: "Overrides for staging environment"
66717
+ }).optional(),
66718
+ production: CourseEnvOverrides4.meta({
66719
+ description: "Overrides for production environment"
66720
+ }).optional()
66721
+ }).meta({ id: "CourseOverrides", description: "Per-environment course overrides" });
66634
66722
  var CourseConfig4 = CourseDefaults4.extend({
66635
- subject: TimebackSubject4,
66636
- grade: TimebackGrade4.optional(),
66723
+ subject: TimebackSubject4.meta({ description: "Subject area for this course" }),
66724
+ grade: TimebackGrade4.meta({
66725
+ description: "Grade level (-1 = Pre-K, 0 = K, 1-12 = grades, 13 = AP)"
66726
+ }).optional(),
66637
66727
  ids: CourseIds4.nullable().optional(),
66638
- sensor: exports_external4.string().url().optional(),
66639
- launchUrl: exports_external4.string().url().optional(),
66728
+ sensor: exports_external4.url().meta({ description: "Caliper sensor endpoint URL for this course" }).optional(),
66729
+ launchUrl: exports_external4.url().meta({ description: "LTI launch URL for this course" }).optional(),
66640
66730
  overrides: CourseOverrides4.optional()
66731
+ }).meta({
66732
+ id: "CourseConfig",
66733
+ description: "Configuration for a single course. Must have either grade or courseCode (or both)."
66641
66734
  });
66642
66735
  var TimebackConfig4 = exports_external4.object({
66643
- name: exports_external4.string().min(1, "App name is required"),
66644
- defaults: CourseDefaults4.optional(),
66645
- courses: exports_external4.array(CourseConfig4).min(1, "At least one course is required"),
66646
- sensor: exports_external4.string().url().optional(),
66647
- launchUrl: exports_external4.string().url().optional()
66736
+ $schema: exports_external4.string().meta({ description: "JSON Schema reference for editor support" }).optional(),
66737
+ name: exports_external4.string().min(1, "App name is required").meta({ description: "Display name for your app" }),
66738
+ defaults: CourseDefaults4.meta({
66739
+ description: "Default properties applied to all courses"
66740
+ }).optional(),
66741
+ courses: exports_external4.array(CourseConfig4).min(1, "At least one course is required").meta({ description: "Courses available in this app" }),
66742
+ sensor: exports_external4.url().meta({ description: "Default Caliper sensor endpoint URL for all courses" }).optional(),
66743
+ launchUrl: exports_external4.url().meta({ description: "Default LTI launch URL for all courses" }).optional()
66744
+ }).meta({
66745
+ id: "TimebackConfig",
66746
+ title: "Timeback Config",
66747
+ description: "Configuration schema for timeback.config.json files"
66648
66748
  }).refine((config22) => {
66649
66749
  return config22.courses.every((c) => c.grade !== undefined || c.courseCode !== undefined);
66650
66750
  }, {
@@ -82979,7 +83079,7 @@ var TimebackSubject5 = exports_external5.enum([
82979
83079
  "Math",
82980
83080
  "None",
82981
83081
  "Other"
82982
- ]);
83082
+ ]).meta({ id: "TimebackSubject", description: "Subject area" });
82983
83083
  var TimebackGrade5 = exports_external5.union([
82984
83084
  exports_external5.literal(-1),
82985
83085
  exports_external5.literal(0),
@@ -82996,7 +83096,10 @@ var TimebackGrade5 = exports_external5.union([
82996
83096
  exports_external5.literal(11),
82997
83097
  exports_external5.literal(12),
82998
83098
  exports_external5.literal(13)
82999
- ]);
83099
+ ]).meta({
83100
+ id: "TimebackGrade",
83101
+ description: "Grade level (-1 = Pre-K, 0 = K, 1-12 = grades, 13 = AP)"
83102
+ });
83000
83103
  var ScoreStatus5 = exports_external5.enum([
83001
83104
  "exempt",
83002
83105
  "fully graded",
@@ -83226,62 +83329,84 @@ var CaliperListEventsParams5 = exports_external5.object({
83226
83329
  actorEmail: exports_external5.email().optional()
83227
83330
  }).strict();
83228
83331
  var CourseIds5 = exports_external5.object({
83229
- staging: exports_external5.string().optional(),
83230
- production: exports_external5.string().optional()
83231
- });
83232
- var CourseType5 = exports_external5.enum(["base", "hole-filling", "optional"]);
83233
- var PublishStatus5 = exports_external5.enum(["draft", "testing", "published", "deactivated"]);
83332
+ staging: exports_external5.string().meta({ description: "Course ID in staging environment" }).optional(),
83333
+ production: exports_external5.string().meta({ description: "Course ID in production environment" }).optional()
83334
+ }).meta({ id: "CourseIds", description: "Environment-specific course IDs (populated by sync)" });
83335
+ var CourseType5 = exports_external5.enum(["base", "hole-filling", "optional"]).meta({ id: "CourseType", description: "Course classification type" });
83336
+ var PublishStatus5 = exports_external5.enum(["draft", "testing", "published", "deactivated"]).meta({ id: "PublishStatus", description: "Course publication status" });
83234
83337
  var CourseGoals5 = exports_external5.object({
83235
- dailyXp: exports_external5.number().int().positive().optional(),
83236
- dailyLessons: exports_external5.number().int().positive().optional(),
83237
- dailyActiveMinutes: exports_external5.number().int().positive().optional(),
83238
- dailyAccuracy: exports_external5.number().int().min(0).max(100).optional(),
83239
- dailyMasteredUnits: exports_external5.number().int().positive().optional()
83240
- });
83338
+ dailyXp: exports_external5.number().int().positive().meta({ description: "Target XP to earn per day" }).optional(),
83339
+ dailyLessons: exports_external5.number().int().positive().meta({ description: "Target lessons to complete per day" }).optional(),
83340
+ dailyActiveMinutes: exports_external5.number().int().positive().meta({ description: "Target active learning minutes per day" }).optional(),
83341
+ dailyAccuracy: exports_external5.number().int().min(0).max(100).meta({ description: "Target accuracy percentage (0-100)" }).optional(),
83342
+ dailyMasteredUnits: exports_external5.number().int().positive().meta({ description: "Target units to master per day" }).optional()
83343
+ }).meta({ id: "CourseGoals", description: "Daily learning goals for a course" });
83241
83344
  var CourseMetrics5 = exports_external5.object({
83242
- totalXp: exports_external5.number().int().positive().optional(),
83243
- totalLessons: exports_external5.number().int().positive().optional(),
83244
- totalGrades: exports_external5.number().int().positive().optional()
83245
- });
83345
+ totalXp: exports_external5.number().int().positive().meta({ description: "Total XP available in the course" }).optional(),
83346
+ totalLessons: exports_external5.number().int().positive().meta({ description: "Total number of lessons/activities" }).optional(),
83347
+ totalGrades: exports_external5.number().int().positive().meta({ description: "Total grade levels covered" }).optional()
83348
+ }).meta({ id: "CourseMetrics", description: "Aggregate metrics for a course" });
83246
83349
  var CourseMetadata5 = exports_external5.object({
83247
83350
  courseType: CourseType5.optional(),
83248
- isSupplemental: exports_external5.boolean().optional(),
83249
- isCustom: exports_external5.boolean().optional(),
83351
+ isSupplemental: exports_external5.boolean().meta({ description: "Whether this is supplemental to a base course" }).optional(),
83352
+ isCustom: exports_external5.boolean().meta({ description: "Whether this is a custom course for an individual student" }).optional(),
83250
83353
  publishStatus: PublishStatus5.optional(),
83251
- contactEmail: exports_external5.email().optional(),
83252
- primaryApp: exports_external5.string().optional(),
83354
+ contactEmail: exports_external5.email().meta({ description: "Contact email for course issues" }).optional(),
83355
+ primaryApp: exports_external5.string().meta({ description: "Primary application identifier" }).optional(),
83253
83356
  goals: CourseGoals5.optional(),
83254
83357
  metrics: CourseMetrics5.optional()
83255
- });
83358
+ }).meta({ id: "CourseMetadata", description: "Course metadata (matches API metadata object)" });
83256
83359
  var CourseDefaults5 = exports_external5.object({
83257
- courseCode: exports_external5.string().optional(),
83258
- level: exports_external5.string().optional(),
83360
+ courseCode: exports_external5.string().meta({ description: "Course code (e.g., 'MATH101')" }).optional(),
83361
+ level: exports_external5.string().meta({ description: "Course level (e.g., 'AP', 'Honors')" }).optional(),
83259
83362
  metadata: CourseMetadata5.optional()
83363
+ }).meta({
83364
+ id: "CourseDefaults",
83365
+ description: "Default properties that apply to all courses unless overridden"
83260
83366
  });
83261
83367
  var CourseEnvOverrides5 = exports_external5.object({
83262
- level: exports_external5.string().optional(),
83263
- sensor: exports_external5.string().url().optional(),
83264
- launchUrl: exports_external5.string().url().optional(),
83368
+ level: exports_external5.string().meta({ description: "Course level for this environment" }).optional(),
83369
+ sensor: exports_external5.url().meta({ description: "Caliper sensor endpoint URL for this environment" }).optional(),
83370
+ launchUrl: exports_external5.url().meta({ description: "LTI launch URL for this environment" }).optional(),
83265
83371
  metadata: CourseMetadata5.optional()
83372
+ }).meta({
83373
+ id: "CourseEnvOverrides",
83374
+ description: "Environment-specific course overrides (non-identity fields)"
83266
83375
  });
83267
83376
  var CourseOverrides5 = exports_external5.object({
83268
- staging: CourseEnvOverrides5.optional(),
83269
- production: CourseEnvOverrides5.optional()
83270
- });
83377
+ staging: CourseEnvOverrides5.meta({
83378
+ description: "Overrides for staging environment"
83379
+ }).optional(),
83380
+ production: CourseEnvOverrides5.meta({
83381
+ description: "Overrides for production environment"
83382
+ }).optional()
83383
+ }).meta({ id: "CourseOverrides", description: "Per-environment course overrides" });
83271
83384
  var CourseConfig5 = CourseDefaults5.extend({
83272
- subject: TimebackSubject5,
83273
- grade: TimebackGrade5.optional(),
83385
+ subject: TimebackSubject5.meta({ description: "Subject area for this course" }),
83386
+ grade: TimebackGrade5.meta({
83387
+ description: "Grade level (-1 = Pre-K, 0 = K, 1-12 = grades, 13 = AP)"
83388
+ }).optional(),
83274
83389
  ids: CourseIds5.nullable().optional(),
83275
- sensor: exports_external5.string().url().optional(),
83276
- launchUrl: exports_external5.string().url().optional(),
83390
+ sensor: exports_external5.url().meta({ description: "Caliper sensor endpoint URL for this course" }).optional(),
83391
+ launchUrl: exports_external5.url().meta({ description: "LTI launch URL for this course" }).optional(),
83277
83392
  overrides: CourseOverrides5.optional()
83393
+ }).meta({
83394
+ id: "CourseConfig",
83395
+ description: "Configuration for a single course. Must have either grade or courseCode (or both)."
83278
83396
  });
83279
83397
  var TimebackConfig5 = exports_external5.object({
83280
- name: exports_external5.string().min(1, "App name is required"),
83281
- defaults: CourseDefaults5.optional(),
83282
- courses: exports_external5.array(CourseConfig5).min(1, "At least one course is required"),
83283
- sensor: exports_external5.string().url().optional(),
83284
- launchUrl: exports_external5.string().url().optional()
83398
+ $schema: exports_external5.string().meta({ description: "JSON Schema reference for editor support" }).optional(),
83399
+ name: exports_external5.string().min(1, "App name is required").meta({ description: "Display name for your app" }),
83400
+ defaults: CourseDefaults5.meta({
83401
+ description: "Default properties applied to all courses"
83402
+ }).optional(),
83403
+ courses: exports_external5.array(CourseConfig5).min(1, "At least one course is required").meta({ description: "Courses available in this app" }),
83404
+ sensor: exports_external5.url().meta({ description: "Default Caliper sensor endpoint URL for all courses" }).optional(),
83405
+ launchUrl: exports_external5.url().meta({ description: "Default LTI launch URL for all courses" }).optional()
83406
+ }).meta({
83407
+ id: "TimebackConfig",
83408
+ title: "Timeback Config",
83409
+ description: "Configuration schema for timeback.config.json files"
83285
83410
  }).refine((config22) => {
83286
83411
  return config22.courses.every((c) => c.grade !== undefined || c.courseCode !== undefined);
83287
83412
  }, {
@@ -85060,8 +85185,8 @@ var {
85060
85185
 
85061
85186
  // ../internal/cli-infra/src/config/timeback.ts
85062
85187
  import { existsSync } from "node:fs";
85063
- import { basename, relative, resolve } from "node:path";
85064
- import { pathToFileURL } from "node:url";
85188
+ import { basename, extname, relative, resolve } from "node:path";
85189
+ import { loadConfig as c12LoadConfig } from "c12";
85065
85190
 
85066
85191
  // ../types/src/zod/primitives.ts
85067
85192
  import { z as z6 } from "zod/v4";
@@ -85079,7 +85204,7 @@ var TimebackSubject6 = z6.enum([
85079
85204
  "Math",
85080
85205
  "None",
85081
85206
  "Other"
85082
- ]);
85207
+ ]).meta({ id: "TimebackSubject", description: "Subject area" });
85083
85208
  var TimebackGrade6 = z6.union([
85084
85209
  z6.literal(-1),
85085
85210
  z6.literal(0),
@@ -85096,7 +85221,10 @@ var TimebackGrade6 = z6.union([
85096
85221
  z6.literal(11),
85097
85222
  z6.literal(12),
85098
85223
  z6.literal(13)
85099
- ]);
85224
+ ]).meta({
85225
+ id: "TimebackGrade",
85226
+ description: "Grade level (-1 = Pre-K, 0 = K, 1-12 = grades, 13 = AP)"
85227
+ });
85100
85228
  var ScoreStatus6 = z6.enum([
85101
85229
  "exempt",
85102
85230
  "fully graded",
@@ -85330,62 +85458,84 @@ var CaliperListEventsParams6 = z8.object({
85330
85458
  // ../types/src/zod/config.ts
85331
85459
  import { z as z9 } from "zod/v4";
85332
85460
  var CourseIds6 = z9.object({
85333
- staging: z9.string().optional(),
85334
- production: z9.string().optional()
85335
- });
85336
- var CourseType6 = z9.enum(["base", "hole-filling", "optional"]);
85337
- var PublishStatus6 = z9.enum(["draft", "testing", "published", "deactivated"]);
85461
+ staging: z9.string().meta({ description: "Course ID in staging environment" }).optional(),
85462
+ production: z9.string().meta({ description: "Course ID in production environment" }).optional()
85463
+ }).meta({ id: "CourseIds", description: "Environment-specific course IDs (populated by sync)" });
85464
+ var CourseType6 = z9.enum(["base", "hole-filling", "optional"]).meta({ id: "CourseType", description: "Course classification type" });
85465
+ var PublishStatus6 = z9.enum(["draft", "testing", "published", "deactivated"]).meta({ id: "PublishStatus", description: "Course publication status" });
85338
85466
  var CourseGoals6 = z9.object({
85339
- dailyXp: z9.number().int().positive().optional(),
85340
- dailyLessons: z9.number().int().positive().optional(),
85341
- dailyActiveMinutes: z9.number().int().positive().optional(),
85342
- dailyAccuracy: z9.number().int().min(0).max(100).optional(),
85343
- dailyMasteredUnits: z9.number().int().positive().optional()
85344
- });
85467
+ dailyXp: z9.number().int().positive().meta({ description: "Target XP to earn per day" }).optional(),
85468
+ dailyLessons: z9.number().int().positive().meta({ description: "Target lessons to complete per day" }).optional(),
85469
+ dailyActiveMinutes: z9.number().int().positive().meta({ description: "Target active learning minutes per day" }).optional(),
85470
+ dailyAccuracy: z9.number().int().min(0).max(100).meta({ description: "Target accuracy percentage (0-100)" }).optional(),
85471
+ dailyMasteredUnits: z9.number().int().positive().meta({ description: "Target units to master per day" }).optional()
85472
+ }).meta({ id: "CourseGoals", description: "Daily learning goals for a course" });
85345
85473
  var CourseMetrics6 = z9.object({
85346
- totalXp: z9.number().int().positive().optional(),
85347
- totalLessons: z9.number().int().positive().optional(),
85348
- totalGrades: z9.number().int().positive().optional()
85349
- });
85474
+ totalXp: z9.number().int().positive().meta({ description: "Total XP available in the course" }).optional(),
85475
+ totalLessons: z9.number().int().positive().meta({ description: "Total number of lessons/activities" }).optional(),
85476
+ totalGrades: z9.number().int().positive().meta({ description: "Total grade levels covered" }).optional()
85477
+ }).meta({ id: "CourseMetrics", description: "Aggregate metrics for a course" });
85350
85478
  var CourseMetadata6 = z9.object({
85351
85479
  courseType: CourseType6.optional(),
85352
- isSupplemental: z9.boolean().optional(),
85353
- isCustom: z9.boolean().optional(),
85480
+ isSupplemental: z9.boolean().meta({ description: "Whether this is supplemental to a base course" }).optional(),
85481
+ isCustom: z9.boolean().meta({ description: "Whether this is a custom course for an individual student" }).optional(),
85354
85482
  publishStatus: PublishStatus6.optional(),
85355
- contactEmail: z9.email().optional(),
85356
- primaryApp: z9.string().optional(),
85483
+ contactEmail: z9.email().meta({ description: "Contact email for course issues" }).optional(),
85484
+ primaryApp: z9.string().meta({ description: "Primary application identifier" }).optional(),
85357
85485
  goals: CourseGoals6.optional(),
85358
85486
  metrics: CourseMetrics6.optional()
85359
- });
85487
+ }).meta({ id: "CourseMetadata", description: "Course metadata (matches API metadata object)" });
85360
85488
  var CourseDefaults6 = z9.object({
85361
- courseCode: z9.string().optional(),
85362
- level: z9.string().optional(),
85489
+ courseCode: z9.string().meta({ description: "Course code (e.g., 'MATH101')" }).optional(),
85490
+ level: z9.string().meta({ description: "Course level (e.g., 'AP', 'Honors')" }).optional(),
85363
85491
  metadata: CourseMetadata6.optional()
85492
+ }).meta({
85493
+ id: "CourseDefaults",
85494
+ description: "Default properties that apply to all courses unless overridden"
85364
85495
  });
85365
85496
  var CourseEnvOverrides6 = z9.object({
85366
- level: z9.string().optional(),
85367
- sensor: z9.string().url().optional(),
85368
- launchUrl: z9.string().url().optional(),
85497
+ level: z9.string().meta({ description: "Course level for this environment" }).optional(),
85498
+ sensor: z9.url().meta({ description: "Caliper sensor endpoint URL for this environment" }).optional(),
85499
+ launchUrl: z9.url().meta({ description: "LTI launch URL for this environment" }).optional(),
85369
85500
  metadata: CourseMetadata6.optional()
85501
+ }).meta({
85502
+ id: "CourseEnvOverrides",
85503
+ description: "Environment-specific course overrides (non-identity fields)"
85370
85504
  });
85371
85505
  var CourseOverrides6 = z9.object({
85372
- staging: CourseEnvOverrides6.optional(),
85373
- production: CourseEnvOverrides6.optional()
85374
- });
85506
+ staging: CourseEnvOverrides6.meta({
85507
+ description: "Overrides for staging environment"
85508
+ }).optional(),
85509
+ production: CourseEnvOverrides6.meta({
85510
+ description: "Overrides for production environment"
85511
+ }).optional()
85512
+ }).meta({ id: "CourseOverrides", description: "Per-environment course overrides" });
85375
85513
  var CourseConfig6 = CourseDefaults6.extend({
85376
- subject: TimebackSubject6,
85377
- grade: TimebackGrade6.optional(),
85514
+ subject: TimebackSubject6.meta({ description: "Subject area for this course" }),
85515
+ grade: TimebackGrade6.meta({
85516
+ description: "Grade level (-1 = Pre-K, 0 = K, 1-12 = grades, 13 = AP)"
85517
+ }).optional(),
85378
85518
  ids: CourseIds6.nullable().optional(),
85379
- sensor: z9.string().url().optional(),
85380
- launchUrl: z9.string().url().optional(),
85519
+ sensor: z9.url().meta({ description: "Caliper sensor endpoint URL for this course" }).optional(),
85520
+ launchUrl: z9.url().meta({ description: "LTI launch URL for this course" }).optional(),
85381
85521
  overrides: CourseOverrides6.optional()
85522
+ }).meta({
85523
+ id: "CourseConfig",
85524
+ description: "Configuration for a single course. Must have either grade or courseCode (or both)."
85382
85525
  });
85383
85526
  var TimebackConfig6 = z9.object({
85384
- name: z9.string().min(1, "App name is required"),
85385
- defaults: CourseDefaults6.optional(),
85386
- courses: z9.array(CourseConfig6).min(1, "At least one course is required"),
85387
- sensor: z9.string().url().optional(),
85388
- launchUrl: z9.string().url().optional()
85527
+ $schema: z9.string().meta({ description: "JSON Schema reference for editor support" }).optional(),
85528
+ name: z9.string().min(1, "App name is required").meta({ description: "Display name for your app" }),
85529
+ defaults: CourseDefaults6.meta({
85530
+ description: "Default properties applied to all courses"
85531
+ }).optional(),
85532
+ courses: z9.array(CourseConfig6).min(1, "At least one course is required").meta({ description: "Courses available in this app" }),
85533
+ sensor: z9.url().meta({ description: "Default Caliper sensor endpoint URL for all courses" }).optional(),
85534
+ launchUrl: z9.url().meta({ description: "Default LTI launch URL for all courses" }).optional()
85535
+ }).meta({
85536
+ id: "TimebackConfig",
85537
+ title: "Timeback Config",
85538
+ description: "Configuration schema for timeback.config.json files"
85389
85539
  }).refine((config6) => {
85390
85540
  return config6.courses.every((c) => c.grade !== undefined || c.courseCode !== undefined);
85391
85541
  }, {
@@ -86433,94 +86583,88 @@ var CREDENTIALS_DIR = getConfigDir();
86433
86583
  var CREDENTIALS_FILE = join(CREDENTIALS_DIR, "credentials.json");
86434
86584
 
86435
86585
  // ../internal/cli-infra/src/config/timeback.ts
86436
- var FILE_PATTERNS = ["timeback.config.ts", "timeback.config.js", "timeback.config.mjs"];
86437
- var isBun = typeof globalThis.Bun !== "undefined";
86438
- var jitiInstance = null;
86439
- async function getJiti() {
86440
- if (jitiInstance)
86441
- return jitiInstance;
86442
- const { createJiti } = await import("jiti");
86443
- jitiInstance = createJiti(import.meta.url, { fsCache: false });
86444
- return jitiInstance;
86445
- }
86446
- async function importModule(fullPath) {
86447
- let module;
86448
- if (isBun) {
86449
- const fileUrl = pathToFileURL(fullPath).href;
86450
- module = await import(fileUrl);
86451
- } else {
86452
- const jiti = await getJiti();
86453
- module = await jiti.import(fullPath);
86454
- }
86455
- return module.default ?? module;
86586
+ var CONFIG_FILENAME = "timeback.config.json";
86587
+ function isJsonConfigPath(configPath) {
86588
+ return extname(configPath).toLowerCase() === ".json";
86589
+ }
86590
+ async function loadWithC12(cwd, configPath) {
86591
+ if (configPath && !isJsonConfigPath(configPath)) {
86592
+ throw new Error(`Config file must be JSON (.json): ${configPath}`);
86593
+ }
86594
+ const result = await c12LoadConfig({
86595
+ cwd,
86596
+ name: "timeback",
86597
+ configFile: configPath ?? CONFIG_FILENAME,
86598
+ rcFile: false,
86599
+ packageJson: false,
86600
+ dotenv: false,
86601
+ envName: false,
86602
+ extend: false,
86603
+ omit$Keys: true,
86604
+ defaults: {},
86605
+ overrides: {}
86606
+ });
86607
+ if (!result.config || Object.keys(result.config).length === 0) {
86608
+ return null;
86609
+ }
86610
+ const rawConfig = result.config;
86611
+ if ("extends" in rawConfig) {
86612
+ throw new Error("The 'extends' feature is not supported in timeback.config.json. " + "Please inline all configuration.");
86613
+ }
86614
+ const { $schema: _schema, ...configWithoutSchema } = rawConfig;
86615
+ return {
86616
+ config: configWithoutSchema,
86617
+ configFile: result.configFile ?? resolve(cwd, configPath ?? CONFIG_FILENAME)
86618
+ };
86456
86619
  }
86457
86620
  async function loadConfig(opts = {}) {
86458
86621
  const cwd = process.cwd();
86459
- let rawConfig = null;
86460
- let foundPath = null;
86461
- let loadError = null;
86462
- if (opts.configPath) {
86463
- const fullPath = resolve(cwd, opts.configPath);
86464
- if (!existsSync(fullPath)) {
86622
+ try {
86623
+ if (opts.configPath && !isJsonConfigPath(opts.configPath)) {
86465
86624
  return {
86466
86625
  success: false,
86467
- error: `Config file not found: ${opts.configPath}`
86626
+ error: `Config file must be JSON (.json): ${opts.configPath}`
86468
86627
  };
86469
86628
  }
86470
- try {
86471
- rawConfig = await importModule(fullPath);
86472
- foundPath = fullPath;
86473
- } catch (err) {
86629
+ if (opts.configPath) {
86630
+ const fullPath = resolve(cwd, opts.configPath);
86631
+ if (!existsSync(fullPath)) {
86632
+ return {
86633
+ success: false,
86634
+ error: `Config file not found: ${opts.configPath}`
86635
+ };
86636
+ }
86637
+ }
86638
+ const loaded = await loadWithC12(cwd, opts.configPath);
86639
+ if (!loaded) {
86474
86640
  return {
86475
86641
  success: false,
86476
- error: `Failed to load ${opts.configPath}:
86477
- ${err instanceof Error ? err.message : String(err)}`
86642
+ error: `No timeback config found. Run ${greenBright("timeback init")} to create one.`
86478
86643
  };
86479
86644
  }
86480
- } else {
86481
- for (const filename of FILE_PATTERNS) {
86482
- const fullPath = resolve(cwd, filename);
86483
- if (!existsSync(fullPath))
86484
- continue;
86485
- try {
86486
- rawConfig = await importModule(fullPath);
86487
- foundPath = fullPath;
86488
- break;
86489
- } catch (err) {
86490
- loadError = err instanceof Error ? err : new Error(String(err));
86491
- foundPath = fullPath;
86492
- break;
86493
- }
86645
+ const result = TimebackConfig6.safeParse(loaded.config);
86646
+ if (!result.success) {
86647
+ const issues = result.error.issues.map((issue4) => ` - ${issue4.path.join(".")}: ${issue4.message}`).join(`
86648
+ `);
86649
+ return {
86650
+ success: false,
86651
+ error: `Invalid config in ${basename(loaded.configFile)}:
86652
+ ${issues}`
86653
+ };
86494
86654
  }
86495
- }
86496
- if (loadError && foundPath) {
86497
86655
  return {
86498
- success: false,
86499
- error: `Failed to load ${basename(foundPath)}:
86500
- ${loadError.message}`
86656
+ success: true,
86657
+ config: result.data,
86658
+ configPath: loaded.configFile
86501
86659
  };
86502
- }
86503
- if (!rawConfig || !foundPath) {
86504
- return {
86505
- success: false,
86506
- error: `No timeback config found. Run ${greenBright("timeback init")} to create one.`
86507
- };
86508
- }
86509
- const result = TimebackConfig6.safeParse(rawConfig);
86510
- if (!result.success) {
86511
- const issues = result.error.issues.map((issue4) => ` - ${issue4.path.join(".")}: ${issue4.message}`).join(`
86512
- `);
86660
+ } catch (err) {
86661
+ const filename = opts.configPath ? basename(opts.configPath) : CONFIG_FILENAME;
86513
86662
  return {
86514
86663
  success: false,
86515
- error: `Invalid config in ${basename(foundPath)}:
86516
- ${issues}`
86664
+ error: `Failed to load ${filename}:
86665
+ ${err instanceof Error ? err.message : String(err)}`
86517
86666
  };
86518
86667
  }
86519
- return {
86520
- success: true,
86521
- config: result.data,
86522
- configPath: foundPath
86523
- };
86524
86668
  }
86525
86669
  // src/shared/constants.ts
86526
86670
  var ROUTES = {
@@ -102317,7 +102461,7 @@ var TimebackSubject8 = exports_external6.enum([
102317
102461
  "Math",
102318
102462
  "None",
102319
102463
  "Other"
102320
- ]);
102464
+ ]).meta({ id: "TimebackSubject", description: "Subject area" });
102321
102465
  var TimebackGrade8 = exports_external6.union([
102322
102466
  exports_external6.literal(-1),
102323
102467
  exports_external6.literal(0),
@@ -102334,7 +102478,10 @@ var TimebackGrade8 = exports_external6.union([
102334
102478
  exports_external6.literal(11),
102335
102479
  exports_external6.literal(12),
102336
102480
  exports_external6.literal(13)
102337
- ]);
102481
+ ]).meta({
102482
+ id: "TimebackGrade",
102483
+ description: "Grade level (-1 = Pre-K, 0 = K, 1-12 = grades, 13 = AP)"
102484
+ });
102338
102485
  var ScoreStatus8 = exports_external6.enum([
102339
102486
  "exempt",
102340
102487
  "fully graded",
@@ -102564,62 +102711,84 @@ var CaliperListEventsParams8 = exports_external6.object({
102564
102711
  actorEmail: exports_external6.email().optional()
102565
102712
  }).strict();
102566
102713
  var CourseIds8 = exports_external6.object({
102567
- staging: exports_external6.string().optional(),
102568
- production: exports_external6.string().optional()
102569
- });
102570
- var CourseType8 = exports_external6.enum(["base", "hole-filling", "optional"]);
102571
- var PublishStatus8 = exports_external6.enum(["draft", "testing", "published", "deactivated"]);
102714
+ staging: exports_external6.string().meta({ description: "Course ID in staging environment" }).optional(),
102715
+ production: exports_external6.string().meta({ description: "Course ID in production environment" }).optional()
102716
+ }).meta({ id: "CourseIds", description: "Environment-specific course IDs (populated by sync)" });
102717
+ var CourseType8 = exports_external6.enum(["base", "hole-filling", "optional"]).meta({ id: "CourseType", description: "Course classification type" });
102718
+ var PublishStatus8 = exports_external6.enum(["draft", "testing", "published", "deactivated"]).meta({ id: "PublishStatus", description: "Course publication status" });
102572
102719
  var CourseGoals8 = exports_external6.object({
102573
- dailyXp: exports_external6.number().int().positive().optional(),
102574
- dailyLessons: exports_external6.number().int().positive().optional(),
102575
- dailyActiveMinutes: exports_external6.number().int().positive().optional(),
102576
- dailyAccuracy: exports_external6.number().int().min(0).max(100).optional(),
102577
- dailyMasteredUnits: exports_external6.number().int().positive().optional()
102578
- });
102720
+ dailyXp: exports_external6.number().int().positive().meta({ description: "Target XP to earn per day" }).optional(),
102721
+ dailyLessons: exports_external6.number().int().positive().meta({ description: "Target lessons to complete per day" }).optional(),
102722
+ dailyActiveMinutes: exports_external6.number().int().positive().meta({ description: "Target active learning minutes per day" }).optional(),
102723
+ dailyAccuracy: exports_external6.number().int().min(0).max(100).meta({ description: "Target accuracy percentage (0-100)" }).optional(),
102724
+ dailyMasteredUnits: exports_external6.number().int().positive().meta({ description: "Target units to master per day" }).optional()
102725
+ }).meta({ id: "CourseGoals", description: "Daily learning goals for a course" });
102579
102726
  var CourseMetrics8 = exports_external6.object({
102580
- totalXp: exports_external6.number().int().positive().optional(),
102581
- totalLessons: exports_external6.number().int().positive().optional(),
102582
- totalGrades: exports_external6.number().int().positive().optional()
102583
- });
102727
+ totalXp: exports_external6.number().int().positive().meta({ description: "Total XP available in the course" }).optional(),
102728
+ totalLessons: exports_external6.number().int().positive().meta({ description: "Total number of lessons/activities" }).optional(),
102729
+ totalGrades: exports_external6.number().int().positive().meta({ description: "Total grade levels covered" }).optional()
102730
+ }).meta({ id: "CourseMetrics", description: "Aggregate metrics for a course" });
102584
102731
  var CourseMetadata8 = exports_external6.object({
102585
102732
  courseType: CourseType8.optional(),
102586
- isSupplemental: exports_external6.boolean().optional(),
102587
- isCustom: exports_external6.boolean().optional(),
102733
+ isSupplemental: exports_external6.boolean().meta({ description: "Whether this is supplemental to a base course" }).optional(),
102734
+ isCustom: exports_external6.boolean().meta({ description: "Whether this is a custom course for an individual student" }).optional(),
102588
102735
  publishStatus: PublishStatus8.optional(),
102589
- contactEmail: exports_external6.email().optional(),
102590
- primaryApp: exports_external6.string().optional(),
102736
+ contactEmail: exports_external6.email().meta({ description: "Contact email for course issues" }).optional(),
102737
+ primaryApp: exports_external6.string().meta({ description: "Primary application identifier" }).optional(),
102591
102738
  goals: CourseGoals8.optional(),
102592
102739
  metrics: CourseMetrics8.optional()
102593
- });
102740
+ }).meta({ id: "CourseMetadata", description: "Course metadata (matches API metadata object)" });
102594
102741
  var CourseDefaults8 = exports_external6.object({
102595
- courseCode: exports_external6.string().optional(),
102596
- level: exports_external6.string().optional(),
102742
+ courseCode: exports_external6.string().meta({ description: "Course code (e.g., 'MATH101')" }).optional(),
102743
+ level: exports_external6.string().meta({ description: "Course level (e.g., 'AP', 'Honors')" }).optional(),
102597
102744
  metadata: CourseMetadata8.optional()
102745
+ }).meta({
102746
+ id: "CourseDefaults",
102747
+ description: "Default properties that apply to all courses unless overridden"
102598
102748
  });
102599
102749
  var CourseEnvOverrides8 = exports_external6.object({
102600
- level: exports_external6.string().optional(),
102601
- sensor: exports_external6.string().url().optional(),
102602
- launchUrl: exports_external6.string().url().optional(),
102750
+ level: exports_external6.string().meta({ description: "Course level for this environment" }).optional(),
102751
+ sensor: exports_external6.url().meta({ description: "Caliper sensor endpoint URL for this environment" }).optional(),
102752
+ launchUrl: exports_external6.url().meta({ description: "LTI launch URL for this environment" }).optional(),
102603
102753
  metadata: CourseMetadata8.optional()
102754
+ }).meta({
102755
+ id: "CourseEnvOverrides",
102756
+ description: "Environment-specific course overrides (non-identity fields)"
102604
102757
  });
102605
102758
  var CourseOverrides8 = exports_external6.object({
102606
- staging: CourseEnvOverrides8.optional(),
102607
- production: CourseEnvOverrides8.optional()
102608
- });
102759
+ staging: CourseEnvOverrides8.meta({
102760
+ description: "Overrides for staging environment"
102761
+ }).optional(),
102762
+ production: CourseEnvOverrides8.meta({
102763
+ description: "Overrides for production environment"
102764
+ }).optional()
102765
+ }).meta({ id: "CourseOverrides", description: "Per-environment course overrides" });
102609
102766
  var CourseConfig8 = CourseDefaults8.extend({
102610
- subject: TimebackSubject8,
102611
- grade: TimebackGrade8.optional(),
102767
+ subject: TimebackSubject8.meta({ description: "Subject area for this course" }),
102768
+ grade: TimebackGrade8.meta({
102769
+ description: "Grade level (-1 = Pre-K, 0 = K, 1-12 = grades, 13 = AP)"
102770
+ }).optional(),
102612
102771
  ids: CourseIds8.nullable().optional(),
102613
- sensor: exports_external6.string().url().optional(),
102614
- launchUrl: exports_external6.string().url().optional(),
102772
+ sensor: exports_external6.url().meta({ description: "Caliper sensor endpoint URL for this course" }).optional(),
102773
+ launchUrl: exports_external6.url().meta({ description: "LTI launch URL for this course" }).optional(),
102615
102774
  overrides: CourseOverrides8.optional()
102775
+ }).meta({
102776
+ id: "CourseConfig",
102777
+ description: "Configuration for a single course. Must have either grade or courseCode (or both)."
102616
102778
  });
102617
102779
  var TimebackConfig8 = exports_external6.object({
102618
- name: exports_external6.string().min(1, "App name is required"),
102619
- defaults: CourseDefaults8.optional(),
102620
- courses: exports_external6.array(CourseConfig8).min(1, "At least one course is required"),
102621
- sensor: exports_external6.string().url().optional(),
102622
- launchUrl: exports_external6.string().url().optional()
102780
+ $schema: exports_external6.string().meta({ description: "JSON Schema reference for editor support" }).optional(),
102781
+ name: exports_external6.string().min(1, "App name is required").meta({ description: "Display name for your app" }),
102782
+ defaults: CourseDefaults8.meta({
102783
+ description: "Default properties applied to all courses"
102784
+ }).optional(),
102785
+ courses: exports_external6.array(CourseConfig8).min(1, "At least one course is required").meta({ description: "Courses available in this app" }),
102786
+ sensor: exports_external6.url().meta({ description: "Default Caliper sensor endpoint URL for all courses" }).optional(),
102787
+ launchUrl: exports_external6.url().meta({ description: "Default LTI launch URL for all courses" }).optional()
102788
+ }).meta({
102789
+ id: "TimebackConfig",
102790
+ title: "Timeback Config",
102791
+ description: "Configuration schema for timeback.config.json files"
102623
102792
  }).refine((config22) => {
102624
102793
  return config22.courses.every((c) => c.grade !== undefined || c.courseCode !== undefined);
102625
102794
  }, {
@@ -103992,7 +104161,7 @@ function validateActivityRequest(body, appConfig, env2) {
103992
104161
  log11.error("Ambiguous course selector", { selector: payload.course });
103993
104162
  return {
103994
104163
  ok: false,
103995
- response: jsonResponse({ success: false, error: "Ambiguous course selector in timeback.config.ts" }, 500)
104164
+ response: jsonResponse({ success: false, error: "Ambiguous course selector in timeback.config.json" }, 500)
103996
104165
  };
103997
104166
  }
103998
104167
  throw err;
@@ -104006,7 +104175,7 @@ function validateActivityRequest(body, appConfig, env2) {
104006
104175
  ok: false,
104007
104176
  response: jsonResponse({
104008
104177
  success: false,
104009
- error: `Course "${selectorDesc}" has no sensor configured. Set 'courses[].overrides.${envForOverrides}.sensor', 'courses[].sensor', or top-level 'sensor' in timeback.config.ts.`
104178
+ error: `Course "${selectorDesc}" has no sensor configured. Set 'courses[].overrides.${envForOverrides}.sensor', 'courses[].sensor', or top-level 'sensor' in timeback.config.json.`
104010
104179
  }, 500)
104011
104180
  };
104012
104181
  }