@intellectif/lk-core 0.2.1 → 0.3.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 (59) hide show
  1. package/dist/activity-zdcAMtFB.d.cts +626 -0
  2. package/dist/activity-zdcAMtFB.d.ts +626 -0
  3. package/dist/chunk-3YAVDV5F.js +47 -0
  4. package/dist/chunk-3YAVDV5F.js.map +1 -0
  5. package/dist/chunk-55O4M45K.js +57 -0
  6. package/dist/chunk-55O4M45K.js.map +1 -0
  7. package/dist/chunk-5GJJHGY5.js +576 -0
  8. package/dist/chunk-5GJJHGY5.js.map +1 -0
  9. package/dist/{chunk-ZHOX6TO4.js → chunk-HS7BYCGE.js} +65 -7
  10. package/dist/chunk-HS7BYCGE.js.map +1 -0
  11. package/dist/chunk-PIMX4B4D.cjs +47 -0
  12. package/dist/chunk-PIMX4B4D.cjs.map +1 -0
  13. package/dist/chunk-QOAORTA4.cjs +576 -0
  14. package/dist/chunk-QOAORTA4.cjs.map +1 -0
  15. package/dist/chunk-QSVBYTNM.js +94 -0
  16. package/dist/chunk-QSVBYTNM.js.map +1 -0
  17. package/dist/{chunk-PJFDAP54.cjs → chunk-RUGIOQZY.cjs} +66 -8
  18. package/dist/chunk-RUGIOQZY.cjs.map +1 -0
  19. package/dist/chunk-THSZMZND.cjs +94 -0
  20. package/dist/chunk-THSZMZND.cjs.map +1 -0
  21. package/dist/chunk-YNTYWHZI.cjs +57 -0
  22. package/dist/chunk-YNTYWHZI.cjs.map +1 -0
  23. package/dist/index.cjs +185 -6
  24. package/dist/index.cjs.map +1 -1
  25. package/dist/index.d.cts +253 -7
  26. package/dist/index.d.ts +253 -7
  27. package/dist/index.js +188 -9
  28. package/dist/index.js.map +1 -1
  29. package/dist/schemas.cjs +29 -2
  30. package/dist/schemas.cjs.map +1 -1
  31. package/dist/schemas.d.cts +310 -29
  32. package/dist/schemas.d.ts +310 -29
  33. package/dist/schemas.js +32 -5
  34. package/dist/scoring.cjs +13 -3
  35. package/dist/scoring.cjs.map +1 -1
  36. package/dist/scoring.d.cts +29 -5
  37. package/dist/scoring.d.ts +29 -5
  38. package/dist/scoring.js +12 -2
  39. package/dist/xapi.cjs +3 -3
  40. package/dist/xapi.d.cts +40 -2
  41. package/dist/xapi.d.ts +40 -2
  42. package/dist/xapi.js +2 -2
  43. package/package.json +7 -2
  44. package/dist/activity-D5tqgx8A.d.cts +0 -330
  45. package/dist/activity-D5tqgx8A.d.ts +0 -330
  46. package/dist/chunk-2T3IL7VL.js +0 -147
  47. package/dist/chunk-2T3IL7VL.js.map +0 -1
  48. package/dist/chunk-3JMLUUFS.cjs +0 -124
  49. package/dist/chunk-3JMLUUFS.cjs.map +0 -1
  50. package/dist/chunk-6VOCV4EX.js +0 -25
  51. package/dist/chunk-6VOCV4EX.js.map +0 -1
  52. package/dist/chunk-DCDOTQNH.cjs +0 -147
  53. package/dist/chunk-DCDOTQNH.cjs.map +0 -1
  54. package/dist/chunk-DV466SBJ.cjs +0 -25
  55. package/dist/chunk-DV466SBJ.cjs.map +0 -1
  56. package/dist/chunk-GZ73G2TS.js +0 -124
  57. package/dist/chunk-GZ73G2TS.js.map +0 -1
  58. package/dist/chunk-PJFDAP54.cjs.map +0 -1
  59. package/dist/chunk-ZHOX6TO4.js.map +0 -1
package/dist/schemas.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- import { e as ActivityType, j as ValidationResult, a as ActivityDataMap } from './activity-D5tqgx8A.js';
1
+ import { e as ActivityType, o as ValidationResult, a as ActivityDataMap } from './activity-zdcAMtFB.js';
2
2
  import { z } from 'zod/v4';
3
3
 
4
4
  /**
@@ -9,23 +9,63 @@ import { z } from 'zod/v4';
9
9
  declare const FeedbackSchema: z.ZodObject<{
10
10
  correct: z.ZodOptional<z.ZodString>;
11
11
  incorrect: z.ZodOptional<z.ZodString>;
12
- }, z.core.$strip>;
12
+ }, z.core.$loose>;
13
13
 
14
- /** Zod schema for a single fill-in-the-blank slot configuration. */
14
+ /**
15
+ * Zod schema for a `TextMatchPolicy` — the opt-in matching tolerances a blank
16
+ * may declare. Every default reproduces the v1 trim + case-fold semantics.
17
+ */
18
+ declare const TextMatchPolicySchema: z.ZodObject<{
19
+ caseSensitive: z.ZodOptional<z.ZodBoolean>;
20
+ trim: z.ZodOptional<z.ZodBoolean>;
21
+ normalize: z.ZodOptional<z.ZodEnum<{
22
+ none: "none";
23
+ NFC: "NFC";
24
+ NFKC: "NFKC";
25
+ }>>;
26
+ foldDiacritics: z.ZodOptional<z.ZodBoolean>;
27
+ collapseInnerWhitespace: z.ZodOptional<z.ZodBoolean>;
28
+ ignorePunctuation: z.ZodOptional<z.ZodBoolean>;
29
+ levenshtein: z.ZodOptional<z.ZodNumber>;
30
+ locale: z.ZodOptional<z.ZodString>;
31
+ }, z.core.$loose>;
32
+ /**
33
+ * Zod schema for a single fill-in-the-blank slot configuration. Loose:
34
+ * unknown keys are preserved through validation. Accepted answers must
35
+ * contain non-whitespace characters — a whitespace-only accepted answer
36
+ * normalizes to the empty string and would mark an empty response correct.
37
+ */
15
38
  declare const BlankConfigSchema: z.ZodObject<{
16
39
  id: z.ZodString;
17
40
  acceptedAnswers: z.ZodArray<z.ZodString>;
18
41
  caseSensitive: z.ZodOptional<z.ZodBoolean>;
19
42
  trimWhitespace: z.ZodOptional<z.ZodBoolean>;
43
+ match: z.ZodOptional<z.ZodObject<{
44
+ caseSensitive: z.ZodOptional<z.ZodBoolean>;
45
+ trim: z.ZodOptional<z.ZodBoolean>;
46
+ normalize: z.ZodOptional<z.ZodEnum<{
47
+ none: "none";
48
+ NFC: "NFC";
49
+ NFKC: "NFKC";
50
+ }>>;
51
+ foldDiacritics: z.ZodOptional<z.ZodBoolean>;
52
+ collapseInnerWhitespace: z.ZodOptional<z.ZodBoolean>;
53
+ ignorePunctuation: z.ZodOptional<z.ZodBoolean>;
54
+ levenshtein: z.ZodOptional<z.ZodNumber>;
55
+ locale: z.ZodOptional<z.ZodString>;
56
+ }, z.core.$loose>>;
20
57
  hint: z.ZodOptional<z.ZodString>;
21
58
  feedback: z.ZodOptional<z.ZodString>;
22
- }, z.core.$strip>;
59
+ }, z.core.$loose>;
23
60
  /**
24
61
  * Zod schema validating the full Fill-in-the-Blanks activity data contract.
62
+ * Loose at every level: unknown keys are preserved, never stripped (B7).
25
63
  *
26
- * The refinement enforces a bijection between `{{id}}` placeholders in the
27
- * passage and `blanks[].id`; otherwise a blank could never be rendered, or a
28
- * placeholder could have no scoring config, yielding undefined behaviour.
64
+ * The refinement enforces a true one-to-one correspondence between `{{id}}`
65
+ * placeholders and `blanks[].id`: every blank id appears EXACTLY ONCE in the
66
+ * passage and exactly once in `blanks[]`. (The previous set-based check let
67
+ * duplicate placeholders and duplicate blank configs through, corrupting the
68
+ * partial-score denominator and per-item details.)
29
69
  */
30
70
  declare const FillInTheBlanksDataSchema: z.ZodObject<{
31
71
  schemaVersion: z.ZodLiteral<"1.0">;
@@ -33,14 +73,29 @@ declare const FillInTheBlanksDataSchema: z.ZodObject<{
33
73
  id: z.ZodString;
34
74
  title: z.ZodString;
35
75
  passage: z.ZodString;
76
+ passageHtml: z.ZodOptional<z.ZodString>;
36
77
  blanks: z.ZodArray<z.ZodObject<{
37
78
  id: z.ZodString;
38
79
  acceptedAnswers: z.ZodArray<z.ZodString>;
39
80
  caseSensitive: z.ZodOptional<z.ZodBoolean>;
40
81
  trimWhitespace: z.ZodOptional<z.ZodBoolean>;
82
+ match: z.ZodOptional<z.ZodObject<{
83
+ caseSensitive: z.ZodOptional<z.ZodBoolean>;
84
+ trim: z.ZodOptional<z.ZodBoolean>;
85
+ normalize: z.ZodOptional<z.ZodEnum<{
86
+ none: "none";
87
+ NFC: "NFC";
88
+ NFKC: "NFKC";
89
+ }>>;
90
+ foldDiacritics: z.ZodOptional<z.ZodBoolean>;
91
+ collapseInnerWhitespace: z.ZodOptional<z.ZodBoolean>;
92
+ ignorePunctuation: z.ZodOptional<z.ZodBoolean>;
93
+ levenshtein: z.ZodOptional<z.ZodNumber>;
94
+ locale: z.ZodOptional<z.ZodString>;
95
+ }, z.core.$loose>>;
41
96
  hint: z.ZodOptional<z.ZodString>;
42
97
  feedback: z.ZodOptional<z.ZodString>;
43
- }, z.core.$strip>>;
98
+ }, z.core.$loose>>;
44
99
  scoringStrategy: z.ZodEnum<{
45
100
  "all-or-nothing": "all-or-nothing";
46
101
  partial: "partial";
@@ -52,19 +107,19 @@ declare const FillInTheBlanksDataSchema: z.ZodObject<{
52
107
  video: "video";
53
108
  embed: "embed";
54
109
  }>;
55
- url: z.ZodURL;
110
+ url: z.ZodUnion<readonly [z.ZodURL, z.ZodString]>;
56
111
  alt: z.ZodOptional<z.ZodString>;
57
- captionsUrl: z.ZodOptional<z.ZodURL>;
58
- }, z.core.$strip>>;
112
+ captionsUrl: z.ZodOptional<z.ZodUnion<readonly [z.ZodURL, z.ZodString]>>;
113
+ }, z.core.$loose>>;
59
114
  feedback: z.ZodOptional<z.ZodObject<{
60
115
  correct: z.ZodOptional<z.ZodString>;
61
116
  incorrect: z.ZodOptional<z.ZodString>;
62
- }, z.core.$strip>>;
117
+ }, z.core.$loose>>;
63
118
  passThreshold: z.ZodOptional<z.ZodNumber>;
64
119
  locale: z.ZodOptional<z.ZodString>;
65
120
  learningObjectives: z.ZodOptional<z.ZodArray<z.ZodString>>;
66
121
  difficultyLevel: z.ZodOptional<z.ZodLiteral<1 | 2 | 3 | 4 | 5>>;
67
- }, z.core.$strip>;
122
+ }, z.core.$loose>;
68
123
 
69
124
  /**
70
125
  * JSON Schema (Draft 7) representation of the Multiple Choice activity data
@@ -72,6 +127,9 @@ declare const FillInTheBlanksDataSchema: z.ZodObject<{
72
127
  * 2.2 for the widest AI-prompt / OpenAPI tooling compatibility. The semantic
73
128
  * `.refine()` guards are not representable in JSON Schema and are
74
129
  * intentionally omitted — the export captures the *structural* contract only.
130
+ * Since v0.3 the source schemas are loose, so these no longer emit
131
+ * `additionalProperties: false` — the JSON Schema and `validateActivity` now
132
+ * agree on unknown-key handling.
75
133
  */
76
134
  declare const multipleChoiceJsonSchema: z.core.JSONSchema.JSONSchema;
77
135
  /**
@@ -80,6 +138,20 @@ declare const multipleChoiceJsonSchema: z.core.JSONSchema.JSONSchema;
80
138
  * `.refine()` guards are Zod-only and not representable in JSON Schema).
81
139
  */
82
140
  declare const fillInTheBlanksJsonSchema: z.core.JSONSchema.JSONSchema;
141
+ /**
142
+ * JSON Schema (Draft 7) representation of the Written Response activity data
143
+ * contract. Structural contract only.
144
+ */
145
+ declare const writtenResponseJsonSchema: z.core.JSONSchema.JSONSchema;
146
+ /**
147
+ * Derives the JSON Schema (Draft 7) for any REGISTERED activity type — the
148
+ * live, registry-backed replacement for the static per-type exports above,
149
+ * and the building block for AI generation pipelines (R6.1): pass the result
150
+ * as a structured-output schema so a model can only emit valid items.
151
+ *
152
+ * @throws UnknownActivityTypeError when `type` has no registered descriptor.
153
+ */
154
+ declare function jsonSchemaFor(type: string): Record<string, unknown>;
83
155
 
84
156
  /**
85
157
  * Optional media attached to an activity, rendered above the question or
@@ -97,6 +169,15 @@ declare const fillInTheBlanksJsonSchema: z.core.JSONSchema.JSONSchema;
97
169
  * (e.g. `https://www.youtube.com/embed/<id>`). `alt` is REQUIRED and used
98
170
  * as the iframe's accessible `title` (WCAG 4.1.2 / 2.4.1).
99
171
  */
172
+ /**
173
+ * Media URL policy (security-reviewed): absolute URLs must use `https:`,
174
+ * `http:`, `data:`, or `blob:`; root-relative paths (`/media/x.mp3`) are
175
+ * allowed for same-origin hosting. Everything else — notably `javascript:`,
176
+ * `file:`, `ftp:` — is rejected: these URLs land in `src` attributes
177
+ * (including an iframe for `embed`), so an unvetted scheme is a stored-XSS
178
+ * vector in every consuming app.
179
+ */
180
+ declare const MediaUrlSchema: z.ZodUnion<readonly [z.ZodURL, z.ZodString]>;
100
181
  declare const MediaSchema: z.ZodObject<{
101
182
  type: z.ZodEnum<{
102
183
  image: "image";
@@ -104,27 +185,35 @@ declare const MediaSchema: z.ZodObject<{
104
185
  video: "video";
105
186
  embed: "embed";
106
187
  }>;
107
- url: z.ZodURL;
188
+ url: z.ZodUnion<readonly [z.ZodURL, z.ZodString]>;
108
189
  alt: z.ZodOptional<z.ZodString>;
109
- captionsUrl: z.ZodOptional<z.ZodURL>;
110
- }, z.core.$strip>;
190
+ captionsUrl: z.ZodOptional<z.ZodUnion<readonly [z.ZodURL, z.ZodString]>>;
191
+ }, z.core.$loose>;
111
192
 
112
- /** Zod schema for a single Multiple Choice option. */
193
+ /**
194
+ * Zod schema for a single Multiple Choice option. Loose: unknown keys are
195
+ * preserved through validation (forward-compat / consumer sidecars — B7).
196
+ */
113
197
  declare const MultipleChoiceOptionSchema: z.ZodObject<{
114
198
  id: z.ZodString;
115
199
  text: z.ZodString;
116
200
  isCorrect: z.ZodBoolean;
117
201
  feedback: z.ZodOptional<z.ZodString>;
118
- }, z.core.$strip>;
202
+ }, z.core.$loose>;
119
203
  /**
120
204
  * Zod schema validating the full Multiple Choice activity data contract.
205
+ * Loose at every level: unknown keys are preserved, never stripped, so a
206
+ * v0.3 runtime reading a future payload (or a consumer sidecar field) does
207
+ * not silently delete data.
121
208
  *
122
- * Two semantic guards: (1) at least one option must be correct, otherwise the
209
+ * Semantic guards: (1) at least one option must be correct, otherwise the
123
210
  * activity can never be answered correctly; (2) `mode: 'single'` must have
124
211
  * exactly one correct option — multiple correct options under single-select
125
212
  * make `showCorrectAnswers` and the xAPI correct-response ambiguous and mask
126
- * authoring errors. Both are unrepresentable in JSON Schema and are dropped
127
- * from `toJSONSchema` output by design.
213
+ * authoring errors; (3) option ids must be unique the scorer looks options
214
+ * up by id, so a duplicate id makes one option unscoreable. All are
215
+ * unrepresentable in JSON Schema and are dropped from `toJSONSchema` output
216
+ * by design.
128
217
  */
129
218
  declare const MultipleChoiceDataSchema: z.ZodObject<{
130
219
  schemaVersion: z.ZodLiteral<"1.0">;
@@ -132,6 +221,7 @@ declare const MultipleChoiceDataSchema: z.ZodObject<{
132
221
  id: z.ZodString;
133
222
  title: z.ZodString;
134
223
  question: z.ZodString;
224
+ questionHtml: z.ZodOptional<z.ZodString>;
135
225
  mode: z.ZodEnum<{
136
226
  single: "single";
137
227
  multi: "multi";
@@ -141,7 +231,7 @@ declare const MultipleChoiceDataSchema: z.ZodObject<{
141
231
  text: z.ZodString;
142
232
  isCorrect: z.ZodBoolean;
143
233
  feedback: z.ZodOptional<z.ZodString>;
144
- }, z.core.$strip>>;
234
+ }, z.core.$loose>>;
145
235
  scoringStrategy: z.ZodEnum<{
146
236
  "all-or-nothing": "all-or-nothing";
147
237
  partial: "partial";
@@ -153,27 +243,218 @@ declare const MultipleChoiceDataSchema: z.ZodObject<{
153
243
  video: "video";
154
244
  embed: "embed";
155
245
  }>;
156
- url: z.ZodURL;
246
+ url: z.ZodUnion<readonly [z.ZodURL, z.ZodString]>;
157
247
  alt: z.ZodOptional<z.ZodString>;
158
- captionsUrl: z.ZodOptional<z.ZodURL>;
159
- }, z.core.$strip>>;
248
+ captionsUrl: z.ZodOptional<z.ZodUnion<readonly [z.ZodURL, z.ZodString]>>;
249
+ }, z.core.$loose>>;
160
250
  feedback: z.ZodOptional<z.ZodObject<{
161
251
  correct: z.ZodOptional<z.ZodString>;
162
252
  incorrect: z.ZodOptional<z.ZodString>;
163
- }, z.core.$strip>>;
253
+ }, z.core.$loose>>;
164
254
  passThreshold: z.ZodOptional<z.ZodNumber>;
165
255
  shuffle: z.ZodOptional<z.ZodBoolean>;
166
256
  locale: z.ZodOptional<z.ZodString>;
167
257
  learningObjectives: z.ZodOptional<z.ZodArray<z.ZodString>>;
168
258
  difficultyLevel: z.ZodOptional<z.ZodLiteral<1 | 2 | 3 | 4 | 5>>;
169
- }, z.core.$strip>;
259
+ }, z.core.$loose>;
260
+
261
+ /** A redacted Multiple Choice option: id and display text only — no `isCorrect`, no feedback. */
262
+ declare const RedactedMultipleChoiceOptionSchema: z.ZodObject<{
263
+ id: z.ZodString;
264
+ text: z.ZodString;
265
+ }, z.core.$strict>;
266
+ /**
267
+ * Redacted Multiple Choice data: renderable (question, mode, options to pick
268
+ * from) with the answer key, per-option feedback, overall feedback, and the
269
+ * scoring strategy removed. `scoringStrategy` is answer-key by design: MC
270
+ * `partial` carries a wrong-selection penalty `all-or-nothing` does not, so
271
+ * knowing the strategy tells a learner whether guessing is free.
272
+ */
273
+ declare const RedactedMultipleChoiceDataSchema: z.ZodObject<{
274
+ type: z.ZodLiteral<"multiple-choice">;
275
+ question: z.ZodString;
276
+ questionHtml: z.ZodOptional<z.ZodString>;
277
+ mode: z.ZodEnum<{
278
+ single: "single";
279
+ multi: "multi";
280
+ }>;
281
+ options: z.ZodArray<z.ZodObject<{
282
+ id: z.ZodString;
283
+ text: z.ZodString;
284
+ }, z.core.$strict>>;
285
+ shuffle: z.ZodOptional<z.ZodBoolean>;
286
+ /** Marker distinguishing a redacted projection from full activity data. */
287
+ redacted: z.ZodLiteral<true>;
288
+ schemaVersion: z.ZodLiteral<"1.0">;
289
+ id: z.ZodString;
290
+ title: z.ZodString;
291
+ media: z.ZodOptional<z.ZodObject<{
292
+ type: z.ZodEnum<{
293
+ image: "image";
294
+ audio: "audio";
295
+ video: "video";
296
+ embed: "embed";
297
+ }>;
298
+ url: z.ZodUnion<readonly [z.ZodURL, z.ZodString]>;
299
+ alt: z.ZodOptional<z.ZodString>;
300
+ captionsUrl: z.ZodOptional<z.ZodUnion<readonly [z.ZodURL, z.ZodString]>>;
301
+ }, z.core.$loose>>;
302
+ passThreshold: z.ZodOptional<z.ZodNumber>;
303
+ locale: z.ZodOptional<z.ZodString>;
304
+ learningObjectives: z.ZodOptional<z.ZodArray<z.ZodString>>;
305
+ difficultyLevel: z.ZodOptional<z.ZodLiteral<1 | 2 | 3 | 4 | 5>>;
306
+ }, z.core.$strict>;
307
+ /** A redacted blank: id and hint only — no accepted answers, no matching rules, no feedback. */
308
+ declare const RedactedBlankConfigSchema: z.ZodObject<{
309
+ id: z.ZodString;
310
+ hint: z.ZodOptional<z.ZodString>;
311
+ }, z.core.$strict>;
312
+ /** Redacted Fill-in-the-Blanks data: passage and blank slots, key removed. */
313
+ declare const RedactedFillInTheBlanksDataSchema: z.ZodObject<{
314
+ type: z.ZodLiteral<"fill-in-the-blanks">;
315
+ passage: z.ZodString;
316
+ passageHtml: z.ZodOptional<z.ZodString>;
317
+ blanks: z.ZodArray<z.ZodObject<{
318
+ id: z.ZodString;
319
+ hint: z.ZodOptional<z.ZodString>;
320
+ }, z.core.$strict>>;
321
+ /** Marker distinguishing a redacted projection from full activity data. */
322
+ redacted: z.ZodLiteral<true>;
323
+ schemaVersion: z.ZodLiteral<"1.0">;
324
+ id: z.ZodString;
325
+ title: z.ZodString;
326
+ media: z.ZodOptional<z.ZodObject<{
327
+ type: z.ZodEnum<{
328
+ image: "image";
329
+ audio: "audio";
330
+ video: "video";
331
+ embed: "embed";
332
+ }>;
333
+ url: z.ZodUnion<readonly [z.ZodURL, z.ZodString]>;
334
+ alt: z.ZodOptional<z.ZodString>;
335
+ captionsUrl: z.ZodOptional<z.ZodUnion<readonly [z.ZodURL, z.ZodString]>>;
336
+ }, z.core.$loose>>;
337
+ passThreshold: z.ZodOptional<z.ZodNumber>;
338
+ locale: z.ZodOptional<z.ZodString>;
339
+ learningObjectives: z.ZodOptional<z.ZodArray<z.ZodString>>;
340
+ difficultyLevel: z.ZodOptional<z.ZodLiteral<1 | 2 | 3 | 4 | 5>>;
341
+ }, z.core.$strict>;
342
+ /**
343
+ * Redacted Written Response data: the prompt, word bounds and rubric are
344
+ * learner-visible (a rubric tells the learner what they are graded on);
345
+ * authored pass/fail feedback is removed until the grade exists.
346
+ */
347
+ declare const RedactedWrittenResponseDataSchema: z.ZodObject<{
348
+ type: z.ZodLiteral<"written-response">;
349
+ prompt: z.ZodString;
350
+ promptHtml: z.ZodOptional<z.ZodString>;
351
+ minWords: z.ZodNumber;
352
+ maxWords: z.ZodNumber;
353
+ rubric: z.ZodOptional<z.ZodObject<{
354
+ label: z.ZodOptional<z.ZodString>;
355
+ criteria: z.ZodArray<z.ZodObject<{
356
+ name: z.ZodString;
357
+ description: z.ZodOptional<z.ZodString>;
358
+ weight: z.ZodNumber;
359
+ }, z.core.$loose>>;
360
+ }, z.core.$loose>>;
361
+ languageTarget: z.ZodOptional<z.ZodString>;
362
+ /** Marker distinguishing a redacted projection from full activity data. */
363
+ redacted: z.ZodLiteral<true>;
364
+ schemaVersion: z.ZodLiteral<"1.0">;
365
+ id: z.ZodString;
366
+ title: z.ZodString;
367
+ media: z.ZodOptional<z.ZodObject<{
368
+ type: z.ZodEnum<{
369
+ image: "image";
370
+ audio: "audio";
371
+ video: "video";
372
+ embed: "embed";
373
+ }>;
374
+ url: z.ZodUnion<readonly [z.ZodURL, z.ZodString]>;
375
+ alt: z.ZodOptional<z.ZodString>;
376
+ captionsUrl: z.ZodOptional<z.ZodUnion<readonly [z.ZodURL, z.ZodString]>>;
377
+ }, z.core.$loose>>;
378
+ passThreshold: z.ZodOptional<z.ZodNumber>;
379
+ locale: z.ZodOptional<z.ZodString>;
380
+ learningObjectives: z.ZodOptional<z.ZodArray<z.ZodString>>;
381
+ difficultyLevel: z.ZodOptional<z.ZodLiteral<1 | 2 | 3 | 4 | 5>>;
382
+ }, z.core.$strict>;
170
383
 
384
+ /** Zod schema for a single rubric criterion. Loose: unknown keys preserved. */
385
+ declare const WrittenResponseRubricCriterionSchema: z.ZodObject<{
386
+ name: z.ZodString;
387
+ description: z.ZodOptional<z.ZodString>;
388
+ weight: z.ZodNumber;
389
+ }, z.core.$loose>;
390
+ /** Zod schema for a written-response grading rubric. Loose: unknown keys preserved. */
391
+ declare const WrittenResponseRubricSchema: z.ZodObject<{
392
+ label: z.ZodOptional<z.ZodString>;
393
+ criteria: z.ZodArray<z.ZodObject<{
394
+ name: z.ZodString;
395
+ description: z.ZodOptional<z.ZodString>;
396
+ weight: z.ZodNumber;
397
+ }, z.core.$loose>>;
398
+ }, z.core.$loose>;
171
399
  /**
172
- * Validates raw activity data against the schema for the given activity type.
400
+ * Zod schema validating the Written Response activity data contract (Req 22).
401
+ *
402
+ * Wire-format constraints (Req 22.9): field names are locked for
403
+ * byte-compatibility with consumer-stored rows, and the schema is loose at
404
+ * EVERY level (Req 22.5) — unknown top-level keys, `promptHtml`, `rubric`
405
+ * sidecars and any future fields survive `validateActivity` verbatim.
406
+ */
407
+ declare const WrittenResponseDataSchema: z.ZodObject<{
408
+ schemaVersion: z.ZodLiteral<"1.0">;
409
+ type: z.ZodLiteral<"written-response">;
410
+ id: z.ZodString;
411
+ title: z.ZodString;
412
+ prompt: z.ZodString;
413
+ promptHtml: z.ZodOptional<z.ZodString>;
414
+ minWords: z.ZodNumber;
415
+ maxWords: z.ZodNumber;
416
+ rubric: z.ZodOptional<z.ZodObject<{
417
+ label: z.ZodOptional<z.ZodString>;
418
+ criteria: z.ZodArray<z.ZodObject<{
419
+ name: z.ZodString;
420
+ description: z.ZodOptional<z.ZodString>;
421
+ weight: z.ZodNumber;
422
+ }, z.core.$loose>>;
423
+ }, z.core.$loose>>;
424
+ languageTarget: z.ZodOptional<z.ZodString>;
425
+ media: z.ZodOptional<z.ZodObject<{
426
+ type: z.ZodEnum<{
427
+ image: "image";
428
+ audio: "audio";
429
+ video: "video";
430
+ embed: "embed";
431
+ }>;
432
+ url: z.ZodUnion<readonly [z.ZodURL, z.ZodString]>;
433
+ alt: z.ZodOptional<z.ZodString>;
434
+ captionsUrl: z.ZodOptional<z.ZodUnion<readonly [z.ZodURL, z.ZodString]>>;
435
+ }, z.core.$loose>>;
436
+ feedback: z.ZodOptional<z.ZodObject<{
437
+ correct: z.ZodOptional<z.ZodString>;
438
+ incorrect: z.ZodOptional<z.ZodString>;
439
+ }, z.core.$loose>>;
440
+ passThreshold: z.ZodOptional<z.ZodNumber>;
441
+ locale: z.ZodOptional<z.ZodString>;
442
+ learningObjectives: z.ZodOptional<z.ZodArray<z.ZodString>>;
443
+ difficultyLevel: z.ZodOptional<z.ZodLiteral<1 | 2 | 3 | 4 | 5>>;
444
+ }, z.core.$loose>;
445
+
446
+ /**
447
+ * Validates raw activity data against the schema registered for the given
448
+ * activity type (built-in or consumer-registered via `registerActivityType`).
449
+ *
450
+ * Unknown keys are PRESERVED, not stripped: every built-in schema is loose,
451
+ * so consumer sidecar fields and forward-version fields survive validation
452
+ * verbatim in the returned `data`.
173
453
  *
174
454
  * @returns `{ success: true, data }` with the typed, validated data, or
175
455
  * `{ success: false, errors }` with one entry per failed constraint.
456
+ * @throws UnknownActivityTypeError when `type` has no registered descriptor.
176
457
  */
177
458
  declare function validateActivity<T extends ActivityType>(type: T, data: unknown): ValidationResult<ActivityDataMap[T]>;
178
459
 
179
- export { BlankConfigSchema, FeedbackSchema, FillInTheBlanksDataSchema, MediaSchema, MultipleChoiceDataSchema, MultipleChoiceOptionSchema, fillInTheBlanksJsonSchema, multipleChoiceJsonSchema, validateActivity };
460
+ export { BlankConfigSchema, FeedbackSchema, FillInTheBlanksDataSchema, MediaSchema, MediaUrlSchema, MultipleChoiceDataSchema, MultipleChoiceOptionSchema, RedactedBlankConfigSchema, RedactedFillInTheBlanksDataSchema, RedactedMultipleChoiceDataSchema, RedactedMultipleChoiceOptionSchema, RedactedWrittenResponseDataSchema, TextMatchPolicySchema, WrittenResponseDataSchema, WrittenResponseRubricCriterionSchema, WrittenResponseRubricSchema, fillInTheBlanksJsonSchema, jsonSchemaFor, multipleChoiceJsonSchema, validateActivity, writtenResponseJsonSchema };
package/dist/schemas.js CHANGED
@@ -1,23 +1,50 @@
1
+ import {
2
+ fillInTheBlanksJsonSchema,
3
+ jsonSchemaFor,
4
+ multipleChoiceJsonSchema,
5
+ validateActivity,
6
+ writtenResponseJsonSchema
7
+ } from "./chunk-55O4M45K.js";
1
8
  import {
2
9
  BlankConfigSchema,
3
10
  FeedbackSchema,
4
11
  FillInTheBlanksDataSchema,
5
12
  MediaSchema,
13
+ MediaUrlSchema,
6
14
  MultipleChoiceDataSchema,
7
15
  MultipleChoiceOptionSchema,
8
- fillInTheBlanksJsonSchema,
9
- multipleChoiceJsonSchema,
10
- validateActivity
11
- } from "./chunk-2T3IL7VL.js";
16
+ RedactedBlankConfigSchema,
17
+ RedactedFillInTheBlanksDataSchema,
18
+ RedactedMultipleChoiceDataSchema,
19
+ RedactedMultipleChoiceOptionSchema,
20
+ RedactedWrittenResponseDataSchema,
21
+ TextMatchPolicySchema,
22
+ WrittenResponseDataSchema,
23
+ WrittenResponseRubricCriterionSchema,
24
+ WrittenResponseRubricSchema
25
+ } from "./chunk-5GJJHGY5.js";
26
+ import "./chunk-3YAVDV5F.js";
12
27
  export {
13
28
  BlankConfigSchema,
14
29
  FeedbackSchema,
15
30
  FillInTheBlanksDataSchema,
16
31
  MediaSchema,
32
+ MediaUrlSchema,
17
33
  MultipleChoiceDataSchema,
18
34
  MultipleChoiceOptionSchema,
35
+ RedactedBlankConfigSchema,
36
+ RedactedFillInTheBlanksDataSchema,
37
+ RedactedMultipleChoiceDataSchema,
38
+ RedactedMultipleChoiceOptionSchema,
39
+ RedactedWrittenResponseDataSchema,
40
+ TextMatchPolicySchema,
41
+ WrittenResponseDataSchema,
42
+ WrittenResponseRubricCriterionSchema,
43
+ WrittenResponseRubricSchema,
19
44
  fillInTheBlanksJsonSchema,
45
+ jsonSchemaFor,
20
46
  multipleChoiceJsonSchema,
21
- validateActivity
47
+ validateActivity,
48
+ writtenResponseJsonSchema
22
49
  };
23
50
  //# sourceMappingURL=schemas.js.map
package/dist/scoring.cjs CHANGED
@@ -1,10 +1,20 @@
1
1
  "use strict";Object.defineProperty(exports, "__esModule", {value: true});
2
2
 
3
3
 
4
- var _chunk3JMLUUFScjs = require('./chunk-3JMLUUFS.cjs');
5
- require('./chunk-DV466SBJ.cjs');
6
4
 
7
5
 
6
+ var _chunkTHSZMZNDcjs = require('./chunk-THSZMZND.cjs');
8
7
 
9
- exports.computePassThreshold = _chunk3JMLUUFScjs.computePassThreshold; exports.score = _chunk3JMLUUFScjs.score;
8
+
9
+
10
+ var _chunkQOAORTA4cjs = require('./chunk-QOAORTA4.cjs');
11
+ require('./chunk-PIMX4B4D.cjs');
12
+
13
+
14
+
15
+
16
+
17
+
18
+
19
+ exports.DEFAULT_PASS_THRESHOLD = _chunkTHSZMZNDcjs.DEFAULT_PASS_THRESHOLD; exports.computePassThreshold = _chunkTHSZMZNDcjs.computePassThreshold; exports.evaluate = _chunkTHSZMZNDcjs.evaluate; exports.levenshteinDistance = _chunkQOAORTA4cjs.levenshteinDistance; exports.matchText = _chunkQOAORTA4cjs.matchText; exports.score = _chunkTHSZMZNDcjs.score;
10
20
  //# sourceMappingURL=scoring.cjs.map
@@ -1 +1 @@
1
- {"version":3,"sources":["/home/runner/work/learning-kit/learning-kit/packages/lk-core/dist/scoring.cjs"],"names":[],"mappings":"AAAA;AACE;AACA;AACF,wDAA6B;AAC7B,gCAA6B;AAC7B;AACE;AACA;AACF,+GAAC","file":"/home/runner/work/learning-kit/learning-kit/packages/lk-core/dist/scoring.cjs"}
1
+ {"version":3,"sources":["/home/runner/work/learning-kit/learning-kit/packages/lk-core/dist/scoring.cjs"],"names":[],"mappings":"AAAA;AACE;AACA;AACA;AACA;AACF,wDAA6B;AAC7B;AACE;AACA;AACF,wDAA6B;AAC7B,gCAA6B;AAC7B;AACE;AACA;AACA;AACA;AACA;AACA;AACF,+VAAC","file":"/home/runner/work/learning-kit/learning-kit/packages/lk-core/dist/scoring.cjs"}
@@ -1,8 +1,11 @@
1
- import { A as ActivityData, e as ActivityType, L as LearnerResponse, i as ScoringResult } from './activity-D5tqgx8A.cjs';
1
+ import { A as ActivityData, L as LearnerResponse, h as ItemOutcome, e as ActivityType, m as ScoringResult } from './activity-zdcAMtFB.cjs';
2
+ export { T as TextMatchPolicy, n as TextMatchResult, E as levenshteinDistance, G as matchText } from './activity-zdcAMtFB.cjs';
2
3
 
4
+ /** Default minimum scaled score required to pass when `passThreshold` is absent. */
5
+ declare const DEFAULT_PASS_THRESHOLD = 0.7;
3
6
  /**
4
7
  * Returns `true` iff `score` meets or exceeds the activity's `passThreshold`,
5
- * defaulting to {@link DEFAULT_PASS_THRESHOLD} when the field is absent.
8
+ * defaulting to {@link DEFAULT_PASS_THRESHOLD} (0.7) when the field is absent.
6
9
  */
7
10
  declare function computePassThreshold(activityData: ActivityData, score: number): boolean;
8
11
  /**
@@ -12,9 +15,30 @@ declare function computePassThreshold(activityData: ActivityData, score: number)
12
15
  * Pure and deterministic with no side effects. It does **not** re-validate
13
16
  * `activityData` — schema validation is the component boundary's
14
17
  * responsibility; this is a low-level scoring primitive that trusts its typed
15
- * inputs. Dispatches on `activityType`; an unrecognised type throws
16
- * {@link UnknownActivityTypeError}.
18
+ * inputs. Dispatch is registry-backed: consumer-registered types with `sync`
19
+ * scoring work here too. An unregistered type throws
20
+ * {@link UnknownActivityTypeError}; a type whose grading is deferred (e.g.
21
+ * `written-response`) throws {@link DeferredScoringError} — use
22
+ * {@link evaluate}, which can express "not graded yet".
17
23
  */
18
24
  declare function score(activityType: ActivityType, activityData: ActivityData, learnerResponse: LearnerResponse): ScoringResult;
25
+ /**
26
+ * Evaluates a learner response against an activity and returns an
27
+ * {@link ItemOutcome} — the resilient, forward-compatible alternative to
28
+ * {@link score}:
29
+ *
30
+ * - Synchronously graded types return `{ status: 'scored', ... }` with the
31
+ * same numbers `score()` produces.
32
+ * - Asynchronously graded types (e.g. `written-response`) return
33
+ * `{ status: 'deferred', reason, partial }` instead of a fake zero — "not
34
+ * graded yet" is expressible in the type system, never conflated with
35
+ * "wrong".
36
+ * - An unregistered `data.type` returns `{ status: 'unscorable' }` rather
37
+ * than throwing, so a mixed-version content bank cannot crash an exam run.
38
+ *
39
+ * The activity type is read from `data.type` — there is no separate type
40
+ * parameter to disagree with the payload.
41
+ */
42
+ declare function evaluate(data: ActivityData, response: LearnerResponse): ItemOutcome;
19
43
 
20
- export { computePassThreshold, score };
44
+ export { DEFAULT_PASS_THRESHOLD, computePassThreshold, evaluate, score };
package/dist/scoring.d.ts CHANGED
@@ -1,8 +1,11 @@
1
- import { A as ActivityData, e as ActivityType, L as LearnerResponse, i as ScoringResult } from './activity-D5tqgx8A.js';
1
+ import { A as ActivityData, L as LearnerResponse, h as ItemOutcome, e as ActivityType, m as ScoringResult } from './activity-zdcAMtFB.js';
2
+ export { T as TextMatchPolicy, n as TextMatchResult, E as levenshteinDistance, G as matchText } from './activity-zdcAMtFB.js';
2
3
 
4
+ /** Default minimum scaled score required to pass when `passThreshold` is absent. */
5
+ declare const DEFAULT_PASS_THRESHOLD = 0.7;
3
6
  /**
4
7
  * Returns `true` iff `score` meets or exceeds the activity's `passThreshold`,
5
- * defaulting to {@link DEFAULT_PASS_THRESHOLD} when the field is absent.
8
+ * defaulting to {@link DEFAULT_PASS_THRESHOLD} (0.7) when the field is absent.
6
9
  */
7
10
  declare function computePassThreshold(activityData: ActivityData, score: number): boolean;
8
11
  /**
@@ -12,9 +15,30 @@ declare function computePassThreshold(activityData: ActivityData, score: number)
12
15
  * Pure and deterministic with no side effects. It does **not** re-validate
13
16
  * `activityData` — schema validation is the component boundary's
14
17
  * responsibility; this is a low-level scoring primitive that trusts its typed
15
- * inputs. Dispatches on `activityType`; an unrecognised type throws
16
- * {@link UnknownActivityTypeError}.
18
+ * inputs. Dispatch is registry-backed: consumer-registered types with `sync`
19
+ * scoring work here too. An unregistered type throws
20
+ * {@link UnknownActivityTypeError}; a type whose grading is deferred (e.g.
21
+ * `written-response`) throws {@link DeferredScoringError} — use
22
+ * {@link evaluate}, which can express "not graded yet".
17
23
  */
18
24
  declare function score(activityType: ActivityType, activityData: ActivityData, learnerResponse: LearnerResponse): ScoringResult;
25
+ /**
26
+ * Evaluates a learner response against an activity and returns an
27
+ * {@link ItemOutcome} — the resilient, forward-compatible alternative to
28
+ * {@link score}:
29
+ *
30
+ * - Synchronously graded types return `{ status: 'scored', ... }` with the
31
+ * same numbers `score()` produces.
32
+ * - Asynchronously graded types (e.g. `written-response`) return
33
+ * `{ status: 'deferred', reason, partial }` instead of a fake zero — "not
34
+ * graded yet" is expressible in the type system, never conflated with
35
+ * "wrong".
36
+ * - An unregistered `data.type` returns `{ status: 'unscorable' }` rather
37
+ * than throwing, so a mixed-version content bank cannot crash an exam run.
38
+ *
39
+ * The activity type is read from `data.type` — there is no separate type
40
+ * parameter to disagree with the payload.
41
+ */
42
+ declare function evaluate(data: ActivityData, response: LearnerResponse): ItemOutcome;
19
43
 
20
- export { computePassThreshold, score };
44
+ export { DEFAULT_PASS_THRESHOLD, computePassThreshold, evaluate, score };
package/dist/scoring.js CHANGED
@@ -1,10 +1,20 @@
1
1
  import {
2
+ DEFAULT_PASS_THRESHOLD,
2
3
  computePassThreshold,
4
+ evaluate,
3
5
  score
4
- } from "./chunk-GZ73G2TS.js";
5
- import "./chunk-6VOCV4EX.js";
6
+ } from "./chunk-QSVBYTNM.js";
7
+ import {
8
+ levenshteinDistance,
9
+ matchText
10
+ } from "./chunk-5GJJHGY5.js";
11
+ import "./chunk-3YAVDV5F.js";
6
12
  export {
13
+ DEFAULT_PASS_THRESHOLD,
7
14
  computePassThreshold,
15
+ evaluate,
16
+ levenshteinDistance,
17
+ matchText,
8
18
  score
9
19
  };
10
20
  //# sourceMappingURL=scoring.js.map