@headless-lms/core 0.1.0 → 0.3.0
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/assets/events.d.ts +90 -9
- package/dist/assets/events.js +19 -3
- package/dist/assets/events.js.map +1 -1
- package/dist/assets/file-urls.d.ts +20 -0
- package/dist/assets/file-urls.js +25 -0
- package/dist/assets/file-urls.js.map +1 -0
- package/dist/assets/index.d.ts +5 -4
- package/dist/assets/index.js +3 -2
- package/dist/assets/model.d.ts +2 -2
- package/dist/assets/ports.d.ts +45 -15
- package/dist/assets/service.d.ts +39 -7
- package/dist/assets/service.js +292 -37
- package/dist/assets/service.js.map +1 -1
- package/dist/automations/actions.d.ts +12 -15
- package/dist/automations/actions.js +188 -30
- package/dist/automations/actions.js.map +1 -1
- package/dist/automations/catalog.d.ts +5 -1
- package/dist/automations/catalog.js +514 -197
- package/dist/automations/catalog.js.map +1 -1
- package/dist/automations/community-derivations.d.ts +14 -0
- package/dist/automations/community-derivations.js +439 -0
- package/dist/automations/community-derivations.js.map +1 -0
- package/dist/automations/community-mail.d.ts +112 -0
- package/dist/automations/community-mail.js +90 -0
- package/dist/automations/community-mail.js.map +1 -0
- package/dist/automations/community-notifications.d.ts +16 -0
- package/dist/automations/community-notifications.js +84 -0
- package/dist/automations/community-notifications.js.map +1 -0
- package/dist/automations/events.d.ts +74 -24
- package/dist/automations/events.js +5 -5
- package/dist/automations/events.js.map +1 -1
- package/dist/automations/index.d.ts +7 -5
- package/dist/automations/index.js +3 -2
- package/dist/automations/model.d.ts +20 -3
- package/dist/automations/model.js +36 -3
- package/dist/automations/model.js.map +1 -1
- package/dist/automations/ports.d.ts +27 -8
- package/dist/automations/schedule.d.ts +6 -0
- package/dist/automations/schedule.js +41 -0
- package/dist/automations/schedule.js.map +1 -0
- package/dist/automations/seeds.d.ts +17 -0
- package/dist/automations/seeds.js +235 -0
- package/dist/automations/seeds.js.map +1 -0
- package/dist/automations/service.d.ts +41 -6
- package/dist/automations/service.js +542 -59
- package/dist/automations/service.js.map +1 -1
- package/dist/automations/types.d.ts +2 -2
- package/dist/automations/webhook-signing.d.ts +7 -0
- package/dist/automations/webhook-signing.js +22 -0
- package/dist/automations/webhook-signing.js.map +1 -0
- package/dist/content/events.d.ts +1013 -25
- package/dist/content/events.js +168 -19
- package/dist/content/events.js.map +1 -1
- package/dist/content/index.d.ts +5 -5
- package/dist/content/index.js +2 -2
- package/dist/content/model.d.ts +2 -2
- package/dist/content/ports.d.ts +109 -25
- package/dist/content/service.d.ts +68 -23
- package/dist/content/service.js +647 -60
- package/dist/content/service.js.map +1 -1
- package/dist/content/types.d.ts +2 -2
- package/dist/discussion/authors.d.ts +10 -0
- package/dist/discussion/authors.js +23 -0
- package/dist/discussion/authors.js.map +1 -0
- package/dist/discussion/chats.d.ts +104 -0
- package/dist/discussion/chats.js +798 -0
- package/dist/discussion/chats.js.map +1 -0
- package/dist/discussion/events.d.ts +633 -14
- package/dist/discussion/events.js +134 -5
- package/dist/discussion/events.js.map +1 -1
- package/dist/discussion/index.d.ts +7 -3
- package/dist/discussion/index.js +4 -1
- package/dist/discussion/model.d.ts +1 -2
- package/dist/discussion/ports.d.ts +288 -27
- package/dist/discussion/ports.js +6 -1
- package/dist/discussion/ports.js.map +1 -0
- package/dist/discussion/posts.d.ts +103 -0
- package/dist/discussion/posts.js +723 -0
- package/dist/discussion/posts.js.map +1 -0
- package/dist/discussion/service.d.ts +33 -11
- package/dist/discussion/service.js +297 -81
- package/dist/discussion/service.js.map +1 -1
- package/dist/entitlements/events.d.ts +264 -13
- package/dist/entitlements/events.js +49 -5
- package/dist/entitlements/events.js.map +1 -1
- package/dist/entitlements/index.d.ts +5 -4
- package/dist/entitlements/index.js +2 -1
- package/dist/entitlements/model.d.ts +3 -2
- package/dist/entitlements/ports.d.ts +124 -11
- package/dist/entitlements/rules.d.ts +12 -0
- package/dist/entitlements/rules.js +17 -0
- package/dist/entitlements/rules.js.map +1 -0
- package/dist/entitlements/service.d.ts +54 -3
- package/dist/entitlements/service.js +473 -2
- package/dist/entitlements/service.js.map +1 -1
- package/dist/identity/access.d.ts +6 -0
- package/dist/identity/access.js +7 -0
- package/dist/identity/access.js.map +1 -0
- package/dist/identity/events.d.ts +17 -3
- package/dist/identity/events.js +12 -2
- package/dist/identity/events.js.map +1 -1
- package/dist/identity/index.d.ts +6 -4
- package/dist/identity/index.js +3 -1
- package/dist/identity/model.d.ts +2 -1
- package/dist/identity/notifications.d.ts +27 -0
- package/dist/identity/notifications.js +101 -0
- package/dist/identity/notifications.js.map +1 -0
- package/dist/identity/ports.d.ts +76 -3
- package/dist/identity/service.d.ts +17 -3
- package/dist/identity/service.js +73 -5
- package/dist/identity/service.js.map +1 -1
- package/dist/integrations/events.d.ts +27 -3
- package/dist/integrations/events.js +15 -3
- package/dist/integrations/events.js.map +1 -1
- package/dist/integrations/model.js +1 -1
- package/dist/integrations/model.js.map +1 -1
- package/dist/integrations/service.js +2 -2
- package/dist/integrations/service.js.map +1 -1
- package/dist/organizations/access-scopes.d.ts +19 -0
- package/dist/organizations/access-scopes.js +89 -0
- package/dist/organizations/access-scopes.js.map +1 -0
- package/dist/organizations/events.d.ts +234 -25
- package/dist/organizations/events.js +58 -9
- package/dist/organizations/events.js.map +1 -1
- package/dist/organizations/index.d.ts +8 -7
- package/dist/organizations/index.js +4 -3
- package/dist/organizations/members.d.ts +8 -5
- package/dist/organizations/members.js.map +1 -1
- package/dist/organizations/ports.d.ts +20 -21
- package/dist/organizations/roles.d.ts +6 -10
- package/dist/organizations/roles.js +19 -7
- package/dist/organizations/roles.js.map +1 -1
- package/dist/organizations/service.d.ts +28 -14
- package/dist/organizations/service.js +274 -105
- package/dist/organizations/service.js.map +1 -1
- package/dist/organizations/types.d.ts +2 -11
- package/dist/progress/events.d.ts +34 -2
- package/dist/progress/events.js +15 -2
- package/dist/progress/events.js.map +1 -1
- package/dist/progress/index.d.ts +2 -2
- package/dist/progress/ports.d.ts +6 -1
- package/dist/progress/service.d.ts +5 -3
- package/dist/progress/service.js +9 -3
- package/dist/progress/service.js.map +1 -1
- package/dist/reporting/admin/index.d.ts +4 -0
- package/dist/reporting/admin/index.js +2 -0
- package/dist/reporting/admin/model.d.ts +108 -0
- package/dist/reporting/admin/ports.d.ts +27 -0
- package/dist/reporting/admin/service.d.ts +22 -0
- package/dist/reporting/admin/service.js +38 -0
- package/dist/reporting/admin/service.js.map +1 -0
- package/dist/reporting/member/index.d.ts +5 -0
- package/dist/reporting/member/index.js +2 -0
- package/dist/reporting/member/model.d.ts +124 -0
- package/dist/reporting/member/ports.d.ts +45 -0
- package/dist/reporting/member/service.d.ts +73 -0
- package/dist/reporting/member/service.js +286 -0
- package/dist/reporting/member/service.js.map +1 -0
- package/dist/shared/actor.d.ts +9 -0
- package/dist/shared/errors.d.ts +7 -1
- package/dist/shared/errors.js +10 -1
- package/dist/shared/errors.js.map +1 -1
- package/dist/shared/events.d.ts +5 -3
- package/dist/shared/events.js +1 -0
- package/dist/shared/events.js.map +1 -1
- package/dist/shared/id.d.ts +12 -0
- package/dist/shared/id.js +13 -1
- package/dist/shared/id.js.map +1 -1
- package/dist/shared/mailer.d.ts +6 -1
- package/dist/shared/mailer.js.map +1 -1
- package/dist/shared/network.d.ts +10 -0
- package/dist/shared/network.js +211 -0
- package/dist/shared/network.js.map +1 -0
- package/dist/shared/settings.js.map +1 -1
- package/dist/types/assets.d.ts +2 -2
- package/dist/types/automations.d.ts +21 -2
- package/dist/types/content.d.ts +2 -2
- package/dist/types/discussion.d.ts +12 -3
- package/dist/types/email-templates.d.ts +124 -1
- package/dist/types/entitlements.d.ts +2 -2
- package/dist/types/events.d.ts +3 -3
- package/dist/types/identity.d.ts +48 -2
- package/dist/types/index.d.ts +10 -10
- package/dist/types/organizations.d.ts +2 -2
- package/dist/types/ports.d.ts +7 -1
- package/dist/types/schemas/assets.d.ts +67 -36
- package/dist/types/schemas/assets.js +19 -13
- package/dist/types/schemas/assets.js.map +1 -1
- package/dist/types/schemas/automations.d.ts +88 -4
- package/dist/types/schemas/automations.js +46 -6
- package/dist/types/schemas/automations.js.map +1 -1
- package/dist/types/schemas/content.d.ts +385 -20
- package/dist/types/schemas/content.js +178 -15
- package/dist/types/schemas/content.js.map +1 -1
- package/dist/types/schemas/credentials.js.map +1 -1
- package/dist/types/schemas/discussion.d.ts +379 -4
- package/dist/types/schemas/discussion.js +209 -7
- package/dist/types/schemas/discussion.js.map +1 -1
- package/dist/types/schemas/entitlements.d.ts +44 -4
- package/dist/types/schemas/entitlements.js +32 -4
- package/dist/types/schemas/entitlements.js.map +1 -1
- package/dist/types/schemas/identity.d.ts +115 -5
- package/dist/types/schemas/identity.js +59 -6
- package/dist/types/schemas/identity.js.map +1 -1
- package/dist/types/schemas/index.d.ts +9 -9
- package/dist/types/schemas/index.js +9 -9
- package/dist/types/schemas/integrations.js.map +1 -1
- package/dist/types/schemas/organizations.d.ts +27 -5
- package/dist/types/schemas/organizations.js +14 -7
- package/dist/types/schemas/organizations.js.map +1 -1
- package/dist/types/schemas/outbox.d.ts +1 -0
- package/dist/types/schemas/outbox.js +1 -0
- package/dist/types/schemas/outbox.js.map +1 -1
- package/dist/types/schemas/progress.d.ts +1 -0
- package/dist/types/schemas/progress.js +1 -0
- package/dist/types/schemas/progress.js.map +1 -1
- package/dist/types/schemas/settings.js.map +1 -1
- package/dist/types/schemas/shared.d.ts +4 -1
- package/dist/types/schemas/shared.js +7 -1
- package/dist/types/schemas/shared.js.map +1 -1
- package/dist/types/shared.d.ts +1 -1
- package/package.json +2 -2
- package/dist/reporting/dashboard/index.d.ts +0 -4
- package/dist/reporting/dashboard/index.js +0 -2
- package/dist/reporting/dashboard/model.d.ts +0 -14
- package/dist/reporting/dashboard/ports.d.ts +0 -13
- package/dist/reporting/dashboard/service.d.ts +0 -19
- package/dist/reporting/dashboard/service.js +0 -20
- package/dist/reporting/dashboard/service.js.map +0 -1
- package/dist/reporting/learn/index.d.ts +0 -5
- package/dist/reporting/learn/index.js +0 -2
- package/dist/reporting/learn/model.d.ts +0 -23
- package/dist/reporting/learn/ports.d.ts +0 -42
- package/dist/reporting/learn/service.d.ts +0 -48
- package/dist/reporting/learn/service.js +0 -111
- package/dist/reporting/learn/service.js.map +0 -1
- package/dist/reporting/students/index.d.ts +0 -4
- package/dist/reporting/students/index.js +0 -2
- package/dist/reporting/students/model.d.ts +0 -31
- package/dist/reporting/students/ports.d.ts +0 -13
- package/dist/reporting/students/ports.js +0 -1
- package/dist/reporting/students/service.d.ts +0 -19
- package/dist/reporting/students/service.js +0 -20
- package/dist/reporting/students/service.js.map +0 -1
- /package/dist/reporting/{dashboard → admin}/model.js +0 -0
- /package/dist/reporting/{dashboard → admin}/ports.js +0 -0
- /package/dist/reporting/{learn → member}/model.js +0 -0
- /package/dist/reporting/{learn → member}/ports.js +0 -0
- /package/dist/{reporting/students/model.js → shared/actor.js} +0 -0
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@headless-lms/core",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.3.0",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"sideEffects": false,
|
|
6
6
|
"exports": {
|
|
@@ -30,7 +30,7 @@
|
|
|
30
30
|
],
|
|
31
31
|
"dependencies": {
|
|
32
32
|
"ksuid": "^3.0.0",
|
|
33
|
-
"zod": "4.
|
|
33
|
+
"zod": "4.6.7"
|
|
34
34
|
},
|
|
35
35
|
"devDependencies": {
|
|
36
36
|
"@types/node": "^22.10.2",
|
|
@@ -1,4 +0,0 @@
|
|
|
1
|
-
import { EnrollmentPoint, OverviewStats } from "./model.js";
|
|
2
|
-
import { DashboardReportRepository, DashboardReportService } from "./ports.js";
|
|
3
|
-
import { DashboardReportServiceImpl } from "./service.js";
|
|
4
|
-
export { type DashboardReportRepository, type DashboardReportService, DashboardReportServiceImpl, type EnrollmentPoint, type OverviewStats };
|
|
@@ -1,14 +0,0 @@
|
|
|
1
|
-
//#region src/reporting/dashboard/model.d.ts
|
|
2
|
-
interface OverviewStats {
|
|
3
|
-
publishedCourses: number;
|
|
4
|
-
draftCourses: number;
|
|
5
|
-
activeStudents: number;
|
|
6
|
-
expiringSoon: number;
|
|
7
|
-
}
|
|
8
|
-
interface EnrollmentPoint {
|
|
9
|
-
date: string;
|
|
10
|
-
count: number;
|
|
11
|
-
}
|
|
12
|
-
//#endregion
|
|
13
|
-
export { EnrollmentPoint, OverviewStats };
|
|
14
|
-
//# sourceMappingURL=model.d.ts.map
|
|
@@ -1,13 +0,0 @@
|
|
|
1
|
-
import { EnrollmentPoint, OverviewStats } from "./model.js";
|
|
2
|
-
//#region src/reporting/dashboard/ports.d.ts
|
|
3
|
-
interface DashboardReportService {
|
|
4
|
-
overview(orgId: string): Promise<OverviewStats>;
|
|
5
|
-
enrollments(orgId: string, days: number): Promise<EnrollmentPoint[]>;
|
|
6
|
-
}
|
|
7
|
-
interface DashboardReportRepository {
|
|
8
|
-
overview(orgId: string): Promise<OverviewStats>;
|
|
9
|
-
enrollments(orgId: string, days: number): Promise<EnrollmentPoint[]>;
|
|
10
|
-
}
|
|
11
|
-
//#endregion
|
|
12
|
-
export { DashboardReportRepository, DashboardReportService };
|
|
13
|
-
//# sourceMappingURL=ports.d.ts.map
|
|
@@ -1,19 +0,0 @@
|
|
|
1
|
-
import { Logger } from "../../types/ports.js";
|
|
2
|
-
import "../../shared/ports.js";
|
|
3
|
-
import { EnrollmentPoint, OverviewStats } from "./model.js";
|
|
4
|
-
import { DashboardReportRepository, DashboardReportService } from "./ports.js";
|
|
5
|
-
//#region src/reporting/dashboard/service.d.ts
|
|
6
|
-
type DashboardReportServiceParams = {
|
|
7
|
-
repo: DashboardReportRepository;
|
|
8
|
-
logger?: Logger;
|
|
9
|
-
};
|
|
10
|
-
declare class DashboardReportServiceImpl implements DashboardReportService {
|
|
11
|
-
private readonly repo;
|
|
12
|
-
private readonly logger;
|
|
13
|
-
constructor(params: DashboardReportServiceParams);
|
|
14
|
-
overview(orgId: string): Promise<OverviewStats>;
|
|
15
|
-
enrollments(orgId: string, days: number): Promise<EnrollmentPoint[]>;
|
|
16
|
-
}
|
|
17
|
-
//#endregion
|
|
18
|
-
export { DashboardReportServiceImpl, DashboardReportServiceParams };
|
|
19
|
-
//# sourceMappingURL=service.d.ts.map
|
|
@@ -1,20 +0,0 @@
|
|
|
1
|
-
import { noopLogger } from "../../shared/logger.js";
|
|
2
|
-
//#region src/reporting/dashboard/service.ts
|
|
3
|
-
var DashboardReportServiceImpl = class {
|
|
4
|
-
repo;
|
|
5
|
-
logger;
|
|
6
|
-
constructor(params) {
|
|
7
|
-
this.repo = params.repo;
|
|
8
|
-
this.logger = params.logger ?? noopLogger;
|
|
9
|
-
}
|
|
10
|
-
overview(orgId) {
|
|
11
|
-
return this.repo.overview(orgId);
|
|
12
|
-
}
|
|
13
|
-
enrollments(orgId, days) {
|
|
14
|
-
return this.repo.enrollments(orgId, days);
|
|
15
|
-
}
|
|
16
|
-
};
|
|
17
|
-
//#endregion
|
|
18
|
-
export { DashboardReportServiceImpl };
|
|
19
|
-
|
|
20
|
-
//# sourceMappingURL=service.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"service.js","names":[],"sources":["../../../src/reporting/dashboard/service.ts"],"sourcesContent":["// reporting/dashboard — service implementation (inbound port).\nimport type { EnrollmentPoint, OverviewStats } from './model.js';\nimport type { DashboardReportRepository, DashboardReportService } from './ports.js';\nimport type { Logger } from '../../shared/ports.js';\nimport { noopLogger } from '../../shared/logger.js';\n\nexport type DashboardReportServiceParams = {\n repo: DashboardReportRepository;\n logger?: Logger;\n};\n\nexport class DashboardReportServiceImpl implements DashboardReportService {\n private readonly repo: DashboardReportRepository;\n private readonly logger: Logger;\n\n constructor(params: DashboardReportServiceParams) {\n this.repo = params.repo;\n this.logger = params.logger ?? noopLogger;\n }\n\n overview(orgId: string): Promise<OverviewStats> {\n return this.repo.overview(orgId);\n }\n\n enrollments(orgId: string, days: number): Promise<EnrollmentPoint[]> {\n return this.repo.enrollments(orgId, days);\n }\n}\n"],"mappings":";;AAWA,IAAa,6BAAb,MAA0E;CACxE;CACA;CAEA,YAAY,QAAsC;EAChD,KAAK,OAAO,OAAO;EACnB,KAAK,SAAS,OAAO,UAAU;CACjC;CAEA,SAAS,OAAuC;EAC9C,OAAO,KAAK,KAAK,SAAS,KAAK;CACjC;CAEA,YAAY,OAAe,MAA0C;EACnE,OAAO,KAAK,KAAK,YAAY,OAAO,IAAI;CAC1C;AACF"}
|
|
@@ -1,5 +0,0 @@
|
|
|
1
|
-
import { Course, Module } from "../../types/schemas/content.js";
|
|
2
|
-
import { ContentRef, CourseProgressView } from "./model.js";
|
|
3
|
-
import { LearnEntitlementReader, LearnReportService } from "./ports.js";
|
|
4
|
-
import { LearnReportServiceImpl } from "./service.js";
|
|
5
|
-
export { type ContentRef, type Course, type CourseProgressView, type LearnEntitlementReader, type LearnReportService, LearnReportServiceImpl, type Module };
|
|
@@ -1,23 +0,0 @@
|
|
|
1
|
-
import { Course, Download, DownloadAsset, Module } from "../../types/schemas/content.js";
|
|
2
|
-
import "../../content/index.js";
|
|
3
|
-
//#region src/reporting/learn/model.d.ts
|
|
4
|
-
/** An active-entitlement pointer: the org + content item a student may consume. */
|
|
5
|
-
interface ContentRef {
|
|
6
|
-
orgId: string;
|
|
7
|
-
contentId: string;
|
|
8
|
-
}
|
|
9
|
-
/** Per-course progress for the student surface. Derived on read against the
|
|
10
|
-
* current published structure — never stored. */
|
|
11
|
-
interface CourseProgressView {
|
|
12
|
-
/** Keyed by activity id; absent key = not started. */
|
|
13
|
-
activities: Record<string, 'in-progress' | 'completed'>;
|
|
14
|
-
/** Integer 0–100: completed ÷ current published activities, rounded. */
|
|
15
|
-
percent: number;
|
|
16
|
-
/** The course target's own record says so. */
|
|
17
|
-
completed: boolean;
|
|
18
|
-
/** Per-activity reported state (the record's position map); absent key = none reported. */
|
|
19
|
-
positions: Record<string, unknown>;
|
|
20
|
-
}
|
|
21
|
-
//#endregion
|
|
22
|
-
export { ContentRef, type Course, CourseProgressView, type Download, type DownloadAsset, type Module };
|
|
23
|
-
//# sourceMappingURL=model.d.ts.map
|
|
@@ -1,42 +0,0 @@
|
|
|
1
|
-
import { Course, Download, DownloadAsset, Module } from "../../types/schemas/content.js";
|
|
2
|
-
import { ContentRef, CourseProgressView } from "./model.js";
|
|
3
|
-
//#region src/reporting/learn/ports.d.ts
|
|
4
|
-
/**
|
|
5
|
-
* Inbound: the student-scoped read use-cases. Scoped by `(orgId, orgUserId)` —
|
|
6
|
-
* the portal org resolved at the boundary. `null` ⇒ not enrolled (→ 404).
|
|
7
|
-
*/
|
|
8
|
-
interface LearnReportService {
|
|
9
|
-
listCourses(orgId: string, orgUserId: string): Promise<Course[]>;
|
|
10
|
-
getCourse(orgId: string, orgUserId: string, courseId: string): Promise<Course | null>;
|
|
11
|
-
listModules(orgId: string, orgUserId: string, courseId: string): Promise<Module[] | null>;
|
|
12
|
-
courseProgress(orgId: string, orgUserId: string, courseId: string): Promise<CourseProgressView | null>;
|
|
13
|
-
listDownloads(orgId: string, orgUserId: string): Promise<Download[]>;
|
|
14
|
-
getDownload(orgId: string, orgUserId: string, downloadId: string): Promise<{
|
|
15
|
-
download: Download;
|
|
16
|
-
assets: DownloadAsset[];
|
|
17
|
-
} | null>;
|
|
18
|
-
/** Entitlement-gated. Returns null (→ 404) for every failure — never 403,
|
|
19
|
-
* which would confirm the resource exists to someone not entitled to it. */
|
|
20
|
-
downloadAssetUrl(orgId: string, orgUserId: string, downloadId: string, assetId: string): Promise<{
|
|
21
|
-
url: string;
|
|
22
|
-
filename: string;
|
|
23
|
-
} | null>;
|
|
24
|
-
}
|
|
25
|
-
/**
|
|
26
|
-
* Outbound: the student's active, non-expired course entitlements in PUBLISHED
|
|
27
|
-
* courses, scoped to the portal org. Implemented by a Drizzle read repo; the
|
|
28
|
-
* service resolves each ref against the content service for the full
|
|
29
|
-
* Course/Module payload.
|
|
30
|
-
*/
|
|
31
|
-
interface LearnEntitlementReader {
|
|
32
|
-
activeRefs(orgId: string, orgUserId: string): Promise<ContentRef[]>;
|
|
33
|
-
activeRef(orgId: string, orgUserId: string, courseId: string): Promise<ContentRef | null>;
|
|
34
|
-
/** Active, non-expired grants to PUBLISHED downloads, scoped to the org. */
|
|
35
|
-
activeDownloadRefs(orgId: string, orgUserId: string): Promise<ContentRef[]>;
|
|
36
|
-
activeDownloadRef(orgId: string, orgUserId: string, downloadId: string): Promise<ContentRef | null>;
|
|
37
|
-
/** Whether this asset is linked to this download. The paywall's second gate. */
|
|
38
|
-
downloadHasAsset(orgId: string, downloadId: string, assetId: string): Promise<boolean>;
|
|
39
|
-
}
|
|
40
|
-
//#endregion
|
|
41
|
-
export { LearnEntitlementReader, LearnReportService };
|
|
42
|
-
//# sourceMappingURL=ports.d.ts.map
|
|
@@ -1,48 +0,0 @@
|
|
|
1
|
-
import { Logger } from "../../types/ports.js";
|
|
2
|
-
import { Course, Download, DownloadAsset, Module } from "../../types/schemas/content.js";
|
|
3
|
-
import "../../shared/ports.js";
|
|
4
|
-
import { AssetsService } from "../../assets/ports.js";
|
|
5
|
-
import "../../assets/index.js";
|
|
6
|
-
import { ContentService } from "../../content/ports.js";
|
|
7
|
-
import "../../content/index.js";
|
|
8
|
-
import { ProgressService } from "../../progress/ports.js";
|
|
9
|
-
import "../../progress/index.js";
|
|
10
|
-
import { CourseProgressView } from "./model.js";
|
|
11
|
-
import { LearnEntitlementReader, LearnReportService } from "./ports.js";
|
|
12
|
-
//#region src/reporting/learn/service.d.ts
|
|
13
|
-
type LearnReportServiceParams = {
|
|
14
|
-
reader: LearnEntitlementReader;
|
|
15
|
-
content: ContentService;
|
|
16
|
-
progress: ProgressService;
|
|
17
|
-
assets: AssetsService;
|
|
18
|
-
deliveryExpirySeconds: number;
|
|
19
|
-
logger?: Logger;
|
|
20
|
-
};
|
|
21
|
-
declare class LearnReportServiceImpl implements LearnReportService {
|
|
22
|
-
private readonly reader;
|
|
23
|
-
private readonly content;
|
|
24
|
-
private readonly progress;
|
|
25
|
-
private readonly assets;
|
|
26
|
-
private readonly deliveryExpirySeconds;
|
|
27
|
-
private readonly logger;
|
|
28
|
-
constructor(params: LearnReportServiceParams);
|
|
29
|
-
listCourses(orgId: string, orgUserId: string): Promise<Course[]>;
|
|
30
|
-
getCourse(orgId: string, orgUserId: string, courseId: string): Promise<Course | null>;
|
|
31
|
-
listModules(orgId: string, orgUserId: string, courseId: string): Promise<Module[] | null>;
|
|
32
|
-
courseProgress(orgId: string, orgUserId: string, courseId: string): Promise<CourseProgressView | null>;
|
|
33
|
-
listDownloads(orgId: string, orgUserId: string): Promise<Download[]>;
|
|
34
|
-
getDownload(orgId: string, orgUserId: string, downloadId: string): Promise<{
|
|
35
|
-
download: Download;
|
|
36
|
-
assets: DownloadAsset[];
|
|
37
|
-
} | null>;
|
|
38
|
-
/** The paywall. Two gates, in order: an active entitlement to a published
|
|
39
|
-
* download, then the asset actually belonging to that download — so a
|
|
40
|
-
* student entitled to X cannot reach an asset of Y by swapping the id. */
|
|
41
|
-
downloadAssetUrl(orgId: string, orgUserId: string, downloadId: string, assetId: string): Promise<{
|
|
42
|
-
url: string;
|
|
43
|
-
filename: string;
|
|
44
|
-
} | null>;
|
|
45
|
-
}
|
|
46
|
-
//#endregion
|
|
47
|
-
export { LearnReportServiceImpl, LearnReportServiceParams };
|
|
48
|
-
//# sourceMappingURL=service.d.ts.map
|
|
@@ -1,111 +0,0 @@
|
|
|
1
|
-
import { noopLogger } from "../../shared/logger.js";
|
|
2
|
-
//#region src/reporting/learn/service.ts
|
|
3
|
-
function isActivityPublished(settings) {
|
|
4
|
-
return settings?.published !== false;
|
|
5
|
-
}
|
|
6
|
-
var LearnReportServiceImpl = class {
|
|
7
|
-
reader;
|
|
8
|
-
content;
|
|
9
|
-
progress;
|
|
10
|
-
assets;
|
|
11
|
-
deliveryExpirySeconds;
|
|
12
|
-
logger;
|
|
13
|
-
constructor(params) {
|
|
14
|
-
this.reader = params.reader;
|
|
15
|
-
this.content = params.content;
|
|
16
|
-
this.progress = params.progress;
|
|
17
|
-
this.assets = params.assets;
|
|
18
|
-
this.deliveryExpirySeconds = params.deliveryExpirySeconds;
|
|
19
|
-
this.logger = params.logger ?? noopLogger;
|
|
20
|
-
}
|
|
21
|
-
async listCourses(orgId, orgUserId) {
|
|
22
|
-
const refs = await this.reader.activeRefs(orgId, orgUserId);
|
|
23
|
-
return (await Promise.all(refs.map((ref) => this.content.getCourse(ref.orgId, ref.contentId)))).filter((c) => c !== null && c.status === "published");
|
|
24
|
-
}
|
|
25
|
-
async getCourse(orgId, orgUserId, courseId) {
|
|
26
|
-
const ref = await this.reader.activeRef(orgId, orgUserId, courseId);
|
|
27
|
-
if (!ref) return null;
|
|
28
|
-
const course = await this.content.getCourse(ref.orgId, courseId);
|
|
29
|
-
return course && course.status === "published" ? course : null;
|
|
30
|
-
}
|
|
31
|
-
async listModules(orgId, orgUserId, courseId) {
|
|
32
|
-
const ref = await this.reader.activeRef(orgId, orgUserId, courseId);
|
|
33
|
-
if (!ref) return null;
|
|
34
|
-
return this.content.listCourseModules(ref.orgId, courseId);
|
|
35
|
-
}
|
|
36
|
-
async courseProgress(orgId, orgUserId, courseId) {
|
|
37
|
-
const ref = await this.reader.activeRef(orgId, orgUserId, courseId);
|
|
38
|
-
if (!ref) return null;
|
|
39
|
-
const ids = (await this.content.listCourseActivities(ref.orgId, courseId)).filter((a) => isActivityPublished(a.settings)).map((a) => a.id);
|
|
40
|
-
const records = await this.progress.listByTargets(ref.orgId, orgUserId, ids);
|
|
41
|
-
const activities = {};
|
|
42
|
-
const positions = {};
|
|
43
|
-
let done = 0;
|
|
44
|
-
for (const r of records) {
|
|
45
|
-
if (r.targetType !== "activity") continue;
|
|
46
|
-
activities[r.targetId] = r.completedAt ? "completed" : "in-progress";
|
|
47
|
-
if (r.completedAt) done += 1;
|
|
48
|
-
if (r.position != null) positions[r.targetId] = r.position;
|
|
49
|
-
}
|
|
50
|
-
const courseRecord = await this.progress.get(ref.orgId, {
|
|
51
|
-
orgUserId,
|
|
52
|
-
targetType: "course",
|
|
53
|
-
targetId: courseId
|
|
54
|
-
});
|
|
55
|
-
return {
|
|
56
|
-
activities,
|
|
57
|
-
percent: ids.length > 0 ? Math.round(done / ids.length * 100) : 0,
|
|
58
|
-
completed: courseRecord?.completedAt != null,
|
|
59
|
-
positions
|
|
60
|
-
};
|
|
61
|
-
}
|
|
62
|
-
async listDownloads(orgId, orgUserId) {
|
|
63
|
-
const refs = await this.reader.activeDownloadRefs(orgId, orgUserId);
|
|
64
|
-
return (await Promise.all(refs.map((ref) => this.content.getDownload(ref.orgId, ref.contentId)))).filter((d) => d !== null && d.status === "published");
|
|
65
|
-
}
|
|
66
|
-
async getDownload(orgId, orgUserId, downloadId) {
|
|
67
|
-
const ref = await this.reader.activeDownloadRef(orgId, orgUserId, downloadId);
|
|
68
|
-
if (!ref) return null;
|
|
69
|
-
const download = await this.content.getDownload(ref.orgId, downloadId);
|
|
70
|
-
if (!download || download.status !== "published") return null;
|
|
71
|
-
return {
|
|
72
|
-
download,
|
|
73
|
-
assets: await this.content.listDownloadAssets(ref.orgId, downloadId)
|
|
74
|
-
};
|
|
75
|
-
}
|
|
76
|
-
/** The paywall. Two gates, in order: an active entitlement to a published
|
|
77
|
-
* download, then the asset actually belonging to that download — so a
|
|
78
|
-
* student entitled to X cannot reach an asset of Y by swapping the id. */
|
|
79
|
-
async downloadAssetUrl(orgId, orgUserId, downloadId, assetId) {
|
|
80
|
-
const ref = await this.reader.activeDownloadRef(orgId, orgUserId, downloadId);
|
|
81
|
-
if (!ref) return null;
|
|
82
|
-
if (!await this.reader.downloadHasAsset(ref.orgId, downloadId, assetId)) {
|
|
83
|
-
this.logger.warn("download asset not linked", {
|
|
84
|
-
orgId,
|
|
85
|
-
downloadId,
|
|
86
|
-
assetId
|
|
87
|
-
});
|
|
88
|
-
return null;
|
|
89
|
-
}
|
|
90
|
-
const link = (await this.content.listDownloadAssets(ref.orgId, downloadId)).find((l) => l.assetId === assetId);
|
|
91
|
-
if (!link) return null;
|
|
92
|
-
const asset = await this.assets.get(ref.orgId, assetId);
|
|
93
|
-
if (!asset) return null;
|
|
94
|
-
const filename = link.displayName ?? asset.filename;
|
|
95
|
-
const ticket = await this.assets.requestDownload(ref.orgId, assetId, filename, this.deliveryExpirySeconds);
|
|
96
|
-
if (!ticket) return null;
|
|
97
|
-
this.logger.info("download asset signed", {
|
|
98
|
-
orgId,
|
|
99
|
-
downloadId,
|
|
100
|
-
assetId
|
|
101
|
-
});
|
|
102
|
-
return {
|
|
103
|
-
url: ticket.url,
|
|
104
|
-
filename
|
|
105
|
-
};
|
|
106
|
-
}
|
|
107
|
-
};
|
|
108
|
-
//#endregion
|
|
109
|
-
export { LearnReportServiceImpl };
|
|
110
|
-
|
|
111
|
-
//# sourceMappingURL=service.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"service.js","names":[],"sources":["../../../src/reporting/learn/service.ts"],"sourcesContent":["// reporting/learn — service implementation. Composes the enrollment reader\n// (which published courses the student is actively enrolled in) with the content\n// service (the Course/Module payload). Activities are filtered to published;\n// `settings.published === false` is the only draft signal (missing ⇒ published).\nimport type { ContentService } from '../../content/index.js';\nimport type { ProgressService } from '../../progress/index.js';\nimport type { AssetsService } from '../../assets/index.js';\nimport type { Course, Module, CourseProgressView, Download, DownloadAsset } from './model.js';\nimport type { LearnEntitlementReader, LearnReportService } from './ports.js';\nimport type { Logger } from '../../shared/ports.js';\nimport { noopLogger } from '../../shared/logger.js';\n\nfunction isActivityPublished(settings: unknown): boolean {\n return (settings as { published?: boolean } | null)?.published !== false;\n}\n\nexport type LearnReportServiceParams = {\n reader: LearnEntitlementReader;\n content: ContentService;\n progress: ProgressService;\n assets: AssetsService;\n deliveryExpirySeconds: number;\n logger?: Logger;\n};\n\nexport class LearnReportServiceImpl implements LearnReportService {\n private readonly reader: LearnEntitlementReader;\n private readonly content: ContentService;\n private readonly progress: ProgressService;\n private readonly assets: AssetsService;\n private readonly deliveryExpirySeconds: number;\n private readonly logger: Logger;\n\n constructor(params: LearnReportServiceParams) {\n this.reader = params.reader;\n this.content = params.content;\n this.progress = params.progress;\n this.assets = params.assets;\n this.deliveryExpirySeconds = params.deliveryExpirySeconds;\n this.logger = params.logger ?? noopLogger;\n }\n\n async listCourses(orgId: string, orgUserId: string): Promise<Course[]> {\n const refs = await this.reader.activeRefs(orgId, orgUserId);\n const courses = await Promise.all(\n refs.map((ref) => this.content.getCourse(ref.orgId, ref.contentId)),\n );\n return courses.filter((c): c is Course => c !== null && c.status === 'published');\n }\n\n async getCourse(orgId: string, orgUserId: string, courseId: string): Promise<Course | null> {\n const ref = await this.reader.activeRef(orgId, orgUserId, courseId);\n if (!ref) {\n return null;\n }\n const course = await this.content.getCourse(ref.orgId, courseId);\n return course && course.status === 'published' ? course : null;\n }\n\n async listModules(orgId: string, orgUserId: string, courseId: string): Promise<Module[] | null> {\n const ref = await this.reader.activeRef(orgId, orgUserId, courseId);\n if (!ref) {\n return null;\n }\n return this.content.listCourseModules(ref.orgId, courseId);\n }\n\n async courseProgress(\n orgId: string,\n orgUserId: string,\n courseId: string,\n ): Promise<CourseProgressView | null> {\n const ref = await this.reader.activeRef(orgId, orgUserId, courseId);\n if (!ref) {\n return null;\n }\n const courseActivities = await this.content.listCourseActivities(ref.orgId, courseId);\n const ids = courseActivities.filter((a) => isActivityPublished(a.settings)).map((a) => a.id);\n const records = await this.progress.listByTargets(ref.orgId, orgUserId, ids);\n const activities: CourseProgressView['activities'] = {};\n const positions: CourseProgressView['positions'] = {};\n let done = 0;\n for (const r of records) {\n if (r.targetType !== 'activity') {\n continue;\n }\n activities[r.targetId] = r.completedAt ? 'completed' : 'in-progress';\n if (r.completedAt) {\n done += 1;\n }\n if (r.position != null) {\n positions[r.targetId] = r.position;\n }\n }\n const courseRecord = await this.progress.get(ref.orgId, {\n orgUserId,\n targetType: 'course',\n targetId: courseId,\n });\n return {\n activities,\n percent: ids.length > 0 ? Math.round((done / ids.length) * 100) : 0,\n completed: courseRecord?.completedAt != null,\n positions,\n };\n }\n\n async listDownloads(orgId: string, orgUserId: string): Promise<Download[]> {\n const refs = await this.reader.activeDownloadRefs(orgId, orgUserId);\n const rows = await Promise.all(\n refs.map((ref) => this.content.getDownload(ref.orgId, ref.contentId)),\n );\n return rows.filter((d): d is Download => d !== null && d.status === 'published');\n }\n\n async getDownload(\n orgId: string,\n orgUserId: string,\n downloadId: string,\n ): Promise<{ download: Download; assets: DownloadAsset[] } | null> {\n const ref = await this.reader.activeDownloadRef(orgId, orgUserId, downloadId);\n if (!ref) {\n return null;\n }\n const download = await this.content.getDownload(ref.orgId, downloadId);\n if (!download || download.status !== 'published') {\n return null;\n }\n const assets = await this.content.listDownloadAssets(ref.orgId, downloadId);\n return { download, assets };\n }\n\n /** The paywall. Two gates, in order: an active entitlement to a published\n * download, then the asset actually belonging to that download — so a\n * student entitled to X cannot reach an asset of Y by swapping the id. */\n async downloadAssetUrl(\n orgId: string,\n orgUserId: string,\n downloadId: string,\n assetId: string,\n ): Promise<{ url: string; filename: string } | null> {\n const ref = await this.reader.activeDownloadRef(orgId, orgUserId, downloadId);\n if (!ref) {\n return null;\n }\n const linked = await this.reader.downloadHasAsset(ref.orgId, downloadId, assetId);\n if (!linked) {\n this.logger.warn('download asset not linked', { orgId, downloadId, assetId });\n return null;\n }\n const links = await this.content.listDownloadAssets(ref.orgId, downloadId);\n const link = links.find((l) => l.assetId === assetId);\n if (!link) {\n return null;\n }\n const asset = await this.assets.get(ref.orgId, assetId);\n if (!asset) {\n return null;\n }\n const filename = link.displayName ?? asset.filename;\n const ticket = await this.assets.requestDownload(\n ref.orgId,\n assetId,\n filename,\n this.deliveryExpirySeconds,\n );\n if (!ticket) {\n return null;\n }\n // Never log the signed URL — it is a bearer capability.\n this.logger.info('download asset signed', { orgId, downloadId, assetId });\n return { url: ticket.url, filename };\n }\n}\n"],"mappings":"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"}
|
|
@@ -1,4 +0,0 @@
|
|
|
1
|
-
import { Page, Student, StudentsQuery } from "./model.js";
|
|
2
|
-
import { StudentsReportRepository, StudentsReportService } from "./ports.js";
|
|
3
|
-
import { StudentsReportServiceImpl } from "./service.js";
|
|
4
|
-
export { type Page, type Student, type StudentsQuery, type StudentsReportRepository, type StudentsReportService, StudentsReportServiceImpl };
|
|
@@ -1,31 +0,0 @@
|
|
|
1
|
-
import { OrgUserProfile, OrgUserStatus } from "../../types/schemas/organizations.js";
|
|
2
|
-
import "../../types/index.js";
|
|
3
|
-
//#region src/reporting/students/model.d.ts
|
|
4
|
-
interface Student extends OrgUserProfile {
|
|
5
|
-
/** As typed on the invite form. `name` is the composed rendering name and
|
|
6
|
-
* drifts once the person edits their own profile; these are what the admin
|
|
7
|
-
* edits. Null for anyone who arrived by self-signup. */
|
|
8
|
-
firstName: string | null;
|
|
9
|
-
lastName: string | null;
|
|
10
|
-
entitlementCount: number;
|
|
11
|
-
avgProgress: number;
|
|
12
|
-
/** `invited` until they accept — the admin added them, they have not arrived. */
|
|
13
|
-
status: OrgUserStatus;
|
|
14
|
-
joinedAt: string;
|
|
15
|
-
lastActiveAt: string | null;
|
|
16
|
-
}
|
|
17
|
-
interface StudentsQuery {
|
|
18
|
-
page: number;
|
|
19
|
-
pageSize: number;
|
|
20
|
-
search?: string | undefined;
|
|
21
|
-
sort?: string | undefined;
|
|
22
|
-
}
|
|
23
|
-
interface Page<T> {
|
|
24
|
-
rows: T[];
|
|
25
|
-
total: number;
|
|
26
|
-
page: number;
|
|
27
|
-
pageSize: number;
|
|
28
|
-
}
|
|
29
|
-
//#endregion
|
|
30
|
-
export { Page, Student, StudentsQuery };
|
|
31
|
-
//# sourceMappingURL=model.d.ts.map
|
|
@@ -1,13 +0,0 @@
|
|
|
1
|
-
import { Page, Student, StudentsQuery } from "./model.js";
|
|
2
|
-
//#region src/reporting/students/ports.d.ts
|
|
3
|
-
interface StudentsReportService {
|
|
4
|
-
list(orgId: string, query: StudentsQuery): Promise<Page<Student>>;
|
|
5
|
-
get(orgId: string, id: string): Promise<Student | null>;
|
|
6
|
-
}
|
|
7
|
-
interface StudentsReportRepository {
|
|
8
|
-
list(orgId: string, query: StudentsQuery): Promise<Page<Student>>;
|
|
9
|
-
findById(orgId: string, id: string): Promise<Student | null>;
|
|
10
|
-
}
|
|
11
|
-
//#endregion
|
|
12
|
-
export { StudentsReportRepository, StudentsReportService };
|
|
13
|
-
//# sourceMappingURL=ports.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export {};
|
|
@@ -1,19 +0,0 @@
|
|
|
1
|
-
import { Logger } from "../../types/ports.js";
|
|
2
|
-
import "../../shared/ports.js";
|
|
3
|
-
import { Page, Student, StudentsQuery } from "./model.js";
|
|
4
|
-
import { StudentsReportRepository, StudentsReportService } from "./ports.js";
|
|
5
|
-
//#region src/reporting/students/service.d.ts
|
|
6
|
-
type StudentsReportServiceParams = {
|
|
7
|
-
repo: StudentsReportRepository;
|
|
8
|
-
logger?: Logger;
|
|
9
|
-
};
|
|
10
|
-
declare class StudentsReportServiceImpl implements StudentsReportService {
|
|
11
|
-
private readonly repo;
|
|
12
|
-
private readonly logger;
|
|
13
|
-
constructor(params: StudentsReportServiceParams);
|
|
14
|
-
list(orgId: string, query: StudentsQuery): Promise<Page<Student>>;
|
|
15
|
-
get(orgId: string, id: string): Promise<Student | null>;
|
|
16
|
-
}
|
|
17
|
-
//#endregion
|
|
18
|
-
export { StudentsReportServiceImpl, StudentsReportServiceParams };
|
|
19
|
-
//# sourceMappingURL=service.d.ts.map
|
|
@@ -1,20 +0,0 @@
|
|
|
1
|
-
import { noopLogger } from "../../shared/logger.js";
|
|
2
|
-
//#region src/reporting/students/service.ts
|
|
3
|
-
var StudentsReportServiceImpl = class {
|
|
4
|
-
repo;
|
|
5
|
-
logger;
|
|
6
|
-
constructor(params) {
|
|
7
|
-
this.repo = params.repo;
|
|
8
|
-
this.logger = params.logger ?? noopLogger;
|
|
9
|
-
}
|
|
10
|
-
list(orgId, query) {
|
|
11
|
-
return this.repo.list(orgId, query);
|
|
12
|
-
}
|
|
13
|
-
get(orgId, id) {
|
|
14
|
-
return this.repo.findById(orgId, id);
|
|
15
|
-
}
|
|
16
|
-
};
|
|
17
|
-
//#endregion
|
|
18
|
-
export { StudentsReportServiceImpl };
|
|
19
|
-
|
|
20
|
-
//# sourceMappingURL=service.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"service.js","names":[],"sources":["../../../src/reporting/students/service.ts"],"sourcesContent":["// reporting/students — service implementation (inbound port).\nimport type { Page, Student, StudentsQuery } from './model.js';\nimport type { StudentsReportRepository, StudentsReportService } from './ports.js';\nimport type { Logger } from '../../shared/ports.js';\nimport { noopLogger } from '../../shared/logger.js';\n\nexport type StudentsReportServiceParams = {\n repo: StudentsReportRepository;\n logger?: Logger;\n};\n\nexport class StudentsReportServiceImpl implements StudentsReportService {\n private readonly repo: StudentsReportRepository;\n private readonly logger: Logger;\n\n constructor(params: StudentsReportServiceParams) {\n this.repo = params.repo;\n this.logger = params.logger ?? noopLogger;\n }\n\n list(orgId: string, query: StudentsQuery): Promise<Page<Student>> {\n return this.repo.list(orgId, query);\n }\n\n get(orgId: string, id: string): Promise<Student | null> {\n return this.repo.findById(orgId, id);\n }\n}\n"],"mappings":";;AAWA,IAAa,4BAAb,MAAwE;CACtE;CACA;CAEA,YAAY,QAAqC;EAC/C,KAAK,OAAO,OAAO;EACnB,KAAK,SAAS,OAAO,UAAU;CACjC;CAEA,KAAK,OAAe,OAA8C;EAChE,OAAO,KAAK,KAAK,KAAK,OAAO,KAAK;CACpC;CAEA,IAAI,OAAe,IAAqC;EACtD,OAAO,KAAK,KAAK,SAAS,OAAO,EAAE;CACrC;AACF"}
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|