@intellectif/lk-core 0.22.0 → 1.0.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 (64) hide show
  1. package/CHANGELOG.md +15 -0
  2. package/README.md +5 -5
  3. package/dist/{activity-CYc7SD3d.d.cts → activity-DgpBJeBc.d.cts} +11 -15
  4. package/dist/{activity-CYc7SD3d.d.ts → activity-DgpBJeBc.d.ts} +11 -15
  5. package/dist/ai-check.cjs +8 -8
  6. package/dist/ai-check.d.cts +1 -1
  7. package/dist/ai-check.d.ts +1 -1
  8. package/dist/ai-check.js +3 -3
  9. package/dist/{chunk-2CV6NU32.cjs → chunk-2JT2WUQ2.cjs} +77 -39
  10. package/dist/chunk-2JT2WUQ2.cjs.map +1 -0
  11. package/dist/{chunk-D4TOPSHV.cjs → chunk-DSDXL3JO.cjs} +1216 -1105
  12. package/dist/chunk-DSDXL3JO.cjs.map +1 -0
  13. package/dist/{chunk-D3GP5MET.js → chunk-FBKTION6.js} +1093 -982
  14. package/dist/chunk-FBKTION6.js.map +1 -0
  15. package/dist/{chunk-Q7MV3IXJ.js → chunk-IARLJ5MW.js} +15 -16
  16. package/dist/chunk-IARLJ5MW.js.map +1 -0
  17. package/dist/{chunk-5UCR4UNR.js → chunk-RCZCP5OE.js} +12 -7
  18. package/dist/chunk-RCZCP5OE.js.map +1 -0
  19. package/dist/{chunk-X5DAXBJI.js → chunk-SJVRUPJT.js} +2 -2
  20. package/dist/{chunk-EOFWSGLU.cjs → chunk-TJJFKKH2.cjs} +4 -4
  21. package/dist/{chunk-EOFWSGLU.cjs.map → chunk-TJJFKKH2.cjs.map} +1 -1
  22. package/dist/{chunk-WQVZPIN7.cjs → chunk-VSH7ECQL.cjs} +44 -45
  23. package/dist/chunk-VSH7ECQL.cjs.map +1 -0
  24. package/dist/{chunk-OPMY2MNS.cjs → chunk-W5KB3DNT.cjs} +19 -14
  25. package/dist/chunk-W5KB3DNT.cjs.map +1 -0
  26. package/dist/{chunk-Z7QQZ53L.js → chunk-XS6U2ARZ.js} +70 -32
  27. package/dist/chunk-XS6U2ARZ.js.map +1 -0
  28. package/dist/index-BVNeSCWC.d.ts +548 -0
  29. package/dist/index-BlOLlwOi.d.cts +548 -0
  30. package/dist/index.cjs +129 -206
  31. package/dist/index.cjs.map +1 -1
  32. package/dist/index.d.cts +115 -15
  33. package/dist/index.d.ts +115 -15
  34. package/dist/index.js +26 -103
  35. package/dist/index.js.map +1 -1
  36. package/dist/schemas.cjs +3 -94
  37. package/dist/schemas.cjs.map +1 -1
  38. package/dist/schemas.d.cts +2 -3
  39. package/dist/schemas.d.ts +2 -3
  40. package/dist/schemas.js +6 -97
  41. package/dist/scoring.cjs +3 -3
  42. package/dist/scoring.d.cts +2 -2
  43. package/dist/scoring.d.ts +2 -2
  44. package/dist/scoring.js +2 -2
  45. package/dist/xapi.cjs +3 -3
  46. package/dist/xapi.d.cts +1 -1
  47. package/dist/xapi.d.ts +1 -1
  48. package/dist/xapi.js +2 -2
  49. package/package.json +4 -4
  50. package/vectors/README.md +32 -2
  51. package/vectors/scoring.json +1 -498
  52. package/vectors/validation.json +6742 -0
  53. package/vectors/validation.mjs +195 -0
  54. package/dist/chunk-2CV6NU32.cjs.map +0 -1
  55. package/dist/chunk-5UCR4UNR.js.map +0 -1
  56. package/dist/chunk-D3GP5MET.js.map +0 -1
  57. package/dist/chunk-D4TOPSHV.cjs.map +0 -1
  58. package/dist/chunk-OPMY2MNS.cjs.map +0 -1
  59. package/dist/chunk-Q7MV3IXJ.js.map +0 -1
  60. package/dist/chunk-WQVZPIN7.cjs.map +0 -1
  61. package/dist/chunk-Z7QQZ53L.js.map +0 -1
  62. package/dist/index-0Z3-nnAP.d.ts +0 -2303
  63. package/dist/index-CxxiNSSH.d.cts +0 -2303
  64. /package/dist/{chunk-X5DAXBJI.js.map → chunk-SJVRUPJT.js.map} +0 -0
package/CHANGELOG.md CHANGED
@@ -1,5 +1,20 @@
1
1
  # @intellectif/lk-core
2
2
 
3
+ ## 1.0.0
4
+
5
+ ### Major Changes
6
+
7
+ - [#82](https://github.com/intellectif/learning-kit/pull/82) [`bcae525`](https://github.com/intellectif/learning-kit/commit/bcae52599d7d0481ccd8ceecdfc59f2bd6d4d281) Thanks [@diego28e](https://github.com/diego28e)! - **1.0**: what every 1.x keeps stable, written down, and from now on a lk-core minor releases no lk-react. No grade changes.
8
+
9
+ **Action required:** only if you read `ScoringDetail.correct`, import a zod schema from lk-core, or register an activity type of your own. Install lk-core 1.0.0 and lk-react 23.0.0 together. Each change and its replacement is in the upgrading guide: https://github.com/intellectif/learning-kit/blob/main/docs/upgrading.md
10
+
11
+ - **Stability:** grades, the public API, content and runtimes — what a 1.x release may and may not change — are set out in https://github.com/intellectif/learning-kit/blob/main/docs/stability.md. lk-react 23 peers on `@intellectif/lk-core@^1.0.0`, and a lk-core minor or patch releases no lk-react.
12
+ - **`ScoringDetail.correct` is removed, and `outcome` is required.** Deprecated since 0.3; on a multiple-choice option it meant "the learner acted rightly on it". Read `outcome`. The grade-stability corpus changed only there: 142 vectors lose `correct`, and no score, pass or feedback moves. A detail stored before 0.3 still carries only `correct`; the SDK's components still read it.
13
+ - **Zod is private to lk-core.** No zod schema is exported and no published type names zod, so your app can use any zod, or none. `validateMedia` and `validateOptionMedia` replace `MediaSchema.safeParse` and `MultipleChoiceOptionMediaSchema.safeParse`; `validateActivity`, `validateDraft` and `validateItemGroup` replace the rest. The `*JsonSchema` constants are typed `Record<string, unknown>`, and the `Redacted*` types are written out, unchanged in shape.
14
+ - **A type you register takes Standard Schemas** (https://standardschema.dev): `schema` and `redactedSchema` are `StandardSchemaV1`. A zod 4 schema is one as written; valibot and ArkType work too. Validation must be synchronous. `registerActivityType` throws on a value that is not a Standard Schema, and `jsonSchemaFor` on your type needs the descriptor's new `jsonSchema` unless the schema produces JSON Schema itself, as zod 4.6 does.
15
+ - **Built on zod 4.6.5, pinned exactly**, instead of the zod 4 preview in zod 3.25. A new zod reaches you only in a lk-core release. If your app uses another version of zod, your bundle carries two copies. Every built-in validation accepts and refuses what it did, checked against 0.21.0 on 28,000 inputs; from 1.0, `vectors/validation.json` in the tarball freezes that for over three thousand inputs, and each release replays it. Two error lists are one error shorter: a speech assessment with a string where a list of phonemes or syllables belongs, and an xAPI statement whose actor's `mbox` is not a `mailto:` address.
16
+ - **Fixed (lk-react):** a host's grade whose details carry no `correct` — every detail lk-core 1.0 writes — had all its details dropped, a read-aloud's word marks among them. It is now read.
17
+
3
18
  ## 0.22.0
4
19
 
5
20
  ### Minor Changes
package/README.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # @intellectif/lk-core
2
2
 
3
- Framework-free TypeScript core of [learning-kit](https://github.com/intellectif/learning-kit): Zod-based **activity schemas**, a pure **scoring engine**, **rubric and deferred grading**, **weighted assessment composition**, reproducible **exam attempt plans**, fail-closed **redaction**, and an **xAPI 1.0.3 statement builder + validator**. Zero React, zero DOM — usable in Node, browsers, edge, workers, or as the data layer behind `@intellectif/lk-react`.
3
+ Framework-free TypeScript core of [learning-kit](https://github.com/intellectif/learning-kit): **activity schemas and validation**, a pure **scoring engine**, **rubric and deferred grading**, **weighted assessment composition**, reproducible **exam attempt plans**, fail-closed **redaction**, and an **xAPI 1.0.3 statement builder + validator**. Zero React, zero DOM — usable in Node, browsers, edge, workers, or as the data layer behind `@intellectif/lk-react`.
4
4
 
5
5
  It is built for **summative** assessment as much as practice: nothing here grades on the client, "not marked yet" is a first-class outcome that is never conflated with a zero, and every behavioural change that could move a historical grade is opt-in. A frozen corpus of grading vectors ships in the package, fails CI if any of them moves, and can be replayed against the build you install.
6
6
 
@@ -41,7 +41,7 @@ npm install @intellectif/lk-core
41
41
  - **xAPI builder** — `xAPIBuilder.buildAnsweredStatement(...)` / `buildSubmittedStatement(...)` / `buildCompletedStatement(...)` (plus `buildStatement(...)` for any verb) emit well-formed xAPI 1.0.3 statements with a v4 statement id and an ISO-8601 timestamp. Ids use `crypto.randomUUID()` where available and fall back to `crypto.getRandomValues()`, so statements stay well-formed on the non-secure origins `randomUUID` is gated behind.
42
42
  - **xAPI verbs for async grading** — `XAPIVerb.SUBMITTED` is emitted for work whose grade does not exist yet (`answered` would assert a score nobody computed), and `XAPIVerb.SCORED` is there for the grade that arrives later, often from a different actor. `XAPI_VERB_DISPLAY` supplies the `en-US` labels.
43
43
  - **`xapiDefinitionFor(data)`** — the xAPI interop descriptor (activity-type IRI, `cmi.interaction` type, `correctResponsesPattern`) for any registered type, so a consumer-registered activity gets correct interop with no component changes. Returns `{}` for an unregistered type, so it is always safe to spread.
44
- - **xAPI validator** — `validateXAPIStatement(statement)` (Zod-backed; throws on an invalid statement in development, warns in production).
44
+ - **xAPI validator** — `validateXAPIStatement(statement)` (throws on an invalid statement in development, warns in production).
45
45
  - **Errors** — `ActivitySchemaError`, `UnknownActivityTypeError`, `DeferredScoringError` and `RedactedScoringError`, all with structured payloads.
46
46
  - **Types** — `ActivityData`, `ActivityResult`, `ScoringResult`, `XAPIStatement`, `ThemeTokens`, … all exported with JSDoc.
47
47
 
@@ -115,7 +115,7 @@ result.passed; // boolean, or null while provisional. Never record a provision
115
115
  | Import | Contents |
116
116
  |---|---|
117
117
  | `@intellectif/lk-core` | Everything (barrel) |
118
- | `@intellectif/lk-core/schemas` | Zod schemas + `validateActivity` + JSON Schema export |
118
+ | `@intellectif/lk-core/schemas` | `validateActivity`, `validateItemGroup`, `validateMedia`, `validateOptionMedia`, `jsonSchemaFor` and the JSON Schemas, and the redacted types |
119
119
  | `@intellectif/lk-core/scoring` | `score`, `evaluate`, `composeAssessmentScore`, rounding, text matching |
120
120
  | `@intellectif/lk-core/xapi` | `xAPIBuilder`, `XAPIVerb`, `validateXAPIStatement` |
121
121
  | `@intellectif/lk-core/ai-check` | `runAiCheck`, `aiCheckCases`, `formatAiCheckReport` — test your AI prompts in CI |
@@ -124,8 +124,8 @@ The barrel re-exports everything, and it is the **only** entry point for attempt
124
124
  plans, attempt state, item groups, redaction, the type registry, authoring drafts
125
125
  and content hashing — those have no subpath of their own.
126
126
 
127
- All exports ship as ESM + CJS with `.d.ts` types. Tree-shakeable; `sideEffects: false`. Node >= 20. In browsers, the SDK's own code needs `Object.hasOwn` — Chrome and Edge 93, Firefox 92, Safari 15.4 — because output targets ES2022 and nothing is polyfilled.
128
- Zod is the single runtime dependency: the package depends on `zod@^3.25` and imports the **Zod 4 API** from its `zod/v4` subpath, so it coexists with an app still on Zod 3.
127
+ All exports ship as ESM + CJS with `.d.ts` types. Tree-shakeable; `sideEffects: false`. Node 22 or later. In browsers, the SDK's own code needs `Object.hasOwn` — Chrome and Edge 93, Firefox 92, Safari 15.4 — because output targets ES2022 and nothing is polyfilled.
128
+ Zod is the single runtime dependency, pinned to one exact version and private: no export is a zod schema and no published type names zod, so your app can use any version of zod, or none. The pin keeps validation to what the SDK tested — a new zod ships in a lk-core release, once the validation corpus replays unchanged — at the cost of a second copy of zod in a bundle whose own zod is another version. A type you register brings its own schema, from any library that implements [Standard Schema](https://standardschema.dev). What 1.x keeps stable is set out in [Stability](https://github.com/intellectif/learning-kit/blob/main/docs/stability.md).
129
129
 
130
130
  ## Releases & upgrading
131
131
 
@@ -1460,8 +1460,7 @@ interface ReadAloudLearnerResponse {
1460
1460
  takes?: number;
1461
1461
  }
1462
1462
  /**
1463
- * Fine-grained outcome of the learner's action on a single item, replacing the
1464
- * ambiguous {@link ScoringDetail.correct}:
1463
+ * Fine-grained outcome of the learner's action on a single item:
1465
1464
  * - `correct` — the learner selected/entered the right answer.
1466
1465
  * - `incorrect` — the learner selected/entered a wrong answer.
1467
1466
  * - `correct-omission` — the learner correctly left a non-answer unselected (multiple-choice only).
@@ -1474,20 +1473,17 @@ interface ScoringDetail {
1474
1473
  /** ID of the option, blank, gap or dictation word (`w1`…`wN`) this detail refers to. */
1475
1474
  itemId: string;
1476
1475
  /**
1477
- * @deprecated Ambiguous: for multiple-choice this means "the learner acted
1478
- * correctly on this option" (`wasSelected === option.isCorrect`), NOT "this
1479
- * option is the answer" — an unselected wrong option reads `correct: true`.
1480
- * Read {@link ScoringDetail.outcome} instead; `correct` remains written for
1481
- * backward compatibility and will be removed in v1.0.
1482
- */
1483
- correct: boolean;
1484
- /**
1485
- * Unambiguous outcome of the learner's action on this item. Optional in the
1486
- * type so 0.2-era consumer-constructed literals keep compiling, but ALWAYS
1487
- * written by every built-in scorer (by the first two since 0.3.0); becomes
1488
- * required in v1.0 when the deprecated `correct` is removed.
1476
+ * The outcome of the learner's action on this item. On a multiple-choice
1477
+ * option it says both whether the option was chosen and whether it is part
1478
+ * of the answer.
1479
+ *
1480
+ * Until 1.0 a detail also carried `correct`, which on a multiple-choice
1481
+ * option meant "the learner acted correctly on it" — an unselected wrong
1482
+ * option read `correct: true` — and a detail stored before 0.3 carries only
1483
+ * that. The SDK's components still read such a stored detail; a type written
1484
+ * against 1.0 does not describe it.
1489
1485
  */
1490
- outcome?: ScoringOutcome;
1486
+ outcome: ScoringOutcome;
1491
1487
  /** The learner's actual response for this item. */
1492
1488
  learnerResponse: string | string[];
1493
1489
  /** The expected correct response(s) for this item. */
@@ -1460,8 +1460,7 @@ interface ReadAloudLearnerResponse {
1460
1460
  takes?: number;
1461
1461
  }
1462
1462
  /**
1463
- * Fine-grained outcome of the learner's action on a single item, replacing the
1464
- * ambiguous {@link ScoringDetail.correct}:
1463
+ * Fine-grained outcome of the learner's action on a single item:
1465
1464
  * - `correct` — the learner selected/entered the right answer.
1466
1465
  * - `incorrect` — the learner selected/entered a wrong answer.
1467
1466
  * - `correct-omission` — the learner correctly left a non-answer unselected (multiple-choice only).
@@ -1474,20 +1473,17 @@ interface ScoringDetail {
1474
1473
  /** ID of the option, blank, gap or dictation word (`w1`…`wN`) this detail refers to. */
1475
1474
  itemId: string;
1476
1475
  /**
1477
- * @deprecated Ambiguous: for multiple-choice this means "the learner acted
1478
- * correctly on this option" (`wasSelected === option.isCorrect`), NOT "this
1479
- * option is the answer" — an unselected wrong option reads `correct: true`.
1480
- * Read {@link ScoringDetail.outcome} instead; `correct` remains written for
1481
- * backward compatibility and will be removed in v1.0.
1482
- */
1483
- correct: boolean;
1484
- /**
1485
- * Unambiguous outcome of the learner's action on this item. Optional in the
1486
- * type so 0.2-era consumer-constructed literals keep compiling, but ALWAYS
1487
- * written by every built-in scorer (by the first two since 0.3.0); becomes
1488
- * required in v1.0 when the deprecated `correct` is removed.
1476
+ * The outcome of the learner's action on this item. On a multiple-choice
1477
+ * option it says both whether the option was chosen and whether it is part
1478
+ * of the answer.
1479
+ *
1480
+ * Until 1.0 a detail also carried `correct`, which on a multiple-choice
1481
+ * option meant "the learner acted correctly on it" — an unselected wrong
1482
+ * option read `correct: true` — and a detail stored before 0.3 carries only
1483
+ * that. The SDK's components still read such a stored detail; a type written
1484
+ * against 1.0 does not describe it.
1489
1485
  */
1490
- outcome?: ScoringOutcome;
1486
+ outcome: ScoringOutcome;
1491
1487
  /** The learner's actual response for this item. */
1492
1488
  learnerResponse: string | string[];
1493
1489
  /** The expected correct response(s) for this item. */
package/dist/ai-check.cjs CHANGED
@@ -5,9 +5,9 @@
5
5
 
6
6
 
7
7
 
8
- var _chunkOPMY2MNScjs = require('./chunk-OPMY2MNS.cjs');
9
- require('./chunk-WQVZPIN7.cjs');
10
- require('./chunk-D4TOPSHV.cjs');
8
+ var _chunkW5KB3DNTcjs = require('./chunk-W5KB3DNT.cjs');
9
+ require('./chunk-VSH7ECQL.cjs');
10
+ require('./chunk-DSDXL3JO.cjs');
11
11
 
12
12
  // src/ai-check/cases.ts
13
13
  var capital = {
@@ -106,21 +106,21 @@ var drafted = (text) => ({
106
106
  wordCount: 0
107
107
  });
108
108
  function explanationCase(id, about, data, response) {
109
- const request = _chunkOPMY2MNScjs.aiExplanationRequest.call(void 0, { data, response });
109
+ const request = _chunkW5KB3DNTcjs.aiExplanationRequest.call(void 0, { data, response });
110
110
  if (request === null) {
111
111
  throw new Error(`ai-check: no explanation request for "${id}"`);
112
112
  }
113
113
  return { id, feature: "explanation", about, request };
114
114
  }
115
115
  function hintCase(id, about, data, response, previousHints = []) {
116
- const request = _chunkOPMY2MNScjs.aiHintRequest.call(void 0, { data, response, previousHints });
116
+ const request = _chunkW5KB3DNTcjs.aiHintRequest.call(void 0, { data, response, previousHints });
117
117
  if (request === null) {
118
118
  throw new Error(`ai-check: no hint request for "${id}"`);
119
119
  }
120
120
  return { id, feature: "hint", about, request };
121
121
  }
122
122
  function writingCase(id, about, text, previousFeedback = [], learnerLocale) {
123
- const request = _chunkOPMY2MNScjs.aiWritingFeedbackRequest.call(void 0, {
123
+ const request = _chunkW5KB3DNTcjs.aiWritingFeedbackRequest.call(void 0, {
124
124
  data: weekend,
125
125
  response: drafted(text),
126
126
  previousFeedback,
@@ -263,7 +263,7 @@ async function runCase(ports, one) {
263
263
  }
264
264
  const ms = now() - started;
265
265
  if (one.request.feature === "writing-feedback") {
266
- const checked2 = _chunkOPMY2MNScjs.checkAiWritingFeedback.call(void 0, raw, one.request);
266
+ const checked2 = _chunkW5KB3DNTcjs.checkAiWritingFeedback.call(void 0, raw, one.request);
267
267
  if (checked2.ok) {
268
268
  const { text, provenance, usage } = checked2.feedback;
269
269
  return {
@@ -280,7 +280,7 @@ async function runCase(ports, one) {
280
280
  }
281
281
  return refused(one, raw, checked2.refusal, ms);
282
282
  }
283
- const checked = one.request.feature === "explanation" ? _chunkOPMY2MNScjs.checkAiExplanation.call(void 0, raw, one.request) : _chunkOPMY2MNScjs.checkAiHint.call(void 0, raw, one.request);
283
+ const checked = one.request.feature === "explanation" ? _chunkW5KB3DNTcjs.checkAiExplanation.call(void 0, raw, one.request) : _chunkW5KB3DNTcjs.checkAiHint.call(void 0, raw, one.request);
284
284
  if (checked.ok) {
285
285
  return { case: one, ok: true, result: checked.result, ms };
286
286
  }
@@ -1,4 +1,4 @@
1
- import { k as AiExplanationRequest, q as AiHintRequest, F as AiWritingFeedbackRequest, v as AiRefusal, y as AiTextResult, E as AiWritingFeedback } from './activity-CYc7SD3d.cjs';
1
+ import { k as AiExplanationRequest, q as AiHintRequest, F as AiWritingFeedbackRequest, v as AiRefusal, y as AiTextResult, E as AiWritingFeedback } from './activity-DgpBJeBc.cjs';
2
2
 
3
3
  /**
4
4
  * One call to make against a host's port, and what a learner was looking at
@@ -1,4 +1,4 @@
1
- import { k as AiExplanationRequest, q as AiHintRequest, F as AiWritingFeedbackRequest, v as AiRefusal, y as AiTextResult, E as AiWritingFeedback } from './activity-CYc7SD3d.js';
1
+ import { k as AiExplanationRequest, q as AiHintRequest, F as AiWritingFeedbackRequest, v as AiRefusal, y as AiTextResult, E as AiWritingFeedback } from './activity-DgpBJeBc.js';
2
2
 
3
3
  /**
4
4
  * One call to make against a host's port, and what a learner was looking at
package/dist/ai-check.js CHANGED
@@ -5,9 +5,9 @@ import {
5
5
  checkAiExplanation,
6
6
  checkAiHint,
7
7
  checkAiWritingFeedback
8
- } from "./chunk-5UCR4UNR.js";
9
- import "./chunk-Q7MV3IXJ.js";
10
- import "./chunk-D3GP5MET.js";
8
+ } from "./chunk-RCZCP5OE.js";
9
+ import "./chunk-IARLJ5MW.js";
10
+ import "./chunk-FBKTION6.js";
11
11
 
12
12
  // src/ai-check/cases.ts
13
13
  var capital = {
@@ -11,7 +11,12 @@
11
11
 
12
12
 
13
13
 
14
- var _chunkD4TOPSHVcjs = require('./chunk-D4TOPSHV.cjs');
14
+
15
+
16
+
17
+
18
+
19
+ var _chunkDSDXL3JOcjs = require('./chunk-DSDXL3JO.cjs');
15
20
 
16
21
  // src/schemas/item-group.ts
17
22
  var _v4 = require('zod/v4');
@@ -57,7 +62,7 @@ var StimulusSchema = _v4.z.looseObject({
57
62
  title: _v4.z.string().optional(),
58
63
  body: _v4.z.string().optional(),
59
64
  bodyHtml: _v4.z.string().optional(),
60
- media: _chunkD4TOPSHVcjs.MediaSchema.optional(),
65
+ media: _chunkDSDXL3JOcjs.MediaSchema.optional(),
61
66
  transcript: _v4.z.string().optional(),
62
67
  locale: _v4.z.string().optional(),
63
68
  attribution: _v4.z.string().optional()
@@ -80,10 +85,13 @@ var StimulusSchema = _v4.z.looseObject({
80
85
  path: ["media", "type"]
81
86
  }
82
87
  );
83
- var TimelineTitleSchema = _v4.z.string().max(TIMELINE_MAX_TITLE_LENGTH).refine((title) => title.trim().length > 0, { error: "A title must not be empty." });
88
+ var TimelineTitleSchema = _chunkDSDXL3JOcjs.maxUnits.call(void 0, _v4.z.string(), TIMELINE_MAX_TITLE_LENGTH).refine(
89
+ (title) => title.trim().length > 0,
90
+ { error: "A title must not be empty." }
91
+ );
84
92
  var TimelineTimeSchema = _v4.z.number().min(0, { error: "A time is 0 seconds or more." });
85
93
  var TimelineCueSchema = _v4.z.strictObject({
86
- id: _v4.z.string().min(1).max(64),
94
+ id: _chunkDSDXL3JOcjs.maxUnits.call(void 0, _v4.z.string().min(1), 64),
87
95
  at: TimelineTimeSchema,
88
96
  itemIds: _v4.z.array(_v4.z.string().min(1)).min(1).max(TIMELINE_MAX_ITEMS),
89
97
  title: TimelineTitleSchema.optional(),
@@ -267,7 +275,7 @@ var RedactedStimulusSchema = _v4.z.strictObject({
267
275
  title: _v4.z.string().optional(),
268
276
  body: _v4.z.string().optional(),
269
277
  bodyHtml: _v4.z.string().optional(),
270
- media: _chunkD4TOPSHVcjs.RedactedMediaSchema.optional(),
278
+ media: _chunkDSDXL3JOcjs.RedactedMediaSchema.optional(),
271
279
  locale: _v4.z.string().optional(),
272
280
  attribution: _v4.z.string().optional()
273
281
  });
@@ -286,12 +294,12 @@ var RedactedItemGroupSchema = _v4.z.strictObject({
286
294
  for (const issue of timelineIssues(ctx.value, "redacted")) {
287
295
  ctx.issues.push({ code: "custom", ...issue });
288
296
  }
289
- const captions = _chunkD4TOPSHVcjs.groupCaptionsField.call(void 0, ctx.value);
297
+ const captions = _chunkDSDXL3JOcjs.groupCaptionsField.call(void 0, ctx.value);
290
298
  if (captions !== void 0) {
291
299
  ctx.issues.push({
292
300
  code: "custom",
293
301
  input: _optionalChain([ctx, 'access', _ => _.value, 'access', _2 => _2.stimulus, 'access', _3 => _3.media, 'optionalAccess', _4 => _4[captions]]),
294
- message: _chunkD4TOPSHVcjs.GROUP_CAPTIONS_REVEAL_DICTATION,
302
+ message: _chunkDSDXL3JOcjs.GROUP_CAPTIONS_REVEAL_DICTATION,
295
303
  path: ["stimulus", "media", captions]
296
304
  });
297
305
  }
@@ -311,7 +319,7 @@ function validateItemGroup(data) {
311
319
  const errors = [];
312
320
  const items = [];
313
321
  container.data.items.forEach((item, index) => {
314
- const descriptor = _chunkD4TOPSHVcjs.getActivityTypeDescriptor.call(void 0, item.type);
322
+ const descriptor = _chunkDSDXL3JOcjs.getActivityTypeDescriptor.call(void 0, item.type);
315
323
  if (descriptor === void 0) {
316
324
  errors.push({
317
325
  path: ["items", String(index), "type"],
@@ -320,18 +328,18 @@ function validateItemGroup(data) {
320
328
  });
321
329
  return;
322
330
  }
323
- const parsed = descriptor.schema.safeParse(item);
331
+ const parsed = _chunkDSDXL3JOcjs.readSchema.call(void 0, descriptor.schema, item, `Activity type "${descriptor.type}"`);
324
332
  if (!parsed.success) {
325
- errors.push(...toValidationErrors(parsed.error.issues, ["items", String(index)]));
333
+ errors.push(...toValidationErrors(parsed.issues, ["items", String(index)]));
326
334
  return;
327
335
  }
328
336
  items.push(parsed.data);
329
337
  });
330
- const captions = _chunkD4TOPSHVcjs.groupCaptionsField.call(void 0, container.data);
338
+ const captions = _chunkDSDXL3JOcjs.groupCaptionsField.call(void 0, container.data);
331
339
  if (captions !== void 0) {
332
340
  errors.push({
333
341
  path: ["stimulus", "media", captions],
334
- message: _chunkD4TOPSHVcjs.GROUP_CAPTIONS_REVEAL_DICTATION,
342
+ message: _chunkDSDXL3JOcjs.GROUP_CAPTIONS_REVEAL_DICTATION,
335
343
  code: "custom"
336
344
  });
337
345
  }
@@ -343,53 +351,86 @@ function validateItemGroup(data) {
343
351
 
344
352
  // src/schemas/json-schema.ts
345
353
 
346
- var stimulusJsonSchema = _v4.z.toJSONSchema(StimulusSchema, { target: "draft-7" });
347
- var itemGroupJsonSchema = _v4.z.toJSONSchema(ItemGroupSchema, { target: "draft-7" });
348
- var gapSelectJsonSchema = _v4.z.toJSONSchema(_chunkD4TOPSHVcjs.GapSelectDataSchema, {
349
- target: "draft-7"
350
- });
351
- var dictationJsonSchema = _v4.z.toJSONSchema(_chunkD4TOPSHVcjs.DictationDataSchema, {
354
+ var stimulusJsonSchema = _v4.z.toJSONSchema(StimulusSchema, {
352
355
  target: "draft-7"
353
356
  });
354
- var readAloudJsonSchema = _v4.z.toJSONSchema(_chunkD4TOPSHVcjs.ReadAloudDataSchema, {
357
+ var itemGroupJsonSchema = _v4.z.toJSONSchema(ItemGroupSchema, {
355
358
  target: "draft-7"
356
359
  });
357
- var multipleChoiceJsonSchema = _v4.z.toJSONSchema(_chunkD4TOPSHVcjs.MultipleChoiceDataSchema, {
360
+ var gapSelectJsonSchema = _v4.z.toJSONSchema(_chunkDSDXL3JOcjs.GapSelectDataSchema, {
358
361
  target: "draft-7"
359
362
  });
360
- var fillInTheBlanksJsonSchema = _v4.z.toJSONSchema(_chunkD4TOPSHVcjs.FillInTheBlanksDataSchema, {
363
+ var dictationJsonSchema = _v4.z.toJSONSchema(_chunkDSDXL3JOcjs.DictationDataSchema, {
361
364
  target: "draft-7"
362
365
  });
363
- var writtenResponseJsonSchema = _v4.z.toJSONSchema(_chunkD4TOPSHVcjs.WrittenResponseDataSchema, {
366
+ var readAloudJsonSchema = _v4.z.toJSONSchema(_chunkDSDXL3JOcjs.ReadAloudDataSchema, {
364
367
  target: "draft-7"
365
368
  });
369
+ var multipleChoiceJsonSchema = _v4.z.toJSONSchema(
370
+ _chunkDSDXL3JOcjs.MultipleChoiceDataSchema,
371
+ {
372
+ target: "draft-7"
373
+ }
374
+ );
375
+ var fillInTheBlanksJsonSchema = _v4.z.toJSONSchema(
376
+ _chunkDSDXL3JOcjs.FillInTheBlanksDataSchema,
377
+ {
378
+ target: "draft-7"
379
+ }
380
+ );
381
+ var writtenResponseJsonSchema = _v4.z.toJSONSchema(
382
+ _chunkDSDXL3JOcjs.WrittenResponseDataSchema,
383
+ {
384
+ target: "draft-7"
385
+ }
386
+ );
366
387
  function jsonSchemaFor(type) {
367
- const descriptor = _chunkD4TOPSHVcjs.getActivityTypeDescriptor.call(void 0, type);
388
+ const descriptor = _chunkDSDXL3JOcjs.getActivityTypeDescriptor.call(void 0, type);
368
389
  if (descriptor === void 0) {
369
- throw new (0, _chunkD4TOPSHVcjs.UnknownActivityTypeError)(type);
390
+ throw new (0, _chunkDSDXL3JOcjs.UnknownActivityTypeError)(type);
391
+ }
392
+ if (_chunkDSDXL3JOcjs.isOwnSchema.call(void 0, descriptor.schema)) {
393
+ return _v4.z.toJSONSchema(descriptor.schema, { target: "draft-7" });
394
+ }
395
+ if (descriptor.jsonSchema !== void 0) {
396
+ return structuredClone(descriptor.jsonSchema);
397
+ }
398
+ const generated = _chunkDSDXL3JOcjs.standardJsonSchemaOf.call(void 0, descriptor.schema);
399
+ if (generated === void 0) {
400
+ throw new Error(
401
+ `Activity type "${descriptor.type}" has no JSON Schema: its schema implements no Standard JSON Schema converter ('~standard'.jsonSchema). Give its descriptor a \`jsonSchema\`.`
402
+ );
370
403
  }
371
- return _v4.z.toJSONSchema(descriptor.schema, { target: "draft-7" });
404
+ return generated;
372
405
  }
373
406
 
374
407
  // src/schemas/index.ts
375
- function validateActivity(type, data) {
376
- const descriptor = _chunkD4TOPSHVcjs.getActivityTypeDescriptor.call(void 0, type);
377
- if (descriptor === void 0) {
378
- throw new (0, _chunkD4TOPSHVcjs.UnknownActivityTypeError)(String(type));
379
- }
380
- const result = descriptor.schema.safeParse(data);
381
- if (result.success) {
382
- return { success: true, data: result.data };
408
+ function validateMedia(value) {
409
+ return asValidation(_chunkDSDXL3JOcjs.readSchema.call(void 0, _chunkDSDXL3JOcjs.MediaSchema, value, "Media"));
410
+ }
411
+ function validateOptionMedia(value) {
412
+ return asValidation(_chunkDSDXL3JOcjs.readSchema.call(void 0, _chunkDSDXL3JOcjs.MultipleChoiceOptionMediaSchema, value, "Option media"));
413
+ }
414
+ function asValidation(reading) {
415
+ if (reading.success) {
416
+ return { success: true, data: reading.data };
383
417
  }
384
418
  return {
385
419
  success: false,
386
- errors: result.error.issues.map((issue) => ({
420
+ errors: reading.issues.map((issue) => ({
387
421
  path: issue.path.map(String),
388
422
  message: issue.message,
389
423
  code: issue.code
390
424
  }))
391
425
  };
392
426
  }
427
+ function validateActivity(type, data) {
428
+ const descriptor = _chunkDSDXL3JOcjs.getActivityTypeDescriptor.call(void 0, type);
429
+ if (descriptor === void 0) {
430
+ throw new (0, _chunkDSDXL3JOcjs.UnknownActivityTypeError)(String(type));
431
+ }
432
+ return asValidation(_chunkDSDXL3JOcjs.readSchema.call(void 0, descriptor.schema, data, `Activity type "${descriptor.type}"`));
433
+ }
393
434
 
394
435
 
395
436
 
@@ -413,8 +454,5 @@ function validateActivity(type, data) {
413
454
 
414
455
 
415
456
 
416
-
417
-
418
-
419
- exports.INTERACTIVE_VIDEO_ITEM_TYPES = INTERACTIVE_VIDEO_ITEM_TYPES; exports.isInteractiveVideoItemType = isInteractiveVideoItemType; exports.TIMELINE_MAX_QUIZZES = TIMELINE_MAX_QUIZZES; exports.TIMELINE_MAX_ITEMS = TIMELINE_MAX_ITEMS; exports.TIMELINE_MAX_CHAPTERS = TIMELINE_MAX_CHAPTERS; exports.TIMELINE_MAX_TITLE_LENGTH = TIMELINE_MAX_TITLE_LENGTH; exports.StimulusSchema = StimulusSchema; exports.TimelineCueSchema = TimelineCueSchema; exports.TimelineChapterSchema = TimelineChapterSchema; exports.MediaTimelineSchema = MediaTimelineSchema; 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.readAloudJsonSchema = readAloudJsonSchema; exports.multipleChoiceJsonSchema = multipleChoiceJsonSchema; exports.fillInTheBlanksJsonSchema = fillInTheBlanksJsonSchema; exports.writtenResponseJsonSchema = writtenResponseJsonSchema; exports.jsonSchemaFor = jsonSchemaFor; exports.validateActivity = validateActivity;
420
- //# sourceMappingURL=chunk-2CV6NU32.cjs.map
457
+ exports.INTERACTIVE_VIDEO_ITEM_TYPES = INTERACTIVE_VIDEO_ITEM_TYPES; exports.isInteractiveVideoItemType = isInteractiveVideoItemType; exports.TIMELINE_MAX_QUIZZES = TIMELINE_MAX_QUIZZES; exports.TIMELINE_MAX_ITEMS = TIMELINE_MAX_ITEMS; exports.TIMELINE_MAX_CHAPTERS = TIMELINE_MAX_CHAPTERS; exports.TIMELINE_MAX_TITLE_LENGTH = TIMELINE_MAX_TITLE_LENGTH; exports.ItemGroupSchema = ItemGroupSchema; exports.RedactedItemGroupSchema = RedactedItemGroupSchema; exports.validateItemGroup = validateItemGroup; exports.stimulusJsonSchema = stimulusJsonSchema; exports.itemGroupJsonSchema = itemGroupJsonSchema; exports.gapSelectJsonSchema = gapSelectJsonSchema; exports.dictationJsonSchema = dictationJsonSchema; exports.readAloudJsonSchema = readAloudJsonSchema; exports.multipleChoiceJsonSchema = multipleChoiceJsonSchema; exports.fillInTheBlanksJsonSchema = fillInTheBlanksJsonSchema; exports.writtenResponseJsonSchema = writtenResponseJsonSchema; exports.jsonSchemaFor = jsonSchemaFor; exports.validateMedia = validateMedia; exports.validateOptionMedia = validateOptionMedia; exports.validateActivity = validateActivity;
458
+ //# sourceMappingURL=chunk-2JT2WUQ2.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["/home/runner/work/learning-kit/learning-kit/packages/lk-core/dist/chunk-2JT2WUQ2.cjs","../src/schemas/item-group.ts","../src/timeline-limits.ts","../src/schemas/json-schema.ts","../src/schemas/index.ts"],"names":["z"],"mappings":"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","file":"/home/runner/work/learning-kit/learning-kit/packages/lk-core/dist/chunk-2JT2WUQ2.cjs","sourcesContent":[null,"import { z } from 'zod/v4';\nimport { getActivityTypeDescriptor } from '../registry/index.js';\nimport {\n INTERACTIVE_VIDEO_ITEM_TYPES,\n isInteractiveVideoItemType,\n TIMELINE_MAX_CHAPTERS,\n TIMELINE_MAX_ITEMS,\n TIMELINE_MAX_QUIZZES,\n TIMELINE_MAX_TITLE_LENGTH,\n} from '../timeline-limits.js';\nimport type { ActivityData, ValidationError, ValidationResult } from '../types/activity.js';\nimport type { ItemGroup, StimulusKind } from '../types/item-group.js';\nimport { GROUP_CAPTIONS_REVEAL_DICTATION, groupCaptionsField } from './dictation.js';\nimport { MediaSchema, RedactedMediaSchema } from './media.js';\nimport { readSchema } from './read-schema.js';\nimport { maxUnits } from './text-length.js';\n\n/**\n * An authored slot key.\n *\n * A `.` is rejected here, not at render time: `flattenSequence` uses the first\n * `.` to separate a group from its item, so a key containing one would produce\n * an ambiguous slot id. `keyOf` already threw on it — this moves the rejection\n * to `validateItemGroup`, where an author finds it, instead of leaving it to\n * surface when a learner opens the paper. Content that would newly fail\n * validation already threw at flatten time, so it can never have been sat.\n */\nconst SlotKeySchema = z\n .string()\n .min(1)\n .refine((key) => !key.includes('.'), {\n error:\n 'slotKey must not contain \".\" — that character separates a group from its item in a slot id, so a key containing one would make the slot ambiguous.',\n });\n\nfunction hasBody(stimulus: { body?: string | undefined }): boolean {\n return typeof stimulus.body === 'string' && stimulus.body.trim().length > 0;\n}\n\n/** Which media types can carry a stimulus of each kind. `text`/`mixed` accept any. */\nfunction mediaFits(kind: StimulusKind, mediaType: string | undefined): boolean {\n switch (kind) {\n case 'audio':\n return mediaType === 'audio';\n case 'video':\n return mediaType === 'video' || mediaType === 'embed';\n case 'image':\n return mediaType === 'image';\n default:\n return true;\n }\n}\n\n/**\n * Zod schema for a {@link Stimulus}. Loose: unknown keys preserved.\n *\n * The semantic guards exist because a stimulus that does not carry what its\n * `kind` promises is an authoring error that must not reach an exam: an\n * \"audio\" stimulus with no recording renders as a blank panel above six\n * listening questions. Unrepresentable in JSON Schema; dropped from\n * `stimulusJsonSchema` by design.\n */\nexport const StimulusSchema = z\n .looseObject({\n id: z.string().min(1),\n kind: z.enum(['text', 'audio', 'video', 'image', 'mixed']),\n title: z.string().optional(),\n body: z.string().optional(),\n bodyHtml: z.string().optional(),\n media: MediaSchema.optional(),\n transcript: z.string().optional(),\n locale: z.string().optional(),\n attribution: z.string().optional(),\n })\n .refine((stimulus) => stimulus.bodyHtml === undefined || hasBody(stimulus), {\n error:\n 'bodyHtml requires a plain-text body: it is the accessible fallback rendered when no sanitiser is supplied.',\n path: ['body'],\n })\n .refine(\n (stimulus) => (stimulus.kind !== 'text' && stimulus.kind !== 'mixed') || hasBody(stimulus),\n {\n error: 'A text or mixed stimulus needs a non-empty body.',\n path: ['body'],\n },\n )\n .refine((stimulus) => stimulus.kind === 'text' || stimulus.media !== undefined, {\n error: 'An audio, video, image or mixed stimulus needs media.',\n path: ['media'],\n })\n .refine(\n (stimulus) => stimulus.media === undefined || mediaFits(stimulus.kind, stimulus.media.type),\n {\n error:\n 'media.type does not fit the stimulus kind: audio needs audio; video needs video or embed; image needs image.',\n path: ['media', 'type'],\n },\n );\n\nconst TimelineTitleSchema = maxUnits(z.string(), TIMELINE_MAX_TITLE_LENGTH).refine(\n (title) => title.trim().length > 0,\n { error: 'A title must not be empty.' },\n);\n\n/** Seconds from the start of the video. zod rejects NaN and ±Infinity itself. */\nconst TimelineTimeSchema = z.number().min(0, { error: 'A time is 0 seconds or more.' });\n\n/**\n * A quiz. STRICT, like every part of a timeline: a misspelt `requried` would\n * otherwise be kept and the quiz silently optional on a paper that believed it\n * was required.\n */\nexport const TimelineCueSchema = z.strictObject({\n id: maxUnits(z.string().min(1), 64),\n at: TimelineTimeSchema,\n itemIds: z.array(z.string().min(1)).min(1).max(TIMELINE_MAX_ITEMS),\n title: TimelineTitleSchema.optional(),\n required: z.boolean().optional(),\n});\n\nexport const TimelineChapterSchema = z.strictObject({\n at: TimelineTimeSchema,\n title: TimelineTitleSchema,\n});\n\n/**\n * A timeline on its own: its quizzes, chapters and navigation. The rules that\n * need the group — every item in exactly one quiz, a video stimulus, the five\n * item types — are {@link timelineIssues}, which both group schemas run.\n */\nexport const MediaTimelineSchema = z\n .strictObject({\n cues: z.array(TimelineCueSchema).max(TIMELINE_MAX_QUIZZES),\n chapters: z.array(TimelineChapterSchema).max(TIMELINE_MAX_CHAPTERS).optional(),\n navigation: z.enum(['free', 'no-skip-ahead']).optional(),\n })\n .check((ctx) => {\n const seen = new Set<string>();\n ctx.value.cues.forEach((cue, index) => {\n if (seen.has(cue.id)) {\n ctx.issues.push({\n code: 'custom',\n input: cue.id,\n message: `Quiz id \"${cue.id}\" is used twice: events, drafts and the contents panel name a quiz by its id.`,\n path: ['cues', index, 'id'],\n });\n }\n seen.add(cue.id);\n });\n // Strictly increasing, not merely sorted: two chapters starting at one\n // moment leave the first with no length, and the scrubber no room to draw it.\n const chapters = ctx.value.chapters ?? [];\n chapters.forEach((chapter, index) => {\n const previous = chapters[index - 1];\n if (previous !== undefined && chapter.at <= previous.at) {\n ctx.issues.push({\n code: 'custom',\n input: chapter.at,\n message: 'Chapter times must be strictly increasing.',\n path: ['chapters', index, 'at'],\n });\n }\n });\n });\n\n/** A URL only this document can resolve, or one that inlines the bytes. */\nfunction isLocalOnlyUrl(url: unknown): boolean {\n return typeof url === 'string' && /^(data|blob):/i.test(url);\n}\n\n/**\n * The rules of an interactive video that span the timeline, the stimulus and\n * the items. Run by the content schema and, for everything but the two\n * authoring-only rules, by the strict redacted schema — a projection built by\n * hand never passed through the content schema.\n *\n * Items are read defensively: the redacted schema leaves them opaque, and each\n * is proven against its own type's schema elsewhere.\n */\nfunction timelineIssues(\n group: {\n stimulus: {\n kind: string;\n media?:\n | {\n type: string;\n url: string;\n poster?: string | undefined;\n tracks?: readonly { src: string }[] | undefined;\n }\n | undefined;\n };\n items: readonly unknown[];\n shuffle?: string | undefined;\n timeline?: { cues: readonly { itemIds: readonly string[] }[] } | undefined;\n },\n scope: 'content' | 'redacted',\n): { path: (string | number)[]; message: string; input: unknown }[] {\n const timeline = group.timeline;\n if (timeline === undefined) {\n return [];\n }\n const issues: { path: (string | number)[]; message: string; input: unknown }[] = [];\n const media = group.stimulus.media;\n\n // Reported at the field that is wrong, so an editor's own check at that path\n // can stand in for it without hiding anything else about the stimulus.\n if (group.stimulus.kind !== 'video') {\n issues.push({\n path: ['stimulus', 'kind'],\n input: group.stimulus.kind,\n message:\n 'An interactive video needs a video stimulus: quizzes open at moments of a video, and nothing else has them.',\n });\n } else if (media !== undefined && media.type !== 'video') {\n issues.push({\n path: ['stimulus', 'media', 'type'],\n input: media.type,\n message:\n 'An interactive video needs a video file. An embedded provider player cannot be paused at the moment a quiz opens.',\n });\n }\n if (group.shuffle === 'within-group') {\n issues.push({\n path: ['shuffle'],\n input: group.shuffle,\n message:\n 'An interactive video presents its questions in the order its quizzes open; shuffle: \"within-group\" cannot apply to it.',\n });\n }\n if (group.items.length > TIMELINE_MAX_ITEMS) {\n issues.push({\n path: ['items'],\n input: group.items.length,\n message: `An interactive video holds at most ${TIMELINE_MAX_ITEMS} questions.`,\n });\n }\n\n const itemIds = new Map<string, number>();\n group.items.forEach((item, index) => {\n const {\n id,\n type,\n media: itemMedia,\n } = (item ?? {}) as { id?: unknown; type?: unknown; media?: unknown };\n if (typeof id === 'string') {\n itemIds.set(id, index);\n }\n if (!isInteractiveVideoItemType(type)) {\n issues.push({\n path: ['items', index, 'type'],\n input: type,\n message: `An interactive video may hold only ${INTERACTIVE_VIDEO_ITEM_TYPES.join(', ')} questions.`,\n });\n }\n // The \"play the stimulus\" fallback a dictation has in a listening group\n // means nothing halfway through a video.\n if (scope === 'content' && type === 'dictation' && itemMedia === undefined) {\n issues.push({\n path: ['items', index, 'media'],\n input: itemMedia,\n message: 'A dictation inside an interactive video needs its own recording.',\n });\n }\n });\n\n const placed = new Set<string>();\n timeline.cues.forEach((cue, cueIndex) => {\n cue.itemIds.forEach((itemId, position) => {\n const path = ['timeline', 'cues', cueIndex, 'itemIds', position];\n if (!itemIds.has(itemId)) {\n issues.push({\n path,\n input: itemId,\n message: `No item in this group has the id \"${itemId}\".`,\n });\n } else if (placed.has(itemId)) {\n issues.push({\n path,\n input: itemId,\n message: `Item \"${itemId}\" is placed twice: every question belongs to exactly one quiz.`,\n });\n }\n placed.add(itemId);\n });\n });\n for (const [itemId, index] of itemIds) {\n if (!placed.has(itemId)) {\n issues.push({\n path: ['items', index],\n input: itemId,\n message: `Item \"${itemId}\" is in no quiz, so the video would never show it.`,\n });\n }\n }\n\n // A `data:` video swells the payload and every fingerprint over it; a stored\n // `blob:` URL means nothing in another document.\n if (scope === 'content' && media !== undefined) {\n const urls: [unknown, (string | number)[]][] = [\n [media.url, ['stimulus', 'media', 'url']],\n [media.poster, ['stimulus', 'media', 'poster']],\n ...(media.tracks ?? []).map((track, index): [unknown, (string | number)[]] => [\n track.src,\n ['stimulus', 'media', 'tracks', index, 'src'],\n ]),\n ];\n for (const [url, path] of urls) {\n if (isLocalOnlyUrl(url)) {\n issues.push({\n path,\n input: url,\n message:\n 'An interactive video is stored and served: its URLs cannot be data: or blob: URLs.',\n });\n }\n }\n }\n return issues;\n}\n\n/**\n * The structural minimum of an item as seen by the CONTAINER schema. Each\n * item's own contract is checked against its registered schema by\n * {@link validateItemGroup} — a zod schema cannot dispatch on a registry\n * that consumers extend at runtime.\n */\nconst ItemShapeSchema = z.looseObject({\n type: z.string().min(1),\n id: z.string().min(1),\n slotKey: SlotKeySchema.optional(),\n});\n\n/**\n * Zod schema for an {@link ItemGroup} CONTAINER. Loose: unknown keys\n * preserved. Validates the group's own fields and the stimulus in full, and\n * each item only structurally (`type` and `id`); use {@link validateItemGroup}\n * to validate the items against their registered schemas as well.\n */\nexport const ItemGroupSchema = z\n .looseObject({\n schemaVersion: z.literal('1.0'),\n type: z.literal('item-group'),\n id: z.string().min(1),\n title: z.string().optional(),\n slotKey: SlotKeySchema.optional(),\n stimulus: StimulusSchema,\n items: z.array(ItemShapeSchema).min(1),\n shuffle: z.enum(['none', 'within-group']).optional(),\n timeline: MediaTimelineSchema.optional(),\n })\n .refine((group) => group.items.every((item) => item.type !== 'item-group'), {\n error: 'Item groups do not nest: every item must be an activity.',\n path: ['items'],\n })\n .refine((group) => new Set(group.items.map((item) => item.id)).size === group.items.length, {\n error: 'Item ids must be unique within a group.',\n path: ['items'],\n })\n .check((ctx) => {\n for (const issue of timelineIssues(ctx.value, 'content')) {\n ctx.issues.push({ code: 'custom', ...issue });\n }\n });\n\n/** Strict learner-safe stimulus: everything but the author-only `transcript`. */\nexport const RedactedStimulusSchema = z.strictObject({\n id: z.string().min(1),\n kind: z.enum(['text', 'audio', 'video', 'image', 'mixed']),\n title: z.string().optional(),\n body: z.string().optional(),\n bodyHtml: z.string().optional(),\n media: RedactedMediaSchema.optional(),\n locale: z.string().optional(),\n attribution: z.string().optional(),\n});\n\n/**\n * Strict learner-safe item group. Items are left opaque here — each is proven\n * learner-safe by `assertRedacted` against its OWN type's redacted schema,\n * which is the only place that knowledge lives. The one exception is the one\n * rule that spans the container and an item: a captioned stimulus recording\n * played to a dictation is not learner-safe, because the captions are the\n * dictation's answer.\n */\nexport const RedactedItemGroupSchema = z\n .strictObject({\n redacted: z.literal(true),\n schemaVersion: z.literal('1.0'),\n type: z.literal('item-group'),\n id: z.string().min(1),\n title: z.string().optional(),\n slotKey: SlotKeySchema.optional(),\n stimulus: RedactedStimulusSchema,\n items: z.array(z.unknown()).min(1),\n shuffle: z.enum(['none', 'within-group']).optional(),\n timeline: MediaTimelineSchema.optional(),\n })\n .check((ctx) => {\n for (const issue of timelineIssues(ctx.value, 'redacted')) {\n ctx.issues.push({ code: 'custom', ...issue });\n }\n const captions = groupCaptionsField(ctx.value);\n if (captions !== undefined) {\n ctx.issues.push({\n code: 'custom',\n input: ctx.value.stimulus.media?.[captions],\n message: GROUP_CAPTIONS_REVEAL_DICTATION,\n path: ['stimulus', 'media', captions],\n });\n }\n });\n\nfunction toValidationErrors(\n issues: readonly { path: readonly PropertyKey[]; message: string; code: string }[],\n prefix: string[],\n): ValidationError[] {\n return issues.map((issue) => ({\n path: [...prefix, ...issue.path.map(String)],\n message: issue.message,\n code: issue.code,\n }));\n}\n\n/**\n * Validates an item group in full: the container and stimulus against\n * {@link ItemGroupSchema}, then every item against the schema registered for\n * its `type`. Errors from items are reported at `items.<index>.…`.\n *\n * Unlike `validateActivity`, an item whose type is not registered is REPORTED\n * (code `unknown_activity_type`) rather than thrown: a group is validated as\n * a whole, and an author fixing a six-item group wants every problem listed,\n * not the first one that happened to throw.\n */\nexport function validateItemGroup(data: unknown): ValidationResult<ItemGroup> {\n const container = ItemGroupSchema.safeParse(data);\n if (!container.success) {\n return { success: false, errors: toValidationErrors(container.error.issues, []) };\n }\n\n const errors: ValidationError[] = [];\n const items: ActivityData[] = [];\n container.data.items.forEach((item, index) => {\n const descriptor = getActivityTypeDescriptor(item.type);\n if (descriptor === undefined) {\n errors.push({\n path: ['items', String(index), 'type'],\n message: `Activity type \"${item.type}\" is not registered`,\n code: 'unknown_activity_type',\n });\n return;\n }\n const parsed = readSchema(descriptor.schema, item, `Activity type \"${descriptor.type}\"`);\n if (!parsed.success) {\n errors.push(...toValidationErrors(parsed.issues, ['items', String(index)]));\n return;\n }\n items.push(parsed.data as ActivityData);\n });\n const captions = groupCaptionsField(container.data);\n if (captions !== undefined) {\n errors.push({\n path: ['stimulus', 'media', captions],\n message: GROUP_CAPTIONS_REVEAL_DICTATION,\n code: 'custom',\n });\n }\n\n if (errors.length > 0) {\n return { success: false, errors };\n }\n // zod4 optional outputs are `T | undefined`; the wire type uses exact\n // optionals. Structurally identical at runtime — the cast is type-level.\n return { success: true, data: { ...container.data, items } as unknown as ItemGroup };\n}\n","/**\n * The bounds of an interactive video — an item group with a `timeline`.\n *\n * A leaf module on purpose: the schemas, the authoring checks and the timeline\n * helpers all read these, and nothing here may import any of them back.\n */\n\n/**\n * The item types an interactive video may present. CLOSED on purpose: a type\n * added to the SDK later, or a custom type a host registers, is not silently\n * embeddable. Each one here was chosen, and each works inside a paused video —\n * a read-aloud's microphone included, because every quiz pauses the video\n * first.\n */\nexport const INTERACTIVE_VIDEO_ITEM_TYPES = [\n 'multiple-choice',\n 'fill-in-the-blanks',\n 'gap-select',\n 'dictation',\n 'read-aloud',\n] as const;\n\n/** One of {@link INTERACTIVE_VIDEO_ITEM_TYPES}. */\nexport type InteractiveVideoItemType = (typeof INTERACTIVE_VIDEO_ITEM_TYPES)[number];\n\n/** Whether `type` is one of the item types an interactive video may present. */\nexport function isInteractiveVideoItemType(type: unknown): type is InteractiveVideoItemType {\n return (INTERACTIVE_VIDEO_ITEM_TYPES as readonly unknown[]).includes(type);\n}\n\n/** The most quizzes one video may hold. */\nexport const TIMELINE_MAX_QUIZZES = 100;\n\n/**\n * The most questions one interactive video may hold, across all its quizzes.\n * The player keeps every one of them mounted, so an answer survives the\n * learner rewinding past its quiz.\n */\nexport const TIMELINE_MAX_ITEMS = 200;\n\n/** The most chapters one video may hold. */\nexport const TIMELINE_MAX_CHAPTERS = 100;\n\n/** The longest quiz or chapter title, in UTF-16 units. A title sits on one line of the player. */\nexport const TIMELINE_MAX_TITLE_LENGTH = 120;\n","import { z } from 'zod/v4';\nimport { UnknownActivityTypeError } from '../errors.js';\nimport { getActivityTypeDescriptor } from '../registry/index.js';\nimport { DictationDataSchema } from './dictation.js';\nimport { FillInTheBlanksDataSchema } from './fill-in-the-blanks.js';\nimport { GapSelectDataSchema } from './gap-select.js';\nimport { ItemGroupSchema, StimulusSchema } from './item-group.js';\nimport { MultipleChoiceDataSchema } from './multiple-choice.js';\nimport { ReadAloudDataSchema } from './read-aloud.js';\nimport { isOwnSchema, standardJsonSchemaOf } from './read-schema.js';\nimport { WrittenResponseDataSchema } from './written-response.js';\n\n/**\n * JSON Schema (Draft 7) for a `Stimulus`. Structural contract only — the\n * kind/media/body consistency guards are Zod-only.\n */\nexport const stimulusJsonSchema: Record<string, unknown> = z.toJSONSchema(StimulusSchema, {\n target: 'draft-7',\n});\n\n/**\n * JSON Schema (Draft 7) for an `ItemGroup` CONTAINER. Items appear as objects\n * with `type` and `id` only; each item's own contract is `jsonSchemaFor(type)`.\n * For an AI generation pipeline, ask for the group and each item separately\n * rather than a single nested schema — that keeps the per-type schema the\n * registry's, not a copy.\n */\nexport const itemGroupJsonSchema: Record<string, unknown> = z.toJSONSchema(ItemGroupSchema, {\n target: 'draft-7',\n});\n\n/**\n * JSON Schema (Draft 7) representation of the Multiple Choice activity data\n * contract, generated natively by Zod 4. Draft 7 is mandated by Requirement\n * 2.2 for the widest AI-prompt / OpenAPI tooling compatibility. The semantic\n * `.refine()` guards are not representable in JSON Schema and are\n * intentionally omitted — the export captures the *structural* contract only.\n * Since v0.3 the source schemas are loose, so these no longer emit\n * `additionalProperties: false` — the JSON Schema and `validateActivity` now\n * agree on unknown-key handling.\n */\n/**\n * JSON Schema (Draft 7) representation of the Gap Select activity data\n * contract. Structural contract only: the six semantic guards — the\n * passage/gap bijection, id uniqueness, the one-choice-source rule, and an\n * answer key that names a choice the gap offers — are Zod-only, as they are\n * for the other types.\n */\nexport const gapSelectJsonSchema: Record<string, unknown> = z.toJSONSchema(GapSelectDataSchema, {\n target: 'draft-7',\n});\n\n/**\n * JSON Schema (Draft 7) representation of the Dictation activity data\n * contract. Structural contract, plus the raw length caps JSON Schema can\n * state in code points as zod counts them — `maxLength` 2000 on a transcript\n * and an accepted transcript, 200 on a rule's `from` and `to`. The twelve\n * semantic guards — a transcript that survives normalisation, the caps after\n * equivalences are applied, distinct candidates, audio only, the\n * slow-recording rules, no captions, no transcript in the title — are\n * Zod-only, as they are for the other types.\n */\nexport const dictationJsonSchema: Record<string, unknown> = z.toJSONSchema(DictationDataSchema, {\n target: 'draft-7',\n});\n\n/**\n * JSON Schema (Draft 7) representation of the Read Aloud activity data\n * contract. Structural contract, plus the raw cap JSON Schema can state in code\n * points as zod counts them — `maxLength` 2000 on the reference text — and the\n * canonical locale pattern. The ten semantic guards — the cap after\n * normalisation, a text that survives it, the spaced-script rule, the\n * model-recording rules, unique dimensions, a weight above 0, and the take\n * bounds — are Zod-only, as they are for the other types.\n */\nexport const readAloudJsonSchema: Record<string, unknown> = z.toJSONSchema(ReadAloudDataSchema, {\n target: 'draft-7',\n});\n\nexport const multipleChoiceJsonSchema: Record<string, unknown> = z.toJSONSchema(\n MultipleChoiceDataSchema,\n {\n target: 'draft-7',\n },\n);\n\n/**\n * JSON Schema (Draft 7) representation of the Fill-in-the-Blanks activity data\n * contract, generated natively by Zod 4. Structural contract only (semantic\n * `.refine()` guards are Zod-only and not representable in JSON Schema).\n */\nexport const fillInTheBlanksJsonSchema: Record<string, unknown> = z.toJSONSchema(\n FillInTheBlanksDataSchema,\n {\n target: 'draft-7',\n },\n);\n\n/**\n * JSON Schema (Draft 7) representation of the Written Response activity data\n * contract. Structural contract only.\n */\nexport const writtenResponseJsonSchema: Record<string, unknown> = z.toJSONSchema(\n WrittenResponseDataSchema,\n {\n target: 'draft-7',\n },\n);\n\n/**\n * Derives the JSON Schema (Draft 7) for any REGISTERED activity type — the\n * live, registry-backed replacement for the static per-type exports above,\n * and the building block for AI generation pipelines (R6.1): pass the result\n * as a structured-output schema so a model can only emit valid items.\n *\n * For a type you registered, it is the descriptor's `jsonSchema` when you gave\n * one, or else what the schema produces through the Standard JSON Schema\n * converter (`'~standard'.jsonSchema`) — a zod 4.6 schema has one. A fresh copy\n * every call.\n *\n * @throws UnknownActivityTypeError when `type` has no registered descriptor.\n * @throws Error when a registered type has neither a `jsonSchema` nor a schema\n * that can produce one.\n */\nexport function jsonSchemaFor(type: string): Record<string, unknown> {\n const descriptor = getActivityTypeDescriptor(type);\n if (descriptor === undefined) {\n throw new UnknownActivityTypeError(type);\n }\n if (isOwnSchema(descriptor.schema)) {\n return z.toJSONSchema(descriptor.schema as never, { target: 'draft-7' }) as Record<\n string,\n unknown\n >;\n }\n if (descriptor.jsonSchema !== undefined) {\n return structuredClone(descriptor.jsonSchema) as Record<string, unknown>;\n }\n const generated = standardJsonSchemaOf(descriptor.schema);\n if (generated === undefined) {\n throw new Error(\n `Activity type \"${descriptor.type}\" has no JSON Schema: its schema implements no Standard JSON Schema converter ('~standard'.jsonSchema). Give its descriptor a \\`jsonSchema\\`.`,\n );\n }\n return generated;\n}\n","import { UnknownActivityTypeError } from '../errors.js';\nimport { getActivityTypeDescriptor } from '../registry/index.js';\nimport type {\n ActivityDataMap,\n ActivityMedia,\n ActivityType,\n MultipleChoiceOptionMedia,\n ValidationResult,\n} from '../types/activity.js';\nimport { MediaSchema } from './media.js';\nimport { MultipleChoiceOptionMediaSchema } from './multiple-choice.js';\nimport { readSchema, type SchemaReading } from './read-schema.js';\n\nexport type {\n RedactedActivity,\n RedactedBlankConfig,\n RedactedDictationData,\n RedactedDictationSlowMedia,\n RedactedFillInTheBlanksData,\n RedactedGapSelectBank,\n RedactedGapSelectChoice,\n RedactedGapSelectData,\n RedactedGapSelectGap,\n RedactedMultipleChoiceData,\n RedactedMultipleChoiceOption,\n RedactedMultipleChoiceOptionMedia,\n RedactedReadAloudData,\n RedactedStimulus,\n RedactedWrittenResponseData,\n} from '../types/redacted.js';\nexport { validateItemGroup } from './item-group.js';\nexport {\n dictationJsonSchema,\n fillInTheBlanksJsonSchema,\n gapSelectJsonSchema,\n itemGroupJsonSchema,\n jsonSchemaFor,\n multipleChoiceJsonSchema,\n readAloudJsonSchema,\n stimulusJsonSchema,\n writtenResponseJsonSchema,\n} from './json-schema.js';\n\n/**\n * Checks a piece of activity media — an item's `media`, a stimulus's, a\n * dictation's `slowMedia` — on its own, the way `validateActivity` checks it\n * inside an item: its kind, an address in the allowed schemes, a playback\n * policy only on audio, captions and tracks only where they can play. For an\n * editor's media picker, which holds the media before the item is whole.\n *\n * @returns `{ success: true, data }`, or `{ success: false, errors }` with the\n * same codes, paths and messages `validateActivity` reports.\n */\nexport function validateMedia(value: unknown): ValidationResult<ActivityMedia> {\n return asValidation(readSchema(MediaSchema as never, value, 'Media'));\n}\n\n/**\n * Checks a multiple-choice option's `media` on its own: a picture or a\n * recording, at an address in the allowed schemes, with no playback policy.\n *\n * @returns `{ success: true, data }`, or `{ success: false, errors }` with the\n * same codes, paths and messages `validateActivity` reports.\n */\nexport function validateOptionMedia(value: unknown): ValidationResult<MultipleChoiceOptionMedia> {\n return asValidation(readSchema(MultipleChoiceOptionMediaSchema as never, value, 'Option media'));\n}\n\nfunction asValidation<T>(reading: SchemaReading<unknown>): ValidationResult<T> {\n if (reading.success) {\n return { success: true, data: reading.data as T };\n }\n return {\n success: false,\n errors: reading.issues.map((issue) => ({\n path: issue.path.map(String),\n message: issue.message,\n code: issue.code,\n })),\n };\n}\n\n/**\n * Validates raw activity data against the schema registered for the given\n * activity type (built-in or consumer-registered via `registerActivityType`).\n *\n * Unknown keys are PRESERVED, not stripped: every built-in schema is loose,\n * so consumer sidecar fields and forward-version fields survive validation\n * verbatim in the returned `data`.\n *\n * @returns `{ success: true, data }` with the typed, validated data, or\n * `{ success: false, errors }` with one entry per failed constraint.\n * @throws UnknownActivityTypeError when `type` has no registered descriptor.\n */\nexport function validateActivity<T extends ActivityType>(\n type: T,\n data: unknown,\n): ValidationResult<ActivityDataMap[T]> {\n const descriptor = getActivityTypeDescriptor(type);\n if (descriptor === undefined) {\n throw new UnknownActivityTypeError(String(type));\n }\n\n return asValidation(readSchema(descriptor.schema, data, `Activity type \"${descriptor.type}\"`));\n}\n"]}