@lti-tool/core 1.0.1 → 1.0.3
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/CHANGELOG.md +12 -0
- package/README.md +1 -1
- package/dist/services/session.service.d.ts.map +1 -1
- package/dist/services/session.service.js +27 -20
- package/package.json +4 -4
- package/src/services/session.service.ts +30 -16
package/CHANGELOG.md
CHANGED
package/README.md
CHANGED
|
@@ -47,7 +47,7 @@ const session = await ltiTool.createSession(payload);
|
|
|
47
47
|
|
|
48
48
|
## Documentation
|
|
49
49
|
|
|
50
|
-
- [API Reference](https://lti-tool.dev
|
|
50
|
+
- [API Reference](https://docs.lti-tool.dev) - Complete API documentation
|
|
51
51
|
- [Examples](https://github.com/lti-tool/lti-tool-examples) - (Coming soon) Working examples
|
|
52
52
|
|
|
53
53
|
## Security
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"session.service.d.ts","sourceRoot":"","sources":["../../src/services/session.service.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,6BAA6B,CAAC;AAC9D,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,qBAAqB,CAAC;
|
|
1
|
+
{"version":3,"file":"session.service.d.ts","sourceRoot":"","sources":["../../src/services/session.service.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,6BAA6B,CAAC;AAC9D,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,qBAAqB,CAAC;AAU3D;;;;;;GAMG;AAEH,wBAAgB,aAAa,CAAC,eAAe,EAAE,eAAe,GAAG,UAAU,CAkG1E"}
|
|
@@ -1,3 +1,10 @@
|
|
|
1
|
+
const ROLE_MAPPINGS = {
|
|
2
|
+
Instructor: 'instructor',
|
|
3
|
+
Learner: 'student',
|
|
4
|
+
Administrator: 'admin',
|
|
5
|
+
ContentDeveloper: 'content-developer',
|
|
6
|
+
Member: 'member',
|
|
7
|
+
};
|
|
1
8
|
/**
|
|
2
9
|
* Creates an LTI session object from a validated LTI 1.3 JWT payload.
|
|
3
10
|
* Extracts user information, context data, and available services into a structured session.
|
|
@@ -5,7 +12,7 @@
|
|
|
5
12
|
* @param lti13JwtPayload - Validated LTI 1.3 JWT payload from successful launch
|
|
6
13
|
* @returns Complete LTI session object with user, context, and service information
|
|
7
14
|
*/
|
|
8
|
-
// oxlint-disable-next-line max-lines-per-function
|
|
15
|
+
// oxlint-disable-next-line max-lines-per-function complexity -- flat data mapping
|
|
9
16
|
export function createSession(lti13JwtPayload) {
|
|
10
17
|
const roles = lti13JwtPayload['https://purl.imsglobal.org/spec/lti/claim/roles'] || [];
|
|
11
18
|
const context = lti13JwtPayload['https://purl.imsglobal.org/spec/lti/claim/context'];
|
|
@@ -15,9 +22,9 @@ export function createSession(lti13JwtPayload) {
|
|
|
15
22
|
const agsEndpoint = lti13JwtPayload['https://purl.imsglobal.org/spec/lti-ags/claim/endpoint'];
|
|
16
23
|
const nrpsService = lti13JwtPayload['https://purl.imsglobal.org/spec/lti-nrps/claim/namesroleservice'];
|
|
17
24
|
const deepLinkingSettings = lti13JwtPayload['https://purl.imsglobal.org/spec/lti-dl/claim/deep_linking_settings'];
|
|
18
|
-
const isInstructor = roles
|
|
19
|
-
const isStudent = roles
|
|
20
|
-
const isAdmin = roles
|
|
25
|
+
const isInstructor = hasRole(roles, 'Instructor');
|
|
26
|
+
const isStudent = hasRole(roles, 'Learner');
|
|
27
|
+
const isAdmin = hasRole(roles, 'Administrator');
|
|
21
28
|
const services = {};
|
|
22
29
|
if (agsEndpoint) {
|
|
23
30
|
let lineItemUrl;
|
|
@@ -48,21 +55,7 @@ export function createSession(lti13JwtPayload) {
|
|
|
48
55
|
};
|
|
49
56
|
}
|
|
50
57
|
// Extract simplified roles
|
|
51
|
-
const simplifiedRoles =
|
|
52
|
-
for (const role of roles) {
|
|
53
|
-
if (role.includes('Instructor'))
|
|
54
|
-
simplifiedRoles.push('instructor');
|
|
55
|
-
if (role.includes('Learner'))
|
|
56
|
-
simplifiedRoles.push('student');
|
|
57
|
-
if (role.includes('Administrator'))
|
|
58
|
-
simplifiedRoles.push('admin');
|
|
59
|
-
if (role.includes('ContentDeveloper'))
|
|
60
|
-
simplifiedRoles.push('content-developer');
|
|
61
|
-
if (role.includes('Member'))
|
|
62
|
-
simplifiedRoles.push('member');
|
|
63
|
-
}
|
|
64
|
-
// Remove duplicates
|
|
65
|
-
const uniqueRoles = [...new Set(simplifiedRoles)];
|
|
58
|
+
const simplifiedRoles = simplifyRoles(roles);
|
|
66
59
|
return {
|
|
67
60
|
jwtPayload: lti13JwtPayload,
|
|
68
61
|
id: crypto.randomUUID(),
|
|
@@ -72,7 +65,7 @@ export function createSession(lti13JwtPayload) {
|
|
|
72
65
|
email: lti13JwtPayload.email,
|
|
73
66
|
familyName: lti13JwtPayload.family_name,
|
|
74
67
|
givenName: lti13JwtPayload.given_name,
|
|
75
|
-
roles:
|
|
68
|
+
roles: simplifiedRoles,
|
|
76
69
|
},
|
|
77
70
|
context: {
|
|
78
71
|
id: context?.id || '',
|
|
@@ -106,3 +99,17 @@ export function createSession(lti13JwtPayload) {
|
|
|
106
99
|
isNameAndRolesAvailable: !!nrpsService,
|
|
107
100
|
};
|
|
108
101
|
}
|
|
102
|
+
function simplifyRoles(roles) {
|
|
103
|
+
const simplified = new Set();
|
|
104
|
+
for (const role of roles) {
|
|
105
|
+
for (const [key, value] of Object.entries(ROLE_MAPPINGS)) {
|
|
106
|
+
if (role.includes(key)) {
|
|
107
|
+
simplified.add(value);
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
return [...simplified];
|
|
112
|
+
}
|
|
113
|
+
function hasRole(roles, pattern) {
|
|
114
|
+
return roles.some((role) => role.includes(pattern));
|
|
115
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@lti-tool/core",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.3",
|
|
4
4
|
"description": "LTI 1.3 implementation for Node.js",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"lti",
|
|
@@ -36,8 +36,8 @@
|
|
|
36
36
|
"test": "vitest"
|
|
37
37
|
},
|
|
38
38
|
"dependencies": {
|
|
39
|
-
"jose": "^6.1.
|
|
40
|
-
"zod": "^4.
|
|
39
|
+
"jose": "^6.1.3",
|
|
40
|
+
"zod": "^4.3.5"
|
|
41
41
|
},
|
|
42
42
|
"peerDependencies": {
|
|
43
43
|
"pino": "^9.11.0"
|
|
@@ -48,6 +48,6 @@
|
|
|
48
48
|
}
|
|
49
49
|
},
|
|
50
50
|
"devDependencies": {
|
|
51
|
-
"pino": "^10.
|
|
51
|
+
"pino": "^10.2.0"
|
|
52
52
|
}
|
|
53
53
|
}
|
|
@@ -1,6 +1,14 @@
|
|
|
1
1
|
import type { LTISession } from '../interfaces/ltiSession.js';
|
|
2
2
|
import type { LTI13JwtPayload } from '../schemas/index.js';
|
|
3
3
|
|
|
4
|
+
const ROLE_MAPPINGS: Record<string, string> = {
|
|
5
|
+
Instructor: 'instructor',
|
|
6
|
+
Learner: 'student',
|
|
7
|
+
Administrator: 'admin',
|
|
8
|
+
ContentDeveloper: 'content-developer',
|
|
9
|
+
Member: 'member',
|
|
10
|
+
};
|
|
11
|
+
|
|
4
12
|
/**
|
|
5
13
|
* Creates an LTI session object from a validated LTI 1.3 JWT payload.
|
|
6
14
|
* Extracts user information, context data, and available services into a structured session.
|
|
@@ -8,7 +16,7 @@ import type { LTI13JwtPayload } from '../schemas/index.js';
|
|
|
8
16
|
* @param lti13JwtPayload - Validated LTI 1.3 JWT payload from successful launch
|
|
9
17
|
* @returns Complete LTI session object with user, context, and service information
|
|
10
18
|
*/
|
|
11
|
-
// oxlint-disable-next-line max-lines-per-function
|
|
19
|
+
// oxlint-disable-next-line max-lines-per-function complexity -- flat data mapping
|
|
12
20
|
export function createSession(lti13JwtPayload: LTI13JwtPayload): LTISession {
|
|
13
21
|
const roles = lti13JwtPayload['https://purl.imsglobal.org/spec/lti/claim/roles'] || [];
|
|
14
22
|
const context = lti13JwtPayload['https://purl.imsglobal.org/spec/lti/claim/context'];
|
|
@@ -25,9 +33,9 @@ export function createSession(lti13JwtPayload: LTI13JwtPayload): LTISession {
|
|
|
25
33
|
const deepLinkingSettings =
|
|
26
34
|
lti13JwtPayload['https://purl.imsglobal.org/spec/lti-dl/claim/deep_linking_settings'];
|
|
27
35
|
|
|
28
|
-
const isInstructor = roles
|
|
29
|
-
const isStudent = roles
|
|
30
|
-
const isAdmin = roles
|
|
36
|
+
const isInstructor = hasRole(roles, 'Instructor');
|
|
37
|
+
const isStudent = hasRole(roles, 'Learner');
|
|
38
|
+
const isAdmin = hasRole(roles, 'Administrator');
|
|
31
39
|
|
|
32
40
|
const services: Record<string, unknown> = {};
|
|
33
41
|
if (agsEndpoint) {
|
|
@@ -61,17 +69,7 @@ export function createSession(lti13JwtPayload: LTI13JwtPayload): LTISession {
|
|
|
61
69
|
}
|
|
62
70
|
|
|
63
71
|
// Extract simplified roles
|
|
64
|
-
const simplifiedRoles
|
|
65
|
-
for (const role of roles) {
|
|
66
|
-
if (role.includes('Instructor')) simplifiedRoles.push('instructor');
|
|
67
|
-
if (role.includes('Learner')) simplifiedRoles.push('student');
|
|
68
|
-
if (role.includes('Administrator')) simplifiedRoles.push('admin');
|
|
69
|
-
if (role.includes('ContentDeveloper')) simplifiedRoles.push('content-developer');
|
|
70
|
-
if (role.includes('Member')) simplifiedRoles.push('member');
|
|
71
|
-
}
|
|
72
|
-
|
|
73
|
-
// Remove duplicates
|
|
74
|
-
const uniqueRoles = [...new Set(simplifiedRoles)];
|
|
72
|
+
const simplifiedRoles = simplifyRoles(roles);
|
|
75
73
|
|
|
76
74
|
return {
|
|
77
75
|
jwtPayload: lti13JwtPayload,
|
|
@@ -82,7 +80,7 @@ export function createSession(lti13JwtPayload: LTI13JwtPayload): LTISession {
|
|
|
82
80
|
email: lti13JwtPayload.email,
|
|
83
81
|
familyName: lti13JwtPayload.family_name,
|
|
84
82
|
givenName: lti13JwtPayload.given_name,
|
|
85
|
-
roles:
|
|
83
|
+
roles: simplifiedRoles,
|
|
86
84
|
},
|
|
87
85
|
context: {
|
|
88
86
|
id: context?.id || '',
|
|
@@ -118,3 +116,19 @@ export function createSession(lti13JwtPayload: LTI13JwtPayload): LTISession {
|
|
|
118
116
|
isNameAndRolesAvailable: !!nrpsService,
|
|
119
117
|
};
|
|
120
118
|
}
|
|
119
|
+
|
|
120
|
+
function simplifyRoles(roles: string[]): string[] {
|
|
121
|
+
const simplified = new Set<string>();
|
|
122
|
+
for (const role of roles) {
|
|
123
|
+
for (const [key, value] of Object.entries(ROLE_MAPPINGS)) {
|
|
124
|
+
if (role.includes(key)) {
|
|
125
|
+
simplified.add(value);
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
return [...simplified];
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
function hasRole(roles: string[], pattern: string): boolean {
|
|
133
|
+
return roles.some((role) => role.includes(pattern));
|
|
134
|
+
}
|