@timeback/sdk 0.1.5 → 0.1.7
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/README.md +21 -22
- package/dist/client/adapters/react/hooks/types.d.ts +15 -0
- package/dist/client/adapters/react/hooks/types.d.ts.map +1 -0
- package/dist/client/adapters/react/hooks/useTimebackVerification.d.ts +18 -0
- package/dist/client/adapters/react/hooks/useTimebackVerification.d.ts.map +1 -0
- package/dist/client/adapters/react/index.d.ts +2 -0
- package/dist/client/adapters/react/index.d.ts.map +1 -1
- package/dist/client/adapters/react/index.js +139 -9
- package/dist/client/auth/bearer.d.ts +17 -0
- package/dist/client/auth/bearer.d.ts.map +1 -0
- package/dist/client/auth/index.d.ts +3 -0
- package/dist/client/auth/index.d.ts.map +1 -0
- package/dist/client/auth/types.d.ts +39 -0
- package/dist/client/auth/types.d.ts.map +1 -0
- package/dist/client/index.d.ts +2 -0
- package/dist/client/index.d.ts.map +1 -1
- package/dist/client/lib/fetch.d.ts +19 -0
- package/dist/client/lib/fetch.d.ts.map +1 -0
- package/dist/client/namespaces/user.d.ts +25 -2
- package/dist/client/namespaces/user.d.ts.map +1 -1
- package/dist/client/timeback-client.class.d.ts +15 -0
- package/dist/client/timeback-client.class.d.ts.map +1 -1
- package/dist/client/timeback-client.d.ts +3 -0
- package/dist/client/timeback-client.d.ts.map +1 -1
- package/dist/client.d.ts +2 -1
- package/dist/client.d.ts.map +1 -1
- package/dist/client.js +69 -6
- package/dist/edge.d.ts +1 -1
- package/dist/edge.js +85291 -169
- package/dist/identity.js +85186 -74
- package/dist/index.js +1289 -840
- package/dist/server/adapters/express.d.ts.map +1 -1
- package/dist/server/adapters/express.js +489 -388
- package/dist/server/adapters/native.d.ts.map +1 -1
- package/dist/server/adapters/native.js +32 -1
- package/dist/server/adapters/nextjs.js +32 -1
- package/dist/server/adapters/nuxt.d.ts.map +1 -1
- package/dist/server/adapters/nuxt.js +493 -388
- package/dist/server/adapters/solid-start.d.ts.map +1 -1
- package/dist/server/adapters/solid-start.js +493 -388
- package/dist/server/adapters/svelte-kit.d.ts.map +1 -1
- package/dist/server/adapters/svelte-kit.js +37 -1
- package/dist/server/adapters/tanstack-start.d.ts.map +1 -1
- package/dist/server/adapters/tanstack-start.js +488 -388
- package/dist/server/adapters/utils.d.ts +1 -1
- package/dist/server/adapters/utils.d.ts.map +1 -1
- package/dist/server/{lib/build-activity-events.d.ts → handlers/activity/caliper.d.ts} +29 -4
- package/dist/server/handlers/activity/caliper.d.ts.map +1 -0
- package/dist/server/handlers/activity/gradebook.d.ts +56 -0
- package/dist/server/handlers/activity/gradebook.d.ts.map +1 -0
- package/dist/server/handlers/activity/handler.d.ts +15 -0
- package/dist/server/handlers/activity/handler.d.ts.map +1 -0
- package/dist/server/handlers/activity/index.d.ts +9 -0
- package/dist/server/handlers/activity/index.d.ts.map +1 -0
- package/dist/server/handlers/activity/resolve.d.ts +39 -0
- package/dist/server/handlers/activity/resolve.d.ts.map +1 -0
- package/dist/server/handlers/activity/schema.d.ts +52 -0
- package/dist/server/handlers/activity/schema.d.ts.map +1 -0
- package/dist/server/handlers/activity/types.d.ts +52 -0
- package/dist/server/handlers/activity/types.d.ts.map +1 -0
- package/dist/server/handlers/identity/handler.d.ts +14 -0
- package/dist/server/handlers/identity/handler.d.ts.map +1 -0
- package/dist/server/handlers/identity/index.d.ts +8 -0
- package/dist/server/handlers/identity/index.d.ts.map +1 -0
- package/dist/server/handlers/identity/oidc.d.ts +43 -0
- package/dist/server/handlers/identity/oidc.d.ts.map +1 -0
- package/dist/server/handlers/identity/types.d.ts +24 -0
- package/dist/server/handlers/identity/types.d.ts.map +1 -0
- package/dist/server/handlers/identity-only/handler.d.ts +15 -0
- package/dist/server/handlers/identity-only/handler.d.ts.map +1 -0
- package/dist/server/handlers/identity-only/index.d.ts +8 -0
- package/dist/server/handlers/identity-only/index.d.ts.map +1 -0
- package/dist/server/handlers/identity-only/oidc.d.ts +26 -0
- package/dist/server/handlers/identity-only/oidc.d.ts.map +1 -0
- package/dist/server/handlers/identity-only/types.d.ts +19 -0
- package/dist/server/handlers/identity-only/types.d.ts.map +1 -0
- package/dist/server/handlers/index.d.ts +5 -2
- package/dist/server/handlers/index.d.ts.map +1 -1
- package/dist/server/{lib/build-user-profile.d.ts → handlers/user/enrollments.d.ts} +7 -2
- package/dist/server/handlers/user/enrollments.d.ts.map +1 -0
- package/dist/server/handlers/user/handler.d.ts +17 -0
- package/dist/server/handlers/user/handler.d.ts.map +1 -0
- package/dist/server/handlers/user/index.d.ts +10 -0
- package/dist/server/handlers/user/index.d.ts.map +1 -0
- package/dist/server/handlers/user/profile.d.ts +22 -0
- package/dist/server/handlers/user/profile.d.ts.map +1 -0
- package/dist/server/handlers/user/types.d.ts +35 -0
- package/dist/server/handlers/user/types.d.ts.map +1 -0
- package/dist/server/handlers/user/verify.d.ts +25 -0
- package/dist/server/handlers/user/verify.d.ts.map +1 -0
- package/dist/server/index.d.ts +1 -1
- package/dist/server/index.d.ts.map +1 -1
- package/dist/server/lib/index.d.ts +4 -5
- package/dist/server/lib/index.d.ts.map +1 -1
- package/dist/server/lib/resolve.d.ts +4 -42
- package/dist/server/lib/resolve.d.ts.map +1 -1
- package/dist/server/lib/sso.d.ts +86 -0
- package/dist/server/lib/sso.d.ts.map +1 -0
- package/dist/server/lib/utils.d.ts +32 -1
- package/dist/server/lib/utils.d.ts.map +1 -1
- package/dist/server/timeback-identity.d.ts +2 -2
- package/dist/server/timeback-identity.d.ts.map +1 -1
- package/dist/server/timeback.d.ts.map +1 -1
- package/dist/server/types.d.ts +19 -12
- package/dist/server/types.d.ts.map +1 -1
- package/dist/shared/constants.d.ts +1 -0
- package/dist/shared/constants.d.ts.map +1 -1
- package/dist/shared/types.d.ts +18 -3
- package/dist/shared/types.d.ts.map +1 -1
- package/package.json +7 -7
- package/dist/config.d.ts +0 -20
- package/dist/config.d.ts.map +0 -1
- package/dist/config.js +0 -0
- package/dist/server/handlers/activity.d.ts +0 -25
- package/dist/server/handlers/activity.d.ts.map +0 -1
- package/dist/server/handlers/identity-full.d.ts +0 -28
- package/dist/server/handlers/identity-full.d.ts.map +0 -1
- package/dist/server/handlers/identity-only.d.ts +0 -22
- package/dist/server/handlers/identity-only.d.ts.map +0 -1
- package/dist/server/handlers/user.d.ts +0 -31
- package/dist/server/handlers/user.d.ts.map +0 -1
- package/dist/server/lib/build-activity-events.d.ts.map +0 -1
- package/dist/server/lib/build-user-profile.d.ts.map +0 -1
|
@@ -434,12 +434,32 @@ async function getUserInfo(params) {
|
|
|
434
434
|
return response.json();
|
|
435
435
|
}
|
|
436
436
|
// src/server/lib/utils.ts
|
|
437
|
+
function safeIdSegment(value) {
|
|
438
|
+
return encodeURIComponent(value).replace(/%/g, "_");
|
|
439
|
+
}
|
|
440
|
+
function hashSuffix64Base36(value) {
|
|
441
|
+
let hash = 0xcbf29ce484222325n;
|
|
442
|
+
const prime = 0x100000001b3n;
|
|
443
|
+
const mod64 = 0xffffffffffffffffn;
|
|
444
|
+
for (let i = 0;i < value.length; i++) {
|
|
445
|
+
hash ^= BigInt(value.charCodeAt(i));
|
|
446
|
+
hash = hash * prime & mod64;
|
|
447
|
+
}
|
|
448
|
+
const base36 = hash.toString(36);
|
|
449
|
+
return base36.length > 12 ? base36.slice(-12) : base36;
|
|
450
|
+
}
|
|
437
451
|
function mapEnvForApi(env) {
|
|
438
452
|
if (env === "local" || env === "staging") {
|
|
439
453
|
return "staging";
|
|
440
454
|
}
|
|
441
455
|
return "production";
|
|
442
456
|
}
|
|
457
|
+
function normalizeEnv(env) {
|
|
458
|
+
if (env === "production" || env === "local" || env === "staging") {
|
|
459
|
+
return env;
|
|
460
|
+
}
|
|
461
|
+
return "staging";
|
|
462
|
+
}
|
|
443
463
|
function jsonResponse(data, status = 200, headers) {
|
|
444
464
|
const responseHeaders = new Headers(headers);
|
|
445
465
|
responseHeaders.set("Content-Type", "application/json");
|
|
@@ -15391,7 +15411,7 @@ var TimebackSubject = exports_external.enum([
|
|
|
15391
15411
|
"Math",
|
|
15392
15412
|
"None",
|
|
15393
15413
|
"Other"
|
|
15394
|
-
]);
|
|
15414
|
+
]).meta({ id: "TimebackSubject", description: "Subject area" });
|
|
15395
15415
|
var TimebackGrade = exports_external.union([
|
|
15396
15416
|
exports_external.literal(-1),
|
|
15397
15417
|
exports_external.literal(0),
|
|
@@ -15408,7 +15428,10 @@ var TimebackGrade = exports_external.union([
|
|
|
15408
15428
|
exports_external.literal(11),
|
|
15409
15429
|
exports_external.literal(12),
|
|
15410
15430
|
exports_external.literal(13)
|
|
15411
|
-
])
|
|
15431
|
+
]).meta({
|
|
15432
|
+
id: "TimebackGrade",
|
|
15433
|
+
description: "Grade level (-1 = Pre-K, 0 = K, 1-12 = grades, 13 = AP)"
|
|
15434
|
+
});
|
|
15412
15435
|
var ScoreStatus = exports_external.enum([
|
|
15413
15436
|
"exempt",
|
|
15414
15437
|
"fully graded",
|
|
@@ -15638,62 +15661,84 @@ var CaliperListEventsParams = exports_external.object({
|
|
|
15638
15661
|
actorEmail: exports_external.email().optional()
|
|
15639
15662
|
}).strict();
|
|
15640
15663
|
var CourseIds = exports_external.object({
|
|
15641
|
-
staging: exports_external.string().optional(),
|
|
15642
|
-
production: exports_external.string().optional()
|
|
15643
|
-
});
|
|
15644
|
-
var CourseType = exports_external.enum(["base", "hole-filling", "optional"]);
|
|
15645
|
-
var PublishStatus = exports_external.enum(["draft", "testing", "published", "deactivated"]);
|
|
15664
|
+
staging: exports_external.string().meta({ description: "Course ID in staging environment" }).optional(),
|
|
15665
|
+
production: exports_external.string().meta({ description: "Course ID in production environment" }).optional()
|
|
15666
|
+
}).meta({ id: "CourseIds", description: "Environment-specific course IDs (populated by sync)" });
|
|
15667
|
+
var CourseType = exports_external.enum(["base", "hole-filling", "optional"]).meta({ id: "CourseType", description: "Course classification type" });
|
|
15668
|
+
var PublishStatus = exports_external.enum(["draft", "testing", "published", "deactivated"]).meta({ id: "PublishStatus", description: "Course publication status" });
|
|
15646
15669
|
var CourseGoals = exports_external.object({
|
|
15647
|
-
dailyXp: exports_external.number().int().positive().optional(),
|
|
15648
|
-
dailyLessons: exports_external.number().int().positive().optional(),
|
|
15649
|
-
dailyActiveMinutes: exports_external.number().int().positive().optional(),
|
|
15650
|
-
dailyAccuracy: exports_external.number().int().min(0).max(100).optional(),
|
|
15651
|
-
dailyMasteredUnits: exports_external.number().int().positive().optional()
|
|
15652
|
-
});
|
|
15670
|
+
dailyXp: exports_external.number().int().positive().meta({ description: "Target XP to earn per day" }).optional(),
|
|
15671
|
+
dailyLessons: exports_external.number().int().positive().meta({ description: "Target lessons to complete per day" }).optional(),
|
|
15672
|
+
dailyActiveMinutes: exports_external.number().int().positive().meta({ description: "Target active learning minutes per day" }).optional(),
|
|
15673
|
+
dailyAccuracy: exports_external.number().int().min(0).max(100).meta({ description: "Target accuracy percentage (0-100)" }).optional(),
|
|
15674
|
+
dailyMasteredUnits: exports_external.number().int().positive().meta({ description: "Target units to master per day" }).optional()
|
|
15675
|
+
}).meta({ id: "CourseGoals", description: "Daily learning goals for a course" });
|
|
15653
15676
|
var CourseMetrics = exports_external.object({
|
|
15654
|
-
totalXp: exports_external.number().int().positive().optional(),
|
|
15655
|
-
totalLessons: exports_external.number().int().positive().optional(),
|
|
15656
|
-
totalGrades: exports_external.number().int().positive().optional()
|
|
15657
|
-
});
|
|
15677
|
+
totalXp: exports_external.number().int().positive().meta({ description: "Total XP available in the course" }).optional(),
|
|
15678
|
+
totalLessons: exports_external.number().int().positive().meta({ description: "Total number of lessons/activities" }).optional(),
|
|
15679
|
+
totalGrades: exports_external.number().int().positive().meta({ description: "Total grade levels covered" }).optional()
|
|
15680
|
+
}).meta({ id: "CourseMetrics", description: "Aggregate metrics for a course" });
|
|
15658
15681
|
var CourseMetadata = exports_external.object({
|
|
15659
15682
|
courseType: CourseType.optional(),
|
|
15660
|
-
isSupplemental: exports_external.boolean().optional(),
|
|
15661
|
-
isCustom: exports_external.boolean().optional(),
|
|
15683
|
+
isSupplemental: exports_external.boolean().meta({ description: "Whether this is supplemental to a base course" }).optional(),
|
|
15684
|
+
isCustom: exports_external.boolean().meta({ description: "Whether this is a custom course for an individual student" }).optional(),
|
|
15662
15685
|
publishStatus: PublishStatus.optional(),
|
|
15663
|
-
contactEmail: exports_external.email().optional(),
|
|
15664
|
-
primaryApp: exports_external.string().optional(),
|
|
15686
|
+
contactEmail: exports_external.email().meta({ description: "Contact email for course issues" }).optional(),
|
|
15687
|
+
primaryApp: exports_external.string().meta({ description: "Primary application identifier" }).optional(),
|
|
15665
15688
|
goals: CourseGoals.optional(),
|
|
15666
15689
|
metrics: CourseMetrics.optional()
|
|
15667
|
-
});
|
|
15690
|
+
}).meta({ id: "CourseMetadata", description: "Course metadata (matches API metadata object)" });
|
|
15668
15691
|
var CourseDefaults = exports_external.object({
|
|
15669
|
-
courseCode: exports_external.string().optional(),
|
|
15670
|
-
level: exports_external.string().optional(),
|
|
15692
|
+
courseCode: exports_external.string().meta({ description: "Course code (e.g., 'MATH101')" }).optional(),
|
|
15693
|
+
level: exports_external.string().meta({ description: "Course level (e.g., 'AP', 'Honors')" }).optional(),
|
|
15671
15694
|
metadata: CourseMetadata.optional()
|
|
15695
|
+
}).meta({
|
|
15696
|
+
id: "CourseDefaults",
|
|
15697
|
+
description: "Default properties that apply to all courses unless overridden"
|
|
15672
15698
|
});
|
|
15673
15699
|
var CourseEnvOverrides = exports_external.object({
|
|
15674
|
-
level: exports_external.string().optional(),
|
|
15675
|
-
sensor: exports_external.
|
|
15676
|
-
launchUrl: exports_external.
|
|
15700
|
+
level: exports_external.string().meta({ description: "Course level for this environment" }).optional(),
|
|
15701
|
+
sensor: exports_external.url().meta({ description: "Caliper sensor endpoint URL for this environment" }).optional(),
|
|
15702
|
+
launchUrl: exports_external.url().meta({ description: "LTI launch URL for this environment" }).optional(),
|
|
15677
15703
|
metadata: CourseMetadata.optional()
|
|
15704
|
+
}).meta({
|
|
15705
|
+
id: "CourseEnvOverrides",
|
|
15706
|
+
description: "Environment-specific course overrides (non-identity fields)"
|
|
15678
15707
|
});
|
|
15679
15708
|
var CourseOverrides = exports_external.object({
|
|
15680
|
-
staging: CourseEnvOverrides.
|
|
15681
|
-
|
|
15682
|
-
})
|
|
15709
|
+
staging: CourseEnvOverrides.meta({
|
|
15710
|
+
description: "Overrides for staging environment"
|
|
15711
|
+
}).optional(),
|
|
15712
|
+
production: CourseEnvOverrides.meta({
|
|
15713
|
+
description: "Overrides for production environment"
|
|
15714
|
+
}).optional()
|
|
15715
|
+
}).meta({ id: "CourseOverrides", description: "Per-environment course overrides" });
|
|
15683
15716
|
var CourseConfig = CourseDefaults.extend({
|
|
15684
|
-
subject: TimebackSubject,
|
|
15685
|
-
grade: TimebackGrade.
|
|
15717
|
+
subject: TimebackSubject.meta({ description: "Subject area for this course" }),
|
|
15718
|
+
grade: TimebackGrade.meta({
|
|
15719
|
+
description: "Grade level (-1 = Pre-K, 0 = K, 1-12 = grades, 13 = AP)"
|
|
15720
|
+
}).optional(),
|
|
15686
15721
|
ids: CourseIds.nullable().optional(),
|
|
15687
|
-
sensor: exports_external.
|
|
15688
|
-
launchUrl: exports_external.
|
|
15722
|
+
sensor: exports_external.url().meta({ description: "Caliper sensor endpoint URL for this course" }).optional(),
|
|
15723
|
+
launchUrl: exports_external.url().meta({ description: "LTI launch URL for this course" }).optional(),
|
|
15689
15724
|
overrides: CourseOverrides.optional()
|
|
15725
|
+
}).meta({
|
|
15726
|
+
id: "CourseConfig",
|
|
15727
|
+
description: "Configuration for a single course. Must have either grade or courseCode (or both)."
|
|
15690
15728
|
});
|
|
15691
15729
|
var TimebackConfig = exports_external.object({
|
|
15692
|
-
|
|
15693
|
-
|
|
15694
|
-
|
|
15695
|
-
|
|
15696
|
-
|
|
15730
|
+
$schema: exports_external.string().meta({ description: "JSON Schema reference for editor support" }).optional(),
|
|
15731
|
+
name: exports_external.string().min(1, "App name is required").meta({ description: "Display name for your app" }),
|
|
15732
|
+
defaults: CourseDefaults.meta({
|
|
15733
|
+
description: "Default properties applied to all courses"
|
|
15734
|
+
}).optional(),
|
|
15735
|
+
courses: exports_external.array(CourseConfig).min(1, "At least one course is required").meta({ description: "Courses available in this app" }),
|
|
15736
|
+
sensor: exports_external.url().meta({ description: "Default Caliper sensor endpoint URL for all courses" }).optional(),
|
|
15737
|
+
launchUrl: exports_external.url().meta({ description: "Default LTI launch URL for all courses" }).optional()
|
|
15738
|
+
}).meta({
|
|
15739
|
+
id: "TimebackConfig",
|
|
15740
|
+
title: "Timeback Config",
|
|
15741
|
+
description: "Configuration schema for timeback.config.json files"
|
|
15697
15742
|
}).refine((config2) => {
|
|
15698
15743
|
return config2.courses.every((c) => c.grade !== undefined || c.courseCode !== undefined);
|
|
15699
15744
|
}, {
|
|
@@ -15714,14 +15759,20 @@ var TimebackConfig = exports_external.object({
|
|
|
15714
15759
|
message: "Duplicate courseCode found; each must be unique",
|
|
15715
15760
|
path: ["courses"]
|
|
15716
15761
|
}).refine((config2) => {
|
|
15717
|
-
return config2.courses.every((c) =>
|
|
15718
|
-
|
|
15719
|
-
|
|
15720
|
-
|
|
15721
|
-
|
|
15722
|
-
|
|
15762
|
+
return config2.courses.every((c) => {
|
|
15763
|
+
if (c.sensor !== undefined || config2.sensor !== undefined) {
|
|
15764
|
+
return true;
|
|
15765
|
+
}
|
|
15766
|
+
const launchUrls = [
|
|
15767
|
+
c.launchUrl,
|
|
15768
|
+
config2.launchUrl,
|
|
15769
|
+
c.overrides?.staging?.launchUrl,
|
|
15770
|
+
c.overrides?.production?.launchUrl
|
|
15771
|
+
].filter(Boolean);
|
|
15772
|
+
return launchUrls.length > 0;
|
|
15773
|
+
});
|
|
15723
15774
|
}, {
|
|
15724
|
-
message: "Each course must have an effective
|
|
15775
|
+
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.",
|
|
15725
15776
|
path: ["courses"]
|
|
15726
15777
|
});
|
|
15727
15778
|
var EdubridgeDateString = exports_external.union([IsoDateString, IsoDateTimeString]);
|
|
@@ -31769,7 +31820,7 @@ var TimebackSubject2 = exports_external2.enum([
|
|
|
31769
31820
|
"Math",
|
|
31770
31821
|
"None",
|
|
31771
31822
|
"Other"
|
|
31772
|
-
]);
|
|
31823
|
+
]).meta({ id: "TimebackSubject", description: "Subject area" });
|
|
31773
31824
|
var TimebackGrade2 = exports_external2.union([
|
|
31774
31825
|
exports_external2.literal(-1),
|
|
31775
31826
|
exports_external2.literal(0),
|
|
@@ -31786,7 +31837,10 @@ var TimebackGrade2 = exports_external2.union([
|
|
|
31786
31837
|
exports_external2.literal(11),
|
|
31787
31838
|
exports_external2.literal(12),
|
|
31788
31839
|
exports_external2.literal(13)
|
|
31789
|
-
])
|
|
31840
|
+
]).meta({
|
|
31841
|
+
id: "TimebackGrade",
|
|
31842
|
+
description: "Grade level (-1 = Pre-K, 0 = K, 1-12 = grades, 13 = AP)"
|
|
31843
|
+
});
|
|
31790
31844
|
var ScoreStatus2 = exports_external2.enum([
|
|
31791
31845
|
"exempt",
|
|
31792
31846
|
"fully graded",
|
|
@@ -32016,62 +32070,84 @@ var CaliperListEventsParams2 = exports_external2.object({
|
|
|
32016
32070
|
actorEmail: exports_external2.email().optional()
|
|
32017
32071
|
}).strict();
|
|
32018
32072
|
var CourseIds2 = exports_external2.object({
|
|
32019
|
-
staging: exports_external2.string().optional(),
|
|
32020
|
-
production: exports_external2.string().optional()
|
|
32021
|
-
});
|
|
32022
|
-
var CourseType2 = exports_external2.enum(["base", "hole-filling", "optional"]);
|
|
32023
|
-
var PublishStatus2 = exports_external2.enum(["draft", "testing", "published", "deactivated"]);
|
|
32073
|
+
staging: exports_external2.string().meta({ description: "Course ID in staging environment" }).optional(),
|
|
32074
|
+
production: exports_external2.string().meta({ description: "Course ID in production environment" }).optional()
|
|
32075
|
+
}).meta({ id: "CourseIds", description: "Environment-specific course IDs (populated by sync)" });
|
|
32076
|
+
var CourseType2 = exports_external2.enum(["base", "hole-filling", "optional"]).meta({ id: "CourseType", description: "Course classification type" });
|
|
32077
|
+
var PublishStatus2 = exports_external2.enum(["draft", "testing", "published", "deactivated"]).meta({ id: "PublishStatus", description: "Course publication status" });
|
|
32024
32078
|
var CourseGoals2 = exports_external2.object({
|
|
32025
|
-
dailyXp: exports_external2.number().int().positive().optional(),
|
|
32026
|
-
dailyLessons: exports_external2.number().int().positive().optional(),
|
|
32027
|
-
dailyActiveMinutes: exports_external2.number().int().positive().optional(),
|
|
32028
|
-
dailyAccuracy: exports_external2.number().int().min(0).max(100).optional(),
|
|
32029
|
-
dailyMasteredUnits: exports_external2.number().int().positive().optional()
|
|
32030
|
-
});
|
|
32079
|
+
dailyXp: exports_external2.number().int().positive().meta({ description: "Target XP to earn per day" }).optional(),
|
|
32080
|
+
dailyLessons: exports_external2.number().int().positive().meta({ description: "Target lessons to complete per day" }).optional(),
|
|
32081
|
+
dailyActiveMinutes: exports_external2.number().int().positive().meta({ description: "Target active learning minutes per day" }).optional(),
|
|
32082
|
+
dailyAccuracy: exports_external2.number().int().min(0).max(100).meta({ description: "Target accuracy percentage (0-100)" }).optional(),
|
|
32083
|
+
dailyMasteredUnits: exports_external2.number().int().positive().meta({ description: "Target units to master per day" }).optional()
|
|
32084
|
+
}).meta({ id: "CourseGoals", description: "Daily learning goals for a course" });
|
|
32031
32085
|
var CourseMetrics2 = exports_external2.object({
|
|
32032
|
-
totalXp: exports_external2.number().int().positive().optional(),
|
|
32033
|
-
totalLessons: exports_external2.number().int().positive().optional(),
|
|
32034
|
-
totalGrades: exports_external2.number().int().positive().optional()
|
|
32035
|
-
});
|
|
32086
|
+
totalXp: exports_external2.number().int().positive().meta({ description: "Total XP available in the course" }).optional(),
|
|
32087
|
+
totalLessons: exports_external2.number().int().positive().meta({ description: "Total number of lessons/activities" }).optional(),
|
|
32088
|
+
totalGrades: exports_external2.number().int().positive().meta({ description: "Total grade levels covered" }).optional()
|
|
32089
|
+
}).meta({ id: "CourseMetrics", description: "Aggregate metrics for a course" });
|
|
32036
32090
|
var CourseMetadata2 = exports_external2.object({
|
|
32037
32091
|
courseType: CourseType2.optional(),
|
|
32038
|
-
isSupplemental: exports_external2.boolean().optional(),
|
|
32039
|
-
isCustom: exports_external2.boolean().optional(),
|
|
32092
|
+
isSupplemental: exports_external2.boolean().meta({ description: "Whether this is supplemental to a base course" }).optional(),
|
|
32093
|
+
isCustom: exports_external2.boolean().meta({ description: "Whether this is a custom course for an individual student" }).optional(),
|
|
32040
32094
|
publishStatus: PublishStatus2.optional(),
|
|
32041
|
-
contactEmail: exports_external2.email().optional(),
|
|
32042
|
-
primaryApp: exports_external2.string().optional(),
|
|
32095
|
+
contactEmail: exports_external2.email().meta({ description: "Contact email for course issues" }).optional(),
|
|
32096
|
+
primaryApp: exports_external2.string().meta({ description: "Primary application identifier" }).optional(),
|
|
32043
32097
|
goals: CourseGoals2.optional(),
|
|
32044
32098
|
metrics: CourseMetrics2.optional()
|
|
32045
|
-
});
|
|
32099
|
+
}).meta({ id: "CourseMetadata", description: "Course metadata (matches API metadata object)" });
|
|
32046
32100
|
var CourseDefaults2 = exports_external2.object({
|
|
32047
|
-
courseCode: exports_external2.string().optional(),
|
|
32048
|
-
level: exports_external2.string().optional(),
|
|
32101
|
+
courseCode: exports_external2.string().meta({ description: "Course code (e.g., 'MATH101')" }).optional(),
|
|
32102
|
+
level: exports_external2.string().meta({ description: "Course level (e.g., 'AP', 'Honors')" }).optional(),
|
|
32049
32103
|
metadata: CourseMetadata2.optional()
|
|
32104
|
+
}).meta({
|
|
32105
|
+
id: "CourseDefaults",
|
|
32106
|
+
description: "Default properties that apply to all courses unless overridden"
|
|
32050
32107
|
});
|
|
32051
32108
|
var CourseEnvOverrides2 = exports_external2.object({
|
|
32052
|
-
level: exports_external2.string().optional(),
|
|
32053
|
-
sensor: exports_external2.
|
|
32054
|
-
launchUrl: exports_external2.
|
|
32109
|
+
level: exports_external2.string().meta({ description: "Course level for this environment" }).optional(),
|
|
32110
|
+
sensor: exports_external2.url().meta({ description: "Caliper sensor endpoint URL for this environment" }).optional(),
|
|
32111
|
+
launchUrl: exports_external2.url().meta({ description: "LTI launch URL for this environment" }).optional(),
|
|
32055
32112
|
metadata: CourseMetadata2.optional()
|
|
32113
|
+
}).meta({
|
|
32114
|
+
id: "CourseEnvOverrides",
|
|
32115
|
+
description: "Environment-specific course overrides (non-identity fields)"
|
|
32056
32116
|
});
|
|
32057
32117
|
var CourseOverrides2 = exports_external2.object({
|
|
32058
|
-
staging: CourseEnvOverrides2.
|
|
32059
|
-
|
|
32060
|
-
})
|
|
32118
|
+
staging: CourseEnvOverrides2.meta({
|
|
32119
|
+
description: "Overrides for staging environment"
|
|
32120
|
+
}).optional(),
|
|
32121
|
+
production: CourseEnvOverrides2.meta({
|
|
32122
|
+
description: "Overrides for production environment"
|
|
32123
|
+
}).optional()
|
|
32124
|
+
}).meta({ id: "CourseOverrides", description: "Per-environment course overrides" });
|
|
32061
32125
|
var CourseConfig2 = CourseDefaults2.extend({
|
|
32062
|
-
subject: TimebackSubject2,
|
|
32063
|
-
grade: TimebackGrade2.
|
|
32126
|
+
subject: TimebackSubject2.meta({ description: "Subject area for this course" }),
|
|
32127
|
+
grade: TimebackGrade2.meta({
|
|
32128
|
+
description: "Grade level (-1 = Pre-K, 0 = K, 1-12 = grades, 13 = AP)"
|
|
32129
|
+
}).optional(),
|
|
32064
32130
|
ids: CourseIds2.nullable().optional(),
|
|
32065
|
-
sensor: exports_external2.
|
|
32066
|
-
launchUrl: exports_external2.
|
|
32131
|
+
sensor: exports_external2.url().meta({ description: "Caliper sensor endpoint URL for this course" }).optional(),
|
|
32132
|
+
launchUrl: exports_external2.url().meta({ description: "LTI launch URL for this course" }).optional(),
|
|
32067
32133
|
overrides: CourseOverrides2.optional()
|
|
32134
|
+
}).meta({
|
|
32135
|
+
id: "CourseConfig",
|
|
32136
|
+
description: "Configuration for a single course. Must have either grade or courseCode (or both)."
|
|
32068
32137
|
});
|
|
32069
32138
|
var TimebackConfig2 = exports_external2.object({
|
|
32070
|
-
|
|
32071
|
-
|
|
32072
|
-
|
|
32073
|
-
|
|
32074
|
-
|
|
32139
|
+
$schema: exports_external2.string().meta({ description: "JSON Schema reference for editor support" }).optional(),
|
|
32140
|
+
name: exports_external2.string().min(1, "App name is required").meta({ description: "Display name for your app" }),
|
|
32141
|
+
defaults: CourseDefaults2.meta({
|
|
32142
|
+
description: "Default properties applied to all courses"
|
|
32143
|
+
}).optional(),
|
|
32144
|
+
courses: exports_external2.array(CourseConfig2).min(1, "At least one course is required").meta({ description: "Courses available in this app" }),
|
|
32145
|
+
sensor: exports_external2.url().meta({ description: "Default Caliper sensor endpoint URL for all courses" }).optional(),
|
|
32146
|
+
launchUrl: exports_external2.url().meta({ description: "Default LTI launch URL for all courses" }).optional()
|
|
32147
|
+
}).meta({
|
|
32148
|
+
id: "TimebackConfig",
|
|
32149
|
+
title: "Timeback Config",
|
|
32150
|
+
description: "Configuration schema for timeback.config.json files"
|
|
32075
32151
|
}).refine((config22) => {
|
|
32076
32152
|
return config22.courses.every((c) => c.grade !== undefined || c.courseCode !== undefined);
|
|
32077
32153
|
}, {
|
|
@@ -32092,14 +32168,20 @@ var TimebackConfig2 = exports_external2.object({
|
|
|
32092
32168
|
message: "Duplicate courseCode found; each must be unique",
|
|
32093
32169
|
path: ["courses"]
|
|
32094
32170
|
}).refine((config22) => {
|
|
32095
|
-
return config22.courses.every((c) =>
|
|
32096
|
-
|
|
32097
|
-
|
|
32098
|
-
|
|
32099
|
-
|
|
32100
|
-
|
|
32171
|
+
return config22.courses.every((c) => {
|
|
32172
|
+
if (c.sensor !== undefined || config22.sensor !== undefined) {
|
|
32173
|
+
return true;
|
|
32174
|
+
}
|
|
32175
|
+
const launchUrls = [
|
|
32176
|
+
c.launchUrl,
|
|
32177
|
+
config22.launchUrl,
|
|
32178
|
+
c.overrides?.staging?.launchUrl,
|
|
32179
|
+
c.overrides?.production?.launchUrl
|
|
32180
|
+
].filter(Boolean);
|
|
32181
|
+
return launchUrls.length > 0;
|
|
32182
|
+
});
|
|
32101
32183
|
}, {
|
|
32102
|
-
message: "Each course must have an effective
|
|
32184
|
+
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.",
|
|
32103
32185
|
path: ["courses"]
|
|
32104
32186
|
});
|
|
32105
32187
|
var EdubridgeDateString2 = exports_external2.union([IsoDateString2, IsoDateTimeString2]);
|
|
@@ -49177,7 +49259,7 @@ var TimebackSubject3 = exports_external3.enum([
|
|
|
49177
49259
|
"Math",
|
|
49178
49260
|
"None",
|
|
49179
49261
|
"Other"
|
|
49180
|
-
]);
|
|
49262
|
+
]).meta({ id: "TimebackSubject", description: "Subject area" });
|
|
49181
49263
|
var TimebackGrade3 = exports_external3.union([
|
|
49182
49264
|
exports_external3.literal(-1),
|
|
49183
49265
|
exports_external3.literal(0),
|
|
@@ -49194,7 +49276,10 @@ var TimebackGrade3 = exports_external3.union([
|
|
|
49194
49276
|
exports_external3.literal(11),
|
|
49195
49277
|
exports_external3.literal(12),
|
|
49196
49278
|
exports_external3.literal(13)
|
|
49197
|
-
])
|
|
49279
|
+
]).meta({
|
|
49280
|
+
id: "TimebackGrade",
|
|
49281
|
+
description: "Grade level (-1 = Pre-K, 0 = K, 1-12 = grades, 13 = AP)"
|
|
49282
|
+
});
|
|
49198
49283
|
var ScoreStatus3 = exports_external3.enum([
|
|
49199
49284
|
"exempt",
|
|
49200
49285
|
"fully graded",
|
|
@@ -49424,62 +49509,84 @@ var CaliperListEventsParams3 = exports_external3.object({
|
|
|
49424
49509
|
actorEmail: exports_external3.email().optional()
|
|
49425
49510
|
}).strict();
|
|
49426
49511
|
var CourseIds3 = exports_external3.object({
|
|
49427
|
-
staging: exports_external3.string().optional(),
|
|
49428
|
-
production: exports_external3.string().optional()
|
|
49429
|
-
});
|
|
49430
|
-
var CourseType3 = exports_external3.enum(["base", "hole-filling", "optional"]);
|
|
49431
|
-
var PublishStatus3 = exports_external3.enum(["draft", "testing", "published", "deactivated"]);
|
|
49512
|
+
staging: exports_external3.string().meta({ description: "Course ID in staging environment" }).optional(),
|
|
49513
|
+
production: exports_external3.string().meta({ description: "Course ID in production environment" }).optional()
|
|
49514
|
+
}).meta({ id: "CourseIds", description: "Environment-specific course IDs (populated by sync)" });
|
|
49515
|
+
var CourseType3 = exports_external3.enum(["base", "hole-filling", "optional"]).meta({ id: "CourseType", description: "Course classification type" });
|
|
49516
|
+
var PublishStatus3 = exports_external3.enum(["draft", "testing", "published", "deactivated"]).meta({ id: "PublishStatus", description: "Course publication status" });
|
|
49432
49517
|
var CourseGoals3 = exports_external3.object({
|
|
49433
|
-
dailyXp: exports_external3.number().int().positive().optional(),
|
|
49434
|
-
dailyLessons: exports_external3.number().int().positive().optional(),
|
|
49435
|
-
dailyActiveMinutes: exports_external3.number().int().positive().optional(),
|
|
49436
|
-
dailyAccuracy: exports_external3.number().int().min(0).max(100).optional(),
|
|
49437
|
-
dailyMasteredUnits: exports_external3.number().int().positive().optional()
|
|
49438
|
-
});
|
|
49518
|
+
dailyXp: exports_external3.number().int().positive().meta({ description: "Target XP to earn per day" }).optional(),
|
|
49519
|
+
dailyLessons: exports_external3.number().int().positive().meta({ description: "Target lessons to complete per day" }).optional(),
|
|
49520
|
+
dailyActiveMinutes: exports_external3.number().int().positive().meta({ description: "Target active learning minutes per day" }).optional(),
|
|
49521
|
+
dailyAccuracy: exports_external3.number().int().min(0).max(100).meta({ description: "Target accuracy percentage (0-100)" }).optional(),
|
|
49522
|
+
dailyMasteredUnits: exports_external3.number().int().positive().meta({ description: "Target units to master per day" }).optional()
|
|
49523
|
+
}).meta({ id: "CourseGoals", description: "Daily learning goals for a course" });
|
|
49439
49524
|
var CourseMetrics3 = exports_external3.object({
|
|
49440
|
-
totalXp: exports_external3.number().int().positive().optional(),
|
|
49441
|
-
totalLessons: exports_external3.number().int().positive().optional(),
|
|
49442
|
-
totalGrades: exports_external3.number().int().positive().optional()
|
|
49443
|
-
});
|
|
49525
|
+
totalXp: exports_external3.number().int().positive().meta({ description: "Total XP available in the course" }).optional(),
|
|
49526
|
+
totalLessons: exports_external3.number().int().positive().meta({ description: "Total number of lessons/activities" }).optional(),
|
|
49527
|
+
totalGrades: exports_external3.number().int().positive().meta({ description: "Total grade levels covered" }).optional()
|
|
49528
|
+
}).meta({ id: "CourseMetrics", description: "Aggregate metrics for a course" });
|
|
49444
49529
|
var CourseMetadata3 = exports_external3.object({
|
|
49445
49530
|
courseType: CourseType3.optional(),
|
|
49446
|
-
isSupplemental: exports_external3.boolean().optional(),
|
|
49447
|
-
isCustom: exports_external3.boolean().optional(),
|
|
49531
|
+
isSupplemental: exports_external3.boolean().meta({ description: "Whether this is supplemental to a base course" }).optional(),
|
|
49532
|
+
isCustom: exports_external3.boolean().meta({ description: "Whether this is a custom course for an individual student" }).optional(),
|
|
49448
49533
|
publishStatus: PublishStatus3.optional(),
|
|
49449
|
-
contactEmail: exports_external3.email().optional(),
|
|
49450
|
-
primaryApp: exports_external3.string().optional(),
|
|
49534
|
+
contactEmail: exports_external3.email().meta({ description: "Contact email for course issues" }).optional(),
|
|
49535
|
+
primaryApp: exports_external3.string().meta({ description: "Primary application identifier" }).optional(),
|
|
49451
49536
|
goals: CourseGoals3.optional(),
|
|
49452
49537
|
metrics: CourseMetrics3.optional()
|
|
49453
|
-
});
|
|
49538
|
+
}).meta({ id: "CourseMetadata", description: "Course metadata (matches API metadata object)" });
|
|
49454
49539
|
var CourseDefaults3 = exports_external3.object({
|
|
49455
|
-
courseCode: exports_external3.string().optional(),
|
|
49456
|
-
level: exports_external3.string().optional(),
|
|
49540
|
+
courseCode: exports_external3.string().meta({ description: "Course code (e.g., 'MATH101')" }).optional(),
|
|
49541
|
+
level: exports_external3.string().meta({ description: "Course level (e.g., 'AP', 'Honors')" }).optional(),
|
|
49457
49542
|
metadata: CourseMetadata3.optional()
|
|
49543
|
+
}).meta({
|
|
49544
|
+
id: "CourseDefaults",
|
|
49545
|
+
description: "Default properties that apply to all courses unless overridden"
|
|
49458
49546
|
});
|
|
49459
49547
|
var CourseEnvOverrides3 = exports_external3.object({
|
|
49460
|
-
level: exports_external3.string().optional(),
|
|
49461
|
-
sensor: exports_external3.
|
|
49462
|
-
launchUrl: exports_external3.
|
|
49548
|
+
level: exports_external3.string().meta({ description: "Course level for this environment" }).optional(),
|
|
49549
|
+
sensor: exports_external3.url().meta({ description: "Caliper sensor endpoint URL for this environment" }).optional(),
|
|
49550
|
+
launchUrl: exports_external3.url().meta({ description: "LTI launch URL for this environment" }).optional(),
|
|
49463
49551
|
metadata: CourseMetadata3.optional()
|
|
49552
|
+
}).meta({
|
|
49553
|
+
id: "CourseEnvOverrides",
|
|
49554
|
+
description: "Environment-specific course overrides (non-identity fields)"
|
|
49464
49555
|
});
|
|
49465
49556
|
var CourseOverrides3 = exports_external3.object({
|
|
49466
|
-
staging: CourseEnvOverrides3.
|
|
49467
|
-
|
|
49468
|
-
})
|
|
49557
|
+
staging: CourseEnvOverrides3.meta({
|
|
49558
|
+
description: "Overrides for staging environment"
|
|
49559
|
+
}).optional(),
|
|
49560
|
+
production: CourseEnvOverrides3.meta({
|
|
49561
|
+
description: "Overrides for production environment"
|
|
49562
|
+
}).optional()
|
|
49563
|
+
}).meta({ id: "CourseOverrides", description: "Per-environment course overrides" });
|
|
49469
49564
|
var CourseConfig3 = CourseDefaults3.extend({
|
|
49470
|
-
subject: TimebackSubject3,
|
|
49471
|
-
grade: TimebackGrade3.
|
|
49565
|
+
subject: TimebackSubject3.meta({ description: "Subject area for this course" }),
|
|
49566
|
+
grade: TimebackGrade3.meta({
|
|
49567
|
+
description: "Grade level (-1 = Pre-K, 0 = K, 1-12 = grades, 13 = AP)"
|
|
49568
|
+
}).optional(),
|
|
49472
49569
|
ids: CourseIds3.nullable().optional(),
|
|
49473
|
-
sensor: exports_external3.
|
|
49474
|
-
launchUrl: exports_external3.
|
|
49570
|
+
sensor: exports_external3.url().meta({ description: "Caliper sensor endpoint URL for this course" }).optional(),
|
|
49571
|
+
launchUrl: exports_external3.url().meta({ description: "LTI launch URL for this course" }).optional(),
|
|
49475
49572
|
overrides: CourseOverrides3.optional()
|
|
49573
|
+
}).meta({
|
|
49574
|
+
id: "CourseConfig",
|
|
49575
|
+
description: "Configuration for a single course. Must have either grade or courseCode (or both)."
|
|
49476
49576
|
});
|
|
49477
49577
|
var TimebackConfig3 = exports_external3.object({
|
|
49478
|
-
|
|
49479
|
-
|
|
49480
|
-
|
|
49481
|
-
|
|
49482
|
-
|
|
49578
|
+
$schema: exports_external3.string().meta({ description: "JSON Schema reference for editor support" }).optional(),
|
|
49579
|
+
name: exports_external3.string().min(1, "App name is required").meta({ description: "Display name for your app" }),
|
|
49580
|
+
defaults: CourseDefaults3.meta({
|
|
49581
|
+
description: "Default properties applied to all courses"
|
|
49582
|
+
}).optional(),
|
|
49583
|
+
courses: exports_external3.array(CourseConfig3).min(1, "At least one course is required").meta({ description: "Courses available in this app" }),
|
|
49584
|
+
sensor: exports_external3.url().meta({ description: "Default Caliper sensor endpoint URL for all courses" }).optional(),
|
|
49585
|
+
launchUrl: exports_external3.url().meta({ description: "Default LTI launch URL for all courses" }).optional()
|
|
49586
|
+
}).meta({
|
|
49587
|
+
id: "TimebackConfig",
|
|
49588
|
+
title: "Timeback Config",
|
|
49589
|
+
description: "Configuration schema for timeback.config.json files"
|
|
49483
49590
|
}).refine((config22) => {
|
|
49484
49591
|
return config22.courses.every((c) => c.grade !== undefined || c.courseCode !== undefined);
|
|
49485
49592
|
}, {
|
|
@@ -49500,14 +49607,20 @@ var TimebackConfig3 = exports_external3.object({
|
|
|
49500
49607
|
message: "Duplicate courseCode found; each must be unique",
|
|
49501
49608
|
path: ["courses"]
|
|
49502
49609
|
}).refine((config22) => {
|
|
49503
|
-
return config22.courses.every((c) =>
|
|
49504
|
-
|
|
49505
|
-
|
|
49506
|
-
|
|
49507
|
-
|
|
49508
|
-
|
|
49610
|
+
return config22.courses.every((c) => {
|
|
49611
|
+
if (c.sensor !== undefined || config22.sensor !== undefined) {
|
|
49612
|
+
return true;
|
|
49613
|
+
}
|
|
49614
|
+
const launchUrls = [
|
|
49615
|
+
c.launchUrl,
|
|
49616
|
+
config22.launchUrl,
|
|
49617
|
+
c.overrides?.staging?.launchUrl,
|
|
49618
|
+
c.overrides?.production?.launchUrl
|
|
49619
|
+
].filter(Boolean);
|
|
49620
|
+
return launchUrls.length > 0;
|
|
49621
|
+
});
|
|
49509
49622
|
}, {
|
|
49510
|
-
message: "Each course must have an effective
|
|
49623
|
+
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.",
|
|
49511
49624
|
path: ["courses"]
|
|
49512
49625
|
});
|
|
49513
49626
|
var EdubridgeDateString3 = exports_external3.union([IsoDateString3, IsoDateTimeString3]);
|
|
@@ -66784,7 +66897,7 @@ var TimebackSubject4 = exports_external4.enum([
|
|
|
66784
66897
|
"Math",
|
|
66785
66898
|
"None",
|
|
66786
66899
|
"Other"
|
|
66787
|
-
]);
|
|
66900
|
+
]).meta({ id: "TimebackSubject", description: "Subject area" });
|
|
66788
66901
|
var TimebackGrade4 = exports_external4.union([
|
|
66789
66902
|
exports_external4.literal(-1),
|
|
66790
66903
|
exports_external4.literal(0),
|
|
@@ -66801,7 +66914,10 @@ var TimebackGrade4 = exports_external4.union([
|
|
|
66801
66914
|
exports_external4.literal(11),
|
|
66802
66915
|
exports_external4.literal(12),
|
|
66803
66916
|
exports_external4.literal(13)
|
|
66804
|
-
])
|
|
66917
|
+
]).meta({
|
|
66918
|
+
id: "TimebackGrade",
|
|
66919
|
+
description: "Grade level (-1 = Pre-K, 0 = K, 1-12 = grades, 13 = AP)"
|
|
66920
|
+
});
|
|
66805
66921
|
var ScoreStatus4 = exports_external4.enum([
|
|
66806
66922
|
"exempt",
|
|
66807
66923
|
"fully graded",
|
|
@@ -67031,62 +67147,84 @@ var CaliperListEventsParams4 = exports_external4.object({
|
|
|
67031
67147
|
actorEmail: exports_external4.email().optional()
|
|
67032
67148
|
}).strict();
|
|
67033
67149
|
var CourseIds4 = exports_external4.object({
|
|
67034
|
-
staging: exports_external4.string().optional(),
|
|
67035
|
-
production: exports_external4.string().optional()
|
|
67036
|
-
});
|
|
67037
|
-
var CourseType4 = exports_external4.enum(["base", "hole-filling", "optional"]);
|
|
67038
|
-
var PublishStatus4 = exports_external4.enum(["draft", "testing", "published", "deactivated"]);
|
|
67150
|
+
staging: exports_external4.string().meta({ description: "Course ID in staging environment" }).optional(),
|
|
67151
|
+
production: exports_external4.string().meta({ description: "Course ID in production environment" }).optional()
|
|
67152
|
+
}).meta({ id: "CourseIds", description: "Environment-specific course IDs (populated by sync)" });
|
|
67153
|
+
var CourseType4 = exports_external4.enum(["base", "hole-filling", "optional"]).meta({ id: "CourseType", description: "Course classification type" });
|
|
67154
|
+
var PublishStatus4 = exports_external4.enum(["draft", "testing", "published", "deactivated"]).meta({ id: "PublishStatus", description: "Course publication status" });
|
|
67039
67155
|
var CourseGoals4 = exports_external4.object({
|
|
67040
|
-
dailyXp: exports_external4.number().int().positive().optional(),
|
|
67041
|
-
dailyLessons: exports_external4.number().int().positive().optional(),
|
|
67042
|
-
dailyActiveMinutes: exports_external4.number().int().positive().optional(),
|
|
67043
|
-
dailyAccuracy: exports_external4.number().int().min(0).max(100).optional(),
|
|
67044
|
-
dailyMasteredUnits: exports_external4.number().int().positive().optional()
|
|
67045
|
-
});
|
|
67156
|
+
dailyXp: exports_external4.number().int().positive().meta({ description: "Target XP to earn per day" }).optional(),
|
|
67157
|
+
dailyLessons: exports_external4.number().int().positive().meta({ description: "Target lessons to complete per day" }).optional(),
|
|
67158
|
+
dailyActiveMinutes: exports_external4.number().int().positive().meta({ description: "Target active learning minutes per day" }).optional(),
|
|
67159
|
+
dailyAccuracy: exports_external4.number().int().min(0).max(100).meta({ description: "Target accuracy percentage (0-100)" }).optional(),
|
|
67160
|
+
dailyMasteredUnits: exports_external4.number().int().positive().meta({ description: "Target units to master per day" }).optional()
|
|
67161
|
+
}).meta({ id: "CourseGoals", description: "Daily learning goals for a course" });
|
|
67046
67162
|
var CourseMetrics4 = exports_external4.object({
|
|
67047
|
-
totalXp: exports_external4.number().int().positive().optional(),
|
|
67048
|
-
totalLessons: exports_external4.number().int().positive().optional(),
|
|
67049
|
-
totalGrades: exports_external4.number().int().positive().optional()
|
|
67050
|
-
});
|
|
67163
|
+
totalXp: exports_external4.number().int().positive().meta({ description: "Total XP available in the course" }).optional(),
|
|
67164
|
+
totalLessons: exports_external4.number().int().positive().meta({ description: "Total number of lessons/activities" }).optional(),
|
|
67165
|
+
totalGrades: exports_external4.number().int().positive().meta({ description: "Total grade levels covered" }).optional()
|
|
67166
|
+
}).meta({ id: "CourseMetrics", description: "Aggregate metrics for a course" });
|
|
67051
67167
|
var CourseMetadata4 = exports_external4.object({
|
|
67052
67168
|
courseType: CourseType4.optional(),
|
|
67053
|
-
isSupplemental: exports_external4.boolean().optional(),
|
|
67054
|
-
isCustom: exports_external4.boolean().optional(),
|
|
67169
|
+
isSupplemental: exports_external4.boolean().meta({ description: "Whether this is supplemental to a base course" }).optional(),
|
|
67170
|
+
isCustom: exports_external4.boolean().meta({ description: "Whether this is a custom course for an individual student" }).optional(),
|
|
67055
67171
|
publishStatus: PublishStatus4.optional(),
|
|
67056
|
-
contactEmail: exports_external4.email().optional(),
|
|
67057
|
-
primaryApp: exports_external4.string().optional(),
|
|
67172
|
+
contactEmail: exports_external4.email().meta({ description: "Contact email for course issues" }).optional(),
|
|
67173
|
+
primaryApp: exports_external4.string().meta({ description: "Primary application identifier" }).optional(),
|
|
67058
67174
|
goals: CourseGoals4.optional(),
|
|
67059
67175
|
metrics: CourseMetrics4.optional()
|
|
67060
|
-
});
|
|
67176
|
+
}).meta({ id: "CourseMetadata", description: "Course metadata (matches API metadata object)" });
|
|
67061
67177
|
var CourseDefaults4 = exports_external4.object({
|
|
67062
|
-
courseCode: exports_external4.string().optional(),
|
|
67063
|
-
level: exports_external4.string().optional(),
|
|
67178
|
+
courseCode: exports_external4.string().meta({ description: "Course code (e.g., 'MATH101')" }).optional(),
|
|
67179
|
+
level: exports_external4.string().meta({ description: "Course level (e.g., 'AP', 'Honors')" }).optional(),
|
|
67064
67180
|
metadata: CourseMetadata4.optional()
|
|
67181
|
+
}).meta({
|
|
67182
|
+
id: "CourseDefaults",
|
|
67183
|
+
description: "Default properties that apply to all courses unless overridden"
|
|
67065
67184
|
});
|
|
67066
67185
|
var CourseEnvOverrides4 = exports_external4.object({
|
|
67067
|
-
level: exports_external4.string().optional(),
|
|
67068
|
-
sensor: exports_external4.
|
|
67069
|
-
launchUrl: exports_external4.
|
|
67186
|
+
level: exports_external4.string().meta({ description: "Course level for this environment" }).optional(),
|
|
67187
|
+
sensor: exports_external4.url().meta({ description: "Caliper sensor endpoint URL for this environment" }).optional(),
|
|
67188
|
+
launchUrl: exports_external4.url().meta({ description: "LTI launch URL for this environment" }).optional(),
|
|
67070
67189
|
metadata: CourseMetadata4.optional()
|
|
67190
|
+
}).meta({
|
|
67191
|
+
id: "CourseEnvOverrides",
|
|
67192
|
+
description: "Environment-specific course overrides (non-identity fields)"
|
|
67071
67193
|
});
|
|
67072
67194
|
var CourseOverrides4 = exports_external4.object({
|
|
67073
|
-
staging: CourseEnvOverrides4.
|
|
67074
|
-
|
|
67075
|
-
})
|
|
67195
|
+
staging: CourseEnvOverrides4.meta({
|
|
67196
|
+
description: "Overrides for staging environment"
|
|
67197
|
+
}).optional(),
|
|
67198
|
+
production: CourseEnvOverrides4.meta({
|
|
67199
|
+
description: "Overrides for production environment"
|
|
67200
|
+
}).optional()
|
|
67201
|
+
}).meta({ id: "CourseOverrides", description: "Per-environment course overrides" });
|
|
67076
67202
|
var CourseConfig4 = CourseDefaults4.extend({
|
|
67077
|
-
subject: TimebackSubject4,
|
|
67078
|
-
grade: TimebackGrade4.
|
|
67203
|
+
subject: TimebackSubject4.meta({ description: "Subject area for this course" }),
|
|
67204
|
+
grade: TimebackGrade4.meta({
|
|
67205
|
+
description: "Grade level (-1 = Pre-K, 0 = K, 1-12 = grades, 13 = AP)"
|
|
67206
|
+
}).optional(),
|
|
67079
67207
|
ids: CourseIds4.nullable().optional(),
|
|
67080
|
-
sensor: exports_external4.
|
|
67081
|
-
launchUrl: exports_external4.
|
|
67208
|
+
sensor: exports_external4.url().meta({ description: "Caliper sensor endpoint URL for this course" }).optional(),
|
|
67209
|
+
launchUrl: exports_external4.url().meta({ description: "LTI launch URL for this course" }).optional(),
|
|
67082
67210
|
overrides: CourseOverrides4.optional()
|
|
67211
|
+
}).meta({
|
|
67212
|
+
id: "CourseConfig",
|
|
67213
|
+
description: "Configuration for a single course. Must have either grade or courseCode (or both)."
|
|
67083
67214
|
});
|
|
67084
67215
|
var TimebackConfig4 = exports_external4.object({
|
|
67085
|
-
|
|
67086
|
-
|
|
67087
|
-
|
|
67088
|
-
|
|
67089
|
-
|
|
67216
|
+
$schema: exports_external4.string().meta({ description: "JSON Schema reference for editor support" }).optional(),
|
|
67217
|
+
name: exports_external4.string().min(1, "App name is required").meta({ description: "Display name for your app" }),
|
|
67218
|
+
defaults: CourseDefaults4.meta({
|
|
67219
|
+
description: "Default properties applied to all courses"
|
|
67220
|
+
}).optional(),
|
|
67221
|
+
courses: exports_external4.array(CourseConfig4).min(1, "At least one course is required").meta({ description: "Courses available in this app" }),
|
|
67222
|
+
sensor: exports_external4.url().meta({ description: "Default Caliper sensor endpoint URL for all courses" }).optional(),
|
|
67223
|
+
launchUrl: exports_external4.url().meta({ description: "Default LTI launch URL for all courses" }).optional()
|
|
67224
|
+
}).meta({
|
|
67225
|
+
id: "TimebackConfig",
|
|
67226
|
+
title: "Timeback Config",
|
|
67227
|
+
description: "Configuration schema for timeback.config.json files"
|
|
67090
67228
|
}).refine((config22) => {
|
|
67091
67229
|
return config22.courses.every((c) => c.grade !== undefined || c.courseCode !== undefined);
|
|
67092
67230
|
}, {
|
|
@@ -67107,14 +67245,20 @@ var TimebackConfig4 = exports_external4.object({
|
|
|
67107
67245
|
message: "Duplicate courseCode found; each must be unique",
|
|
67108
67246
|
path: ["courses"]
|
|
67109
67247
|
}).refine((config22) => {
|
|
67110
|
-
return config22.courses.every((c) =>
|
|
67111
|
-
|
|
67112
|
-
|
|
67113
|
-
|
|
67114
|
-
|
|
67115
|
-
|
|
67248
|
+
return config22.courses.every((c) => {
|
|
67249
|
+
if (c.sensor !== undefined || config22.sensor !== undefined) {
|
|
67250
|
+
return true;
|
|
67251
|
+
}
|
|
67252
|
+
const launchUrls = [
|
|
67253
|
+
c.launchUrl,
|
|
67254
|
+
config22.launchUrl,
|
|
67255
|
+
c.overrides?.staging?.launchUrl,
|
|
67256
|
+
c.overrides?.production?.launchUrl
|
|
67257
|
+
].filter(Boolean);
|
|
67258
|
+
return launchUrls.length > 0;
|
|
67259
|
+
});
|
|
67116
67260
|
}, {
|
|
67117
|
-
message: "Each course must have an effective
|
|
67261
|
+
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.",
|
|
67118
67262
|
path: ["courses"]
|
|
67119
67263
|
});
|
|
67120
67264
|
var EdubridgeDateString4 = exports_external4.union([IsoDateString4, IsoDateTimeString4]);
|
|
@@ -83421,7 +83565,7 @@ var TimebackSubject5 = exports_external5.enum([
|
|
|
83421
83565
|
"Math",
|
|
83422
83566
|
"None",
|
|
83423
83567
|
"Other"
|
|
83424
|
-
]);
|
|
83568
|
+
]).meta({ id: "TimebackSubject", description: "Subject area" });
|
|
83425
83569
|
var TimebackGrade5 = exports_external5.union([
|
|
83426
83570
|
exports_external5.literal(-1),
|
|
83427
83571
|
exports_external5.literal(0),
|
|
@@ -83438,7 +83582,10 @@ var TimebackGrade5 = exports_external5.union([
|
|
|
83438
83582
|
exports_external5.literal(11),
|
|
83439
83583
|
exports_external5.literal(12),
|
|
83440
83584
|
exports_external5.literal(13)
|
|
83441
|
-
])
|
|
83585
|
+
]).meta({
|
|
83586
|
+
id: "TimebackGrade",
|
|
83587
|
+
description: "Grade level (-1 = Pre-K, 0 = K, 1-12 = grades, 13 = AP)"
|
|
83588
|
+
});
|
|
83442
83589
|
var ScoreStatus5 = exports_external5.enum([
|
|
83443
83590
|
"exempt",
|
|
83444
83591
|
"fully graded",
|
|
@@ -83668,62 +83815,84 @@ var CaliperListEventsParams5 = exports_external5.object({
|
|
|
83668
83815
|
actorEmail: exports_external5.email().optional()
|
|
83669
83816
|
}).strict();
|
|
83670
83817
|
var CourseIds5 = exports_external5.object({
|
|
83671
|
-
staging: exports_external5.string().optional(),
|
|
83672
|
-
production: exports_external5.string().optional()
|
|
83673
|
-
});
|
|
83674
|
-
var CourseType5 = exports_external5.enum(["base", "hole-filling", "optional"]);
|
|
83675
|
-
var PublishStatus5 = exports_external5.enum(["draft", "testing", "published", "deactivated"]);
|
|
83818
|
+
staging: exports_external5.string().meta({ description: "Course ID in staging environment" }).optional(),
|
|
83819
|
+
production: exports_external5.string().meta({ description: "Course ID in production environment" }).optional()
|
|
83820
|
+
}).meta({ id: "CourseIds", description: "Environment-specific course IDs (populated by sync)" });
|
|
83821
|
+
var CourseType5 = exports_external5.enum(["base", "hole-filling", "optional"]).meta({ id: "CourseType", description: "Course classification type" });
|
|
83822
|
+
var PublishStatus5 = exports_external5.enum(["draft", "testing", "published", "deactivated"]).meta({ id: "PublishStatus", description: "Course publication status" });
|
|
83676
83823
|
var CourseGoals5 = exports_external5.object({
|
|
83677
|
-
dailyXp: exports_external5.number().int().positive().optional(),
|
|
83678
|
-
dailyLessons: exports_external5.number().int().positive().optional(),
|
|
83679
|
-
dailyActiveMinutes: exports_external5.number().int().positive().optional(),
|
|
83680
|
-
dailyAccuracy: exports_external5.number().int().min(0).max(100).optional(),
|
|
83681
|
-
dailyMasteredUnits: exports_external5.number().int().positive().optional()
|
|
83682
|
-
});
|
|
83824
|
+
dailyXp: exports_external5.number().int().positive().meta({ description: "Target XP to earn per day" }).optional(),
|
|
83825
|
+
dailyLessons: exports_external5.number().int().positive().meta({ description: "Target lessons to complete per day" }).optional(),
|
|
83826
|
+
dailyActiveMinutes: exports_external5.number().int().positive().meta({ description: "Target active learning minutes per day" }).optional(),
|
|
83827
|
+
dailyAccuracy: exports_external5.number().int().min(0).max(100).meta({ description: "Target accuracy percentage (0-100)" }).optional(),
|
|
83828
|
+
dailyMasteredUnits: exports_external5.number().int().positive().meta({ description: "Target units to master per day" }).optional()
|
|
83829
|
+
}).meta({ id: "CourseGoals", description: "Daily learning goals for a course" });
|
|
83683
83830
|
var CourseMetrics5 = exports_external5.object({
|
|
83684
|
-
totalXp: exports_external5.number().int().positive().optional(),
|
|
83685
|
-
totalLessons: exports_external5.number().int().positive().optional(),
|
|
83686
|
-
totalGrades: exports_external5.number().int().positive().optional()
|
|
83687
|
-
});
|
|
83831
|
+
totalXp: exports_external5.number().int().positive().meta({ description: "Total XP available in the course" }).optional(),
|
|
83832
|
+
totalLessons: exports_external5.number().int().positive().meta({ description: "Total number of lessons/activities" }).optional(),
|
|
83833
|
+
totalGrades: exports_external5.number().int().positive().meta({ description: "Total grade levels covered" }).optional()
|
|
83834
|
+
}).meta({ id: "CourseMetrics", description: "Aggregate metrics for a course" });
|
|
83688
83835
|
var CourseMetadata5 = exports_external5.object({
|
|
83689
83836
|
courseType: CourseType5.optional(),
|
|
83690
|
-
isSupplemental: exports_external5.boolean().optional(),
|
|
83691
|
-
isCustom: exports_external5.boolean().optional(),
|
|
83837
|
+
isSupplemental: exports_external5.boolean().meta({ description: "Whether this is supplemental to a base course" }).optional(),
|
|
83838
|
+
isCustom: exports_external5.boolean().meta({ description: "Whether this is a custom course for an individual student" }).optional(),
|
|
83692
83839
|
publishStatus: PublishStatus5.optional(),
|
|
83693
|
-
contactEmail: exports_external5.email().optional(),
|
|
83694
|
-
primaryApp: exports_external5.string().optional(),
|
|
83840
|
+
contactEmail: exports_external5.email().meta({ description: "Contact email for course issues" }).optional(),
|
|
83841
|
+
primaryApp: exports_external5.string().meta({ description: "Primary application identifier" }).optional(),
|
|
83695
83842
|
goals: CourseGoals5.optional(),
|
|
83696
83843
|
metrics: CourseMetrics5.optional()
|
|
83697
|
-
});
|
|
83844
|
+
}).meta({ id: "CourseMetadata", description: "Course metadata (matches API metadata object)" });
|
|
83698
83845
|
var CourseDefaults5 = exports_external5.object({
|
|
83699
|
-
courseCode: exports_external5.string().optional(),
|
|
83700
|
-
level: exports_external5.string().optional(),
|
|
83846
|
+
courseCode: exports_external5.string().meta({ description: "Course code (e.g., 'MATH101')" }).optional(),
|
|
83847
|
+
level: exports_external5.string().meta({ description: "Course level (e.g., 'AP', 'Honors')" }).optional(),
|
|
83701
83848
|
metadata: CourseMetadata5.optional()
|
|
83849
|
+
}).meta({
|
|
83850
|
+
id: "CourseDefaults",
|
|
83851
|
+
description: "Default properties that apply to all courses unless overridden"
|
|
83702
83852
|
});
|
|
83703
83853
|
var CourseEnvOverrides5 = exports_external5.object({
|
|
83704
|
-
level: exports_external5.string().optional(),
|
|
83705
|
-
sensor: exports_external5.
|
|
83706
|
-
launchUrl: exports_external5.
|
|
83854
|
+
level: exports_external5.string().meta({ description: "Course level for this environment" }).optional(),
|
|
83855
|
+
sensor: exports_external5.url().meta({ description: "Caliper sensor endpoint URL for this environment" }).optional(),
|
|
83856
|
+
launchUrl: exports_external5.url().meta({ description: "LTI launch URL for this environment" }).optional(),
|
|
83707
83857
|
metadata: CourseMetadata5.optional()
|
|
83858
|
+
}).meta({
|
|
83859
|
+
id: "CourseEnvOverrides",
|
|
83860
|
+
description: "Environment-specific course overrides (non-identity fields)"
|
|
83708
83861
|
});
|
|
83709
83862
|
var CourseOverrides5 = exports_external5.object({
|
|
83710
|
-
staging: CourseEnvOverrides5.
|
|
83711
|
-
|
|
83712
|
-
})
|
|
83863
|
+
staging: CourseEnvOverrides5.meta({
|
|
83864
|
+
description: "Overrides for staging environment"
|
|
83865
|
+
}).optional(),
|
|
83866
|
+
production: CourseEnvOverrides5.meta({
|
|
83867
|
+
description: "Overrides for production environment"
|
|
83868
|
+
}).optional()
|
|
83869
|
+
}).meta({ id: "CourseOverrides", description: "Per-environment course overrides" });
|
|
83713
83870
|
var CourseConfig5 = CourseDefaults5.extend({
|
|
83714
|
-
subject: TimebackSubject5,
|
|
83715
|
-
grade: TimebackGrade5.
|
|
83871
|
+
subject: TimebackSubject5.meta({ description: "Subject area for this course" }),
|
|
83872
|
+
grade: TimebackGrade5.meta({
|
|
83873
|
+
description: "Grade level (-1 = Pre-K, 0 = K, 1-12 = grades, 13 = AP)"
|
|
83874
|
+
}).optional(),
|
|
83716
83875
|
ids: CourseIds5.nullable().optional(),
|
|
83717
|
-
sensor: exports_external5.
|
|
83718
|
-
launchUrl: exports_external5.
|
|
83876
|
+
sensor: exports_external5.url().meta({ description: "Caliper sensor endpoint URL for this course" }).optional(),
|
|
83877
|
+
launchUrl: exports_external5.url().meta({ description: "LTI launch URL for this course" }).optional(),
|
|
83719
83878
|
overrides: CourseOverrides5.optional()
|
|
83879
|
+
}).meta({
|
|
83880
|
+
id: "CourseConfig",
|
|
83881
|
+
description: "Configuration for a single course. Must have either grade or courseCode (or both)."
|
|
83720
83882
|
});
|
|
83721
83883
|
var TimebackConfig5 = exports_external5.object({
|
|
83722
|
-
|
|
83723
|
-
|
|
83724
|
-
|
|
83725
|
-
|
|
83726
|
-
|
|
83884
|
+
$schema: exports_external5.string().meta({ description: "JSON Schema reference for editor support" }).optional(),
|
|
83885
|
+
name: exports_external5.string().min(1, "App name is required").meta({ description: "Display name for your app" }),
|
|
83886
|
+
defaults: CourseDefaults5.meta({
|
|
83887
|
+
description: "Default properties applied to all courses"
|
|
83888
|
+
}).optional(),
|
|
83889
|
+
courses: exports_external5.array(CourseConfig5).min(1, "At least one course is required").meta({ description: "Courses available in this app" }),
|
|
83890
|
+
sensor: exports_external5.url().meta({ description: "Default Caliper sensor endpoint URL for all courses" }).optional(),
|
|
83891
|
+
launchUrl: exports_external5.url().meta({ description: "Default LTI launch URL for all courses" }).optional()
|
|
83892
|
+
}).meta({
|
|
83893
|
+
id: "TimebackConfig",
|
|
83894
|
+
title: "Timeback Config",
|
|
83895
|
+
description: "Configuration schema for timeback.config.json files"
|
|
83727
83896
|
}).refine((config22) => {
|
|
83728
83897
|
return config22.courses.every((c) => c.grade !== undefined || c.courseCode !== undefined);
|
|
83729
83898
|
}, {
|
|
@@ -83744,14 +83913,20 @@ var TimebackConfig5 = exports_external5.object({
|
|
|
83744
83913
|
message: "Duplicate courseCode found; each must be unique",
|
|
83745
83914
|
path: ["courses"]
|
|
83746
83915
|
}).refine((config22) => {
|
|
83747
|
-
return config22.courses.every((c) =>
|
|
83748
|
-
|
|
83749
|
-
|
|
83750
|
-
|
|
83751
|
-
|
|
83752
|
-
|
|
83916
|
+
return config22.courses.every((c) => {
|
|
83917
|
+
if (c.sensor !== undefined || config22.sensor !== undefined) {
|
|
83918
|
+
return true;
|
|
83919
|
+
}
|
|
83920
|
+
const launchUrls = [
|
|
83921
|
+
c.launchUrl,
|
|
83922
|
+
config22.launchUrl,
|
|
83923
|
+
c.overrides?.staging?.launchUrl,
|
|
83924
|
+
c.overrides?.production?.launchUrl
|
|
83925
|
+
].filter(Boolean);
|
|
83926
|
+
return launchUrls.length > 0;
|
|
83927
|
+
});
|
|
83753
83928
|
}, {
|
|
83754
|
-
message: "Each course must have an effective
|
|
83929
|
+
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.",
|
|
83755
83930
|
path: ["courses"]
|
|
83756
83931
|
});
|
|
83757
83932
|
var EdubridgeDateString5 = exports_external5.union([IsoDateString5, IsoDateTimeString5]);
|
|
@@ -85509,163 +85684,6 @@ async function lookupTimebackIdByEmail(params) {
|
|
|
85509
85684
|
throw new TimebackUserResolutionError(`Failed to lookup Timeback user: ${message}`, "timeback_user_lookup_failed");
|
|
85510
85685
|
}
|
|
85511
85686
|
}
|
|
85512
|
-
|
|
85513
|
-
class ActivityCourseResolutionError extends Error {
|
|
85514
|
-
code;
|
|
85515
|
-
selector;
|
|
85516
|
-
count;
|
|
85517
|
-
constructor(code, selector, count) {
|
|
85518
|
-
super(code);
|
|
85519
|
-
this.code = code;
|
|
85520
|
-
this.selector = selector;
|
|
85521
|
-
this.count = count;
|
|
85522
|
-
}
|
|
85523
|
-
get selectorDescription() {
|
|
85524
|
-
if ("grade" in this.selector) {
|
|
85525
|
-
return `${this.selector.subject} grade ${this.selector.grade}`;
|
|
85526
|
-
}
|
|
85527
|
-
return `code "${this.selector.code}"`;
|
|
85528
|
-
}
|
|
85529
|
-
}
|
|
85530
|
-
function resolveActivityCourse(courses, courseRef) {
|
|
85531
|
-
let matches;
|
|
85532
|
-
if ("grade" in courseRef) {
|
|
85533
|
-
matches = courses.filter((c) => c.subject === courseRef.subject && c.grade === courseRef.grade);
|
|
85534
|
-
} else {
|
|
85535
|
-
matches = courses.filter((c) => c.courseCode === courseRef.code);
|
|
85536
|
-
}
|
|
85537
|
-
if (matches.length === 0) {
|
|
85538
|
-
throw new ActivityCourseResolutionError("unknown_course", courseRef);
|
|
85539
|
-
}
|
|
85540
|
-
if (matches.length > 1) {
|
|
85541
|
-
throw new ActivityCourseResolutionError("ambiguous_course", courseRef, matches.length);
|
|
85542
|
-
}
|
|
85543
|
-
return matches[0];
|
|
85544
|
-
}
|
|
85545
|
-
// src/server/lib/build-activity-events.ts
|
|
85546
|
-
class MissingSyncedCourseIdError extends Error {
|
|
85547
|
-
course;
|
|
85548
|
-
env;
|
|
85549
|
-
constructor(course, env) {
|
|
85550
|
-
const identifier = course.grade === undefined ? course.courseCode ?? course.subject : `${course.subject} grade ${course.grade}`;
|
|
85551
|
-
super(`Course "${identifier}" is missing a synced ID for ${env}. Run \`timeback sync\` first.`);
|
|
85552
|
-
this.name = "MissingSyncedCourseIdError";
|
|
85553
|
-
this.course = course;
|
|
85554
|
-
this.env = env;
|
|
85555
|
-
}
|
|
85556
|
-
}
|
|
85557
|
-
function buildCourseId(course, apiEnv) {
|
|
85558
|
-
const courseId = course.ids?.[apiEnv];
|
|
85559
|
-
if (!courseId) {
|
|
85560
|
-
throw new MissingSyncedCourseIdError(course, apiEnv);
|
|
85561
|
-
}
|
|
85562
|
-
return courseId;
|
|
85563
|
-
}
|
|
85564
|
-
function buildCourseName(course) {
|
|
85565
|
-
if (course.courseCode) {
|
|
85566
|
-
return course.courseCode;
|
|
85567
|
-
}
|
|
85568
|
-
if (course.grade !== undefined) {
|
|
85569
|
-
return `${course.subject} G${String(course.grade)}`;
|
|
85570
|
-
}
|
|
85571
|
-
return course.subject;
|
|
85572
|
-
}
|
|
85573
|
-
|
|
85574
|
-
class InvalidSensorUrlError extends Error {
|
|
85575
|
-
sensor;
|
|
85576
|
-
constructor(sensor) {
|
|
85577
|
-
super(`Invalid sensor URL "${sensor}". Sensor must be a valid absolute URL (e.g., "https://sensor.example.com") to support slug-based activity IDs.`);
|
|
85578
|
-
this.name = "InvalidSensorUrlError";
|
|
85579
|
-
this.sensor = sensor;
|
|
85580
|
-
}
|
|
85581
|
-
}
|
|
85582
|
-
function buildCanonicalActivityUrl(sensor, selector, slug) {
|
|
85583
|
-
let base;
|
|
85584
|
-
try {
|
|
85585
|
-
base = new URL(sensor);
|
|
85586
|
-
} catch {
|
|
85587
|
-
throw new InvalidSensorUrlError(sensor);
|
|
85588
|
-
}
|
|
85589
|
-
const pathSegment = "grade" in selector ? `${selector.subject}/g${String(selector.grade)}` : selector.code;
|
|
85590
|
-
const basePath = base.pathname.replace(/\/+$/, "");
|
|
85591
|
-
base.pathname = `${basePath}/activities/${pathSegment}/${encodeURIComponent(slug)}`;
|
|
85592
|
-
return base.toString();
|
|
85593
|
-
}
|
|
85594
|
-
function buildActivityContext(payload, course, appName, apiEnv, sensor) {
|
|
85595
|
-
return {
|
|
85596
|
-
id: buildCanonicalActivityUrl(sensor, payload.course, payload.id),
|
|
85597
|
-
type: "TimebackActivityContext",
|
|
85598
|
-
subject: course.subject,
|
|
85599
|
-
app: { name: appName },
|
|
85600
|
-
activity: { name: payload.name },
|
|
85601
|
-
course: {
|
|
85602
|
-
id: buildCourseId(course, apiEnv),
|
|
85603
|
-
name: buildCourseName(course)
|
|
85604
|
-
}
|
|
85605
|
-
};
|
|
85606
|
-
}
|
|
85607
|
-
function buildActivityMetrics(metrics) {
|
|
85608
|
-
const result = [];
|
|
85609
|
-
if (metrics.totalQuestions !== undefined) {
|
|
85610
|
-
result.push({ type: "totalQuestions", value: metrics.totalQuestions });
|
|
85611
|
-
}
|
|
85612
|
-
if (metrics.correctQuestions !== undefined) {
|
|
85613
|
-
result.push({ type: "correctQuestions", value: metrics.correctQuestions });
|
|
85614
|
-
}
|
|
85615
|
-
if (metrics.xpEarned !== undefined) {
|
|
85616
|
-
result.push({ type: "xpEarned", value: metrics.xpEarned });
|
|
85617
|
-
}
|
|
85618
|
-
if (metrics.masteredUnits !== undefined) {
|
|
85619
|
-
result.push({ type: "masteredUnits", value: metrics.masteredUnits });
|
|
85620
|
-
}
|
|
85621
|
-
return result;
|
|
85622
|
-
}
|
|
85623
|
-
function buildTimeSpentMetrics(elapsedMs, pausedMs) {
|
|
85624
|
-
const result = [{ type: "active", value: Math.max(0, elapsedMs) / 1000 }];
|
|
85625
|
-
if (pausedMs > 0) {
|
|
85626
|
-
result.push({ type: "inactive", value: Math.max(0, pausedMs) / 1000 });
|
|
85627
|
-
}
|
|
85628
|
-
return result;
|
|
85629
|
-
}
|
|
85630
|
-
async function sendCaliperEnvelope(client, sensor, activityEvent, timeSpentEvent) {
|
|
85631
|
-
await client.caliper.events.send(sensor, [activityEvent, timeSpentEvent]);
|
|
85632
|
-
}
|
|
85633
|
-
// src/server/lib/build-user-profile.ts
|
|
85634
|
-
function buildCourseLookup(courses, apiEnv) {
|
|
85635
|
-
const courseById = new Map;
|
|
85636
|
-
for (const course of courses) {
|
|
85637
|
-
const courseId = course.ids?.[apiEnv];
|
|
85638
|
-
if (courseId) {
|
|
85639
|
-
courseById.set(courseId, course);
|
|
85640
|
-
}
|
|
85641
|
-
}
|
|
85642
|
-
return courseById;
|
|
85643
|
-
}
|
|
85644
|
-
function mapEnrollmentsToCourses(enrollments, courseById) {
|
|
85645
|
-
return enrollments.map((enrollment) => {
|
|
85646
|
-
const configuredCourse = courseById.get(enrollment.course.id);
|
|
85647
|
-
return {
|
|
85648
|
-
id: enrollment.course.id,
|
|
85649
|
-
code: configuredCourse?.courseCode ?? enrollment.course.id,
|
|
85650
|
-
name: enrollment.course.title
|
|
85651
|
-
};
|
|
85652
|
-
});
|
|
85653
|
-
}
|
|
85654
|
-
function pickGoalsFromEnrollments(enrollments) {
|
|
85655
|
-
return enrollments.map((enrollment) => enrollment.metadata?.goals).find(Boolean);
|
|
85656
|
-
}
|
|
85657
|
-
function getUtcDayRange(date6) {
|
|
85658
|
-
const start = new Date(Date.UTC(date6.getUTCFullYear(), date6.getUTCMonth(), date6.getUTCDate()));
|
|
85659
|
-
const end = new Date(Date.UTC(date6.getUTCFullYear(), date6.getUTCMonth(), date6.getUTCDate(), 23, 59, 59, 999));
|
|
85660
|
-
return { start, end };
|
|
85661
|
-
}
|
|
85662
|
-
function sumXp(facts) {
|
|
85663
|
-
return Object.values(facts).reduce((dateTotal, subjects) => {
|
|
85664
|
-
return dateTotal + Object.values(subjects).reduce((subjectTotal, metrics) => {
|
|
85665
|
-
return subjectTotal + (metrics.activityMetrics?.xpEarned ?? 0);
|
|
85666
|
-
}, 0);
|
|
85667
|
-
}, 0);
|
|
85668
|
-
}
|
|
85669
85687
|
// src/shared/constants.ts
|
|
85670
85688
|
var ROUTES = {
|
|
85671
85689
|
ACTIVITY: "/activity",
|
|
@@ -85675,10 +85693,83 @@ var ROUTES = {
|
|
|
85675
85693
|
CALLBACK: "/identity/callback"
|
|
85676
85694
|
},
|
|
85677
85695
|
USER: {
|
|
85678
|
-
ME: "/user/me"
|
|
85696
|
+
ME: "/user/me",
|
|
85697
|
+
VERIFY: "/user/verify"
|
|
85679
85698
|
}
|
|
85680
85699
|
};
|
|
85681
85700
|
|
|
85701
|
+
// src/server/lib/sso.ts
|
|
85702
|
+
function buildErrorContext(error57, errorCode, state, req) {
|
|
85703
|
+
return {
|
|
85704
|
+
error: error57,
|
|
85705
|
+
errorCode,
|
|
85706
|
+
state,
|
|
85707
|
+
req,
|
|
85708
|
+
redirect: redirectResponse,
|
|
85709
|
+
json: jsonResponse
|
|
85710
|
+
};
|
|
85711
|
+
}
|
|
85712
|
+
function tryDecodeState(stateParam) {
|
|
85713
|
+
try {
|
|
85714
|
+
return decodeBase64Url(stateParam);
|
|
85715
|
+
} catch {
|
|
85716
|
+
ssoLog.warn("Failed to decode state");
|
|
85717
|
+
return;
|
|
85718
|
+
}
|
|
85719
|
+
}
|
|
85720
|
+
function handleIdpError(errorParam, url6, state, req, onCallbackError) {
|
|
85721
|
+
const errorDesc = url6.searchParams.get("error_description");
|
|
85722
|
+
ssoLog.error("IdP returned error", { error: errorParam, description: errorDesc });
|
|
85723
|
+
const error57 = new Error(errorDesc ?? errorParam);
|
|
85724
|
+
if (onCallbackError) {
|
|
85725
|
+
return onCallbackError(buildErrorContext(error57, errorParam, state, req));
|
|
85726
|
+
}
|
|
85727
|
+
return jsonResponse({ error: errorParam }, 400);
|
|
85728
|
+
}
|
|
85729
|
+
function handleMissingCode(state, req, onCallbackError) {
|
|
85730
|
+
ssoLog.error("Missing authorization code in callback");
|
|
85731
|
+
const error57 = new Error("Missing authorization code");
|
|
85732
|
+
if (onCallbackError) {
|
|
85733
|
+
return onCallbackError(buildErrorContext(error57, "missing_code", state, req));
|
|
85734
|
+
}
|
|
85735
|
+
return jsonResponse({ error: "Missing authorization code" }, 400);
|
|
85736
|
+
}
|
|
85737
|
+
async function initiateSignIn(params) {
|
|
85738
|
+
const { req, env, clientId, buildState } = params;
|
|
85739
|
+
const issuer = params.issuer ?? getIssuer(env);
|
|
85740
|
+
const url6 = new URL(req.url);
|
|
85741
|
+
let redirectUri = params.redirectUri;
|
|
85742
|
+
if (!redirectUri) {
|
|
85743
|
+
const basePath = url6.pathname.replace(ROUTES.IDENTITY.SIGNIN, "");
|
|
85744
|
+
redirectUri = `${url6.origin}${basePath}${ROUTES.IDENTITY.CALLBACK}`;
|
|
85745
|
+
}
|
|
85746
|
+
ssoLog.debug("SSO sign-in initiated", { env, issuer, clientId, redirectUri });
|
|
85747
|
+
const stateData = buildState ? buildState({ req, url: url6 }) : {};
|
|
85748
|
+
const state = encodeBase64Url(stateData);
|
|
85749
|
+
const authUrl = await buildAuthorizationUrl({
|
|
85750
|
+
issuer,
|
|
85751
|
+
clientId,
|
|
85752
|
+
redirectUri,
|
|
85753
|
+
state
|
|
85754
|
+
});
|
|
85755
|
+
return redirectResponse(authUrl);
|
|
85756
|
+
}
|
|
85757
|
+
function parseCallback(req) {
|
|
85758
|
+
const url6 = new URL(req.url);
|
|
85759
|
+
const code = url6.searchParams.get("code");
|
|
85760
|
+
const errorParam = url6.searchParams.get("error");
|
|
85761
|
+
const stateParam = url6.searchParams.get("state");
|
|
85762
|
+
ssoLog.debug("Received callback from IdP", { hasCode: !!code, error: errorParam });
|
|
85763
|
+
const state = stateParam ? tryDecodeState(stateParam) : undefined;
|
|
85764
|
+
return { url: url6, code, errorParam, state };
|
|
85765
|
+
}
|
|
85766
|
+
function computeRedirectUri(url6, configuredRedirectUri) {
|
|
85767
|
+
if (configuredRedirectUri) {
|
|
85768
|
+
return configuredRedirectUri;
|
|
85769
|
+
}
|
|
85770
|
+
const basePath = url6.pathname.replace(ROUTES.IDENTITY.CALLBACK, "");
|
|
85771
|
+
return `${url6.origin}${basePath}${ROUTES.IDENTITY.CALLBACK}`;
|
|
85772
|
+
}
|
|
85682
85773
|
// src/server/adapters/utils.ts
|
|
85683
85774
|
function normalizePathname(path) {
|
|
85684
85775
|
const raw = path.trim();
|
|
@@ -85728,6 +85819,8 @@ function matchTimebackRoute(params) {
|
|
|
85728
85819
|
return "identity.signOut";
|
|
85729
85820
|
if (relative === ROUTES.USER.ME)
|
|
85730
85821
|
return "user.me";
|
|
85822
|
+
if (relative === ROUTES.USER.VERIFY)
|
|
85823
|
+
return "user.verify";
|
|
85731
85824
|
}
|
|
85732
85825
|
if (method === "POST") {
|
|
85733
85826
|
if (relative === ROUTES.ACTIVITY)
|
|
@@ -85753,6 +85846,8 @@ function matchTimebackRoute(params) {
|
|
|
85753
85846
|
return "identity.signOut";
|
|
85754
85847
|
if (pathname.endsWith(ROUTES.USER.ME))
|
|
85755
85848
|
return "user.me";
|
|
85849
|
+
if (pathname.endsWith(ROUTES.USER.VERIFY))
|
|
85850
|
+
return "user.verify";
|
|
85756
85851
|
}
|
|
85757
85852
|
if (method === "POST") {
|
|
85758
85853
|
if (pathname.endsWith(ROUTES.ACTIVITY))
|
|
@@ -85888,6 +85983,11 @@ async function nuxtHandler(options) {
|
|
|
85888
85983
|
return;
|
|
85889
85984
|
return handle.user.me(request);
|
|
85890
85985
|
}
|
|
85986
|
+
if (route === "user.verify") {
|
|
85987
|
+
if (!hasUserHandler(handle))
|
|
85988
|
+
return;
|
|
85989
|
+
return handle.user.verify(request);
|
|
85990
|
+
}
|
|
85891
85991
|
if (route === "activity") {
|
|
85892
85992
|
if (!hasActivityHandler(handle))
|
|
85893
85993
|
return;
|
|
@@ -85917,6 +86017,11 @@ function toNuxtHandler(input) {
|
|
|
85917
86017
|
return jsonResponse({ error: "Not found" }, 404);
|
|
85918
86018
|
return handle.user.me(request);
|
|
85919
86019
|
}
|
|
86020
|
+
if (route === "user.verify") {
|
|
86021
|
+
if (!hasUserHandler(handle))
|
|
86022
|
+
return jsonResponse({ error: "Not found" }, 404);
|
|
86023
|
+
return handle.user.verify(request);
|
|
86024
|
+
}
|
|
85920
86025
|
if (route === "activity") {
|
|
85921
86026
|
if (!hasActivityHandler(handle))
|
|
85922
86027
|
return jsonResponse({ error: "Not found" }, 404);
|