@intellectif/lk-core 0.12.0 → 0.13.1

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 (51) hide show
  1. package/CHANGELOG.md +36 -0
  2. package/README.md +2 -1
  3. package/dist/{activity-B2QxK15j.d.cts → activity-DfAmJ1sl.d.cts} +134 -7
  4. package/dist/{activity-B2QxK15j.d.ts → activity-DfAmJ1sl.d.ts} +134 -7
  5. package/dist/{chunk-VYE6BYON.cjs → chunk-DQKJUMUW.cjs} +38 -15
  6. package/dist/chunk-DQKJUMUW.cjs.map +1 -0
  7. package/dist/{chunk-RK2NVTHZ.js → chunk-FGN4LLSP.js} +50 -6
  8. package/dist/chunk-FGN4LLSP.js.map +1 -0
  9. package/dist/{chunk-O2IVKTHV.cjs → chunk-FT7SAC3X.cjs} +4 -4
  10. package/dist/{chunk-O2IVKTHV.cjs.map → chunk-FT7SAC3X.cjs.map} +1 -1
  11. package/dist/{chunk-UQPNJP2O.js → chunk-PYP3HCRQ.js} +2 -2
  12. package/dist/{chunk-4OHWLCI6.cjs → chunk-UHQVIC3P.cjs} +58 -14
  13. package/dist/chunk-UHQVIC3P.cjs.map +1 -0
  14. package/dist/{chunk-FVN37GIH.js → chunk-XKKKWKRH.js} +1944 -177
  15. package/dist/chunk-XKKKWKRH.js.map +1 -0
  16. package/dist/{chunk-J6POE4HL.cjs → chunk-XONKWL6D.cjs} +1785 -18
  17. package/dist/chunk-XONKWL6D.cjs.map +1 -0
  18. package/dist/{chunk-7JMMPE7O.js → chunk-Y36S3X3L.js} +26 -3
  19. package/dist/chunk-Y36S3X3L.js.map +1 -0
  20. package/dist/{index-B_scInLM.d.cts → index-BefQ8FAS.d.cts} +192 -15
  21. package/dist/{index-CRKtWP5G.d.ts → index-BiIvdASA.d.ts} +192 -15
  22. package/dist/index.cjs +132 -74
  23. package/dist/index.cjs.map +1 -1
  24. package/dist/index.d.cts +19 -6
  25. package/dist/index.d.ts +19 -6
  26. package/dist/index.js +64 -6
  27. package/dist/index.js.map +1 -1
  28. package/dist/schemas.cjs +17 -3
  29. package/dist/schemas.cjs.map +1 -1
  30. package/dist/schemas.d.cts +2 -2
  31. package/dist/schemas.d.ts +2 -2
  32. package/dist/schemas.js +16 -2
  33. package/dist/scoring.cjs +19 -3
  34. package/dist/scoring.cjs.map +1 -1
  35. package/dist/scoring.d.cts +150 -5
  36. package/dist/scoring.d.ts +150 -5
  37. package/dist/scoring.js +18 -2
  38. package/dist/xapi.cjs +3 -3
  39. package/dist/xapi.d.cts +1 -1
  40. package/dist/xapi.d.ts +1 -1
  41. package/dist/xapi.js +2 -2
  42. package/package.json +1 -1
  43. package/vectors/README.md +9 -1
  44. package/vectors/scoring.json +12023 -1
  45. package/dist/chunk-4OHWLCI6.cjs.map +0 -1
  46. package/dist/chunk-7JMMPE7O.js.map +0 -1
  47. package/dist/chunk-FVN37GIH.js.map +0 -1
  48. package/dist/chunk-J6POE4HL.cjs.map +0 -1
  49. package/dist/chunk-RK2NVTHZ.js.map +0 -1
  50. package/dist/chunk-VYE6BYON.cjs.map +0 -1
  51. /package/dist/{chunk-UQPNJP2O.js.map → chunk-PYP3HCRQ.js.map} +0 -0
package/CHANGELOG.md CHANGED
@@ -1,5 +1,41 @@
1
1
  # @intellectif/lk-core
2
2
 
3
+ ## 0.13.1
4
+
5
+ ### Patch Changes
6
+
7
+ - 551b900: `validateItemGroupDraft` no longer reports a registered item type as unknown when that type's own checks throw.
8
+
9
+ Every item in a group is checked by `validateDraft` for its own type. Any error thrown on the way was caught and reported as `ig_item_type_unknown` — `"<type>" is not a registered activity type.` — a code documented for a type nobody registered. So a registered type whose `checkDraft` threw for some other reason, such as a bug in the check or input that took it past a limit like a regular expression too large to compile, was reported as unknown; so was one whose schema threw, whenever the group around it failed its own schema — a missing stimulus, say, or two questions sharing an id. An editor showed the author a problem the draft did not have, and the real error was hidden.
10
+
11
+ Now only an `UnknownActivityTypeError` for the item's own type is reported. Any other error is thrown from `validateItemGroupDraft`, whatever state the rest of the group is in, as `validateDraft` already throws it for the same item on its own. (`validateItemGroup` throws a schema's error too, but only once the group around the item passes its own schema.) An unregistered type is reported exactly as before, with the same code, severity, path and message, and every other item's problems are still listed.
12
+
13
+ A group made only of built-in types behaves as before: their checks are property-tested not to throw on any input. If you register your own types, a `checkDraft` that throws now surfaces as an error where you call `validateItemGroupDraft`. `checkDraft` must not throw on a plain object, so the fix belongs in the check.
14
+
15
+ ## 0.13.0
16
+
17
+ ### Minor Changes
18
+
19
+ - f26bab6: A built-in `dictation` activity type: the learner listens and types what they hear, and the grade is how close their text is to the transcript.
20
+
21
+ **lk-core**
22
+
23
+ - `DictationData` carries a `transcript` (the answer key), optional `acceptedTranscripts` scored best-of, an audio recording with the usual playback policy, an optional second slower recording (`slowMedia`, a separate file that follows the recording's policy and never has a play budget of its own), progressive word hints for practice (`hints`), and whole-word rewrite rules in `tolerance.equivalences` — the place a contraction table or a regional spelling lives, as content rather than as code inside the scorer.
24
+ - The score is `(length − edit distance) / length` over the whole sentence, in NFC code points, after case, punctuation, spacing and invisible characters (control, format and default-ignorable characters, variation selectors included) are ignored; typographic apostrophes and the hyphens of other scripts are folded, compatibility characters such as fullwidth and halfwidth forms, Latin digraphs, ligatures and Kangxi radicals are read as the characters they stand for (a halfwidth voiced sound mark as the mark on the kana before it), and a few sequences written two ways — the Thai SARA AM typed as its two parts, a Malayalam chillu in its older spelling — compare as one. What is spelling counts: an apostrophe, a hyphen, a Catalan middle dot or a Tibetan tsheg inside a word, a zero-width joiner or non-joiner where it changes what is written (beside a virama, as Unicode 16 lists them, or the Persian half-space between two letters that would otherwise join), the Mongolian vowel separator and free variation selectors, the tag characters of a subdivision flag, the base of a keycap and the format characters that are drawn, such as the Arabic number sign; a combining mark belongs to its word. One `ScoringDetail` per transcript word carries its own `score` — a new optional field on `ScoringDetail` — so a stored result records how each word was marked; the item's `score` is not the mean of them.
25
+ - `alignDictation(data, text)` returns the same comparison as data: the normalised strings, which transcript was scored against, and the word pairings with their similarities. `diffDictationChars(reference, attempt)` returns the character-level edit operations for a marked display, and `dictationReferenceWords(data)` the ids and words a stored result can be checked against. A review screen or an analytics job never re-implements the arithmetic.
26
+ - Learner text is compared up to 8000 code points and a transcript is at most 2000; the alignment says when text was cut. An item carries at most ten accepted transcripts and 100 equivalence rules, each `from` and `to` at most 200 code points; a rule rewrites whole words — in a script written without spaces, whose words show no edges, wherever its letters stand, though a number is a word in every script — and inserts its rewrite as words, set apart by a space where a letter of a script written with spaces, or a digit, would touch one, so `50%` with a rule for `%` reads as `50 percent`; no rule deletes a word. While rules run the text is cut at twice the attempt cap — a transcript that needs that cut is refused, an attempt that needs it is reported as truncated — so no combination of rules, authored or stale, can exhaust the process that grades an exam. The caps are exported as constants.
27
+ - The schema refuses captions on a dictation recording (they are the answer), and `validateItemGroup` refuses them on a group's stimulus recording that a dictation plays. It refuses a title or recording description that contains the whole transcript, or a whole accepted transcript, as whole words — as written and with the item's rules applied, and also where punctuation joins them to other words — or, for a transcript with four or more letters of a script written without spaces, wherever those letters stand, the transcript always read as it is written; and one too long to be searched in full. `validateActivity` reports these beside a refusal in any other field of the item. `assertRedacted` refuses a dictation projection that carries captions, a slow recording beside a play budget or a slow recording with no recording, and `assertRedactedItemGroup` a captioned stimulus a dictation plays, so a payload built by hand cannot pass as learner-safe.
28
+ - `score()` and `evaluate()` accept an optional `{ rounding }` so a pass line can be compared the way a score is displayed; without it nothing changes, and a malformed policy throws a `RangeError` instead of failing every comparison.
29
+ - `dictationType` and the previously unexported `gapSelectType` are on the barrel, and so are `MediaPlaybackPolicy`, the type of `ActivityMedia.playback`, and the `NativeControlHint` it lists, by name. Twenty-one draft issue codes (`dc_*`) with their severities and paths are in the authoring guide.
30
+ - `validateDraft` matches a schema's failures against the issues already reported in the depth of each path, where it made a pass over every reported issue for each failure: a draft with thousands of malformed entries took seconds, for every type. The issues it reports are unchanged. `validateDraft` and `validateItemGroupDraft` also normalise each dictation transcript, title and recording description once, however many of their checks read it.
31
+ - Every existing grade replays unchanged: vectors were added, none changed.
32
+
33
+ **lk-react**
34
+
35
+ - `<Dictation>`, also at `@intellectif/lk-react/components/Dictation`: the recording(s), the text box, and after submission an accessible word-by-word marked result with a character-level diff and a solution toggle. A recording's play limit binds through `mediaBudget` as for every other activity. Starting one of the two recordings pauses the other, and pausing spends no play.
36
+ - The marks are built for assistive technology and for every script: the per-word sentences a screen reader hears are in the interface language and stay hidden without the optional skin; the dictation's own words carry its `data.locale`, and its word list and diff take their direction from that tag when it names one — by a script subtag, or a language written right to left — or else from the transcript's first letter or directional mark, rather than from whatever was typed; the form is named by its title; authored feedback in the live announcement is isolated from the interface text around it. A wrong character inside a wrong word is marked by its own shape, in forced colours too — a combining mark or a stacked letter together with the character it is drawn into — and a missing character's bullet keeps its place inside a number or a word of the other direction. Keyboard focus stays on the hint controls, and a response reports only the hints actually shown.
37
+ - `LkStrings` gains the dictation strings. A dictionary declared as a complete `LkStrings` must add them; partial overrides are unaffected.
38
+
3
39
  ## 0.12.0
4
40
 
5
41
  ### Minor Changes
package/README.md CHANGED
@@ -14,12 +14,13 @@ npm install @intellectif/lk-core
14
14
 
15
15
  ## What's in the box
16
16
 
17
- - **Activity schemas** for `multiple-choice`, `fill-in-the-blanks` and `written-response`, with semantic refinements (e.g. *at least one correct option*, *single-select ⇒ exactly one correct*, *passage ↔ blank-id bijection*, *image/embed require `alt`*). Loose at every level, so your sidecar fields survive validation.
17
+ - **Activity schemas** for `multiple-choice`, `fill-in-the-blanks`, `written-response`, `gap-select` and `dictation`, with semantic refinements (e.g. *at least one correct option*, *single-select ⇒ exactly one correct*, *passage ↔ blank-id bijection*, *image/embed require `alt`*, *a dictation title never contains its whole transcript as words*). Loose at every level, so your sidecar fields survive validation.
18
18
  - **`validateActivity(type, data)`** — the authoritative runtime validator. Returns a typed `{ success, data }` or a structured `{ success: false, errors[] }`, and **throws `UnknownActivityTypeError` if `type` is not registered** — so guard it when validating a content bank that may carry types this build does not know. `validateItemGroup(data)` is the equivalent for a `Stimulus` + `ItemGroup` container, which `validateActivity` cannot take.
19
19
  - **`validateDraft(type, draft)`** — for editors. Reports `complete`, `incomplete` (something not written yet) or `invalid` (something wrong), each issue with a `severity` and a `code` — documented for every problem the checks recognise — and deliberately no `success` boolean to misread. Stricter than `validateActivity`, never looser. **`createDraft(type, { newId })`** returns an empty draft to start from; a multiple-choice draft marks no option correct.
20
20
  - **An open type system** — `defineActivityType` / `registerActivityType` make an activity type a *value*, not a hard-coded union member: register one and `validateActivity`, `validateDraft`, `score`, `evaluate`, `redact` and `jsonSchemaFor` all work for it, with no SDK release. An `authoring` block on the descriptor gives it draft support.
21
21
  - **JSON Schema (Draft-7) export** — `jsonSchemaFor(type)` for any registered type (plus the static per-type exports), suitable for form generators or AI prompting.
22
22
  - **Scoring engine** — `score(activityType, data, response)` returning `{ score ∈ [0,1], maxScore: 1, passed, feedback, details }`. Pure, deterministic, 100 % test coverage enforced. It **throws** rather than inventing a number: `DeferredScoringError` for a deferred-graded type (`written-response`), and `RedactedScoringError` when handed a `redact()` projection, which has no answer key. Both are on the documented exam path — use `evaluate()` there, which returns `deferred` / `unscorable` instead of throwing.
23
+ - **Dictation marking as data** — a dictation is graded by the character-level similarity of the typed text to the transcript, with one `ScoringDetail` per word carrying its own `score`. `alignDictation(data, text)` returns the same comparison the grade was made of (normalised strings, word pairings, which accepted transcript won), `diffDictationChars(reference, attempt)` the character-level edits for a marked display, and `dictationReferenceWords(data)` the ids and words a stored result can be checked against — so a review screen or an analytics job never re-implements the arithmetic. `score()` and `evaluate()` take an optional `{ rounding }` to compare the pass line as displayed.
23
24
  - **`evaluate(data, response)` → `ItemOutcome`** — the resilient result: `scored`, `deferred` (graded later by an AI or a human), `graded` (the grade came back), or `unscorable`. "Not graded yet" is expressible in the type system and is never conflated with a zero.
24
25
  - **Deferred grading, both directions** — `GradeRecord`, `gradeFromRubric()` (the weighted total as a pure function of the grader's judgements — never the model's arithmetic; declare `maxScore` per criterion if your grader works out of 100 or out of 9), `outcomeFromGrade()`, `hasGrade()`.
25
26
  - **Assessment composition** — `composeAssessmentScore()` for weighted, sectioned totals, with a `provisional` status so an unmarked essay never deflates a grade, and `RoundingPolicy` / `roundGrade` / `gte` / `classifyBand` keeping grade rounding and band classification as the two distinct operations they are.
@@ -360,6 +360,7 @@ interface ActivityDataMap {
360
360
  'fill-in-the-blanks': FillInTheBlanksData;
361
361
  'written-response': WrittenResponseData;
362
362
  'gap-select': GapSelectData;
363
+ dictation: DictationData;
363
364
  }
364
365
  /**
365
366
  * The set of activity types supported by learning-kit. Derived from
@@ -782,6 +783,108 @@ interface WrittenResponseData {
782
783
  /** Subjective difficulty on a 1–5 scale. */
783
784
  difficultyLevel?: 1 | 2 | 3 | 4 | 5;
784
785
  }
786
+ /**
787
+ * A second, slower recording of a dictation — a separate file (a text-to-speech
788
+ * render at reduced speed, or a slower human reading), not a `playbackRate`
789
+ * change. It carries no `captionsUrl` (a caption track of a dictation is the
790
+ * transcript on screen) and no `playback` policy of its own: it follows the
791
+ * policy on `media`, except the play budget, which it never has.
792
+ */
793
+ interface DictationSlowMedia {
794
+ type: 'audio';
795
+ /** Source URL, under the same policy as {@link ActivityMedia.url}. */
796
+ url: string;
797
+ /** Accessible label — a description ("Recording, slow"), never a transcription. */
798
+ alt?: string;
799
+ }
800
+ /**
801
+ * A whole-word rewrite applied to BOTH the transcript and the attempt before
802
+ * they are compared. `from` and `to` are literal text: a rule is applied to
803
+ * every whole-word occurrence, exactly once, in the order the rules are listed,
804
+ * after spacing is collapsed and before punctuation is ignored — so a rule may
805
+ * name a symbol (`{ from: '&', to: 'and' }`) and a multi-word `from` matches
806
+ * across any whitespace.
807
+ */
808
+ interface DictationEquivalence {
809
+ /** What to rewrite: at least one code point that survives case, quote and whitespace folding. */
810
+ from: string;
811
+ /** What it becomes: 1..200 code points, something of which survives normalisation. A rule cannot delete a word. */
812
+ to: string;
813
+ }
814
+ /** Grading tolerances for a dictation. Part of the answer key. */
815
+ interface DictationTolerance {
816
+ /** Whole-word rewrites, applied in listed order, each exactly once. */
817
+ equivalences?: DictationEquivalence[];
818
+ }
819
+ /**
820
+ * Data contract for a Dictation activity: the learner listens to a recording
821
+ * and types what they hear; the grade is how close their text is to the
822
+ * transcript.
823
+ *
824
+ * Scoring is character-level similarity over the whole sentence —
825
+ * `(length − edit distance) / length` over NFC code points after case,
826
+ * punctuation and spacing are ignored — with one {@link ScoringDetail} per
827
+ * transcript word carrying that word's own {@link ScoringDetail.score}. It is
828
+ * deliberately not a mode of {@link FillInTheBlanksData}: a blank is right or
829
+ * wrong, a dictation is graded on a continuum, and the whole `TextMatchPolicy`
830
+ * surface (typo tolerance, diacritic folding) would be a second, competing
831
+ * notion of "close enough".
832
+ */
833
+ interface DictationData {
834
+ schemaVersion: '1.0';
835
+ type: 'dictation';
836
+ /** Unique identifier for this activity. */
837
+ id: string;
838
+ /**
839
+ * Human-readable title used in xAPI statements and error boundaries. It is
840
+ * the stem the learner sees, so it must not contain the transcript.
841
+ */
842
+ title: string;
843
+ /**
844
+ * What the learner is expected to type. ANSWER KEY. 1..2000 code points,
845
+ * before and after its equivalences are applied, and something must survive
846
+ * normalisation.
847
+ */
848
+ transcript: string;
849
+ /**
850
+ * Alternative transcriptions accepted at full credit — a regional spelling, a
851
+ * numeral, a whole-sentence contraction variant. ANSWER KEY. At most 10, each
852
+ * 1..2000 code points, none normalising equal to the transcript or to each
853
+ * other. The attempt is scored against every candidate and the best
854
+ * similarity wins; a tie goes to `transcript`.
855
+ */
856
+ acceptedTranscripts?: string[];
857
+ /**
858
+ * The recording. Audio only, never with captions. Optional in the schema — a
859
+ * dictation inside an item group may draw on the group's stimulus recording —
860
+ * but required whenever `slowMedia` is present. Budgeted per slot like any
861
+ * other activity media, with the usual playback policy.
862
+ */
863
+ media?: ActivityMedia;
864
+ /** A second, slower recording. See {@link DictationSlowMedia}. */
865
+ slowMedia?: DictationSlowMedia;
866
+ /**
867
+ * Progressive word hints, in `practice` only (the transcript is absent in
868
+ * `exam` mode, so there is nothing to reveal). Public: it reveals nothing by
869
+ * itself. `progressive-words` reveals the transcript's words left to right,
870
+ * one per request; a revealed hint never changes the score.
871
+ */
872
+ hints?: {
873
+ mode: 'progressive-words';
874
+ };
875
+ /** Grading tolerances. ANSWER KEY. */
876
+ tolerance?: DictationTolerance;
877
+ /** Optional authored overall feedback shown after submission. */
878
+ feedback?: ActivityFeedback;
879
+ /** Minimum scaled score [0–1] required to pass. Defaults to {@link DEFAULT_PASS_THRESHOLD} (0.7) when absent. */
880
+ passThreshold?: number;
881
+ /** BCP 47 language tag for the activity content. Presentation only: scoring never reads it. */
882
+ locale?: string;
883
+ /** IRI references to learning objectives addressed by this activity. */
884
+ learningObjectives?: string[];
885
+ /** Subjective difficulty on a 1–5 scale. */
886
+ difficultyLevel?: 1 | 2 | 3 | 4 | 5;
887
+ }
785
888
  /**
786
889
  * Maps each ActivityType string to its learner-response shape. Open for
787
890
  * extension via module augmentation, mirroring {@link ActivityDataMap}.
@@ -791,6 +894,7 @@ interface LearnerResponseMap {
791
894
  'fill-in-the-blanks': FillInTheBlanksLearnerResponse;
792
895
  'written-response': WrittenResponseLearnerResponse;
793
896
  'gap-select': GapSelectLearnerResponse;
897
+ dictation: DictationLearnerResponse;
794
898
  }
795
899
  /** Union of all learner response shapes. */
796
900
  type LearnerResponse = LearnerResponseMap[keyof LearnerResponseMap];
@@ -828,18 +932,34 @@ interface WrittenResponseLearnerResponse {
828
932
  /** Word count of `text`, computed with the canonical `countWords()` helper. */
829
933
  wordCount: number;
830
934
  }
935
+ /**
936
+ * Learner response for a Dictation activity.
937
+ *
938
+ * `text` is exactly what the learner typed; every normalisation happens in the
939
+ * scorer. `hintsRevealed` is client-reported telemetry — how many hint words
940
+ * were shown before submitting — that the scorer ignores and a consumer may
941
+ * log or penalise, knowing it cannot be verified.
942
+ */
943
+ interface DictationLearnerResponse {
944
+ type: 'dictation';
945
+ /** The learner's text, as typed. */
946
+ text: string;
947
+ /** Hint words revealed before submitting (practice only). Absent or 0 means none. */
948
+ hintsRevealed?: number;
949
+ }
831
950
  /**
832
951
  * Fine-grained outcome of the learner's action on a single item, replacing the
833
952
  * ambiguous {@link ScoringDetail.correct}:
834
953
  * - `correct` — the learner selected/entered the right answer.
835
954
  * - `incorrect` — the learner selected/entered a wrong answer.
836
955
  * - `correct-omission` — the learner correctly left a non-answer unselected (multiple-choice only).
837
- * - `incorrect-omission` — the learner failed to select a correct answer (multiple-choice only).
956
+ * - `incorrect-omission` — a correct answer the learner did not give: an unselected
957
+ * correct option, an unanswered gap, a missing dictation word.
838
958
  */
839
959
  type ScoringOutcome = 'correct' | 'incorrect' | 'correct-omission' | 'incorrect-omission';
840
960
  /** Per-item scoring breakdown returned by the scoring engine. */
841
961
  interface ScoringDetail {
842
- /** ID of the option or blank this detail refers to. */
962
+ /** ID of the option, blank, gap or dictation word (`w1`…`wN`) this detail refers to. */
843
963
  itemId: string;
844
964
  /**
845
965
  * @deprecated Ambiguous: for multiple-choice this means "the learner acted
@@ -852,8 +972,8 @@ interface ScoringDetail {
852
972
  /**
853
973
  * Unambiguous outcome of the learner's action on this item. Optional in the
854
974
  * type so 0.2-era consumer-constructed literals keep compiling, but ALWAYS
855
- * written by both built-in scorers since 0.3.0; becomes required in v1.0
856
- * when the deprecated `correct` is removed.
975
+ * written by every built-in scorer (by the first two since 0.3.0); becomes
976
+ * required in v1.0 when the deprecated `correct` is removed.
857
977
  */
858
978
  outcome?: ScoringOutcome;
859
979
  /** The learner's actual response for this item. */
@@ -861,10 +981,17 @@ interface ScoringDetail {
861
981
  /** The expected correct response(s) for this item. */
862
982
  correctResponse: string | string[];
863
983
  /**
864
- * Weight applied to this item's contribution to the overall score. Both
865
- * built-in scorers currently weight every item equally and write `1`.
984
+ * Weight applied to this item's contribution to the overall score. Every
985
+ * built-in scorer currently weights every item equally and writes `1`.
866
986
  */
867
987
  weight?: number;
988
+ /**
989
+ * The item's own scaled score in [0, 1], for a type that grades its items on
990
+ * a continuum rather than right or wrong. Written by the dictation scorer
991
+ * (the similarity of each transcript word to what was typed for it) and by
992
+ * nothing else today. Absent, an item is right or wrong: read `outcome`.
993
+ */
994
+ score?: number;
868
995
  }
869
996
  /** Full scoring result returned by the scoring engine. */
870
997
  interface ScoringResult {
@@ -1020,4 +1147,4 @@ interface InteractionEvent {
1020
1147
  payload: Record<string, unknown>;
1021
1148
  }
1022
1149
 
1023
- export { levenshteinDistance as $, type ActivityData as A, type BlankConfig as B, type CriterionScore as C, type DeferredScoringPartial as D, type WrittenResponseLearnerResponse as E, type FillInTheBlanksData as F, type GapSelectBank as G, type WrittenResponseRubric as H, type InlineCorrection as I, type WrittenResponseRubricCriterion as J, type XAPIConfig as K, type LearnerResponse as L, type MultipleChoiceData as M, type NativeControlHint as N, type XAPIContext as O, type XAPIContextActivities as P, type XAPIError as Q, type XAPIObject as R, type ScoringDetail as S, type TextMatchPolicy as T, type XAPIResult as U, type ValidationError as V, type WrittenResponseData as W, type XAPIActor as X, type XAPIScore as Y, type XAPIStatement as Z, type XAPIVerbObject as _, type ActivityDataMap as a, matchText as a0, type ActivityFeedback as b, type ActivityMedia as c, type ActivityResult as d, type ActivityType as e, type FillInTheBlanksLearnerResponse as f, type GapSelectChoice as g, type GapSelectData as h, type GapSelectGap as i, type GapSelectLearnerResponse as j, type GradeRecord as k, type Grader as l, type GraderKind as m, type GraderUsage as n, type GradingState as o, type InteractionEvent as p, type InteractionKind as q, type ItemOutcome as r, type LearnerResponseMap as s, type MultipleChoiceLearnerResponse as t, type MultipleChoiceOption as u, type MultipleChoiceOptionMedia as v, type ScoringOutcome as w, type ScoringResult as x, type TextMatchResult as y, type ValidationResult as z };
1150
+ export { type XAPIError as $, type ActivityData as A, type BlankConfig as B, type CriterionScore as C, type DeferredScoringPartial as D, type MultipleChoiceOption as E, type FillInTheBlanksData as F, type GapSelectBank as G, type MultipleChoiceOptionMedia as H, type InlineCorrection as I, type ScoringOutcome as J, type ScoringResult as K, type LearnerResponse as L, type MediaPlaybackPolicy as M, type NativeControlHint as N, type TextMatchResult as O, type ValidationResult as P, type WrittenResponseLearnerResponse as Q, type WrittenResponseRubric as R, type ScoringDetail as S, type TextMatchPolicy as T, type WrittenResponseRubricCriterion as U, type ValidationError as V, type WrittenResponseData as W, type XAPIActor as X, type XAPIConfig as Y, type XAPIContext as Z, type XAPIContextActivities as _, type ActivityDataMap as a, type XAPIObject as a0, type XAPIResult as a1, type XAPIScore as a2, type XAPIStatement as a3, type XAPIVerbObject as a4, levenshteinDistance as a5, matchText as a6, type ActivityFeedback as b, type ActivityMedia as c, type ActivityResult as d, type ActivityType as e, type DictationData as f, type DictationEquivalence as g, type DictationLearnerResponse as h, type DictationSlowMedia as i, type DictationTolerance as j, type FillInTheBlanksLearnerResponse as k, type GapSelectChoice as l, type GapSelectData as m, type GapSelectGap as n, type GapSelectLearnerResponse as o, type GradeRecord as p, type Grader as q, type GraderKind as r, type GraderUsage as s, type GradingState as t, type InteractionEvent as u, type InteractionKind as v, type ItemOutcome as w, type LearnerResponseMap as x, type MultipleChoiceData as y, type MultipleChoiceLearnerResponse as z };
@@ -360,6 +360,7 @@ interface ActivityDataMap {
360
360
  'fill-in-the-blanks': FillInTheBlanksData;
361
361
  'written-response': WrittenResponseData;
362
362
  'gap-select': GapSelectData;
363
+ dictation: DictationData;
363
364
  }
364
365
  /**
365
366
  * The set of activity types supported by learning-kit. Derived from
@@ -782,6 +783,108 @@ interface WrittenResponseData {
782
783
  /** Subjective difficulty on a 1–5 scale. */
783
784
  difficultyLevel?: 1 | 2 | 3 | 4 | 5;
784
785
  }
786
+ /**
787
+ * A second, slower recording of a dictation — a separate file (a text-to-speech
788
+ * render at reduced speed, or a slower human reading), not a `playbackRate`
789
+ * change. It carries no `captionsUrl` (a caption track of a dictation is the
790
+ * transcript on screen) and no `playback` policy of its own: it follows the
791
+ * policy on `media`, except the play budget, which it never has.
792
+ */
793
+ interface DictationSlowMedia {
794
+ type: 'audio';
795
+ /** Source URL, under the same policy as {@link ActivityMedia.url}. */
796
+ url: string;
797
+ /** Accessible label — a description ("Recording, slow"), never a transcription. */
798
+ alt?: string;
799
+ }
800
+ /**
801
+ * A whole-word rewrite applied to BOTH the transcript and the attempt before
802
+ * they are compared. `from` and `to` are literal text: a rule is applied to
803
+ * every whole-word occurrence, exactly once, in the order the rules are listed,
804
+ * after spacing is collapsed and before punctuation is ignored — so a rule may
805
+ * name a symbol (`{ from: '&', to: 'and' }`) and a multi-word `from` matches
806
+ * across any whitespace.
807
+ */
808
+ interface DictationEquivalence {
809
+ /** What to rewrite: at least one code point that survives case, quote and whitespace folding. */
810
+ from: string;
811
+ /** What it becomes: 1..200 code points, something of which survives normalisation. A rule cannot delete a word. */
812
+ to: string;
813
+ }
814
+ /** Grading tolerances for a dictation. Part of the answer key. */
815
+ interface DictationTolerance {
816
+ /** Whole-word rewrites, applied in listed order, each exactly once. */
817
+ equivalences?: DictationEquivalence[];
818
+ }
819
+ /**
820
+ * Data contract for a Dictation activity: the learner listens to a recording
821
+ * and types what they hear; the grade is how close their text is to the
822
+ * transcript.
823
+ *
824
+ * Scoring is character-level similarity over the whole sentence —
825
+ * `(length − edit distance) / length` over NFC code points after case,
826
+ * punctuation and spacing are ignored — with one {@link ScoringDetail} per
827
+ * transcript word carrying that word's own {@link ScoringDetail.score}. It is
828
+ * deliberately not a mode of {@link FillInTheBlanksData}: a blank is right or
829
+ * wrong, a dictation is graded on a continuum, and the whole `TextMatchPolicy`
830
+ * surface (typo tolerance, diacritic folding) would be a second, competing
831
+ * notion of "close enough".
832
+ */
833
+ interface DictationData {
834
+ schemaVersion: '1.0';
835
+ type: 'dictation';
836
+ /** Unique identifier for this activity. */
837
+ id: string;
838
+ /**
839
+ * Human-readable title used in xAPI statements and error boundaries. It is
840
+ * the stem the learner sees, so it must not contain the transcript.
841
+ */
842
+ title: string;
843
+ /**
844
+ * What the learner is expected to type. ANSWER KEY. 1..2000 code points,
845
+ * before and after its equivalences are applied, and something must survive
846
+ * normalisation.
847
+ */
848
+ transcript: string;
849
+ /**
850
+ * Alternative transcriptions accepted at full credit — a regional spelling, a
851
+ * numeral, a whole-sentence contraction variant. ANSWER KEY. At most 10, each
852
+ * 1..2000 code points, none normalising equal to the transcript or to each
853
+ * other. The attempt is scored against every candidate and the best
854
+ * similarity wins; a tie goes to `transcript`.
855
+ */
856
+ acceptedTranscripts?: string[];
857
+ /**
858
+ * The recording. Audio only, never with captions. Optional in the schema — a
859
+ * dictation inside an item group may draw on the group's stimulus recording —
860
+ * but required whenever `slowMedia` is present. Budgeted per slot like any
861
+ * other activity media, with the usual playback policy.
862
+ */
863
+ media?: ActivityMedia;
864
+ /** A second, slower recording. See {@link DictationSlowMedia}. */
865
+ slowMedia?: DictationSlowMedia;
866
+ /**
867
+ * Progressive word hints, in `practice` only (the transcript is absent in
868
+ * `exam` mode, so there is nothing to reveal). Public: it reveals nothing by
869
+ * itself. `progressive-words` reveals the transcript's words left to right,
870
+ * one per request; a revealed hint never changes the score.
871
+ */
872
+ hints?: {
873
+ mode: 'progressive-words';
874
+ };
875
+ /** Grading tolerances. ANSWER KEY. */
876
+ tolerance?: DictationTolerance;
877
+ /** Optional authored overall feedback shown after submission. */
878
+ feedback?: ActivityFeedback;
879
+ /** Minimum scaled score [0–1] required to pass. Defaults to {@link DEFAULT_PASS_THRESHOLD} (0.7) when absent. */
880
+ passThreshold?: number;
881
+ /** BCP 47 language tag for the activity content. Presentation only: scoring never reads it. */
882
+ locale?: string;
883
+ /** IRI references to learning objectives addressed by this activity. */
884
+ learningObjectives?: string[];
885
+ /** Subjective difficulty on a 1–5 scale. */
886
+ difficultyLevel?: 1 | 2 | 3 | 4 | 5;
887
+ }
785
888
  /**
786
889
  * Maps each ActivityType string to its learner-response shape. Open for
787
890
  * extension via module augmentation, mirroring {@link ActivityDataMap}.
@@ -791,6 +894,7 @@ interface LearnerResponseMap {
791
894
  'fill-in-the-blanks': FillInTheBlanksLearnerResponse;
792
895
  'written-response': WrittenResponseLearnerResponse;
793
896
  'gap-select': GapSelectLearnerResponse;
897
+ dictation: DictationLearnerResponse;
794
898
  }
795
899
  /** Union of all learner response shapes. */
796
900
  type LearnerResponse = LearnerResponseMap[keyof LearnerResponseMap];
@@ -828,18 +932,34 @@ interface WrittenResponseLearnerResponse {
828
932
  /** Word count of `text`, computed with the canonical `countWords()` helper. */
829
933
  wordCount: number;
830
934
  }
935
+ /**
936
+ * Learner response for a Dictation activity.
937
+ *
938
+ * `text` is exactly what the learner typed; every normalisation happens in the
939
+ * scorer. `hintsRevealed` is client-reported telemetry — how many hint words
940
+ * were shown before submitting — that the scorer ignores and a consumer may
941
+ * log or penalise, knowing it cannot be verified.
942
+ */
943
+ interface DictationLearnerResponse {
944
+ type: 'dictation';
945
+ /** The learner's text, as typed. */
946
+ text: string;
947
+ /** Hint words revealed before submitting (practice only). Absent or 0 means none. */
948
+ hintsRevealed?: number;
949
+ }
831
950
  /**
832
951
  * Fine-grained outcome of the learner's action on a single item, replacing the
833
952
  * ambiguous {@link ScoringDetail.correct}:
834
953
  * - `correct` — the learner selected/entered the right answer.
835
954
  * - `incorrect` — the learner selected/entered a wrong answer.
836
955
  * - `correct-omission` — the learner correctly left a non-answer unselected (multiple-choice only).
837
- * - `incorrect-omission` — the learner failed to select a correct answer (multiple-choice only).
956
+ * - `incorrect-omission` — a correct answer the learner did not give: an unselected
957
+ * correct option, an unanswered gap, a missing dictation word.
838
958
  */
839
959
  type ScoringOutcome = 'correct' | 'incorrect' | 'correct-omission' | 'incorrect-omission';
840
960
  /** Per-item scoring breakdown returned by the scoring engine. */
841
961
  interface ScoringDetail {
842
- /** ID of the option or blank this detail refers to. */
962
+ /** ID of the option, blank, gap or dictation word (`w1`…`wN`) this detail refers to. */
843
963
  itemId: string;
844
964
  /**
845
965
  * @deprecated Ambiguous: for multiple-choice this means "the learner acted
@@ -852,8 +972,8 @@ interface ScoringDetail {
852
972
  /**
853
973
  * Unambiguous outcome of the learner's action on this item. Optional in the
854
974
  * type so 0.2-era consumer-constructed literals keep compiling, but ALWAYS
855
- * written by both built-in scorers since 0.3.0; becomes required in v1.0
856
- * when the deprecated `correct` is removed.
975
+ * written by every built-in scorer (by the first two since 0.3.0); becomes
976
+ * required in v1.0 when the deprecated `correct` is removed.
857
977
  */
858
978
  outcome?: ScoringOutcome;
859
979
  /** The learner's actual response for this item. */
@@ -861,10 +981,17 @@ interface ScoringDetail {
861
981
  /** The expected correct response(s) for this item. */
862
982
  correctResponse: string | string[];
863
983
  /**
864
- * Weight applied to this item's contribution to the overall score. Both
865
- * built-in scorers currently weight every item equally and write `1`.
984
+ * Weight applied to this item's contribution to the overall score. Every
985
+ * built-in scorer currently weights every item equally and writes `1`.
866
986
  */
867
987
  weight?: number;
988
+ /**
989
+ * The item's own scaled score in [0, 1], for a type that grades its items on
990
+ * a continuum rather than right or wrong. Written by the dictation scorer
991
+ * (the similarity of each transcript word to what was typed for it) and by
992
+ * nothing else today. Absent, an item is right or wrong: read `outcome`.
993
+ */
994
+ score?: number;
868
995
  }
869
996
  /** Full scoring result returned by the scoring engine. */
870
997
  interface ScoringResult {
@@ -1020,4 +1147,4 @@ interface InteractionEvent {
1020
1147
  payload: Record<string, unknown>;
1021
1148
  }
1022
1149
 
1023
- export { levenshteinDistance as $, type ActivityData as A, type BlankConfig as B, type CriterionScore as C, type DeferredScoringPartial as D, type WrittenResponseLearnerResponse as E, type FillInTheBlanksData as F, type GapSelectBank as G, type WrittenResponseRubric as H, type InlineCorrection as I, type WrittenResponseRubricCriterion as J, type XAPIConfig as K, type LearnerResponse as L, type MultipleChoiceData as M, type NativeControlHint as N, type XAPIContext as O, type XAPIContextActivities as P, type XAPIError as Q, type XAPIObject as R, type ScoringDetail as S, type TextMatchPolicy as T, type XAPIResult as U, type ValidationError as V, type WrittenResponseData as W, type XAPIActor as X, type XAPIScore as Y, type XAPIStatement as Z, type XAPIVerbObject as _, type ActivityDataMap as a, matchText as a0, type ActivityFeedback as b, type ActivityMedia as c, type ActivityResult as d, type ActivityType as e, type FillInTheBlanksLearnerResponse as f, type GapSelectChoice as g, type GapSelectData as h, type GapSelectGap as i, type GapSelectLearnerResponse as j, type GradeRecord as k, type Grader as l, type GraderKind as m, type GraderUsage as n, type GradingState as o, type InteractionEvent as p, type InteractionKind as q, type ItemOutcome as r, type LearnerResponseMap as s, type MultipleChoiceLearnerResponse as t, type MultipleChoiceOption as u, type MultipleChoiceOptionMedia as v, type ScoringOutcome as w, type ScoringResult as x, type TextMatchResult as y, type ValidationResult as z };
1150
+ export { type XAPIError as $, type ActivityData as A, type BlankConfig as B, type CriterionScore as C, type DeferredScoringPartial as D, type MultipleChoiceOption as E, type FillInTheBlanksData as F, type GapSelectBank as G, type MultipleChoiceOptionMedia as H, type InlineCorrection as I, type ScoringOutcome as J, type ScoringResult as K, type LearnerResponse as L, type MediaPlaybackPolicy as M, type NativeControlHint as N, type TextMatchResult as O, type ValidationResult as P, type WrittenResponseLearnerResponse as Q, type WrittenResponseRubric as R, type ScoringDetail as S, type TextMatchPolicy as T, type WrittenResponseRubricCriterion as U, type ValidationError as V, type WrittenResponseData as W, type XAPIActor as X, type XAPIConfig as Y, type XAPIContext as Z, type XAPIContextActivities as _, type ActivityDataMap as a, type XAPIObject as a0, type XAPIResult as a1, type XAPIScore as a2, type XAPIStatement as a3, type XAPIVerbObject as a4, levenshteinDistance as a5, matchText as a6, type ActivityFeedback as b, type ActivityMedia as c, type ActivityResult as d, type ActivityType as e, type DictationData as f, type DictationEquivalence as g, type DictationLearnerResponse as h, type DictationSlowMedia as i, type DictationTolerance as j, type FillInTheBlanksLearnerResponse as k, type GapSelectChoice as l, type GapSelectData as m, type GapSelectGap as n, type GapSelectLearnerResponse as o, type GradeRecord as p, type Grader as q, type GraderKind as r, type GraderUsage as s, type GradingState as t, type InteractionEvent as u, type InteractionKind as v, type ItemOutcome as w, type LearnerResponseMap as x, type MultipleChoiceData as y, type MultipleChoiceLearnerResponse as z };
@@ -1,4 +1,4 @@
1
- "use strict";Object.defineProperty(exports, "__esModule", {value: true});
1
+ "use strict";Object.defineProperty(exports, "__esModule", {value: true}); function _optionalChain(ops) { let lastAccessLHS = undefined; let value = ops[0]; let i = 1; while (i < ops.length) { const op = ops[i]; const fn = ops[i + 1]; i += 2; if ((op === 'optionalAccess' || op === 'optionalCall') && value == null) { return undefined; } if (op === 'access' || op === 'optionalAccess') { lastAccessLHS = value; value = fn(value); } else if (op === 'call' || op === 'optionalCall') { value = fn((...args) => value.call(lastAccessLHS, ...args)); lastAccessLHS = undefined; } } return value; }
2
2
 
3
3
 
4
4
 
@@ -7,7 +7,10 @@
7
7
 
8
8
 
9
9
 
10
- var _chunkJ6POE4HLcjs = require('./chunk-J6POE4HL.cjs');
10
+
11
+
12
+
13
+ var _chunkXONKWL6Dcjs = require('./chunk-XONKWL6D.cjs');
11
14
 
12
15
  // src/schemas/item-group.ts
13
16
  var _v4 = require('zod/v4');
@@ -35,7 +38,7 @@ var StimulusSchema = _v4.z.looseObject({
35
38
  title: _v4.z.string().optional(),
36
39
  body: _v4.z.string().optional(),
37
40
  bodyHtml: _v4.z.string().optional(),
38
- media: _chunkJ6POE4HLcjs.MediaSchema.optional(),
41
+ media: _chunkXONKWL6Dcjs.MediaSchema.optional(),
39
42
  transcript: _v4.z.string().optional(),
40
43
  locale: _v4.z.string().optional(),
41
44
  attribution: _v4.z.string().optional()
@@ -85,7 +88,7 @@ var RedactedStimulusSchema = _v4.z.strictObject({
85
88
  title: _v4.z.string().optional(),
86
89
  body: _v4.z.string().optional(),
87
90
  bodyHtml: _v4.z.string().optional(),
88
- media: _chunkJ6POE4HLcjs.RedactedMediaSchema.optional(),
91
+ media: _chunkXONKWL6Dcjs.RedactedMediaSchema.optional(),
89
92
  locale: _v4.z.string().optional(),
90
93
  attribution: _v4.z.string().optional()
91
94
  });
@@ -99,6 +102,15 @@ var RedactedItemGroupSchema = _v4.z.strictObject({
99
102
  stimulus: RedactedStimulusSchema,
100
103
  items: _v4.z.array(_v4.z.unknown()).min(1),
101
104
  shuffle: _v4.z.enum(["none", "within-group"]).optional()
105
+ }).check((ctx) => {
106
+ if (_chunkXONKWL6Dcjs.groupCaptionsRevealDictation.call(void 0, ctx.value)) {
107
+ ctx.issues.push({
108
+ code: "custom",
109
+ input: _optionalChain([ctx, 'access', _ => _.value, 'access', _2 => _2.stimulus, 'access', _3 => _3.media, 'optionalAccess', _4 => _4.captionsUrl]),
110
+ message: _chunkXONKWL6Dcjs.GROUP_CAPTIONS_REVEAL_DICTATION,
111
+ path: ["stimulus", "media", "captionsUrl"]
112
+ });
113
+ }
102
114
  });
103
115
  function toValidationErrors(issues, prefix) {
104
116
  return issues.map((issue) => ({
@@ -115,7 +127,7 @@ function validateItemGroup(data) {
115
127
  const errors = [];
116
128
  const items = [];
117
129
  container.data.items.forEach((item, index) => {
118
- const descriptor = _chunkJ6POE4HLcjs.getActivityTypeDescriptor.call(void 0, item.type);
130
+ const descriptor = _chunkXONKWL6Dcjs.getActivityTypeDescriptor.call(void 0, item.type);
119
131
  if (descriptor === void 0) {
120
132
  errors.push({
121
133
  path: ["items", String(index), "type"],
@@ -131,6 +143,13 @@ function validateItemGroup(data) {
131
143
  }
132
144
  items.push(parsed.data);
133
145
  });
146
+ if (_chunkXONKWL6Dcjs.groupCaptionsRevealDictation.call(void 0, container.data)) {
147
+ errors.push({
148
+ path: ["stimulus", "media", "captionsUrl"],
149
+ message: _chunkXONKWL6Dcjs.GROUP_CAPTIONS_REVEAL_DICTATION,
150
+ code: "custom"
151
+ });
152
+ }
134
153
  if (errors.length > 0) {
135
154
  return { success: false, errors };
136
155
  }
@@ -141,31 +160,34 @@ function validateItemGroup(data) {
141
160
 
142
161
  var stimulusJsonSchema = _v4.z.toJSONSchema(StimulusSchema, { target: "draft-7" });
143
162
  var itemGroupJsonSchema = _v4.z.toJSONSchema(ItemGroupSchema, { target: "draft-7" });
144
- var gapSelectJsonSchema = _v4.z.toJSONSchema(_chunkJ6POE4HLcjs.GapSelectDataSchema, {
163
+ var gapSelectJsonSchema = _v4.z.toJSONSchema(_chunkXONKWL6Dcjs.GapSelectDataSchema, {
164
+ target: "draft-7"
165
+ });
166
+ var dictationJsonSchema = _v4.z.toJSONSchema(_chunkXONKWL6Dcjs.DictationDataSchema, {
145
167
  target: "draft-7"
146
168
  });
147
- var multipleChoiceJsonSchema = _v4.z.toJSONSchema(_chunkJ6POE4HLcjs.MultipleChoiceDataSchema, {
169
+ var multipleChoiceJsonSchema = _v4.z.toJSONSchema(_chunkXONKWL6Dcjs.MultipleChoiceDataSchema, {
148
170
  target: "draft-7"
149
171
  });
150
- var fillInTheBlanksJsonSchema = _v4.z.toJSONSchema(_chunkJ6POE4HLcjs.FillInTheBlanksDataSchema, {
172
+ var fillInTheBlanksJsonSchema = _v4.z.toJSONSchema(_chunkXONKWL6Dcjs.FillInTheBlanksDataSchema, {
151
173
  target: "draft-7"
152
174
  });
153
- var writtenResponseJsonSchema = _v4.z.toJSONSchema(_chunkJ6POE4HLcjs.WrittenResponseDataSchema, {
175
+ var writtenResponseJsonSchema = _v4.z.toJSONSchema(_chunkXONKWL6Dcjs.WrittenResponseDataSchema, {
154
176
  target: "draft-7"
155
177
  });
156
178
  function jsonSchemaFor(type) {
157
- const descriptor = _chunkJ6POE4HLcjs.getActivityTypeDescriptor.call(void 0, type);
179
+ const descriptor = _chunkXONKWL6Dcjs.getActivityTypeDescriptor.call(void 0, type);
158
180
  if (descriptor === void 0) {
159
- throw new (0, _chunkJ6POE4HLcjs.UnknownActivityTypeError)(type);
181
+ throw new (0, _chunkXONKWL6Dcjs.UnknownActivityTypeError)(type);
160
182
  }
161
183
  return _v4.z.toJSONSchema(descriptor.schema, { target: "draft-7" });
162
184
  }
163
185
 
164
186
  // src/schemas/index.ts
165
187
  function validateActivity(type, data) {
166
- const descriptor = _chunkJ6POE4HLcjs.getActivityTypeDescriptor.call(void 0, type);
188
+ const descriptor = _chunkXONKWL6Dcjs.getActivityTypeDescriptor.call(void 0, type);
167
189
  if (descriptor === void 0) {
168
- throw new (0, _chunkJ6POE4HLcjs.UnknownActivityTypeError)(String(type));
190
+ throw new (0, _chunkXONKWL6Dcjs.UnknownActivityTypeError)(String(type));
169
191
  }
170
192
  const result = descriptor.schema.safeParse(data);
171
193
  if (result.success) {
@@ -195,5 +217,6 @@ function validateActivity(type, data) {
195
217
 
196
218
 
197
219
 
198
- exports.StimulusSchema = StimulusSchema; exports.ItemGroupSchema = ItemGroupSchema; exports.RedactedStimulusSchema = RedactedStimulusSchema; exports.RedactedItemGroupSchema = RedactedItemGroupSchema; exports.validateItemGroup = validateItemGroup; exports.stimulusJsonSchema = stimulusJsonSchema; exports.itemGroupJsonSchema = itemGroupJsonSchema; exports.gapSelectJsonSchema = gapSelectJsonSchema; exports.multipleChoiceJsonSchema = multipleChoiceJsonSchema; exports.fillInTheBlanksJsonSchema = fillInTheBlanksJsonSchema; exports.writtenResponseJsonSchema = writtenResponseJsonSchema; exports.jsonSchemaFor = jsonSchemaFor; exports.validateActivity = validateActivity;
199
- //# sourceMappingURL=chunk-VYE6BYON.cjs.map
220
+
221
+ exports.StimulusSchema = StimulusSchema; exports.ItemGroupSchema = ItemGroupSchema; exports.RedactedStimulusSchema = RedactedStimulusSchema; exports.RedactedItemGroupSchema = RedactedItemGroupSchema; exports.validateItemGroup = validateItemGroup; exports.stimulusJsonSchema = stimulusJsonSchema; exports.itemGroupJsonSchema = itemGroupJsonSchema; exports.gapSelectJsonSchema = gapSelectJsonSchema; exports.dictationJsonSchema = dictationJsonSchema; exports.multipleChoiceJsonSchema = multipleChoiceJsonSchema; exports.fillInTheBlanksJsonSchema = fillInTheBlanksJsonSchema; exports.writtenResponseJsonSchema = writtenResponseJsonSchema; exports.jsonSchemaFor = jsonSchemaFor; exports.validateActivity = validateActivity;
222
+ //# sourceMappingURL=chunk-DQKJUMUW.cjs.map