@happyvertical/smrt-education 0.57.40 → 0.57.42
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/AGENTS.md +12 -0
- package/README.md +10 -0
- package/agents/enrollment-notes.md +42 -0
- package/agents/group-sharing.md +278 -0
- package/agents/learner-plan.md +66 -0
- package/agents/submission-service.md +16 -1
- package/agents/workbook-service.md +39 -3
- package/dist/chunks/{workbook-photo-service-DCmqeWLd.js → workbook-photo-service-C6mbUUp6.js} +721 -280
- package/dist/chunks/workbook-photo-service-C6mbUUp6.js.map +1 -0
- package/dist/enrollment-note-service.d.ts +24 -0
- package/dist/enrollment-note-service.d.ts.map +1 -0
- package/dist/enrollment-notes.d.ts +22 -0
- package/dist/enrollment-notes.d.ts.map +1 -0
- package/dist/group-sharing-authorization.d.ts +67 -0
- package/dist/group-sharing-authorization.d.ts.map +1 -0
- package/dist/group-sharing-comments.d.ts +30 -0
- package/dist/group-sharing-comments.d.ts.map +1 -0
- package/dist/group-sharing-contracts.d.ts +201 -0
- package/dist/group-sharing-contracts.d.ts.map +1 -0
- package/dist/group-sharing-hash.d.ts +3 -0
- package/dist/group-sharing-hash.d.ts.map +1 -0
- package/dist/group-sharing-models.d.ts +106 -0
- package/dist/group-sharing-models.d.ts.map +1 -0
- package/dist/group-sharing-policy.d.ts +19 -0
- package/dist/group-sharing-policy.d.ts.map +1 -0
- package/dist/group-sharing-reader.d.ts +45 -0
- package/dist/group-sharing-reader.d.ts.map +1 -0
- package/dist/group-sharing-service.d.ts +108 -0
- package/dist/group-sharing-service.d.ts.map +1 -0
- package/dist/group-sharing-workspace.d.ts +10 -0
- package/dist/group-sharing-workspace.d.ts.map +1 -0
- package/dist/index.d.ts +13 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2266 -56
- package/dist/index.js.map +1 -1
- package/dist/ingestion.js +1 -1
- package/dist/learner-plan-service.d.ts +46 -0
- package/dist/learner-plan-service.d.ts.map +1 -0
- package/dist/learner-service.d.ts +1 -1
- package/dist/learner-service.d.ts.map +1 -1
- package/dist/manifest.json +5610 -1922
- package/dist/recipes.d.ts +24 -0
- package/dist/recipes.d.ts.map +1 -1
- package/dist/smrt-knowledge.json +1455 -48
- package/dist/submission-service.d.ts +3 -0
- package/dist/submission-service.d.ts.map +1 -1
- package/dist/workbook-completion.d.ts +38 -0
- package/dist/workbook-completion.d.ts.map +1 -0
- package/dist/workbook-contracts.d.ts +33 -0
- package/dist/workbook-contracts.d.ts.map +1 -1
- package/dist/workbook-service.d.ts +6 -1
- package/dist/workbook-service.d.ts.map +1 -1
- package/package.json +9 -9
- package/dist/chunks/workbook-photo-service-DCmqeWLd.js.map +0 -1
package/dist/chunks/{workbook-photo-service-DCmqeWLd.js → workbook-photo-service-C6mbUUp6.js}
RENAMED
|
@@ -4,8 +4,8 @@ import { AssetCollection, createAssetRuntime, withPrivateAssetAccess } from "@ha
|
|
|
4
4
|
import { TenantCollection } from "@happyvertical/smrt-users";
|
|
5
5
|
//#region \0rolldown/runtime.js
|
|
6
6
|
var __create = Object.create;
|
|
7
|
-
var __defProp$
|
|
8
|
-
var __getOwnPropDesc$
|
|
7
|
+
var __defProp$8 = Object.defineProperty;
|
|
8
|
+
var __getOwnPropDesc$8 = Object.getOwnPropertyDescriptor;
|
|
9
9
|
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
10
10
|
var __getProtoOf = Object.getPrototypeOf;
|
|
11
11
|
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
@@ -13,34 +13,34 @@ var __commonJSMin = (cb, mod) => () => (mod || (cb((mod = { exports: {} }).expor
|
|
|
13
13
|
var __copyProps = (to, from, except, desc) => {
|
|
14
14
|
if (from && typeof from === "object" || typeof from === "function") for (var keys = __getOwnPropNames(from), i = 0, n = keys.length, key; i < n; i++) {
|
|
15
15
|
key = keys[i];
|
|
16
|
-
if (!__hasOwnProp.call(to, key) && key !== except) __defProp$
|
|
16
|
+
if (!__hasOwnProp.call(to, key) && key !== except) __defProp$8(to, key, {
|
|
17
17
|
get: ((k) => from[k]).bind(null, key),
|
|
18
|
-
enumerable: !(desc = __getOwnPropDesc$
|
|
18
|
+
enumerable: !(desc = __getOwnPropDesc$8(from, key)) || desc.enumerable
|
|
19
19
|
});
|
|
20
20
|
}
|
|
21
21
|
return to;
|
|
22
22
|
};
|
|
23
|
-
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(isNodeMode || !mod || !mod.__esModule ? __defProp$
|
|
23
|
+
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(isNodeMode || !mod || !mod.__esModule ? __defProp$8(target, "default", {
|
|
24
24
|
value: mod,
|
|
25
25
|
enumerable: true
|
|
26
26
|
}) : target, mod));
|
|
27
27
|
//#endregion
|
|
28
28
|
//#region src/catalog.ts
|
|
29
|
-
var __defProp$
|
|
30
|
-
var __getOwnPropDesc$
|
|
31
|
-
var __defNormalProp$
|
|
29
|
+
var __defProp$7 = Object.defineProperty;
|
|
30
|
+
var __getOwnPropDesc$7 = Object.getOwnPropertyDescriptor;
|
|
31
|
+
var __defNormalProp$7 = (obj, key, value) => key in obj ? __defProp$7(obj, key, {
|
|
32
32
|
enumerable: true,
|
|
33
33
|
configurable: true,
|
|
34
34
|
writable: true,
|
|
35
35
|
value
|
|
36
36
|
}) : obj[key] = value;
|
|
37
|
-
var __decorateClass$
|
|
38
|
-
var result = kind > 1 ? void 0 : kind ? __getOwnPropDesc$
|
|
37
|
+
var __decorateClass$7 = (decorators, target, key, kind) => {
|
|
38
|
+
var result = kind > 1 ? void 0 : kind ? __getOwnPropDesc$7(target, key) : target;
|
|
39
39
|
for (var i = decorators.length - 1, decorator; i >= 0; i--) if (decorator = decorators[i]) result = (kind ? decorator(target, key, result) : decorator(result)) || result;
|
|
40
|
-
if (kind && result) __defProp$
|
|
40
|
+
if (kind && result) __defProp$7(target, key, result);
|
|
41
41
|
return result;
|
|
42
42
|
};
|
|
43
|
-
var __publicField$
|
|
43
|
+
var __publicField$7 = (obj, key, value) => __defNormalProp$7(obj, typeof key !== "symbol" ? key + "" : key, value);
|
|
44
44
|
var closed$5 = {
|
|
45
45
|
api: false,
|
|
46
46
|
mcp: false,
|
|
@@ -100,22 +100,22 @@ var Course = class extends SmrtObject {
|
|
|
100
100
|
return await super.save(options);
|
|
101
101
|
}
|
|
102
102
|
};
|
|
103
|
-
__publicField$
|
|
104
|
-
__decorateClass$
|
|
105
|
-
__decorateClass$
|
|
106
|
-
Course = __decorateClass$
|
|
103
|
+
__publicField$7(Course, "__smrtPackage__", "@happyvertical/smrt-education");
|
|
104
|
+
__decorateClass$7([tenantId({ nullable: true })], Course.prototype, "tenantId", 2);
|
|
105
|
+
__decorateClass$7([field({ required: true })], Course.prototype, "title", 2);
|
|
106
|
+
Course = __decorateClass$7([TenantScoped({ mode: "optional" }), smrt({
|
|
107
107
|
tableStrategy: "sti",
|
|
108
108
|
...closed$5
|
|
109
109
|
})], Course);
|
|
110
110
|
var ExternalCourse = class extends Course {};
|
|
111
|
-
__publicField$
|
|
112
|
-
ExternalCourse = __decorateClass$
|
|
111
|
+
__publicField$7(ExternalCourse, "__smrtPackage__", "@happyvertical/smrt-education");
|
|
112
|
+
ExternalCourse = __decorateClass$7([smrt({
|
|
113
113
|
tableName: "courses",
|
|
114
114
|
...closed$5
|
|
115
115
|
})], ExternalCourse);
|
|
116
116
|
var AuthoredCourse = class extends Course {};
|
|
117
|
-
__publicField$
|
|
118
|
-
AuthoredCourse = __decorateClass$
|
|
117
|
+
__publicField$7(AuthoredCourse, "__smrtPackage__", "@happyvertical/smrt-education");
|
|
118
|
+
AuthoredCourse = __decorateClass$7([smrt({
|
|
119
119
|
tableName: "courses",
|
|
120
120
|
...closed$5
|
|
121
121
|
})], AuthoredCourse);
|
|
@@ -138,11 +138,11 @@ var CourseSection = class extends SmrtObject {
|
|
|
138
138
|
return await super.save(options);
|
|
139
139
|
}
|
|
140
140
|
};
|
|
141
|
-
__publicField$
|
|
142
|
-
__decorateClass$
|
|
143
|
-
__decorateClass$
|
|
144
|
-
__decorateClass$
|
|
145
|
-
CourseSection = __decorateClass$
|
|
141
|
+
__publicField$7(CourseSection, "__smrtPackage__", "@happyvertical/smrt-education");
|
|
142
|
+
__decorateClass$7([tenantId({ nullable: true })], CourseSection.prototype, "tenantId", 2);
|
|
143
|
+
__decorateClass$7([foreignKey("Course", { required: true })], CourseSection.prototype, "courseId", 2);
|
|
144
|
+
__decorateClass$7([field({ required: true })], CourseSection.prototype, "title", 2);
|
|
145
|
+
CourseSection = __decorateClass$7([TenantScoped({ mode: "optional" }), smrt({ ...closed$5 })], CourseSection);
|
|
146
146
|
var Lesson = class extends SmrtObject {
|
|
147
147
|
tenantId = null;
|
|
148
148
|
sectionId = "";
|
|
@@ -169,17 +169,17 @@ var Lesson = class extends SmrtObject {
|
|
|
169
169
|
return await super.save(options);
|
|
170
170
|
}
|
|
171
171
|
};
|
|
172
|
-
__publicField$
|
|
173
|
-
__decorateClass$
|
|
174
|
-
__decorateClass$
|
|
175
|
-
__decorateClass$
|
|
176
|
-
Lesson = __decorateClass$
|
|
172
|
+
__publicField$7(Lesson, "__smrtPackage__", "@happyvertical/smrt-education");
|
|
173
|
+
__decorateClass$7([tenantId({ nullable: true })], Lesson.prototype, "tenantId", 2);
|
|
174
|
+
__decorateClass$7([foreignKey("CourseSection", { required: true })], Lesson.prototype, "sectionId", 2);
|
|
175
|
+
__decorateClass$7([field({ required: true })], Lesson.prototype, "title", 2);
|
|
176
|
+
Lesson = __decorateClass$7([TenantScoped({ mode: "optional" }), smrt({
|
|
177
177
|
tableStrategy: "sti",
|
|
178
178
|
...closed$5
|
|
179
179
|
})], Lesson);
|
|
180
180
|
var Reading = class extends Lesson {};
|
|
181
|
-
__publicField$
|
|
182
|
-
Reading = __decorateClass$
|
|
181
|
+
__publicField$7(Reading, "__smrtPackage__", "@happyvertical/smrt-education");
|
|
182
|
+
Reading = __decorateClass$7([smrt({
|
|
183
183
|
tableName: "lessons",
|
|
184
184
|
...closed$5
|
|
185
185
|
})], Reading);
|
|
@@ -190,8 +190,8 @@ var Video = class extends Lesson {
|
|
|
190
190
|
applyModelOptions(this, options);
|
|
191
191
|
}
|
|
192
192
|
};
|
|
193
|
-
__publicField$
|
|
194
|
-
Video = __decorateClass$
|
|
193
|
+
__publicField$7(Video, "__smrtPackage__", "@happyvertical/smrt-education");
|
|
194
|
+
Video = __decorateClass$7([smrt({
|
|
195
195
|
tableName: "lessons",
|
|
196
196
|
...closed$5
|
|
197
197
|
})], Video);
|
|
@@ -205,14 +205,14 @@ var Worksheet = class extends Lesson {
|
|
|
205
205
|
applyModelOptions(this, options);
|
|
206
206
|
}
|
|
207
207
|
};
|
|
208
|
-
__publicField$
|
|
209
|
-
Worksheet = __decorateClass$
|
|
208
|
+
__publicField$7(Worksheet, "__smrtPackage__", "@happyvertical/smrt-education");
|
|
209
|
+
Worksheet = __decorateClass$7([smrt({
|
|
210
210
|
tableName: "lessons",
|
|
211
211
|
...closed$5
|
|
212
212
|
})], Worksheet);
|
|
213
213
|
var Exercise = class extends Lesson {};
|
|
214
|
-
__publicField$
|
|
215
|
-
Exercise = __decorateClass$
|
|
214
|
+
__publicField$7(Exercise, "__smrtPackage__", "@happyvertical/smrt-education");
|
|
215
|
+
Exercise = __decorateClass$7([smrt({
|
|
216
216
|
tableName: "lessons",
|
|
217
217
|
...closed$5
|
|
218
218
|
})], Exercise);
|
|
@@ -246,21 +246,21 @@ GlobalInterceptors.register({
|
|
|
246
246
|
});
|
|
247
247
|
//#endregion
|
|
248
248
|
//#region src/learners.ts
|
|
249
|
-
var __defProp$
|
|
250
|
-
var __getOwnPropDesc$
|
|
251
|
-
var __defNormalProp$
|
|
249
|
+
var __defProp$6 = Object.defineProperty;
|
|
250
|
+
var __getOwnPropDesc$6 = Object.getOwnPropertyDescriptor;
|
|
251
|
+
var __defNormalProp$6 = (obj, key, value) => key in obj ? __defProp$6(obj, key, {
|
|
252
252
|
enumerable: true,
|
|
253
253
|
configurable: true,
|
|
254
254
|
writable: true,
|
|
255
255
|
value
|
|
256
256
|
}) : obj[key] = value;
|
|
257
|
-
var __decorateClass$
|
|
258
|
-
var result = kind > 1 ? void 0 : kind ? __getOwnPropDesc$
|
|
257
|
+
var __decorateClass$6 = (decorators, target, key, kind) => {
|
|
258
|
+
var result = kind > 1 ? void 0 : kind ? __getOwnPropDesc$6(target, key) : target;
|
|
259
259
|
for (var i = decorators.length - 1, decorator; i >= 0; i--) if (decorator = decorators[i]) result = (kind ? decorator(target, key, result) : decorator(result)) || result;
|
|
260
|
-
if (kind && result) __defProp$
|
|
260
|
+
if (kind && result) __defProp$6(target, key, result);
|
|
261
261
|
return result;
|
|
262
262
|
};
|
|
263
|
-
var __publicField$
|
|
263
|
+
var __publicField$6 = (obj, key, value) => __defNormalProp$6(obj, typeof key !== "symbol" ? key + "" : key, value);
|
|
264
264
|
var closed$4 = {
|
|
265
265
|
api: false,
|
|
266
266
|
mcp: false,
|
|
@@ -326,11 +326,11 @@ var Learner = class extends SmrtObject {
|
|
|
326
326
|
return super.save(options);
|
|
327
327
|
}
|
|
328
328
|
};
|
|
329
|
-
__publicField$
|
|
330
|
-
__decorateClass$
|
|
331
|
-
__decorateClass$
|
|
332
|
-
__decorateClass$
|
|
333
|
-
Learner = __decorateClass$
|
|
329
|
+
__publicField$6(Learner, "__smrtPackage__", "@happyvertical/smrt-education");
|
|
330
|
+
__decorateClass$6([tenantId()], Learner.prototype, "tenantId", 2);
|
|
331
|
+
__decorateClass$6([crossPackageRef("@happyvertical/smrt-users:User", { required: true })], Learner.prototype, "userId", 2);
|
|
332
|
+
__decorateClass$6([crossPackageRef("@happyvertical/smrt-profiles:Profile", { required: true })], Learner.prototype, "profileId", 2);
|
|
333
|
+
Learner = __decorateClass$6([TenantScoped({ mode: "required" }), smrt({ ...closed$4 })], Learner);
|
|
334
334
|
var Curriculum = class extends SmrtObject {
|
|
335
335
|
tenantId = "";
|
|
336
336
|
learnerId = "";
|
|
@@ -357,11 +357,11 @@ var Curriculum = class extends SmrtObject {
|
|
|
357
357
|
return super.save(options);
|
|
358
358
|
}
|
|
359
359
|
};
|
|
360
|
-
__publicField$
|
|
361
|
-
__decorateClass$
|
|
362
|
-
__decorateClass$
|
|
363
|
-
__decorateClass$
|
|
364
|
-
Curriculum = __decorateClass$
|
|
360
|
+
__publicField$6(Curriculum, "__smrtPackage__", "@happyvertical/smrt-education");
|
|
361
|
+
__decorateClass$6([tenantId()], Curriculum.prototype, "tenantId", 2);
|
|
362
|
+
__decorateClass$6([foreignKey("Learner", { required: true })], Curriculum.prototype, "learnerId", 2);
|
|
363
|
+
__decorateClass$6([field({ required: true })], Curriculum.prototype, "title", 2);
|
|
364
|
+
Curriculum = __decorateClass$6([TenantScoped({ mode: "required" }), smrt({
|
|
365
365
|
...closed$4,
|
|
366
366
|
tableName: "curricula"
|
|
367
367
|
})], Curriculum);
|
|
@@ -401,12 +401,12 @@ var Enrollment = class extends SmrtObject {
|
|
|
401
401
|
return super.save(options);
|
|
402
402
|
}
|
|
403
403
|
};
|
|
404
|
-
__publicField$
|
|
405
|
-
__decorateClass$
|
|
406
|
-
__decorateClass$
|
|
407
|
-
__decorateClass$
|
|
408
|
-
__decorateClass$
|
|
409
|
-
Enrollment = __decorateClass$
|
|
404
|
+
__publicField$6(Enrollment, "__smrtPackage__", "@happyvertical/smrt-education");
|
|
405
|
+
__decorateClass$6([tenantId()], Enrollment.prototype, "tenantId", 2);
|
|
406
|
+
__decorateClass$6([foreignKey("Curriculum", { required: true })], Enrollment.prototype, "curriculumId", 2);
|
|
407
|
+
__decorateClass$6([foreignKey("Learner", { required: true })], Enrollment.prototype, "learnerId", 2);
|
|
408
|
+
__decorateClass$6([foreignKey("Course", { required: true })], Enrollment.prototype, "courseId", 2);
|
|
409
|
+
Enrollment = __decorateClass$6([TenantScoped({ mode: "required" }), smrt({
|
|
410
410
|
...closed$4,
|
|
411
411
|
conflictColumns: [
|
|
412
412
|
"tenant_id",
|
|
@@ -458,16 +458,16 @@ var LessonProgress = class extends SmrtObject {
|
|
|
458
458
|
return super.save(options);
|
|
459
459
|
}
|
|
460
460
|
};
|
|
461
|
-
__publicField$
|
|
462
|
-
__decorateClass$
|
|
463
|
-
__decorateClass$
|
|
464
|
-
__decorateClass$
|
|
465
|
-
__decorateClass$
|
|
466
|
-
__decorateClass$
|
|
461
|
+
__publicField$6(LessonProgress, "__smrtPackage__", "@happyvertical/smrt-education");
|
|
462
|
+
__decorateClass$6([tenantId()], LessonProgress.prototype, "tenantId", 2);
|
|
463
|
+
__decorateClass$6([foreignKey("Enrollment", { required: true })], LessonProgress.prototype, "enrollmentId", 2);
|
|
464
|
+
__decorateClass$6([foreignKey("Learner", { required: true })], LessonProgress.prototype, "learnerId", 2);
|
|
465
|
+
__decorateClass$6([foreignKey("Lesson", { required: true })], LessonProgress.prototype, "lessonId", 2);
|
|
466
|
+
__decorateClass$6([field({
|
|
467
467
|
type: "decimal",
|
|
468
468
|
nullable: true
|
|
469
469
|
})], LessonProgress.prototype, "bestScore", 2);
|
|
470
|
-
LessonProgress = __decorateClass$
|
|
470
|
+
LessonProgress = __decorateClass$6([TenantScoped({ mode: "required" }), smrt({
|
|
471
471
|
...closed$4,
|
|
472
472
|
tableName: "lesson_progress",
|
|
473
473
|
conflictColumns: [
|
|
@@ -478,21 +478,21 @@ LessonProgress = __decorateClass$5([TenantScoped({ mode: "required" }), smrt({
|
|
|
478
478
|
})], LessonProgress);
|
|
479
479
|
//#endregion
|
|
480
480
|
//#region src/lesson-assets.ts
|
|
481
|
-
var __defProp$
|
|
482
|
-
var __getOwnPropDesc$
|
|
483
|
-
var __defNormalProp$
|
|
481
|
+
var __defProp$5 = Object.defineProperty;
|
|
482
|
+
var __getOwnPropDesc$5 = Object.getOwnPropertyDescriptor;
|
|
483
|
+
var __defNormalProp$5 = (obj, key, value) => key in obj ? __defProp$5(obj, key, {
|
|
484
484
|
enumerable: true,
|
|
485
485
|
configurable: true,
|
|
486
486
|
writable: true,
|
|
487
487
|
value
|
|
488
488
|
}) : obj[key] = value;
|
|
489
|
-
var __decorateClass$
|
|
490
|
-
var result = kind > 1 ? void 0 : kind ? __getOwnPropDesc$
|
|
489
|
+
var __decorateClass$5 = (decorators, target, key, kind) => {
|
|
490
|
+
var result = kind > 1 ? void 0 : kind ? __getOwnPropDesc$5(target, key) : target;
|
|
491
491
|
for (var i = decorators.length - 1, decorator; i >= 0; i--) if (decorator = decorators[i]) result = (kind ? decorator(target, key, result) : decorator(result)) || result;
|
|
492
|
-
if (kind && result) __defProp$
|
|
492
|
+
if (kind && result) __defProp$5(target, key, result);
|
|
493
493
|
return result;
|
|
494
494
|
};
|
|
495
|
-
var __publicField$
|
|
495
|
+
var __publicField$5 = (obj, key, value) => __defNormalProp$5(obj, typeof key !== "symbol" ? key + "" : key, value);
|
|
496
496
|
var LessonAsset = class extends SmrtObject {
|
|
497
497
|
tenantId = null;
|
|
498
498
|
lessonId = "";
|
|
@@ -526,12 +526,12 @@ var LessonAsset = class extends SmrtObject {
|
|
|
526
526
|
return await super.save(options);
|
|
527
527
|
}
|
|
528
528
|
};
|
|
529
|
-
__publicField$
|
|
530
|
-
__decorateClass$
|
|
531
|
-
__decorateClass$
|
|
532
|
-
__decorateClass$
|
|
533
|
-
__decorateClass$
|
|
534
|
-
LessonAsset = __decorateClass$
|
|
529
|
+
__publicField$5(LessonAsset, "__smrtPackage__", "@happyvertical/smrt-education");
|
|
530
|
+
__decorateClass$5([tenantId({ nullable: true })], LessonAsset.prototype, "tenantId", 2);
|
|
531
|
+
__decorateClass$5([foreignKey("Lesson", { required: true })], LessonAsset.prototype, "lessonId", 2);
|
|
532
|
+
__decorateClass$5([crossPackageRef("@happyvertical/smrt-assets:Asset", { required: true })], LessonAsset.prototype, "assetId", 2);
|
|
533
|
+
__decorateClass$5([field({ required: true })], LessonAsset.prototype, "relationship", 2);
|
|
534
|
+
LessonAsset = __decorateClass$5([TenantScoped({ mode: "optional" }), smrt({
|
|
535
535
|
tableName: "lesson_assets",
|
|
536
536
|
conflictColumns: [
|
|
537
537
|
"tenant_id",
|
|
@@ -545,21 +545,21 @@ LessonAsset = __decorateClass$4([TenantScoped({ mode: "optional" }), smrt({
|
|
|
545
545
|
})], LessonAsset);
|
|
546
546
|
//#endregion
|
|
547
547
|
//#region src/submissions.ts
|
|
548
|
-
var __defProp$
|
|
549
|
-
var __getOwnPropDesc$
|
|
550
|
-
var __defNormalProp$
|
|
548
|
+
var __defProp$4 = Object.defineProperty;
|
|
549
|
+
var __getOwnPropDesc$4 = Object.getOwnPropertyDescriptor;
|
|
550
|
+
var __defNormalProp$4 = (obj, key, value) => key in obj ? __defProp$4(obj, key, {
|
|
551
551
|
enumerable: true,
|
|
552
552
|
configurable: true,
|
|
553
553
|
writable: true,
|
|
554
554
|
value
|
|
555
555
|
}) : obj[key] = value;
|
|
556
|
-
var __decorateClass$
|
|
557
|
-
var result = kind > 1 ? void 0 : kind ? __getOwnPropDesc$
|
|
556
|
+
var __decorateClass$4 = (decorators, target, key, kind) => {
|
|
557
|
+
var result = kind > 1 ? void 0 : kind ? __getOwnPropDesc$4(target, key) : target;
|
|
558
558
|
for (var i = decorators.length - 1, decorator; i >= 0; i--) if (decorator = decorators[i]) result = (kind ? decorator(target, key, result) : decorator(result)) || result;
|
|
559
|
-
if (kind && result) __defProp$
|
|
559
|
+
if (kind && result) __defProp$4(target, key, result);
|
|
560
560
|
return result;
|
|
561
561
|
};
|
|
562
|
-
var __publicField$
|
|
562
|
+
var __publicField$4 = (obj, key, value) => __defNormalProp$4(obj, typeof key !== "symbol" ? key + "" : key, value);
|
|
563
563
|
var closed$3 = {
|
|
564
564
|
api: false,
|
|
565
565
|
mcp: false,
|
|
@@ -650,18 +650,18 @@ var Submission = class extends SmrtObject {
|
|
|
650
650
|
return super.save(options);
|
|
651
651
|
}
|
|
652
652
|
};
|
|
653
|
-
__publicField$
|
|
654
|
-
__decorateClass$
|
|
655
|
-
__decorateClass$
|
|
656
|
-
__decorateClass$
|
|
657
|
-
__decorateClass$
|
|
658
|
-
__decorateClass$
|
|
659
|
-
__decorateClass$
|
|
660
|
-
__decorateClass$
|
|
653
|
+
__publicField$4(Submission, "__smrtPackage__", "@happyvertical/smrt-education");
|
|
654
|
+
__decorateClass$4([tenantId()], Submission.prototype, "tenantId", 2);
|
|
655
|
+
__decorateClass$4([foreignKey("Learner", { required: true })], Submission.prototype, "learnerId", 2);
|
|
656
|
+
__decorateClass$4([foreignKey("Lesson", { required: true })], Submission.prototype, "lessonId", 2);
|
|
657
|
+
__decorateClass$4([foreignKey("LessonProgress", { required: true })], Submission.prototype, "progressId", 2);
|
|
658
|
+
__decorateClass$4([field({ required: true })], Submission.prototype, "kind", 2);
|
|
659
|
+
__decorateClass$4([foreignKey("Submission", { nullable: true })], Submission.prototype, "previousSubmissionId", 2);
|
|
660
|
+
__decorateClass$4([field({
|
|
661
661
|
type: "text",
|
|
662
662
|
nullable: true
|
|
663
663
|
})], Submission.prototype, "intakeItemId", 2);
|
|
664
|
-
Submission = __decorateClass$
|
|
664
|
+
Submission = __decorateClass$4([TenantScoped({ mode: "required" }), smrt({
|
|
665
665
|
tableStrategy: "sti",
|
|
666
666
|
...closed$3
|
|
667
667
|
})], Submission);
|
|
@@ -684,14 +684,14 @@ var SubmissionIntakeBinding = class extends SmrtObject {
|
|
|
684
684
|
return super.save(options);
|
|
685
685
|
}
|
|
686
686
|
};
|
|
687
|
-
__publicField$
|
|
688
|
-
__decorateClass$
|
|
689
|
-
__decorateClass$
|
|
687
|
+
__publicField$4(SubmissionIntakeBinding, "__smrtPackage__", "@happyvertical/smrt-education");
|
|
688
|
+
__decorateClass$4([tenantId()], SubmissionIntakeBinding.prototype, "tenantId", 2);
|
|
689
|
+
__decorateClass$4([field({
|
|
690
690
|
required: true,
|
|
691
691
|
type: "text"
|
|
692
692
|
})], SubmissionIntakeBinding.prototype, "intakeItemId", 2);
|
|
693
|
-
__decorateClass$
|
|
694
|
-
SubmissionIntakeBinding = __decorateClass$
|
|
693
|
+
__decorateClass$4([foreignKey("Submission", { required: true })], SubmissionIntakeBinding.prototype, "submissionId", 2);
|
|
694
|
+
SubmissionIntakeBinding = __decorateClass$4([TenantScoped({ mode: "required" }), smrt({
|
|
695
695
|
tableName: "submission_intake_bindings",
|
|
696
696
|
...closed$3,
|
|
697
697
|
conflictColumns: ["tenant_id", "intake_item_id"]
|
|
@@ -715,8 +715,8 @@ var ScannedSubmission = class extends Submission {
|
|
|
715
715
|
return super.save(options);
|
|
716
716
|
}
|
|
717
717
|
};
|
|
718
|
-
__publicField$
|
|
719
|
-
ScannedSubmission = __decorateClass$
|
|
718
|
+
__publicField$4(ScannedSubmission, "__smrtPackage__", "@happyvertical/smrt-education");
|
|
719
|
+
ScannedSubmission = __decorateClass$4([smrt({
|
|
720
720
|
tableName: "submissions",
|
|
721
721
|
...closed$3
|
|
722
722
|
})], ScannedSubmission);
|
|
@@ -738,15 +738,15 @@ var ExternalCompletion = class extends Submission {
|
|
|
738
738
|
return super.save(options);
|
|
739
739
|
}
|
|
740
740
|
};
|
|
741
|
-
__publicField$
|
|
742
|
-
__decorateClass$
|
|
743
|
-
ExternalCompletion = __decorateClass$
|
|
741
|
+
__publicField$4(ExternalCompletion, "__smrtPackage__", "@happyvertical/smrt-education");
|
|
742
|
+
__decorateClass$4([field({ type: "decimal" })], ExternalCompletion.prototype, "reportedScore", 2);
|
|
743
|
+
ExternalCompletion = __decorateClass$4([smrt({
|
|
744
744
|
tableName: "submissions",
|
|
745
745
|
...closed$3
|
|
746
746
|
})], ExternalCompletion);
|
|
747
747
|
var Attestation = class extends Submission {};
|
|
748
|
-
__publicField$
|
|
749
|
-
Attestation = __decorateClass$
|
|
748
|
+
__publicField$4(Attestation, "__smrtPackage__", "@happyvertical/smrt-education");
|
|
749
|
+
Attestation = __decorateClass$4([smrt({
|
|
750
750
|
tableName: "submissions",
|
|
751
751
|
...closed$3
|
|
752
752
|
})], Attestation);
|
|
@@ -785,12 +785,12 @@ var SubmissionAsset = class extends SmrtObject {
|
|
|
785
785
|
return super.save(options);
|
|
786
786
|
}
|
|
787
787
|
};
|
|
788
|
-
__publicField$
|
|
789
|
-
__decorateClass$
|
|
790
|
-
__decorateClass$
|
|
791
|
-
__decorateClass$
|
|
792
|
-
__decorateClass$
|
|
793
|
-
SubmissionAsset = __decorateClass$
|
|
788
|
+
__publicField$4(SubmissionAsset, "__smrtPackage__", "@happyvertical/smrt-education");
|
|
789
|
+
__decorateClass$4([tenantId()], SubmissionAsset.prototype, "tenantId", 2);
|
|
790
|
+
__decorateClass$4([foreignKey("Submission", { required: true })], SubmissionAsset.prototype, "submissionId", 2);
|
|
791
|
+
__decorateClass$4([crossPackageRef("@happyvertical/smrt-assets:Asset", { required: true })], SubmissionAsset.prototype, "assetId", 2);
|
|
792
|
+
__decorateClass$4([field({ required: true })], SubmissionAsset.prototype, "relationship", 2);
|
|
793
|
+
SubmissionAsset = __decorateClass$4([TenantScoped({ mode: "required" }), smrt({
|
|
794
794
|
tableName: "submission_assets",
|
|
795
795
|
conflictColumns: [
|
|
796
796
|
"tenant_id",
|
|
@@ -839,24 +839,24 @@ var Grade = class extends SmrtObject {
|
|
|
839
839
|
return super.save(options);
|
|
840
840
|
}
|
|
841
841
|
};
|
|
842
|
-
__publicField$
|
|
843
|
-
__decorateClass$
|
|
844
|
-
__decorateClass$
|
|
845
|
-
__decorateClass$
|
|
846
|
-
__decorateClass$
|
|
847
|
-
__decorateClass$
|
|
842
|
+
__publicField$4(Grade, "__smrtPackage__", "@happyvertical/smrt-education");
|
|
843
|
+
__decorateClass$4([tenantId()], Grade.prototype, "tenantId", 2);
|
|
844
|
+
__decorateClass$4([foreignKey("Submission", { required: true })], Grade.prototype, "submissionId", 2);
|
|
845
|
+
__decorateClass$4([field({ required: true })], Grade.prototype, "graderKind", 2);
|
|
846
|
+
__decorateClass$4([crossPackageRef("@happyvertical/smrt-profiles:Profile", { nullable: true })], Grade.prototype, "graderProfileId", 2);
|
|
847
|
+
__decorateClass$4([field({
|
|
848
848
|
type: "decimal",
|
|
849
849
|
nullable: true
|
|
850
850
|
})], Grade.prototype, "score", 2);
|
|
851
|
-
__decorateClass$
|
|
851
|
+
__decorateClass$4([field({
|
|
852
852
|
type: "integer",
|
|
853
853
|
nullable: true
|
|
854
854
|
})], Grade.prototype, "pointsEarned", 2);
|
|
855
|
-
__decorateClass$
|
|
855
|
+
__decorateClass$4([field({
|
|
856
856
|
type: "integer",
|
|
857
857
|
nullable: true
|
|
858
858
|
})], Grade.prototype, "pointsPossible", 2);
|
|
859
|
-
Grade = __decorateClass$
|
|
859
|
+
Grade = __decorateClass$4([TenantScoped({ mode: "required" }), smrt({ ...closed$3 })], Grade);
|
|
860
860
|
//#endregion
|
|
861
861
|
//#region src/collections.ts
|
|
862
862
|
var CourseCollection = class extends SmrtCollection {
|
|
@@ -1059,21 +1059,21 @@ function familyIntakeScopeId(tenantId) {
|
|
|
1059
1059
|
}
|
|
1060
1060
|
//#endregion
|
|
1061
1061
|
//#region src/family-intake-models.ts
|
|
1062
|
-
var __defProp$
|
|
1063
|
-
var __getOwnPropDesc$
|
|
1064
|
-
var __defNormalProp$
|
|
1062
|
+
var __defProp$3 = Object.defineProperty;
|
|
1063
|
+
var __getOwnPropDesc$3 = Object.getOwnPropertyDescriptor;
|
|
1064
|
+
var __defNormalProp$3 = (obj, key, value) => key in obj ? __defProp$3(obj, key, {
|
|
1065
1065
|
enumerable: true,
|
|
1066
1066
|
configurable: true,
|
|
1067
1067
|
writable: true,
|
|
1068
1068
|
value
|
|
1069
1069
|
}) : obj[key] = value;
|
|
1070
|
-
var __decorateClass$
|
|
1071
|
-
var result = kind > 1 ? void 0 : kind ? __getOwnPropDesc$
|
|
1070
|
+
var __decorateClass$3 = (decorators, target, key, kind) => {
|
|
1071
|
+
var result = kind > 1 ? void 0 : kind ? __getOwnPropDesc$3(target, key) : target;
|
|
1072
1072
|
for (var i = decorators.length - 1, decorator; i >= 0; i--) if (decorator = decorators[i]) result = (kind ? decorator(target, key, result) : decorator(result)) || result;
|
|
1073
|
-
if (kind && result) __defProp$
|
|
1073
|
+
if (kind && result) __defProp$3(target, key, result);
|
|
1074
1074
|
return result;
|
|
1075
1075
|
};
|
|
1076
|
-
var __publicField$
|
|
1076
|
+
var __publicField$3 = (obj, key, value) => __defNormalProp$3(obj, typeof key !== "symbol" ? key + "" : key, value);
|
|
1077
1077
|
var closed$2 = {
|
|
1078
1078
|
api: false,
|
|
1079
1079
|
mcp: false,
|
|
@@ -1104,11 +1104,11 @@ var FamilyIntake = class extends SmrtObject {
|
|
|
1104
1104
|
noDelete();
|
|
1105
1105
|
}
|
|
1106
1106
|
};
|
|
1107
|
-
__publicField$
|
|
1108
|
-
__decorateClass$
|
|
1109
|
-
__decorateClass$
|
|
1110
|
-
__decorateClass$
|
|
1111
|
-
FamilyIntake = __decorateClass$
|
|
1107
|
+
__publicField$3(FamilyIntake, "__smrtPackage__", "@happyvertical/smrt-education");
|
|
1108
|
+
__decorateClass$3([tenantId()], FamilyIntake.prototype, "tenantId", 2);
|
|
1109
|
+
__decorateClass$3([crossPackageRef("@happyvertical/smrt-profiles:Profile")], FamilyIntake.prototype, "ownerProfileId", 2);
|
|
1110
|
+
__decorateClass$3([field({ type: "text" })], FamilyIntake.prototype, "sourceJson", 2);
|
|
1111
|
+
FamilyIntake = __decorateClass$3([TenantScoped({ mode: "required" }), smrt({
|
|
1112
1112
|
tableName: "family_intakes",
|
|
1113
1113
|
conflictColumns: ["tenant_id", "item_id"],
|
|
1114
1114
|
...closed$2
|
|
@@ -1146,11 +1146,11 @@ var FamilyIntakeAsset = class extends SmrtObject {
|
|
|
1146
1146
|
noDelete();
|
|
1147
1147
|
}
|
|
1148
1148
|
};
|
|
1149
|
-
__publicField$
|
|
1150
|
-
__decorateClass$
|
|
1151
|
-
__decorateClass$
|
|
1152
|
-
__decorateClass$
|
|
1153
|
-
FamilyIntakeAsset = __decorateClass$
|
|
1149
|
+
__publicField$3(FamilyIntakeAsset, "__smrtPackage__", "@happyvertical/smrt-education");
|
|
1150
|
+
__decorateClass$3([tenantId()], FamilyIntakeAsset.prototype, "tenantId", 2);
|
|
1151
|
+
__decorateClass$3([foreignKey("FamilyIntake", { required: true })], FamilyIntakeAsset.prototype, "intakeId", 2);
|
|
1152
|
+
__decorateClass$3([crossPackageRef("@happyvertical/smrt-assets:Asset")], FamilyIntakeAsset.prototype, "assetId", 2);
|
|
1153
|
+
FamilyIntakeAsset = __decorateClass$3([TenantScoped({ mode: "required" }), smrt({
|
|
1154
1154
|
tableName: "family_intake_assets",
|
|
1155
1155
|
conflictColumns: [
|
|
1156
1156
|
"tenant_id",
|
|
@@ -1185,11 +1185,11 @@ var FamilyIntakeDecision = class extends SmrtObject {
|
|
|
1185
1185
|
noDelete();
|
|
1186
1186
|
}
|
|
1187
1187
|
};
|
|
1188
|
-
__publicField$
|
|
1189
|
-
__decorateClass$
|
|
1190
|
-
__decorateClass$
|
|
1191
|
-
__decorateClass$
|
|
1192
|
-
FamilyIntakeDecision = __decorateClass$
|
|
1188
|
+
__publicField$3(FamilyIntakeDecision, "__smrtPackage__", "@happyvertical/smrt-education");
|
|
1189
|
+
__decorateClass$3([tenantId()], FamilyIntakeDecision.prototype, "tenantId", 2);
|
|
1190
|
+
__decorateClass$3([foreignKey("FamilyIntake", { required: true })], FamilyIntakeDecision.prototype, "intakeId", 2);
|
|
1191
|
+
__decorateClass$3([field({ type: "text" })], FamilyIntakeDecision.prototype, "bodyJson", 2);
|
|
1192
|
+
FamilyIntakeDecision = __decorateClass$3([TenantScoped({ mode: "required" }), smrt({
|
|
1193
1193
|
tableName: "family_intake_decisions",
|
|
1194
1194
|
conflictColumns: [
|
|
1195
1195
|
"tenant_id",
|
|
@@ -1216,6 +1216,160 @@ async function familyAdoptionOwner(db, photo) {
|
|
|
1216
1216
|
return String(family.owner_profile_id);
|
|
1217
1217
|
}
|
|
1218
1218
|
//#endregion
|
|
1219
|
+
//#region src/group-sharing-contracts.ts
|
|
1220
|
+
var GroupSharingAuthorizationError = class extends Error {
|
|
1221
|
+
constructor(message = "Group sharing authorization denied") {
|
|
1222
|
+
super(message);
|
|
1223
|
+
this.name = "GroupSharingAuthorizationError";
|
|
1224
|
+
}
|
|
1225
|
+
};
|
|
1226
|
+
var GroupSharingConflictError = class extends Error {
|
|
1227
|
+
constructor(message = "Group sharing state conflict") {
|
|
1228
|
+
super(message);
|
|
1229
|
+
this.name = "GroupSharingConflictError";
|
|
1230
|
+
}
|
|
1231
|
+
};
|
|
1232
|
+
var GroupSharingPolicyValidationError = class extends Error {
|
|
1233
|
+
constructor(message = "Invalid group sharing policy") {
|
|
1234
|
+
super(message);
|
|
1235
|
+
this.name = "GroupSharingPolicyValidationError";
|
|
1236
|
+
}
|
|
1237
|
+
};
|
|
1238
|
+
function record$1(value) {
|
|
1239
|
+
return !!value && typeof value === "object" && !Array.isArray(value) && (Object.getPrototypeOf(value) === Object.prototype || Object.getPrototypeOf(value) === null);
|
|
1240
|
+
}
|
|
1241
|
+
function keys(value, expected) {
|
|
1242
|
+
const actual = Object.keys(value);
|
|
1243
|
+
return actual.length === expected.length && actual.every((key) => expected.includes(key));
|
|
1244
|
+
}
|
|
1245
|
+
function selector(value) {
|
|
1246
|
+
if (!record$1(value)) return false;
|
|
1247
|
+
if (value.mode === "all") return keys(value, ["mode"]);
|
|
1248
|
+
return value.mode === "include" && keys(value, ["mode", "values"]) && Array.isArray(value.values) && value.values.length <= 1e3 && value.values.every((v) => typeof v === "string" && v.length > 0 && v.length <= 256 && v.trim() === v) && new Set(value.values).size === value.values.length;
|
|
1249
|
+
}
|
|
1250
|
+
function validateGroupSharingPolicy(value) {
|
|
1251
|
+
const booleans = [
|
|
1252
|
+
"shareWork",
|
|
1253
|
+
"shareMedia",
|
|
1254
|
+
"shareFeedback",
|
|
1255
|
+
"shareProgress",
|
|
1256
|
+
"parentReviewedOnly"
|
|
1257
|
+
];
|
|
1258
|
+
if (!record$1(value) || !keys(value, [
|
|
1259
|
+
"schemaVersion",
|
|
1260
|
+
...booleans,
|
|
1261
|
+
"commentVisibility",
|
|
1262
|
+
"historyFrom",
|
|
1263
|
+
"subjects",
|
|
1264
|
+
"courseIds"
|
|
1265
|
+
]) || value.schemaVersion !== 1 || !["parent-only", "learner-visible"].includes(value.commentVisibility) || !booleans.every((key) => typeof value[key] === "boolean") || typeof value.historyFrom !== "string" || !/^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}\.\d{3}Z$/.test(value.historyFrom) || !Number.isFinite(Date.parse(value.historyFrom)) || new Date(value.historyFrom).toISOString() !== value.historyFrom || !selector(value.subjects) || !selector(value.courseIds)) throw new GroupSharingPolicyValidationError();
|
|
1266
|
+
}
|
|
1267
|
+
function canonicalGroupSharingPolicy(value) {
|
|
1268
|
+
validateGroupSharingPolicy(value);
|
|
1269
|
+
const ordered = (s) => s.mode === "all" ? { mode: "all" } : {
|
|
1270
|
+
mode: "include",
|
|
1271
|
+
values: [...s.values].sort()
|
|
1272
|
+
};
|
|
1273
|
+
return JSON.stringify({
|
|
1274
|
+
schemaVersion: 1,
|
|
1275
|
+
shareWork: value.shareWork,
|
|
1276
|
+
shareMedia: value.shareMedia,
|
|
1277
|
+
shareFeedback: value.shareFeedback,
|
|
1278
|
+
shareProgress: value.shareProgress,
|
|
1279
|
+
parentReviewedOnly: value.parentReviewedOnly,
|
|
1280
|
+
commentVisibility: value.commentVisibility,
|
|
1281
|
+
historyFrom: value.historyFrom,
|
|
1282
|
+
subjects: ordered(value.subjects),
|
|
1283
|
+
courseIds: ordered(value.courseIds)
|
|
1284
|
+
});
|
|
1285
|
+
}
|
|
1286
|
+
//#endregion
|
|
1287
|
+
//#region src/group-sharing-policy.ts
|
|
1288
|
+
function evaluateGroupSharingPolicy(policy, facts) {
|
|
1289
|
+
validateGroupSharingPolicy(policy);
|
|
1290
|
+
const reasons = [];
|
|
1291
|
+
const captured = Date.parse(facts.capturedAt);
|
|
1292
|
+
if (!Number.isFinite(captured) || !Number.isFinite(Date.parse(policy.historyFrom)) || captured < Date.parse(policy.historyFrom)) reasons.push("history");
|
|
1293
|
+
if (policy.courseIds.mode === "include" && (!facts.courseId || !policy.courseIds.values.includes(facts.courseId))) reasons.push("course");
|
|
1294
|
+
if (policy.subjects.mode === "include" && (!facts.subject || !policy.subjects.values.includes(facts.subject))) reasons.push("subject");
|
|
1295
|
+
if (policy.parentReviewedOnly && !facts.parentReviewed) reasons.push("parent-review");
|
|
1296
|
+
const eligible = reasons.length === 0;
|
|
1297
|
+
return {
|
|
1298
|
+
eligible,
|
|
1299
|
+
work: eligible && policy.shareWork,
|
|
1300
|
+
media: eligible && policy.shareWork && policy.shareMedia,
|
|
1301
|
+
feedback: eligible && policy.shareFeedback,
|
|
1302
|
+
progress: eligible && policy.shareProgress,
|
|
1303
|
+
reasons
|
|
1304
|
+
};
|
|
1305
|
+
}
|
|
1306
|
+
function summarizeWorkbookEvidence(evidence) {
|
|
1307
|
+
const summaries = /* @__PURE__ */ new Map();
|
|
1308
|
+
const independentSeen = /* @__PURE__ */ new Set();
|
|
1309
|
+
for (const { attempt, revisionId, assessment, confirmed } of evidence) for (const q of assessment.questions) for (const conceptId of q.conceptIds) {
|
|
1310
|
+
const key = `${assessment.vocabulary.namespace}:${assessment.vocabulary.version}:${conceptId}`;
|
|
1311
|
+
const concept = assessment.vocabulary.concepts.find((c) => c.id === conceptId);
|
|
1312
|
+
if (!concept) throw new Error("Unknown workbook concept");
|
|
1313
|
+
let summary = summaries.get(key);
|
|
1314
|
+
if (!summary) {
|
|
1315
|
+
summary = {
|
|
1316
|
+
namespace: assessment.vocabulary.namespace,
|
|
1317
|
+
version: assessment.vocabulary.version,
|
|
1318
|
+
conceptId,
|
|
1319
|
+
label: concept.label,
|
|
1320
|
+
confirmed: {
|
|
1321
|
+
independent: 0,
|
|
1322
|
+
assisted: 0,
|
|
1323
|
+
unknown: 0,
|
|
1324
|
+
correct: 0,
|
|
1325
|
+
needsCorrection: 0,
|
|
1326
|
+
unassessed: 0
|
|
1327
|
+
},
|
|
1328
|
+
provisional: 0,
|
|
1329
|
+
episodes: [],
|
|
1330
|
+
revisionIds: [],
|
|
1331
|
+
cues: [],
|
|
1332
|
+
observations: []
|
|
1333
|
+
};
|
|
1334
|
+
summaries.set(key, summary);
|
|
1335
|
+
}
|
|
1336
|
+
if (!summary.episodes.includes(attempt.episodeId)) summary.episodes.push(attempt.episodeId);
|
|
1337
|
+
if (!summary.revisionIds.includes(revisionId)) summary.revisionIds.push(revisionId);
|
|
1338
|
+
const assistance = attempt.previousAttemptId && attempt.assistance === "independent" ? "unknown" : attempt.assistance;
|
|
1339
|
+
summary.observations.push({
|
|
1340
|
+
submissionId: attempt.submissionId,
|
|
1341
|
+
revisionId,
|
|
1342
|
+
questionId: q.id,
|
|
1343
|
+
episodeId: attempt.episodeId,
|
|
1344
|
+
result: q.result,
|
|
1345
|
+
assistance,
|
|
1346
|
+
isCorrection: Boolean(attempt.previousAttemptId),
|
|
1347
|
+
capturedAt: attempt.capturedAt,
|
|
1348
|
+
confirmed
|
|
1349
|
+
});
|
|
1350
|
+
if (!confirmed) {
|
|
1351
|
+
summary.provisional++;
|
|
1352
|
+
continue;
|
|
1353
|
+
}
|
|
1354
|
+
if (q.result === "unassessed") {
|
|
1355
|
+
summary.confirmed.unassessed++;
|
|
1356
|
+
continue;
|
|
1357
|
+
}
|
|
1358
|
+
const episodeQuestion = `${key}:${attempt.episodeId}:${q.id}`;
|
|
1359
|
+
if (assistance !== "independent" || !independentSeen.has(episodeQuestion)) summary.confirmed[assistance]++;
|
|
1360
|
+
if (assistance === "independent") independentSeen.add(episodeQuestion);
|
|
1361
|
+
if (q.result === "correct") summary.confirmed.correct++;
|
|
1362
|
+
else summary.confirmed.needsCorrection++;
|
|
1363
|
+
if (attempt.previousAttemptId && q.result === "correct" && !summary.cues.includes("improving on this item")) summary.cues.push("improving on this item");
|
|
1364
|
+
}
|
|
1365
|
+
for (const summary of summaries.values()) {
|
|
1366
|
+
if (!summary.confirmed.independent) summary.cues.push("needs a fresh independent check");
|
|
1367
|
+
if (summary.confirmed.needsCorrection) summary.cues.push("needs practice");
|
|
1368
|
+
if (!summary.confirmed.correct && !summary.confirmed.needsCorrection) summary.cues.push("not enough evidence");
|
|
1369
|
+
}
|
|
1370
|
+
return [...summaries.values()];
|
|
1371
|
+
}
|
|
1372
|
+
//#endregion
|
|
1219
1373
|
//#region src/workbook-contracts.ts
|
|
1220
1374
|
var WorkbookAssessmentValidationError = class extends Error {
|
|
1221
1375
|
constructor(message, reason = "invalid_assessment") {
|
|
@@ -1251,6 +1405,14 @@ function aggregateWorkbookQuestions(questions) {
|
|
|
1251
1405
|
function workbookAggregateFeedback(aggregate) {
|
|
1252
1406
|
return `${aggregate.correct} correct; ${aggregate.incorrect} incorrect; ${aggregate.partiallyCorrect} partially correct; ${aggregate.unassessed} unassessed.`;
|
|
1253
1407
|
}
|
|
1408
|
+
var WorkbookCompletionConflictError = class extends Error {
|
|
1409
|
+
constructor(code) {
|
|
1410
|
+
super(`Workbook completion conflict: ${code}`);
|
|
1411
|
+
this.code = code;
|
|
1412
|
+
this.name = "WorkbookCompletionConflictError";
|
|
1413
|
+
}
|
|
1414
|
+
code;
|
|
1415
|
+
};
|
|
1254
1416
|
function text(value, label, max = 1e4) {
|
|
1255
1417
|
if (typeof value !== "string" || value.length > max) throw new WorkbookAssessmentValidationError(`Invalid ${label}`);
|
|
1256
1418
|
}
|
|
@@ -1363,21 +1525,21 @@ var WORKBOOK_MATH_VOCABULARY = {
|
|
|
1363
1525
|
};
|
|
1364
1526
|
//#endregion
|
|
1365
1527
|
//#region src/workbook-models.ts
|
|
1366
|
-
var __defProp$
|
|
1367
|
-
var __getOwnPropDesc$
|
|
1368
|
-
var __defNormalProp$
|
|
1528
|
+
var __defProp$2 = Object.defineProperty;
|
|
1529
|
+
var __getOwnPropDesc$2 = Object.getOwnPropertyDescriptor;
|
|
1530
|
+
var __defNormalProp$2 = (obj, key, value) => key in obj ? __defProp$2(obj, key, {
|
|
1369
1531
|
enumerable: true,
|
|
1370
1532
|
configurable: true,
|
|
1371
1533
|
writable: true,
|
|
1372
1534
|
value
|
|
1373
1535
|
}) : obj[key] = value;
|
|
1374
|
-
var __decorateClass$
|
|
1375
|
-
var result = kind > 1 ? void 0 : kind ? __getOwnPropDesc$
|
|
1536
|
+
var __decorateClass$2 = (decorators, target, key, kind) => {
|
|
1537
|
+
var result = kind > 1 ? void 0 : kind ? __getOwnPropDesc$2(target, key) : target;
|
|
1376
1538
|
for (var i = decorators.length - 1, decorator; i >= 0; i--) if (decorator = decorators[i]) result = (kind ? decorator(target, key, result) : decorator(result)) || result;
|
|
1377
|
-
if (kind && result) __defProp$
|
|
1539
|
+
if (kind && result) __defProp$2(target, key, result);
|
|
1378
1540
|
return result;
|
|
1379
1541
|
};
|
|
1380
|
-
var __publicField$
|
|
1542
|
+
var __publicField$2 = (obj, key, value) => __defNormalProp$2(obj, typeof key !== "symbol" ? key + "" : key, value);
|
|
1381
1543
|
var closed$1 = {
|
|
1382
1544
|
api: false,
|
|
1383
1545
|
mcp: false,
|
|
@@ -1416,10 +1578,10 @@ var Workbook = class extends SmrtObject {
|
|
|
1416
1578
|
return super.save(options);
|
|
1417
1579
|
}
|
|
1418
1580
|
};
|
|
1419
|
-
__publicField$
|
|
1420
|
-
__decorateClass$
|
|
1421
|
-
__decorateClass$
|
|
1422
|
-
Workbook = __decorateClass$
|
|
1581
|
+
__publicField$2(Workbook, "__smrtPackage__", "@happyvertical/smrt-education");
|
|
1582
|
+
__decorateClass$2([tenantId()], Workbook.prototype, "tenantId", 2);
|
|
1583
|
+
__decorateClass$2([foreignKey("Learner", { required: true })], Workbook.prototype, "learnerId", 2);
|
|
1584
|
+
Workbook = __decorateClass$2([TenantScoped({ mode: "required" }), smrt({
|
|
1423
1585
|
tableName: "workbooks",
|
|
1424
1586
|
conflictColumns: [
|
|
1425
1587
|
"tenant_id",
|
|
@@ -1497,19 +1659,19 @@ var WorkbookActivity = class extends SmrtObject {
|
|
|
1497
1659
|
return super.save(options);
|
|
1498
1660
|
}
|
|
1499
1661
|
};
|
|
1500
|
-
__publicField$
|
|
1501
|
-
__decorateClass$
|
|
1502
|
-
__decorateClass$
|
|
1503
|
-
__decorateClass$
|
|
1504
|
-
__decorateClass$
|
|
1662
|
+
__publicField$2(WorkbookActivity, "__smrtPackage__", "@happyvertical/smrt-education");
|
|
1663
|
+
__decorateClass$2([tenantId()], WorkbookActivity.prototype, "tenantId", 2);
|
|
1664
|
+
__decorateClass$2([foreignKey("Learner", { required: true })], WorkbookActivity.prototype, "learnerId", 2);
|
|
1665
|
+
__decorateClass$2([foreignKey("Workbook", { nullable: true })], WorkbookActivity.prototype, "workbookId", 2);
|
|
1666
|
+
__decorateClass$2([field({
|
|
1505
1667
|
type: "text",
|
|
1506
1668
|
required: true,
|
|
1507
1669
|
default: "identified"
|
|
1508
1670
|
})], WorkbookActivity.prototype, "captureKind", 2);
|
|
1509
|
-
__decorateClass$
|
|
1510
|
-
__decorateClass$
|
|
1511
|
-
__decorateClass$
|
|
1512
|
-
WorkbookActivity = __decorateClass$
|
|
1671
|
+
__decorateClass$2([foreignKey("WorkbookPhotoIntake", { nullable: true })], WorkbookActivity.prototype, "photoIntakeId", 2);
|
|
1672
|
+
__decorateClass$2([foreignKey("Enrollment", { required: true })], WorkbookActivity.prototype, "enrollmentId", 2);
|
|
1673
|
+
__decorateClass$2([foreignKey("Lesson", { required: true })], WorkbookActivity.prototype, "lessonId", 2);
|
|
1674
|
+
WorkbookActivity = __decorateClass$2([TenantScoped({ mode: "required" }), smrt({
|
|
1513
1675
|
tableName: "workbook_activities",
|
|
1514
1676
|
conflictColumns: [
|
|
1515
1677
|
"tenant_id",
|
|
@@ -1573,14 +1735,14 @@ var WorkbookWorkFiling = class extends SmrtObject {
|
|
|
1573
1735
|
return super.save(options);
|
|
1574
1736
|
}
|
|
1575
1737
|
};
|
|
1576
|
-
__publicField$
|
|
1577
|
-
__decorateClass$
|
|
1578
|
-
__decorateClass$
|
|
1579
|
-
__decorateClass$
|
|
1580
|
-
__decorateClass$
|
|
1581
|
-
__decorateClass$
|
|
1582
|
-
__decorateClass$
|
|
1583
|
-
WorkbookWorkFiling = __decorateClass$
|
|
1738
|
+
__publicField$2(WorkbookWorkFiling, "__smrtPackage__", "@happyvertical/smrt-education");
|
|
1739
|
+
__decorateClass$2([tenantId()], WorkbookWorkFiling.prototype, "tenantId", 2);
|
|
1740
|
+
__decorateClass$2([foreignKey("Learner", { required: true })], WorkbookWorkFiling.prototype, "learnerId", 2);
|
|
1741
|
+
__decorateClass$2([foreignKey("WorkbookActivity", { required: true })], WorkbookWorkFiling.prototype, "sourceActivityId", 2);
|
|
1742
|
+
__decorateClass$2([foreignKey("Workbook", { required: true })], WorkbookWorkFiling.prototype, "workbookId", 2);
|
|
1743
|
+
__decorateClass$2([foreignKey("WorkbookActivity", { nullable: true })], WorkbookWorkFiling.prototype, "canonicalActivityId", 2);
|
|
1744
|
+
__decorateClass$2([foreignKey("WorkbookWorkFiling", { nullable: true })], WorkbookWorkFiling.prototype, "previousRevisionId", 2);
|
|
1745
|
+
WorkbookWorkFiling = __decorateClass$2([TenantScoped({ mode: "required" }), smrt({
|
|
1584
1746
|
tableName: "workbook_work_filings",
|
|
1585
1747
|
conflictColumns: [
|
|
1586
1748
|
"tenant_id",
|
|
@@ -1647,14 +1809,14 @@ var WorkbookAttempt = class extends SmrtObject {
|
|
|
1647
1809
|
return super.save(options);
|
|
1648
1810
|
}
|
|
1649
1811
|
};
|
|
1650
|
-
__publicField$
|
|
1651
|
-
__decorateClass$
|
|
1652
|
-
__decorateClass$
|
|
1653
|
-
__decorateClass$
|
|
1654
|
-
__decorateClass$
|
|
1655
|
-
__decorateClass$
|
|
1656
|
-
__decorateClass$
|
|
1657
|
-
WorkbookAttempt = __decorateClass$
|
|
1812
|
+
__publicField$2(WorkbookAttempt, "__smrtPackage__", "@happyvertical/smrt-education");
|
|
1813
|
+
__decorateClass$2([tenantId()], WorkbookAttempt.prototype, "tenantId", 2);
|
|
1814
|
+
__decorateClass$2([foreignKey("Learner", { required: true })], WorkbookAttempt.prototype, "learnerId", 2);
|
|
1815
|
+
__decorateClass$2([foreignKey("WorkbookActivity", { required: true })], WorkbookAttempt.prototype, "activityId", 2);
|
|
1816
|
+
__decorateClass$2([foreignKey("Submission", { required: true })], WorkbookAttempt.prototype, "submissionId", 2);
|
|
1817
|
+
__decorateClass$2([foreignKey("WorkbookAttempt", { nullable: true })], WorkbookAttempt.prototype, "previousAttemptId", 2);
|
|
1818
|
+
__decorateClass$2([field({ type: "text" })], WorkbookAttempt.prototype, "sourceHashes", 2);
|
|
1819
|
+
WorkbookAttempt = __decorateClass$2([TenantScoped({ mode: "required" }), smrt({
|
|
1658
1820
|
tableName: "workbook_attempts",
|
|
1659
1821
|
conflictColumns: ["tenant_id", "submission_id"],
|
|
1660
1822
|
...closed$1
|
|
@@ -1701,14 +1863,14 @@ var WorkbookAssessmentRevision = class extends SmrtObject {
|
|
|
1701
1863
|
return super.save(options);
|
|
1702
1864
|
}
|
|
1703
1865
|
};
|
|
1704
|
-
__publicField$
|
|
1705
|
-
__decorateClass$
|
|
1706
|
-
__decorateClass$
|
|
1707
|
-
__decorateClass$
|
|
1708
|
-
__decorateClass$
|
|
1709
|
-
__decorateClass$
|
|
1710
|
-
__decorateClass$
|
|
1711
|
-
WorkbookAssessmentRevision = __decorateClass$
|
|
1866
|
+
__publicField$2(WorkbookAssessmentRevision, "__smrtPackage__", "@happyvertical/smrt-education");
|
|
1867
|
+
__decorateClass$2([tenantId()], WorkbookAssessmentRevision.prototype, "tenantId", 2);
|
|
1868
|
+
__decorateClass$2([foreignKey("Learner", { required: true })], WorkbookAssessmentRevision.prototype, "learnerId", 2);
|
|
1869
|
+
__decorateClass$2([foreignKey("WorkbookAttempt", { required: true })], WorkbookAssessmentRevision.prototype, "attemptId", 2);
|
|
1870
|
+
__decorateClass$2([foreignKey("WorkbookAssessmentRevision", { nullable: true })], WorkbookAssessmentRevision.prototype, "sourceRevisionId", 2);
|
|
1871
|
+
__decorateClass$2([foreignKey("WorkbookAssessmentRevision", { nullable: true })], WorkbookAssessmentRevision.prototype, "supersedesId", 2);
|
|
1872
|
+
__decorateClass$2([field({ type: "text" })], WorkbookAssessmentRevision.prototype, "assessmentJson", 2);
|
|
1873
|
+
WorkbookAssessmentRevision = __decorateClass$2([TenantScoped({ mode: "required" }), smrt({
|
|
1712
1874
|
tableName: "workbook_assessment_revisions",
|
|
1713
1875
|
conflictColumns: [
|
|
1714
1876
|
"tenant_id",
|
|
@@ -1753,13 +1915,13 @@ var WorkbookFeedbackRelease = class extends SmrtObject {
|
|
|
1753
1915
|
return super.save(options);
|
|
1754
1916
|
}
|
|
1755
1917
|
};
|
|
1756
|
-
__publicField$
|
|
1757
|
-
__decorateClass$
|
|
1758
|
-
__decorateClass$
|
|
1759
|
-
__decorateClass$
|
|
1760
|
-
__decorateClass$
|
|
1761
|
-
__decorateClass$
|
|
1762
|
-
WorkbookFeedbackRelease = __decorateClass$
|
|
1918
|
+
__publicField$2(WorkbookFeedbackRelease, "__smrtPackage__", "@happyvertical/smrt-education");
|
|
1919
|
+
__decorateClass$2([tenantId()], WorkbookFeedbackRelease.prototype, "tenantId", 2);
|
|
1920
|
+
__decorateClass$2([foreignKey("Learner", { required: true })], WorkbookFeedbackRelease.prototype, "learnerId", 2);
|
|
1921
|
+
__decorateClass$2([foreignKey("WorkbookAttempt", { required: true })], WorkbookFeedbackRelease.prototype, "attemptId", 2);
|
|
1922
|
+
__decorateClass$2([foreignKey("WorkbookAssessmentRevision", { required: true })], WorkbookFeedbackRelease.prototype, "revisionId", 2);
|
|
1923
|
+
__decorateClass$2([foreignKey("WorkbookAssessmentRevision", { nullable: true })], WorkbookFeedbackRelease.prototype, "expectedHeadId", 2);
|
|
1924
|
+
WorkbookFeedbackRelease = __decorateClass$2([TenantScoped({ mode: "required" }), smrt({
|
|
1763
1925
|
tableName: "workbook_feedback_releases",
|
|
1764
1926
|
conflictColumns: [
|
|
1765
1927
|
"tenant_id",
|
|
@@ -1802,12 +1964,12 @@ var WorkbookFeedbackDelivery = class extends SmrtObject {
|
|
|
1802
1964
|
throw new Error("Workbook delivery history is immutable");
|
|
1803
1965
|
}
|
|
1804
1966
|
};
|
|
1805
|
-
__publicField$
|
|
1806
|
-
__decorateClass$
|
|
1807
|
-
__decorateClass$
|
|
1808
|
-
__decorateClass$
|
|
1809
|
-
__decorateClass$
|
|
1810
|
-
WorkbookFeedbackDelivery = __decorateClass$
|
|
1967
|
+
__publicField$2(WorkbookFeedbackDelivery, "__smrtPackage__", "@happyvertical/smrt-education");
|
|
1968
|
+
__decorateClass$2([tenantId()], WorkbookFeedbackDelivery.prototype, "tenantId", 2);
|
|
1969
|
+
__decorateClass$2([foreignKey("Learner", { required: true })], WorkbookFeedbackDelivery.prototype, "learnerId", 2);
|
|
1970
|
+
__decorateClass$2([foreignKey("WorkbookAttempt", { required: true })], WorkbookFeedbackDelivery.prototype, "attemptId", 2);
|
|
1971
|
+
__decorateClass$2([foreignKey("WorkbookAssessmentRevision", { required: true })], WorkbookFeedbackDelivery.prototype, "revisionId", 2);
|
|
1972
|
+
WorkbookFeedbackDelivery = __decorateClass$2([TenantScoped({ mode: "required" }), smrt({
|
|
1811
1973
|
tableName: "workbook_feedback_deliveries",
|
|
1812
1974
|
conflictColumns: [
|
|
1813
1975
|
"tenant_id",
|
|
@@ -1821,6 +1983,176 @@ var WorkbookFeedbackDeliveryCollection = class extends SmrtCollection {
|
|
|
1821
1983
|
static _itemClass = WorkbookFeedbackDelivery;
|
|
1822
1984
|
};
|
|
1823
1985
|
//#endregion
|
|
1986
|
+
//#region src/workbook-completion.ts
|
|
1987
|
+
var __defProp$1 = Object.defineProperty;
|
|
1988
|
+
var __getOwnPropDesc$1 = Object.getOwnPropertyDescriptor;
|
|
1989
|
+
var __defNormalProp$1 = (obj, key, value) => key in obj ? __defProp$1(obj, key, {
|
|
1990
|
+
enumerable: true,
|
|
1991
|
+
configurable: true,
|
|
1992
|
+
writable: true,
|
|
1993
|
+
value
|
|
1994
|
+
}) : obj[key] = value;
|
|
1995
|
+
var __decorateClass$1 = (decorators, target, key, kind) => {
|
|
1996
|
+
var result = kind > 1 ? void 0 : kind ? __getOwnPropDesc$1(target, key) : target;
|
|
1997
|
+
for (var i = decorators.length - 1, decorator; i >= 0; i--) if (decorator = decorators[i]) result = (kind ? decorator(target, key, result) : decorator(result)) || result;
|
|
1998
|
+
if (kind && result) __defProp$1(target, key, result);
|
|
1999
|
+
return result;
|
|
2000
|
+
};
|
|
2001
|
+
var __publicField$1 = (obj, key, value) => __defNormalProp$1(obj, typeof key !== "symbol" ? key + "" : key, value);
|
|
2002
|
+
var WorkbookCompletionDecision = class extends SmrtObject {
|
|
2003
|
+
tenantId = "";
|
|
2004
|
+
learnerId = "";
|
|
2005
|
+
activityId = "";
|
|
2006
|
+
attemptId = "";
|
|
2007
|
+
submissionId = "";
|
|
2008
|
+
feedbackHeadId = null;
|
|
2009
|
+
actorUserId = "";
|
|
2010
|
+
requestKey = "";
|
|
2011
|
+
recordedAt = /* @__PURE__ */ new Date();
|
|
2012
|
+
constructor(options = {}) {
|
|
2013
|
+
super(options);
|
|
2014
|
+
for (const [key, value] of Object.entries(options)) if (Object.hasOwn(this, key)) this[key] = value;
|
|
2015
|
+
}
|
|
2016
|
+
async delete() {
|
|
2017
|
+
throw new Error("Workbook completion history is immutable");
|
|
2018
|
+
}
|
|
2019
|
+
async save(options) {
|
|
2020
|
+
if (this.id && await this.db.get(this.tableName, { id: this.id })) throw new Error("Workbook completion history is immutable");
|
|
2021
|
+
if (!this.tenantId.trim() || !this.actorUserId || typeof this.requestKey !== "string" || !this.requestKey.trim() || this.requestKey.length > 200 || Array.from(this.requestKey).some((character) => {
|
|
2022
|
+
const code = character.charCodeAt(0);
|
|
2023
|
+
return code < 32 || code === 127;
|
|
2024
|
+
})) throw new Error("Workbook completion requires tenant, actor and request key");
|
|
2025
|
+
const owner = {
|
|
2026
|
+
tenant_id: this.tenantId,
|
|
2027
|
+
learner_id: this.learnerId
|
|
2028
|
+
};
|
|
2029
|
+
const activity = await this.db.get("workbook_activities", {
|
|
2030
|
+
...owner,
|
|
2031
|
+
id: this.activityId
|
|
2032
|
+
});
|
|
2033
|
+
const submission = await this.db.get("submissions", {
|
|
2034
|
+
...owner,
|
|
2035
|
+
id: this.submissionId
|
|
2036
|
+
});
|
|
2037
|
+
if (!activity || !submission || !await this.db.get("learners", {
|
|
2038
|
+
id: this.learnerId,
|
|
2039
|
+
tenant_id: this.tenantId
|
|
2040
|
+
}) || !await this.db.get("workbook_attempts", {
|
|
2041
|
+
...owner,
|
|
2042
|
+
id: this.attemptId,
|
|
2043
|
+
activity_id: this.activityId,
|
|
2044
|
+
submission_id: this.submissionId
|
|
2045
|
+
}) || submission.lesson_id !== activity.lesson_id || !await this.db.get("lesson_progress", {
|
|
2046
|
+
...owner,
|
|
2047
|
+
id: submission.progress_id,
|
|
2048
|
+
enrollment_id: activity.enrollment_id,
|
|
2049
|
+
lesson_id: activity.lesson_id
|
|
2050
|
+
}) || !await this.db.get("memberships", {
|
|
2051
|
+
tenant_id: this.tenantId,
|
|
2052
|
+
user_id: this.actorUserId,
|
|
2053
|
+
status: "active"
|
|
2054
|
+
})) throw new Error("Workbook completion ownership mismatch");
|
|
2055
|
+
if (this.feedbackHeadId !== null && !await this.db.get("workbook_assessment_revisions", {
|
|
2056
|
+
...owner,
|
|
2057
|
+
id: this.feedbackHeadId,
|
|
2058
|
+
attempt_id: this.attemptId
|
|
2059
|
+
})) throw new Error("Workbook completion feedback head mismatch");
|
|
2060
|
+
this.recordedAt = /* @__PURE__ */ new Date();
|
|
2061
|
+
this.requireInsertOnSave();
|
|
2062
|
+
return super.save(options);
|
|
2063
|
+
}
|
|
2064
|
+
};
|
|
2065
|
+
__publicField$1(WorkbookCompletionDecision, "__smrtPackage__", "@happyvertical/smrt-education");
|
|
2066
|
+
__decorateClass$1([tenantId()], WorkbookCompletionDecision.prototype, "tenantId", 2);
|
|
2067
|
+
__decorateClass$1([foreignKey("Learner", { required: true })], WorkbookCompletionDecision.prototype, "learnerId", 2);
|
|
2068
|
+
__decorateClass$1([foreignKey("WorkbookActivity", { required: true })], WorkbookCompletionDecision.prototype, "activityId", 2);
|
|
2069
|
+
__decorateClass$1([foreignKey("WorkbookAttempt", { required: true })], WorkbookCompletionDecision.prototype, "attemptId", 2);
|
|
2070
|
+
__decorateClass$1([foreignKey("Submission", { required: true })], WorkbookCompletionDecision.prototype, "submissionId", 2);
|
|
2071
|
+
__decorateClass$1([foreignKey("WorkbookAssessmentRevision", { nullable: true })], WorkbookCompletionDecision.prototype, "feedbackHeadId", 2);
|
|
2072
|
+
__decorateClass$1([crossPackageRef("@happyvertical/smrt-users:User", { required: true })], WorkbookCompletionDecision.prototype, "actorUserId", 2);
|
|
2073
|
+
WorkbookCompletionDecision = __decorateClass$1([TenantScoped({ mode: "required" }), smrt({
|
|
2074
|
+
api: false,
|
|
2075
|
+
mcp: false,
|
|
2076
|
+
cli: false,
|
|
2077
|
+
tableName: "workbook_completion_decisions",
|
|
2078
|
+
conflictColumns: [
|
|
2079
|
+
"tenant_id",
|
|
2080
|
+
"activity_id",
|
|
2081
|
+
"request_key"
|
|
2082
|
+
],
|
|
2083
|
+
indexes: [{
|
|
2084
|
+
name: "workbook_completion_decisions_attempt_unique",
|
|
2085
|
+
columns: [
|
|
2086
|
+
"tenantId",
|
|
2087
|
+
"activityId",
|
|
2088
|
+
"attemptId"
|
|
2089
|
+
],
|
|
2090
|
+
unique: true
|
|
2091
|
+
}]
|
|
2092
|
+
})], WorkbookCompletionDecision);
|
|
2093
|
+
var WorkbookCompletionDecisionCollection = class extends SmrtCollection {
|
|
2094
|
+
static _itemClass = WorkbookCompletionDecision;
|
|
2095
|
+
};
|
|
2096
|
+
async function readWorkbookCompletion(db, scope) {
|
|
2097
|
+
if (!scope.tenantId || !scope.learnerId || !scope.activityId) throw new Error("Workbook completion requires exact scope");
|
|
2098
|
+
const attempts = await db.tableExists("workbook_attempts") ? await (await WorkbookAttemptCollection.create({ db })).list({ where: scope }) : [];
|
|
2099
|
+
const byId = new Map(attempts.map((attempt) => [String(attempt.id), attempt]));
|
|
2100
|
+
const episodes = /* @__PURE__ */ new Map();
|
|
2101
|
+
for (const attempt of attempts) {
|
|
2102
|
+
const episode = episodes.get(attempt.episodeId) ?? [];
|
|
2103
|
+
episode.push(attempt);
|
|
2104
|
+
episodes.set(attempt.episodeId, episode);
|
|
2105
|
+
}
|
|
2106
|
+
const leaves = [];
|
|
2107
|
+
for (const episode of episodes.values()) {
|
|
2108
|
+
const predecessors = new Set(episode.flatMap((attempt) => attempt.previousAttemptId ? [attempt.previousAttemptId] : []));
|
|
2109
|
+
const episodeLeaves = episode.filter((attempt) => !predecessors.has(String(attempt.id)));
|
|
2110
|
+
if (episodeLeaves.length !== 1) throw new Error("Workbook current attempt is ambiguous");
|
|
2111
|
+
const leaf = episodeLeaves[0];
|
|
2112
|
+
const visited = /* @__PURE__ */ new Set();
|
|
2113
|
+
let ancestor = leaf;
|
|
2114
|
+
while (ancestor) {
|
|
2115
|
+
const id = String(ancestor.id);
|
|
2116
|
+
if (visited.has(id)) throw new Error("Workbook attempt ancestry is cyclic");
|
|
2117
|
+
if (ancestor.episodeId !== leaf.episodeId) throw new Error("Workbook attempt ancestry crosses practice episodes");
|
|
2118
|
+
visited.add(id);
|
|
2119
|
+
const previous = ancestor.previousAttemptId;
|
|
2120
|
+
ancestor = previous ? byId.get(previous) ?? null : null;
|
|
2121
|
+
if (previous && !ancestor) throw new Error("Workbook attempt ancestry is incomplete");
|
|
2122
|
+
}
|
|
2123
|
+
if (visited.size !== episode.length) throw new Error("Workbook attempt ancestry is disconnected");
|
|
2124
|
+
leaves.push(leaf);
|
|
2125
|
+
}
|
|
2126
|
+
leaves.sort((a, b) => new Date(b.capturedAt).getTime() - new Date(a.capturedAt).getTime() || String(b.id).localeCompare(String(a.id)));
|
|
2127
|
+
const currentAttempt = leaves[0] ?? null;
|
|
2128
|
+
const revisions = currentAttempt ? await (await WorkbookAssessmentRevisionCollection.create({ db })).list({ where: {
|
|
2129
|
+
tenantId: scope.tenantId,
|
|
2130
|
+
learnerId: scope.learnerId,
|
|
2131
|
+
attemptId: String(currentAttempt.id)
|
|
2132
|
+
} }) : [];
|
|
2133
|
+
revisions.sort((a, b) => new Date(b.recordedAt).getTime() - new Date(a.recordedAt).getTime() || String(b.id).localeCompare(String(a.id)));
|
|
2134
|
+
const head = revisions.find((revision) => revision.kind === "guardian") ?? revisions.find((revision) => revision.kind === "ai");
|
|
2135
|
+
const decisions = await db.tableExists("workbook_completion_decisions") ? await (await WorkbookCompletionDecisionCollection.create({ db })).list({ where: scope }) : [];
|
|
2136
|
+
const currentDecisions = decisions.filter((decision2) => decision2.attemptId === currentAttempt?.id);
|
|
2137
|
+
if (currentDecisions.length > 1) throw new Error("Workbook current completion decision is ambiguous");
|
|
2138
|
+
const decision = currentDecisions[0] ?? null;
|
|
2139
|
+
if (decision && decision.submissionId !== currentAttempt?.submissionId) throw new Error("Workbook completion submission mismatch");
|
|
2140
|
+
return {
|
|
2141
|
+
currentAttempt,
|
|
2142
|
+
feedbackHeadId: head ? String(head.id) : null,
|
|
2143
|
+
decision,
|
|
2144
|
+
decisions,
|
|
2145
|
+
completion: decision ? {
|
|
2146
|
+
status: "complete",
|
|
2147
|
+
completedAt: new Date(decision.recordedAt)
|
|
2148
|
+
} : {
|
|
2149
|
+
status: "doing",
|
|
2150
|
+
completedAt: null
|
|
2151
|
+
},
|
|
2152
|
+
attempts
|
|
2153
|
+
};
|
|
2154
|
+
}
|
|
2155
|
+
//#endregion
|
|
1824
2156
|
//#region src/learner-service.ts
|
|
1825
2157
|
var LearnerAuthorizationError = class extends Error {
|
|
1826
2158
|
constructor() {
|
|
@@ -2019,7 +2351,10 @@ var LearnerService = class LearnerService {
|
|
|
2019
2351
|
if (own && [
|
|
2020
2352
|
"education.learner.plan",
|
|
2021
2353
|
"education.learner.grade",
|
|
2022
|
-
"education.learner.packet"
|
|
2354
|
+
"education.learner.packet",
|
|
2355
|
+
"education.learner.notes.read",
|
|
2356
|
+
"education.learner.notes.add",
|
|
2357
|
+
"education.learner.complete"
|
|
2023
2358
|
].includes(action)) throw new LearnerAuthorizationError();
|
|
2024
2359
|
if (await this.authorize({
|
|
2025
2360
|
...request,
|
|
@@ -2255,15 +2590,25 @@ var LearnerService = class LearnerService {
|
|
|
2255
2590
|
/** Compatibility progress never transports a workbook learner's feedback. */
|
|
2256
2591
|
async projectProgress(request, row) {
|
|
2257
2592
|
const view = progressView(row);
|
|
2258
|
-
|
|
2593
|
+
const activity = await this.findWorkbookActivity(request, {
|
|
2594
|
+
enrollmentId: row.enrollmentId,
|
|
2595
|
+
lessonId: row.lessonId
|
|
2596
|
+
});
|
|
2597
|
+
if (!activity) return view;
|
|
2598
|
+
const state = await readWorkbookCompletion(this.db, {
|
|
2599
|
+
tenantId: request.tenantId,
|
|
2600
|
+
learnerId: request.learnerId,
|
|
2601
|
+
activityId: String(activity.id)
|
|
2602
|
+
});
|
|
2603
|
+
const learner = await this.db.get("learners", {
|
|
2259
2604
|
id: request.learnerId,
|
|
2260
2605
|
tenant_id: request.tenantId
|
|
2261
|
-
})
|
|
2606
|
+
});
|
|
2262
2607
|
return {
|
|
2263
2608
|
...view,
|
|
2264
|
-
|
|
2265
|
-
completedAt:
|
|
2266
|
-
|
|
2609
|
+
status: state.completion.status === "complete" ? "complete" : ["complete", "skipped"].includes(view.status) ? "in_progress" : view.status,
|
|
2610
|
+
completedAt: state.completion.completedAt,
|
|
2611
|
+
...learner?.user_id === request.actorUserId ? { bestScore: null } : {}
|
|
2267
2612
|
};
|
|
2268
2613
|
}
|
|
2269
2614
|
async listProgress(request) {
|
|
@@ -25107,9 +25452,13 @@ var SubmissionService = class SubmissionService extends LearnerService {
|
|
|
25107
25452
|
"application/pdf"
|
|
25108
25453
|
].includes(page.mimeType) || !Buffer.isBuffer(page.data) || !page.data.length || page.data.length > 25 * 1024 * 1024) throw new Error("Invalid capture page");
|
|
25109
25454
|
}
|
|
25455
|
+
async lockProgressOwner(request) {
|
|
25456
|
+
if (await this.findWorkbookActivity(request, { enrollmentId: request.enrollmentId })) await this.db.query("UPDATE learners SET id = id WHERE id = ? AND tenant_id = ?", [request.learnerId, request.tenantId]);
|
|
25457
|
+
await this.lock("enrollments", request.enrollmentId, request.tenantId);
|
|
25458
|
+
}
|
|
25110
25459
|
async progress(request, action) {
|
|
25111
25460
|
const enrollment = await this.requireEnrollment(request, action);
|
|
25112
|
-
await this.
|
|
25461
|
+
await this.lockProgressOwner(request);
|
|
25113
25462
|
if (!(await this.catalog(request, enrollment.courseId)).sections.some((section) => section.lessons.some(({ lesson }) => lesson.id === request.lessonId))) throw new LearnerAuthorizationError();
|
|
25114
25463
|
const collection = await LessonProgressCollection.create({ db: this.db });
|
|
25115
25464
|
let progress = await collection.get({
|
|
@@ -25446,6 +25795,38 @@ var SubmissionService = class SubmissionService extends LearnerService {
|
|
|
25446
25795
|
async getSubmission(request) {
|
|
25447
25796
|
return this.view((await this.requireSubmission(request, "education.learner.read")).row, request.actorUserId);
|
|
25448
25797
|
}
|
|
25798
|
+
/** Latest retained completed-work evidence; lesson completion is independent. */
|
|
25799
|
+
async getLatestLessonSubmission(request) {
|
|
25800
|
+
const enrollment = await this.requireEnrollment(request, "education.learner.read");
|
|
25801
|
+
if (!(await this.catalog(request, enrollment.courseId)).sections.some((section) => section.lessons.some(({ lesson }) => lesson.id === request.lessonId))) throw new LearnerAuthorizationError();
|
|
25802
|
+
const progress = await (await LessonProgressCollection.create({ db: this.db })).get({
|
|
25803
|
+
enrollmentId: request.enrollmentId,
|
|
25804
|
+
learnerId: request.learnerId,
|
|
25805
|
+
lessonId: request.lessonId,
|
|
25806
|
+
tenantId: request.tenantId
|
|
25807
|
+
}, { cache: false });
|
|
25808
|
+
if (!progress) return null;
|
|
25809
|
+
const [row] = await (await SubmissionCollection.create({ db: this.db })).list({
|
|
25810
|
+
where: {
|
|
25811
|
+
tenantId: request.tenantId,
|
|
25812
|
+
learnerId: request.learnerId,
|
|
25813
|
+
lessonId: request.lessonId,
|
|
25814
|
+
progressId: String(progress.id),
|
|
25815
|
+
kind: "completed_work",
|
|
25816
|
+
"status in": [
|
|
25817
|
+
"captured",
|
|
25818
|
+
"needs_review",
|
|
25819
|
+
"graded"
|
|
25820
|
+
]
|
|
25821
|
+
},
|
|
25822
|
+
orderBy: ["submittedAt DESC", "id DESC"],
|
|
25823
|
+
limit: 1
|
|
25824
|
+
});
|
|
25825
|
+
return row ? this.getSubmission({
|
|
25826
|
+
...request,
|
|
25827
|
+
submissionId: String(row.id)
|
|
25828
|
+
}) : null;
|
|
25829
|
+
}
|
|
25449
25830
|
async grade(request, row, progress, score, feedback) {
|
|
25450
25831
|
if (typeof feedback !== "string") throw new Error("Feedback must be text");
|
|
25451
25832
|
if (score !== null && (typeof score !== "number" || !Number.isFinite(score) || score < 0 || score > 1)) throw new Error("Score must be null or a number from zero to one");
|
|
@@ -25469,8 +25850,17 @@ var SubmissionService = class SubmissionService extends LearnerService {
|
|
|
25469
25850
|
});
|
|
25470
25851
|
row.status = "graded";
|
|
25471
25852
|
await row.save();
|
|
25472
|
-
|
|
25473
|
-
|
|
25853
|
+
const workbookActivity = await this.findWorkbookActivity(request, {
|
|
25854
|
+
enrollmentId: progress.enrollmentId,
|
|
25855
|
+
lessonId: row.lessonId
|
|
25856
|
+
});
|
|
25857
|
+
const completion = workbookActivity ? await readWorkbookCompletion(this.db, {
|
|
25858
|
+
tenantId: request.tenantId,
|
|
25859
|
+
learnerId: request.learnerId,
|
|
25860
|
+
activityId: String(workbookActivity.id)
|
|
25861
|
+
}) : null;
|
|
25862
|
+
progress.status = completion ? completion.completion.status === "complete" ? "complete" : "in_progress" : "complete";
|
|
25863
|
+
progress.completedAt = completion ? completion.completion.completedAt : /* @__PURE__ */ new Date();
|
|
25474
25864
|
progress.bestScore = score;
|
|
25475
25865
|
await progress.save();
|
|
25476
25866
|
return this.view(row, request.actorUserId);
|
|
@@ -25478,7 +25868,7 @@ var SubmissionService = class SubmissionService extends LearnerService {
|
|
|
25478
25868
|
async reviewSubmission(request) {
|
|
25479
25869
|
return this.mutate(async (service) => {
|
|
25480
25870
|
await service.requireEnrollment(request, "education.learner.grade");
|
|
25481
|
-
await service.
|
|
25871
|
+
await service.lockProgressOwner(request);
|
|
25482
25872
|
const { row, progress } = await service.requireSubmission(request, "education.learner.grade");
|
|
25483
25873
|
if (row.kind !== "completed_work") throw new Error("Blank workbook references cannot be graded");
|
|
25484
25874
|
if ((await (await SubmissionCollection.create({ db: service.db })).list({ where: {
|
|
@@ -26018,6 +26408,17 @@ function revisionView(row) {
|
|
|
26018
26408
|
assessment: JSON.parse(row.assessmentJson)
|
|
26019
26409
|
};
|
|
26020
26410
|
}
|
|
26411
|
+
function completionDecisionView(row) {
|
|
26412
|
+
return {
|
|
26413
|
+
id: String(row.id),
|
|
26414
|
+
activityId: row.activityId,
|
|
26415
|
+
attemptId: row.attemptId,
|
|
26416
|
+
submissionId: row.submissionId,
|
|
26417
|
+
feedbackHeadId: row.feedbackHeadId,
|
|
26418
|
+
actorUserId: row.actorUserId,
|
|
26419
|
+
completedAt: new Date(row.recordedAt)
|
|
26420
|
+
};
|
|
26421
|
+
}
|
|
26021
26422
|
var WorkbookService = class WorkbookService extends SubmissionService {
|
|
26022
26423
|
constructor(db, authorize, authorizeCatalog, workbookOptions) {
|
|
26023
26424
|
super(db, authorize, authorizeCatalog, workbookOptions);
|
|
@@ -26086,7 +26487,15 @@ var WorkbookService = class WorkbookService extends SubmissionService {
|
|
|
26086
26487
|
workbookId: head.workbookId
|
|
26087
26488
|
}, { cache: false }) : null;
|
|
26088
26489
|
if (head && (!projectedBook || head.canonicalActivityId && !target)) throw new LearnerAuthorizationError();
|
|
26490
|
+
const completion = await readWorkbookCompletion(this.db, {
|
|
26491
|
+
tenantId: row.tenantId,
|
|
26492
|
+
learnerId: row.learnerId,
|
|
26493
|
+
activityId: String(row.id)
|
|
26494
|
+
});
|
|
26089
26495
|
return {
|
|
26496
|
+
currentAttemptId: completion.currentAttempt ? String(completion.currentAttempt.id) : null,
|
|
26497
|
+
latestSubmissionId: completion.currentAttempt?.submissionId ?? null,
|
|
26498
|
+
completion: completion.completion,
|
|
26090
26499
|
id: String(row.id),
|
|
26091
26500
|
learnerId: row.learnerId,
|
|
26092
26501
|
workbookKey: projectedBook?.workbookKey ?? "",
|
|
@@ -26521,6 +26930,21 @@ var WorkbookService = class WorkbookService extends SubmissionService {
|
|
|
26521
26930
|
previous = predecessor.attempt;
|
|
26522
26931
|
if (predecessor.learner.userId === request.actorUserId && !await service.questionIdentityVisible(request, previous, await service.identityRevision(request, previous))) throw new LearnerAuthorizationError();
|
|
26523
26932
|
}
|
|
26933
|
+
if (request.previousSubmissionId) {
|
|
26934
|
+
const current = await readWorkbookCompletion(service.db, {
|
|
26935
|
+
tenantId: request.tenantId,
|
|
26936
|
+
learnerId: request.learnerId,
|
|
26937
|
+
activityId: request.activityId
|
|
26938
|
+
});
|
|
26939
|
+
if (current.currentAttempt?.submissionId !== request.previousSubmissionId) {
|
|
26940
|
+
if (!(await (await SubmissionCollection.create({ db: service.db })).list({ where: {
|
|
26941
|
+
tenantId: request.tenantId,
|
|
26942
|
+
learnerId: request.learnerId,
|
|
26943
|
+
lessonId: row.lessonId,
|
|
26944
|
+
captureKey: request.requestKey
|
|
26945
|
+
} })).some((submission2) => current.attempts.some((attempt2) => attempt2.submissionId === submission2.id))) throw new WorkbookCompletionConflictError("stale_attempt");
|
|
26946
|
+
}
|
|
26947
|
+
}
|
|
26524
26948
|
const capture = {
|
|
26525
26949
|
...request,
|
|
26526
26950
|
enrollmentId: row.enrollmentId,
|
|
@@ -26563,7 +26987,11 @@ var WorkbookService = class WorkbookService extends SubmissionService {
|
|
|
26563
26987
|
policyVersion: workbook?.policyVersion ?? 1,
|
|
26564
26988
|
assistance,
|
|
26565
26989
|
actorUserId: request.actorUserId,
|
|
26566
|
-
capturedAt: submission.submittedAt,
|
|
26990
|
+
capturedAt: new Date(Math.max(new Date(submission.submittedAt).getTime(), ...(await attempts.list({ where: {
|
|
26991
|
+
tenantId: request.tenantId,
|
|
26992
|
+
learnerId: request.learnerId,
|
|
26993
|
+
activityId: request.activityId
|
|
26994
|
+
} })).map((prior2) => new Date(prior2.capturedAt).getTime() + 1))),
|
|
26567
26995
|
sourceHashes: JSON.stringify(sourceHashes)
|
|
26568
26996
|
});
|
|
26569
26997
|
return service.attemptView(request, row, attempt);
|
|
@@ -26875,6 +27303,57 @@ var WorkbookService = class WorkbookService extends SubmissionService {
|
|
|
26875
27303
|
return revisionView(result.row);
|
|
26876
27304
|
});
|
|
26877
27305
|
}
|
|
27306
|
+
async completeWorkbookActivity(request) {
|
|
27307
|
+
return this.composeMutation(async (service) => {
|
|
27308
|
+
await service.requireActor(request, "education.learner.complete");
|
|
27309
|
+
await service.serialize(request);
|
|
27310
|
+
const { row } = await service.activity(request, "education.learner.complete");
|
|
27311
|
+
nonempty(request.requestKey, "completion request key");
|
|
27312
|
+
nonempty(request.expectedAttemptId, "completion attempt");
|
|
27313
|
+
nonempty(request.submissionId, "completion submission");
|
|
27314
|
+
if (request.expectedHeadId !== null) nonempty(request.expectedHeadId, "completion feedback head");
|
|
27315
|
+
const decisions = await WorkbookCompletionDecisionCollection.create({ db: service.db });
|
|
27316
|
+
const prior = await decisions.get({
|
|
27317
|
+
tenantId: request.tenantId,
|
|
27318
|
+
activityId: request.activityId,
|
|
27319
|
+
requestKey: request.requestKey
|
|
27320
|
+
}, { cache: false });
|
|
27321
|
+
if (prior) {
|
|
27322
|
+
if (prior.learnerId !== request.learnerId || prior.actorUserId !== request.actorUserId || prior.attemptId !== request.expectedAttemptId || prior.submissionId !== request.submissionId || prior.feedbackHeadId !== request.expectedHeadId) throw new WorkbookCompletionConflictError("changed_retry");
|
|
27323
|
+
return completionDecisionView(prior);
|
|
27324
|
+
}
|
|
27325
|
+
const current = await readWorkbookCompletion(service.db, {
|
|
27326
|
+
tenantId: request.tenantId,
|
|
27327
|
+
learnerId: request.learnerId,
|
|
27328
|
+
activityId: request.activityId
|
|
27329
|
+
});
|
|
27330
|
+
if (!current.currentAttempt || current.currentAttempt.id !== request.expectedAttemptId || current.currentAttempt.submissionId !== request.submissionId) throw new WorkbookCompletionConflictError("stale_attempt");
|
|
27331
|
+
if (current.feedbackHeadId !== request.expectedHeadId) throw new WorkbookCompletionConflictError("stale_head");
|
|
27332
|
+
if (current.decision) throw new WorkbookCompletionConflictError("already_complete");
|
|
27333
|
+
const decision = await decisions.create({
|
|
27334
|
+
tenantId: request.tenantId,
|
|
27335
|
+
learnerId: request.learnerId,
|
|
27336
|
+
activityId: request.activityId,
|
|
27337
|
+
attemptId: request.expectedAttemptId,
|
|
27338
|
+
submissionId: request.submissionId,
|
|
27339
|
+
feedbackHeadId: request.expectedHeadId,
|
|
27340
|
+
actorUserId: request.actorUserId,
|
|
27341
|
+
requestKey: request.requestKey,
|
|
27342
|
+
_insertOnly: true
|
|
27343
|
+
});
|
|
27344
|
+
const progress = await (await LessonProgressCollection.create({ db: service.db })).get({
|
|
27345
|
+
tenantId: request.tenantId,
|
|
27346
|
+
learnerId: request.learnerId,
|
|
27347
|
+
enrollmentId: row.enrollmentId,
|
|
27348
|
+
lessonId: row.lessonId
|
|
27349
|
+
}, { cache: false });
|
|
27350
|
+
if (!progress) throw new LearnerAuthorizationError();
|
|
27351
|
+
progress.status = "complete";
|
|
27352
|
+
progress.completedAt = new Date(decision.recordedAt);
|
|
27353
|
+
await progress.save();
|
|
27354
|
+
return completionDecisionView(decision);
|
|
27355
|
+
});
|
|
27356
|
+
}
|
|
26878
27357
|
async releaseWorkbookFeedback(request) {
|
|
26879
27358
|
return this.composeMutation(async (service) => {
|
|
26880
27359
|
await service.requireActor(request, "education.learner.grade");
|
|
@@ -26958,6 +27437,11 @@ var WorkbookService = class WorkbookService extends SubmissionService {
|
|
|
26958
27437
|
async getWorkbookTimeline(request) {
|
|
26959
27438
|
const { row, workbook, learner } = await this.activity(request);
|
|
26960
27439
|
const own = learner.userId === request.actorUserId;
|
|
27440
|
+
const completion = await readWorkbookCompletion(this.db, {
|
|
27441
|
+
tenantId: request.tenantId,
|
|
27442
|
+
learnerId: request.learnerId,
|
|
27443
|
+
activityId: request.activityId
|
|
27444
|
+
});
|
|
26961
27445
|
const limit = request.limit ?? 25;
|
|
26962
27446
|
if (!Number.isSafeInteger(limit) || limit < 1 || limit > 100) throw new Error("Invalid timeline limit");
|
|
26963
27447
|
const all = await (await WorkbookAttemptCollection.create({ db: this.db })).list({
|
|
@@ -27014,10 +27498,22 @@ var WorkbookService = class WorkbookService extends SubmissionService {
|
|
|
27014
27498
|
actorUserId: d.actorUserId,
|
|
27015
27499
|
createdAt: d.recordedAt
|
|
27016
27500
|
})),
|
|
27017
|
-
headId: own ? null : headId ? String(headId) : null
|
|
27501
|
+
headId: own ? null : headId ? String(headId) : null,
|
|
27502
|
+
completionDecision: own ? null : (() => {
|
|
27503
|
+
const decision = completion.decisions.find((value) => value.attemptId === attempt.id);
|
|
27504
|
+
return decision ? completionDecisionView(decision) : null;
|
|
27505
|
+
})()
|
|
27018
27506
|
});
|
|
27019
27507
|
}
|
|
27020
27508
|
return {
|
|
27509
|
+
currentAttemptId: completion.currentAttempt ? String(completion.currentAttempt.id) : null,
|
|
27510
|
+
latestSubmissionId: completion.currentAttempt?.submissionId ?? null,
|
|
27511
|
+
completion: completion.completion,
|
|
27512
|
+
completionContext: own || !completion.currentAttempt ? null : {
|
|
27513
|
+
attemptId: String(completion.currentAttempt.id),
|
|
27514
|
+
submissionId: completion.currentAttempt.submissionId,
|
|
27515
|
+
expectedHeadId: completion.feedbackHeadId
|
|
27516
|
+
},
|
|
27021
27517
|
activity: await this.activityView(row, workbook),
|
|
27022
27518
|
attempts,
|
|
27023
27519
|
nextCursor: start + limit < all.length ? String(all[start + limit - 1].id) : null
|
|
@@ -27031,8 +27527,7 @@ var WorkbookService = class WorkbookService extends SubmissionService {
|
|
|
27031
27527
|
learnerId: request.learnerId,
|
|
27032
27528
|
activityId: request.activityId
|
|
27033
27529
|
} });
|
|
27034
|
-
const
|
|
27035
|
-
const independentSeen = /* @__PURE__ */ new Set();
|
|
27530
|
+
const evidence = [];
|
|
27036
27531
|
const ordered = [...attempts].sort((a, b) => Number(Boolean(a.previousAttemptId)) - Number(Boolean(b.previousAttemptId)) || String(a.id).localeCompare(String(b.id)));
|
|
27037
27532
|
for (const attempt of ordered) {
|
|
27038
27533
|
const revisions = await this.revisions(request, String(attempt.id));
|
|
@@ -27040,70 +27535,16 @@ var WorkbookService = class WorkbookService extends SubmissionService {
|
|
|
27040
27535
|
const effective = confirmed ?? revisions.filter((r) => r.kind === "ai").at(-1);
|
|
27041
27536
|
if (!effective) continue;
|
|
27042
27537
|
const assessment = revisionView(effective).assessment;
|
|
27043
|
-
|
|
27044
|
-
|
|
27045
|
-
|
|
27046
|
-
|
|
27047
|
-
|
|
27048
|
-
|
|
27049
|
-
version: assessment.vocabulary.version,
|
|
27050
|
-
conceptId,
|
|
27051
|
-
label: assessment.vocabulary.concepts.find((c) => c.id === conceptId).label,
|
|
27052
|
-
confirmed: {
|
|
27053
|
-
independent: 0,
|
|
27054
|
-
assisted: 0,
|
|
27055
|
-
unknown: 0,
|
|
27056
|
-
correct: 0,
|
|
27057
|
-
needsCorrection: 0,
|
|
27058
|
-
unassessed: 0
|
|
27059
|
-
},
|
|
27060
|
-
provisional: 0,
|
|
27061
|
-
episodes: [],
|
|
27062
|
-
revisionIds: [],
|
|
27063
|
-
cues: [],
|
|
27064
|
-
observations: []
|
|
27065
|
-
};
|
|
27066
|
-
summaries.set(key, summary);
|
|
27067
|
-
}
|
|
27068
|
-
if (!summary.episodes.includes(attempt.episodeId)) summary.episodes.push(attempt.episodeId);
|
|
27069
|
-
if (!summary.revisionIds.includes(String(effective.id))) summary.revisionIds.push(String(effective.id));
|
|
27070
|
-
const observationAssistance = attempt.previousAttemptId && attempt.assistance === "independent" ? "unknown" : attempt.assistance;
|
|
27071
|
-
summary.observations.push({
|
|
27072
|
-
submissionId: attempt.submissionId,
|
|
27073
|
-
revisionId: String(effective.id),
|
|
27074
|
-
questionId: q.id,
|
|
27075
|
-
episodeId: attempt.episodeId,
|
|
27076
|
-
result: q.result,
|
|
27077
|
-
assistance: observationAssistance,
|
|
27078
|
-
isCorrection: Boolean(attempt.previousAttemptId),
|
|
27079
|
-
capturedAt: attempt.capturedAt,
|
|
27080
|
-
confirmed: Boolean(confirmed)
|
|
27081
|
-
});
|
|
27082
|
-
if (!confirmed) {
|
|
27083
|
-
summary.provisional++;
|
|
27084
|
-
continue;
|
|
27085
|
-
}
|
|
27086
|
-
if (q.result === "unassessed") {
|
|
27087
|
-
summary.confirmed.unassessed++;
|
|
27088
|
-
continue;
|
|
27089
|
-
}
|
|
27090
|
-
const episodeQuestion = `${key}:${attempt.episodeId}:${q.id}`;
|
|
27091
|
-
const assistance = attempt.previousAttemptId && attempt.assistance === "independent" ? "unknown" : attempt.assistance;
|
|
27092
|
-
if (assistance !== "independent" || !independentSeen.has(episodeQuestion)) summary.confirmed[assistance]++;
|
|
27093
|
-
if (assistance === "independent") independentSeen.add(episodeQuestion);
|
|
27094
|
-
if (q.result === "correct") summary.confirmed.correct++;
|
|
27095
|
-
else summary.confirmed.needsCorrection++;
|
|
27096
|
-
if (attempt.previousAttemptId && q.result === "correct" && !summary.cues.includes("improving on this item")) summary.cues.push("improving on this item");
|
|
27097
|
-
}
|
|
27098
|
-
}
|
|
27099
|
-
for (const summary of summaries.values()) {
|
|
27100
|
-
if (!summary.confirmed.independent) summary.cues.push("needs a fresh independent check");
|
|
27101
|
-
if (summary.confirmed.needsCorrection) summary.cues.push("needs practice");
|
|
27102
|
-
if (!summary.confirmed.correct && !summary.confirmed.needsCorrection) summary.cues.push("not enough evidence");
|
|
27538
|
+
evidence.push({
|
|
27539
|
+
attempt,
|
|
27540
|
+
revisionId: String(effective.id),
|
|
27541
|
+
assessment,
|
|
27542
|
+
confirmed: Boolean(confirmed)
|
|
27543
|
+
});
|
|
27103
27544
|
}
|
|
27104
27545
|
return {
|
|
27105
27546
|
algorithmVersion: "workbook-descriptive-v1",
|
|
27106
|
-
concepts:
|
|
27547
|
+
concepts: summarizeWorkbookEvidence(evidence)
|
|
27107
27548
|
};
|
|
27108
27549
|
}
|
|
27109
27550
|
};
|
|
@@ -27600,6 +28041,6 @@ var WorkbookPhotoService = class WorkbookPhotoService extends WorkbookService {
|
|
|
27600
28041
|
}
|
|
27601
28042
|
};
|
|
27602
28043
|
//#endregion
|
|
27603
|
-
export {
|
|
28044
|
+
export { FamilyIntakeDecision as $, WorkbookFeedbackDelivery as A, SubmissionAsset as At, validateWorkbookAssessment as B, Exercise as Bt, WorkbookActivity as C, VideoCollection as Ct, WorkbookAttempt as D, Grade as Dt, WorkbookAssessmentRevisionCollection as E, ExternalCompletion as Et, WorkbookWorkFilingCollection as F, Learner as Ft, GroupSharingConflictError as G, Worksheet as Gt, evaluateGroupSharingPolicy as H, Lesson as Ht, WORKBOOK_MATH_VOCABULARY as I, LessonProgress as It, validateGroupSharingPolicy as J, GroupSharingPolicyValidationError as K, WorkbookAssessmentValidationError as L, AuthoredCourse as Lt, WorkbookFeedbackRelease as M, LessonAsset as Mt, WorkbookFeedbackReleaseCollection as N, Curriculum as Nt, WorkbookAttemptCollection as O, ScannedSubmission as Ot, WorkbookWorkFiling as P, Enrollment as Pt, FamilyIntakeCollection as Q, WorkbookCompletionConflictError as R, Course as Rt, Workbook as S, SubmissionIntakeBindingCollection as St, WorkbookAssessmentRevision as T, Attestation as Tt, summarizeWorkbookEvidence as U, Reading as Ut, workbookAggregateFeedback as V, ExternalCourse as Vt, GroupSharingAuthorizationError as W, Video as Wt, FamilyIntakeAsset as X, FamilyIntake as Y, FamilyIntakeAssetCollection as Z, WorkbookWorkflowRequiredError as _, LessonProgressCollection as _t, WorkbookContextRevisionCollection as a, AuthoredCourseCollection as at, WorkbookCompletionDecision as b, SubmissionAssetCollection as bt, WorkbookPhotoDecision as c, CurriculumCollection as ct, WorkbookPhotoIntakeCollection as d, ExternalCompletionCollection as dt, FamilyIntakeDecisionCollection as et, validateWorkbookPhotoIdentification as f, ExternalCourseCollection as ft, SubmissionStorageCleanupError as g, LessonCollection as gt, SubmissionService as h, LessonAssetCollection as ht, WorkbookContextRevision as i, AttestationCollection as it, WorkbookFeedbackDeliveryCollection as j, SubmissionIntakeBinding as jt, WorkbookCollection as k, Submission as kt, WorkbookPhotoDecisionCollection as l, EnrollmentCollection as lt, normalizeWorkbookAnswerRegions as m, LearnerCollection as mt, preservePhotoProposal as n, CatalogAuthorizationError as nt, WorkbookPhotoAsset as o, CourseCollection as ot, normalizeWorkbookObservedLayout as p, GradeCollection as pt, canonicalGroupSharingPolicy as q, WorkbookService as r, CatalogService as rt, WorkbookPhotoAssetCollection as s, CourseSectionCollection as st, WorkbookPhotoService as t, familyIntakeScopeId as tt, WorkbookPhotoIntake as u, ExerciseCollection as ut, LearnerAuthorizationError as v, ReadingCollection as vt, WorkbookActivityCollection as w, WorksheetCollection as wt, WorkbookCompletionDecisionCollection as x, SubmissionCollection as xt, LearnerService as y, ScannedSubmissionCollection as yt, aggregateWorkbookQuestions as z, CourseSection as zt };
|
|
27604
28045
|
|
|
27605
|
-
//# sourceMappingURL=workbook-photo-service-
|
|
28046
|
+
//# sourceMappingURL=workbook-photo-service-C6mbUUp6.js.map
|