@happyvertical/smrt-education 0.0.0-stage → 0.57.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.
Files changed (41) hide show
  1. package/AGENTS.md +32 -0
  2. package/CLAUDE.md +1 -0
  3. package/LICENSE +7 -0
  4. package/README.md +139 -2
  5. package/agents/catalog-service.md +45 -0
  6. package/agents/learner-service.md +101 -0
  7. package/agents/source-import.md +63 -0
  8. package/agents/submission-service.md +122 -0
  9. package/dist/__smrt-register__.d.ts +2 -0
  10. package/dist/__smrt-register__.d.ts.map +1 -0
  11. package/dist/catalog-service.d.ts +50 -0
  12. package/dist/catalog-service.d.ts.map +1 -0
  13. package/dist/catalog.d.ts +72 -0
  14. package/dist/catalog.d.ts.map +1 -0
  15. package/dist/collections.d.ts +70 -0
  16. package/dist/collections.d.ts.map +1 -0
  17. package/dist/course-source.d.ts +25 -0
  18. package/dist/course-source.d.ts.map +1 -0
  19. package/dist/index.d.ts +24 -0
  20. package/dist/index.d.ts.map +1 -0
  21. package/dist/index.js +24733 -0
  22. package/dist/index.js.map +1 -0
  23. package/dist/learner-service.d.ts +95 -0
  24. package/dist/learner-service.d.ts.map +1 -0
  25. package/dist/learners.d.ts +58 -0
  26. package/dist/learners.d.ts.map +1 -0
  27. package/dist/lesson-assets.d.ts +12 -0
  28. package/dist/lesson-assets.d.ts.map +1 -0
  29. package/dist/manifest.json +9484 -0
  30. package/dist/recipes.d.ts +50 -0
  31. package/dist/recipes.d.ts.map +1 -0
  32. package/dist/smrt-knowledge.json +3600 -0
  33. package/dist/source-import-service.d.ts +50 -0
  34. package/dist/source-import-service.d.ts.map +1 -0
  35. package/dist/sources/easy-peasy-parser.d.ts +23 -0
  36. package/dist/sources/easy-peasy-parser.d.ts.map +1 -0
  37. package/dist/submission-service.d.ts +110 -0
  38. package/dist/submission-service.d.ts.map +1 -0
  39. package/dist/submissions.d.ts +70 -0
  40. package/dist/submissions.d.ts.map +1 -0
  41. package/package.json +64 -3
@@ -0,0 +1,95 @@
1
+ import type { DatabaseInterface } from '@happyvertical/sql';
2
+ import { type CatalogAuthorizer } from './catalog-service.js';
3
+ import type { Curriculum, Enrollment, Learner, LessonProgress } from './learners.js';
4
+ /** Inputs are identifiers, never an authority claim or model patch. */
5
+ export interface LearnerRequest {
6
+ tenantId: string;
7
+ actorUserId: string;
8
+ learnerId: string;
9
+ guardianRelationshipId?: string;
10
+ }
11
+ /** The host validates relationship type/terms and its own permission policy. */
12
+ export type LearnerAuthorizer = (request: LearnerRequest & {
13
+ action: 'education.learner.read' | 'education.learner.plan' | 'education.learner.start' | 'education.learner.submit' | 'education.learner.grade' | 'education.learner.packet';
14
+ own: boolean;
15
+ relationshipTypeId?: string;
16
+ }) => boolean | Promise<boolean>;
17
+ export declare class LearnerAuthorizationError extends Error {
18
+ constructor();
19
+ }
20
+ /** Service results contain data only, with no transaction-bound model handle. */
21
+ export type LearnerView = Readonly<{
22
+ id: string;
23
+ tenantId: string;
24
+ userId: string;
25
+ profileId: string;
26
+ displayName: string;
27
+ level: number;
28
+ settings: Record<string, unknown>;
29
+ }>;
30
+ export type CurriculumView = Readonly<{
31
+ id: string;
32
+ learnerId: string;
33
+ title: string;
34
+ status: Curriculum['status'];
35
+ }>;
36
+ export type EnrollmentView = Readonly<{
37
+ id: string;
38
+ learnerId: string;
39
+ curriculumId: string;
40
+ courseId: string;
41
+ status: Enrollment['status'];
42
+ }>;
43
+ export type LessonProgressView = Readonly<{
44
+ id: string;
45
+ learnerId: string;
46
+ enrollmentId: string;
47
+ lessonId: string;
48
+ status: LessonProgress['status'];
49
+ bestScore: number | null;
50
+ attempts: number;
51
+ timeSpentSeconds: number;
52
+ startedAt: Date | null;
53
+ completedAt: Date | null;
54
+ }>;
55
+ /** Closed models are exposed only through this actor-bound resource boundary. */
56
+ export declare class LearnerService {
57
+ protected readonly db: DatabaseInterface;
58
+ protected readonly authorize: LearnerAuthorizer;
59
+ protected readonly authorizeCatalog: CatalogAuthorizer;
60
+ private transactionState;
61
+ private writeFailure;
62
+ private writeTail;
63
+ private postgres;
64
+ constructor(db: DatabaseInterface, authorize: LearnerAuthorizer, authorizeCatalog: CatalogAuthorizer);
65
+ /** Compose planning/start operations atomically using the callback's service. */
66
+ withTransaction<T>(operation: (service: this) => Promise<T>): Promise<T>;
67
+ /** Internal subclass hook: preserve the concrete owning service in a transaction. */
68
+ protected createTransactionService(db: DatabaseInterface): this;
69
+ /** Internal compensation hook, invoked after in-flight work drains on abort. */
70
+ protected rollbackResources(_cause: unknown, _rootDb: DatabaseInterface): Promise<void>;
71
+ protected mutate<T>(operation: (service: this) => Promise<T>): Promise<T>;
72
+ protected requireActor(request: LearnerRequest, action: Parameters<LearnerAuthorizer>[0]['action']): Promise<Learner>;
73
+ getLearner(request: LearnerRequest): Promise<LearnerView>;
74
+ createCurriculum(request: LearnerRequest & {
75
+ title: string;
76
+ }): Promise<CurriculumView>;
77
+ protected catalog(request: LearnerRequest, courseId: string): Promise<import("./catalog-service.js").CatalogProjection>;
78
+ protected lock(table: 'curricula' | 'enrollments', id: string, tenant: string): Promise<void>;
79
+ enroll(request: LearnerRequest & {
80
+ curriculumId: string;
81
+ courseId: string;
82
+ }): Promise<EnrollmentView>;
83
+ protected requireEnrollment(request: LearnerRequest & {
84
+ enrollmentId: string;
85
+ }, action: Parameters<LearnerAuthorizer>[0]['action']): Promise<Enrollment>;
86
+ listProgress(request: LearnerRequest & {
87
+ enrollmentId: string;
88
+ }): Promise<LessonProgressView[]>;
89
+ /** Start once. Caller-supplied learner/status/score/counter patches are never applied. */
90
+ startLesson(request: LearnerRequest & {
91
+ enrollmentId: string;
92
+ lessonId: string;
93
+ }): Promise<LessonProgressView>;
94
+ }
95
+ //# sourceMappingURL=learner-service.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"learner-service.d.ts","sourceRoot":"","sources":["../src/learner-service.ts"],"names":[],"mappings":"AAOA,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,oBAAoB,CAAC;AAC5D,OAAO,EAAE,KAAK,iBAAiB,EAAkB,MAAM,sBAAsB,CAAC;AAW9E,OAAO,KAAK,EACV,UAAU,EACV,UAAU,EACV,OAAO,EACP,cAAc,EACf,MAAM,eAAe,CAAC;AAEvB,uEAAuE;AACvE,MAAM,WAAW,cAAc;IAC7B,QAAQ,EAAE,MAAM,CAAC;IACjB,WAAW,EAAE,MAAM,CAAC;IACpB,SAAS,EAAE,MAAM,CAAC;IAClB,sBAAsB,CAAC,EAAE,MAAM,CAAC;CACjC;AAED,gFAAgF;AAChF,MAAM,MAAM,iBAAiB,GAAG,CAC9B,OAAO,EAAE,cAAc,GAAG;IACxB,MAAM,EACF,wBAAwB,GACxB,wBAAwB,GACxB,yBAAyB,GACzB,0BAA0B,GAC1B,yBAAyB,GACzB,0BAA0B,CAAC;IAC/B,GAAG,EAAE,OAAO,CAAC;IACb,kBAAkB,CAAC,EAAE,MAAM,CAAC;CAC7B,KACE,OAAO,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC;AAEhC,qBAAa,yBAA0B,SAAQ,KAAK;;CAKnD;AAED,iFAAiF;AACjF,MAAM,MAAM,WAAW,GAAG,QAAQ,CAAC;IACjC,EAAE,EAAE,MAAM,CAAC;IACX,QAAQ,EAAE,MAAM,CAAC;IACjB,MAAM,EAAE,MAAM,CAAC;IACf,SAAS,EAAE,MAAM,CAAC;IAClB,WAAW,EAAE,MAAM,CAAC;IACpB,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CACnC,CAAC,CAAC;AACH,MAAM,MAAM,cAAc,GAAG,QAAQ,CAAC;IACpC,EAAE,EAAE,MAAM,CAAC;IACX,SAAS,EAAE,MAAM,CAAC;IAClB,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,UAAU,CAAC,QAAQ,CAAC,CAAC;CAC9B,CAAC,CAAC;AACH,MAAM,MAAM,cAAc,GAAG,QAAQ,CAAC;IACpC,EAAE,EAAE,MAAM,CAAC;IACX,SAAS,EAAE,MAAM,CAAC;IAClB,YAAY,EAAE,MAAM,CAAC;IACrB,QAAQ,EAAE,MAAM,CAAC;IACjB,MAAM,EAAE,UAAU,CAAC,QAAQ,CAAC,CAAC;CAC9B,CAAC,CAAC;AACH,MAAM,MAAM,kBAAkB,GAAG,QAAQ,CAAC;IACxC,EAAE,EAAE,MAAM,CAAC;IACX,SAAS,EAAE,MAAM,CAAC;IAClB,YAAY,EAAE,MAAM,CAAC;IACrB,QAAQ,EAAE,MAAM,CAAC;IACjB,MAAM,EAAE,cAAc,CAAC,QAAQ,CAAC,CAAC;IACjC,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;IACzB,QAAQ,EAAE,MAAM,CAAC;IACjB,gBAAgB,EAAE,MAAM,CAAC;IACzB,SAAS,EAAE,IAAI,GAAG,IAAI,CAAC;IACvB,WAAW,EAAE,IAAI,GAAG,IAAI,CAAC;CAC1B,CAAC,CAAC;AAiCH,iFAAiF;AACjF,qBAAa,cAAc;IAWvB,SAAS,CAAC,QAAQ,CAAC,EAAE,EAAE,iBAAiB;IACxC,SAAS,CAAC,QAAQ,CAAC,SAAS,EAAE,iBAAiB;IAC/C,SAAS,CAAC,QAAQ,CAAC,gBAAgB,EAAE,iBAAiB;IAZxD,OAAO,CAAC,gBAAgB,CAKV;IACd,OAAO,CAAC,YAAY,CAAiC;IACrD,OAAO,CAAC,SAAS,CAAoC;IACrD,OAAO,CAAC,QAAQ,CAAU;gBAEL,EAAE,EAAE,iBAAiB,EACrB,SAAS,EAAE,iBAAiB,EAC5B,gBAAgB,EAAE,iBAAiB;IAKxD,iFAAiF;IAC3E,eAAe,CAAC,CAAC,EACrB,SAAS,EAAE,CAAC,OAAO,EAAE,IAAI,KAAK,OAAO,CAAC,CAAC,CAAC,GACvC,OAAO,CAAC,CAAC,CAAC;IAwCb,qFAAqF;IACrF,SAAS,CAAC,wBAAwB,CAAC,EAAE,EAAE,iBAAiB,GAAG,IAAI;IAQ/D,gFAAgF;cAChE,iBAAiB,CAC/B,MAAM,EAAE,OAAO,EACf,OAAO,EAAE,iBAAiB,GACzB,OAAO,CAAC,IAAI,CAAC;IAIhB,SAAS,CAAC,MAAM,CAAC,CAAC,EAAE,SAAS,EAAE,CAAC,OAAO,EAAE,IAAI,KAAK,OAAO,CAAC,CAAC,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC;cA4BzD,YAAY,CAC1B,OAAO,EAAE,cAAc,EACvB,MAAM,EAAE,UAAU,CAAC,iBAAiB,CAAC,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,GACjD,OAAO,CAAC,OAAO,CAAC;IAkFb,UAAU,CAAC,OAAO,EAAE,cAAc,GAAG,OAAO,CAAC,WAAW,CAAC;IAazD,gBAAgB,CACpB,OAAO,EAAE,cAAc,GAAG;QAAE,KAAK,EAAE,MAAM,CAAA;KAAE,GAC1C,OAAO,CAAC,cAAc,CAAC;cAkBV,OAAO,CAAC,OAAO,EAAE,cAAc,EAAE,QAAQ,EAAE,MAAM;cAoBjD,IAAI,CAClB,KAAK,EAAE,WAAW,GAAG,aAAa,EAClC,EAAE,EAAE,MAAM,EACV,MAAM,EAAE,MAAM,GACb,OAAO,CAAC,IAAI,CAAC;IAQV,MAAM,CACV,OAAO,EAAE,cAAc,GAAG;QAAE,YAAY,EAAE,MAAM,CAAC;QAAC,QAAQ,EAAE,MAAM,CAAA;KAAE,GACnE,OAAO,CAAC,cAAc,CAAC;cA6CV,iBAAiB,CAC/B,OAAO,EAAE,cAAc,GAAG;QAAE,YAAY,EAAE,MAAM,CAAA;KAAE,EAClD,MAAM,EAAE,UAAU,CAAC,iBAAiB,CAAC,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,GACjD,OAAO,CAAC,UAAU,CAAC;IAwBhB,YAAY,CAChB,OAAO,EAAE,cAAc,GAAG;QAAE,YAAY,EAAE,MAAM,CAAA;KAAE,GACjD,OAAO,CAAC,kBAAkB,EAAE,CAAC;IA0BhC,0FAA0F;IACpF,WAAW,CACf,OAAO,EAAE,cAAc,GAAG;QAAE,YAAY,EAAE,MAAM,CAAC;QAAC,QAAQ,EAAE,MAAM,CAAA;KAAE,GACnE,OAAO,CAAC,kBAAkB,CAAC;CA2C/B"}
@@ -0,0 +1,58 @@
1
+ import { SmrtObject } from '@happyvertical/smrt-core';
2
+ /** A learner is a real user/profile identity with active family membership. */
3
+ export declare class Learner extends SmrtObject {
4
+ tenantId: string;
5
+ userId: string;
6
+ profileId: string;
7
+ displayName: string;
8
+ birthDate: Date | null;
9
+ level: number;
10
+ settings: string;
11
+ constructor(options?: Record<string, unknown>);
12
+ getSettings(): Record<string, unknown>;
13
+ setSettings(value: Record<string, unknown>): void;
14
+ save(): Promise<this>;
15
+ }
16
+ /** A distinct plan retains its own enrollment history. */
17
+ export declare class Curriculum extends SmrtObject {
18
+ tenantId: string;
19
+ learnerId: string;
20
+ title: string;
21
+ startsOn: Date | null;
22
+ endsOn: Date | null;
23
+ status: 'planned' | 'active' | 'completed' | 'archived';
24
+ constructor(options?: Record<string, unknown>);
25
+ save(): Promise<this>;
26
+ }
27
+ export type EnrollmentStatus = 'planned' | 'active' | 'paused' | 'completed' | 'dropped';
28
+ /** One course in one curriculum; a new curriculum means a new enrollment. */
29
+ export declare class Enrollment extends SmrtObject {
30
+ tenantId: string;
31
+ curriculumId: string;
32
+ learnerId: string;
33
+ courseId: string;
34
+ status: EnrollmentStatus;
35
+ startedAt: Date | null;
36
+ completedAt: Date | null;
37
+ targetMinutesPerWeek: number;
38
+ sortOrder: number;
39
+ constructor(options?: Record<string, unknown>);
40
+ save(): Promise<this>;
41
+ }
42
+ export type LessonProgressStatus = 'not_started' | 'in_progress' | 'submitted' | 'needs_review' | 'complete' | 'skipped';
43
+ /** Progress identity is enrollment + lesson, never learner + lesson. */
44
+ export declare class LessonProgress extends SmrtObject {
45
+ tenantId: string;
46
+ enrollmentId: string;
47
+ learnerId: string;
48
+ lessonId: string;
49
+ status: LessonProgressStatus;
50
+ startedAt: Date | null;
51
+ completedAt: Date | null;
52
+ timeSpentSeconds: number;
53
+ attempts: number;
54
+ bestScore: number | null;
55
+ constructor(options?: Record<string, unknown>);
56
+ save(): Promise<this>;
57
+ }
58
+ //# sourceMappingURL=learners.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"learners.d.ts","sourceRoot":"","sources":["../src/learners.ts"],"names":[],"mappings":"AAAA,OAAO,EAIL,UAAU,EAEX,MAAM,0BAA0B,CAAC;AAiClC,+EAA+E;AAC/E,qBAEa,OAAQ,SAAQ,UAAU;IACzB,QAAQ,SAAM;IAE1B,MAAM,SAAM;IAEZ,SAAS,SAAM;IACf,WAAW,SAAM;IACjB,SAAS,EAAE,IAAI,GAAG,IAAI,CAAQ;IAC9B,KAAK,SAAK;IACV,QAAQ,SAAQ;gBAEJ,OAAO,GAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAM;IAKjD,WAAW,IAAI,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC;IAatC,WAAW,CAAC,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI;IAMlC,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC;CA6BrC;AAED,0DAA0D;AAC1D,qBAEa,UAAW,SAAQ,UAAU;IAC5B,QAAQ,SAAM;IACiB,SAAS,SAAM;IAC/B,KAAK,SAAM;IACtC,QAAQ,EAAE,IAAI,GAAG,IAAI,CAAQ;IAC7B,MAAM,EAAE,IAAI,GAAG,IAAI,CAAQ;IAC3B,MAAM,EAAE,SAAS,GAAG,QAAQ,GAAG,WAAW,GAAG,UAAU,CAAa;gBACxD,OAAO,GAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAM;IAIlC,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC;CAYrC;AAED,MAAM,MAAM,gBAAgB,GACxB,SAAS,GACT,QAAQ,GACR,QAAQ,GACR,WAAW,GACX,SAAS,CAAC;AAEd,6EAA6E;AAC7E,qBAKa,UAAW,SAAQ,UAAU;IAC5B,QAAQ,SAAM;IACoB,YAAY,SAAM;IACrB,SAAS,SAAM;IAChB,QAAQ,SAAM;IACxD,MAAM,EAAE,gBAAgB,CAAa;IACrC,SAAS,EAAE,IAAI,GAAG,IAAI,CAAQ;IAC9B,WAAW,EAAE,IAAI,GAAG,IAAI,CAAQ;IAChC,oBAAoB,SAAK;IACzB,SAAS,SAAK;gBACF,OAAO,GAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAM;IAIlC,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC;CA4BrC;AAED,MAAM,MAAM,oBAAoB,GAC5B,aAAa,GACb,aAAa,GACb,WAAW,GACX,cAAc,GACd,UAAU,GACV,SAAS,CAAC;AAEd,wEAAwE;AACxE,qBAMa,cAAe,SAAQ,UAAU;IAChC,QAAQ,SAAM;IACoB,YAAY,SAAM;IACrB,SAAS,SAAM;IAChB,QAAQ,SAAM;IACxD,MAAM,EAAE,oBAAoB,CAAiB;IAC7C,SAAS,EAAE,IAAI,GAAG,IAAI,CAAQ;IAC9B,WAAW,EAAE,IAAI,GAAG,IAAI,CAAQ;IAChC,gBAAgB,SAAK;IACrB,QAAQ,SAAK;IAC+B,SAAS,EAAE,MAAM,GAAG,IAAI,CAAQ;gBAChE,OAAO,GAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAM;IAIlC,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC;CA2CrC"}
@@ -0,0 +1,12 @@
1
+ import { SmrtObject } from '@happyvertical/smrt-core';
2
+ export type LessonAssetRelationship = 'printable' | 'answer-key' | 'video' | 'attachment';
3
+ export declare class LessonAsset extends SmrtObject {
4
+ tenantId: string | null;
5
+ lessonId: string;
6
+ assetId: string;
7
+ relationship: LessonAssetRelationship;
8
+ sortOrder: number;
9
+ constructor(options?: Record<string, unknown>);
10
+ save(): Promise<this>;
11
+ }
12
+ //# sourceMappingURL=lesson-assets.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"lesson-assets.d.ts","sourceRoot":"","sources":["../src/lesson-assets.ts"],"names":[],"mappings":"AACA,OAAO,EAIL,UAAU,EAEX,MAAM,0BAA0B,CAAC;AAGlC,MAAM,MAAM,uBAAuB,GAC/B,WAAW,GACX,YAAY,GACZ,OAAO,GACP,YAAY,CAAC;AAEjB,qBAQa,WAAY,SAAQ,UAAU;IACX,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAQ;IACnB,QAAQ,SAAM;IAExD,OAAO,SAAM;IACc,YAAY,EAAE,uBAAuB,CACjD;IACf,SAAS,SAAK;gBACF,OAAO,GAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAM;IAQlC,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC;CA2CrC"}