@happyvertical/smrt-education 0.59.1 → 0.60.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 (43) hide show
  1. package/AGENTS.md +3 -1
  2. package/README.md +7 -2
  3. package/agents/class-crunchlabs.md +8 -4
  4. package/agents/course-bundle-import.md +89 -10
  5. package/agents/lesson-materials.md +21 -4
  6. package/dist/chunks/course-authoring-contracts-C4Hqba-e.js.map +1 -1
  7. package/dist/chunks/{course-bundle-zip-5KUe3C5H.js → course-bundle-zip-CGR1Ci0Z.js} +3 -2
  8. package/dist/chunks/course-bundle-zip-CGR1Ci0Z.js.map +1 -0
  9. package/dist/chunks/{workbook-photo-service-CjcB0y8Y.js → workbook-photo-service-DHP5ja82.js} +103 -46
  10. package/dist/chunks/workbook-photo-service-DHP5ja82.js.map +1 -0
  11. package/dist/course-authoring-contracts.d.ts +1 -1
  12. package/dist/course-authoring-contracts.d.ts.map +1 -1
  13. package/dist/course-bundle-contracts.d.ts +2 -0
  14. package/dist/course-bundle-contracts.d.ts.map +1 -1
  15. package/dist/course-bundle-manifest-v2.d.ts +24 -1
  16. package/dist/course-bundle-manifest-v2.d.ts.map +1 -1
  17. package/dist/course-bundle-models.d.ts +88 -0
  18. package/dist/course-bundle-models.d.ts.map +1 -1
  19. package/dist/course-bundle-service.d.ts +153 -7
  20. package/dist/course-bundle-service.d.ts.map +1 -1
  21. package/dist/course-bundle.d.ts +17 -0
  22. package/dist/course-bundle.d.ts.map +1 -1
  23. package/dist/document-converter.d.ts +8 -0
  24. package/dist/document-converter.d.ts.map +1 -1
  25. package/dist/hearth-class-crunchlabs.d.ts +3 -2
  26. package/dist/hearth-class-crunchlabs.d.ts.map +1 -1
  27. package/dist/index.d.ts +2 -2
  28. package/dist/index.d.ts.map +1 -1
  29. package/dist/index.js +844 -133
  30. package/dist/index.js.map +1 -1
  31. package/dist/ingestion.js +1 -1
  32. package/dist/lesson-assets.d.ts +19 -0
  33. package/dist/lesson-assets.d.ts.map +1 -1
  34. package/dist/manifest.json +1803 -145
  35. package/dist/node.js +1 -1
  36. package/dist/smrt-knowledge.json +571 -15
  37. package/dist/sources/class-crunchlabs.d.ts +7 -0
  38. package/dist/sources/class-crunchlabs.d.ts.map +1 -1
  39. package/dist/submission-service.d.ts +24 -4
  40. package/dist/submission-service.d.ts.map +1 -1
  41. package/package.json +8 -8
  42. package/dist/chunks/course-bundle-zip-5KUe3C5H.js.map +0 -1
  43. package/dist/chunks/workbook-photo-service-CjcB0y8Y.js.map +0 -1
@@ -636,10 +636,28 @@ function materialAudience(relationship, audience) {
636
636
  if (effective === "learner" && GUARDIAN_ONLY_RELATIONSHIPS.has(role)) throw new Error("Keys and assessment guidance are guardian-only");
637
637
  return effective;
638
638
  }
639
- async function requirePrivateAsset(row) {
640
- const asset = await (await AssetCollection.create({ db: row.db })).get(row.assetId, { cache: false });
639
+ var MATERIAL_RENDITIONS = ["original", "rendered"];
640
+ async function requirePrivateAsset(row, assetId = row.assetId) {
641
+ const asset = await (await AssetCollection.create({ db: row.db })).get(assetId, { cache: false });
641
642
  if (!row.tenantId || !asset || asset.tenantId !== row.tenantId || asset.accessMode !== "private" || !asset.ownerProfileId) throw new Error("Private lesson material requires an authorized private asset");
642
643
  }
644
+ async function checkRendition(row, privateOnly) {
645
+ if (row.rendition !== "" && !MATERIAL_RENDITIONS.includes(row.rendition)) throw new Error("Invalid material rendition");
646
+ if (row.rendition === "original" && materialAudience(row.relationship, row.audience) !== "guardian") throw new Error("An editable original is guardian-only material");
647
+ if (row.renditionOfAssetId && (row.rendition !== "rendered" || row.renditionOfAssetId === row.assetId)) throw new Error("Only a rendering names the original it came from");
648
+ if (!row.thumbnailAssetId) return;
649
+ const prior = row.id ? await row.db.get(row.tableName, {
650
+ id: row.id,
651
+ tenant_id: row.tenantId
652
+ }) : null;
653
+ if (prior && prior.thumbnail_asset_id === row.thumbnailAssetId) return;
654
+ if (row.thumbnailAssetId === row.assetId) throw new Error("A thumbnail is a separate image asset");
655
+ if (privateOnly) await requirePrivateAsset(row, row.thumbnailAssetId);
656
+ else if (!row.tenantId || !await row.db.get("assets", {
657
+ id: row.thumbnailAssetId,
658
+ tenant_id: row.tenantId
659
+ })) throw new Error("A material thumbnail must be an asset of the same family");
660
+ }
643
661
  async function courseOf(row, courseId) {
644
662
  const course = await row.db.get("courses", {
645
663
  id: courseId,
@@ -656,6 +674,10 @@ var LessonAsset = class extends SmrtObject {
656
674
  sortOrder = 0;
657
675
  /** '' reads as the role default (`materialAudience`). */
658
676
  audience = "";
677
+ /** `original` / `rendered` for a Word/PowerPoint material, '' for a file as supplied. */
678
+ rendition = "";
679
+ renditionOfAssetId = null;
680
+ thumbnailAssetId = null;
659
681
  constructor(options = {}) {
660
682
  super(options);
661
683
  for (const [key, value] of Object.entries(options)) if (Object.hasOwn(this, key)) this[key] = value;
@@ -674,7 +696,9 @@ var LessonAsset = class extends SmrtObject {
674
696
  });
675
697
  if (!section) throw new Error("education asset course does not exist");
676
698
  const course = await courseOf(this, String(section.course_id));
677
- if (GUARDIAN_ONLY_RELATIONSHIPS.has(this.relationship) || course.license_kind === "personal-use-copy") await requirePrivateAsset(this);
699
+ const privateOnly = GUARDIAN_ONLY_RELATIONSHIPS.has(this.relationship) || course.license_kind === "personal-use-copy";
700
+ if (privateOnly) await requirePrivateAsset(this);
701
+ await checkRendition(this, privateOnly);
678
702
  return await super.save(options);
679
703
  }
680
704
  };
@@ -683,6 +707,8 @@ __decorateClass$10([tenantId({ nullable: true })], LessonAsset.prototype, "tenan
683
707
  __decorateClass$10([foreignKey("Lesson", { required: true })], LessonAsset.prototype, "lessonId", 2);
684
708
  __decorateClass$10([crossPackageRef("@happyvertical/smrt-assets:Asset", { required: true })], LessonAsset.prototype, "assetId", 2);
685
709
  __decorateClass$10([field({ required: true })], LessonAsset.prototype, "relationship", 2);
710
+ __decorateClass$10([crossPackageRef("@happyvertical/smrt-assets:Asset", { nullable: true })], LessonAsset.prototype, "renditionOfAssetId", 2);
711
+ __decorateClass$10([crossPackageRef("@happyvertical/smrt-assets:Asset", { nullable: true })], LessonAsset.prototype, "thumbnailAssetId", 2);
686
712
  LessonAsset = __decorateClass$10([TenantScoped({ mode: "optional" }), smrt({
687
713
  tableName: "lesson_assets",
688
714
  conflictColumns: [
@@ -703,6 +729,10 @@ var CourseAsset = class extends SmrtObject {
703
729
  audience = "";
704
730
  title = "";
705
731
  sortOrder = 0;
732
+ /** `original` / `rendered` for a Word/PowerPoint material, '' for a file as supplied. */
733
+ rendition = "";
734
+ renditionOfAssetId = null;
735
+ thumbnailAssetId = null;
706
736
  constructor(options = {}) {
707
737
  super(options);
708
738
  for (const [key, value] of Object.entries(options)) if (Object.hasOwn(this, key)) this[key] = value;
@@ -711,7 +741,9 @@ var CourseAsset = class extends SmrtObject {
711
741
  materialAudience(this.relationship, this.audience);
712
742
  if (typeof this.title !== "string" || this.title.length > 200) throw new Error("Invalid course material title");
713
743
  const course = await courseOf(this, this.courseId);
714
- if (GUARDIAN_ONLY_RELATIONSHIPS.has(this.relationship) || course.license_kind === "personal-use-copy") await requirePrivateAsset(this);
744
+ const privateOnly = GUARDIAN_ONLY_RELATIONSHIPS.has(this.relationship) || course.license_kind === "personal-use-copy";
745
+ if (privateOnly) await requirePrivateAsset(this);
746
+ await checkRendition(this, privateOnly);
715
747
  return await super.save(options);
716
748
  }
717
749
  };
@@ -720,6 +752,8 @@ __decorateClass$10([tenantId({ nullable: true })], CourseAsset.prototype, "tenan
720
752
  __decorateClass$10([foreignKey("Course", { required: true })], CourseAsset.prototype, "courseId", 2);
721
753
  __decorateClass$10([crossPackageRef("@happyvertical/smrt-assets:Asset", { required: true })], CourseAsset.prototype, "assetId", 2);
722
754
  __decorateClass$10([field({ required: true })], CourseAsset.prototype, "relationship", 2);
755
+ __decorateClass$10([crossPackageRef("@happyvertical/smrt-assets:Asset", { nullable: true })], CourseAsset.prototype, "renditionOfAssetId", 2);
756
+ __decorateClass$10([crossPackageRef("@happyvertical/smrt-assets:Asset", { nullable: true })], CourseAsset.prototype, "thumbnailAssetId", 2);
723
757
  CourseAsset = __decorateClass$10([TenantScoped({ mode: "optional" }), smrt({
724
758
  tableName: "course_assets",
725
759
  conflictColumns: [
@@ -32397,6 +32431,20 @@ var ExternalVideoReferenceError = class extends LearnerValidationError {
32397
32431
  this.name = "ExternalVideoReferenceError";
32398
32432
  }
32399
32433
  };
32434
+ function pairRenditions(rows, views) {
32435
+ const out = views.map((v) => ({ ...v }));
32436
+ rows.forEach((row, i) => {
32437
+ const of = row.rendition_of_asset_id;
32438
+ if (row.rendition !== "rendered" || !of) return;
32439
+ const j = rows.findIndex((r) => r.rendition === "original" && r.asset_id === of && r.relationship === row.relationship);
32440
+ const a = out[i];
32441
+ const b = out[j];
32442
+ if (j < 0 || !a || !b) return;
32443
+ a.pairedMaterialId = b.id;
32444
+ b.pairedMaterialId = a.id;
32445
+ });
32446
+ return out;
32447
+ }
32400
32448
  function submissionPageKey(pageKey, sortOrder) {
32401
32449
  return pageKey || `p${sortOrder + 1}`;
32402
32450
  }
@@ -33216,9 +33264,32 @@ var SubmissionService = class SubmissionService extends LearnerService {
33216
33264
  visibleTo(learnerOnly, relationship, audience) {
33217
33265
  return !learnerOnly || materialAudience(relationship, audience) === "learner";
33218
33266
  }
33219
- async materialName(assetId) {
33267
+ async materialAsset(assetId) {
33220
33268
  const asset = await this.db.get("assets", { id: assetId });
33221
- return String(asset?.name ?? "");
33269
+ return {
33270
+ name: String(asset?.name ?? ""),
33271
+ mimeType: asset?.mime_type ? String(asset.mime_type) : null
33272
+ };
33273
+ }
33274
+ async fileView(row, scope) {
33275
+ const asset = await this.materialAsset(String(row.asset_id));
33276
+ return {
33277
+ id: String(row.id),
33278
+ kind: "file",
33279
+ scope,
33280
+ relationship: row.relationship,
33281
+ audience: materialAudience(String(row.relationship), String(row.audience ?? "")),
33282
+ title: scope === "course" && String(row.title ?? "") || asset.name,
33283
+ order: Number(row.sort_order) || 0,
33284
+ assetId: String(row.asset_id),
33285
+ provider: null,
33286
+ videoId: null,
33287
+ embedUrl: null,
33288
+ mimeType: asset.mimeType,
33289
+ rendition: row.rendition === "original" || row.rendition === "rendered" ? row.rendition : null,
33290
+ pairedMaterialId: null,
33291
+ thumbnailAssetId: row.thumbnail_asset_id ? String(row.thumbnail_asset_id) : null
33292
+ };
33222
33293
  }
33223
33294
  /**
33224
33295
  * A lesson's materials for this actor: files by role and audience, then
@@ -33234,20 +33305,9 @@ var SubmissionService = class SubmissionService extends LearnerService {
33234
33305
  const learnerOnly = await this.learnerAudienceOnly(request);
33235
33306
  const files = (await this.db.list("lesson_assets", { lesson_id: request.lessonId })).filter((row) => (row.tenant_id ?? null) === tenant && this.visibleTo(learnerOnly, String(row.relationship), String(row.audience ?? ""))).sort((a, b) => Number(a.sort_order) - Number(b.sort_order) || String(a.id).localeCompare(String(b.id)));
33236
33307
  const videos = await this.db.tableExists("lesson_external_videos") ? (await this.db.list("lesson_external_videos", { lesson_id: request.lessonId })).filter((row) => (row.tenant_id ?? null) === tenant && this.visibleTo(learnerOnly, "video", String(row.audience ?? ""))).sort((a, b) => Number(a.step_order) - Number(b.step_order) || String(a.id).localeCompare(String(b.id))) : [];
33237
- const result = [];
33238
- for (const row of files) result.push({
33239
- id: String(row.id),
33240
- kind: "file",
33241
- scope: "lesson",
33242
- relationship: row.relationship,
33243
- audience: materialAudience(String(row.relationship), String(row.audience ?? "")),
33244
- title: await this.materialName(String(row.asset_id)),
33245
- order: Number(row.sort_order) || 0,
33246
- assetId: String(row.asset_id),
33247
- provider: null,
33248
- videoId: null,
33249
- embedUrl: null
33250
- });
33308
+ const fileViews = [];
33309
+ for (const row of files) fileViews.push(await this.fileView(row, "lesson"));
33310
+ const result = pairRenditions(files, fileViews);
33251
33311
  for (const row of videos) result.push({
33252
33312
  id: String(row.id),
33253
33313
  kind: "external-video",
@@ -33259,7 +33319,11 @@ var SubmissionService = class SubmissionService extends LearnerService {
33259
33319
  assetId: null,
33260
33320
  provider: row.provider,
33261
33321
  videoId: String(row.video_id),
33262
- embedUrl: externalVideoEmbedUrl(row.provider, String(row.video_id))
33322
+ embedUrl: externalVideoEmbedUrl(row.provider, String(row.video_id)),
33323
+ mimeType: null,
33324
+ rendition: null,
33325
+ pairedMaterialId: null,
33326
+ thumbnailAssetId: null
33263
33327
  });
33264
33328
  return result;
33265
33329
  }
@@ -33271,21 +33335,9 @@ var SubmissionService = class SubmissionService extends LearnerService {
33271
33335
  if (!course) throw new LearnerAuthorizationError();
33272
33336
  const learnerOnly = await this.learnerAudienceOnly(request);
33273
33337
  const rows = (await this.db.list("course_assets", { course_id: enrollment.courseId })).filter((row) => (row.tenant_id ?? null) === (course.tenant_id ?? null) && this.visibleTo(learnerOnly, String(row.relationship), String(row.audience ?? ""))).sort((a, b) => Number(a.sort_order) - Number(b.sort_order) || String(a.id).localeCompare(String(b.id)));
33274
- const result = [];
33275
- for (const row of rows) result.push({
33276
- id: String(row.id),
33277
- kind: "file",
33278
- scope: "course",
33279
- relationship: row.relationship,
33280
- audience: materialAudience(String(row.relationship), String(row.audience ?? "")),
33281
- title: String(row.title ?? "") || await this.materialName(String(row.asset_id)),
33282
- order: Number(row.sort_order) || 0,
33283
- assetId: String(row.asset_id),
33284
- provider: null,
33285
- videoId: null,
33286
- embedUrl: null
33287
- });
33288
- return result;
33338
+ const views = [];
33339
+ for (const row of rows) views.push(await this.fileView(row, "course"));
33340
+ return pairRenditions(rows, views);
33289
33341
  }
33290
33342
  async signMaterial(request, scope, assetId) {
33291
33343
  if (!this.options.signAsset) throw new LearnerAuthorizationError();
@@ -33303,18 +33355,23 @@ var SubmissionService = class SubmissionService extends LearnerService {
33303
33355
  expiresAt
33304
33356
  };
33305
33357
  }
33306
- /** Sign one lesson file the actor may see (learners: learner audience only). */
33358
+ /**
33359
+ * Sign one lesson file the actor may see (learners: learner audience only),
33360
+ * or its recorded thumbnail with `thumbnail: true`.
33361
+ */
33307
33362
  async signLessonMaterial(request) {
33308
33363
  const material = (await this.listLessonMaterials(request)).find((m) => m.kind === "file" && m.id === request.materialId);
33309
- if (!material?.assetId) throw new LearnerAuthorizationError();
33310
- return this.signMaterial(request, `lesson:${request.lessonId}`, material.assetId);
33364
+ const assetId = request.thumbnail ? material?.thumbnailAssetId : material?.assetId;
33365
+ if (!assetId) throw new LearnerAuthorizationError();
33366
+ return this.signMaterial(request, `lesson:${request.lessonId}`, assetId);
33311
33367
  }
33312
- /** Sign one course-level file the actor may see. */
33368
+ /** Sign one course-level file the actor may see, or its thumbnail. */
33313
33369
  async signCourseMaterial(request) {
33314
33370
  const enrollment = await this.requireEnrollment(request, "education.learner.read");
33315
33371
  const material = (await this.listCourseMaterials(request)).find((m) => m.id === request.materialId);
33316
- if (!material?.assetId) throw new LearnerAuthorizationError();
33317
- return this.signMaterial(request, `course:${enrollment.courseId}`, material.assetId);
33372
+ const assetId = request.thumbnail ? material?.thumbnailAssetId : material?.assetId;
33373
+ if (!assetId) throw new LearnerAuthorizationError();
33374
+ return this.signMaterial(request, `course:${enrollment.courseId}`, assetId);
33318
33375
  }
33319
33376
  /** Re-save a family material join under the exact private-asset capability. */
33320
33377
  async saveFamilyMaterial(request, assetId, save) {
@@ -33358,7 +33415,7 @@ var SubmissionService = class SubmissionService extends LearnerService {
33358
33415
  courseId: enrollment.courseId
33359
33416
  }, { cache: false });
33360
33417
  if (!row2) throw new LearnerAuthorizationError();
33361
- if (materialAudience(row2.relationship, request.audience) !== request.audience) throw new LearnerValidationError("Invalid material audience");
33418
+ if (materialAudience(row2.relationship, request.audience) !== request.audience || row2.rendition === "original" && request.audience !== "guardian") throw new LearnerValidationError("Invalid material audience");
33362
33419
  row2.audience = request.audience;
33363
33420
  await service.saveFamilyMaterial(request, row2.assetId, () => row2.save());
33364
33421
  const view2 = (await service.listCourseMaterials(request)).find((m) => m.id === request.materialId);
@@ -33382,7 +33439,7 @@ var SubmissionService = class SubmissionService extends LearnerService {
33382
33439
  tenantId: request.tenantId
33383
33440
  }, { cache: false });
33384
33441
  if (!row) throw new LearnerAuthorizationError();
33385
- if (materialAudience("relationship" in row ? row.relationship : "video", request.audience) !== request.audience) throw new LearnerValidationError("Invalid material audience");
33442
+ if (materialAudience("relationship" in row ? row.relationship : "video", request.audience) !== request.audience || "rendition" in row && row.rendition === "original" && request.audience !== "guardian") throw new LearnerValidationError("Invalid material audience");
33386
33443
  row.audience = request.audience;
33387
33444
  if ("assetId" in row) await service.saveFamilyMaterial(request, row.assetId, () => row.save());
33388
33445
  else await row.save();
@@ -36881,6 +36938,6 @@ var WorkbookPhotoService = class WorkbookPhotoService extends LessonWorkService
36881
36938
  }
36882
36939
  };
36883
36940
  //#endregion
36884
- export { LessonAlreadyCompleteError as $, Enrollment as $i, QUESTION_COMPLETION_MODES as $n, ReleasedLesson as $r, WorkFeedbackRelease as $t, QUESTION_EXTRACTION_VERSION as A, Attestation as Ai, QuestionRevision as An, CourseCoverChangeCollection as Ar, WorkbookPhotoDecision as At, SELF_ATTESTABLE_LESSON_KINDS as B, CourseAsset as Bi, normalizeQuestionContent as Bn, CourseUpgradeChoiceCollection as Br, WorkCompletionDecision as Bt, MAX_EXTRACTED_OMISSIONS as C, ReadingCollection as Ci, LearningObjectiveCollection as Cn, MAX_REFUSAL_EXPLANATION_LENGTH as Cr, canonicalGroupSharingPolicy as Ct, MAX_EXTRACTED_STUDENT_WORK as D, SubmissionIntakeBindingCollection as Di, QuestionCollection as Dn, CourseArchiveDecision as Dr, BookContextRevisionCollection as Dt, MAX_EXTRACTED_SECTIONS as E, SubmissionCollection as Ei, Question as En, readDelegation as Er, BookContextRevision as Et, normalizeWorkObservedLayout as F, Submission as Fi, resolveEnrollmentLessons as Fn, CourseRelease as Fr, FamilyIntakeAsset as Ft, EnrollmentNotActiveError as G, LESSON_ASSET_RELATIONSHIPS as Gi, MAX_PRINTABLE_ITEMS as Gn, EnrollmentAssignmentRecord as Gr, LessonWorkFiling as Gt, SubmissionStorageCleanupError as H, EXTERNAL_VIDEO_PROVIDERS as Hi, GENERATED_PRINTABLE_RELATIONSHIPS as Hn, CourseVisibilityChangeCollection as Hr, readWorkCompletion as Ht, normalizeWorkAnswerRegions as I, SubmissionAsset as Ii, applyProposalFields as In, CourseReleaseCollection as Ir, FamilyIntakeAssetCollection as It, InterestThemeError as J, LessonExternalVideoCollection as Ji, MAX_PRINTABLE_TOTAL_TEXT as Jn, EnrollmentAutoUpgradeSkipCollection as Jr, WorkAssessmentRevisionCollection as Jt, EnrollmentPaceError as K, LessonAsset as Ki, MAX_PRINTABLE_PAGES as Kn, EnrollmentAssignmentRecordCollection as Kr, LessonWorkFilingCollection as Kt, LessonWorkWorkflowRequiredError as L, SubmissionIntakeBinding as Li, draftFromRevision as Ln, CourseRevision as Lr, FamilyIntakeCollection as Lt, QuestionExtractionPendingError as M, Grade as Mi, CourseAuthoringService as Mn, CourseDiscardTombstoneCollection as Mr, WorkbookPhotoIntake as Mt, QuestionExtractionValidationError as N, LessonSelfAttestation as Ni, authoredVisibilityPermitsGroups as Nn, CourseDraftHead as Nr, WorkbookPhotoIntakeCollection as Nt, MAX_EXTRACTED_TEXT as O, VideoCollection as Oi, QuestionResponse as On, CourseArchiveDecisionCollection as Or, WorkbookPhotoAsset as Ot, LessonWorkService as P, ScannedSubmission as Pi, effectiveCourseVisibility as Pn, CourseDraftHeadCollection as Pr, FamilyIntake as Pt, LearnerValidationError as Q, Curriculum as Qi, PrintableStorageNotConfiguredError as Qn, LessonRevisionCollection as Qr, WorkFeedbackDeliveryCollection as Qt, OwnAttestationConflictError as R, parseQuestionRubric as Ri, planProposal as Rn, CourseRevisionCollection as Rr, FamilyIntakeDecision as Rt, MAX_EXTRACTED_ANCHORS as S, LessonSelfAttestationCollection as Si, LearningObjective as Sn, MAX_REFUSAL_CATEGORY_LENGTH as Sr, GroupSharingPolicyValidationError as St, MAX_EXTRACTED_QUESTIONS as T, SubmissionAssetCollection as Ti, LearningObjectiveRevisionCollection as Tn, delegationRecordFields as Tr, familyIntakeScopeId as Tt, submissionPageKey as U, GUARDIAN_ONLY_RELATIONSHIPS as Ui, LearningObjectiveKeyConflictError as Un, CurriculumCreationRecord as Ur, LessonActivity as Ut, SubmissionService as V, CourseAssetCollection as Vi, GENERATED_PRINTABLE_AUDIENCES as Vn, CourseVisibilityChange as Vr, WorkCompletionDecisionCollection as Vt, ENROLLMENT_STATUS_TRANSITIONS as W, LESSON_ASSET_DEFAULT_AUDIENCE as Wi, LearningObjectiveNotFoundError as Wn, CurriculumCreationRecordCollection as Wr, LessonActivityCollection as Wt, LearnerHistoryUnavailableError as X, materialAudience as Xi, PrintableOwnerError as Xn, EnrollmentReleasePinCollection as Xr, WorkAttemptCollection as Xt, LearnerAuthorizationError as Y, externalVideoEmbedUrl as Yi, MAX_RESOLVE_QUESTION_REVISIONS as Yn, EnrollmentReleasePin as Yr, WorkAttempt as Yt, LearnerService as Z, parseYouTubeReference as Zi, PrintableStorageCleanupError as Zn, LessonRevision as Zr, WorkFeedbackDelivery as Zt, EXTRACTED_OMISSION_REASONS as _, GradeCollection as _i, renderGuardianWorksheetPdf as _n, CourseProposalFieldError as _r, LessonProgressTransitionCollection as _t, questionExtractionProposalDigest as a, parseInterestTheme as aa, mostRestrictiveLicense as ai, aggregateWorkQuestions as an, QuestionReferenceError as ar, MIN_LESSONS_PER_WEEK as at, EXTRACTED_QUESTION_STATUSES as b, LessonCollection as bi, GeneratedPrintable as bn, MAX_GENERATION_GRADE as br, GroupSharingAuthorizationError as bt, QuestionExtractionRecord as c, Course as ca, AttestationCollection as ci, LessonPage as cn, COURSE_GENERATION_STATUSES as cr, EnrollmentPaceChange as ct, extractedQuestionContent as d, ExternalCourse as da, CourseSectionCollection as di, validLessonPageKey as dn, CourseGenerationBriefError as dr, EnrollmentStatusChangeCollection as dt, Learner as ea, ReleasedLessonCollection as ei, WorkFeedbackReleaseCollection as en, QUESTION_FIELDS as er, LessonPutBackError as et, matchExtractedQuestions as f, Lesson as fa, CurriculumCollection as fi, QuestionAuthoringService as fn, CourseGenerationInProgressError as fr, LearnerInterestThemeChange as ft, EXTRACTED_MEDIA_KINDS as g, ExternalCourseCollection as gi, worksheetVersionId as gn, CourseGeneratorNotConfiguredError as gr, LessonProgressTransition as gt, EXTRACTED_LEGIBILITY as h, Worksheet as ha, ExternalCompletionCollection as hi, canonical$2 as hn, CourseGenerationRefusal as hr, LessonCompletionRecordCollection as ht, QuestionExtractionService as i, interestThemeFromColumns as ia, isGroupShareableLicense as ii, WorkCompletionConflictError as in, QuestionNotFoundError as ir, MAX_NEXT_LESSONS_COUNT as it, QuestionExtractionNotFoundError as j, ExternalCompletion as ji, QuestionRevisionCollection as jn, CourseDiscardTombstone as jr, WorkbookPhotoDecisionCollection as jt, QUESTION_EXTRACTION_SOURCE_KINDS as k, WorksheetCollection as ki, QuestionResponseCollection as kn, CourseCoverChange as kr, WorkbookPhotoAssetCollection as kt, QuestionExtractionRecordCollection as l, CourseSection as la, AuthoredCourseCollection as li, LessonPageCollection as ln, COURSE_GENERATION_TARGETS as lr, EnrollmentPaceChangeCollection as lt, questionExtractionSourceIdentity as m, Video as ma, ExerciseCollection as mi, buildLearnerWorksheet as mn, CourseGenerationOutputError as mr, LessonCompletionRecord as mt, preservePhotoProposal as n, MAX_INTEREST_THEME_KEY_CHARS as na, AUTHORED_RELEASE_SOURCE_KEY as ni, WORK_MATH_VOCABULARY as nn, QUESTION_PROVENANCES as nr, LessonWorkOwnedError as nt, ExtractedQuestionLink as o, AuthoredCourse as oa, CatalogAuthorizationError as oi, validateWorkAssessment as on, WorksheetVersionMismatchError as or, enrollmentView as ot, normalizeQuestionExtraction as p, Reading as pa, EnrollmentCollection as pi, buildGuardianWorksheet as pn, CourseGenerationNotFoundError as pr, LearnerInterestThemeChangeCollection as pt, EnrollmentStatusTransitionError as q, LessonExternalVideo as qi, MAX_PRINTABLE_TEXT_LENGTH as qn, EnrollmentAutoUpgradeSkip as qr, WorkAssessmentRevision as qt, validateWorkbookPhotoIdentification as r, MAX_INTEREST_THEME_LABEL_CHARS as ra, isAuthoredReleaseGroupShareable as ri, WorkAssessmentValidationError as rn, QUESTION_RESPONSE_TYPES as rr, MAX_LESSONS_PER_WEEK as rt, ExtractedQuestionLinkCollection as s, COURSE_VISIBILITIES as sa, CatalogService as si, workAggregateFeedback as sn, groupSharingDigest as sr, requirePolicyBasis as st, WorkbookPhotoService as t, LessonProgress as ta, AUTHORED_IDENTITY_SOURCE_KEY as ti, LessonWorkPlacementError as tn, QUESTION_PROMPT_SUMMARY_LENGTH as tr, LessonSkippedError as tt, QUESTION_EXTRACTION_ARGS_SCHEMA as u, Exercise as ua, CourseCollection as ui, lessonPageView as un, COURSE_GENERATION_TERMINAL as ur, EnrollmentStatusChange as ut, EXTRACTED_ORIGINS as v, LearnerCollection as vi, renderLearnerWorksheetPdf as vn, CourseProposalNotFoundError as vr, evaluateGroupSharingPolicy as vt, MAX_EXTRACTED_PAGES as w, ScannedSubmissionCollection as wi, LearningObjectiveRevision as wn, delegationActorFields as wr, validateGroupSharingPolicy as wt, EXTRACTED_READABILITY as x, LessonProgressCollection as xi, GeneratedPrintableCollection as xn, MAX_GENERATION_OBJECTIVE_CHARS as xr, GroupSharingConflictError as xt, EXTRACTED_PAGE_ROLES as y, LessonAssetCollection as yi, es_exports as yn, MAX_GENERATION_BRIEF_FIELD_CHARS as yr, summarizeWorkEvidence as yt, OwnAttestationLessonKindError as z, validateRubricResults as zi, validateCourseGenerationOutput as zn, CourseUpgradeChoice as zr, FamilyIntakeDecisionCollection as zt };
36941
+ export { LessonAlreadyCompleteError as $, Curriculum as $i, QUESTION_COMPLETION_MODES as $n, ReleasedLesson as $r, WorkFeedbackRelease as $t, QUESTION_EXTRACTION_VERSION as A, Attestation as Ai, QuestionRevision as An, CourseCoverChangeCollection as Ar, WorkbookPhotoDecision as At, SELF_ATTESTABLE_LESSON_KINDS as B, CourseAsset as Bi, normalizeQuestionContent as Bn, CourseUpgradeChoiceCollection as Br, WorkCompletionDecision as Bt, MAX_EXTRACTED_OMISSIONS as C, ReadingCollection as Ci, LearningObjectiveCollection as Cn, MAX_REFUSAL_EXPLANATION_LENGTH as Cr, canonicalGroupSharingPolicy as Ct, MAX_EXTRACTED_STUDENT_WORK as D, SubmissionIntakeBindingCollection as Di, QuestionCollection as Dn, CourseArchiveDecision as Dr, BookContextRevisionCollection as Dt, MAX_EXTRACTED_SECTIONS as E, SubmissionCollection as Ei, Question as En, readDelegation as Er, BookContextRevision as Et, normalizeWorkObservedLayout as F, Submission as Fi, resolveEnrollmentLessons as Fn, CourseRelease as Fr, FamilyIntakeAsset as Ft, EnrollmentNotActiveError as G, LESSON_ASSET_RELATIONSHIPS as Gi, MAX_PRINTABLE_ITEMS as Gn, EnrollmentAssignmentRecord as Gr, LessonWorkFiling as Gt, SubmissionStorageCleanupError as H, EXTERNAL_VIDEO_PROVIDERS as Hi, GENERATED_PRINTABLE_RELATIONSHIPS as Hn, CourseVisibilityChangeCollection as Hr, readWorkCompletion as Ht, normalizeWorkAnswerRegions as I, SubmissionAsset as Ii, applyProposalFields as In, CourseReleaseCollection as Ir, FamilyIntakeAssetCollection as It, InterestThemeError as J, LessonExternalVideoCollection as Ji, MAX_PRINTABLE_TOTAL_TEXT as Jn, EnrollmentAutoUpgradeSkipCollection as Jr, WorkAssessmentRevisionCollection as Jt, EnrollmentPaceError as K, LessonAsset as Ki, MAX_PRINTABLE_PAGES as Kn, EnrollmentAssignmentRecordCollection as Kr, LessonWorkFilingCollection as Kt, LessonWorkWorkflowRequiredError as L, SubmissionIntakeBinding as Li, draftFromRevision as Ln, CourseRevision as Lr, FamilyIntakeCollection as Lt, QuestionExtractionPendingError as M, Grade as Mi, CourseAuthoringService as Mn, CourseDiscardTombstoneCollection as Mr, WorkbookPhotoIntake as Mt, QuestionExtractionValidationError as N, LessonSelfAttestation as Ni, authoredVisibilityPermitsGroups as Nn, CourseDraftHead as Nr, WorkbookPhotoIntakeCollection as Nt, MAX_EXTRACTED_TEXT as O, VideoCollection as Oi, QuestionResponse as On, CourseArchiveDecisionCollection as Or, WorkbookPhotoAsset as Ot, LessonWorkService as P, ScannedSubmission as Pi, effectiveCourseVisibility as Pn, CourseDraftHeadCollection as Pr, FamilyIntake as Pt, LearnerValidationError as Q, parseYouTubeReference as Qi, PrintableStorageNotConfiguredError as Qn, LessonRevisionCollection as Qr, WorkFeedbackDeliveryCollection as Qt, OwnAttestationConflictError as R, parseQuestionRubric as Ri, planProposal as Rn, CourseRevisionCollection as Rr, FamilyIntakeDecision as Rt, MAX_EXTRACTED_ANCHORS as S, LessonSelfAttestationCollection as Si, LearningObjective as Sn, MAX_REFUSAL_CATEGORY_LENGTH as Sr, GroupSharingPolicyValidationError as St, MAX_EXTRACTED_QUESTIONS as T, SubmissionAssetCollection as Ti, LearningObjectiveRevisionCollection as Tn, delegationRecordFields as Tr, familyIntakeScopeId as Tt, submissionPageKey as U, GUARDIAN_ONLY_RELATIONSHIPS as Ui, LearningObjectiveKeyConflictError as Un, CurriculumCreationRecord as Ur, LessonActivity as Ut, SubmissionService as V, CourseAssetCollection as Vi, GENERATED_PRINTABLE_AUDIENCES as Vn, CourseVisibilityChange as Vr, WorkCompletionDecisionCollection as Vt, ENROLLMENT_STATUS_TRANSITIONS as W, LESSON_ASSET_DEFAULT_AUDIENCE as Wi, LearningObjectiveNotFoundError as Wn, CurriculumCreationRecordCollection as Wr, LessonActivityCollection as Wt, LearnerHistoryUnavailableError as X, externalVideoEmbedUrl as Xi, PrintableOwnerError as Xn, EnrollmentReleasePinCollection as Xr, WorkAttemptCollection as Xt, LearnerAuthorizationError as Y, MATERIAL_RENDITIONS as Yi, MAX_RESOLVE_QUESTION_REVISIONS as Yn, EnrollmentReleasePin as Yr, WorkAttempt as Yt, LearnerService as Z, materialAudience as Zi, PrintableStorageCleanupError as Zn, LessonRevision as Zr, WorkFeedbackDelivery as Zt, EXTRACTED_OMISSION_REASONS as _, GradeCollection as _i, renderGuardianWorksheetPdf as _n, CourseProposalFieldError as _r, LessonProgressTransitionCollection as _t, questionExtractionProposalDigest as a, interestThemeFromColumns as aa, mostRestrictiveLicense as ai, aggregateWorkQuestions as an, QuestionReferenceError as ar, MIN_LESSONS_PER_WEEK as at, EXTRACTED_QUESTION_STATUSES as b, LessonCollection as bi, GeneratedPrintable as bn, MAX_GENERATION_GRADE as br, GroupSharingAuthorizationError as bt, QuestionExtractionRecord as c, COURSE_VISIBILITIES as ca, AttestationCollection as ci, LessonPage as cn, COURSE_GENERATION_STATUSES as cr, EnrollmentPaceChange as ct, extractedQuestionContent as d, Exercise as da, CourseSectionCollection as di, validLessonPageKey as dn, CourseGenerationBriefError as dr, EnrollmentStatusChangeCollection as dt, Enrollment as ea, ReleasedLessonCollection as ei, WorkFeedbackReleaseCollection as en, QUESTION_FIELDS as er, LessonPutBackError as et, matchExtractedQuestions as f, ExternalCourse as fa, CurriculumCollection as fi, QuestionAuthoringService as fn, CourseGenerationInProgressError as fr, LearnerInterestThemeChange as ft, EXTRACTED_MEDIA_KINDS as g, Worksheet as ga, ExternalCourseCollection as gi, worksheetVersionId as gn, CourseGeneratorNotConfiguredError as gr, LessonProgressTransition as gt, EXTRACTED_LEGIBILITY as h, Video as ha, ExternalCompletionCollection as hi, canonical$2 as hn, CourseGenerationRefusal as hr, LessonCompletionRecordCollection as ht, QuestionExtractionService as i, MAX_INTEREST_THEME_LABEL_CHARS as ia, isGroupShareableLicense as ii, WorkCompletionConflictError as in, QuestionNotFoundError as ir, MAX_NEXT_LESSONS_COUNT as it, QuestionExtractionNotFoundError as j, ExternalCompletion as ji, QuestionRevisionCollection as jn, CourseDiscardTombstone as jr, WorkbookPhotoDecisionCollection as jt, QUESTION_EXTRACTION_SOURCE_KINDS as k, WorksheetCollection as ki, QuestionResponseCollection as kn, CourseCoverChange as kr, WorkbookPhotoAssetCollection as kt, QuestionExtractionRecordCollection as l, Course as la, AuthoredCourseCollection as li, LessonPageCollection as ln, COURSE_GENERATION_TARGETS as lr, EnrollmentPaceChangeCollection as lt, questionExtractionSourceIdentity as m, Reading as ma, ExerciseCollection as mi, buildLearnerWorksheet as mn, CourseGenerationOutputError as mr, LessonCompletionRecord as mt, preservePhotoProposal as n, LessonProgress as na, AUTHORED_RELEASE_SOURCE_KEY as ni, WORK_MATH_VOCABULARY as nn, QUESTION_PROVENANCES as nr, LessonWorkOwnedError as nt, ExtractedQuestionLink as o, parseInterestTheme as oa, CatalogAuthorizationError as oi, validateWorkAssessment as on, WorksheetVersionMismatchError as or, enrollmentView as ot, normalizeQuestionExtraction as p, Lesson as pa, EnrollmentCollection as pi, buildGuardianWorksheet as pn, CourseGenerationNotFoundError as pr, LearnerInterestThemeChangeCollection as pt, EnrollmentStatusTransitionError as q, LessonExternalVideo as qi, MAX_PRINTABLE_TEXT_LENGTH as qn, EnrollmentAutoUpgradeSkip as qr, WorkAssessmentRevision as qt, validateWorkbookPhotoIdentification as r, MAX_INTEREST_THEME_KEY_CHARS as ra, isAuthoredReleaseGroupShareable as ri, WorkAssessmentValidationError as rn, QUESTION_RESPONSE_TYPES as rr, MAX_LESSONS_PER_WEEK as rt, ExtractedQuestionLinkCollection as s, AuthoredCourse as sa, CatalogService as si, workAggregateFeedback as sn, groupSharingDigest as sr, requirePolicyBasis as st, WorkbookPhotoService as t, Learner as ta, AUTHORED_IDENTITY_SOURCE_KEY as ti, LessonWorkPlacementError as tn, QUESTION_PROMPT_SUMMARY_LENGTH as tr, LessonSkippedError as tt, QUESTION_EXTRACTION_ARGS_SCHEMA as u, CourseSection as ua, CourseCollection as ui, lessonPageView as un, COURSE_GENERATION_TERMINAL as ur, EnrollmentStatusChange as ut, EXTRACTED_ORIGINS as v, LearnerCollection as vi, renderLearnerWorksheetPdf as vn, CourseProposalNotFoundError as vr, evaluateGroupSharingPolicy as vt, MAX_EXTRACTED_PAGES as w, ScannedSubmissionCollection as wi, LearningObjectiveRevision as wn, delegationActorFields as wr, validateGroupSharingPolicy as wt, EXTRACTED_READABILITY as x, LessonProgressCollection as xi, GeneratedPrintableCollection as xn, MAX_GENERATION_OBJECTIVE_CHARS as xr, GroupSharingConflictError as xt, EXTRACTED_PAGE_ROLES as y, LessonAssetCollection as yi, es_exports as yn, MAX_GENERATION_BRIEF_FIELD_CHARS as yr, summarizeWorkEvidence as yt, OwnAttestationLessonKindError as z, validateRubricResults as zi, validateCourseGenerationOutput as zn, CourseUpgradeChoice as zr, FamilyIntakeDecisionCollection as zt };
36885
36942
 
36886
- //# sourceMappingURL=workbook-photo-service-CjcB0y8Y.js.map
36943
+ //# sourceMappingURL=workbook-photo-service-DHP5ja82.js.map