@timeback/core 0.1.3 → 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
@@ -699,7 +699,17 @@ class TimebackProvider {
699
699
  }
700
700
  function getEnv(key) {
701
701
  try {
702
- return typeof process === "undefined" ? undefined : process.env[key];
702
+ if (typeof process === "undefined")
703
+ return;
704
+ if (typeof key === "string") {
705
+ return process.env[key];
706
+ }
707
+ for (const k of key) {
708
+ const value = process.env[k];
709
+ if (value !== undefined)
710
+ return value;
711
+ }
712
+ return;
703
713
  } catch {
704
714
  return;
705
715
  }
@@ -730,6 +740,18 @@ var DEFAULT_PROVIDER_REGISTRY = {
730
740
  }
731
741
  }
732
742
  };
743
+ function primaryEnvVar(key) {
744
+ if (typeof key === "string") {
745
+ return key;
746
+ }
747
+ if (key.length === 0) {
748
+ throw new Error(`Missing env var key: ${key}`);
749
+ }
750
+ return key[0];
751
+ }
752
+ function formatEnvVarKey(key) {
753
+ return primaryEnvVar(key);
754
+ }
733
755
  function validateEnv(env) {
734
756
  if (env !== "staging" && env !== "production") {
735
757
  throw new Error(`Invalid env "${env}": must be "staging" or "production"`);
@@ -740,10 +762,10 @@ function validateAuth(auth, envVars) {
740
762
  const clientId = auth?.clientId ?? getEnv(envVars.clientId);
741
763
  const clientSecret = auth?.clientSecret ?? getEnv(envVars.clientSecret);
742
764
  if (!clientId) {
743
- throw new Error(`Missing clientId: provide in config or set ${envVars.clientId}`);
765
+ throw new Error(`Missing clientId: provide in config or set ${formatEnvVarKey(envVars.clientId)}`);
744
766
  }
745
767
  if (!clientSecret) {
746
- throw new Error(`Missing clientSecret: provide in config or set ${envVars.clientSecret}`);
768
+ throw new Error(`Missing clientSecret: provide in config or set ${formatEnvVarKey(envVars.clientSecret)}`);
747
769
  }
748
770
  return { clientId, clientSecret };
749
771
  }
@@ -759,21 +781,21 @@ function buildMissingEnvError(envVars) {
759
781
  const clientId = getEnv(envVars.clientId);
760
782
  const clientSecret = getEnv(envVars.clientSecret);
761
783
  if (baseUrl === undefined && clientId === undefined) {
762
- const hint = envVars.env ?? envVars.baseUrl;
784
+ const hint = formatEnvVarKey(envVars.env ?? envVars.baseUrl);
763
785
  return `Missing env: provide in config or set ${hint}`;
764
786
  }
765
787
  const missing = [];
766
788
  if (baseUrl === undefined) {
767
- missing.push(envVars.env ?? envVars.baseUrl);
789
+ missing.push(formatEnvVarKey(envVars.env ?? envVars.baseUrl));
768
790
  }
769
791
  if (baseUrl !== undefined && authUrl === undefined) {
770
- missing.push(envVars.authUrl);
792
+ missing.push(formatEnvVarKey(envVars.authUrl));
771
793
  }
772
794
  if (clientId === undefined) {
773
- missing.push(envVars.clientId);
795
+ missing.push(formatEnvVarKey(envVars.clientId));
774
796
  }
775
797
  if (clientSecret === undefined) {
776
- missing.push(envVars.clientSecret);
798
+ missing.push(formatEnvVarKey(envVars.clientSecret));
777
799
  }
778
800
  return `Missing environment variables: ${missing.join(", ")}`;
779
801
  }
@@ -1473,10 +1495,10 @@ function validateOffsetListParams(params) {
1473
1495
  }
1474
1496
  }
1475
1497
  var CALIPER_ENV_VARS = {
1476
- baseUrl: "CALIPER_BASE_URL",
1477
- authUrl: "CALIPER_TOKEN_URL",
1478
- clientId: "CALIPER_CLIENT_ID",
1479
- clientSecret: "CALIPER_CLIENT_SECRET"
1498
+ baseUrl: ["TIMEBACK_API_BASE_URL", "TIMEBACK_BASE_URL", "CALIPER_BASE_URL"],
1499
+ authUrl: ["TIMEBACK_API_AUTH_URL", "TIMEBACK_AUTH_URL", "CALIPER_TOKEN_URL"],
1500
+ clientId: ["TIMEBACK_API_CLIENT_ID", "TIMEBACK_CLIENT_ID", "CALIPER_CLIENT_ID"],
1501
+ clientSecret: ["TIMEBACK_API_CLIENT_SECRET", "TIMEBACK_CLIENT_SECRET", "CALIPER_CLIENT_SECRET"]
1480
1502
  };
1481
1503
  var CALIPER_DATA_VERSION = "http://purl.imsglobal.org/ctx/caliper/v1p2";
1482
1504
  function resolveToProvider2(config, registry = DEFAULT_PROVIDER_REGISTRY) {
@@ -3725,7 +3747,7 @@ class Doc {
3725
3747
  var version = {
3726
3748
  major: 4,
3727
3749
  minor: 3,
3728
- patch: 5
3750
+ patch: 6
3729
3751
  };
3730
3752
  var $ZodType = /* @__PURE__ */ $constructor("$ZodType", (inst, def) => {
3731
3753
  var _a;
@@ -5009,7 +5031,7 @@ var $ZodRecord = /* @__PURE__ */ $constructor("$ZodRecord", (inst, def) => {
5009
5031
  if (keyResult instanceof Promise) {
5010
5032
  throw new Error("Async schemas not supported in object keys currently");
5011
5033
  }
5012
- const checkNumericKey = typeof key === "string" && number.test(key) && keyResult.issues.length && keyResult.issues.some((iss) => iss.code === "invalid_type" && iss.expected === "number");
5034
+ const checkNumericKey = typeof key === "string" && number.test(key) && keyResult.issues.length;
5013
5035
  if (checkNumericKey) {
5014
5036
  const retryResult = def.keyType._zod.run({ value: Number(key), issues: [] }, ctx);
5015
5037
  if (retryResult instanceof Promise) {
@@ -12326,7 +12348,7 @@ function finalize(ctx, schema) {
12326
12348
  }
12327
12349
  }
12328
12350
  }
12329
- if (refSchema.$ref) {
12351
+ if (refSchema.$ref && refSeen.def) {
12330
12352
  for (const key in schema2) {
12331
12353
  if (key === "$ref" || key === "allOf")
12332
12354
  continue;
@@ -14958,7 +14980,7 @@ var TimebackSubject = exports_external.enum([
14958
14980
  "Math",
14959
14981
  "None",
14960
14982
  "Other"
14961
- ]);
14983
+ ]).meta({ id: "TimebackSubject", description: "Subject area" });
14962
14984
  var TimebackGrade = exports_external.union([
14963
14985
  exports_external.literal(-1),
14964
14986
  exports_external.literal(0),
@@ -14975,7 +14997,10 @@ var TimebackGrade = exports_external.union([
14975
14997
  exports_external.literal(11),
14976
14998
  exports_external.literal(12),
14977
14999
  exports_external.literal(13)
14978
- ]);
15000
+ ]).meta({
15001
+ id: "TimebackGrade",
15002
+ description: "Grade level (-1 = Pre-K, 0 = K, 1-12 = grades, 13 = AP)"
15003
+ });
14979
15004
  var ScoreStatus = exports_external.enum([
14980
15005
  "exempt",
14981
15006
  "fully graded",
@@ -15205,62 +15230,84 @@ var CaliperListEventsParams = exports_external.object({
15205
15230
  actorEmail: exports_external.email().optional()
15206
15231
  }).strict();
15207
15232
  var CourseIds = exports_external.object({
15208
- staging: exports_external.string().optional(),
15209
- production: exports_external.string().optional()
15210
- });
15211
- var CourseType = exports_external.enum(["base", "hole-filling", "optional"]);
15212
- var PublishStatus = exports_external.enum(["draft", "testing", "published", "deactivated"]);
15233
+ staging: exports_external.string().meta({ description: "Course ID in staging environment" }).optional(),
15234
+ production: exports_external.string().meta({ description: "Course ID in production environment" }).optional()
15235
+ }).meta({ id: "CourseIds", description: "Environment-specific course IDs (populated by sync)" });
15236
+ var CourseType = exports_external.enum(["base", "hole-filling", "optional"]).meta({ id: "CourseType", description: "Course classification type" });
15237
+ var PublishStatus = exports_external.enum(["draft", "testing", "published", "deactivated"]).meta({ id: "PublishStatus", description: "Course publication status" });
15213
15238
  var CourseGoals = exports_external.object({
15214
- dailyXp: exports_external.number().int().positive().optional(),
15215
- dailyLessons: exports_external.number().int().positive().optional(),
15216
- dailyActiveMinutes: exports_external.number().int().positive().optional(),
15217
- dailyAccuracy: exports_external.number().int().min(0).max(100).optional(),
15218
- dailyMasteredUnits: exports_external.number().int().positive().optional()
15219
- });
15239
+ dailyXp: exports_external.number().int().positive().meta({ description: "Target XP to earn per day" }).optional(),
15240
+ dailyLessons: exports_external.number().int().positive().meta({ description: "Target lessons to complete per day" }).optional(),
15241
+ dailyActiveMinutes: exports_external.number().int().positive().meta({ description: "Target active learning minutes per day" }).optional(),
15242
+ dailyAccuracy: exports_external.number().int().min(0).max(100).meta({ description: "Target accuracy percentage (0-100)" }).optional(),
15243
+ dailyMasteredUnits: exports_external.number().int().positive().meta({ description: "Target units to master per day" }).optional()
15244
+ }).meta({ id: "CourseGoals", description: "Daily learning goals for a course" });
15220
15245
  var CourseMetrics = exports_external.object({
15221
- totalXp: exports_external.number().int().positive().optional(),
15222
- totalLessons: exports_external.number().int().positive().optional(),
15223
- totalGrades: exports_external.number().int().positive().optional()
15224
- });
15246
+ totalXp: exports_external.number().int().positive().meta({ description: "Total XP available in the course" }).optional(),
15247
+ totalLessons: exports_external.number().int().positive().meta({ description: "Total number of lessons/activities" }).optional(),
15248
+ totalGrades: exports_external.number().int().positive().meta({ description: "Total grade levels covered" }).optional()
15249
+ }).meta({ id: "CourseMetrics", description: "Aggregate metrics for a course" });
15225
15250
  var CourseMetadata = exports_external.object({
15226
15251
  courseType: CourseType.optional(),
15227
- isSupplemental: exports_external.boolean().optional(),
15228
- isCustom: exports_external.boolean().optional(),
15252
+ isSupplemental: exports_external.boolean().meta({ description: "Whether this is supplemental to a base course" }).optional(),
15253
+ isCustom: exports_external.boolean().meta({ description: "Whether this is a custom course for an individual student" }).optional(),
15229
15254
  publishStatus: PublishStatus.optional(),
15230
- contactEmail: exports_external.email().optional(),
15231
- primaryApp: exports_external.string().optional(),
15255
+ contactEmail: exports_external.email().meta({ description: "Contact email for course issues" }).optional(),
15256
+ primaryApp: exports_external.string().meta({ description: "Primary application identifier" }).optional(),
15232
15257
  goals: CourseGoals.optional(),
15233
15258
  metrics: CourseMetrics.optional()
15234
- });
15259
+ }).meta({ id: "CourseMetadata", description: "Course metadata (matches API metadata object)" });
15235
15260
  var CourseDefaults = exports_external.object({
15236
- courseCode: exports_external.string().optional(),
15237
- level: exports_external.string().optional(),
15261
+ courseCode: exports_external.string().meta({ description: "Course code (e.g., 'MATH101')" }).optional(),
15262
+ level: exports_external.string().meta({ description: "Course level (e.g., 'AP', 'Honors')" }).optional(),
15238
15263
  metadata: CourseMetadata.optional()
15264
+ }).meta({
15265
+ id: "CourseDefaults",
15266
+ description: "Default properties that apply to all courses unless overridden"
15239
15267
  });
15240
15268
  var CourseEnvOverrides = exports_external.object({
15241
- level: exports_external.string().optional(),
15242
- sensor: exports_external.string().url().optional(),
15243
- launchUrl: exports_external.string().url().optional(),
15269
+ level: exports_external.string().meta({ description: "Course level for this environment" }).optional(),
15270
+ sensor: exports_external.url().meta({ description: "Caliper sensor endpoint URL for this environment" }).optional(),
15271
+ launchUrl: exports_external.url().meta({ description: "LTI launch URL for this environment" }).optional(),
15244
15272
  metadata: CourseMetadata.optional()
15273
+ }).meta({
15274
+ id: "CourseEnvOverrides",
15275
+ description: "Environment-specific course overrides (non-identity fields)"
15245
15276
  });
15246
15277
  var CourseOverrides = exports_external.object({
15247
- staging: CourseEnvOverrides.optional(),
15248
- production: CourseEnvOverrides.optional()
15249
- });
15278
+ staging: CourseEnvOverrides.meta({
15279
+ description: "Overrides for staging environment"
15280
+ }).optional(),
15281
+ production: CourseEnvOverrides.meta({
15282
+ description: "Overrides for production environment"
15283
+ }).optional()
15284
+ }).meta({ id: "CourseOverrides", description: "Per-environment course overrides" });
15250
15285
  var CourseConfig = CourseDefaults.extend({
15251
- subject: TimebackSubject,
15252
- grade: TimebackGrade.optional(),
15286
+ subject: TimebackSubject.meta({ description: "Subject area for this course" }),
15287
+ grade: TimebackGrade.meta({
15288
+ description: "Grade level (-1 = Pre-K, 0 = K, 1-12 = grades, 13 = AP)"
15289
+ }).optional(),
15253
15290
  ids: CourseIds.nullable().optional(),
15254
- sensor: exports_external.string().url().optional(),
15255
- launchUrl: exports_external.string().url().optional(),
15291
+ sensor: exports_external.url().meta({ description: "Caliper sensor endpoint URL for this course" }).optional(),
15292
+ launchUrl: exports_external.url().meta({ description: "LTI launch URL for this course" }).optional(),
15256
15293
  overrides: CourseOverrides.optional()
15294
+ }).meta({
15295
+ id: "CourseConfig",
15296
+ description: "Configuration for a single course. Must have either grade or courseCode (or both)."
15257
15297
  });
15258
15298
  var TimebackConfig = exports_external.object({
15259
- name: exports_external.string().min(1, "App name is required"),
15260
- defaults: CourseDefaults.optional(),
15261
- courses: exports_external.array(CourseConfig).min(1, "At least one course is required"),
15262
- sensor: exports_external.string().url().optional(),
15263
- launchUrl: exports_external.string().url().optional()
15299
+ $schema: exports_external.string().meta({ description: "JSON Schema reference for editor support" }).optional(),
15300
+ name: exports_external.string().min(1, "App name is required").meta({ description: "Display name for your app" }),
15301
+ defaults: CourseDefaults.meta({
15302
+ description: "Default properties applied to all courses"
15303
+ }).optional(),
15304
+ courses: exports_external.array(CourseConfig).min(1, "At least one course is required").meta({ description: "Courses available in this app" }),
15305
+ sensor: exports_external.url().meta({ description: "Default Caliper sensor endpoint URL for all courses" }).optional(),
15306
+ launchUrl: exports_external.url().meta({ description: "Default LTI launch URL for all courses" }).optional()
15307
+ }).meta({
15308
+ id: "TimebackConfig",
15309
+ title: "Timeback Config",
15310
+ description: "Configuration schema for timeback.config.json files"
15264
15311
  }).refine((config2) => {
15265
15312
  return config2.courses.every((c) => c.grade !== undefined || c.courseCode !== undefined);
15266
15313
  }, {
@@ -15281,17 +15328,23 @@ var TimebackConfig = exports_external.object({
15281
15328
  message: "Duplicate courseCode found; each must be unique",
15282
15329
  path: ["courses"]
15283
15330
  }).refine((config2) => {
15284
- return config2.courses.every((c) => c.sensor !== undefined || config2.sensor !== undefined);
15285
- }, {
15286
- message: "Each course must have an effective sensor; set a top-level `sensor` or per-course `sensor`",
15287
- path: ["courses"]
15288
- }).refine((config2) => {
15289
- return config2.courses.every((c) => c.launchUrl !== undefined || config2.launchUrl !== undefined);
15331
+ return config2.courses.every((c) => {
15332
+ if (c.sensor !== undefined || config2.sensor !== undefined) {
15333
+ return true;
15334
+ }
15335
+ const launchUrls = [
15336
+ c.launchUrl,
15337
+ config2.launchUrl,
15338
+ c.overrides?.staging?.launchUrl,
15339
+ c.overrides?.production?.launchUrl
15340
+ ].filter(Boolean);
15341
+ return launchUrls.length > 0;
15342
+ });
15290
15343
  }, {
15291
- message: "Each course must have an effective launchUrl; set a top-level `launchUrl` or per-course `launchUrl`",
15344
+ message: "Each course must have an effective sensor. Either set `sensor` explicitly (top-level or per-course), or provide a `launchUrl` so sensor can be derived from its origin.",
15292
15345
  path: ["courses"]
15293
15346
  });
15294
- var EdubridgeDateString = exports_external.union([IsoDateString, IsoDateTimeString]);
15347
+ var EdubridgeDateString = IsoDateTimeString;
15295
15348
  var EduBridgeEnrollment = exports_external.object({
15296
15349
  id: exports_external.string(),
15297
15350
  role: exports_external.string(),
@@ -15355,12 +15408,9 @@ var EmailOrStudentId = exports_external.object({
15355
15408
  });
15356
15409
  var SubjectTrackInput = exports_external.object({
15357
15410
  subject: NonEmptyString,
15358
- gradeLevel: NonEmptyString,
15359
- targetCourseId: NonEmptyString,
15360
- metadata: exports_external.record(exports_external.string(), exports_external.unknown()).optional()
15361
- });
15362
- var SubjectTrackUpsertInput = SubjectTrackInput.extend({
15363
- id: NonEmptyString
15411
+ grade: NonEmptyString,
15412
+ courseId: NonEmptyString,
15413
+ orgSourcedId: NonEmptyString.optional()
15364
15414
  });
15365
15415
  var EdubridgeListEnrollmentsParams = exports_external.object({
15366
15416
  userId: NonEmptyString
@@ -17244,7 +17294,17 @@ class TimebackProvider2 {
17244
17294
  }
17245
17295
  function getEnv2(key) {
17246
17296
  try {
17247
- return typeof process === "undefined" ? undefined : process.env[key];
17297
+ if (typeof process === "undefined")
17298
+ return;
17299
+ if (typeof key === "string") {
17300
+ return process.env[key];
17301
+ }
17302
+ for (const k of key) {
17303
+ const value = process.env[k];
17304
+ if (value !== undefined)
17305
+ return value;
17306
+ }
17307
+ return;
17248
17308
  } catch {
17249
17309
  return;
17250
17310
  }
@@ -17275,6 +17335,18 @@ var DEFAULT_PROVIDER_REGISTRY2 = {
17275
17335
  }
17276
17336
  }
17277
17337
  };
17338
+ function primaryEnvVar2(key) {
17339
+ if (typeof key === "string") {
17340
+ return key;
17341
+ }
17342
+ if (key.length === 0) {
17343
+ throw new Error(`Missing env var key: ${key}`);
17344
+ }
17345
+ return key[0];
17346
+ }
17347
+ function formatEnvVarKey2(key) {
17348
+ return primaryEnvVar2(key);
17349
+ }
17278
17350
  function validateEnv2(env) {
17279
17351
  if (env !== "staging" && env !== "production") {
17280
17352
  throw new Error(`Invalid env "${env}": must be "staging" or "production"`);
@@ -17285,10 +17357,10 @@ function validateAuth2(auth, envVars) {
17285
17357
  const clientId = auth?.clientId ?? getEnv2(envVars.clientId);
17286
17358
  const clientSecret = auth?.clientSecret ?? getEnv2(envVars.clientSecret);
17287
17359
  if (!clientId) {
17288
- throw new Error(`Missing clientId: provide in config or set ${envVars.clientId}`);
17360
+ throw new Error(`Missing clientId: provide in config or set ${formatEnvVarKey2(envVars.clientId)}`);
17289
17361
  }
17290
17362
  if (!clientSecret) {
17291
- throw new Error(`Missing clientSecret: provide in config or set ${envVars.clientSecret}`);
17363
+ throw new Error(`Missing clientSecret: provide in config or set ${formatEnvVarKey2(envVars.clientSecret)}`);
17292
17364
  }
17293
17365
  return { clientId, clientSecret };
17294
17366
  }
@@ -17304,21 +17376,21 @@ function buildMissingEnvError2(envVars) {
17304
17376
  const clientId = getEnv2(envVars.clientId);
17305
17377
  const clientSecret = getEnv2(envVars.clientSecret);
17306
17378
  if (baseUrl === undefined && clientId === undefined) {
17307
- const hint = envVars.env ?? envVars.baseUrl;
17379
+ const hint = formatEnvVarKey2(envVars.env ?? envVars.baseUrl);
17308
17380
  return `Missing env: provide in config or set ${hint}`;
17309
17381
  }
17310
17382
  const missing = [];
17311
17383
  if (baseUrl === undefined) {
17312
- missing.push(envVars.env ?? envVars.baseUrl);
17384
+ missing.push(formatEnvVarKey2(envVars.env ?? envVars.baseUrl));
17313
17385
  }
17314
17386
  if (baseUrl !== undefined && authUrl === undefined) {
17315
- missing.push(envVars.authUrl);
17387
+ missing.push(formatEnvVarKey2(envVars.authUrl));
17316
17388
  }
17317
17389
  if (clientId === undefined) {
17318
- missing.push(envVars.clientId);
17390
+ missing.push(formatEnvVarKey2(envVars.clientId));
17319
17391
  }
17320
17392
  if (clientSecret === undefined) {
17321
- missing.push(envVars.clientSecret);
17393
+ missing.push(formatEnvVarKey2(envVars.clientSecret));
17322
17394
  }
17323
17395
  return `Missing environment variables: ${missing.join(", ")}`;
17324
17396
  }
@@ -17809,10 +17881,10 @@ function validateNonEmptyString2(value, name) {
17809
17881
  }
17810
17882
  }
17811
17883
  var EDUBRIDGE_ENV_VARS = {
17812
- baseUrl: "EDUBRIDGE_BASE_URL",
17813
- clientId: "EDUBRIDGE_CLIENT_ID",
17814
- clientSecret: "EDUBRIDGE_CLIENT_SECRET",
17815
- authUrl: "EDUBRIDGE_TOKEN_URL"
17884
+ baseUrl: ["TIMEBACK_API_BASE_URL", "TIMEBACK_BASE_URL", "EDUBRIDGE_BASE_URL"],
17885
+ clientId: ["TIMEBACK_API_CLIENT_ID", "TIMEBACK_CLIENT_ID", "EDUBRIDGE_CLIENT_ID"],
17886
+ clientSecret: ["TIMEBACK_API_CLIENT_SECRET", "TIMEBACK_CLIENT_SECRET", "EDUBRIDGE_CLIENT_SECRET"],
17887
+ authUrl: ["TIMEBACK_API_AUTH_URL", "TIMEBACK_AUTH_URL", "EDUBRIDGE_TOKEN_URL"]
17816
17888
  };
17817
17889
  function resolveToProvider22(config2, registry2 = DEFAULT_PROVIDER_REGISTRY2) {
17818
17890
  return resolveToProvider3(config2, EDUBRIDGE_ENV_VARS, registry2);
@@ -20140,7 +20212,7 @@ class Doc2 {
20140
20212
  var version2 = {
20141
20213
  major: 4,
20142
20214
  minor: 3,
20143
- patch: 5
20215
+ patch: 6
20144
20216
  };
20145
20217
  var $ZodType2 = /* @__PURE__ */ $constructor2("$ZodType", (inst, def) => {
20146
20218
  var _a2;
@@ -21424,7 +21496,7 @@ var $ZodRecord2 = /* @__PURE__ */ $constructor2("$ZodRecord", (inst, def) => {
21424
21496
  if (keyResult instanceof Promise) {
21425
21497
  throw new Error("Async schemas not supported in object keys currently");
21426
21498
  }
21427
- const checkNumericKey = typeof key === "string" && number4.test(key) && keyResult.issues.length && keyResult.issues.some((iss) => iss.code === "invalid_type" && iss.expected === "number");
21499
+ const checkNumericKey = typeof key === "string" && number4.test(key) && keyResult.issues.length;
21428
21500
  if (checkNumericKey) {
21429
21501
  const retryResult = def.keyType._zod.run({ value: Number(key), issues: [] }, ctx);
21430
21502
  if (retryResult instanceof Promise) {
@@ -28741,7 +28813,7 @@ function finalize2(ctx, schema) {
28741
28813
  }
28742
28814
  }
28743
28815
  }
28744
- if (refSchema.$ref) {
28816
+ if (refSchema.$ref && refSeen.def) {
28745
28817
  for (const key in schema2) {
28746
28818
  if (key === "$ref" || key === "allOf")
28747
28819
  continue;
@@ -31373,7 +31445,7 @@ var TimebackSubject2 = exports_external2.enum([
31373
31445
  "Math",
31374
31446
  "None",
31375
31447
  "Other"
31376
- ]);
31448
+ ]).meta({ id: "TimebackSubject", description: "Subject area" });
31377
31449
  var TimebackGrade2 = exports_external2.union([
31378
31450
  exports_external2.literal(-1),
31379
31451
  exports_external2.literal(0),
@@ -31390,7 +31462,10 @@ var TimebackGrade2 = exports_external2.union([
31390
31462
  exports_external2.literal(11),
31391
31463
  exports_external2.literal(12),
31392
31464
  exports_external2.literal(13)
31393
- ]);
31465
+ ]).meta({
31466
+ id: "TimebackGrade",
31467
+ description: "Grade level (-1 = Pre-K, 0 = K, 1-12 = grades, 13 = AP)"
31468
+ });
31394
31469
  var ScoreStatus2 = exports_external2.enum([
31395
31470
  "exempt",
31396
31471
  "fully graded",
@@ -31620,62 +31695,84 @@ var CaliperListEventsParams2 = exports_external2.object({
31620
31695
  actorEmail: exports_external2.email().optional()
31621
31696
  }).strict();
31622
31697
  var CourseIds2 = exports_external2.object({
31623
- staging: exports_external2.string().optional(),
31624
- production: exports_external2.string().optional()
31625
- });
31626
- var CourseType2 = exports_external2.enum(["base", "hole-filling", "optional"]);
31627
- var PublishStatus2 = exports_external2.enum(["draft", "testing", "published", "deactivated"]);
31698
+ staging: exports_external2.string().meta({ description: "Course ID in staging environment" }).optional(),
31699
+ production: exports_external2.string().meta({ description: "Course ID in production environment" }).optional()
31700
+ }).meta({ id: "CourseIds", description: "Environment-specific course IDs (populated by sync)" });
31701
+ var CourseType2 = exports_external2.enum(["base", "hole-filling", "optional"]).meta({ id: "CourseType", description: "Course classification type" });
31702
+ var PublishStatus2 = exports_external2.enum(["draft", "testing", "published", "deactivated"]).meta({ id: "PublishStatus", description: "Course publication status" });
31628
31703
  var CourseGoals2 = exports_external2.object({
31629
- dailyXp: exports_external2.number().int().positive().optional(),
31630
- dailyLessons: exports_external2.number().int().positive().optional(),
31631
- dailyActiveMinutes: exports_external2.number().int().positive().optional(),
31632
- dailyAccuracy: exports_external2.number().int().min(0).max(100).optional(),
31633
- dailyMasteredUnits: exports_external2.number().int().positive().optional()
31634
- });
31704
+ dailyXp: exports_external2.number().int().positive().meta({ description: "Target XP to earn per day" }).optional(),
31705
+ dailyLessons: exports_external2.number().int().positive().meta({ description: "Target lessons to complete per day" }).optional(),
31706
+ dailyActiveMinutes: exports_external2.number().int().positive().meta({ description: "Target active learning minutes per day" }).optional(),
31707
+ dailyAccuracy: exports_external2.number().int().min(0).max(100).meta({ description: "Target accuracy percentage (0-100)" }).optional(),
31708
+ dailyMasteredUnits: exports_external2.number().int().positive().meta({ description: "Target units to master per day" }).optional()
31709
+ }).meta({ id: "CourseGoals", description: "Daily learning goals for a course" });
31635
31710
  var CourseMetrics2 = exports_external2.object({
31636
- totalXp: exports_external2.number().int().positive().optional(),
31637
- totalLessons: exports_external2.number().int().positive().optional(),
31638
- totalGrades: exports_external2.number().int().positive().optional()
31639
- });
31711
+ totalXp: exports_external2.number().int().positive().meta({ description: "Total XP available in the course" }).optional(),
31712
+ totalLessons: exports_external2.number().int().positive().meta({ description: "Total number of lessons/activities" }).optional(),
31713
+ totalGrades: exports_external2.number().int().positive().meta({ description: "Total grade levels covered" }).optional()
31714
+ }).meta({ id: "CourseMetrics", description: "Aggregate metrics for a course" });
31640
31715
  var CourseMetadata2 = exports_external2.object({
31641
31716
  courseType: CourseType2.optional(),
31642
- isSupplemental: exports_external2.boolean().optional(),
31643
- isCustom: exports_external2.boolean().optional(),
31717
+ isSupplemental: exports_external2.boolean().meta({ description: "Whether this is supplemental to a base course" }).optional(),
31718
+ isCustom: exports_external2.boolean().meta({ description: "Whether this is a custom course for an individual student" }).optional(),
31644
31719
  publishStatus: PublishStatus2.optional(),
31645
- contactEmail: exports_external2.email().optional(),
31646
- primaryApp: exports_external2.string().optional(),
31720
+ contactEmail: exports_external2.email().meta({ description: "Contact email for course issues" }).optional(),
31721
+ primaryApp: exports_external2.string().meta({ description: "Primary application identifier" }).optional(),
31647
31722
  goals: CourseGoals2.optional(),
31648
31723
  metrics: CourseMetrics2.optional()
31649
- });
31724
+ }).meta({ id: "CourseMetadata", description: "Course metadata (matches API metadata object)" });
31650
31725
  var CourseDefaults2 = exports_external2.object({
31651
- courseCode: exports_external2.string().optional(),
31652
- level: exports_external2.string().optional(),
31726
+ courseCode: exports_external2.string().meta({ description: "Course code (e.g., 'MATH101')" }).optional(),
31727
+ level: exports_external2.string().meta({ description: "Course level (e.g., 'AP', 'Honors')" }).optional(),
31653
31728
  metadata: CourseMetadata2.optional()
31729
+ }).meta({
31730
+ id: "CourseDefaults",
31731
+ description: "Default properties that apply to all courses unless overridden"
31654
31732
  });
31655
31733
  var CourseEnvOverrides2 = exports_external2.object({
31656
- level: exports_external2.string().optional(),
31657
- sensor: exports_external2.string().url().optional(),
31658
- launchUrl: exports_external2.string().url().optional(),
31734
+ level: exports_external2.string().meta({ description: "Course level for this environment" }).optional(),
31735
+ sensor: exports_external2.url().meta({ description: "Caliper sensor endpoint URL for this environment" }).optional(),
31736
+ launchUrl: exports_external2.url().meta({ description: "LTI launch URL for this environment" }).optional(),
31659
31737
  metadata: CourseMetadata2.optional()
31738
+ }).meta({
31739
+ id: "CourseEnvOverrides",
31740
+ description: "Environment-specific course overrides (non-identity fields)"
31660
31741
  });
31661
31742
  var CourseOverrides2 = exports_external2.object({
31662
- staging: CourseEnvOverrides2.optional(),
31663
- production: CourseEnvOverrides2.optional()
31664
- });
31743
+ staging: CourseEnvOverrides2.meta({
31744
+ description: "Overrides for staging environment"
31745
+ }).optional(),
31746
+ production: CourseEnvOverrides2.meta({
31747
+ description: "Overrides for production environment"
31748
+ }).optional()
31749
+ }).meta({ id: "CourseOverrides", description: "Per-environment course overrides" });
31665
31750
  var CourseConfig2 = CourseDefaults2.extend({
31666
- subject: TimebackSubject2,
31667
- grade: TimebackGrade2.optional(),
31751
+ subject: TimebackSubject2.meta({ description: "Subject area for this course" }),
31752
+ grade: TimebackGrade2.meta({
31753
+ description: "Grade level (-1 = Pre-K, 0 = K, 1-12 = grades, 13 = AP)"
31754
+ }).optional(),
31668
31755
  ids: CourseIds2.nullable().optional(),
31669
- sensor: exports_external2.string().url().optional(),
31670
- launchUrl: exports_external2.string().url().optional(),
31756
+ sensor: exports_external2.url().meta({ description: "Caliper sensor endpoint URL for this course" }).optional(),
31757
+ launchUrl: exports_external2.url().meta({ description: "LTI launch URL for this course" }).optional(),
31671
31758
  overrides: CourseOverrides2.optional()
31759
+ }).meta({
31760
+ id: "CourseConfig",
31761
+ description: "Configuration for a single course. Must have either grade or courseCode (or both)."
31672
31762
  });
31673
31763
  var TimebackConfig2 = exports_external2.object({
31674
- name: exports_external2.string().min(1, "App name is required"),
31675
- defaults: CourseDefaults2.optional(),
31676
- courses: exports_external2.array(CourseConfig2).min(1, "At least one course is required"),
31677
- sensor: exports_external2.string().url().optional(),
31678
- launchUrl: exports_external2.string().url().optional()
31764
+ $schema: exports_external2.string().meta({ description: "JSON Schema reference for editor support" }).optional(),
31765
+ name: exports_external2.string().min(1, "App name is required").meta({ description: "Display name for your app" }),
31766
+ defaults: CourseDefaults2.meta({
31767
+ description: "Default properties applied to all courses"
31768
+ }).optional(),
31769
+ courses: exports_external2.array(CourseConfig2).min(1, "At least one course is required").meta({ description: "Courses available in this app" }),
31770
+ sensor: exports_external2.url().meta({ description: "Default Caliper sensor endpoint URL for all courses" }).optional(),
31771
+ launchUrl: exports_external2.url().meta({ description: "Default LTI launch URL for all courses" }).optional()
31772
+ }).meta({
31773
+ id: "TimebackConfig",
31774
+ title: "Timeback Config",
31775
+ description: "Configuration schema for timeback.config.json files"
31679
31776
  }).refine((config22) => {
31680
31777
  return config22.courses.every((c) => c.grade !== undefined || c.courseCode !== undefined);
31681
31778
  }, {
@@ -31696,17 +31793,23 @@ var TimebackConfig2 = exports_external2.object({
31696
31793
  message: "Duplicate courseCode found; each must be unique",
31697
31794
  path: ["courses"]
31698
31795
  }).refine((config22) => {
31699
- return config22.courses.every((c) => c.sensor !== undefined || config22.sensor !== undefined);
31700
- }, {
31701
- message: "Each course must have an effective sensor; set a top-level `sensor` or per-course `sensor`",
31702
- path: ["courses"]
31703
- }).refine((config22) => {
31704
- return config22.courses.every((c) => c.launchUrl !== undefined || config22.launchUrl !== undefined);
31796
+ return config22.courses.every((c) => {
31797
+ if (c.sensor !== undefined || config22.sensor !== undefined) {
31798
+ return true;
31799
+ }
31800
+ const launchUrls = [
31801
+ c.launchUrl,
31802
+ config22.launchUrl,
31803
+ c.overrides?.staging?.launchUrl,
31804
+ c.overrides?.production?.launchUrl
31805
+ ].filter(Boolean);
31806
+ return launchUrls.length > 0;
31807
+ });
31705
31808
  }, {
31706
- message: "Each course must have an effective launchUrl; set a top-level `launchUrl` or per-course `launchUrl`",
31809
+ message: "Each course must have an effective sensor. Either set `sensor` explicitly (top-level or per-course), or provide a `launchUrl` so sensor can be derived from its origin.",
31707
31810
  path: ["courses"]
31708
31811
  });
31709
- var EdubridgeDateString2 = exports_external2.union([IsoDateString2, IsoDateTimeString2]);
31812
+ var EdubridgeDateString2 = IsoDateTimeString2;
31710
31813
  var EduBridgeEnrollment2 = exports_external2.object({
31711
31814
  id: exports_external2.string(),
31712
31815
  role: exports_external2.string(),
@@ -31770,13 +31873,11 @@ var EmailOrStudentId2 = exports_external2.object({
31770
31873
  });
31771
31874
  var SubjectTrackInput2 = exports_external2.object({
31772
31875
  subject: NonEmptyString4,
31773
- gradeLevel: NonEmptyString4,
31774
- targetCourseId: NonEmptyString4,
31775
- metadata: exports_external2.record(exports_external2.string(), exports_external2.unknown()).optional()
31776
- });
31777
- var SubjectTrackUpsertInput2 = SubjectTrackInput2.extend({
31778
- id: NonEmptyString4
31876
+ grade: NonEmptyString4,
31877
+ courseId: NonEmptyString4,
31878
+ orgSourcedId: NonEmptyString4.optional()
31779
31879
  });
31880
+ var SubjectTrackUpsertInput = SubjectTrackInput2;
31780
31881
  var EdubridgeListEnrollmentsParams2 = exports_external2.object({
31781
31882
  userId: NonEmptyString4
31782
31883
  });
@@ -32834,7 +32935,7 @@ class SubjectTrackResource {
32834
32935
  return response.subjectTrack;
32835
32936
  }
32836
32937
  async upsert(data) {
32837
- validateWithSchema2(SubjectTrackUpsertInput2, data, "subject track");
32938
+ validateWithSchema2(SubjectTrackUpsertInput, data, "subject track");
32838
32939
  const response = await this.transport.request(`${this.transport.paths.base}/subject-track/`, { method: "PUT", body: data });
32839
32940
  return response.subjectTrack;
32840
32941
  }
@@ -33625,7 +33726,17 @@ class TimebackProvider3 {
33625
33726
  // ../../internal/client-infra/src/utils/utils.ts
33626
33727
  function getEnv3(key) {
33627
33728
  try {
33628
- return typeof process === "undefined" ? undefined : process.env[key];
33729
+ if (typeof process === "undefined")
33730
+ return;
33731
+ if (typeof key === "string") {
33732
+ return process.env[key];
33733
+ }
33734
+ for (const k of key) {
33735
+ const value = process.env[k];
33736
+ if (value !== undefined)
33737
+ return value;
33738
+ }
33739
+ return;
33629
33740
  } catch {
33630
33741
  return;
33631
33742
  }
@@ -33646,6 +33757,18 @@ var DEFAULT_PROVIDER_REGISTRY3 = {
33646
33757
  };
33647
33758
 
33648
33759
  // ../../internal/client-infra/src/config/resolve.ts
33760
+ function primaryEnvVar3(key) {
33761
+ if (typeof key === "string") {
33762
+ return key;
33763
+ }
33764
+ if (key.length === 0) {
33765
+ throw new Error(`Missing env var key: ${key}`);
33766
+ }
33767
+ return key[0];
33768
+ }
33769
+ function formatEnvVarKey3(key) {
33770
+ return primaryEnvVar3(key);
33771
+ }
33649
33772
  function validateEnv3(env) {
33650
33773
  if (env !== "staging" && env !== "production") {
33651
33774
  throw new Error(`Invalid env "${env}": must be "staging" or "production"`);
@@ -33656,10 +33779,10 @@ function validateAuth3(auth, envVars) {
33656
33779
  const clientId = auth?.clientId ?? getEnv3(envVars.clientId);
33657
33780
  const clientSecret = auth?.clientSecret ?? getEnv3(envVars.clientSecret);
33658
33781
  if (!clientId) {
33659
- throw new Error(`Missing clientId: provide in config or set ${envVars.clientId}`);
33782
+ throw new Error(`Missing clientId: provide in config or set ${formatEnvVarKey3(envVars.clientId)}`);
33660
33783
  }
33661
33784
  if (!clientSecret) {
33662
- throw new Error(`Missing clientSecret: provide in config or set ${envVars.clientSecret}`);
33785
+ throw new Error(`Missing clientSecret: provide in config or set ${formatEnvVarKey3(envVars.clientSecret)}`);
33663
33786
  }
33664
33787
  return { clientId, clientSecret };
33665
33788
  }
@@ -33675,21 +33798,21 @@ function buildMissingEnvError3(envVars) {
33675
33798
  const clientId = getEnv3(envVars.clientId);
33676
33799
  const clientSecret = getEnv3(envVars.clientSecret);
33677
33800
  if (baseUrl === undefined && clientId === undefined) {
33678
- const hint = envVars.env ?? envVars.baseUrl;
33801
+ const hint = formatEnvVarKey3(envVars.env ?? envVars.baseUrl);
33679
33802
  return `Missing env: provide in config or set ${hint}`;
33680
33803
  }
33681
33804
  const missing = [];
33682
33805
  if (baseUrl === undefined) {
33683
- missing.push(envVars.env ?? envVars.baseUrl);
33806
+ missing.push(formatEnvVarKey3(envVars.env ?? envVars.baseUrl));
33684
33807
  }
33685
33808
  if (baseUrl !== undefined && authUrl === undefined) {
33686
- missing.push(envVars.authUrl);
33809
+ missing.push(formatEnvVarKey3(envVars.authUrl));
33687
33810
  }
33688
33811
  if (clientId === undefined) {
33689
- missing.push(envVars.clientId);
33812
+ missing.push(formatEnvVarKey3(envVars.clientId));
33690
33813
  }
33691
33814
  if (clientSecret === undefined) {
33692
- missing.push(envVars.clientSecret);
33815
+ missing.push(formatEnvVarKey3(envVars.clientSecret));
33693
33816
  }
33694
33817
  return `Missing environment variables: ${missing.join(", ")}`;
33695
33818
  }
@@ -34651,7 +34774,17 @@ class TimebackProvider4 {
34651
34774
  }
34652
34775
  function getEnv4(key) {
34653
34776
  try {
34654
- return typeof process === "undefined" ? undefined : process.env[key];
34777
+ if (typeof process === "undefined")
34778
+ return;
34779
+ if (typeof key === "string") {
34780
+ return process.env[key];
34781
+ }
34782
+ for (const k of key) {
34783
+ const value = process.env[k];
34784
+ if (value !== undefined)
34785
+ return value;
34786
+ }
34787
+ return;
34655
34788
  } catch {
34656
34789
  return;
34657
34790
  }
@@ -34682,6 +34815,18 @@ var DEFAULT_PROVIDER_REGISTRY4 = {
34682
34815
  }
34683
34816
  }
34684
34817
  };
34818
+ function primaryEnvVar4(key) {
34819
+ if (typeof key === "string") {
34820
+ return key;
34821
+ }
34822
+ if (key.length === 0) {
34823
+ throw new Error(`Missing env var key: ${key}`);
34824
+ }
34825
+ return key[0];
34826
+ }
34827
+ function formatEnvVarKey4(key) {
34828
+ return primaryEnvVar4(key);
34829
+ }
34685
34830
  function validateEnv4(env) {
34686
34831
  if (env !== "staging" && env !== "production") {
34687
34832
  throw new Error(`Invalid env "${env}": must be "staging" or "production"`);
@@ -34692,10 +34837,10 @@ function validateAuth4(auth, envVars) {
34692
34837
  const clientId = auth?.clientId ?? getEnv4(envVars.clientId);
34693
34838
  const clientSecret = auth?.clientSecret ?? getEnv4(envVars.clientSecret);
34694
34839
  if (!clientId) {
34695
- throw new Error(`Missing clientId: provide in config or set ${envVars.clientId}`);
34840
+ throw new Error(`Missing clientId: provide in config or set ${formatEnvVarKey4(envVars.clientId)}`);
34696
34841
  }
34697
34842
  if (!clientSecret) {
34698
- throw new Error(`Missing clientSecret: provide in config or set ${envVars.clientSecret}`);
34843
+ throw new Error(`Missing clientSecret: provide in config or set ${formatEnvVarKey4(envVars.clientSecret)}`);
34699
34844
  }
34700
34845
  return { clientId, clientSecret };
34701
34846
  }
@@ -34711,21 +34856,21 @@ function buildMissingEnvError4(envVars) {
34711
34856
  const clientId = getEnv4(envVars.clientId);
34712
34857
  const clientSecret = getEnv4(envVars.clientSecret);
34713
34858
  if (baseUrl === undefined && clientId === undefined) {
34714
- const hint = envVars.env ?? envVars.baseUrl;
34859
+ const hint = formatEnvVarKey4(envVars.env ?? envVars.baseUrl);
34715
34860
  return `Missing env: provide in config or set ${hint}`;
34716
34861
  }
34717
34862
  const missing = [];
34718
34863
  if (baseUrl === undefined) {
34719
- missing.push(envVars.env ?? envVars.baseUrl);
34864
+ missing.push(formatEnvVarKey4(envVars.env ?? envVars.baseUrl));
34720
34865
  }
34721
34866
  if (baseUrl !== undefined && authUrl === undefined) {
34722
- missing.push(envVars.authUrl);
34867
+ missing.push(formatEnvVarKey4(envVars.authUrl));
34723
34868
  }
34724
34869
  if (clientId === undefined) {
34725
- missing.push(envVars.clientId);
34870
+ missing.push(formatEnvVarKey4(envVars.clientId));
34726
34871
  }
34727
34872
  if (clientSecret === undefined) {
34728
- missing.push(envVars.clientSecret);
34873
+ missing.push(formatEnvVarKey4(envVars.clientSecret));
34729
34874
  }
34730
34875
  return `Missing environment variables: ${missing.join(", ")}`;
34731
34876
  }
@@ -35441,10 +35586,10 @@ function validateSourcedId2(sourcedId, context) {
35441
35586
  }
35442
35587
  }
35443
35588
  var ONEROSTER_ENV_VARS = {
35444
- baseUrl: "ONEROSTER_BASE_URL",
35445
- clientId: "ONEROSTER_CLIENT_ID",
35446
- clientSecret: "ONEROSTER_CLIENT_SECRET",
35447
- authUrl: "ONEROSTER_TOKEN_URL"
35589
+ baseUrl: ["TIMEBACK_API_BASE_URL", "TIMEBACK_BASE_URL", "ONEROSTER_BASE_URL"],
35590
+ clientId: ["TIMEBACK_API_CLIENT_ID", "TIMEBACK_CLIENT_ID", "ONEROSTER_CLIENT_ID"],
35591
+ clientSecret: ["TIMEBACK_API_CLIENT_SECRET", "TIMEBACK_CLIENT_SECRET", "ONEROSTER_CLIENT_SECRET"],
35592
+ authUrl: ["TIMEBACK_API_AUTH_URL", "TIMEBACK_AUTH_URL", "ONEROSTER_TOKEN_URL"]
35448
35593
  };
35449
35594
  function resolveToProvider23(config3, registry3 = DEFAULT_PROVIDER_REGISTRY4) {
35450
35595
  return resolveToProvider6(config3, ONEROSTER_ENV_VARS, registry3);
@@ -37699,7 +37844,7 @@ class Doc3 {
37699
37844
  var version3 = {
37700
37845
  major: 4,
37701
37846
  minor: 3,
37702
- patch: 5
37847
+ patch: 6
37703
37848
  };
37704
37849
  var $ZodType3 = /* @__PURE__ */ $constructor3("$ZodType", (inst, def) => {
37705
37850
  var _a3;
@@ -38983,7 +39128,7 @@ var $ZodRecord3 = /* @__PURE__ */ $constructor3("$ZodRecord", (inst, def) => {
38983
39128
  if (keyResult instanceof Promise) {
38984
39129
  throw new Error("Async schemas not supported in object keys currently");
38985
39130
  }
38986
- const checkNumericKey = typeof key === "string" && number6.test(key) && keyResult.issues.length && keyResult.issues.some((iss) => iss.code === "invalid_type" && iss.expected === "number");
39131
+ const checkNumericKey = typeof key === "string" && number6.test(key) && keyResult.issues.length;
38987
39132
  if (checkNumericKey) {
38988
39133
  const retryResult = def.keyType._zod.run({ value: Number(key), issues: [] }, ctx);
38989
39134
  if (retryResult instanceof Promise) {
@@ -46300,7 +46445,7 @@ function finalize3(ctx, schema) {
46300
46445
  }
46301
46446
  }
46302
46447
  }
46303
- if (refSchema.$ref) {
46448
+ if (refSchema.$ref && refSeen.def) {
46304
46449
  for (const key in schema2) {
46305
46450
  if (key === "$ref" || key === "allOf")
46306
46451
  continue;
@@ -48932,7 +49077,7 @@ var TimebackSubject3 = exports_external3.enum([
48932
49077
  "Math",
48933
49078
  "None",
48934
49079
  "Other"
48935
- ]);
49080
+ ]).meta({ id: "TimebackSubject", description: "Subject area" });
48936
49081
  var TimebackGrade3 = exports_external3.union([
48937
49082
  exports_external3.literal(-1),
48938
49083
  exports_external3.literal(0),
@@ -48949,7 +49094,10 @@ var TimebackGrade3 = exports_external3.union([
48949
49094
  exports_external3.literal(11),
48950
49095
  exports_external3.literal(12),
48951
49096
  exports_external3.literal(13)
48952
- ]);
49097
+ ]).meta({
49098
+ id: "TimebackGrade",
49099
+ description: "Grade level (-1 = Pre-K, 0 = K, 1-12 = grades, 13 = AP)"
49100
+ });
48953
49101
  var ScoreStatus3 = exports_external3.enum([
48954
49102
  "exempt",
48955
49103
  "fully graded",
@@ -49179,62 +49327,84 @@ var CaliperListEventsParams3 = exports_external3.object({
49179
49327
  actorEmail: exports_external3.email().optional()
49180
49328
  }).strict();
49181
49329
  var CourseIds3 = exports_external3.object({
49182
- staging: exports_external3.string().optional(),
49183
- production: exports_external3.string().optional()
49184
- });
49185
- var CourseType3 = exports_external3.enum(["base", "hole-filling", "optional"]);
49186
- var PublishStatus3 = exports_external3.enum(["draft", "testing", "published", "deactivated"]);
49330
+ staging: exports_external3.string().meta({ description: "Course ID in staging environment" }).optional(),
49331
+ production: exports_external3.string().meta({ description: "Course ID in production environment" }).optional()
49332
+ }).meta({ id: "CourseIds", description: "Environment-specific course IDs (populated by sync)" });
49333
+ var CourseType3 = exports_external3.enum(["base", "hole-filling", "optional"]).meta({ id: "CourseType", description: "Course classification type" });
49334
+ var PublishStatus3 = exports_external3.enum(["draft", "testing", "published", "deactivated"]).meta({ id: "PublishStatus", description: "Course publication status" });
49187
49335
  var CourseGoals3 = exports_external3.object({
49188
- dailyXp: exports_external3.number().int().positive().optional(),
49189
- dailyLessons: exports_external3.number().int().positive().optional(),
49190
- dailyActiveMinutes: exports_external3.number().int().positive().optional(),
49191
- dailyAccuracy: exports_external3.number().int().min(0).max(100).optional(),
49192
- dailyMasteredUnits: exports_external3.number().int().positive().optional()
49193
- });
49336
+ dailyXp: exports_external3.number().int().positive().meta({ description: "Target XP to earn per day" }).optional(),
49337
+ dailyLessons: exports_external3.number().int().positive().meta({ description: "Target lessons to complete per day" }).optional(),
49338
+ dailyActiveMinutes: exports_external3.number().int().positive().meta({ description: "Target active learning minutes per day" }).optional(),
49339
+ dailyAccuracy: exports_external3.number().int().min(0).max(100).meta({ description: "Target accuracy percentage (0-100)" }).optional(),
49340
+ dailyMasteredUnits: exports_external3.number().int().positive().meta({ description: "Target units to master per day" }).optional()
49341
+ }).meta({ id: "CourseGoals", description: "Daily learning goals for a course" });
49194
49342
  var CourseMetrics3 = exports_external3.object({
49195
- totalXp: exports_external3.number().int().positive().optional(),
49196
- totalLessons: exports_external3.number().int().positive().optional(),
49197
- totalGrades: exports_external3.number().int().positive().optional()
49198
- });
49343
+ totalXp: exports_external3.number().int().positive().meta({ description: "Total XP available in the course" }).optional(),
49344
+ totalLessons: exports_external3.number().int().positive().meta({ description: "Total number of lessons/activities" }).optional(),
49345
+ totalGrades: exports_external3.number().int().positive().meta({ description: "Total grade levels covered" }).optional()
49346
+ }).meta({ id: "CourseMetrics", description: "Aggregate metrics for a course" });
49199
49347
  var CourseMetadata3 = exports_external3.object({
49200
49348
  courseType: CourseType3.optional(),
49201
- isSupplemental: exports_external3.boolean().optional(),
49202
- isCustom: exports_external3.boolean().optional(),
49349
+ isSupplemental: exports_external3.boolean().meta({ description: "Whether this is supplemental to a base course" }).optional(),
49350
+ isCustom: exports_external3.boolean().meta({ description: "Whether this is a custom course for an individual student" }).optional(),
49203
49351
  publishStatus: PublishStatus3.optional(),
49204
- contactEmail: exports_external3.email().optional(),
49205
- primaryApp: exports_external3.string().optional(),
49352
+ contactEmail: exports_external3.email().meta({ description: "Contact email for course issues" }).optional(),
49353
+ primaryApp: exports_external3.string().meta({ description: "Primary application identifier" }).optional(),
49206
49354
  goals: CourseGoals3.optional(),
49207
49355
  metrics: CourseMetrics3.optional()
49208
- });
49356
+ }).meta({ id: "CourseMetadata", description: "Course metadata (matches API metadata object)" });
49209
49357
  var CourseDefaults3 = exports_external3.object({
49210
- courseCode: exports_external3.string().optional(),
49211
- level: exports_external3.string().optional(),
49358
+ courseCode: exports_external3.string().meta({ description: "Course code (e.g., 'MATH101')" }).optional(),
49359
+ level: exports_external3.string().meta({ description: "Course level (e.g., 'AP', 'Honors')" }).optional(),
49212
49360
  metadata: CourseMetadata3.optional()
49361
+ }).meta({
49362
+ id: "CourseDefaults",
49363
+ description: "Default properties that apply to all courses unless overridden"
49213
49364
  });
49214
49365
  var CourseEnvOverrides3 = exports_external3.object({
49215
- level: exports_external3.string().optional(),
49216
- sensor: exports_external3.string().url().optional(),
49217
- launchUrl: exports_external3.string().url().optional(),
49366
+ level: exports_external3.string().meta({ description: "Course level for this environment" }).optional(),
49367
+ sensor: exports_external3.url().meta({ description: "Caliper sensor endpoint URL for this environment" }).optional(),
49368
+ launchUrl: exports_external3.url().meta({ description: "LTI launch URL for this environment" }).optional(),
49218
49369
  metadata: CourseMetadata3.optional()
49370
+ }).meta({
49371
+ id: "CourseEnvOverrides",
49372
+ description: "Environment-specific course overrides (non-identity fields)"
49219
49373
  });
49220
49374
  var CourseOverrides3 = exports_external3.object({
49221
- staging: CourseEnvOverrides3.optional(),
49222
- production: CourseEnvOverrides3.optional()
49223
- });
49375
+ staging: CourseEnvOverrides3.meta({
49376
+ description: "Overrides for staging environment"
49377
+ }).optional(),
49378
+ production: CourseEnvOverrides3.meta({
49379
+ description: "Overrides for production environment"
49380
+ }).optional()
49381
+ }).meta({ id: "CourseOverrides", description: "Per-environment course overrides" });
49224
49382
  var CourseConfig3 = CourseDefaults3.extend({
49225
- subject: TimebackSubject3,
49226
- grade: TimebackGrade3.optional(),
49383
+ subject: TimebackSubject3.meta({ description: "Subject area for this course" }),
49384
+ grade: TimebackGrade3.meta({
49385
+ description: "Grade level (-1 = Pre-K, 0 = K, 1-12 = grades, 13 = AP)"
49386
+ }).optional(),
49227
49387
  ids: CourseIds3.nullable().optional(),
49228
- sensor: exports_external3.string().url().optional(),
49229
- launchUrl: exports_external3.string().url().optional(),
49388
+ sensor: exports_external3.url().meta({ description: "Caliper sensor endpoint URL for this course" }).optional(),
49389
+ launchUrl: exports_external3.url().meta({ description: "LTI launch URL for this course" }).optional(),
49230
49390
  overrides: CourseOverrides3.optional()
49391
+ }).meta({
49392
+ id: "CourseConfig",
49393
+ description: "Configuration for a single course. Must have either grade or courseCode (or both)."
49231
49394
  });
49232
49395
  var TimebackConfig3 = exports_external3.object({
49233
- name: exports_external3.string().min(1, "App name is required"),
49234
- defaults: CourseDefaults3.optional(),
49235
- courses: exports_external3.array(CourseConfig3).min(1, "At least one course is required"),
49236
- sensor: exports_external3.string().url().optional(),
49237
- launchUrl: exports_external3.string().url().optional()
49396
+ $schema: exports_external3.string().meta({ description: "JSON Schema reference for editor support" }).optional(),
49397
+ name: exports_external3.string().min(1, "App name is required").meta({ description: "Display name for your app" }),
49398
+ defaults: CourseDefaults3.meta({
49399
+ description: "Default properties applied to all courses"
49400
+ }).optional(),
49401
+ courses: exports_external3.array(CourseConfig3).min(1, "At least one course is required").meta({ description: "Courses available in this app" }),
49402
+ sensor: exports_external3.url().meta({ description: "Default Caliper sensor endpoint URL for all courses" }).optional(),
49403
+ launchUrl: exports_external3.url().meta({ description: "Default LTI launch URL for all courses" }).optional()
49404
+ }).meta({
49405
+ id: "TimebackConfig",
49406
+ title: "Timeback Config",
49407
+ description: "Configuration schema for timeback.config.json files"
49238
49408
  }).refine((config22) => {
49239
49409
  return config22.courses.every((c) => c.grade !== undefined || c.courseCode !== undefined);
49240
49410
  }, {
@@ -49255,17 +49425,23 @@ var TimebackConfig3 = exports_external3.object({
49255
49425
  message: "Duplicate courseCode found; each must be unique",
49256
49426
  path: ["courses"]
49257
49427
  }).refine((config22) => {
49258
- return config22.courses.every((c) => c.sensor !== undefined || config22.sensor !== undefined);
49259
- }, {
49260
- message: "Each course must have an effective sensor; set a top-level `sensor` or per-course `sensor`",
49261
- path: ["courses"]
49262
- }).refine((config22) => {
49263
- return config22.courses.every((c) => c.launchUrl !== undefined || config22.launchUrl !== undefined);
49428
+ return config22.courses.every((c) => {
49429
+ if (c.sensor !== undefined || config22.sensor !== undefined) {
49430
+ return true;
49431
+ }
49432
+ const launchUrls = [
49433
+ c.launchUrl,
49434
+ config22.launchUrl,
49435
+ c.overrides?.staging?.launchUrl,
49436
+ c.overrides?.production?.launchUrl
49437
+ ].filter(Boolean);
49438
+ return launchUrls.length > 0;
49439
+ });
49264
49440
  }, {
49265
- message: "Each course must have an effective launchUrl; set a top-level `launchUrl` or per-course `launchUrl`",
49441
+ message: "Each course must have an effective sensor. Either set `sensor` explicitly (top-level or per-course), or provide a `launchUrl` so sensor can be derived from its origin.",
49266
49442
  path: ["courses"]
49267
49443
  });
49268
- var EdubridgeDateString3 = exports_external3.union([IsoDateString3, IsoDateTimeString3]);
49444
+ var EdubridgeDateString3 = IsoDateTimeString3;
49269
49445
  var EduBridgeEnrollment3 = exports_external3.object({
49270
49446
  id: exports_external3.string(),
49271
49447
  role: exports_external3.string(),
@@ -49329,12 +49505,9 @@ var EmailOrStudentId3 = exports_external3.object({
49329
49505
  });
49330
49506
  var SubjectTrackInput3 = exports_external3.object({
49331
49507
  subject: NonEmptyString6,
49332
- gradeLevel: NonEmptyString6,
49333
- targetCourseId: NonEmptyString6,
49334
- metadata: exports_external3.record(exports_external3.string(), exports_external3.unknown()).optional()
49335
- });
49336
- var SubjectTrackUpsertInput3 = SubjectTrackInput3.extend({
49337
- id: NonEmptyString6
49508
+ grade: NonEmptyString6,
49509
+ courseId: NonEmptyString6,
49510
+ orgSourcedId: NonEmptyString6.optional()
49338
49511
  });
49339
49512
  var EdubridgeListEnrollmentsParams3 = exports_external3.object({
49340
49513
  userId: NonEmptyString6
@@ -50303,7 +50476,8 @@ class BaseResource {
50303
50476
  return this.stream(params).toArray();
50304
50477
  }
50305
50478
  async first(params) {
50306
- const result = await this.list({ ...params, limit: 1 });
50479
+ const limitedParams = { ...params ?? {}, limit: 1 };
50480
+ const result = await new Paginator22(this.transport, this.basePath, limitedParams, this.unwrapKey, this.transform.bind(this)).firstPage();
50307
50481
  return result.data[0];
50308
50482
  }
50309
50483
  stream(params) {
@@ -50386,7 +50560,8 @@ class ReadOnlyResource {
50386
50560
  return this.stream(params).toArray();
50387
50561
  }
50388
50562
  async first(params) {
50389
- const result = await this.list({ ...params, limit: 1 });
50563
+ const limitedParams = { ...params ?? {}, limit: 1 };
50564
+ const result = await new Paginator22(this.transport, this.basePath, limitedParams, this.unwrapKey, this.transform.bind(this)).firstPage();
50390
50565
  return result.data[0];
50391
50566
  }
50392
50567
  stream(params) {
@@ -52305,7 +52480,17 @@ class TimebackProvider5 {
52305
52480
  }
52306
52481
  function getEnv5(key) {
52307
52482
  try {
52308
- return typeof process === "undefined" ? undefined : process.env[key];
52483
+ if (typeof process === "undefined")
52484
+ return;
52485
+ if (typeof key === "string") {
52486
+ return process.env[key];
52487
+ }
52488
+ for (const k of key) {
52489
+ const value = process.env[k];
52490
+ if (value !== undefined)
52491
+ return value;
52492
+ }
52493
+ return;
52309
52494
  } catch {
52310
52495
  return;
52311
52496
  }
@@ -52336,6 +52521,18 @@ var DEFAULT_PROVIDER_REGISTRY5 = {
52336
52521
  }
52337
52522
  }
52338
52523
  };
52524
+ function primaryEnvVar5(key) {
52525
+ if (typeof key === "string") {
52526
+ return key;
52527
+ }
52528
+ if (key.length === 0) {
52529
+ throw new Error(`Missing env var key: ${key}`);
52530
+ }
52531
+ return key[0];
52532
+ }
52533
+ function formatEnvVarKey5(key) {
52534
+ return primaryEnvVar5(key);
52535
+ }
52339
52536
  function validateEnv5(env) {
52340
52537
  if (env !== "staging" && env !== "production") {
52341
52538
  throw new Error(`Invalid env "${env}": must be "staging" or "production"`);
@@ -52346,10 +52543,10 @@ function validateAuth5(auth, envVars) {
52346
52543
  const clientId = auth?.clientId ?? getEnv5(envVars.clientId);
52347
52544
  const clientSecret = auth?.clientSecret ?? getEnv5(envVars.clientSecret);
52348
52545
  if (!clientId) {
52349
- throw new Error(`Missing clientId: provide in config or set ${envVars.clientId}`);
52546
+ throw new Error(`Missing clientId: provide in config or set ${formatEnvVarKey5(envVars.clientId)}`);
52350
52547
  }
52351
52548
  if (!clientSecret) {
52352
- throw new Error(`Missing clientSecret: provide in config or set ${envVars.clientSecret}`);
52549
+ throw new Error(`Missing clientSecret: provide in config or set ${formatEnvVarKey5(envVars.clientSecret)}`);
52353
52550
  }
52354
52551
  return { clientId, clientSecret };
52355
52552
  }
@@ -52365,21 +52562,21 @@ function buildMissingEnvError5(envVars) {
52365
52562
  const clientId = getEnv5(envVars.clientId);
52366
52563
  const clientSecret = getEnv5(envVars.clientSecret);
52367
52564
  if (baseUrl === undefined && clientId === undefined) {
52368
- const hint = envVars.env ?? envVars.baseUrl;
52565
+ const hint = formatEnvVarKey5(envVars.env ?? envVars.baseUrl);
52369
52566
  return `Missing env: provide in config or set ${hint}`;
52370
52567
  }
52371
52568
  const missing = [];
52372
52569
  if (baseUrl === undefined) {
52373
- missing.push(envVars.env ?? envVars.baseUrl);
52570
+ missing.push(formatEnvVarKey5(envVars.env ?? envVars.baseUrl));
52374
52571
  }
52375
52572
  if (baseUrl !== undefined && authUrl === undefined) {
52376
- missing.push(envVars.authUrl);
52573
+ missing.push(formatEnvVarKey5(envVars.authUrl));
52377
52574
  }
52378
52575
  if (clientId === undefined) {
52379
- missing.push(envVars.clientId);
52576
+ missing.push(formatEnvVarKey5(envVars.clientId));
52380
52577
  }
52381
52578
  if (clientSecret === undefined) {
52382
- missing.push(envVars.clientSecret);
52579
+ missing.push(formatEnvVarKey5(envVars.clientSecret));
52383
52580
  }
52384
52581
  return `Missing environment variables: ${missing.join(", ")}`;
52385
52582
  }
@@ -53063,10 +53260,14 @@ function validateNonEmptyString4(value, name) {
53063
53260
  }
53064
53261
  }
53065
53262
  var POWERPATH_ENV_VARS = {
53066
- baseUrl: "POWERPATH_BASE_URL",
53067
- clientId: "POWERPATH_CLIENT_ID",
53068
- clientSecret: "POWERPATH_CLIENT_SECRET",
53069
- authUrl: "POWERPATH_TOKEN_URL"
53263
+ baseUrl: ["TIMEBACK_API_BASE_URL", "TIMEBACK_BASE_URL", "POWERPATH_BASE_URL"],
53264
+ clientId: ["TIMEBACK_API_CLIENT_ID", "TIMEBACK_CLIENT_ID", "POWERPATH_CLIENT_ID"],
53265
+ clientSecret: [
53266
+ "TIMEBACK_API_CLIENT_SECRET",
53267
+ "TIMEBACK_CLIENT_SECRET",
53268
+ "POWERPATH_CLIENT_SECRET"
53269
+ ],
53270
+ authUrl: ["TIMEBACK_API_AUTH_URL", "TIMEBACK_AUTH_URL", "POWERPATH_TOKEN_URL"]
53070
53271
  };
53071
53272
  function resolveToProvider24(config4, registry4 = DEFAULT_PROVIDER_REGISTRY5) {
53072
53273
  return resolveToProvider7(config4, POWERPATH_ENV_VARS, registry4);
@@ -55308,7 +55509,7 @@ class Doc4 {
55308
55509
  var version4 = {
55309
55510
  major: 4,
55310
55511
  minor: 3,
55311
- patch: 5
55512
+ patch: 6
55312
55513
  };
55313
55514
  var $ZodType4 = /* @__PURE__ */ $constructor4("$ZodType", (inst, def) => {
55314
55515
  var _a4;
@@ -56592,7 +56793,7 @@ var $ZodRecord4 = /* @__PURE__ */ $constructor4("$ZodRecord", (inst, def) => {
56592
56793
  if (keyResult instanceof Promise) {
56593
56794
  throw new Error("Async schemas not supported in object keys currently");
56594
56795
  }
56595
- const checkNumericKey = typeof key === "string" && number7.test(key) && keyResult.issues.length && keyResult.issues.some((iss) => iss.code === "invalid_type" && iss.expected === "number");
56796
+ const checkNumericKey = typeof key === "string" && number7.test(key) && keyResult.issues.length;
56596
56797
  if (checkNumericKey) {
56597
56798
  const retryResult = def.keyType._zod.run({ value: Number(key), issues: [] }, ctx);
56598
56799
  if (retryResult instanceof Promise) {
@@ -63909,7 +64110,7 @@ function finalize4(ctx, schema) {
63909
64110
  }
63910
64111
  }
63911
64112
  }
63912
- if (refSchema.$ref) {
64113
+ if (refSchema.$ref && refSeen.def) {
63913
64114
  for (const key in schema2) {
63914
64115
  if (key === "$ref" || key === "allOf")
63915
64116
  continue;
@@ -66541,7 +66742,7 @@ var TimebackSubject4 = exports_external4.enum([
66541
66742
  "Math",
66542
66743
  "None",
66543
66744
  "Other"
66544
- ]);
66745
+ ]).meta({ id: "TimebackSubject", description: "Subject area" });
66545
66746
  var TimebackGrade4 = exports_external4.union([
66546
66747
  exports_external4.literal(-1),
66547
66748
  exports_external4.literal(0),
@@ -66558,7 +66759,10 @@ var TimebackGrade4 = exports_external4.union([
66558
66759
  exports_external4.literal(11),
66559
66760
  exports_external4.literal(12),
66560
66761
  exports_external4.literal(13)
66561
- ]);
66762
+ ]).meta({
66763
+ id: "TimebackGrade",
66764
+ description: "Grade level (-1 = Pre-K, 0 = K, 1-12 = grades, 13 = AP)"
66765
+ });
66562
66766
  var ScoreStatus4 = exports_external4.enum([
66563
66767
  "exempt",
66564
66768
  "fully graded",
@@ -66788,62 +66992,84 @@ var CaliperListEventsParams4 = exports_external4.object({
66788
66992
  actorEmail: exports_external4.email().optional()
66789
66993
  }).strict();
66790
66994
  var CourseIds4 = exports_external4.object({
66791
- staging: exports_external4.string().optional(),
66792
- production: exports_external4.string().optional()
66793
- });
66794
- var CourseType4 = exports_external4.enum(["base", "hole-filling", "optional"]);
66795
- var PublishStatus4 = exports_external4.enum(["draft", "testing", "published", "deactivated"]);
66995
+ staging: exports_external4.string().meta({ description: "Course ID in staging environment" }).optional(),
66996
+ production: exports_external4.string().meta({ description: "Course ID in production environment" }).optional()
66997
+ }).meta({ id: "CourseIds", description: "Environment-specific course IDs (populated by sync)" });
66998
+ var CourseType4 = exports_external4.enum(["base", "hole-filling", "optional"]).meta({ id: "CourseType", description: "Course classification type" });
66999
+ var PublishStatus4 = exports_external4.enum(["draft", "testing", "published", "deactivated"]).meta({ id: "PublishStatus", description: "Course publication status" });
66796
67000
  var CourseGoals4 = exports_external4.object({
66797
- dailyXp: exports_external4.number().int().positive().optional(),
66798
- dailyLessons: exports_external4.number().int().positive().optional(),
66799
- dailyActiveMinutes: exports_external4.number().int().positive().optional(),
66800
- dailyAccuracy: exports_external4.number().int().min(0).max(100).optional(),
66801
- dailyMasteredUnits: exports_external4.number().int().positive().optional()
66802
- });
67001
+ dailyXp: exports_external4.number().int().positive().meta({ description: "Target XP to earn per day" }).optional(),
67002
+ dailyLessons: exports_external4.number().int().positive().meta({ description: "Target lessons to complete per day" }).optional(),
67003
+ dailyActiveMinutes: exports_external4.number().int().positive().meta({ description: "Target active learning minutes per day" }).optional(),
67004
+ dailyAccuracy: exports_external4.number().int().min(0).max(100).meta({ description: "Target accuracy percentage (0-100)" }).optional(),
67005
+ dailyMasteredUnits: exports_external4.number().int().positive().meta({ description: "Target units to master per day" }).optional()
67006
+ }).meta({ id: "CourseGoals", description: "Daily learning goals for a course" });
66803
67007
  var CourseMetrics4 = exports_external4.object({
66804
- totalXp: exports_external4.number().int().positive().optional(),
66805
- totalLessons: exports_external4.number().int().positive().optional(),
66806
- totalGrades: exports_external4.number().int().positive().optional()
66807
- });
67008
+ totalXp: exports_external4.number().int().positive().meta({ description: "Total XP available in the course" }).optional(),
67009
+ totalLessons: exports_external4.number().int().positive().meta({ description: "Total number of lessons/activities" }).optional(),
67010
+ totalGrades: exports_external4.number().int().positive().meta({ description: "Total grade levels covered" }).optional()
67011
+ }).meta({ id: "CourseMetrics", description: "Aggregate metrics for a course" });
66808
67012
  var CourseMetadata4 = exports_external4.object({
66809
67013
  courseType: CourseType4.optional(),
66810
- isSupplemental: exports_external4.boolean().optional(),
66811
- isCustom: exports_external4.boolean().optional(),
67014
+ isSupplemental: exports_external4.boolean().meta({ description: "Whether this is supplemental to a base course" }).optional(),
67015
+ isCustom: exports_external4.boolean().meta({ description: "Whether this is a custom course for an individual student" }).optional(),
66812
67016
  publishStatus: PublishStatus4.optional(),
66813
- contactEmail: exports_external4.email().optional(),
66814
- primaryApp: exports_external4.string().optional(),
67017
+ contactEmail: exports_external4.email().meta({ description: "Contact email for course issues" }).optional(),
67018
+ primaryApp: exports_external4.string().meta({ description: "Primary application identifier" }).optional(),
66815
67019
  goals: CourseGoals4.optional(),
66816
67020
  metrics: CourseMetrics4.optional()
66817
- });
67021
+ }).meta({ id: "CourseMetadata", description: "Course metadata (matches API metadata object)" });
66818
67022
  var CourseDefaults4 = exports_external4.object({
66819
- courseCode: exports_external4.string().optional(),
66820
- level: exports_external4.string().optional(),
67023
+ courseCode: exports_external4.string().meta({ description: "Course code (e.g., 'MATH101')" }).optional(),
67024
+ level: exports_external4.string().meta({ description: "Course level (e.g., 'AP', 'Honors')" }).optional(),
66821
67025
  metadata: CourseMetadata4.optional()
67026
+ }).meta({
67027
+ id: "CourseDefaults",
67028
+ description: "Default properties that apply to all courses unless overridden"
66822
67029
  });
66823
67030
  var CourseEnvOverrides4 = exports_external4.object({
66824
- level: exports_external4.string().optional(),
66825
- sensor: exports_external4.string().url().optional(),
66826
- launchUrl: exports_external4.string().url().optional(),
67031
+ level: exports_external4.string().meta({ description: "Course level for this environment" }).optional(),
67032
+ sensor: exports_external4.url().meta({ description: "Caliper sensor endpoint URL for this environment" }).optional(),
67033
+ launchUrl: exports_external4.url().meta({ description: "LTI launch URL for this environment" }).optional(),
66827
67034
  metadata: CourseMetadata4.optional()
67035
+ }).meta({
67036
+ id: "CourseEnvOverrides",
67037
+ description: "Environment-specific course overrides (non-identity fields)"
66828
67038
  });
66829
67039
  var CourseOverrides4 = exports_external4.object({
66830
- staging: CourseEnvOverrides4.optional(),
66831
- production: CourseEnvOverrides4.optional()
66832
- });
67040
+ staging: CourseEnvOverrides4.meta({
67041
+ description: "Overrides for staging environment"
67042
+ }).optional(),
67043
+ production: CourseEnvOverrides4.meta({
67044
+ description: "Overrides for production environment"
67045
+ }).optional()
67046
+ }).meta({ id: "CourseOverrides", description: "Per-environment course overrides" });
66833
67047
  var CourseConfig4 = CourseDefaults4.extend({
66834
- subject: TimebackSubject4,
66835
- grade: TimebackGrade4.optional(),
67048
+ subject: TimebackSubject4.meta({ description: "Subject area for this course" }),
67049
+ grade: TimebackGrade4.meta({
67050
+ description: "Grade level (-1 = Pre-K, 0 = K, 1-12 = grades, 13 = AP)"
67051
+ }).optional(),
66836
67052
  ids: CourseIds4.nullable().optional(),
66837
- sensor: exports_external4.string().url().optional(),
66838
- launchUrl: exports_external4.string().url().optional(),
67053
+ sensor: exports_external4.url().meta({ description: "Caliper sensor endpoint URL for this course" }).optional(),
67054
+ launchUrl: exports_external4.url().meta({ description: "LTI launch URL for this course" }).optional(),
66839
67055
  overrides: CourseOverrides4.optional()
67056
+ }).meta({
67057
+ id: "CourseConfig",
67058
+ description: "Configuration for a single course. Must have either grade or courseCode (or both)."
66840
67059
  });
66841
67060
  var TimebackConfig4 = exports_external4.object({
66842
- name: exports_external4.string().min(1, "App name is required"),
66843
- defaults: CourseDefaults4.optional(),
66844
- courses: exports_external4.array(CourseConfig4).min(1, "At least one course is required"),
66845
- sensor: exports_external4.string().url().optional(),
66846
- launchUrl: exports_external4.string().url().optional()
67061
+ $schema: exports_external4.string().meta({ description: "JSON Schema reference for editor support" }).optional(),
67062
+ name: exports_external4.string().min(1, "App name is required").meta({ description: "Display name for your app" }),
67063
+ defaults: CourseDefaults4.meta({
67064
+ description: "Default properties applied to all courses"
67065
+ }).optional(),
67066
+ courses: exports_external4.array(CourseConfig4).min(1, "At least one course is required").meta({ description: "Courses available in this app" }),
67067
+ sensor: exports_external4.url().meta({ description: "Default Caliper sensor endpoint URL for all courses" }).optional(),
67068
+ launchUrl: exports_external4.url().meta({ description: "Default LTI launch URL for all courses" }).optional()
67069
+ }).meta({
67070
+ id: "TimebackConfig",
67071
+ title: "Timeback Config",
67072
+ description: "Configuration schema for timeback.config.json files"
66847
67073
  }).refine((config22) => {
66848
67074
  return config22.courses.every((c) => c.grade !== undefined || c.courseCode !== undefined);
66849
67075
  }, {
@@ -66864,17 +67090,23 @@ var TimebackConfig4 = exports_external4.object({
66864
67090
  message: "Duplicate courseCode found; each must be unique",
66865
67091
  path: ["courses"]
66866
67092
  }).refine((config22) => {
66867
- return config22.courses.every((c) => c.sensor !== undefined || config22.sensor !== undefined);
66868
- }, {
66869
- message: "Each course must have an effective sensor; set a top-level `sensor` or per-course `sensor`",
66870
- path: ["courses"]
66871
- }).refine((config22) => {
66872
- return config22.courses.every((c) => c.launchUrl !== undefined || config22.launchUrl !== undefined);
67093
+ return config22.courses.every((c) => {
67094
+ if (c.sensor !== undefined || config22.sensor !== undefined) {
67095
+ return true;
67096
+ }
67097
+ const launchUrls = [
67098
+ c.launchUrl,
67099
+ config22.launchUrl,
67100
+ c.overrides?.staging?.launchUrl,
67101
+ c.overrides?.production?.launchUrl
67102
+ ].filter(Boolean);
67103
+ return launchUrls.length > 0;
67104
+ });
66873
67105
  }, {
66874
- message: "Each course must have an effective launchUrl; set a top-level `launchUrl` or per-course `launchUrl`",
67106
+ message: "Each course must have an effective sensor. Either set `sensor` explicitly (top-level or per-course), or provide a `launchUrl` so sensor can be derived from its origin.",
66875
67107
  path: ["courses"]
66876
67108
  });
66877
- var EdubridgeDateString4 = exports_external4.union([IsoDateString4, IsoDateTimeString4]);
67109
+ var EdubridgeDateString4 = IsoDateTimeString4;
66878
67110
  var EduBridgeEnrollment4 = exports_external4.object({
66879
67111
  id: exports_external4.string(),
66880
67112
  role: exports_external4.string(),
@@ -66938,12 +67170,9 @@ var EmailOrStudentId4 = exports_external4.object({
66938
67170
  });
66939
67171
  var SubjectTrackInput4 = exports_external4.object({
66940
67172
  subject: NonEmptyString7,
66941
- gradeLevel: NonEmptyString7,
66942
- targetCourseId: NonEmptyString7,
66943
- metadata: exports_external4.record(exports_external4.string(), exports_external4.unknown()).optional()
66944
- });
66945
- var SubjectTrackUpsertInput4 = SubjectTrackInput4.extend({
66946
- id: NonEmptyString7
67173
+ grade: NonEmptyString7,
67174
+ courseId: NonEmptyString7,
67175
+ orgSourcedId: NonEmptyString7.optional()
66947
67176
  });
66948
67177
  var EdubridgeListEnrollmentsParams4 = exports_external4.object({
66949
67178
  userId: NonEmptyString7
@@ -68924,7 +69153,17 @@ class TimebackProvider6 {
68924
69153
  }
68925
69154
  function getEnv6(key) {
68926
69155
  try {
68927
- return typeof process === "undefined" ? undefined : process.env[key];
69156
+ if (typeof process === "undefined")
69157
+ return;
69158
+ if (typeof key === "string") {
69159
+ return process.env[key];
69160
+ }
69161
+ for (const k of key) {
69162
+ const value = process.env[k];
69163
+ if (value !== undefined)
69164
+ return value;
69165
+ }
69166
+ return;
68928
69167
  } catch {
68929
69168
  return;
68930
69169
  }
@@ -68955,6 +69194,18 @@ var DEFAULT_PROVIDER_REGISTRY6 = {
68955
69194
  }
68956
69195
  }
68957
69196
  };
69197
+ function primaryEnvVar6(key) {
69198
+ if (typeof key === "string") {
69199
+ return key;
69200
+ }
69201
+ if (key.length === 0) {
69202
+ throw new Error(`Missing env var key: ${key}`);
69203
+ }
69204
+ return key[0];
69205
+ }
69206
+ function formatEnvVarKey6(key) {
69207
+ return primaryEnvVar6(key);
69208
+ }
68958
69209
  function validateEnv6(env) {
68959
69210
  if (env !== "staging" && env !== "production") {
68960
69211
  throw new Error(`Invalid env "${env}": must be "staging" or "production"`);
@@ -68965,10 +69216,10 @@ function validateAuth6(auth, envVars) {
68965
69216
  const clientId = auth?.clientId ?? getEnv6(envVars.clientId);
68966
69217
  const clientSecret = auth?.clientSecret ?? getEnv6(envVars.clientSecret);
68967
69218
  if (!clientId) {
68968
- throw new Error(`Missing clientId: provide in config or set ${envVars.clientId}`);
69219
+ throw new Error(`Missing clientId: provide in config or set ${formatEnvVarKey6(envVars.clientId)}`);
68969
69220
  }
68970
69221
  if (!clientSecret) {
68971
- throw new Error(`Missing clientSecret: provide in config or set ${envVars.clientSecret}`);
69222
+ throw new Error(`Missing clientSecret: provide in config or set ${formatEnvVarKey6(envVars.clientSecret)}`);
68972
69223
  }
68973
69224
  return { clientId, clientSecret };
68974
69225
  }
@@ -68984,21 +69235,21 @@ function buildMissingEnvError6(envVars) {
68984
69235
  const clientId = getEnv6(envVars.clientId);
68985
69236
  const clientSecret = getEnv6(envVars.clientSecret);
68986
69237
  if (baseUrl === undefined && clientId === undefined) {
68987
- const hint = envVars.env ?? envVars.baseUrl;
69238
+ const hint = formatEnvVarKey6(envVars.env ?? envVars.baseUrl);
68988
69239
  return `Missing env: provide in config or set ${hint}`;
68989
69240
  }
68990
69241
  const missing = [];
68991
69242
  if (baseUrl === undefined) {
68992
- missing.push(envVars.env ?? envVars.baseUrl);
69243
+ missing.push(formatEnvVarKey6(envVars.env ?? envVars.baseUrl));
68993
69244
  }
68994
69245
  if (baseUrl !== undefined && authUrl === undefined) {
68995
- missing.push(envVars.authUrl);
69246
+ missing.push(formatEnvVarKey6(envVars.authUrl));
68996
69247
  }
68997
69248
  if (clientId === undefined) {
68998
- missing.push(envVars.clientId);
69249
+ missing.push(formatEnvVarKey6(envVars.clientId));
68999
69250
  }
69000
69251
  if (clientSecret === undefined) {
69001
- missing.push(envVars.clientSecret);
69252
+ missing.push(formatEnvVarKey6(envVars.clientSecret));
69002
69253
  }
69003
69254
  return `Missing environment variables: ${missing.join(", ")}`;
69004
69255
  }
@@ -69698,10 +69949,10 @@ function validatePageListParams2(params) {
69698
69949
  }
69699
69950
  }
69700
69951
  var QTI_ENV_VARS = {
69701
- baseUrl: "QTI_BASE_URL",
69702
- clientId: "QTI_CLIENT_ID",
69703
- clientSecret: "QTI_CLIENT_SECRET",
69704
- authUrl: "QTI_TOKEN_URL"
69952
+ baseUrl: ["TIMEBACK_API_BASE_URL", "TIMEBACK_BASE_URL", "QTI_BASE_URL"],
69953
+ clientId: ["TIMEBACK_API_CLIENT_ID", "TIMEBACK_CLIENT_ID", "QTI_CLIENT_ID"],
69954
+ clientSecret: ["TIMEBACK_API_CLIENT_SECRET", "TIMEBACK_CLIENT_SECRET", "QTI_CLIENT_SECRET"],
69955
+ authUrl: ["TIMEBACK_API_AUTH_URL", "TIMEBACK_AUTH_URL", "QTI_TOKEN_URL"]
69705
69956
  };
69706
69957
  function resolveToProvider25(config5, registry5 = DEFAULT_PROVIDER_REGISTRY6) {
69707
69958
  return resolveToProvider8(config5, QTI_ENV_VARS, registry5);
@@ -71947,7 +72198,7 @@ class Doc5 {
71947
72198
  var version5 = {
71948
72199
  major: 4,
71949
72200
  minor: 3,
71950
- patch: 5
72201
+ patch: 6
71951
72202
  };
71952
72203
  var $ZodType5 = /* @__PURE__ */ $constructor5("$ZodType", (inst, def) => {
71953
72204
  var _a5;
@@ -73231,7 +73482,7 @@ var $ZodRecord5 = /* @__PURE__ */ $constructor5("$ZodRecord", (inst, def) => {
73231
73482
  if (keyResult instanceof Promise) {
73232
73483
  throw new Error("Async schemas not supported in object keys currently");
73233
73484
  }
73234
- const checkNumericKey = typeof key === "string" && number8.test(key) && keyResult.issues.length && keyResult.issues.some((iss) => iss.code === "invalid_type" && iss.expected === "number");
73485
+ const checkNumericKey = typeof key === "string" && number8.test(key) && keyResult.issues.length;
73235
73486
  if (checkNumericKey) {
73236
73487
  const retryResult = def.keyType._zod.run({ value: Number(key), issues: [] }, ctx);
73237
73488
  if (retryResult instanceof Promise) {
@@ -80548,7 +80799,7 @@ function finalize5(ctx, schema) {
80548
80799
  }
80549
80800
  }
80550
80801
  }
80551
- if (refSchema.$ref) {
80802
+ if (refSchema.$ref && refSeen.def) {
80552
80803
  for (const key in schema2) {
80553
80804
  if (key === "$ref" || key === "allOf")
80554
80805
  continue;
@@ -83180,7 +83431,7 @@ var TimebackSubject5 = exports_external5.enum([
83180
83431
  "Math",
83181
83432
  "None",
83182
83433
  "Other"
83183
- ]);
83434
+ ]).meta({ id: "TimebackSubject", description: "Subject area" });
83184
83435
  var TimebackGrade5 = exports_external5.union([
83185
83436
  exports_external5.literal(-1),
83186
83437
  exports_external5.literal(0),
@@ -83197,7 +83448,10 @@ var TimebackGrade5 = exports_external5.union([
83197
83448
  exports_external5.literal(11),
83198
83449
  exports_external5.literal(12),
83199
83450
  exports_external5.literal(13)
83200
- ]);
83451
+ ]).meta({
83452
+ id: "TimebackGrade",
83453
+ description: "Grade level (-1 = Pre-K, 0 = K, 1-12 = grades, 13 = AP)"
83454
+ });
83201
83455
  var ScoreStatus5 = exports_external5.enum([
83202
83456
  "exempt",
83203
83457
  "fully graded",
@@ -83427,62 +83681,84 @@ var CaliperListEventsParams5 = exports_external5.object({
83427
83681
  actorEmail: exports_external5.email().optional()
83428
83682
  }).strict();
83429
83683
  var CourseIds5 = exports_external5.object({
83430
- staging: exports_external5.string().optional(),
83431
- production: exports_external5.string().optional()
83432
- });
83433
- var CourseType5 = exports_external5.enum(["base", "hole-filling", "optional"]);
83434
- var PublishStatus5 = exports_external5.enum(["draft", "testing", "published", "deactivated"]);
83684
+ staging: exports_external5.string().meta({ description: "Course ID in staging environment" }).optional(),
83685
+ production: exports_external5.string().meta({ description: "Course ID in production environment" }).optional()
83686
+ }).meta({ id: "CourseIds", description: "Environment-specific course IDs (populated by sync)" });
83687
+ var CourseType5 = exports_external5.enum(["base", "hole-filling", "optional"]).meta({ id: "CourseType", description: "Course classification type" });
83688
+ var PublishStatus5 = exports_external5.enum(["draft", "testing", "published", "deactivated"]).meta({ id: "PublishStatus", description: "Course publication status" });
83435
83689
  var CourseGoals5 = exports_external5.object({
83436
- dailyXp: exports_external5.number().int().positive().optional(),
83437
- dailyLessons: exports_external5.number().int().positive().optional(),
83438
- dailyActiveMinutes: exports_external5.number().int().positive().optional(),
83439
- dailyAccuracy: exports_external5.number().int().min(0).max(100).optional(),
83440
- dailyMasteredUnits: exports_external5.number().int().positive().optional()
83441
- });
83690
+ dailyXp: exports_external5.number().int().positive().meta({ description: "Target XP to earn per day" }).optional(),
83691
+ dailyLessons: exports_external5.number().int().positive().meta({ description: "Target lessons to complete per day" }).optional(),
83692
+ dailyActiveMinutes: exports_external5.number().int().positive().meta({ description: "Target active learning minutes per day" }).optional(),
83693
+ dailyAccuracy: exports_external5.number().int().min(0).max(100).meta({ description: "Target accuracy percentage (0-100)" }).optional(),
83694
+ dailyMasteredUnits: exports_external5.number().int().positive().meta({ description: "Target units to master per day" }).optional()
83695
+ }).meta({ id: "CourseGoals", description: "Daily learning goals for a course" });
83442
83696
  var CourseMetrics5 = exports_external5.object({
83443
- totalXp: exports_external5.number().int().positive().optional(),
83444
- totalLessons: exports_external5.number().int().positive().optional(),
83445
- totalGrades: exports_external5.number().int().positive().optional()
83446
- });
83697
+ totalXp: exports_external5.number().int().positive().meta({ description: "Total XP available in the course" }).optional(),
83698
+ totalLessons: exports_external5.number().int().positive().meta({ description: "Total number of lessons/activities" }).optional(),
83699
+ totalGrades: exports_external5.number().int().positive().meta({ description: "Total grade levels covered" }).optional()
83700
+ }).meta({ id: "CourseMetrics", description: "Aggregate metrics for a course" });
83447
83701
  var CourseMetadata5 = exports_external5.object({
83448
83702
  courseType: CourseType5.optional(),
83449
- isSupplemental: exports_external5.boolean().optional(),
83450
- isCustom: exports_external5.boolean().optional(),
83703
+ isSupplemental: exports_external5.boolean().meta({ description: "Whether this is supplemental to a base course" }).optional(),
83704
+ isCustom: exports_external5.boolean().meta({ description: "Whether this is a custom course for an individual student" }).optional(),
83451
83705
  publishStatus: PublishStatus5.optional(),
83452
- contactEmail: exports_external5.email().optional(),
83453
- primaryApp: exports_external5.string().optional(),
83706
+ contactEmail: exports_external5.email().meta({ description: "Contact email for course issues" }).optional(),
83707
+ primaryApp: exports_external5.string().meta({ description: "Primary application identifier" }).optional(),
83454
83708
  goals: CourseGoals5.optional(),
83455
83709
  metrics: CourseMetrics5.optional()
83456
- });
83710
+ }).meta({ id: "CourseMetadata", description: "Course metadata (matches API metadata object)" });
83457
83711
  var CourseDefaults5 = exports_external5.object({
83458
- courseCode: exports_external5.string().optional(),
83459
- level: exports_external5.string().optional(),
83712
+ courseCode: exports_external5.string().meta({ description: "Course code (e.g., 'MATH101')" }).optional(),
83713
+ level: exports_external5.string().meta({ description: "Course level (e.g., 'AP', 'Honors')" }).optional(),
83460
83714
  metadata: CourseMetadata5.optional()
83715
+ }).meta({
83716
+ id: "CourseDefaults",
83717
+ description: "Default properties that apply to all courses unless overridden"
83461
83718
  });
83462
83719
  var CourseEnvOverrides5 = exports_external5.object({
83463
- level: exports_external5.string().optional(),
83464
- sensor: exports_external5.string().url().optional(),
83465
- launchUrl: exports_external5.string().url().optional(),
83720
+ level: exports_external5.string().meta({ description: "Course level for this environment" }).optional(),
83721
+ sensor: exports_external5.url().meta({ description: "Caliper sensor endpoint URL for this environment" }).optional(),
83722
+ launchUrl: exports_external5.url().meta({ description: "LTI launch URL for this environment" }).optional(),
83466
83723
  metadata: CourseMetadata5.optional()
83724
+ }).meta({
83725
+ id: "CourseEnvOverrides",
83726
+ description: "Environment-specific course overrides (non-identity fields)"
83467
83727
  });
83468
83728
  var CourseOverrides5 = exports_external5.object({
83469
- staging: CourseEnvOverrides5.optional(),
83470
- production: CourseEnvOverrides5.optional()
83471
- });
83729
+ staging: CourseEnvOverrides5.meta({
83730
+ description: "Overrides for staging environment"
83731
+ }).optional(),
83732
+ production: CourseEnvOverrides5.meta({
83733
+ description: "Overrides for production environment"
83734
+ }).optional()
83735
+ }).meta({ id: "CourseOverrides", description: "Per-environment course overrides" });
83472
83736
  var CourseConfig5 = CourseDefaults5.extend({
83473
- subject: TimebackSubject5,
83474
- grade: TimebackGrade5.optional(),
83737
+ subject: TimebackSubject5.meta({ description: "Subject area for this course" }),
83738
+ grade: TimebackGrade5.meta({
83739
+ description: "Grade level (-1 = Pre-K, 0 = K, 1-12 = grades, 13 = AP)"
83740
+ }).optional(),
83475
83741
  ids: CourseIds5.nullable().optional(),
83476
- sensor: exports_external5.string().url().optional(),
83477
- launchUrl: exports_external5.string().url().optional(),
83742
+ sensor: exports_external5.url().meta({ description: "Caliper sensor endpoint URL for this course" }).optional(),
83743
+ launchUrl: exports_external5.url().meta({ description: "LTI launch URL for this course" }).optional(),
83478
83744
  overrides: CourseOverrides5.optional()
83745
+ }).meta({
83746
+ id: "CourseConfig",
83747
+ description: "Configuration for a single course. Must have either grade or courseCode (or both)."
83479
83748
  });
83480
83749
  var TimebackConfig5 = exports_external5.object({
83481
- name: exports_external5.string().min(1, "App name is required"),
83482
- defaults: CourseDefaults5.optional(),
83483
- courses: exports_external5.array(CourseConfig5).min(1, "At least one course is required"),
83484
- sensor: exports_external5.string().url().optional(),
83485
- launchUrl: exports_external5.string().url().optional()
83750
+ $schema: exports_external5.string().meta({ description: "JSON Schema reference for editor support" }).optional(),
83751
+ name: exports_external5.string().min(1, "App name is required").meta({ description: "Display name for your app" }),
83752
+ defaults: CourseDefaults5.meta({
83753
+ description: "Default properties applied to all courses"
83754
+ }).optional(),
83755
+ courses: exports_external5.array(CourseConfig5).min(1, "At least one course is required").meta({ description: "Courses available in this app" }),
83756
+ sensor: exports_external5.url().meta({ description: "Default Caliper sensor endpoint URL for all courses" }).optional(),
83757
+ launchUrl: exports_external5.url().meta({ description: "Default LTI launch URL for all courses" }).optional()
83758
+ }).meta({
83759
+ id: "TimebackConfig",
83760
+ title: "Timeback Config",
83761
+ description: "Configuration schema for timeback.config.json files"
83486
83762
  }).refine((config22) => {
83487
83763
  return config22.courses.every((c) => c.grade !== undefined || c.courseCode !== undefined);
83488
83764
  }, {
@@ -83503,17 +83779,23 @@ var TimebackConfig5 = exports_external5.object({
83503
83779
  message: "Duplicate courseCode found; each must be unique",
83504
83780
  path: ["courses"]
83505
83781
  }).refine((config22) => {
83506
- return config22.courses.every((c) => c.sensor !== undefined || config22.sensor !== undefined);
83507
- }, {
83508
- message: "Each course must have an effective sensor; set a top-level `sensor` or per-course `sensor`",
83509
- path: ["courses"]
83510
- }).refine((config22) => {
83511
- return config22.courses.every((c) => c.launchUrl !== undefined || config22.launchUrl !== undefined);
83782
+ return config22.courses.every((c) => {
83783
+ if (c.sensor !== undefined || config22.sensor !== undefined) {
83784
+ return true;
83785
+ }
83786
+ const launchUrls = [
83787
+ c.launchUrl,
83788
+ config22.launchUrl,
83789
+ c.overrides?.staging?.launchUrl,
83790
+ c.overrides?.production?.launchUrl
83791
+ ].filter(Boolean);
83792
+ return launchUrls.length > 0;
83793
+ });
83512
83794
  }, {
83513
- message: "Each course must have an effective launchUrl; set a top-level `launchUrl` or per-course `launchUrl`",
83795
+ message: "Each course must have an effective sensor. Either set `sensor` explicitly (top-level or per-course), or provide a `launchUrl` so sensor can be derived from its origin.",
83514
83796
  path: ["courses"]
83515
83797
  });
83516
- var EdubridgeDateString5 = exports_external5.union([IsoDateString5, IsoDateTimeString5]);
83798
+ var EdubridgeDateString5 = IsoDateTimeString5;
83517
83799
  var EduBridgeEnrollment5 = exports_external5.object({
83518
83800
  id: exports_external5.string(),
83519
83801
  role: exports_external5.string(),
@@ -83577,12 +83859,9 @@ var EmailOrStudentId5 = exports_external5.object({
83577
83859
  });
83578
83860
  var SubjectTrackInput5 = exports_external5.object({
83579
83861
  subject: NonEmptyString8,
83580
- gradeLevel: NonEmptyString8,
83581
- targetCourseId: NonEmptyString8,
83582
- metadata: exports_external5.record(exports_external5.string(), exports_external5.unknown()).optional()
83583
- });
83584
- var SubjectTrackUpsertInput5 = SubjectTrackInput5.extend({
83585
- id: NonEmptyString8
83862
+ grade: NonEmptyString8,
83863
+ courseId: NonEmptyString8,
83864
+ orgSourcedId: NonEmptyString8.optional()
83586
83865
  });
83587
83866
  var EdubridgeListEnrollmentsParams5 = exports_external5.object({
83588
83867
  userId: NonEmptyString8
@@ -84978,11 +85257,21 @@ var QtiClient = createQtiClient();
84978
85257
  // src/constants.ts
84979
85258
  var TIMEBACK_ENV_VARS = {
84980
85259
  env: "TIMEBACK_ENV",
84981
- baseUrl: "TIMEBACK_BASE_URL",
84982
- authUrl: "TIMEBACK_TOKEN_URL",
84983
- clientId: "TIMEBACK_CLIENT_ID",
84984
- clientSecret: "TIMEBACK_CLIENT_SECRET"
85260
+ baseUrl: ["TIMEBACK_API_BASE_URL", "TIMEBACK_BASE_URL"],
85261
+ authUrl: ["TIMEBACK_API_AUTH_URL", "TIMEBACK_AUTH_URL"],
85262
+ clientId: ["TIMEBACK_API_CLIENT_ID", "TIMEBACK_CLIENT_ID"],
85263
+ clientSecret: ["TIMEBACK_API_CLIENT_SECRET", "TIMEBACK_CLIENT_SECRET"]
84985
85264
  };
85265
+ function getServiceUrlsForEnv(env, platform = DEFAULT_PLATFORM3) {
85266
+ const endpoints = PLATFORM_ENDPOINTS3[platform];
85267
+ return {
85268
+ oneroster: endpoints.api[env],
85269
+ caliper: endpoints.caliper[env],
85270
+ edubridge: endpoints.api[env],
85271
+ qti: endpoints.qti[env],
85272
+ authUrl: endpoints.token[env]
85273
+ };
85274
+ }
84986
85275
 
84987
85276
  // src/client.ts
84988
85277
  class TimebackClient {
@@ -85160,6 +85449,7 @@ class TimebackManager {
85160
85449
  export {
85161
85450
  whereToFilter2 as whereToFilter,
85162
85451
  isApiError,
85452
+ getServiceUrlsForEnv,
85163
85453
  ValidationError3 as ValidationError,
85164
85454
  UnauthorizedError3 as UnauthorizedError,
85165
85455
  TimebackManager,