@timeback/sdk 0.1.6 → 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/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.js +85291 -169
- package/dist/identity.js +85186 -74
- package/dist/index.js +773 -493
- package/dist/server/adapters/express.d.ts.map +1 -1
- package/dist/server/adapters/express.js +169 -193
- 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 +173 -193
- package/dist/server/adapters/solid-start.d.ts.map +1 -1
- package/dist/server/adapters/solid-start.js +173 -193
- 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 +168 -193
- 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.map +1 -1
- package/dist/server/timeback.d.ts.map +1 -1
- package/dist/server/types.d.ts +16 -9
- 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 +15 -0
- package/dist/shared/types.d.ts.map +1 -1
- package/package.json +6 -2
- 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
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"express.d.ts","sourceRoot":"","sources":["../../../src/server/adapters/express.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAKH,OAAO,KAAK,EACX,gBAAgB,EAChB,kBAAkB,EAIlB,iBAAiB,EACjB,MAAM,SAAS,CAAA;AA6FhB;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AACH,wBAAgB,mBAAmB,CAAC,KAAK,EAAE,gBAAgB,GAAG,kBAAkB,
|
|
1
|
+
{"version":3,"file":"express.d.ts","sourceRoot":"","sources":["../../../src/server/adapters/express.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAKH,OAAO,KAAK,EACX,gBAAgB,EAChB,kBAAkB,EAIlB,iBAAiB,EACjB,MAAM,SAAS,CAAA;AA6FhB;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AACH,wBAAgB,mBAAmB,CAAC,KAAK,EAAE,gBAAgB,GAAG,kBAAkB,CAiD/E;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AACH,wBAAgB,kBAAkB,CAAC,KAAK,EAAE,gBAAgB,EAAE,MAAM,EAAE,iBAAiB,GAAG,IAAI,CA6D3F"}
|
|
@@ -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");
|
|
@@ -15739,14 +15759,20 @@ var TimebackConfig = exports_external.object({
|
|
|
15739
15759
|
message: "Duplicate courseCode found; each must be unique",
|
|
15740
15760
|
path: ["courses"]
|
|
15741
15761
|
}).refine((config2) => {
|
|
15742
|
-
return config2.courses.every((c) =>
|
|
15743
|
-
|
|
15744
|
-
|
|
15745
|
-
|
|
15746
|
-
|
|
15747
|
-
|
|
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
|
+
});
|
|
15748
15774
|
}, {
|
|
15749
|
-
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.",
|
|
15750
15776
|
path: ["courses"]
|
|
15751
15777
|
});
|
|
15752
15778
|
var EdubridgeDateString = exports_external.union([IsoDateString, IsoDateTimeString]);
|
|
@@ -32142,14 +32168,20 @@ var TimebackConfig2 = exports_external2.object({
|
|
|
32142
32168
|
message: "Duplicate courseCode found; each must be unique",
|
|
32143
32169
|
path: ["courses"]
|
|
32144
32170
|
}).refine((config22) => {
|
|
32145
|
-
return config22.courses.every((c) =>
|
|
32146
|
-
|
|
32147
|
-
|
|
32148
|
-
|
|
32149
|
-
|
|
32150
|
-
|
|
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
|
+
});
|
|
32151
32183
|
}, {
|
|
32152
|
-
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.",
|
|
32153
32185
|
path: ["courses"]
|
|
32154
32186
|
});
|
|
32155
32187
|
var EdubridgeDateString2 = exports_external2.union([IsoDateString2, IsoDateTimeString2]);
|
|
@@ -49575,14 +49607,20 @@ var TimebackConfig3 = exports_external3.object({
|
|
|
49575
49607
|
message: "Duplicate courseCode found; each must be unique",
|
|
49576
49608
|
path: ["courses"]
|
|
49577
49609
|
}).refine((config22) => {
|
|
49578
|
-
return config22.courses.every((c) =>
|
|
49579
|
-
|
|
49580
|
-
|
|
49581
|
-
|
|
49582
|
-
|
|
49583
|
-
|
|
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
|
+
});
|
|
49584
49622
|
}, {
|
|
49585
|
-
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.",
|
|
49586
49624
|
path: ["courses"]
|
|
49587
49625
|
});
|
|
49588
49626
|
var EdubridgeDateString3 = exports_external3.union([IsoDateString3, IsoDateTimeString3]);
|
|
@@ -67207,14 +67245,20 @@ var TimebackConfig4 = exports_external4.object({
|
|
|
67207
67245
|
message: "Duplicate courseCode found; each must be unique",
|
|
67208
67246
|
path: ["courses"]
|
|
67209
67247
|
}).refine((config22) => {
|
|
67210
|
-
return config22.courses.every((c) =>
|
|
67211
|
-
|
|
67212
|
-
|
|
67213
|
-
|
|
67214
|
-
|
|
67215
|
-
|
|
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
|
+
});
|
|
67216
67260
|
}, {
|
|
67217
|
-
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.",
|
|
67218
67262
|
path: ["courses"]
|
|
67219
67263
|
});
|
|
67220
67264
|
var EdubridgeDateString4 = exports_external4.union([IsoDateString4, IsoDateTimeString4]);
|
|
@@ -83869,14 +83913,20 @@ var TimebackConfig5 = exports_external5.object({
|
|
|
83869
83913
|
message: "Duplicate courseCode found; each must be unique",
|
|
83870
83914
|
path: ["courses"]
|
|
83871
83915
|
}).refine((config22) => {
|
|
83872
|
-
return config22.courses.every((c) =>
|
|
83873
|
-
|
|
83874
|
-
|
|
83875
|
-
|
|
83876
|
-
|
|
83877
|
-
|
|
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
|
+
});
|
|
83878
83928
|
}, {
|
|
83879
|
-
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.",
|
|
83880
83930
|
path: ["courses"]
|
|
83881
83931
|
});
|
|
83882
83932
|
var EdubridgeDateString5 = exports_external5.union([IsoDateString5, IsoDateTimeString5]);
|
|
@@ -85634,163 +85684,6 @@ async function lookupTimebackIdByEmail(params) {
|
|
|
85634
85684
|
throw new TimebackUserResolutionError(`Failed to lookup Timeback user: ${message}`, "timeback_user_lookup_failed");
|
|
85635
85685
|
}
|
|
85636
85686
|
}
|
|
85637
|
-
|
|
85638
|
-
class ActivityCourseResolutionError extends Error {
|
|
85639
|
-
code;
|
|
85640
|
-
selector;
|
|
85641
|
-
count;
|
|
85642
|
-
constructor(code, selector, count) {
|
|
85643
|
-
super(code);
|
|
85644
|
-
this.code = code;
|
|
85645
|
-
this.selector = selector;
|
|
85646
|
-
this.count = count;
|
|
85647
|
-
}
|
|
85648
|
-
get selectorDescription() {
|
|
85649
|
-
if ("grade" in this.selector) {
|
|
85650
|
-
return `${this.selector.subject} grade ${this.selector.grade}`;
|
|
85651
|
-
}
|
|
85652
|
-
return `code "${this.selector.code}"`;
|
|
85653
|
-
}
|
|
85654
|
-
}
|
|
85655
|
-
function resolveActivityCourse(courses, courseRef) {
|
|
85656
|
-
let matches;
|
|
85657
|
-
if ("grade" in courseRef) {
|
|
85658
|
-
matches = courses.filter((c) => c.subject === courseRef.subject && c.grade === courseRef.grade);
|
|
85659
|
-
} else {
|
|
85660
|
-
matches = courses.filter((c) => c.courseCode === courseRef.code);
|
|
85661
|
-
}
|
|
85662
|
-
if (matches.length === 0) {
|
|
85663
|
-
throw new ActivityCourseResolutionError("unknown_course", courseRef);
|
|
85664
|
-
}
|
|
85665
|
-
if (matches.length > 1) {
|
|
85666
|
-
throw new ActivityCourseResolutionError("ambiguous_course", courseRef, matches.length);
|
|
85667
|
-
}
|
|
85668
|
-
return matches[0];
|
|
85669
|
-
}
|
|
85670
|
-
// src/server/lib/build-activity-events.ts
|
|
85671
|
-
class MissingSyncedCourseIdError extends Error {
|
|
85672
|
-
course;
|
|
85673
|
-
env;
|
|
85674
|
-
constructor(course, env) {
|
|
85675
|
-
const identifier = course.grade === undefined ? course.courseCode ?? course.subject : `${course.subject} grade ${course.grade}`;
|
|
85676
|
-
super(`Course "${identifier}" is missing a synced ID for ${env}. Run \`timeback sync\` first.`);
|
|
85677
|
-
this.name = "MissingSyncedCourseIdError";
|
|
85678
|
-
this.course = course;
|
|
85679
|
-
this.env = env;
|
|
85680
|
-
}
|
|
85681
|
-
}
|
|
85682
|
-
function buildCourseId(course, apiEnv) {
|
|
85683
|
-
const courseId = course.ids?.[apiEnv];
|
|
85684
|
-
if (!courseId) {
|
|
85685
|
-
throw new MissingSyncedCourseIdError(course, apiEnv);
|
|
85686
|
-
}
|
|
85687
|
-
return courseId;
|
|
85688
|
-
}
|
|
85689
|
-
function buildCourseName(course) {
|
|
85690
|
-
if (course.courseCode) {
|
|
85691
|
-
return course.courseCode;
|
|
85692
|
-
}
|
|
85693
|
-
if (course.grade !== undefined) {
|
|
85694
|
-
return `${course.subject} G${String(course.grade)}`;
|
|
85695
|
-
}
|
|
85696
|
-
return course.subject;
|
|
85697
|
-
}
|
|
85698
|
-
|
|
85699
|
-
class InvalidSensorUrlError extends Error {
|
|
85700
|
-
sensor;
|
|
85701
|
-
constructor(sensor) {
|
|
85702
|
-
super(`Invalid sensor URL "${sensor}". Sensor must be a valid absolute URL (e.g., "https://sensor.example.com") to support slug-based activity IDs.`);
|
|
85703
|
-
this.name = "InvalidSensorUrlError";
|
|
85704
|
-
this.sensor = sensor;
|
|
85705
|
-
}
|
|
85706
|
-
}
|
|
85707
|
-
function buildCanonicalActivityUrl(sensor, selector, slug) {
|
|
85708
|
-
let base;
|
|
85709
|
-
try {
|
|
85710
|
-
base = new URL(sensor);
|
|
85711
|
-
} catch {
|
|
85712
|
-
throw new InvalidSensorUrlError(sensor);
|
|
85713
|
-
}
|
|
85714
|
-
const pathSegment = "grade" in selector ? `${selector.subject}/g${String(selector.grade)}` : selector.code;
|
|
85715
|
-
const basePath = base.pathname.replace(/\/+$/, "");
|
|
85716
|
-
base.pathname = `${basePath}/activities/${pathSegment}/${encodeURIComponent(slug)}`;
|
|
85717
|
-
return base.toString();
|
|
85718
|
-
}
|
|
85719
|
-
function buildActivityContext(payload, course, appName, apiEnv, sensor) {
|
|
85720
|
-
return {
|
|
85721
|
-
id: buildCanonicalActivityUrl(sensor, payload.course, payload.id),
|
|
85722
|
-
type: "TimebackActivityContext",
|
|
85723
|
-
subject: course.subject,
|
|
85724
|
-
app: { name: appName },
|
|
85725
|
-
activity: { name: payload.name },
|
|
85726
|
-
course: {
|
|
85727
|
-
id: buildCourseId(course, apiEnv),
|
|
85728
|
-
name: buildCourseName(course)
|
|
85729
|
-
}
|
|
85730
|
-
};
|
|
85731
|
-
}
|
|
85732
|
-
function buildActivityMetrics(metrics) {
|
|
85733
|
-
const result = [];
|
|
85734
|
-
if (metrics.totalQuestions !== undefined) {
|
|
85735
|
-
result.push({ type: "totalQuestions", value: metrics.totalQuestions });
|
|
85736
|
-
}
|
|
85737
|
-
if (metrics.correctQuestions !== undefined) {
|
|
85738
|
-
result.push({ type: "correctQuestions", value: metrics.correctQuestions });
|
|
85739
|
-
}
|
|
85740
|
-
if (metrics.xpEarned !== undefined) {
|
|
85741
|
-
result.push({ type: "xpEarned", value: metrics.xpEarned });
|
|
85742
|
-
}
|
|
85743
|
-
if (metrics.masteredUnits !== undefined) {
|
|
85744
|
-
result.push({ type: "masteredUnits", value: metrics.masteredUnits });
|
|
85745
|
-
}
|
|
85746
|
-
return result;
|
|
85747
|
-
}
|
|
85748
|
-
function buildTimeSpentMetrics(elapsedMs, pausedMs) {
|
|
85749
|
-
const result = [{ type: "active", value: Math.max(0, elapsedMs) / 1000 }];
|
|
85750
|
-
if (pausedMs > 0) {
|
|
85751
|
-
result.push({ type: "inactive", value: Math.max(0, pausedMs) / 1000 });
|
|
85752
|
-
}
|
|
85753
|
-
return result;
|
|
85754
|
-
}
|
|
85755
|
-
async function sendCaliperEnvelope(client, sensor, activityEvent, timeSpentEvent) {
|
|
85756
|
-
await client.caliper.events.send(sensor, [activityEvent, timeSpentEvent]);
|
|
85757
|
-
}
|
|
85758
|
-
// src/server/lib/build-user-profile.ts
|
|
85759
|
-
function buildCourseLookup(courses, apiEnv) {
|
|
85760
|
-
const courseById = new Map;
|
|
85761
|
-
for (const course of courses) {
|
|
85762
|
-
const courseId = course.ids?.[apiEnv];
|
|
85763
|
-
if (courseId) {
|
|
85764
|
-
courseById.set(courseId, course);
|
|
85765
|
-
}
|
|
85766
|
-
}
|
|
85767
|
-
return courseById;
|
|
85768
|
-
}
|
|
85769
|
-
function mapEnrollmentsToCourses(enrollments, courseById) {
|
|
85770
|
-
return enrollments.map((enrollment) => {
|
|
85771
|
-
const configuredCourse = courseById.get(enrollment.course.id);
|
|
85772
|
-
return {
|
|
85773
|
-
id: enrollment.course.id,
|
|
85774
|
-
code: configuredCourse?.courseCode ?? enrollment.course.id,
|
|
85775
|
-
name: enrollment.course.title
|
|
85776
|
-
};
|
|
85777
|
-
});
|
|
85778
|
-
}
|
|
85779
|
-
function pickGoalsFromEnrollments(enrollments) {
|
|
85780
|
-
return enrollments.map((enrollment) => enrollment.metadata?.goals).find(Boolean);
|
|
85781
|
-
}
|
|
85782
|
-
function getUtcDayRange(date6) {
|
|
85783
|
-
const start = new Date(Date.UTC(date6.getUTCFullYear(), date6.getUTCMonth(), date6.getUTCDate()));
|
|
85784
|
-
const end = new Date(Date.UTC(date6.getUTCFullYear(), date6.getUTCMonth(), date6.getUTCDate(), 23, 59, 59, 999));
|
|
85785
|
-
return { start, end };
|
|
85786
|
-
}
|
|
85787
|
-
function sumXp(facts) {
|
|
85788
|
-
return Object.values(facts).reduce((dateTotal, subjects) => {
|
|
85789
|
-
return dateTotal + Object.values(subjects).reduce((subjectTotal, metrics) => {
|
|
85790
|
-
return subjectTotal + (metrics.activityMetrics?.xpEarned ?? 0);
|
|
85791
|
-
}, 0);
|
|
85792
|
-
}, 0);
|
|
85793
|
-
}
|
|
85794
85687
|
// src/shared/constants.ts
|
|
85795
85688
|
var ROUTES = {
|
|
85796
85689
|
ACTIVITY: "/activity",
|
|
@@ -85800,10 +85693,83 @@ var ROUTES = {
|
|
|
85800
85693
|
CALLBACK: "/identity/callback"
|
|
85801
85694
|
},
|
|
85802
85695
|
USER: {
|
|
85803
|
-
ME: "/user/me"
|
|
85696
|
+
ME: "/user/me",
|
|
85697
|
+
VERIFY: "/user/verify"
|
|
85804
85698
|
}
|
|
85805
85699
|
};
|
|
85806
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
|
+
}
|
|
85807
85773
|
// src/server/adapters/utils.ts
|
|
85808
85774
|
function normalizePathname(path) {
|
|
85809
85775
|
const raw = path.trim();
|
|
@@ -85853,6 +85819,8 @@ function matchTimebackRoute(params) {
|
|
|
85853
85819
|
return "identity.signOut";
|
|
85854
85820
|
if (relative === ROUTES.USER.ME)
|
|
85855
85821
|
return "user.me";
|
|
85822
|
+
if (relative === ROUTES.USER.VERIFY)
|
|
85823
|
+
return "user.verify";
|
|
85856
85824
|
}
|
|
85857
85825
|
if (method === "POST") {
|
|
85858
85826
|
if (relative === ROUTES.ACTIVITY)
|
|
@@ -85878,6 +85846,8 @@ function matchTimebackRoute(params) {
|
|
|
85878
85846
|
return "identity.signOut";
|
|
85879
85847
|
if (pathname.endsWith(ROUTES.USER.ME))
|
|
85880
85848
|
return "user.me";
|
|
85849
|
+
if (pathname.endsWith(ROUTES.USER.VERIFY))
|
|
85850
|
+
return "user.verify";
|
|
85881
85851
|
}
|
|
85882
85852
|
if (method === "POST") {
|
|
85883
85853
|
if (pathname.endsWith(ROUTES.ACTIVITY))
|
|
@@ -85952,6 +85922,11 @@ function toExpressMiddleware(input) {
|
|
|
85952
85922
|
return Promise.resolve(undefined);
|
|
85953
85923
|
return handle.user.me(webReq);
|
|
85954
85924
|
}
|
|
85925
|
+
if (route === "user.verify") {
|
|
85926
|
+
if (!hasUserHandler(handle))
|
|
85927
|
+
return Promise.resolve(undefined);
|
|
85928
|
+
return handle.user.verify(webReq);
|
|
85929
|
+
}
|
|
85955
85930
|
if (route === "activity") {
|
|
85956
85931
|
if (!hasActivityHandler(handle))
|
|
85957
85932
|
return Promise.resolve(undefined);
|
|
@@ -85986,6 +85961,7 @@ function mountExpressRoutes(input, router) {
|
|
|
85986
85961
|
router.get("/identity/signout", createHandler(() => handle.identity.signOut()));
|
|
85987
85962
|
if (hasUserHandler(handle)) {
|
|
85988
85963
|
router.get("/user/me", createHandler((req) => handle.user.me(req)));
|
|
85964
|
+
router.get("/user/verify", createHandler((req) => handle.user.verify(req)));
|
|
85989
85965
|
}
|
|
85990
85966
|
if (hasActivityHandler(handle)) {
|
|
85991
85967
|
router.post("/activity", createHandler((req) => handle.activity(req)));
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"native.d.ts","sourceRoot":"","sources":["../../../src/server/adapters/native.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAKH,OAAO,KAAK,EAAE,gBAAgB,EAAE,oBAAoB,EAAE,MAAM,SAAS,CAAA;AAYrE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAqCG;AACH,wBAAgB,eAAe,CAC9B,KAAK,EAAE,gBAAgB,GAAG,oBAAoB,GAC5C,CAAC,GAAG,EAAE,OAAO,KAAK,OAAO,CAAC,QAAQ,CAAC,
|
|
1
|
+
{"version":3,"file":"native.d.ts","sourceRoot":"","sources":["../../../src/server/adapters/native.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAKH,OAAO,KAAK,EAAE,gBAAgB,EAAE,oBAAoB,EAAE,MAAM,SAAS,CAAA;AAYrE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAqCG;AACH,wBAAgB,eAAe,CAC9B,KAAK,EAAE,gBAAgB,GAAG,oBAAoB,GAC5C,CAAC,GAAG,EAAE,OAAO,KAAK,OAAO,CAAC,QAAQ,CAAC,CA+CrC"}
|
|
@@ -18,12 +18,32 @@ var __toESM = (mod, isNodeMode, target) => {
|
|
|
18
18
|
var __require = /* @__PURE__ */ createRequire(import.meta.url);
|
|
19
19
|
|
|
20
20
|
// src/server/lib/utils.ts
|
|
21
|
+
function safeIdSegment(value) {
|
|
22
|
+
return encodeURIComponent(value).replace(/%/g, "_");
|
|
23
|
+
}
|
|
24
|
+
function hashSuffix64Base36(value) {
|
|
25
|
+
let hash = 0xcbf29ce484222325n;
|
|
26
|
+
const prime = 0x100000001b3n;
|
|
27
|
+
const mod64 = 0xffffffffffffffffn;
|
|
28
|
+
for (let i = 0;i < value.length; i++) {
|
|
29
|
+
hash ^= BigInt(value.charCodeAt(i));
|
|
30
|
+
hash = hash * prime & mod64;
|
|
31
|
+
}
|
|
32
|
+
const base36 = hash.toString(36);
|
|
33
|
+
return base36.length > 12 ? base36.slice(-12) : base36;
|
|
34
|
+
}
|
|
21
35
|
function mapEnvForApi(env) {
|
|
22
36
|
if (env === "local" || env === "staging") {
|
|
23
37
|
return "staging";
|
|
24
38
|
}
|
|
25
39
|
return "production";
|
|
26
40
|
}
|
|
41
|
+
function normalizeEnv(env) {
|
|
42
|
+
if (env === "production" || env === "local" || env === "staging") {
|
|
43
|
+
return env;
|
|
44
|
+
}
|
|
45
|
+
return "staging";
|
|
46
|
+
}
|
|
27
47
|
function jsonResponse(data, status = 200, headers) {
|
|
28
48
|
const responseHeaders = new Headers(headers);
|
|
29
49
|
responseHeaders.set("Content-Type", "application/json");
|
|
@@ -53,7 +73,8 @@ var ROUTES = {
|
|
|
53
73
|
CALLBACK: "/identity/callback"
|
|
54
74
|
},
|
|
55
75
|
USER: {
|
|
56
|
-
ME: "/user/me"
|
|
76
|
+
ME: "/user/me",
|
|
77
|
+
VERIFY: "/user/verify"
|
|
57
78
|
}
|
|
58
79
|
};
|
|
59
80
|
|
|
@@ -106,6 +127,8 @@ function matchTimebackRoute(params) {
|
|
|
106
127
|
return "identity.signOut";
|
|
107
128
|
if (relative === ROUTES.USER.ME)
|
|
108
129
|
return "user.me";
|
|
130
|
+
if (relative === ROUTES.USER.VERIFY)
|
|
131
|
+
return "user.verify";
|
|
109
132
|
}
|
|
110
133
|
if (method === "POST") {
|
|
111
134
|
if (relative === ROUTES.ACTIVITY)
|
|
@@ -131,6 +154,8 @@ function matchTimebackRoute(params) {
|
|
|
131
154
|
return "identity.signOut";
|
|
132
155
|
if (pathname.endsWith(ROUTES.USER.ME))
|
|
133
156
|
return "user.me";
|
|
157
|
+
if (pathname.endsWith(ROUTES.USER.VERIFY))
|
|
158
|
+
return "user.verify";
|
|
134
159
|
}
|
|
135
160
|
if (method === "POST") {
|
|
136
161
|
if (pathname.endsWith(ROUTES.ACTIVITY))
|
|
@@ -176,6 +201,12 @@ function toNativeHandler(input) {
|
|
|
176
201
|
}
|
|
177
202
|
return handle.user.me(req);
|
|
178
203
|
}
|
|
204
|
+
if (route === "user.verify") {
|
|
205
|
+
if (!hasUserHandler(handle)) {
|
|
206
|
+
return Promise.resolve(jsonResponse({ error: "Not found" }, 404));
|
|
207
|
+
}
|
|
208
|
+
return handle.user.verify(req);
|
|
209
|
+
}
|
|
179
210
|
if (route === "activity") {
|
|
180
211
|
if (!hasActivityHandler(handle)) {
|
|
181
212
|
return Promise.resolve(jsonResponse({ error: "Not found" }, 404));
|
|
@@ -18,12 +18,32 @@ var __toESM = (mod, isNodeMode, target) => {
|
|
|
18
18
|
var __require = /* @__PURE__ */ createRequire(import.meta.url);
|
|
19
19
|
|
|
20
20
|
// src/server/lib/utils.ts
|
|
21
|
+
function safeIdSegment(value) {
|
|
22
|
+
return encodeURIComponent(value).replace(/%/g, "_");
|
|
23
|
+
}
|
|
24
|
+
function hashSuffix64Base36(value) {
|
|
25
|
+
let hash = 0xcbf29ce484222325n;
|
|
26
|
+
const prime = 0x100000001b3n;
|
|
27
|
+
const mod64 = 0xffffffffffffffffn;
|
|
28
|
+
for (let i = 0;i < value.length; i++) {
|
|
29
|
+
hash ^= BigInt(value.charCodeAt(i));
|
|
30
|
+
hash = hash * prime & mod64;
|
|
31
|
+
}
|
|
32
|
+
const base36 = hash.toString(36);
|
|
33
|
+
return base36.length > 12 ? base36.slice(-12) : base36;
|
|
34
|
+
}
|
|
21
35
|
function mapEnvForApi(env) {
|
|
22
36
|
if (env === "local" || env === "staging") {
|
|
23
37
|
return "staging";
|
|
24
38
|
}
|
|
25
39
|
return "production";
|
|
26
40
|
}
|
|
41
|
+
function normalizeEnv(env) {
|
|
42
|
+
if (env === "production" || env === "local" || env === "staging") {
|
|
43
|
+
return env;
|
|
44
|
+
}
|
|
45
|
+
return "staging";
|
|
46
|
+
}
|
|
27
47
|
function jsonResponse(data, status = 200, headers) {
|
|
28
48
|
const responseHeaders = new Headers(headers);
|
|
29
49
|
responseHeaders.set("Content-Type", "application/json");
|
|
@@ -53,7 +73,8 @@ var ROUTES = {
|
|
|
53
73
|
CALLBACK: "/identity/callback"
|
|
54
74
|
},
|
|
55
75
|
USER: {
|
|
56
|
-
ME: "/user/me"
|
|
76
|
+
ME: "/user/me",
|
|
77
|
+
VERIFY: "/user/verify"
|
|
57
78
|
}
|
|
58
79
|
};
|
|
59
80
|
|
|
@@ -106,6 +127,8 @@ function matchTimebackRoute(params) {
|
|
|
106
127
|
return "identity.signOut";
|
|
107
128
|
if (relative === ROUTES.USER.ME)
|
|
108
129
|
return "user.me";
|
|
130
|
+
if (relative === ROUTES.USER.VERIFY)
|
|
131
|
+
return "user.verify";
|
|
109
132
|
}
|
|
110
133
|
if (method === "POST") {
|
|
111
134
|
if (relative === ROUTES.ACTIVITY)
|
|
@@ -131,6 +154,8 @@ function matchTimebackRoute(params) {
|
|
|
131
154
|
return "identity.signOut";
|
|
132
155
|
if (pathname.endsWith(ROUTES.USER.ME))
|
|
133
156
|
return "user.me";
|
|
157
|
+
if (pathname.endsWith(ROUTES.USER.VERIFY))
|
|
158
|
+
return "user.verify";
|
|
134
159
|
}
|
|
135
160
|
if (method === "POST") {
|
|
136
161
|
if (pathname.endsWith(ROUTES.ACTIVITY))
|
|
@@ -176,6 +201,12 @@ function toNativeHandler(input) {
|
|
|
176
201
|
}
|
|
177
202
|
return handle.user.me(req);
|
|
178
203
|
}
|
|
204
|
+
if (route === "user.verify") {
|
|
205
|
+
if (!hasUserHandler(handle)) {
|
|
206
|
+
return Promise.resolve(jsonResponse({ error: "Not found" }, 404));
|
|
207
|
+
}
|
|
208
|
+
return handle.user.verify(req);
|
|
209
|
+
}
|
|
179
210
|
if (route === "activity") {
|
|
180
211
|
if (!hasActivityHandler(handle)) {
|
|
181
212
|
return Promise.resolve(jsonResponse({ error: "Not found" }, 404));
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"nuxt.d.ts","sourceRoot":"","sources":["../../../src/server/adapters/nuxt.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAWH,OAAO,KAAK,EACX,gBAAgB,EAEhB,kBAAkB,EAClB,YAAY,EACZ,aAAa,EACb,MAAM,SAAS,CAAA;AAuMhB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAgDG;AACH,wBAAsB,WAAW,CAAC,MAAM,SAAS,aAAa,EAC7D,OAAO,EAAE,kBAAkB,CAAC,MAAM,CAAC,GACjC,OAAO,CAAC,QAAQ,GAAG,SAAS,CAAC,
|
|
1
|
+
{"version":3,"file":"nuxt.d.ts","sourceRoot":"","sources":["../../../src/server/adapters/nuxt.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAWH,OAAO,KAAK,EACX,gBAAgB,EAEhB,kBAAkB,EAClB,YAAY,EACZ,aAAa,EACb,MAAM,SAAS,CAAA;AAuMhB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAgDG;AACH,wBAAsB,WAAW,CAAC,MAAM,SAAS,aAAa,EAC7D,OAAO,EAAE,kBAAkB,CAAC,MAAM,CAAC,GACjC,OAAO,CAAC,QAAQ,GAAG,SAAS,CAAC,CAiC/B;AAMD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAgCG;AACH,wBAAgB,aAAa,CAC5B,KAAK,EAAE,gBAAgB,GAAG;IAAE,QAAQ,EAAE,gBAAgB,CAAC;IAAC,YAAY,CAAC,EAAE,MAAM,CAAA;CAAE,GAC7E,YAAY,CA4Cd"}
|