@happyvertical/smrt-education 0.58.0 → 0.59.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 (53) hide show
  1. package/AGENTS.md +6 -1
  2. package/agents/class-crunchlabs.md +83 -0
  3. package/agents/course-bundle-import.md +108 -18
  4. package/dist/catalog-contracts.d.ts +6 -2
  5. package/dist/catalog-contracts.d.ts.map +1 -1
  6. package/dist/catalog-materialization-service.d.ts.map +1 -1
  7. package/dist/catalog-policy.d.ts +11 -1
  8. package/dist/catalog-policy.d.ts.map +1 -1
  9. package/dist/catalog-preview.d.ts +6 -1
  10. package/dist/catalog-preview.d.ts.map +1 -1
  11. package/dist/chunks/course-authoring-contracts-C4Hqba-e.js +131 -0
  12. package/dist/chunks/course-authoring-contracts-C4Hqba-e.js.map +1 -0
  13. package/dist/chunks/course-bundle-zip-5KUe3C5H.js +323 -0
  14. package/dist/chunks/course-bundle-zip-5KUe3C5H.js.map +1 -0
  15. package/dist/chunks/{workbook-photo-service-COtyQL1y.js → workbook-photo-service-CjcB0y8Y.js} +226 -130
  16. package/dist/chunks/workbook-photo-service-CjcB0y8Y.js.map +1 -0
  17. package/dist/course-authoring-contracts.d.ts +1 -1
  18. package/dist/course-authoring-contracts.d.ts.map +1 -1
  19. package/dist/course-bundle-contracts.d.ts +21 -3
  20. package/dist/course-bundle-contracts.d.ts.map +1 -1
  21. package/dist/course-bundle-manifest-util.d.ts +15 -0
  22. package/dist/course-bundle-manifest-util.d.ts.map +1 -0
  23. package/dist/course-bundle-manifest-v2.d.ts +66 -0
  24. package/dist/course-bundle-manifest-v2.d.ts.map +1 -0
  25. package/dist/course-bundle-models.d.ts +29 -1
  26. package/dist/course-bundle-models.d.ts.map +1 -1
  27. package/dist/course-bundle-service.d.ts +104 -5
  28. package/dist/course-bundle-service.d.ts.map +1 -1
  29. package/dist/course-bundle.d.ts +81 -2
  30. package/dist/course-bundle.d.ts.map +1 -1
  31. package/dist/document-converter.d.ts +30 -18
  32. package/dist/document-converter.d.ts.map +1 -1
  33. package/dist/hearth-catalog-providers.d.ts +1 -1
  34. package/dist/hearth-catalog-providers.d.ts.map +1 -1
  35. package/dist/hearth-class-crunchlabs.d.ts +94 -0
  36. package/dist/hearth-class-crunchlabs.d.ts.map +1 -0
  37. package/dist/index.d.ts +5 -2
  38. package/dist/index.d.ts.map +1 -1
  39. package/dist/index.js +1633 -399
  40. package/dist/index.js.map +1 -1
  41. package/dist/ingestion.js +1 -1
  42. package/dist/manifest.json +418 -6
  43. package/dist/node.d.ts +3 -0
  44. package/dist/node.d.ts.map +1 -0
  45. package/dist/node.js +134 -0
  46. package/dist/node.js.map +1 -0
  47. package/dist/smrt-knowledge.json +162 -10
  48. package/dist/sources/class-crunchlabs-files.d.ts +8 -0
  49. package/dist/sources/class-crunchlabs-files.d.ts.map +1 -0
  50. package/dist/sources/class-crunchlabs.d.ts +217 -0
  51. package/dist/sources/class-crunchlabs.d.ts.map +1 -0
  52. package/package.json +12 -8
  53. package/dist/chunks/workbook-photo-service-COtyQL1y.js.map +0 -1
package/AGENTS.md CHANGED
@@ -57,11 +57,16 @@ Structured questions from scans and imported course files use
57
57
  ingestion handler. Anchors come from provider region catalogs only; match by worksheet
58
58
  id and layout, never text; ambiguous matches stay unattached; source-keyed replays.
59
59
 
60
- Course bundles (zip with a closed manifest, or a file set; Word/PowerPoint members render through an injected `DocumentConverter`, fail closed) use
60
+ Course bundles (zip with a closed manifest v1 or v2, or a file set; Word/PowerPoint members render through an injected `DocumentConverter`, fail closed; v2 carries material roles, audience, lesson pages, course members and YouTube references) use
61
61
  [CourseBundleImportService](agents/course-bundle-import.md). Parse only with the
62
62
  bounded reader; refuse, never trim, hostile input; unsupported members stay
63
63
  visible; proposals only, nothing auto-published.
64
64
 
65
+ Class CrunchLabs (a download read into a manifest v2 bundle; an operator-only
66
+ global catalog provider until the operator's single public switch):
67
+ [source contract](agents/class-crunchlabs.md). Never host its files; `operator`
68
+ visibility needs the host's `operatorTenantIds`.
69
+
65
70
  Source import: [host boundary and transaction contract](agents/source-import.md).
66
71
  `SourceImportService` requires host opt-in, matching active actor/tenant and
67
72
  explicit licensing authorization; never add a system/global write bypass.
@@ -0,0 +1,83 @@
1
+ # Class CrunchLabs source (SMRT #4616)
2
+
3
+ Class CrunchLabs is a global catalog provider (`class-crunchlabs`) whose units are
4
+ listed under Science, with the @ClassCrunchLabs YouTube course playlists as
5
+ previews. "Add to a course" reads the family's own download of the unit and runs
6
+ the [bundle import](course-bundle-import.md) with a manifest version 2 built from
7
+ it. Files come from CrunchLabs' own downloads and YouTube; **nothing is hosted
8
+ here** and the listing has no acquirable formats.
9
+
10
+ ## Operator-only until permission, one public switch
11
+
12
+ `CatalogVisibility` gains `operator`. A `CatalogPolicy` built with
13
+ `operatorTenantIds` lets only those families (host configuration, never a
14
+ request) see `operator` records; the default policy shows them to nobody, and
15
+ `authorize` answers `operator-only`. Materialization refuses them.
16
+
17
+ `createClassCrunchLabsCatalogAdapter({ playlists, publicListing? })` is a snapshot
18
+ `CatalogSyncAdapter` (one terminal page, no cursor). By default
19
+ (`CLASS_CRUNCHLABS_PUBLIC_LISTING_DEFAULT = false`) every record is `operator`
20
+ visibility with licence state `unknown`, no permitted operations and the text
21
+ "free curriculum, permission pending". Only the literal `publicListing: true`,
22
+ set by the operator in host configuration, makes records `catalog` visibility
23
+ with `verified` evidence permitting `link` only. The switch is part of each
24
+ record's revision, so the next sync rewrites the rows when it is flipped.
25
+ `classCrunchLabsPreviewEmbedUrl(record)` returns the youtube-nocookie playlist
26
+ embed for a listed unit (null for anything else). The playlist data is an
27
+ injected `ClassCrunchLabsPlaylistSource`; the adapter never touches the network.
28
+
29
+ `addClassCrunchLabsUnit({ service, actor, catalogActor, record, listing, policy,
30
+ files, playlists, pageCounter?, receiveMember? })` re-checks
31
+ `canAddClassCrunchLabsUnit(actor, policy, listing)`: visibility is derived from the
32
+ host's own `listing.publicListing` (operator unless the literal `true`), never from
33
+ the record or any caller-supplied visibility or licence; an operator-only listing
34
+ is refused to every other family, and the course actor must be the catalog actor, builds the bundle and imports each part. Then propose
35
+ structure and `applyMaterials` per part as for any bundle. Courses are
36
+ `personal-use-copy` (`build.licenseKind`).
37
+
38
+ ## Reading a download
39
+
40
+ `buildClassCrunchLabsBundle({ files, playlists?, unit?, pageCounter?,
41
+ includeUnitWideAggregates?, maxPartBytes? })` takes a `ClassCrunchLabsFileSource`:
42
+ `folderClassCrunchLabsSource(dir)` (Node only, from `@happyvertical/smrt-education/node`, never the root: a folder, the Drive zip parts, or both;
43
+ zips are read lazily from their central directory, zip64/encrypted/symlinks are
44
+ skipped) or `memoryClassCrunchLabsSource(files)`. It never reads video files.
45
+
46
+ - Layout: `<Unit>_All Unit Wide Materials` and `<Unit>_Lesson <n>`; letters A
47
+ teacher manual, B slides, C student mission log, D status check assessment
48
+ (plus guidance and the editable master), E handouts, F extras, G videos. A
49
+ lettered directory wins over a file's own letter. Several units need `unit`.
50
+ - Mapping to manifest v2: A `teacher-guide`, B `slides`, C `learner-pages`, D
51
+ `assessment` / `assessment-guidance`, E `handout`, F `printable`, the unit-wide
52
+ Supply List `attachment`. Audiences are the role defaults (teacher manual and
53
+ guidance guardian, slides guardian, mission log learner); the editable
54
+ assessment master is guardian. Unit-wide files become course members.
55
+ - The unit-wide "(all lessons)" combined files repeat the per-lesson files and
56
+ are large, so they are left out unless `includeUnitWideAggregates` (reported as
57
+ `aggregate-of-lessons`); the supply list, posters and other extras are kept.
58
+ - Lesson pages: the first mission log of a lesson gets a `Mission log` range
59
+ from `pageCounter` (`createClassCrunchLabsPageCounter({ converter? })` counts
60
+ PDFs with pdf-lib and Word files by rendering them through the converter).
61
+ Without a count the lesson gets no pages and the report says so.
62
+ - Videos: names `Lnn.step_Video_Kind_Title` are matched, by unit (playlist
63
+ title), lesson and step (`L03.6` or `Lesson 3 ... Step 6` in the item title),
64
+ to the unit playlist; two videos sharing a step are told apart by the item
65
+ title naming their title or kind, else both stay unmatched (`ambiguous`).
66
+ Matches become `videos` references with a title and a step order (materials
67
+ prep videos are guardian audience); unit-level videos (a teaser) and unmatched
68
+ ones are only reported.
69
+ - De-duplication: repeated exports of one logical path collapse (CRC and size
70
+ when known; the newer export wins, a changed file is `superseded`); the same
71
+ bytes under another name or place keep one copy (the lesson-named file in its
72
+ lesson, posters unit wide, never a `copy`).
73
+ - A unit larger than one archive (bundle cap 100 MiB) is split by lesson into
74
+ `build.parts` (default 90 MiB each; the first part carries the course members and
75
+ any lesson that fits beside them, others go to the first part with room; if no
76
+ lesson fits beside the course members the build refuses with `too_large`); `build.bundle`
77
+ and `build.manifest` are the first part.
78
+
79
+ The `report` lists lessons, members, parts, pages, matched and unmatched videos,
80
+ duplicates, ignored files and warnings. Fixtures in tests are synthetic files
81
+ with the same naming; no real download is ever copied into the repository.
82
+
83
+ Tests: `src/__tests__/class-crunchlabs.test.ts`.
@@ -84,7 +84,7 @@ too long or deep). An **honestly** oversize member (declared over
84
84
 
85
85
  ## Members and statuses
86
86
 
87
- By content (never by extension alone): `docx`/`pptx` (see below), `pdf` (`%PDF-` in the first 1 KiB),
87
+ By content (never by extension alone): `docx`/`pptx`/`xlsx` (see below), `pdf` (`%PDF-` in the first 1 KiB),
88
88
  `image` (PNG, JPEG, WebP), `text` (`.txt`/`.md`, strict UTF-8, no control
89
89
  characters, body-sized), `manifest` (root `manifest.json`), else `unsupported`.
90
90
  Status: `accepted` (handed to extraction), `duplicate` (same sha256 as an earlier
@@ -97,9 +97,11 @@ on literal text inside an uncompressed stream is refused, never read.
97
97
 
98
98
  ## Word and PowerPoint members (SMRT #4615)
99
99
 
100
- A `.docx`/`.pptx` member is an OOXML package only when the name and the content
101
- agree: a zip whose entries include `[Content_Types].xml` and `word/document.xml`
102
- (docx) or `ppt/presentation.xml` (pptx). Before the bytes go anywhere, the
100
+ A `.docx`/`.pptx`/`.xlsx` member is an OOXML package only when the name and the
101
+ content agree: a zip whose entries include `[Content_Types].xml` and
102
+ `word/document.xml` (docx), `ppt/presentation.xml` (pptx) or `xl/workbook.xml`
103
+ (xlsx). A workbook (a supply list) is rendered and kept like the others but has
104
+ no text reader. Before the bytes go anywhere, the
103
105
  package itself passes the same bounded zip reader (ratio, overlap, paths, CRC,
104
106
  100 MiB inflated); a failure is `refused / unsafe_office`, never a refusal of the
105
107
  whole bundle. Other zips stay `unsupported / nested_archive`.
@@ -158,10 +160,15 @@ network**, its own size/time limits and no shared volume with the app; this
158
160
  package assumes untrusted files never run next to the application. Tests use
159
161
  `FakeDocumentConverter` (records calls; `failWith`, `failWhen`, `delayMs`, `output`).
160
162
 
161
- `OfficeTextReader` is deliberately not wired to the SDK here, so this package
162
- does not depend on an unreleased `@happyvertical/documents`. Once the Office
163
- processors ship (sdk#1485, `extractOffice(bytes, 'docx' | 'pptx')`), implement
164
- `read` with it; the snippet is in the `OfficeTextReader` doc comment.
163
+ `OfficeTextReader` reads Office text through the SDK without this package
164
+ depending on `@happyvertical/documents`: the host imports `extractOffice`
165
+ (released in `@happyvertical/documents` 0.111.4, sdk#1486, Kreuzberg) and passes
166
+ it to `createOfficeTextReader(extractOffice)`, which returns whole-document
167
+ text for Word and text plus speaker notes per slide for PowerPoint (images are
168
+ never requested). An absent engine reads as `null`; a corrupt file rejects and
169
+ the importer treats that as "no text". The repository's current `catalog:`
170
+ pin is 0.111.3, which predates the Office processors, so the host bumps the SDK
171
+ set (and its minimum release age) before it can import `extractOffice`.
165
172
 
166
173
  ## Manifest (`manifest.json`, version 1, closed)
167
174
 
@@ -186,10 +193,96 @@ are never inlined. Members whose declared role is `answer_key` or `mixed` never
186
193
  contribute text to a lesson body (they remain recorded evidence members); the
187
194
  proposal rationale only counts how many were withheld.
188
195
 
196
+ ## Manifest version 2 (SMRT #4615)
197
+
198
+ A root `manifest.json` with `"version": 2` is laid out by the `manifest-v2`
199
+ reader; version 1 keeps its own reader and page roles. The schema is closed in
200
+ the same way: an unknown key anywhere is `manifest_unknown_key` (with its path in
201
+ `entry`), another version is `manifest_version`.
202
+
203
+ ```json
204
+ { "version": 2, "course": { "subject": "Science" },
205
+ "courseMembers": [ { "path": "unit/supplies.pdf", "role": "attachment", "title": "Supply list" } ],
206
+ "sections": [ { "key": "unit", "title": "Unit", "lessons": [ {
207
+ "key": "l1", "title": "Lesson 1",
208
+ "members": [ { "path": "l1/log.docx", "role": "learner-pages" },
209
+ { "path": "l1/deck.pptx", "role": "slides" },
210
+ { "path": "l1/guidance.pdf", "role": "assessment-guidance" } ],
211
+ "pages": [ { "member": "l1/log.docx", "from": 1, "to": 4, "label": "Mission log" } ],
212
+ "videos": [ { "reference": "dQw4w9WgXcQ", "title": "Recap", "step": 1 } ] } ] } ] }
213
+ ```
214
+
215
+ - **Members** (lesson `members` and root `courseMembers`): `path` (must exist, listed
216
+ once), `role` (required) one of `teacher-guide`, `slides`, `learner-pages`,
217
+ `assessment`, `assessment-guidance`, `handout`, `printable`, `answer-key`,
218
+ `attachment` (`manifest_role` otherwise; a video is a reference, never a file),
219
+ optional `audience` and `title`. The audience is the role default
220
+ (`LESSON_ASSET_DEFAULT_AUDIENCE`) unless stated; `answer-key` and
221
+ `assessment-guidance` are always guardian (a learner audience is
222
+ `manifest_audience`). Members not listed stay recorded evidence with no role.
223
+ - **Pages**: `{ member, from, to, label? }` ranges over a member of the same lesson
224
+ (PDF, Word or PowerPoint; the rendered PDF for Office). Each page becomes a
225
+ `LessonPage` keyed `p<n>`, labelled `<label> <n>` (default `Page <n>`), ordered by
226
+ declaration. Bad, overlapping or unpageable ranges are `manifest_pages`; at most
227
+ 500 pages per lesson.
228
+ - **Videos**: `{ reference, title, step, audience? }` where `reference` is a bare id
229
+ or an allowlisted https YouTube URL (`parseYouTubeReference`; anything else is
230
+ `manifest_video`), `step` an integer 0-9999. They become `LessonExternalVideo`
231
+ rows; nothing is downloaded.
232
+ - **Course members** become `CourseAsset` rows, not tied to any lesson.
233
+
234
+ Guardian-audience text (teacher guides, guidance, keys) never enters a proposed
235
+ lesson body; only learner-audience text members do. Under v2 `role` on the member
236
+ evidence row is the material role and `audience` the effective audience (NULL on
237
+ rows recorded before v2). The plan carries `materials` (also on
238
+ `CourseBundleImportResult.materials`): the resolved materials, pages and videos,
239
+ plus `skipped` for declared members that were unsupported, refused or failed
240
+ rendering. A duplicate member resolves to the earlier identical member's bytes
241
+ (`assetPath`) and one material per (place, role, content).
242
+
243
+ `receiveMember` also gets `audience` and `courseLevel`. **Slides** keep the original
244
+ deck (hand `bytes` to the host as a private asset: "Open in PowerPoint") and its
245
+ rendered pages (`rendered`: "Present").
246
+
247
+ ### Applying materials
248
+
249
+ `applyMaterials({ ...actor, importId, bundle, courseId, lessons, assets })`
250
+ (`education.course.author`, operation `apply-course-bundle-materials`) writes the
251
+ rows in one transaction. The host has stored each accepted member as a private
252
+ asset and created the course's lessons: `lessons` maps manifest lesson key to the
253
+ `Lesson` id, `assets` maps member path to `{ original, rendered }` asset ids.
254
+ Slides join both the original deck and the rendered PDF; the original join is always
255
+ guardian-only whatever the deck's declared audience (the audience applies to the
256
+ rendered PDF), and a join written earlier with a wider audience is repaired on
257
+ re-apply (`repaired`); any other Word/PowerPoint
258
+ member joins only its rendered PDF, so a learner is never handed an editable
259
+ original. `LessonAsset`/`CourseAsset` saves keep their private-asset rule (guardian-
260
+ only roles and personal-use-copy courses need private assets). It targets
261
+ family-owned courses; an authored course is `authored-course` because authored
262
+ material changes through course authoring. Idempotent: an identical row is
263
+ `unchanged`, a row with other details is `CourseBundleMaterialsError('conflict')`,
264
+ a missing asset or lesson is `asset-missing`/`lesson-missing`; any error writes
265
+ nothing.
266
+
267
+ ### Retrying a failed rendering
268
+
269
+ `retryRendering({ ...actor, importId, bundle, paths?, receiveMember? })`
270
+ (`education.course.author`, operation `retry-course-bundle-rendering`, needs a
271
+ converter) renders the Word/PowerPoint members whose first import recorded a
272
+ *transient* failure (`converter_unavailable`, `converter_failed`,
273
+ `converter_timeout`; `COURSE_BUNDLE_RETRYABLE_REASONS`). The first import's member
274
+ rows are never rewritten. A success appends one `course_bundle_renderings` row
275
+ per (import, content hash); every reader (`readImport`, replayed imports,
276
+ proposals) overlays it, so the member reads `accepted` (identical copies as
277
+ duplicates) with its rendered hash. A failure records nothing, so asking again is
278
+ always allowed; a second retry of a repaired member is `unchanged` and renders
279
+ nothing. Converter rejections, size limits and the Office member cap are not
280
+ retryable: change the bundle. The bundle must be the imported one.
281
+
189
282
  ## Readers
190
283
 
191
284
  `BundleReader { formatId, detect, prepare }` in a `BundleReaderRegistry`;
192
- built-ins are `manifest-v1` and `plain-files`. SCORM and Common Cartridge are
285
+ built-ins are `manifest-v2`, `manifest-v1` and `plain-files`. SCORM and Common Cartridge are
193
286
  **not implemented** (their manifests describe launch resources and activity
194
287
  trees that do not map to sections/lessons without design); a host can register
195
288
  a reader ahead of the built-ins (`register(reader, { first: true })`).
@@ -203,20 +296,17 @@ re-zipping, reordering and timestamps replay. One `CourseBundleImport` per
203
296
  ## Models (closed, required tenant, no REST/CLI/MCP/AI, append-only)
204
297
 
205
298
  `CourseBundleImport` (`course_bundle_imports`: identity, format, reader,
206
- manifest version, counts, actor) and `CourseBundleMember` (`course_bundle_members`:
299
+ manifest version, counts, actor), `CourseBundleMember` (`course_bundle_members`:
207
300
  unique tenant/import/path; ordinal, sha256, size, media type, kind, status,
208
- reason, duplicate-of, role, section and lesson key). Hashes and placements only:
301
+ reason, duplicate-of, role, audience, section and lesson key) and
302
+ `CourseBundleRendering` (`course_bundle_renderings`: a deliberate retry's success). Hashes and placements only:
209
303
  bytes stay with the host's ingestion receipts. Rewrites and deletes throw.
210
- Normal manifest migrations create both tables.
304
+ Normal manifest migrations create the tables and add `audience` (NULL on older rows).
211
305
 
212
306
  ## Not in this release
213
307
 
214
- - Manifest version 2 (material roles with audience, lesson pages, course-level
215
- members, external video references) waits for the phase 1 role vocabulary
216
- (smrt#4614). The page-role vocabulary and the closed v1 schema are unchanged;
217
- see the hand-off note on smrt#4615.
218
- - Re-rendering a member whose first import recorded a converter failure (outcomes
219
- are append-only per bundle identity).
308
+ - Material rows for authored courses: a proposal still carries lesson text only;
309
+ authored course material goes through `CourseMaterialInput` and release.
220
310
  - Ingestion's receipt contract is unchanged: there is no `application/zip` part
221
311
  type or `parentEvidenceId` in ingestion. The education side unpacks and the
222
312
  host receives members one by one, so archive-to-member lineage lives in
@@ -1,6 +1,10 @@
1
1
  import type { CatalogPreview } from './catalog-preview.js';
2
- /** Metadata-only resource visibility. Teacher material is never learner-visible. */
3
- export type CatalogVisibility = 'catalog' | 'teacher';
2
+ /**
3
+ * Metadata-only resource visibility. Teacher material is never learner-visible.
4
+ * `operator` records (a provider whose permission is pending) are visible only
5
+ * to the tenants the host designated as operator families; see `CatalogPolicy`.
6
+ */
7
+ export type CatalogVisibility = 'catalog' | 'teacher' | 'operator';
4
8
  export type CatalogLicenseState = 'verified' | 'unknown' | 'conflicting' | 'restricted';
5
9
  export type CatalogOperation = 'link' | 'download' | 'print' | 'adapt' | 'redistribute' | 'commercial-use';
6
10
  /** Exact source evidence; no provider-wide license inference is permitted. */
@@ -1 +1 @@
1
- {"version":3,"file":"catalog-contracts.d.ts","sourceRoot":"","sources":["../src/catalog-contracts.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"catalog-contracts.d.ts","sourceRoot":"","sources":["../src/catalog-contracts.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAC;AAE3D;;;;GAIG;AACH,MAAM,MAAM,iBAAiB,GAAG,SAAS,GAAG,SAAS,GAAG,UAAU,CAAC;AACnE,MAAM,MAAM,mBAAmB,GAC3B,UAAU,GACV,SAAS,GACT,aAAa,GACb,YAAY,CAAC;AACjB,MAAM,MAAM,gBAAgB,GACxB,MAAM,GACN,UAAU,GACV,OAAO,GACP,OAAO,GACP,cAAc,GACd,gBAAgB,CAAC;AAErB,8EAA8E;AAC9E,MAAM,WAAW,sBAAsB;IACrC,KAAK,EAAE,mBAAmB,CAAC;IAC3B,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,8DAA8D;IAC9D,mBAAmB,CAAC,EAAE,gBAAgB,EAAE,CAAC;CAC1C;AAED,oFAAoF;AACpF,UAAU,6BAA6B;IACrC,UAAU,EAAE,MAAM,CAAC;IACnB,UAAU,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,YAAY,EAAE,MAAM,CAAA;KAAE,CAAC;CACpD;AACD,MAAM,MAAM,6BAA6B,GAAG,6BAA6B,GACvE,CACI;IACE,MAAM,EAAE,KAAK,GAAG,KAAK,GAAG,MAAM,CAAC;IAC/B,SAAS,EACL,iBAAiB,GACjB,iBAAiB,GACjB,yEAAyE,CAAC;IAC9E,WAAW,EACP;QAAE,MAAM,EAAE,WAAW,CAAC;QAAC,QAAQ,EAAE,MAAM,CAAA;KAAE,GACzC;QAAE,MAAM,EAAE,oBAAoB,CAAA;KAAE,GAChC;QAAE,MAAM,EAAE,YAAY,CAAC;QAAC,QAAQ,EAAE,MAAM,CAAA;KAAE,CAAC;CAChD,GACD;IACE,MAAM,EAAE,SAAS,CAAC;IAClB,kFAAkF;IAClF,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;IACzB,WAAW,EAAE;QACX,MAAM,EAAE,gBAAgB,CAAC;QACzB,MAAM,EAAE,sBAAsB,GAAG,2BAA2B,CAAC;KAC9D,CAAC;CACH,CACJ,CAAC;AACJ,MAAM,MAAM,oCAAoC,GAC5C;IAAE,OAAO,EAAE,IAAI,CAAC;IAAC,YAAY,EAAE,UAAU,GAAG,QAAQ,CAAA;CAAE,GACtD;IACE,OAAO,EAAE,KAAK,CAAC;IACf,MAAM,EACF,oBAAoB,GACpB,oBAAoB,GACpB,gBAAgB,GAChB,YAAY,GACZ,iCAAiC,CAAC;IACtC,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB,CAAC;AAEN,mFAAmF;AACnF,MAAM,WAAW,mBAAmB;IAClC,UAAU,EAAE,MAAM,CAAC;IACnB,QAAQ,EAAE,MAAM,CAAC;IACjB,QAAQ,EAAE,MAAM,CAAC;IACjB,YAAY,EAAE,MAAM,CAAC;IACrB,KAAK,EAAE,MAAM,CAAC;IACd,mBAAmB,CAAC,EAAE,MAAM,CAAC;IAC7B,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,QAAQ,CAAC,EAAE,MAAM,EAAE,CAAC;IACpB,UAAU,CAAC,EAAE;QAAE,GAAG,CAAC,EAAE,MAAM,CAAC;QAAC,GAAG,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC;IAC5C,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,gBAAgB,CAAC,EAAE,MAAM,EAAE,CAAC;IAC5B,cAAc,CAAC,EAAE,6BAA6B,CAAC;IAC/C,OAAO,CAAC,EAAE,cAAc,CAAC;IACzB,eAAe,EAAE,sBAAsB,CAAC;IACxC,UAAU,EAAE,iBAAiB,CAAC;CAC/B;AAED,MAAM,WAAW,kBAAkB;IACjC,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC;IAChB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,uEAAuE;IACvE,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,iFAAiF;IACjF,kBAAkB,CAAC,EAAE,MAAM,CAAC;CAC7B;AAED,yFAAyF;AACzF,MAAM,WAAW,eAAe;IAC9B,OAAO,EAAE,mBAAmB,EAAE,CAAC;IAC/B,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,QAAQ,EAAE,OAAO,CAAC;IAClB,mEAAmE;IACnE,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,mFAAmF;IACnF,UAAU,CAAC,EAAE,kBAAkB,EAAE,CAAC;IAClC,4EAA4E;IAC5E,gBAAgB,CAAC,EAAE,kBAAkB,EAAE,CAAC;CACzC;AAED,MAAM,WAAW,qBAAqB;IACpC,UAAU,EAAE,MAAM,CAAC;IACnB,qFAAqF;IACrF,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,QAAQ,EAAE,OAAO,CAAC;IAClB,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,aAAa,EAAE,MAAM,CAAC;IACtB,QAAQ,EAAE,kBAAkB,EAAE,CAAC;CAChC;AAED,MAAM,WAAW,kBAAkB;IACjC,SAAS,CAAC,KAAK,EAAE;QACf,MAAM,CAAC,EAAE,MAAM,CAAC;QAChB,UAAU,EAAE,qBAAqB,CAAC;KACnC,GAAG,OAAO,CAAC,eAAe,CAAC,CAAC;CAC9B;AAED,MAAM,WAAW,qBAAqB;IACpC,OAAO,CAAC,KAAK,EAAE;QACb,UAAU,EAAE,MAAM,CAAC;QACnB,QAAQ,EAAE,MAAM,CAAC;QACjB,QAAQ,EAAE,MAAM,CAAC;QACjB,MAAM,EAAE,MAAM,CAAC;KAChB,GAAG,OAAO,CAAC;QAAE,KAAK,EAAE,UAAU,CAAC;QAAC,MAAM,EAAE,MAAM,CAAC;QAAC,QAAQ,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;CACtE;AAED,MAAM,WAAW,YAAY;IAC3B,QAAQ,EAAE,MAAM,CAAC;IACjB,WAAW,EAAE,MAAM,CAAC;IACpB,KAAK,EAAE,SAAS,MAAM,EAAE,CAAC;CAC1B"}
@@ -1 +1 @@
1
- {"version":3,"file":"catalog-materialization-service.d.ts","sourceRoot":"","sources":["../src/catalog-materialization-service.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"catalog-materialization-service.d.ts","sourceRoot":"","sources":["../src/catalog-materialization-service.ts"],"names":[],"mappings":"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"}
@@ -1,10 +1,20 @@
1
1
  import type { CatalogActor, CatalogOperation, CatalogSourceRecord } from './catalog-contracts.js';
2
2
  export interface CatalogPolicyDecision {
3
3
  allowed: boolean;
4
- reason?: 'teacher-material' | 'unverified-license' | 'operation-not-permitted';
4
+ reason?: 'teacher-material' | 'operator-only' | 'unverified-license' | 'operation-not-permitted';
5
+ }
6
+ export interface CatalogPolicyOptions {
7
+ /**
8
+ * Tenants (families) designated by the host operator that may see `operator`
9
+ * visibility records. Host configuration, never derived from a request; the
10
+ * default is none, so operator-only records are invisible to everyone.
11
+ */
12
+ operatorTenantIds?: Iterable<string>;
5
13
  }
6
14
  /** Server-side resource policy. UI affordances are advisory and cannot bypass it. */
7
15
  export declare class CatalogPolicy {
16
+ private readonly operatorTenants;
17
+ constructor(options?: CatalogPolicyOptions);
8
18
  canView(record: Pick<CatalogSourceRecord, 'visibility'>, actor: CatalogActor): boolean;
9
19
  authorize(record: Pick<CatalogSourceRecord, 'visibility' | 'licenseEvidence'>, operation: CatalogOperation, actor: CatalogActor): CatalogPolicyDecision;
10
20
  private isVerified;
@@ -1 +1 @@
1
- {"version":3,"file":"catalog-policy.d.ts","sourceRoot":"","sources":["../src/catalog-policy.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,YAAY,EAEZ,gBAAgB,EAChB,mBAAmB,EACpB,MAAM,wBAAwB,CAAC;AAEhC,MAAM,WAAW,qBAAqB;IACpC,OAAO,EAAE,OAAO,CAAC;IACjB,MAAM,CAAC,EACH,kBAAkB,GAClB,oBAAoB,GACpB,yBAAyB,CAAC;CAC/B;AAED,qFAAqF;AACrF,qBAAa,aAAa;IACxB,OAAO,CACL,MAAM,EAAE,IAAI,CAAC,mBAAmB,EAAE,YAAY,CAAC,EAC/C,KAAK,EAAE,YAAY,GAClB,OAAO;IAIV,SAAS,CACP,MAAM,EAAE,IAAI,CAAC,mBAAmB,EAAE,YAAY,GAAG,iBAAiB,CAAC,EACnE,SAAS,EAAE,gBAAgB,EAC3B,KAAK,EAAE,YAAY,GAClB,qBAAqB;IAWxB,OAAO,CAAC,UAAU;CAGnB"}
1
+ {"version":3,"file":"catalog-policy.d.ts","sourceRoot":"","sources":["../src/catalog-policy.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,YAAY,EAEZ,gBAAgB,EAChB,mBAAmB,EACpB,MAAM,wBAAwB,CAAC;AAEhC,MAAM,WAAW,qBAAqB;IACpC,OAAO,EAAE,OAAO,CAAC;IACjB,MAAM,CAAC,EACH,kBAAkB,GAClB,eAAe,GACf,oBAAoB,GACpB,yBAAyB,CAAC;CAC/B;AAED,MAAM,WAAW,oBAAoB;IACnC;;;;OAIG;IACH,iBAAiB,CAAC,EAAE,QAAQ,CAAC,MAAM,CAAC,CAAC;CACtC;AAED,qFAAqF;AACrF,qBAAa,aAAa;IACxB,OAAO,CAAC,QAAQ,CAAC,eAAe,CAAsB;gBAC1C,OAAO,GAAE,oBAAyB;IAQ9C,OAAO,CACL,MAAM,EAAE,IAAI,CAAC,mBAAmB,EAAE,YAAY,CAAC,EAC/C,KAAK,EAAE,YAAY,GAClB,OAAO;IASV,SAAS,CACP,MAAM,EAAE,IAAI,CAAC,mBAAmB,EAAE,YAAY,GAAG,iBAAiB,CAAC,EACnE,SAAS,EAAE,gBAAgB,EAC3B,KAAK,EAAE,YAAY,GAClB,qBAAqB;IAiBxB,OAAO,CAAC,UAAU;CAGnB"}
@@ -1,4 +1,5 @@
1
1
  import type { CatalogActor, CatalogSourceRecord } from './catalog-contracts.js';
2
+ import { CatalogPolicy } from './catalog-policy.js';
2
3
  /** Publisher preview permission is independent of original-resource permissions. */
3
4
  export interface CatalogPreview {
4
5
  providerId: 'illustrative-mathematics';
@@ -51,9 +52,13 @@ export interface CatalogPreviewLoader {
51
52
  export declare class CatalogPreviewService {
52
53
  private readonly store;
53
54
  private readonly loader;
55
+ /** Host policy carrying the operator families; the default shows operator records to nobody. */
56
+ private readonly policy;
54
57
  private readonly cache;
55
58
  private cacheBytes;
56
- constructor(store: CatalogPreviewStore, loader: CatalogPreviewLoader);
59
+ constructor(store: CatalogPreviewStore, loader: CatalogPreviewLoader,
60
+ /** Host policy carrying the operator families; the default shows operator records to nobody. */
61
+ policy?: CatalogPolicy);
57
62
  serve(input: {
58
63
  actor: CatalogActor;
59
64
  resourceId: string;
@@ -1 +1 @@
1
- {"version":3,"file":"catalog-preview.d.ts","sourceRoot":"","sources":["../src/catalog-preview.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,mBAAmB,EAAE,MAAM,wBAAwB,CAAC;AAGhF,oFAAoF;AACpF,MAAM,WAAW,cAAc;IAC7B,UAAU,EAAE,0BAA0B,CAAC;IACvC,QAAQ,EAAE,MAAM,CAAC;IACjB,QAAQ,EAAE,MAAM,CAAC;IACjB,4EAA4E;IAC5E,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,EAAE,WAAW,CAAC;IACvB,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;IACf,UAAU,EAAE,MAAM,CAAC;IACnB,MAAM,EAAE,MAAM,CAAC;IACf,GAAG,EAAE,MAAM,CAAC;IACZ,MAAM,EAAE;QACN,KAAK,EAAE,UAAU,CAAC;QAClB,UAAU,EAAE,WAAW,CAAC;QACxB,SAAS,EAAE,MAAM,CAAC;QAClB,WAAW,EAAE,MAAM,CAAC;QACpB,WAAW,EAAE,MAAM,CAAC;QACpB,SAAS,CAAC,EAAE,MAAM,CAAC;KACpB,CAAC;CACH;AAED,eAAO,MAAM,yBAAyB,QAAkB,CAAC;AACzD,eAAO,MAAM,6BAA6B,OAAO,CAAC;AAElD,oFAAoF;AACpF,wBAAgB,uBAAuB,CACrC,KAAK,EAAE,OAAO,GACb,cAAc,GAAG,SAAS,CAgF5B;AAED,oFAAoF;AACpF,wBAAgB,iBAAiB,CAC/B,MAAM,EAAE,IAAI,CACV,mBAAmB,EACnB,YAAY,GAAG,UAAU,GAAG,UAAU,GAAG,SAAS,CACnD,EACD,GAAG,SAAa,GACf,cAAc,GAAG,SAAS,CAS5B;AAED,yFAAyF;AACzF,wBAAgB,2BAA2B,CAAC,KAAK,EAAE,UAAU,GAAG;IAC9D,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;CAChB,CAqFA;AAED,MAAM,WAAW,mBAAmB;IAClC,6FAA6F;IAC7F,WAAW,CACT,EAAE,EAAE,MAAM,EACV,KAAK,EAAE,YAAY,GAClB,OAAO,CACN,CAAC,mBAAmB,GAAG;QAAE,EAAE,EAAE,MAAM,CAAC;QAAC,WAAW,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;KAAE,CAAC,GACnE,SAAS,CACZ,CAAC;IACF,uGAAuG;IACvG,SAAS,CACP,KAAK,EAAE,YAAY,EACnB,QAAQ,EAAE,mBAAmB,GAAG;QAAE,EAAE,EAAE,MAAM,CAAA;KAAE,GAC7C,OAAO,CAAC,OAAO,CAAC,CAAC;CACrB;AACD,MAAM,WAAW,oBAAoB;IACnC,4FAA4F;IAC5F,WAAW,CAAC,OAAO,EAAE,cAAc,GAAG,OAAO,CAAC,UAAU,CAAC,CAAC;CAC3D;AAED,uGAAuG;AACvG,qBAAa,qBAAqB;IAO9B,OAAO,CAAC,QAAQ,CAAC,KAAK;IACtB,OAAO,CAAC,QAAQ,CAAC,MAAM;IAPzB,OAAO,CAAC,QAAQ,CAAC,KAAK,CAGlB;IACJ,OAAO,CAAC,UAAU,CAAK;gBAEJ,KAAK,EAAE,mBAAmB,EAC1B,MAAM,EAAE,oBAAoB;IAGzC,KAAK,CAAC,KAAK,EAAE;QACjB,KAAK,EAAE,YAAY,CAAC;QACpB,UAAU,EAAE,MAAM,CAAC;QACnB,QAAQ,EAAE,MAAM,CAAC;KAClB,GAAG,OAAO,CAAC,QAAQ,CAAC;CA8FtB"}
1
+ {"version":3,"file":"catalog-preview.d.ts","sourceRoot":"","sources":["../src/catalog-preview.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,mBAAmB,EAAE,MAAM,wBAAwB,CAAC;AAChF,OAAO,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AAEpD,oFAAoF;AACpF,MAAM,WAAW,cAAc;IAC7B,UAAU,EAAE,0BAA0B,CAAC;IACvC,QAAQ,EAAE,MAAM,CAAC;IACjB,QAAQ,EAAE,MAAM,CAAC;IACjB,4EAA4E;IAC5E,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,EAAE,WAAW,CAAC;IACvB,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;IACf,UAAU,EAAE,MAAM,CAAC;IACnB,MAAM,EAAE,MAAM,CAAC;IACf,GAAG,EAAE,MAAM,CAAC;IACZ,MAAM,EAAE;QACN,KAAK,EAAE,UAAU,CAAC;QAClB,UAAU,EAAE,WAAW,CAAC;QACxB,SAAS,EAAE,MAAM,CAAC;QAClB,WAAW,EAAE,MAAM,CAAC;QACpB,WAAW,EAAE,MAAM,CAAC;QACpB,SAAS,CAAC,EAAE,MAAM,CAAC;KACpB,CAAC;CACH;AAED,eAAO,MAAM,yBAAyB,QAAkB,CAAC;AACzD,eAAO,MAAM,6BAA6B,OAAO,CAAC;AAElD,oFAAoF;AACpF,wBAAgB,uBAAuB,CACrC,KAAK,EAAE,OAAO,GACb,cAAc,GAAG,SAAS,CAgF5B;AAED,oFAAoF;AACpF,wBAAgB,iBAAiB,CAC/B,MAAM,EAAE,IAAI,CACV,mBAAmB,EACnB,YAAY,GAAG,UAAU,GAAG,UAAU,GAAG,SAAS,CACnD,EACD,GAAG,SAAa,GACf,cAAc,GAAG,SAAS,CAS5B;AAED,yFAAyF;AACzF,wBAAgB,2BAA2B,CAAC,KAAK,EAAE,UAAU,GAAG;IAC9D,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;CAChB,CAqFA;AAED,MAAM,WAAW,mBAAmB;IAClC,6FAA6F;IAC7F,WAAW,CACT,EAAE,EAAE,MAAM,EACV,KAAK,EAAE,YAAY,GAClB,OAAO,CACN,CAAC,mBAAmB,GAAG;QAAE,EAAE,EAAE,MAAM,CAAC;QAAC,WAAW,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;KAAE,CAAC,GACnE,SAAS,CACZ,CAAC;IACF,uGAAuG;IACvG,SAAS,CACP,KAAK,EAAE,YAAY,EACnB,QAAQ,EAAE,mBAAmB,GAAG;QAAE,EAAE,EAAE,MAAM,CAAA;KAAE,GAC7C,OAAO,CAAC,OAAO,CAAC,CAAC;CACrB;AACD,MAAM,WAAW,oBAAoB;IACnC,4FAA4F;IAC5F,WAAW,CAAC,OAAO,EAAE,cAAc,GAAG,OAAO,CAAC,UAAU,CAAC,CAAC;CAC3D;AAED,uGAAuG;AACvG,qBAAa,qBAAqB;IAO9B,OAAO,CAAC,QAAQ,CAAC,KAAK;IACtB,OAAO,CAAC,QAAQ,CAAC,MAAM;IACvB,gGAAgG;IAChG,OAAO,CAAC,QAAQ,CAAC,MAAM;IATzB,OAAO,CAAC,QAAQ,CAAC,KAAK,CAGlB;IACJ,OAAO,CAAC,UAAU,CAAK;gBAEJ,KAAK,EAAE,mBAAmB,EAC1B,MAAM,EAAE,oBAAoB;IAC7C,gGAAgG;IAC/E,MAAM,GAAE,aAAmC;IAGxD,KAAK,CAAC,KAAK,EAAE;QACjB,KAAK,EAAE,YAAY,CAAC;QACpB,UAAU,EAAE,MAAM,CAAC;QACnB,QAAQ,EAAE,MAAM,CAAC;KAClB,GAAG,OAAO,CAAC,QAAQ,CAAC;CA8FtB"}
@@ -0,0 +1,131 @@
1
+ //#region src/course-authoring-contracts.ts
2
+ var COURSE_AUTHORING_ACTIONS = [
3
+ "education.course.read-draft",
4
+ "education.course.author",
5
+ "education.course.generate",
6
+ "education.course.review",
7
+ "education.course.release",
8
+ "education.course.assign",
9
+ "education.course.archive",
10
+ "education.course.set-visibility",
11
+ "education.course.set-cover"
12
+ ];
13
+ var COURSE_PROVENANCES = [
14
+ "supplied",
15
+ "generated",
16
+ "edited",
17
+ "extracted"
18
+ ];
19
+ var MAX_PAGE_SIZE = 100;
20
+ var DEFAULT_PAGE_SIZE = 50;
21
+ var CourseAuthoringError = class extends Error {
22
+ constructor(code, message) {
23
+ super(message);
24
+ this.code = code;
25
+ this.name = new.target.name;
26
+ }
27
+ code;
28
+ };
29
+ var CourseAuthoringAuthorizationError = class extends CourseAuthoringError {
30
+ constructor() {
31
+ super("not-authorized", "Course authoring access is not authorized.");
32
+ }
33
+ };
34
+ var CourseAuthoringValidationError = class extends CourseAuthoringError {
35
+ constructor(message) {
36
+ super("invalid-request", message);
37
+ }
38
+ };
39
+ var CourseNotFoundError = class extends CourseAuthoringError {
40
+ constructor() {
41
+ super("course-not-found", "Course was not found.");
42
+ }
43
+ };
44
+ var CourseDiscardedError = class extends CourseAuthoringError {
45
+ constructor() {
46
+ super("course-discarded", "Course draft was discarded.");
47
+ }
48
+ };
49
+ var CourseArchivedError = class extends CourseAuthoringError {
50
+ constructor() {
51
+ super("course-archived", "Course is archived; unarchive it first.");
52
+ }
53
+ };
54
+ var CourseAppendRefusedError = class extends CourseAuthoringError {
55
+ constructor(reason) {
56
+ super("append-refused", `Lesson append refused: ${reason}.`);
57
+ this.reason = reason;
58
+ }
59
+ reason;
60
+ };
61
+ var CourseStaleHeadError = class extends CourseAuthoringError {
62
+ constructor(currentHeadRevisionId) {
63
+ super("stale-head", "The draft head moved; reload and retry.");
64
+ this.currentHeadRevisionId = currentHeadRevisionId;
65
+ }
66
+ currentHeadRevisionId;
67
+ };
68
+ var CoursePolicyBasisMismatchError = class extends CourseAuthoringError {
69
+ constructor() {
70
+ super("policy-basis-mismatch", "The supplied policy basis differs from the one the authorizer relied on.");
71
+ }
72
+ };
73
+ var CourseRequestKeyConflictError = class extends CourseAuthoringError {
74
+ constructor() {
75
+ super("request-key-conflict", "The request key was already used for a different request.");
76
+ }
77
+ };
78
+ var ReviewGateRequiredError = class extends CourseAuthoringError {
79
+ constructor() {
80
+ super("review-gate-required", "Release requires a configured review gate; none is configured.");
81
+ }
82
+ };
83
+ var ReviewNotCurrentError = class extends CourseAuthoringError {
84
+ constructor(reason) {
85
+ super("review-not-current", "Release requires a current review of this exact revision.");
86
+ this.reason = reason;
87
+ }
88
+ reason;
89
+ };
90
+ var CourseRevisionAlreadyReleasedError = class extends CourseAuthoringError {
91
+ constructor(releaseId) {
92
+ super("revision-already-released", "This revision is already released.");
93
+ this.releaseId = releaseId;
94
+ }
95
+ releaseId;
96
+ };
97
+ var CourseDiscardRefusedError = class extends CourseAuthoringError {
98
+ constructor(references) {
99
+ super("discard-refused", "Only drafts with no release, enrollment, attempt, review or variant can be discarded.");
100
+ this.references = references;
101
+ }
102
+ references;
103
+ };
104
+ var EnrollmentPinConflictError = class extends CourseAuthoringError {
105
+ constructor(message = "Enrollment pin request conflicts with current state.") {
106
+ super("enrollment-pin-conflict", message);
107
+ }
108
+ };
109
+ var CourseMaterialCopyError = class extends CourseAuthoringError {
110
+ constructor(message = "Course material could not be copied to an owned asset.") {
111
+ super("material-copy-failed", message);
112
+ }
113
+ };
114
+ var CourseVisibilityRefusedError = class extends CourseAuthoringError {
115
+ constructor(visibility) {
116
+ super("visibility-refused", "A personal-use course can only be family-visible.");
117
+ this.visibility = visibility;
118
+ }
119
+ visibility;
120
+ };
121
+ var CourseCoverInvalidError = class extends CourseAuthoringError {
122
+ constructor(reason) {
123
+ super("cover-invalid", "The cover must be a readable education-owned image.");
124
+ this.reason = reason;
125
+ }
126
+ reason;
127
+ };
128
+ //#endregion
129
+ export { ReviewNotCurrentError as S, CourseVisibilityRefusedError as _, CourseAuthoringAuthorizationError as a, MAX_PAGE_SIZE as b, CourseCoverInvalidError as c, CourseMaterialCopyError as d, CourseNotFoundError as f, CourseStaleHeadError as g, CourseRevisionAlreadyReleasedError as h, CourseArchivedError as i, CourseDiscardRefusedError as l, CourseRequestKeyConflictError as m, COURSE_PROVENANCES as n, CourseAuthoringError as o, CoursePolicyBasisMismatchError as p, CourseAppendRefusedError as r, CourseAuthoringValidationError as s, COURSE_AUTHORING_ACTIONS as t, CourseDiscardedError as u, DEFAULT_PAGE_SIZE as v, ReviewGateRequiredError as x, EnrollmentPinConflictError as y };
130
+
131
+ //# sourceMappingURL=course-authoring-contracts-C4Hqba-e.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"course-authoring-contracts-C4Hqba-e.js","names":[],"sources":["../../src/course-authoring-contracts.ts"],"sourcesContent":["import type { DatabaseInterface } from '@happyvertical/sql';\nimport type {\n CourseLicenseKind,\n CourseModality,\n CourseVisibility,\n} from './catalog.js';\nimport type {\n LessonAssetRelationship,\n MaterialAudience,\n} from './lesson-assets.js';\nimport type {\n LessonLayoutParams,\n LessonQuestionRefInput,\n} from './question-contracts.js';\n\n/** Authorizer actions. The host maps roles; the service never infers a role. */\nexport type CourseAuthoringAction =\n | 'education.course.read-draft'\n | 'education.course.author'\n | 'education.course.generate'\n | 'education.course.review'\n | 'education.course.release'\n | 'education.course.assign'\n | 'education.course.archive'\n | 'education.course.set-visibility'\n | 'education.course.set-cover';\n\nexport const COURSE_AUTHORING_ACTIONS: readonly CourseAuthoringAction[] = [\n 'education.course.read-draft',\n 'education.course.author',\n 'education.course.generate',\n 'education.course.review',\n 'education.course.release',\n 'education.course.assign',\n 'education.course.archive',\n 'education.course.set-visibility',\n 'education.course.set-cover',\n];\n\n/** Which service operation asked, so a host can deny agents specific operations. */\nexport type CourseAuthoringOperation =\n | 'create'\n | 'save-draft'\n | 'append-lesson'\n | 'read-draft'\n | 'release'\n | 'archive'\n | 'unarchive'\n | 'set-visibility'\n | 'set-cover'\n | 'discard'\n | 'pin-enrollment'\n | 'upgrade-enrollment'\n | 'set-auto-upgrade'\n | 'auto-upgrade'\n | 'read-enrollment'\n | 'create-question'\n | 'save-question'\n | 'read-question'\n | 'resolve-question-revisions'\n | 'create-objective'\n | 'save-objective'\n | 'link-objectives'\n | 'read-worksheet'\n | 'request-generation'\n | 'run-generation'\n | 'cancel-generation'\n | 'accept-proposal'\n | 'read-generation'\n | 'record-review'\n | 'read-review'\n | 'resolve-finding'\n | 'note-context-change'\n | 'list-courses'\n | 'list-upgrade-choices'\n | 'list-auto-upgrade-skips'\n | 'read-released-lesson'\n | 'attach-printable'\n | 'preserve-question-extraction'\n | 'read-question-extraction'\n | 'apply-question-extraction'\n | 'import-course-bundle'\n | 'read-course-bundle'\n | 'retry-course-bundle-rendering'\n | 'apply-course-bundle-materials';\n\n/** Trusted identity supplied by the host session, never by a browser form. */\nexport interface CourseAuthoringActor {\n tenantId: string;\n actorUserId: string;\n /** Agent calls: the guardian whose delegation the host re-validates per check. */\n delegatingGuardianUserId?: string;\n /**\n * Host-supplied opaque delegation id (1-200 printable characters), required\n * with, and only with, `delegatingGuardianUserId`. Recorded on every decision\n * and passed to every authorizer call; it grants nothing by itself.\n */\n delegationId?: string;\n}\n\n/**\n * A richer authorizer answer. `reason` (at most 200 characters) and `code` (a\n * short token, at most 64 characters of `[a-z0-9._-]`) are recorded on an\n * auto-upgrade skip when `allowed` is false; invalid values are dropped, never\n * thrown. A plain `boolean` stays valid everywhere.\n */\nexport interface CourseAuthorizationDecision {\n allowed: boolean;\n reason?: string;\n code?: string;\n /**\n * `education.course.assign` only: the assignment-setting value the host relied\n * on (1-200 printable characters). It becomes the recorded policy basis for pin,\n * upgrade and opt-in rows, replacing the caller-supplied one; if the caller also\n * sent one it must be equal (`CoursePolicyBasisMismatchError`). Ignored for other\n * actions. An invalid value is a validation error and nothing is written.\n */\n policyBasis?: string;\n}\n\n/** Result of a host delegation check; a bare boolean is accepted as well. */\nexport type CourseDelegationDecision =\n | boolean\n | { allowed: boolean; reason?: string; code?: string };\n\n/**\n * Host port that verifies a delegation (the agent may act for the guardian under\n * this id) on the supplied transaction executor. Without it every delegated\n * request is refused; it runs before the host authorizer and never grants by\n * itself.\n */\nexport type CourseDelegationVerifier = (\n executor: DatabaseInterface,\n request: {\n tenantId: string;\n actorUserId: string;\n delegatingGuardianUserId: string;\n delegationId: string;\n action: CourseAuthoringAction;\n operation: CourseAuthoringOperation;\n courseId?: string;\n enrollmentId?: string;\n learnerId?: string;\n /** Pin and upgrade only: the target release and its materialized course. */\n releaseId?: string;\n releaseCourseId?: string;\n },\n) => CourseDelegationDecision | Promise<CourseDelegationDecision>;\n\nexport type CourseAuthoringAuthorizer = (\n request: CourseAuthoringActor & {\n action: CourseAuthoringAction;\n operation: CourseAuthoringOperation;\n /** The active service executor; host policy reads must share its transaction. */\n executor: DatabaseInterface;\n courseId?: string;\n enrollmentId?: string;\n learnerId?: string;\n /** Pin and upgrade only: the target release and its materialized course. */\n releaseId?: string;\n releaseCourseId?: string;\n },\n) =>\n | boolean\n | CourseAuthorizationDecision\n | Promise<boolean | CourseAuthorizationDecision>;\n\nexport type CourseProvenance =\n | 'supplied'\n | 'generated'\n | 'edited'\n | 'extracted';\nexport const COURSE_PROVENANCES: readonly CourseProvenance[] = [\n 'supplied',\n 'generated',\n 'edited',\n 'extracted',\n];\nexport type CourseLessonType = 'reading' | 'video' | 'worksheet' | 'exercise';\nexport type CourseLessonCompletion = 'attest' | 'submit' | 'score' | 'external';\n\n/** Hook supplied by #4516; the service never treats an absent gate as a pass. */\nexport type ReleaseReviewGate = (\n executor: DatabaseInterface,\n request: { tenantId: string; courseId: string; revisionId: string },\n) =>\n | { current: boolean; reviewId?: string; reason?: string }\n | Promise<{ current: boolean; reviewId?: string; reason?: string }>;\n\n/** Hook supplied by #4516/variants: report review/variant rows that reference a draft. */\nexport type CourseReferenceGuard = (\n executor: DatabaseInterface,\n request: { tenantId: string; courseId: string },\n) =>\n | { referenced: boolean; kinds?: readonly string[] }\n | Promise<{ referenced: boolean; kinds?: readonly string[] }>;\n\n/** Copies an upload (for example an ingestion item) to an education-owned asset. */\nexport interface CourseMaterialSource {\n kind: string;\n ref: string;\n}\nexport interface CourseMaterialCopyRequest {\n tenantId: string;\n actorUserId: string;\n courseId: string;\n source: CourseMaterialSource;\n relationship: LessonAssetRelationship;\n}\nexport interface CourseMaterialCopyPort {\n /** Must return an asset owned by the same tenant, independent of the source's expiry. */\n copy(\n executor: DatabaseInterface,\n request: CourseMaterialCopyRequest,\n ): Promise<{ assetId: string }>;\n}\n\nexport interface CourseMaterialInput {\n /** Uploaded material to copy; mutually exclusive with `assetId`. */\n source?: CourseMaterialSource;\n /** Reuse an asset already copied into this course by an earlier revision. */\n assetId?: string;\n relationship: LessonAssetRelationship;\n licenseKind?: CourseLicenseKind;\n /** Who it is for; omitted means the role default (`LESSON_ASSET_DEFAULT_AUDIENCE`). */\n audience?: MaterialAudience;\n}\nexport interface CourseMaterialView {\n assetId: string;\n relationship: LessonAssetRelationship;\n /** Stated audience; absent means the role default. */\n audience?: MaterialAudience;\n licenseKind: CourseLicenseKind;\n provenance: {\n source: CourseMaterialSource | null;\n copiedAt: string;\n copiedByUserId: string;\n };\n}\n\nexport interface CourseLessonInput {\n /** Stable cross-version identity; omit for a new lesson. */\n lessonKey?: string;\n title: string;\n body?: string;\n lessonType?: CourseLessonType;\n completionRule?: CourseLessonCompletion;\n estimatedMinutes?: number;\n difficulty?: number;\n modality?: CourseModality;\n externalRef?: string;\n externalUrl?: string;\n licenseKind?: CourseLicenseKind;\n provenance?: CourseProvenance;\n fieldProvenance?: Record<string, CourseProvenance>;\n materials?: CourseMaterialInput[];\n /** Ordered immutable question revisions; each must exist in this tenant. */\n questions?: LessonQuestionRefInput[];\n /** Flat render parameters folded into the worksheet version id. */\n layoutParams?: LessonLayoutParams;\n}\nexport interface CourseSectionInput {\n sectionKey: string;\n title: string;\n lessons: CourseLessonInput[];\n}\nexport interface CourseDraftInput {\n title: string;\n summary?: string;\n subject?: string;\n theme?: string;\n levelMin?: number;\n levelMax?: number;\n objectives?: string[];\n sections: CourseSectionInput[];\n provenance: CourseProvenance;\n fieldProvenance?: Record<string, CourseProvenance>;\n}\n\nexport interface CourseLessonRevisionView {\n id: string;\n lessonKey: string;\n parentRevisionId: string | null;\n title: string;\n body: string;\n lessonType: CourseLessonType;\n completionRule: CourseLessonCompletion;\n estimatedMinutes: number;\n difficulty: number;\n modality: CourseModality;\n externalRef: string;\n externalUrl: string;\n licenseKind: CourseLicenseKind;\n provenance: CourseProvenance;\n fieldProvenance: Record<string, CourseProvenance>;\n materials: CourseMaterialView[];\n questions: LessonQuestionRefInput[];\n layoutParams: LessonLayoutParams;\n}\n/** Alias for hosts: a lesson revision as read by the authoring views. */\nexport type LessonRevisionView = CourseLessonRevisionView;\nexport interface CourseRevisionView {\n id: string;\n courseId: string;\n parentRevisionId: string | null;\n sequence: number;\n title: string;\n summary: string;\n subject: string;\n theme: string;\n levelMin: number;\n levelMax: number;\n objectives: string[];\n licenseKind: CourseLicenseKind;\n provenance: CourseProvenance;\n fieldProvenance: Record<string, CourseProvenance>;\n authorUserId: string;\n delegatingGuardianUserId: string | null;\n delegationId: string | null;\n recordedAt: string;\n sections: Array<{\n sectionKey: string;\n title: string;\n lessons: CourseLessonRevisionView[];\n }>;\n}\nexport interface CourseHeadView {\n courseId: string;\n /** The expected-head token for the next save. */\n headRevisionId: string;\n version: number;\n}\n/** Result of `appendLesson`: the new revision and, unless skipped, its release. */\nexport type CourseAppendLessonView = Readonly<{\n courseId: string;\n /** The appended revision; the new draft head. */\n revisionId: string;\n version: number;\n lessonKey: string;\n /** The release of that revision; null when `release: false` was requested. */\n release: CourseReleaseView | null;\n}>;\n\nexport type CourseReleaseView = Readonly<{\n id: string;\n courseId: string;\n revisionId: string;\n releaseNumber: number;\n releaseCourseId: string;\n /** The cover snapshotted onto this release; null when the course had none. */\n coverAssetId: string | null;\n reviewId: string | null;\n actorUserId: string;\n delegatingGuardianUserId: string | null;\n delegationId: string | null;\n /** The host setting the release relied on (for example an auto-approve); null if none. */\n policyBasis: string | null;\n recordedAt: string;\n lessons: ReadonlyArray<{\n lessonKey: string;\n lessonRevisionId: string;\n lessonId: string;\n sectionId: string;\n }>;\n}>;\nexport type CourseLifecycleState =\n | 'draft'\n | 'released'\n | 'archived'\n | 'discarded';\nexport type CourseStateView = Readonly<{\n courseId: string;\n title: string;\n state: CourseLifecycleState;\n licenseKind: CourseLicenseKind;\n /** Personal-use material makes the course tenant-private and never group-shareable. */\n groupShareable: boolean;\n /** `family` unless set otherwise (see `setVisibility`). */\n visibility: CourseVisibility;\n /** The education-owned cover image asset, or null (hosts render a fallback). */\n coverAssetId: string | null;\n headRevisionId: string | null;\n releases: ReadonlyArray<{\n id: string;\n releaseNumber: number;\n revisionId: string;\n releaseCourseId: string;\n }>;\n}>;\n/** Largest page a list read returns; the default is `DEFAULT_PAGE_SIZE`. */\nexport const MAX_PAGE_SIZE = 100;\nexport const DEFAULT_PAGE_SIZE = 50;\n\n/** Opaque, deterministic pagination: pass back `nextCursor` unchanged. */\nexport interface CoursePageRequest {\n limit?: number;\n cursor?: string;\n}\nexport type CoursePage<T> = Readonly<{\n items: ReadonlyArray<T>;\n /** Null on the last page. */\n nextCursor: string | null;\n}>;\n\nexport type CourseArchiveDecisionView = Readonly<{\n action: 'archive' | 'unarchive';\n sequence: number;\n actorUserId: string;\n delegatingGuardianUserId: string | null;\n delegationId: string | null;\n recordedAt: string;\n}>;\n/** One authored course in `listCourses`. */\nexport type CourseSummaryView = Readonly<{\n courseId: string;\n title: string;\n state: CourseLifecycleState;\n createdAt: string;\n /**\n * Effective licence: the most restrictive of the head revision and every release's\n * materialized course, so a restriction recorded by any release never loosens.\n * `CourseStateView.licenseKind` reads the head alone and may be looser.\n */\n licenseKind: CourseLicenseKind;\n /**\n * The group-sharing rule applied to this course: false for personal-use and\n * false until the course has a release (nothing to share).\n */\n groupShareable: boolean;\n visibility: CourseVisibility;\n coverAssetId: string | null;\n /** Number of releases (0 for a draft-only course). */\n releaseCount: number;\n /** The draft head; `revisionId` is the expected-head token for the next save. */\n head: Readonly<{\n revisionId: string;\n sequence: number;\n version: number;\n }> | null;\n latestRelease: Readonly<{\n id: string;\n revisionId: string;\n releaseNumber: number;\n releaseCourseId: string;\n /** The cover snapshotted onto that release. */\n coverAssetId: string | null;\n recordedAt: string;\n }> | null;\n archive: Readonly<{\n archived: boolean;\n latestDecision: CourseArchiveDecisionView | null;\n }>;\n}>;\n\nexport type CourseUpgradeChoiceView = Readonly<{\n id: string;\n courseId: string;\n scope: 'course' | 'enrollment';\n /** Null for a course-level choice. */\n enrollmentId: string | null;\n enabled: boolean;\n kind: 'opt-in' | 'opt-out';\n sequence: number;\n actorUserId: string;\n delegatingGuardianUserId: string | null;\n delegationId: string | null;\n policyBasis: string;\n recordedAt: string;\n}>;\n\nexport type AutoUpgradeSkipView = Readonly<{\n id: string;\n enrollmentId: string;\n learnerId: string;\n courseId: string;\n releaseId: string;\n optInScope: 'course' | 'enrollment';\n optInActorUserId: string;\n optInDelegatingGuardianUserId: string | null;\n optInDelegationId: string | null;\n policyBasis: string;\n /** The authorizer's reason when it gave one, else `not-authorized`. */\n reason: string;\n /** The authorizer's short code, or an empty string. */\n code: string;\n recordedAt: string;\n}>;\n\nexport type EnrollmentPinKind = 'initial' | 'explicit' | 'auto';\nexport type EnrollmentPinView = Readonly<{\n enrollmentId: string;\n /** The enrollment's learner, from the enrollment row; hosts never read `enrollments`. */\n learnerId: string;\n /** The authored course identity (`AuthoredCourse` id) the pin follows. */\n courseId: string;\n releaseId: string;\n /** The materialized release `Course` id the enrollment is created on. */\n releaseCourseId: string;\n releaseNumber: number;\n kind: EnrollmentPinKind;\n autoUpgrade: boolean;\n /** Assignment-setting value the host relied on for the current pin. */\n policyBasis: string;\n history: ReadonlyArray<{\n releaseId: string;\n releaseCourseId: string;\n previousReleaseId: string | null;\n kind: EnrollmentPinKind;\n sequence: number;\n actorUserId: string | null;\n delegatingGuardianUserId: string | null;\n delegationId: string | null;\n policyBasis: string;\n /** For automatic moves: the scope of the opt-in followed. */\n optInScope: 'course' | 'enrollment' | null;\n recordedAt: string;\n }>;\n}>;\n/** Result of `getEnrollmentRelease`; identity fields repeat the pin's for convenience. */\nexport type EnrollmentReleaseView = Readonly<{\n learnerId: string;\n courseId: string;\n releaseCourseId: string;\n pin: EnrollmentPinView;\n lessons: EffectiveLessonView[];\n}>;\n/** Result of `setAutoUpgrade`; `learnerId` is null for a course-level choice. */\nexport type SetAutoUpgradeResult = Readonly<{\n courseId: string;\n enrollmentId: string | null;\n learnerId: string | null;\n enabled: boolean;\n policyBasis: string;\n}>;\nexport type EffectiveLessonView = Readonly<{\n lessonKey: string;\n lessonId: string;\n releaseId: string;\n /** True when a started lesson stays on an older release than the current pin. */\n pinnedToOlderRelease: boolean;\n}>;\n\nexport class CourseAuthoringError extends Error {\n constructor(\n readonly code: string,\n message: string,\n ) {\n super(message);\n this.name = new.target.name;\n }\n}\nexport class CourseAuthoringAuthorizationError extends CourseAuthoringError {\n constructor() {\n super('not-authorized', 'Course authoring access is not authorized.');\n }\n}\nexport class CourseAuthoringValidationError extends CourseAuthoringError {\n constructor(message: string) {\n super('invalid-request', message);\n }\n}\nexport class CourseNotFoundError extends CourseAuthoringError {\n constructor() {\n super('course-not-found', 'Course was not found.');\n }\n}\nexport class CourseDiscardedError extends CourseAuthoringError {\n constructor() {\n super('course-discarded', 'Course draft was discarded.');\n }\n}\nexport class CourseArchivedError extends CourseAuthoringError {\n constructor() {\n super('course-archived', 'Course is archived; unarchive it first.');\n }\n}\n/**\n * `appendLesson` was refused for the course's state: it has no release yet\n * (`not-released`), its head holds changes that are not released\n * (`unreleased-changes`), or the lesson key or section is already taken\n * (`duplicate-lesson`).\n */\nexport class CourseAppendRefusedError extends CourseAuthoringError {\n constructor(\n readonly reason: 'not-released' | 'unreleased-changes' | 'duplicate-lesson',\n ) {\n super('append-refused', `Lesson append refused: ${reason}.`);\n }\n}\nexport class CourseStaleHeadError extends CourseAuthoringError {\n constructor(readonly currentHeadRevisionId: string) {\n super('stale-head', 'The draft head moved; reload and retry.');\n }\n}\n/** The caller and the assign authorizer named different policy bases. */\nexport class CoursePolicyBasisMismatchError extends CourseAuthoringError {\n constructor() {\n super(\n 'policy-basis-mismatch',\n 'The supplied policy basis differs from the one the authorizer relied on.',\n );\n }\n}\nexport class CourseRequestKeyConflictError extends CourseAuthoringError {\n constructor() {\n super(\n 'request-key-conflict',\n 'The request key was already used for a different request.',\n );\n }\n}\nexport class ReviewGateRequiredError extends CourseAuthoringError {\n constructor() {\n super(\n 'review-gate-required',\n 'Release requires a configured review gate; none is configured.',\n );\n }\n}\nexport class ReviewNotCurrentError extends CourseAuthoringError {\n constructor(readonly reason?: string) {\n super(\n 'review-not-current',\n 'Release requires a current review of this exact revision.',\n );\n }\n}\nexport class CourseRevisionAlreadyReleasedError extends CourseAuthoringError {\n constructor(readonly releaseId: string) {\n super('revision-already-released', 'This revision is already released.');\n }\n}\nexport class CourseDiscardRefusedError extends CourseAuthoringError {\n constructor(readonly references: readonly string[]) {\n super(\n 'discard-refused',\n 'Only drafts with no release, enrollment, attempt, review or variant can be discarded.',\n );\n }\n}\nexport class EnrollmentPinConflictError extends CourseAuthoringError {\n constructor(\n message = 'Enrollment pin request conflicts with current state.',\n ) {\n super('enrollment-pin-conflict', message);\n }\n}\nexport class CourseMaterialCopyError extends CourseAuthoringError {\n constructor(\n message = 'Course material could not be copied to an owned asset.',\n ) {\n super('material-copy-failed', message);\n }\n}\n\n/** Result of `setVisibility`/`setCover`: the course state after the (maybe unchanged) write. */\nexport type CourseVisibilityResult = CourseStateView;\nexport type CourseCoverResult = CourseStateView;\n\n/** A personal-use-copy course can never be shared with groups or listed publicly. */\nexport class CourseVisibilityRefusedError extends CourseAuthoringError {\n constructor(readonly visibility: CourseVisibility) {\n super(\n 'visibility-refused',\n 'A personal-use course can only be family-visible.',\n );\n }\n}\n/** The cover asset is missing, foreign, not an image, an answer key or unreadable. */\nexport class CourseCoverInvalidError extends CourseAuthoringError {\n constructor(readonly reason: string) {\n super(\n 'cover-invalid',\n 'The cover must be a readable education-owned image.',\n );\n }\n}\n"],"mappings":";AA2BO,IAAM,2BAA6D;CACxE;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;AACF;AAuIO,IAAM,qBAAkD;CAC7D;CACA;CACA;CACA;AACF;AAqNO,IAAM,gBAAgB;AACtB,IAAM,oBAAoB;AAuJ1B,IAAM,uBAAN,cAAmC,MAAM;CAC9C,YACW,MACT,SACA;EACA,MAAM,OAAO;EAHJ,KAAA,OAAA;EAIT,KAAK,OAAO,IAAA,OAAW;CACzB;CALW;AAMb;AACO,IAAM,oCAAN,cAAgD,qBAAqB;CAC1E,cAAc;EACZ,MAAM,kBAAkB,4CAA4C;CACtE;AACF;AACO,IAAM,iCAAN,cAA6C,qBAAqB;CACvE,YAAY,SAAiB;EAC3B,MAAM,mBAAmB,OAAO;CAClC;AACF;AACO,IAAM,sBAAN,cAAkC,qBAAqB;CAC5D,cAAc;EACZ,MAAM,oBAAoB,uBAAuB;CACnD;AACF;AACO,IAAM,uBAAN,cAAmC,qBAAqB;CAC7D,cAAc;EACZ,MAAM,oBAAoB,6BAA6B;CACzD;AACF;AACO,IAAM,sBAAN,cAAkC,qBAAqB;CAC5D,cAAc;EACZ,MAAM,mBAAmB,yCAAyC;CACpE;AACF;AAOO,IAAM,2BAAN,cAAuC,qBAAqB;CACjE,YACW,QACT;EACA,MAAM,kBAAkB,0BAA0B,OAAM,EAAG;EAFlD,KAAA,SAAA;CAGX;CAHW;AAIb;AACO,IAAM,uBAAN,cAAmC,qBAAqB;CAC7D,YAAqB,uBAA+B;EAClD,MAAM,cAAc,yCAAyC;EAD1C,KAAA,wBAAA;CAErB;CAFqB;AAGvB;AAEO,IAAM,iCAAN,cAA6C,qBAAqB;CACvE,cAAc;EACZ,MACE,yBACA,0EACF;CACF;AACF;AACO,IAAM,gCAAN,cAA4C,qBAAqB;CACtE,cAAc;EACZ,MACE,wBACA,2DACF;CACF;AACF;AACO,IAAM,0BAAN,cAAsC,qBAAqB;CAChE,cAAc;EACZ,MACE,wBACA,gEACF;CACF;AACF;AACO,IAAM,wBAAN,cAAoC,qBAAqB;CAC9D,YAAqB,QAAiB;EACpC,MACE,sBACA,2DACF;EAJmB,KAAA,SAAA;CAKrB;CALqB;AAMvB;AACO,IAAM,qCAAN,cAAiD,qBAAqB;CAC3E,YAAqB,WAAmB;EACtC,MAAM,6BAA6B,oCAAoC;EADpD,KAAA,YAAA;CAErB;CAFqB;AAGvB;AACO,IAAM,4BAAN,cAAwC,qBAAqB;CAClE,YAAqB,YAA+B;EAClD,MACE,mBACA,uFACF;EAJmB,KAAA,aAAA;CAKrB;CALqB;AAMvB;AACO,IAAM,6BAAN,cAAyC,qBAAqB;CACnE,YACE,UAAU,wDACV;EACA,MAAM,2BAA2B,OAAO;CAC1C;AACF;AACO,IAAM,0BAAN,cAAsC,qBAAqB;CAChE,YACE,UAAU,0DACV;EACA,MAAM,wBAAwB,OAAO;CACvC;AACF;AAOO,IAAM,+BAAN,cAA2C,qBAAqB;CACrE,YAAqB,YAA8B;EACjD,MACE,sBACA,mDACF;EAJmB,KAAA,aAAA;CAKrB;CALqB;AAMvB;AAEO,IAAM,0BAAN,cAAsC,qBAAqB;CAChE,YAAqB,QAAgB;EACnC,MACE,iBACA,qDACF;EAJmB,KAAA,SAAA;CAKrB;CALqB;AAMvB"}