timeback-studio 0.1.2 → 0.1.4

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
@@ -14776,7 +14776,7 @@ async function loadCredentials(environment) {
14776
14776
  }
14777
14777
  // ../internal/cli-infra/src/ui.ts
14778
14778
  function intro(title) {
14779
- console.log();
14779
+ console.log("");
14780
14780
  Ie(bgCyan(black(` ${title} `)));
14781
14781
  }
14782
14782
  var outro = {
@@ -14816,10 +14816,9 @@ var playcademyParser = {
14816
14816
  };
14817
14817
 
14818
14818
  // ../internal/cli-infra/src/config/timeback.ts
14819
- import { existsSync } from "node:fs";
14820
14819
  import { readFile as readFile2 } from "node:fs/promises";
14821
- import { basename, relative, resolve } from "node:path";
14822
- import { createJiti } from "jiti";
14820
+ import { basename, extname, relative, resolve } from "node:path";
14821
+ import { loadConfig as c12LoadConfig } from "c12";
14823
14822
  // ../types/src/zod/primitives.ts
14824
14823
  var IsoDateTimeRegex = /^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}(?:\.\d+)?(?:Z|[+-]\d{2}:\d{2})$/;
14825
14824
  var IsoDateTimeString = exports_external.string().min(1).regex(IsoDateTimeRegex, "must be a valid ISO 8601 datetime");
@@ -14835,7 +14834,7 @@ var TimebackSubject = exports_external.enum([
14835
14834
  "Math",
14836
14835
  "None",
14837
14836
  "Other"
14838
- ]);
14837
+ ]).meta({ id: "TimebackSubject", description: "Subject area" });
14839
14838
  var TimebackGrade = exports_external.union([
14840
14839
  exports_external.literal(-1),
14841
14840
  exports_external.literal(0),
@@ -14852,7 +14851,10 @@ var TimebackGrade = exports_external.union([
14852
14851
  exports_external.literal(11),
14853
14852
  exports_external.literal(12),
14854
14853
  exports_external.literal(13)
14855
- ]);
14854
+ ]).meta({
14855
+ id: "TimebackGrade",
14856
+ description: "Grade level (-1 = Pre-K, 0 = K, 1-12 = grades, 13 = AP)"
14857
+ });
14856
14858
  var ScoreStatus = exports_external.enum([
14857
14859
  "exempt",
14858
14860
  "fully graded",
@@ -14879,6 +14881,47 @@ var OneRosterUserRole = exports_external.enum([
14879
14881
  "teacher"
14880
14882
  ]);
14881
14883
  var EnrollmentRole = exports_external.enum(["administrator", "proctor", "student", "teacher"]);
14884
+ var ResourceType = exports_external.enum([
14885
+ "qti",
14886
+ "text",
14887
+ "audio",
14888
+ "video",
14889
+ "interactive",
14890
+ "visual",
14891
+ "course-material",
14892
+ "assessment-bank"
14893
+ ]);
14894
+ var QtiSubType = exports_external.enum(["qti-test", "qti-question", "qti-stimulus", "qti-test-bank"]);
14895
+ var CourseMaterialSubType = exports_external.enum(["unit", "course", "resource-collection"]);
14896
+ var QuestionType = exports_external.enum([
14897
+ "choice",
14898
+ "order",
14899
+ "associate",
14900
+ "match",
14901
+ "hotspot",
14902
+ "hottext",
14903
+ "select-point",
14904
+ "graphic-order",
14905
+ "graphic-associate",
14906
+ "graphic-gap-match",
14907
+ "text-entry",
14908
+ "extended-text",
14909
+ "inline-choice",
14910
+ "upload",
14911
+ "slider",
14912
+ "drawing",
14913
+ "media",
14914
+ "custom"
14915
+ ]);
14916
+ var Difficulty = exports_external.enum(["easy", "medium", "hard"]);
14917
+ var LearningObjectiveSetSchema = exports_external.array(exports_external.object({
14918
+ source: exports_external.string(),
14919
+ learningObjectiveIds: exports_external.array(exports_external.string())
14920
+ }));
14921
+ var FastFailConfigSchema = exports_external.object({
14922
+ consecutive_failures: exports_external.number().int().min(1).optional(),
14923
+ stagnation_limit: exports_external.number().int().min(1).optional()
14924
+ }).optional();
14882
14925
  var LessonType = exports_external.enum(["powerpath-100", "quiz", "test-out", "placement", "unit-test", "alpha-read-article"]).nullable();
14883
14926
  var IMSErrorResponse = exports_external.object({
14884
14927
  imsx_codeMajor: exports_external.enum(["failure", "success"]),
@@ -14955,7 +14998,11 @@ var ActivityCompletedInput = exports_external.object({
14955
14998
  eventTime: IsoDateTimeString.optional(),
14956
14999
  metricsId: exports_external.string().optional(),
14957
15000
  id: exports_external.string().optional(),
14958
- extensions: exports_external.record(exports_external.string(), exports_external.unknown()).optional()
15001
+ extensions: exports_external.record(exports_external.string(), exports_external.unknown()).optional(),
15002
+ attempt: exports_external.number().int().min(1).optional(),
15003
+ generatedExtensions: exports_external.object({
15004
+ pctCompleteApp: exports_external.number().optional()
15005
+ }).loose().optional()
14959
15006
  }).strict();
14960
15007
  var TimeSpentInput = exports_external.object({
14961
15008
  actor: TimebackUser,
@@ -15039,48 +15086,113 @@ var CaliperListEventsParams = exports_external.object({
15039
15086
  }).strict();
15040
15087
  // ../types/src/zod/config.ts
15041
15088
  var CourseIds = exports_external.object({
15042
- staging: exports_external.string().optional(),
15043
- production: exports_external.string().optional()
15044
- });
15045
- var CourseType = exports_external.enum(["base", "hole-filling", "optional"]);
15046
- var PublishStatus = exports_external.enum(["draft", "testing", "published", "deactivated"]);
15089
+ staging: exports_external.string().meta({ description: "Course ID in staging environment" }).optional(),
15090
+ production: exports_external.string().meta({ description: "Course ID in production environment" }).optional()
15091
+ }).meta({ id: "CourseIds", description: "Environment-specific course IDs (populated by sync)" });
15092
+ var CourseType = exports_external.enum(["base", "hole-filling", "optional"]).meta({ id: "CourseType", description: "Course classification type" });
15093
+ var PublishStatus = exports_external.enum(["draft", "testing", "published", "deactivated"]).meta({ id: "PublishStatus", description: "Course publication status" });
15047
15094
  var CourseGoals = exports_external.object({
15048
- dailyXp: exports_external.number().int().positive().optional(),
15049
- dailyLessons: exports_external.number().int().positive().optional(),
15050
- dailyActiveMinutes: exports_external.number().int().positive().optional(),
15051
- dailyAccuracy: exports_external.number().int().min(0).max(100).optional(),
15052
- dailyMasteredUnits: exports_external.number().int().positive().optional()
15053
- });
15095
+ dailyXp: exports_external.number().int().positive().meta({ description: "Target XP to earn per day" }).optional(),
15096
+ dailyLessons: exports_external.number().int().positive().meta({ description: "Target lessons to complete per day" }).optional(),
15097
+ dailyActiveMinutes: exports_external.number().int().positive().meta({ description: "Target active learning minutes per day" }).optional(),
15098
+ dailyAccuracy: exports_external.number().int().min(0).max(100).meta({ description: "Target accuracy percentage (0-100)" }).optional(),
15099
+ dailyMasteredUnits: exports_external.number().int().positive().meta({ description: "Target units to master per day" }).optional()
15100
+ }).meta({ id: "CourseGoals", description: "Daily learning goals for a course" });
15054
15101
  var CourseMetrics = exports_external.object({
15055
- totalXp: exports_external.number().int().positive().optional(),
15056
- totalLessons: exports_external.number().int().positive().optional(),
15057
- totalGrades: exports_external.number().int().positive().optional()
15058
- });
15102
+ totalXp: exports_external.number().int().positive().meta({ description: "Total XP available in the course" }).optional(),
15103
+ totalLessons: exports_external.number().int().positive().meta({ description: "Total number of lessons/activities" }).optional(),
15104
+ totalGrades: exports_external.number().int().positive().meta({ description: "Total grade levels covered" }).optional()
15105
+ }).meta({ id: "CourseMetrics", description: "Aggregate metrics for a course" });
15059
15106
  var CourseMetadata = exports_external.object({
15060
15107
  courseType: CourseType.optional(),
15061
- isSupplemental: exports_external.boolean().optional(),
15062
- isCustom: exports_external.boolean().optional(),
15108
+ isSupplemental: exports_external.boolean().meta({ description: "Whether this is supplemental to a base course" }).optional(),
15109
+ isCustom: exports_external.boolean().meta({ description: "Whether this is a custom course for an individual student" }).optional(),
15063
15110
  publishStatus: PublishStatus.optional(),
15064
- contactEmail: exports_external.email().optional(),
15065
- primaryApp: exports_external.string().optional(),
15111
+ contactEmail: exports_external.email().meta({ description: "Contact email for course issues" }).optional(),
15112
+ primaryApp: exports_external.string().meta({ description: "Primary application identifier" }).optional(),
15066
15113
  goals: CourseGoals.optional(),
15067
15114
  metrics: CourseMetrics.optional()
15068
- });
15115
+ }).meta({ id: "CourseMetadata", description: "Course metadata (matches API metadata object)" });
15069
15116
  var CourseDefaults = exports_external.object({
15070
- courseCode: exports_external.string().optional(),
15071
- level: exports_external.string().optional(),
15117
+ courseCode: exports_external.string().meta({ description: "Course code (e.g., 'MATH101')" }).optional(),
15118
+ level: exports_external.string().meta({ description: "Course level (e.g., 'AP', 'Honors')" }).optional(),
15072
15119
  metadata: CourseMetadata.optional()
15120
+ }).meta({
15121
+ id: "CourseDefaults",
15122
+ description: "Default properties that apply to all courses unless overridden"
15073
15123
  });
15124
+ var CourseEnvOverrides = exports_external.object({
15125
+ level: exports_external.string().meta({ description: "Course level for this environment" }).optional(),
15126
+ sensor: exports_external.url().meta({ description: "Caliper sensor endpoint URL for this environment" }).optional(),
15127
+ launchUrl: exports_external.url().meta({ description: "LTI launch URL for this environment" }).optional(),
15128
+ metadata: CourseMetadata.optional()
15129
+ }).meta({
15130
+ id: "CourseEnvOverrides",
15131
+ description: "Environment-specific course overrides (non-identity fields)"
15132
+ });
15133
+ var CourseOverrides = exports_external.object({
15134
+ staging: CourseEnvOverrides.meta({
15135
+ description: "Overrides for staging environment"
15136
+ }).optional(),
15137
+ production: CourseEnvOverrides.meta({
15138
+ description: "Overrides for production environment"
15139
+ }).optional()
15140
+ }).meta({ id: "CourseOverrides", description: "Per-environment course overrides" });
15074
15141
  var CourseConfig = CourseDefaults.extend({
15075
- subject: TimebackSubject,
15076
- grade: TimebackGrade,
15077
- ids: CourseIds.nullable().optional()
15142
+ subject: TimebackSubject.meta({ description: "Subject area for this course" }),
15143
+ grade: TimebackGrade.meta({
15144
+ description: "Grade level (-1 = Pre-K, 0 = K, 1-12 = grades, 13 = AP)"
15145
+ }).optional(),
15146
+ ids: CourseIds.nullable().optional(),
15147
+ sensor: exports_external.url().meta({ description: "Caliper sensor endpoint URL for this course" }).optional(),
15148
+ launchUrl: exports_external.url().meta({ description: "LTI launch URL for this course" }).optional(),
15149
+ overrides: CourseOverrides.optional()
15150
+ }).meta({
15151
+ id: "CourseConfig",
15152
+ description: "Configuration for a single course. Must have either grade or courseCode (or both)."
15078
15153
  });
15079
15154
  var TimebackConfig = exports_external.object({
15080
- name: exports_external.string().min(1, "App name is required"),
15081
- defaults: CourseDefaults.optional(),
15082
- courses: exports_external.array(CourseConfig).min(1, "At least one course is required"),
15083
- sensors: exports_external.array(exports_external.string().url()).optional()
15155
+ $schema: exports_external.string().meta({ description: "JSON Schema reference for editor support" }).optional(),
15156
+ name: exports_external.string().min(1, "App name is required").meta({ description: "Display name for your app" }),
15157
+ defaults: CourseDefaults.meta({
15158
+ description: "Default properties applied to all courses"
15159
+ }).optional(),
15160
+ courses: exports_external.array(CourseConfig).min(1, "At least one course is required").meta({ description: "Courses available in this app" }),
15161
+ sensor: exports_external.url().meta({ description: "Default Caliper sensor endpoint URL for all courses" }).optional(),
15162
+ launchUrl: exports_external.url().meta({ description: "Default LTI launch URL for all courses" }).optional()
15163
+ }).meta({
15164
+ id: "TimebackConfig",
15165
+ title: "Timeback Config",
15166
+ description: "Configuration schema for timeback.config.json files"
15167
+ }).refine((config2) => {
15168
+ return config2.courses.every((c) => c.grade !== undefined || c.courseCode !== undefined);
15169
+ }, {
15170
+ message: "Each course must have either a grade or a courseCode",
15171
+ path: ["courses"]
15172
+ }).refine((config2) => {
15173
+ const withGrade = config2.courses.filter((c) => c.grade !== undefined);
15174
+ const keys = withGrade.map((c) => `${c.subject}:${c.grade}`);
15175
+ return new Set(keys).size === keys.length;
15176
+ }, {
15177
+ message: "Duplicate (subject, grade) pair found; each must be unique",
15178
+ path: ["courses"]
15179
+ }).refine((config2) => {
15180
+ const withCode = config2.courses.filter((c) => c.courseCode !== undefined);
15181
+ const codes = withCode.map((c) => c.courseCode);
15182
+ return new Set(codes).size === codes.length;
15183
+ }, {
15184
+ message: "Duplicate courseCode found; each must be unique",
15185
+ path: ["courses"]
15186
+ }).refine((config2) => {
15187
+ return config2.courses.every((c) => c.sensor !== undefined || config2.sensor !== undefined);
15188
+ }, {
15189
+ message: "Each course must have an effective sensor; set a top-level `sensor` or per-course `sensor`",
15190
+ path: ["courses"]
15191
+ }).refine((config2) => {
15192
+ return config2.courses.every((c) => c.launchUrl !== undefined || config2.launchUrl !== undefined);
15193
+ }, {
15194
+ message: "Each course must have an effective launchUrl; set a top-level `launchUrl` or per-course `launchUrl`",
15195
+ path: ["courses"]
15084
15196
  });
15085
15197
  // ../types/src/zod/edubridge.ts
15086
15198
  var EdubridgeDateString = exports_external.union([IsoDateString, IsoDateTimeString]);
@@ -15331,20 +15443,45 @@ var OneRosterScoreScaleCreateInput = exports_external.object({
15331
15443
  }).strict();
15332
15444
  var OneRosterAssessmentLineItemCreateInput = exports_external.object({
15333
15445
  sourcedId: NonEmptyString2.optional(),
15446
+ status: Status.optional(),
15447
+ dateLastModified: IsoDateTimeString.optional(),
15334
15448
  title: NonEmptyString2.describe("title must be a non-empty string"),
15335
- class: Ref,
15336
- school: Ref,
15337
- category: Ref,
15338
- assignDate: OneRosterDateString,
15339
- dueDate: OneRosterDateString,
15340
- status: Status,
15449
+ description: exports_external.string().nullable().optional(),
15450
+ class: Ref.nullable().optional(),
15451
+ parentAssessmentLineItem: Ref.nullable().optional(),
15452
+ scoreScale: Ref.nullable().optional(),
15453
+ resultValueMin: exports_external.number().nullable().optional(),
15454
+ resultValueMax: exports_external.number().nullable().optional(),
15455
+ component: Ref.nullable().optional(),
15456
+ componentResource: Ref.nullable().optional(),
15457
+ learningObjectiveSet: exports_external.array(exports_external.object({
15458
+ source: exports_external.string(),
15459
+ learningObjectiveIds: exports_external.array(exports_external.string())
15460
+ })).optional().nullable(),
15461
+ course: Ref.nullable().optional(),
15341
15462
  metadata: Metadata
15342
15463
  }).strict();
15464
+ var LearningObjectiveResult = exports_external.object({
15465
+ learningObjectiveId: exports_external.string(),
15466
+ score: exports_external.number().optional(),
15467
+ textScore: exports_external.string().optional()
15468
+ });
15469
+ var LearningObjectiveScoreSetSchema = exports_external.array(exports_external.object({
15470
+ source: exports_external.string(),
15471
+ learningObjectiveResults: exports_external.array(LearningObjectiveResult)
15472
+ }));
15343
15473
  var OneRosterAssessmentResultCreateInput = exports_external.object({
15344
15474
  sourcedId: NonEmptyString2.optional(),
15345
- lineItem: Ref,
15475
+ status: Status.optional(),
15476
+ dateLastModified: IsoDateTimeString.optional(),
15477
+ metadata: Metadata,
15478
+ assessmentLineItem: Ref,
15346
15479
  student: Ref,
15347
- scoreDate: OneRosterDateString,
15480
+ score: exports_external.number().nullable().optional(),
15481
+ textScore: exports_external.string().nullable().optional(),
15482
+ scoreDate: exports_external.string().datetime(),
15483
+ scoreScale: Ref.nullable().optional(),
15484
+ scorePercentile: exports_external.number().nullable().optional(),
15348
15485
  scoreStatus: exports_external.enum([
15349
15486
  "exempt",
15350
15487
  "fully graded",
@@ -15352,9 +15489,12 @@ var OneRosterAssessmentResultCreateInput = exports_external.object({
15352
15489
  "partially graded",
15353
15490
  "submitted"
15354
15491
  ]),
15355
- score: exports_external.string().optional(),
15356
- status: Status,
15357
- metadata: Metadata
15492
+ comment: exports_external.string().nullable().optional(),
15493
+ learningObjectiveSet: LearningObjectiveScoreSetSchema.nullable().optional(),
15494
+ inProgress: exports_external.string().nullable().optional(),
15495
+ incomplete: exports_external.string().nullable().optional(),
15496
+ late: exports_external.string().nullable().optional(),
15497
+ missing: exports_external.string().nullable().optional()
15358
15498
  }).strict();
15359
15499
  var OneRosterOrgCreateInput = exports_external.object({
15360
15500
  sourcedId: NonEmptyString2.optional(),
@@ -15422,6 +15562,75 @@ var OneRosterCredentialInput = exports_external.object({
15422
15562
  var OneRosterDemographicsCreateInput = exports_external.object({
15423
15563
  sourcedId: NonEmptyString2.describe("sourcedId must be a non-empty string")
15424
15564
  }).loose();
15565
+ var CommonResourceMetadataSchema = exports_external.object({
15566
+ type: ResourceType,
15567
+ subject: TimebackSubject.nullish(),
15568
+ grades: exports_external.array(TimebackGrade).nullish(),
15569
+ language: exports_external.string().nullish(),
15570
+ xp: exports_external.number().nullish(),
15571
+ url: exports_external.url().nullish(),
15572
+ keywords: exports_external.array(exports_external.string()).nullish(),
15573
+ learningObjectiveSet: LearningObjectiveSetSchema.nullish(),
15574
+ lessonType: exports_external.string().nullish()
15575
+ }).passthrough();
15576
+ var QtiMetadataSchema = CommonResourceMetadataSchema.extend({
15577
+ type: exports_external.literal("qti"),
15578
+ subType: QtiSubType,
15579
+ questionType: QuestionType.optional(),
15580
+ difficulty: Difficulty.optional()
15581
+ });
15582
+ var TextMetadataSchema = CommonResourceMetadataSchema.extend({
15583
+ type: exports_external.literal("text"),
15584
+ format: exports_external.string(),
15585
+ author: exports_external.string().optional(),
15586
+ pageCount: exports_external.number().optional()
15587
+ });
15588
+ var AudioMetadataSchema = CommonResourceMetadataSchema.extend({
15589
+ type: exports_external.literal("audio"),
15590
+ duration: exports_external.string().regex(/^\d{2}:\d{2}:\d{2}(\.\d{2})?$/).optional(),
15591
+ format: exports_external.string(),
15592
+ speaker: exports_external.string().optional()
15593
+ });
15594
+ var VideoMetadataSchema = CommonResourceMetadataSchema.extend({
15595
+ type: exports_external.literal("video"),
15596
+ duration: exports_external.string().regex(/^\d{2}:\d{2}:\d{2}(\.\d{2})?$/).optional(),
15597
+ captionsAvailable: exports_external.boolean().optional(),
15598
+ format: exports_external.string()
15599
+ });
15600
+ var InteractiveMetadataSchema = CommonResourceMetadataSchema.extend({
15601
+ type: exports_external.literal("interactive"),
15602
+ launchUrl: exports_external.url().optional(),
15603
+ toolProvider: exports_external.string().optional(),
15604
+ instructionalMethod: exports_external.string().optional(),
15605
+ courseIdOnFail: exports_external.string().nullable().optional(),
15606
+ fail_fast: FastFailConfigSchema
15607
+ });
15608
+ var VisualMetadataSchema = CommonResourceMetadataSchema.extend({
15609
+ type: exports_external.literal("visual"),
15610
+ format: exports_external.string(),
15611
+ resolution: exports_external.string().optional()
15612
+ });
15613
+ var CourseMaterialMetadataSchema = CommonResourceMetadataSchema.extend({
15614
+ type: exports_external.literal("course-material"),
15615
+ subType: CourseMaterialSubType,
15616
+ author: exports_external.string().optional(),
15617
+ format: exports_external.string(),
15618
+ instructionalMethod: exports_external.string().optional()
15619
+ });
15620
+ var AssessmentBankMetadataSchema = CommonResourceMetadataSchema.extend({
15621
+ type: exports_external.literal("assessment-bank"),
15622
+ resources: exports_external.array(exports_external.string())
15623
+ });
15624
+ var ResourceMetadataSchema = exports_external.discriminatedUnion("type", [
15625
+ QtiMetadataSchema,
15626
+ TextMetadataSchema,
15627
+ AudioMetadataSchema,
15628
+ VideoMetadataSchema,
15629
+ InteractiveMetadataSchema,
15630
+ VisualMetadataSchema,
15631
+ CourseMaterialMetadataSchema,
15632
+ AssessmentBankMetadataSchema
15633
+ ]);
15425
15634
  var OneRosterResourceCreateInput = exports_external.object({
15426
15635
  sourcedId: NonEmptyString2.optional(),
15427
15636
  title: NonEmptyString2.describe("title must be a non-empty string"),
@@ -15431,7 +15640,7 @@ var OneRosterResourceCreateInput = exports_external.object({
15431
15640
  vendorId: exports_external.string().optional(),
15432
15641
  applicationId: exports_external.string().optional(),
15433
15642
  status: Status.optional(),
15434
- metadata: Metadata
15643
+ metadata: ResourceMetadataSchema.nullable().optional()
15435
15644
  }).strict();
15436
15645
  var CourseStructureItem = exports_external.object({
15437
15646
  url: NonEmptyString2.describe("courseStructure.url must be a non-empty string"),
@@ -15456,6 +15665,268 @@ var OneRosterBulkResultItem = exports_external.object({
15456
15665
  student: Ref
15457
15666
  }).loose();
15458
15667
  var OneRosterBulkResultsInput = exports_external.array(OneRosterBulkResultItem).min(1, "results must have at least one item");
15668
+ // ../types/src/zod/powerpath.ts
15669
+ var NonEmptyString3 = exports_external.string().trim().min(1);
15670
+ var ToolProvider = exports_external.enum(["edulastic", "mastery-track"]);
15671
+ var LessonTypeRequired = exports_external.enum([
15672
+ "powerpath-100",
15673
+ "quiz",
15674
+ "test-out",
15675
+ "placement",
15676
+ "unit-test",
15677
+ "alpha-read-article"
15678
+ ]);
15679
+ var GradeArray = exports_external.array(TimebackGrade);
15680
+ var ResourceMetadata = exports_external.record(exports_external.string(), exports_external.unknown()).optional();
15681
+ var ExternalTestBase = exports_external.object({
15682
+ courseId: NonEmptyString3,
15683
+ lessonTitle: NonEmptyString3.optional(),
15684
+ launchUrl: exports_external.url().optional(),
15685
+ toolProvider: ToolProvider,
15686
+ unitTitle: NonEmptyString3.optional(),
15687
+ courseComponentSourcedId: NonEmptyString3.optional(),
15688
+ vendorId: NonEmptyString3.optional(),
15689
+ description: NonEmptyString3.optional(),
15690
+ resourceMetadata: ResourceMetadata.nullable().optional(),
15691
+ grades: GradeArray
15692
+ });
15693
+ var ExternalTestOut = ExternalTestBase.extend({
15694
+ lessonType: exports_external.literal("test-out"),
15695
+ xp: exports_external.number()
15696
+ });
15697
+ var ExternalPlacement = ExternalTestBase.extend({
15698
+ lessonType: exports_external.literal("placement"),
15699
+ courseIdOnFail: NonEmptyString3.optional(),
15700
+ xp: exports_external.number().optional()
15701
+ });
15702
+ var InternalTestBase = exports_external.object({
15703
+ courseId: NonEmptyString3,
15704
+ lessonType: LessonTypeRequired,
15705
+ lessonTitle: NonEmptyString3.optional(),
15706
+ unitTitle: NonEmptyString3.optional(),
15707
+ courseComponentSourcedId: NonEmptyString3.optional(),
15708
+ resourceMetadata: ResourceMetadata.nullable().optional(),
15709
+ xp: exports_external.number().optional(),
15710
+ grades: GradeArray.optional(),
15711
+ courseIdOnFail: NonEmptyString3.optional()
15712
+ });
15713
+ var PowerPathCreateInternalTestInput = exports_external.union([
15714
+ InternalTestBase.extend({
15715
+ testType: exports_external.literal("qti"),
15716
+ qti: exports_external.object({
15717
+ url: exports_external.url(),
15718
+ title: NonEmptyString3.optional(),
15719
+ metadata: exports_external.record(exports_external.string(), exports_external.unknown()).optional()
15720
+ })
15721
+ }),
15722
+ InternalTestBase.extend({
15723
+ testType: exports_external.literal("assessment-bank"),
15724
+ assessmentBank: exports_external.object({
15725
+ resources: exports_external.array(exports_external.object({
15726
+ url: exports_external.url(),
15727
+ title: NonEmptyString3.optional(),
15728
+ metadata: exports_external.record(exports_external.string(), exports_external.unknown()).optional()
15729
+ }))
15730
+ })
15731
+ })
15732
+ ]);
15733
+ var PowerPathCreateNewAttemptInput = exports_external.object({
15734
+ student: NonEmptyString3,
15735
+ lesson: NonEmptyString3
15736
+ });
15737
+ var PowerPathFinalStudentAssessmentResponseInput = exports_external.object({
15738
+ student: NonEmptyString3,
15739
+ lesson: NonEmptyString3
15740
+ });
15741
+ var PowerPathLessonPlansCreateInput = exports_external.object({
15742
+ courseId: NonEmptyString3,
15743
+ userId: NonEmptyString3,
15744
+ classId: NonEmptyString3.optional()
15745
+ });
15746
+ var LessonPlanTarget = exports_external.object({
15747
+ type: exports_external.enum(["component", "resource"]),
15748
+ id: NonEmptyString3
15749
+ });
15750
+ var PowerPathLessonPlanOperationInput = exports_external.union([
15751
+ exports_external.object({
15752
+ type: exports_external.literal("set-skipped"),
15753
+ payload: exports_external.object({
15754
+ target: LessonPlanTarget,
15755
+ value: exports_external.boolean()
15756
+ })
15757
+ }),
15758
+ exports_external.object({
15759
+ type: exports_external.literal("add-custom-resource"),
15760
+ payload: exports_external.object({
15761
+ resource_id: NonEmptyString3,
15762
+ parent_component_id: NonEmptyString3,
15763
+ skipped: exports_external.boolean().optional()
15764
+ })
15765
+ }),
15766
+ exports_external.object({
15767
+ type: exports_external.literal("move-item-before"),
15768
+ payload: exports_external.object({
15769
+ target: LessonPlanTarget,
15770
+ reference_id: NonEmptyString3
15771
+ })
15772
+ }),
15773
+ exports_external.object({
15774
+ type: exports_external.literal("move-item-after"),
15775
+ payload: exports_external.object({
15776
+ target: LessonPlanTarget,
15777
+ reference_id: NonEmptyString3
15778
+ })
15779
+ }),
15780
+ exports_external.object({
15781
+ type: exports_external.literal("move-item-to-start"),
15782
+ payload: exports_external.object({
15783
+ target: LessonPlanTarget
15784
+ })
15785
+ }),
15786
+ exports_external.object({
15787
+ type: exports_external.literal("move-item-to-end"),
15788
+ payload: exports_external.object({
15789
+ target: LessonPlanTarget
15790
+ })
15791
+ }),
15792
+ exports_external.object({
15793
+ type: exports_external.literal("change-item-parent"),
15794
+ payload: exports_external.object({
15795
+ target: LessonPlanTarget,
15796
+ new_parent_id: NonEmptyString3,
15797
+ position: exports_external.enum(["start", "end"]).optional()
15798
+ })
15799
+ })
15800
+ ]);
15801
+ var PowerPathLessonPlanOperationsInput = exports_external.object({
15802
+ operation: exports_external.array(PowerPathLessonPlanOperationInput),
15803
+ reason: NonEmptyString3.optional()
15804
+ });
15805
+ var PowerPathLessonPlanUpdateStudentItemResponseInput = exports_external.object({
15806
+ studentId: NonEmptyString3,
15807
+ componentResourceId: NonEmptyString3,
15808
+ result: exports_external.object({
15809
+ status: exports_external.enum(["active", "tobedeleted"]),
15810
+ metadata: exports_external.record(exports_external.string(), exports_external.unknown()).optional(),
15811
+ score: exports_external.number().optional(),
15812
+ textScore: NonEmptyString3.optional(),
15813
+ scoreDate: NonEmptyString3,
15814
+ scorePercentile: exports_external.number().optional(),
15815
+ scoreStatus: ScoreStatus,
15816
+ comment: NonEmptyString3.optional(),
15817
+ learningObjectiveSet: exports_external.array(exports_external.object({
15818
+ source: NonEmptyString3,
15819
+ learningObjectiveResults: exports_external.array(exports_external.object({
15820
+ learningObjectiveId: NonEmptyString3,
15821
+ score: exports_external.number().optional(),
15822
+ textScore: NonEmptyString3.optional()
15823
+ }))
15824
+ })).optional(),
15825
+ inProgress: NonEmptyString3.optional(),
15826
+ incomplete: NonEmptyString3.optional(),
15827
+ late: NonEmptyString3.optional(),
15828
+ missing: NonEmptyString3.optional()
15829
+ })
15830
+ });
15831
+ var PowerPathMakeExternalTestAssignmentInput = exports_external.object({
15832
+ student: NonEmptyString3,
15833
+ lesson: NonEmptyString3,
15834
+ applicationName: NonEmptyString3.optional(),
15835
+ testId: NonEmptyString3.optional(),
15836
+ skipCourseEnrollment: exports_external.boolean().optional()
15837
+ });
15838
+ var PowerPathPlacementResetUserPlacementInput = exports_external.object({
15839
+ student: NonEmptyString3,
15840
+ subject: TimebackSubject
15841
+ });
15842
+ var PowerPathResetAttemptInput = exports_external.object({
15843
+ student: NonEmptyString3,
15844
+ lesson: NonEmptyString3
15845
+ });
15846
+ var PowerPathScreeningResetSessionInput = exports_external.object({
15847
+ userId: NonEmptyString3
15848
+ });
15849
+ var PowerPathScreeningAssignTestInput = exports_external.object({
15850
+ userId: NonEmptyString3,
15851
+ subject: exports_external.enum(["Math", "Reading", "Language", "Science"])
15852
+ });
15853
+ var PowerPathTestAssignmentsCreateInput = exports_external.object({
15854
+ student: NonEmptyString3,
15855
+ subject: TimebackSubject,
15856
+ grade: TimebackGrade,
15857
+ testName: NonEmptyString3.optional()
15858
+ });
15859
+ var PowerPathTestAssignmentsUpdateInput = exports_external.object({
15860
+ testName: NonEmptyString3
15861
+ });
15862
+ var PowerPathTestAssignmentItemInput = exports_external.object({
15863
+ student: NonEmptyString3,
15864
+ subject: TimebackSubject,
15865
+ grade: TimebackGrade,
15866
+ testName: NonEmptyString3.optional()
15867
+ });
15868
+ var PowerPathTestAssignmentsBulkInput = exports_external.object({
15869
+ items: exports_external.array(PowerPathTestAssignmentItemInput)
15870
+ });
15871
+ var PowerPathTestAssignmentsImportInput = exports_external.object({
15872
+ spreadsheetUrl: exports_external.url(),
15873
+ sheet: NonEmptyString3
15874
+ });
15875
+ var PowerPathTestAssignmentsListParams = exports_external.object({
15876
+ student: NonEmptyString3,
15877
+ status: exports_external.enum(["assigned", "in_progress", "completed", "failed", "expired", "cancelled"]).optional(),
15878
+ subject: NonEmptyString3.optional(),
15879
+ grade: TimebackGrade.optional(),
15880
+ limit: exports_external.number().int().positive().max(3000).optional(),
15881
+ offset: exports_external.number().int().nonnegative().optional()
15882
+ });
15883
+ var PowerPathTestAssignmentsAdminParams = exports_external.object({
15884
+ student: NonEmptyString3.optional(),
15885
+ status: exports_external.enum(["assigned", "in_progress", "completed", "failed", "expired", "cancelled"]).optional(),
15886
+ subject: NonEmptyString3.optional(),
15887
+ grade: TimebackGrade.optional(),
15888
+ limit: exports_external.number().int().positive().max(3000).optional(),
15889
+ offset: exports_external.number().int().nonnegative().optional()
15890
+ });
15891
+ var PowerPathUpdateStudentQuestionResponseInput = exports_external.object({
15892
+ student: NonEmptyString3,
15893
+ question: NonEmptyString3,
15894
+ response: exports_external.union([NonEmptyString3, exports_external.array(NonEmptyString3)]).optional(),
15895
+ responses: exports_external.record(exports_external.string(), exports_external.union([NonEmptyString3, exports_external.array(NonEmptyString3)])).optional(),
15896
+ lesson: NonEmptyString3
15897
+ });
15898
+ var PowerPathGetAssessmentProgressParams = exports_external.object({
15899
+ student: NonEmptyString3,
15900
+ lesson: NonEmptyString3,
15901
+ attempt: exports_external.number().int().positive().optional()
15902
+ });
15903
+ var PowerPathGetNextQuestionParams = exports_external.object({
15904
+ student: NonEmptyString3,
15905
+ lesson: NonEmptyString3
15906
+ });
15907
+ var PowerPathGetAttemptsParams = exports_external.object({
15908
+ student: NonEmptyString3,
15909
+ lesson: NonEmptyString3
15910
+ });
15911
+ var PowerPathTestOutParams = exports_external.object({
15912
+ student: NonEmptyString3,
15913
+ lesson: NonEmptyString3.optional(),
15914
+ finalized: exports_external.boolean().optional(),
15915
+ toolProvider: NonEmptyString3.optional(),
15916
+ attempt: exports_external.number().int().positive().optional()
15917
+ });
15918
+ var PowerPathImportExternalTestAssignmentResultsParams = exports_external.object({
15919
+ student: NonEmptyString3,
15920
+ lesson: NonEmptyString3,
15921
+ applicationName: NonEmptyString3.optional()
15922
+ });
15923
+ var PowerPathPlacementQueryParams = exports_external.object({
15924
+ student: NonEmptyString3,
15925
+ subject: TimebackSubject
15926
+ });
15927
+ var PowerPathSyllabusQueryParams = exports_external.object({
15928
+ status: exports_external.enum(["active", "tobedeleted"]).optional()
15929
+ });
15459
15930
  // ../types/src/zod/qti.ts
15460
15931
  var QtiAssessmentItemType = exports_external.enum([
15461
15932
  "choice",
@@ -15707,11 +16178,10 @@ var QtiLessonFeedbackInput = exports_external.object({
15707
16178
  humanApproved: exports_external.boolean().optional()
15708
16179
  }).strict();
15709
16180
  // ../internal/cli-infra/src/config/timeback.ts
15710
- var FILE_PATTERNS2 = ["timeback.config.ts", "timeback.config.js", "timeback.config.mjs"];
15711
- var jiti = createJiti(import.meta.url, { fsCache: false });
15712
- async function importModule(fullPath) {
15713
- const module = await jiti.import(fullPath);
15714
- return module.default ?? module;
16181
+ var CONFIG_FILENAME = "timeback.config.json";
16182
+ var FILE_PATTERNS2 = [CONFIG_FILENAME];
16183
+ function isJsonConfigPath(configPath) {
16184
+ return extname(configPath).toLowerCase() === ".json";
15715
16185
  }
15716
16186
  function deriveCourseIds(config3) {
15717
16187
  const result = { staging: [], production: [] };
@@ -15729,58 +16199,73 @@ async function readPackageVersion(cwd) {
15729
16199
  return "0.0.0";
15730
16200
  }
15731
16201
  }
16202
+ async function loadWithC12(cwd, configPath) {
16203
+ if (configPath && !isJsonConfigPath(configPath)) {
16204
+ throw new Error(`Config file must be JSON (.json): ${configPath}`);
16205
+ }
16206
+ const result = await c12LoadConfig({
16207
+ cwd,
16208
+ name: "timeback",
16209
+ configFile: configPath ?? CONFIG_FILENAME,
16210
+ rcFile: false,
16211
+ packageJson: false,
16212
+ dotenv: false,
16213
+ envName: false,
16214
+ extend: false,
16215
+ omit$Keys: true,
16216
+ defaults: {},
16217
+ overrides: {}
16218
+ });
16219
+ if (!result.config || Object.keys(result.config).length === 0) {
16220
+ return null;
16221
+ }
16222
+ const rawConfig = result.config;
16223
+ if ("extends" in rawConfig) {
16224
+ throw new Error("The 'extends' feature is not supported in timeback.config.json. " + "Please inline all configuration.");
16225
+ }
16226
+ const { $schema: _schema, ...configWithoutSchema } = rawConfig;
16227
+ return {
16228
+ config: configWithoutSchema,
16229
+ configFile: result.configFile ?? resolve(cwd, configPath ?? CONFIG_FILENAME)
16230
+ };
16231
+ }
15732
16232
  async function parse6() {
15733
16233
  const cwd = process.cwd();
15734
- let rawConfig = null;
15735
- let foundPath = null;
15736
- let loadError = null;
15737
- for (const configPath of FILE_PATTERNS2) {
15738
- const fullPath = resolve(cwd, configPath);
15739
- if (!existsSync(fullPath))
15740
- continue;
15741
- try {
15742
- rawConfig = await importModule(fullPath);
15743
- foundPath = configPath;
15744
- break;
15745
- } catch (err) {
15746
- loadError = err instanceof Error ? err : new Error(String(err));
15747
- foundPath = configPath;
15748
- break;
16234
+ try {
16235
+ const loaded = await loadWithC12(cwd);
16236
+ if (!loaded) {
16237
+ return {
16238
+ success: false,
16239
+ error: `No timeback config found. Create ${CONFIG_FILENAME}`
16240
+ };
15749
16241
  }
15750
- }
15751
- if (loadError && foundPath) {
15752
- return {
15753
- success: false,
15754
- error: `Failed to load ${foundPath}:
15755
- ${loadError.message}`
15756
- };
15757
- }
15758
- if (!rawConfig || !foundPath) {
16242
+ const result = TimebackConfig.safeParse(loaded.config);
16243
+ if (!result.success) {
16244
+ const issues = result.error.issues.map((issue2) => ` - ${issue2.path.join(".")}: ${issue2.message}`).join(`
16245
+ `);
16246
+ return {
16247
+ success: false,
16248
+ error: `Invalid config in ${CONFIG_FILENAME}:
16249
+ ${issues}`
16250
+ };
16251
+ }
16252
+ const version2 = await readPackageVersion(cwd);
16253
+ const baseConfig = { ...result.data, version: version2 };
15759
16254
  return {
15760
- success: false,
15761
- error: `No timeback config found. Create one of: ${FILE_PATTERNS2.join(", ")}`
16255
+ success: true,
16256
+ config: {
16257
+ ...baseConfig,
16258
+ path: loaded.configFile,
16259
+ courseIds: deriveCourseIds(baseConfig)
16260
+ }
15762
16261
  };
15763
- }
15764
- const result = TimebackConfig.safeParse(rawConfig);
15765
- if (!result.success) {
15766
- const issues = result.error.issues.map((issue2) => ` - ${issue2.path.join(".")}: ${issue2.message}`).join(`
15767
- `);
16262
+ } catch (err) {
15768
16263
  return {
15769
16264
  success: false,
15770
- error: `Invalid config in ${foundPath}:
15771
- ${issues}`
16265
+ error: `Failed to load ${CONFIG_FILENAME}:
16266
+ ${err instanceof Error ? err.message : String(err)}`
15772
16267
  };
15773
16268
  }
15774
- const version2 = await readPackageVersion(cwd);
15775
- const baseConfig = { ...result.data, version: version2 };
15776
- return {
15777
- success: true,
15778
- config: {
15779
- ...baseConfig,
15780
- path: `${cwd}/${foundPath}`,
15781
- courseIds: deriveCourseIds(baseConfig)
15782
- }
15783
- };
15784
16269
  }
15785
16270
  function printError2(error48) {
15786
16271
  console.log();
@@ -15788,13 +16273,16 @@ function printError2(error48) {
15788
16273
  console.log();
15789
16274
  console.log(` ${error48}`);
15790
16275
  console.log();
15791
- console.log(` ${dim("Example timeback.config.ts:")}`);
16276
+ console.log(` ${dim("Example timeback.config.json:")}`);
15792
16277
  console.log();
15793
- console.log(` ${yellow("export default {")}`);
15794
- console.log(` ${yellow(" name: 'My Timeback App',")}`);
15795
- console.log(` ${yellow(" courses: [")}`);
15796
- console.log(` ${yellow(" { subject: 'Math', grade: 3 },")}`);
15797
- console.log(` ${yellow(" ],")}`);
16278
+ console.log(` ${yellow("{")}`);
16279
+ console.log(` ${yellow(' "$schema": "https://timeback.dev/schema.json",')}`);
16280
+ console.log(` ${yellow(' "name": "My Timeback App",')}`);
16281
+ console.log(` ${yellow(' "launchUrl": "https://example.com/play",')}`);
16282
+ console.log(` ${yellow(' "sensor": "https://example.com/sensor",')}`);
16283
+ console.log(` ${yellow(' "courses": [')}`);
16284
+ console.log(` ${yellow(' { "subject": "Math", "grade": 3 }')}`);
16285
+ console.log(` ${yellow(" ]")}`);
15798
16286
  console.log(` ${yellow("}")}`);
15799
16287
  console.log();
15800
16288
  }
@@ -16022,29 +16510,18 @@ function isValidUrl(url2) {
16022
16510
  return false;
16023
16511
  }
16024
16512
  }
16025
- async function promptSensors() {
16026
- const wantSensors = await ye({
16027
- message: "Add Caliper sensor URLs for event filtering?",
16028
- initialValue: false
16029
- });
16030
- if (isCancelled(wantSensors)) {
16031
- return;
16032
- }
16033
- if (!wantSensors) {
16034
- return [];
16035
- }
16513
+ async function promptSensor(options) {
16514
+ const { defaultValue } = options ?? {};
16036
16515
  const input = await he({
16037
- message: "Sensor URLs (comma-separated)",
16038
- placeholder: "https://myapp.example.com/caliper/sensors/activity",
16516
+ message: "Sensor URL (your app origin, used for activity tracking)",
16517
+ placeholder: "https://myapp.example.com",
16518
+ defaultValue,
16039
16519
  validate: (value) => {
16040
16520
  if (!value.trim()) {
16041
- return "Enter at least one sensor URL";
16521
+ return "Sensor URL is required for activity tracking";
16042
16522
  }
16043
- const urls = value.split(",").map((s) => s.trim());
16044
- for (const url2 of urls) {
16045
- if (!isValidUrl(url2)) {
16046
- return `Invalid URL: ${url2}`;
16047
- }
16523
+ if (!isValidUrl(value.trim())) {
16524
+ return "Invalid URL format";
16048
16525
  }
16049
16526
  return;
16050
16527
  }
@@ -16052,7 +16529,26 @@ async function promptSensors() {
16052
16529
  if (isCancelled(input)) {
16053
16530
  return;
16054
16531
  }
16055
- return input.split(",").map((s) => s.trim()).filter(Boolean);
16532
+ return input.trim();
16533
+ }
16534
+ // ../internal/cli-infra/src/sensors/utils.ts
16535
+ function deriveSensorsFromConfig(config3) {
16536
+ const sensors = new Set;
16537
+ if (config3.sensor) {
16538
+ sensors.add(config3.sensor);
16539
+ }
16540
+ for (const course of config3.courses) {
16541
+ if (course.sensor) {
16542
+ sensors.add(course.sensor);
16543
+ }
16544
+ if (course.overrides?.staging?.sensor) {
16545
+ sensors.add(course.overrides.staging.sensor);
16546
+ }
16547
+ if (course.overrides?.production?.sensor) {
16548
+ sensors.add(course.overrides.production.sensor);
16549
+ }
16550
+ }
16551
+ return Array.from(sensors);
16056
16552
  }
16057
16553
  // src/config/constants.ts
16058
16554
  var configValues = {
@@ -16616,8 +17112,8 @@ async function promptImportApp(credentials, configuredEnvs) {
16616
17112
  if (!result.success) {
16617
17113
  return result;
16618
17114
  }
16619
- const sensors = await promptSensors();
16620
- if (sensors === undefined) {
17115
+ const sensor = await promptSensor();
17116
+ if (sensor === undefined) {
16621
17117
  return { success: false, cancelled: true };
16622
17118
  }
16623
17119
  return {
@@ -16625,7 +17121,7 @@ async function promptImportApp(credentials, configuredEnvs) {
16625
17121
  name: result.appName,
16626
17122
  courses: result.courses,
16627
17123
  environment: result.environment,
16628
- sensors: sensors.length > 0 ? sensors : undefined
17124
+ sensor
16629
17125
  };
16630
17126
  } catch (error48) {
16631
17127
  const message = error48 instanceof Error ? error48.message : "Unknown error";
@@ -16655,7 +17151,7 @@ async function promptNoConfig(credentials, configuredEnvs, opts = {}) {
16655
17151
  // src/cli/commands/serve/config.ts
16656
17152
  import { basename as basename2 } from "node:path";
16657
17153
  function buildUserConfigFromImport(result) {
16658
- const { name, courses, sensors } = result;
17154
+ const { name, courses, sensor } = result;
16659
17155
  const courseIds = {
16660
17156
  staging: [],
16661
17157
  production: []
@@ -16668,8 +17164,8 @@ function buildUserConfigFromImport(result) {
16668
17164
  }
16669
17165
  return {
16670
17166
  name,
17167
+ sensor,
16671
17168
  courses,
16672
- sensors,
16673
17169
  version: "0.0.0",
16674
17170
  path: "",
16675
17171
  courseIds
@@ -16743,17 +17239,16 @@ async function resolveFromConfigOrImport(credentials, configuredEnvs, defaultEnv
16743
17239
  function parseSensors(sensors) {
16744
17240
  return sensors.split(",").map((s) => s.trim()).filter(Boolean);
16745
17241
  }
16746
- function applyCliOverrides(config3, opts) {
17242
+ function getEffectiveSensors(config3, opts) {
16747
17243
  if (opts.sensors) {
16748
- config3.sensors = parseSensors(opts.sensors);
17244
+ return parseSensors(opts.sensors);
16749
17245
  }
17246
+ const derived = deriveSensorsFromConfig(config3);
17247
+ return derived.length > 0 ? derived : undefined;
16750
17248
  }
16751
17249
  async function resolveConfig(courseIds, opts, credentials, configuredEnvs, defaultEnv) {
16752
17250
  const parserOpts = { playcademy: opts.playcademy };
16753
17251
  const resolved = courseIds.length > 0 ? await resolveFromCourseIds(courseIds, defaultEnv, credentials, configuredEnvs) : await resolveFromConfigOrImport(credentials, configuredEnvs, defaultEnv, parserOpts);
16754
- if (!resolved)
16755
- return null;
16756
- applyCliOverrides(resolved.userConfig, opts);
16757
17252
  return resolved;
16758
17253
  }
16759
17254
 
@@ -19891,7 +20386,7 @@ function createEnvMiddleware(ctx, manager) {
19891
20386
  }, 400);
19892
20387
  }
19893
20388
  const client = manager.get(env2);
19894
- const sensors = ctx.userConfig.sensors;
20389
+ const sensors = ctx.derivedSensors;
19895
20390
  c.set("env", env2);
19896
20391
  c.set("client", client);
19897
20392
  c.set("sensors", sensors);
@@ -20430,7 +20925,8 @@ async function serveCommand(courseIds, opts) {
20430
20925
  serverConfig,
20431
20926
  userConfig: resolved.userConfig,
20432
20927
  credentials,
20433
- defaultEnvironment: resolved.environment
20928
+ defaultEnvironment: resolved.environment,
20929
+ derivedSensors: getEffectiveSensors(resolved.userConfig, opts)
20434
20930
  };
20435
20931
  startServer(ctx, serverConfig, resolved.configFile);
20436
20932
  }