@intellectif/lk-core 0.14.1 → 0.15.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.
- package/CHANGELOG.md +25 -0
- package/README.md +1 -0
- package/dist/{activity-BVkg9VDo.d.cts → activity-C7cR8U9n.d.cts} +35 -2
- package/dist/{activity-BVkg9VDo.d.ts → activity-C7cR8U9n.d.ts} +35 -2
- package/dist/{chunk-KTDOZR7Y.js → chunk-54XYQ3CS.js} +2 -2
- package/dist/{chunk-J5OIRIOW.cjs → chunk-5KWF34LJ.cjs} +31 -31
- package/dist/{chunk-J5OIRIOW.cjs.map → chunk-5KWF34LJ.cjs.map} +1 -1
- package/dist/{chunk-E7LPIZXI.cjs → chunk-7ETU6EXQ.cjs} +4 -4
- package/dist/{chunk-E7LPIZXI.cjs.map → chunk-7ETU6EXQ.cjs.map} +1 -1
- package/dist/{chunk-6RND47QE.js → chunk-DPHX4E7X.js} +62 -3
- package/dist/chunk-DPHX4E7X.js.map +1 -0
- package/dist/{chunk-NBADQ3JU.js → chunk-EEMVWBPP.js} +195 -4
- package/dist/chunk-EEMVWBPP.js.map +1 -0
- package/dist/{chunk-RTIR6R2U.js → chunk-L6YBQXSB.js} +2 -2
- package/dist/{chunk-VCXIPLEW.cjs → chunk-QFWEF5ST.cjs} +63 -4
- package/dist/chunk-QFWEF5ST.cjs.map +1 -0
- package/dist/chunk-W7AQP6AV.cjs +418 -0
- package/dist/chunk-W7AQP6AV.cjs.map +1 -0
- package/dist/{index-v2_-Fyn3.d.ts → index-BWyMDlUS.d.cts} +367 -2
- package/dist/{index-BE1bM2Wi.d.cts → index-D10NaztZ.d.ts} +367 -2
- package/dist/index.cjs +397 -96
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +103 -7
- package/dist/index.d.ts +103 -7
- package/dist/index.js +310 -9
- package/dist/index.js.map +1 -1
- package/dist/schemas.cjs +11 -3
- package/dist/schemas.cjs.map +1 -1
- package/dist/schemas.d.cts +2 -2
- package/dist/schemas.d.ts +2 -2
- package/dist/schemas.js +10 -2
- package/dist/scoring.cjs +3 -3
- package/dist/scoring.d.cts +2 -2
- package/dist/scoring.d.ts +2 -2
- package/dist/scoring.js +2 -2
- package/dist/xapi.cjs +3 -3
- package/dist/xapi.d.cts +1 -1
- package/dist/xapi.d.ts +1 -1
- package/dist/xapi.js +2 -2
- package/package.json +1 -1
- package/dist/chunk-2NIALQEH.cjs +0 -227
- package/dist/chunk-2NIALQEH.cjs.map +0 -1
- package/dist/chunk-6RND47QE.js.map +0 -1
- package/dist/chunk-NBADQ3JU.js.map +0 -1
- package/dist/chunk-VCXIPLEW.cjs.map +0 -1
- /package/dist/{chunk-KTDOZR7Y.js.map → chunk-54XYQ3CS.js.map} +0 -0
- /package/dist/{chunk-RTIR6R2U.js.map → chunk-L6YBQXSB.js.map} +0 -0
|
@@ -11,10 +11,28 @@ import {
|
|
|
11
11
|
WrittenResponseDataSchema,
|
|
12
12
|
getActivityTypeDescriptor,
|
|
13
13
|
groupCaptionsRevealDictation
|
|
14
|
-
} from "./chunk-
|
|
14
|
+
} from "./chunk-DPHX4E7X.js";
|
|
15
15
|
|
|
16
16
|
// src/schemas/item-group.ts
|
|
17
17
|
import { z } from "zod/v4";
|
|
18
|
+
|
|
19
|
+
// src/timeline-limits.ts
|
|
20
|
+
var INTERACTIVE_VIDEO_ITEM_TYPES = [
|
|
21
|
+
"multiple-choice",
|
|
22
|
+
"fill-in-the-blanks",
|
|
23
|
+
"gap-select",
|
|
24
|
+
"dictation",
|
|
25
|
+
"read-aloud"
|
|
26
|
+
];
|
|
27
|
+
function isInteractiveVideoItemType(type) {
|
|
28
|
+
return INTERACTIVE_VIDEO_ITEM_TYPES.includes(type);
|
|
29
|
+
}
|
|
30
|
+
var TIMELINE_MAX_QUIZZES = 100;
|
|
31
|
+
var TIMELINE_MAX_ITEMS = 200;
|
|
32
|
+
var TIMELINE_MAX_CHAPTERS = 100;
|
|
33
|
+
var TIMELINE_MAX_TITLE_LENGTH = 120;
|
|
34
|
+
|
|
35
|
+
// src/schemas/item-group.ts
|
|
18
36
|
var SlotKeySchema = z.string().min(1).refine((key) => !key.includes("."), {
|
|
19
37
|
error: 'slotKey must not contain "." \u2014 that character separates a group from its item in a slot id, so a key containing one would make the slot ambiguous.'
|
|
20
38
|
});
|
|
@@ -62,6 +80,161 @@ var StimulusSchema = z.looseObject({
|
|
|
62
80
|
path: ["media", "type"]
|
|
63
81
|
}
|
|
64
82
|
);
|
|
83
|
+
var TimelineTitleSchema = z.string().max(TIMELINE_MAX_TITLE_LENGTH).refine((title) => title.trim().length > 0, { error: "A title must not be empty." });
|
|
84
|
+
var TimelineTimeSchema = z.number().min(0, { error: "A time is 0 seconds or more." });
|
|
85
|
+
var TimelineCueSchema = z.strictObject({
|
|
86
|
+
id: z.string().min(1).max(64),
|
|
87
|
+
at: TimelineTimeSchema,
|
|
88
|
+
itemIds: z.array(z.string().min(1)).min(1).max(TIMELINE_MAX_ITEMS),
|
|
89
|
+
title: TimelineTitleSchema.optional(),
|
|
90
|
+
required: z.boolean().optional()
|
|
91
|
+
});
|
|
92
|
+
var TimelineChapterSchema = z.strictObject({
|
|
93
|
+
at: TimelineTimeSchema,
|
|
94
|
+
title: TimelineTitleSchema
|
|
95
|
+
});
|
|
96
|
+
var MediaTimelineSchema = z.strictObject({
|
|
97
|
+
cues: z.array(TimelineCueSchema).max(TIMELINE_MAX_QUIZZES),
|
|
98
|
+
chapters: z.array(TimelineChapterSchema).max(TIMELINE_MAX_CHAPTERS).optional(),
|
|
99
|
+
navigation: z.enum(["free", "no-skip-ahead"]).optional()
|
|
100
|
+
}).check((ctx) => {
|
|
101
|
+
const seen = /* @__PURE__ */ new Set();
|
|
102
|
+
ctx.value.cues.forEach((cue, index) => {
|
|
103
|
+
if (seen.has(cue.id)) {
|
|
104
|
+
ctx.issues.push({
|
|
105
|
+
code: "custom",
|
|
106
|
+
input: cue.id,
|
|
107
|
+
message: `Quiz id "${cue.id}" is used twice: events, drafts and the contents panel name a quiz by its id.`,
|
|
108
|
+
path: ["cues", index, "id"]
|
|
109
|
+
});
|
|
110
|
+
}
|
|
111
|
+
seen.add(cue.id);
|
|
112
|
+
});
|
|
113
|
+
const chapters = ctx.value.chapters ?? [];
|
|
114
|
+
chapters.forEach((chapter, index) => {
|
|
115
|
+
const previous = chapters[index - 1];
|
|
116
|
+
if (previous !== void 0 && chapter.at <= previous.at) {
|
|
117
|
+
ctx.issues.push({
|
|
118
|
+
code: "custom",
|
|
119
|
+
input: chapter.at,
|
|
120
|
+
message: "Chapter times must be strictly increasing.",
|
|
121
|
+
path: ["chapters", index, "at"]
|
|
122
|
+
});
|
|
123
|
+
}
|
|
124
|
+
});
|
|
125
|
+
});
|
|
126
|
+
function isLocalOnlyUrl(url) {
|
|
127
|
+
return typeof url === "string" && /^(data|blob):/i.test(url);
|
|
128
|
+
}
|
|
129
|
+
function timelineIssues(group, scope) {
|
|
130
|
+
const timeline = group.timeline;
|
|
131
|
+
if (timeline === void 0) {
|
|
132
|
+
return [];
|
|
133
|
+
}
|
|
134
|
+
const issues = [];
|
|
135
|
+
const media = group.stimulus.media;
|
|
136
|
+
if (group.stimulus.kind !== "video") {
|
|
137
|
+
issues.push({
|
|
138
|
+
path: ["stimulus", "kind"],
|
|
139
|
+
input: group.stimulus.kind,
|
|
140
|
+
message: "An interactive video needs a video stimulus: quizzes open at moments of a video, and nothing else has them."
|
|
141
|
+
});
|
|
142
|
+
} else if (media !== void 0 && media.type !== "video") {
|
|
143
|
+
issues.push({
|
|
144
|
+
path: ["stimulus", "media", "type"],
|
|
145
|
+
input: media.type,
|
|
146
|
+
message: "An interactive video needs a video file. An embedded provider player cannot be paused at the moment a quiz opens."
|
|
147
|
+
});
|
|
148
|
+
}
|
|
149
|
+
if (group.shuffle === "within-group") {
|
|
150
|
+
issues.push({
|
|
151
|
+
path: ["shuffle"],
|
|
152
|
+
input: group.shuffle,
|
|
153
|
+
message: 'An interactive video presents its questions in the order its quizzes open; shuffle: "within-group" cannot apply to it.'
|
|
154
|
+
});
|
|
155
|
+
}
|
|
156
|
+
if (group.items.length > TIMELINE_MAX_ITEMS) {
|
|
157
|
+
issues.push({
|
|
158
|
+
path: ["items"],
|
|
159
|
+
input: group.items.length,
|
|
160
|
+
message: `An interactive video holds at most ${TIMELINE_MAX_ITEMS} questions.`
|
|
161
|
+
});
|
|
162
|
+
}
|
|
163
|
+
const itemIds = /* @__PURE__ */ new Map();
|
|
164
|
+
group.items.forEach((item, index) => {
|
|
165
|
+
const {
|
|
166
|
+
id,
|
|
167
|
+
type,
|
|
168
|
+
media: itemMedia
|
|
169
|
+
} = item ?? {};
|
|
170
|
+
if (typeof id === "string") {
|
|
171
|
+
itemIds.set(id, index);
|
|
172
|
+
}
|
|
173
|
+
if (!isInteractiveVideoItemType(type)) {
|
|
174
|
+
issues.push({
|
|
175
|
+
path: ["items", index, "type"],
|
|
176
|
+
input: type,
|
|
177
|
+
message: `An interactive video may hold only ${INTERACTIVE_VIDEO_ITEM_TYPES.join(", ")} questions.`
|
|
178
|
+
});
|
|
179
|
+
}
|
|
180
|
+
if (scope === "content" && type === "dictation" && itemMedia === void 0) {
|
|
181
|
+
issues.push({
|
|
182
|
+
path: ["items", index, "media"],
|
|
183
|
+
input: itemMedia,
|
|
184
|
+
message: "A dictation inside an interactive video needs its own recording."
|
|
185
|
+
});
|
|
186
|
+
}
|
|
187
|
+
});
|
|
188
|
+
const placed = /* @__PURE__ */ new Set();
|
|
189
|
+
timeline.cues.forEach((cue, cueIndex) => {
|
|
190
|
+
cue.itemIds.forEach((itemId, position) => {
|
|
191
|
+
const path = ["timeline", "cues", cueIndex, "itemIds", position];
|
|
192
|
+
if (!itemIds.has(itemId)) {
|
|
193
|
+
issues.push({
|
|
194
|
+
path,
|
|
195
|
+
input: itemId,
|
|
196
|
+
message: `No item in this group has the id "${itemId}".`
|
|
197
|
+
});
|
|
198
|
+
} else if (placed.has(itemId)) {
|
|
199
|
+
issues.push({
|
|
200
|
+
path,
|
|
201
|
+
input: itemId,
|
|
202
|
+
message: `Item "${itemId}" is placed twice: every question belongs to exactly one quiz.`
|
|
203
|
+
});
|
|
204
|
+
}
|
|
205
|
+
placed.add(itemId);
|
|
206
|
+
});
|
|
207
|
+
});
|
|
208
|
+
for (const [itemId, index] of itemIds) {
|
|
209
|
+
if (!placed.has(itemId)) {
|
|
210
|
+
issues.push({
|
|
211
|
+
path: ["items", index],
|
|
212
|
+
input: itemId,
|
|
213
|
+
message: `Item "${itemId}" is in no quiz, so the video would never show it.`
|
|
214
|
+
});
|
|
215
|
+
}
|
|
216
|
+
}
|
|
217
|
+
if (scope === "content" && media !== void 0) {
|
|
218
|
+
const urls = [
|
|
219
|
+
[media.url, ["stimulus", "media", "url"]],
|
|
220
|
+
[media.poster, ["stimulus", "media", "poster"]],
|
|
221
|
+
...(media.tracks ?? []).map((track, index) => [
|
|
222
|
+
track.src,
|
|
223
|
+
["stimulus", "media", "tracks", index, "src"]
|
|
224
|
+
])
|
|
225
|
+
];
|
|
226
|
+
for (const [url, path] of urls) {
|
|
227
|
+
if (isLocalOnlyUrl(url)) {
|
|
228
|
+
issues.push({
|
|
229
|
+
path,
|
|
230
|
+
input: url,
|
|
231
|
+
message: "An interactive video is stored and served: its URLs cannot be data: or blob: URLs."
|
|
232
|
+
});
|
|
233
|
+
}
|
|
234
|
+
}
|
|
235
|
+
}
|
|
236
|
+
return issues;
|
|
237
|
+
}
|
|
65
238
|
var ItemShapeSchema = z.looseObject({
|
|
66
239
|
type: z.string().min(1),
|
|
67
240
|
id: z.string().min(1),
|
|
@@ -75,13 +248,18 @@ var ItemGroupSchema = z.looseObject({
|
|
|
75
248
|
slotKey: SlotKeySchema.optional(),
|
|
76
249
|
stimulus: StimulusSchema,
|
|
77
250
|
items: z.array(ItemShapeSchema).min(1),
|
|
78
|
-
shuffle: z.enum(["none", "within-group"]).optional()
|
|
251
|
+
shuffle: z.enum(["none", "within-group"]).optional(),
|
|
252
|
+
timeline: MediaTimelineSchema.optional()
|
|
79
253
|
}).refine((group) => group.items.every((item) => item.type !== "item-group"), {
|
|
80
254
|
error: "Item groups do not nest: every item must be an activity.",
|
|
81
255
|
path: ["items"]
|
|
82
256
|
}).refine((group) => new Set(group.items.map((item) => item.id)).size === group.items.length, {
|
|
83
257
|
error: "Item ids must be unique within a group.",
|
|
84
258
|
path: ["items"]
|
|
259
|
+
}).check((ctx) => {
|
|
260
|
+
for (const issue of timelineIssues(ctx.value, "content")) {
|
|
261
|
+
ctx.issues.push({ code: "custom", ...issue });
|
|
262
|
+
}
|
|
85
263
|
});
|
|
86
264
|
var RedactedStimulusSchema = z.strictObject({
|
|
87
265
|
id: z.string().min(1),
|
|
@@ -102,8 +280,12 @@ var RedactedItemGroupSchema = z.strictObject({
|
|
|
102
280
|
slotKey: SlotKeySchema.optional(),
|
|
103
281
|
stimulus: RedactedStimulusSchema,
|
|
104
282
|
items: z.array(z.unknown()).min(1),
|
|
105
|
-
shuffle: z.enum(["none", "within-group"]).optional()
|
|
283
|
+
shuffle: z.enum(["none", "within-group"]).optional(),
|
|
284
|
+
timeline: MediaTimelineSchema.optional()
|
|
106
285
|
}).check((ctx) => {
|
|
286
|
+
for (const issue of timelineIssues(ctx.value, "redacted")) {
|
|
287
|
+
ctx.issues.push({ code: "custom", ...issue });
|
|
288
|
+
}
|
|
107
289
|
if (groupCaptionsRevealDictation(ctx.value)) {
|
|
108
290
|
ctx.issues.push({
|
|
109
291
|
code: "custom",
|
|
@@ -208,7 +390,16 @@ function validateActivity(type, data) {
|
|
|
208
390
|
}
|
|
209
391
|
|
|
210
392
|
export {
|
|
393
|
+
INTERACTIVE_VIDEO_ITEM_TYPES,
|
|
394
|
+
isInteractiveVideoItemType,
|
|
395
|
+
TIMELINE_MAX_QUIZZES,
|
|
396
|
+
TIMELINE_MAX_ITEMS,
|
|
397
|
+
TIMELINE_MAX_CHAPTERS,
|
|
398
|
+
TIMELINE_MAX_TITLE_LENGTH,
|
|
211
399
|
StimulusSchema,
|
|
400
|
+
TimelineCueSchema,
|
|
401
|
+
TimelineChapterSchema,
|
|
402
|
+
MediaTimelineSchema,
|
|
212
403
|
ItemGroupSchema,
|
|
213
404
|
RedactedStimulusSchema,
|
|
214
405
|
RedactedItemGroupSchema,
|
|
@@ -224,4 +415,4 @@ export {
|
|
|
224
415
|
jsonSchemaFor,
|
|
225
416
|
validateActivity
|
|
226
417
|
};
|
|
227
|
-
//# sourceMappingURL=chunk-
|
|
418
|
+
//# sourceMappingURL=chunk-EEMVWBPP.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/schemas/item-group.ts","../src/timeline-limits.ts","../src/schemas/json-schema.ts","../src/schemas/index.ts"],"sourcesContent":["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, groupCaptionsRevealDictation } from './dictation.js';\nimport { MediaSchema, RedactedMediaSchema } from './media.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 = z\n .string()\n .max(TIMELINE_MAX_TITLE_LENGTH)\n .refine((title) => title.trim().length > 0, { error: 'A title must not be empty.' });\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: z.string().min(1).max(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/** The learner-safe shape of a stimulus, derived from the strict schema below. */\nexport type RedactedStimulus = z.infer<typeof RedactedStimulusSchema>;\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 if (groupCaptionsRevealDictation(ctx.value)) {\n ctx.issues.push({\n code: 'custom',\n input: ctx.value.stimulus.media?.captionsUrl,\n message: GROUP_CAPTIONS_REVEAL_DICTATION,\n path: ['stimulus', 'media', 'captionsUrl'],\n });\n }\n });\n\nfunction toValidationErrors(\n issues: readonly { path: 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 = descriptor.schema.safeParse(item);\n if (!parsed.success) {\n errors.push(...toValidationErrors(parsed.error.issues, ['items', String(index)]));\n return;\n }\n items.push(parsed.data as ActivityData);\n });\n if (groupCaptionsRevealDictation(container.data)) {\n errors.push({\n path: ['stimulus', 'media', 'captionsUrl'],\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 { 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 = z.toJSONSchema(StimulusSchema, { target: 'draft-7' });\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 = z.toJSONSchema(ItemGroupSchema, { target: 'draft-7' });\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 = 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 = 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 = z.toJSONSchema(ReadAloudDataSchema, {\n target: 'draft-7',\n});\n\nexport const multipleChoiceJsonSchema = z.toJSONSchema(MultipleChoiceDataSchema, {\n target: 'draft-7',\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 = z.toJSONSchema(FillInTheBlanksDataSchema, {\n target: 'draft-7',\n});\n\n/**\n * JSON Schema (Draft 7) representation of the Written Response activity data\n * contract. Structural contract only.\n */\nexport const writtenResponseJsonSchema = z.toJSONSchema(WrittenResponseDataSchema, {\n target: 'draft-7',\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 * @throws UnknownActivityTypeError when `type` has no registered descriptor.\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 return z.toJSONSchema(descriptor.schema as never, { target: 'draft-7' }) as Record<\n string,\n unknown\n >;\n}\n","import { UnknownActivityTypeError } from '../errors.js';\nimport { getActivityTypeDescriptor } from '../registry/index.js';\nimport type { ActivityDataMap, ActivityType, ValidationResult } from '../types/activity.js';\n\nexport {\n DictationDataSchema,\n DictationEquivalenceSchema,\n DictationSlowMediaSchema,\n DictationToleranceSchema,\n} from './dictation.js';\nexport { FeedbackSchema } from './feedback.js';\nexport {\n BlankConfigSchema,\n FillInTheBlanksDataSchema,\n TextMatchPolicySchema,\n} from './fill-in-the-blanks.js';\nexport {\n GapSelectBankSchema,\n GapSelectChoiceSchema,\n GapSelectDataSchema,\n GapSelectGapSchema,\n} from './gap-select.js';\nexport type { RedactedStimulus } from './item-group.js';\nexport {\n ItemGroupSchema,\n MediaTimelineSchema,\n RedactedItemGroupSchema,\n RedactedStimulusSchema,\n StimulusSchema,\n TimelineChapterSchema,\n TimelineCueSchema,\n validateItemGroup,\n} 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';\nexport {\n MediaPlaybackSchema,\n MediaSchema,\n MediaTrackSchema,\n MediaUrlSchema,\n NativeControlHintSchema,\n RedactedMediaSchema,\n} from './media.js';\nexport {\n MultipleChoiceDataSchema,\n MultipleChoiceOptionMediaSchema,\n MultipleChoiceOptionSchema,\n} from './multiple-choice.js';\nexport { ReadAloudDataSchema, ReadAloudSlowMediaSchema } from './read-aloud.js';\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 RedactedWrittenResponseData,\n} from './redacted.js';\nexport {\n RedactedBlankConfigSchema,\n RedactedDictationDataSchema,\n RedactedDictationSlowMediaSchema,\n RedactedFillInTheBlanksDataSchema,\n RedactedGapSelectBankSchema,\n RedactedGapSelectChoiceSchema,\n RedactedGapSelectDataSchema,\n RedactedGapSelectGapSchema,\n RedactedMultipleChoiceDataSchema,\n RedactedMultipleChoiceOptionMediaSchema,\n RedactedMultipleChoiceOptionSchema,\n RedactedReadAloudDataSchema,\n RedactedWrittenResponseDataSchema,\n} from './redacted.js';\nexport {\n WrittenResponseDataSchema,\n WrittenResponseRubricCriterionSchema,\n WrittenResponseRubricSchema,\n} from './written-response.js';\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 const result = descriptor.schema.safeParse(data);\n\n if (result.success) {\n return { success: true, data: result.data as ActivityDataMap[T] };\n }\n\n return {\n success: false,\n errors: result.error.issues.map((issue) => ({\n path: issue.path.map(String),\n message: issue.message,\n code: issue.code,\n })),\n };\n}\n"],"mappings":"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","names":["z","z"]}
|
|
@@ -14,7 +14,7 @@ import {
|
|
|
14
14
|
dictationReferenceWords,
|
|
15
15
|
getActivityTypeDescriptor,
|
|
16
16
|
normalizeDictationText
|
|
17
|
-
} from "./chunk-
|
|
17
|
+
} from "./chunk-DPHX4E7X.js";
|
|
18
18
|
|
|
19
19
|
// src/is-redacted.ts
|
|
20
20
|
function isRedacted(data) {
|
|
@@ -1031,4 +1031,4 @@ export {
|
|
|
1031
1031
|
score,
|
|
1032
1032
|
evaluate
|
|
1033
1033
|
};
|
|
1034
|
-
//# sourceMappingURL=chunk-
|
|
1034
|
+
//# sourceMappingURL=chunk-L6YBQXSB.js.map
|
|
@@ -953,11 +953,43 @@ var MediaPlaybackSchema = _v4.z.strictObject({
|
|
|
953
953
|
/** Advisory only. See {@link NativeControlHintSchema}. */
|
|
954
954
|
nativeControlHints: _v4.z.array(NativeControlHintSchema).min(1).max(2).optional()
|
|
955
955
|
});
|
|
956
|
+
var MediaTrackSchema = _v4.z.strictObject({
|
|
957
|
+
kind: _v4.z.enum(["captions", "subtitles"]),
|
|
958
|
+
src: MediaUrlSchema,
|
|
959
|
+
srclang: _v4.z.string().regex(/^[A-Za-z]{2,3}(-[A-Za-z0-9]{2,8})*$/, {
|
|
960
|
+
error: 'srclang must be a BCP 47 language tag, such as "en", "es" or "pt-BR".'
|
|
961
|
+
}),
|
|
962
|
+
label: _v4.z.string().max(60).refine((label) => label.trim().length > 0, { error: "A track label must not be empty." }),
|
|
963
|
+
default: _v4.z.boolean().optional()
|
|
964
|
+
});
|
|
965
|
+
var MAX_TRACKS = 12;
|
|
966
|
+
function posterFits(m) {
|
|
967
|
+
return m.poster === void 0 || m.type === "video";
|
|
968
|
+
}
|
|
969
|
+
function tracksFit(m) {
|
|
970
|
+
return m.tracks === void 0 || m.type === "audio" || m.type === "video";
|
|
971
|
+
}
|
|
972
|
+
function tracksAreDistinct(m) {
|
|
973
|
+
if (m.tracks === void 0) {
|
|
974
|
+
return true;
|
|
975
|
+
}
|
|
976
|
+
const defaults = m.tracks.filter((track) => track.default === true).length;
|
|
977
|
+
const keys = new Set(m.tracks.map((track) => `${track.kind}:${track.srclang.toLowerCase()}`));
|
|
978
|
+
return defaults <= 1 && keys.size === m.tracks.length;
|
|
979
|
+
}
|
|
980
|
+
var POSTER_FITS = { error: "poster is for video media only.", path: ["poster"] };
|
|
981
|
+
var TRACKS_FIT = { error: "tracks are for audio and video media only.", path: ["tracks"] };
|
|
982
|
+
var TRACKS_DISTINCT = {
|
|
983
|
+
error: "tracks: at most one may be the default, and no two may share a kind and a language \u2014 a menu listing one language twice cannot say which one it plays.",
|
|
984
|
+
path: ["tracks"]
|
|
985
|
+
};
|
|
956
986
|
var MediaSchema = _v4.z.looseObject({
|
|
957
987
|
type: _v4.z.enum(["image", "audio", "video", "embed"]),
|
|
958
988
|
url: MediaUrlSchema,
|
|
959
989
|
alt: _v4.z.string().min(1).optional(),
|
|
960
990
|
captionsUrl: MediaUrlSchema.optional(),
|
|
991
|
+
tracks: _v4.z.array(MediaTrackSchema).min(1).max(MAX_TRACKS).optional(),
|
|
992
|
+
poster: MediaUrlSchema.optional(),
|
|
961
993
|
playback: MediaPlaybackSchema.optional()
|
|
962
994
|
}).refine(
|
|
963
995
|
(m) => m.type !== "image" && m.type !== "embed" || typeof m.alt === "string" && m.alt.length > 0,
|
|
@@ -968,7 +1000,7 @@ var MediaSchema = _v4.z.looseObject({
|
|
|
968
1000
|
).refine((m) => m.type !== "embed" || /^https?:\/\//i.test(m.url), {
|
|
969
1001
|
error: "embed media requires an absolute http(s) provider URL. data:, blob:, and relative URLs are not allowed for embeds \u2014 the embed iframe runs with allow-scripts, and a data:/same-origin document there is an XSS vector.",
|
|
970
1002
|
path: ["url"]
|
|
971
|
-
}).refine((m) => m.playback === void 0 || m.type === "audio", {
|
|
1003
|
+
}).refine(posterFits, POSTER_FITS).refine(tracksFit, TRACKS_FIT).refine(tracksAreDistinct, TRACKS_DISTINCT).refine((m) => m.playback === void 0 || m.type === "audio", {
|
|
972
1004
|
error: "playback policy is supported on audio media only. An embed is a provider iframe the SDK cannot control at all (it has no reliable JS API for a third-party player); an image has nothing to play; video is deliberately deferred, because a video transport must also own fullscreen and Picture-in-Picture and the SDK will not pretend to govern those yet.",
|
|
973
1005
|
path: ["playback"]
|
|
974
1006
|
}).refine(
|
|
@@ -998,6 +1030,8 @@ var RedactedMediaSchema = _v4.z.strictObject({
|
|
|
998
1030
|
url: MediaUrlSchema,
|
|
999
1031
|
alt: _v4.z.string().min(1).optional(),
|
|
1000
1032
|
captionsUrl: MediaUrlSchema.optional(),
|
|
1033
|
+
tracks: _v4.z.array(MediaTrackSchema).min(1).max(MAX_TRACKS).optional(),
|
|
1034
|
+
poster: MediaUrlSchema.optional(),
|
|
1001
1035
|
playback: MediaPlaybackSchema.optional()
|
|
1002
1036
|
}).refine(
|
|
1003
1037
|
(m) => m.type !== "image" && m.type !== "embed" || typeof m.alt === "string" && m.alt.length > 0,
|
|
@@ -1008,7 +1042,7 @@ var RedactedMediaSchema = _v4.z.strictObject({
|
|
|
1008
1042
|
).refine((m) => m.type !== "embed" || /^https?:\/\//i.test(m.url), {
|
|
1009
1043
|
error: "embed media requires an absolute http(s) provider URL. data:, blob:, and relative URLs are not allowed for embeds \u2014 the embed iframe runs with allow-scripts, and a data:/same-origin document there is an XSS vector.",
|
|
1010
1044
|
path: ["url"]
|
|
1011
|
-
});
|
|
1045
|
+
}).refine(posterFits, POSTER_FITS).refine(tracksFit, TRACKS_FIT).refine(tracksAreDistinct, TRACKS_DISTINCT);
|
|
1012
1046
|
|
|
1013
1047
|
// src/schemas/dictation.ts
|
|
1014
1048
|
|
|
@@ -2203,6 +2237,21 @@ var DRAFT_ISSUE_SEVERITY = {
|
|
|
2203
2237
|
ig_item_type_unknown: "invalid",
|
|
2204
2238
|
ig_item_nested_group: "invalid",
|
|
2205
2239
|
ig_shuffle_invalid: "invalid",
|
|
2240
|
+
// interactive video (an item group with a timeline)
|
|
2241
|
+
ig_timeline_stimulus_kind: "invalid",
|
|
2242
|
+
ig_timeline_shuffle: "invalid",
|
|
2243
|
+
ig_timeline_quiz_id_required: "incomplete",
|
|
2244
|
+
ig_timeline_quiz_id_duplicate: "invalid",
|
|
2245
|
+
ig_timeline_quiz_time_required: "incomplete",
|
|
2246
|
+
ig_timeline_quiz_time_invalid: "invalid",
|
|
2247
|
+
ig_timeline_quiz_empty: "incomplete",
|
|
2248
|
+
ig_timeline_quiz_unknown_item: "invalid",
|
|
2249
|
+
ig_timeline_item_duplicate: "invalid",
|
|
2250
|
+
ig_timeline_item_unplaced: "incomplete",
|
|
2251
|
+
ig_timeline_item_type: "invalid",
|
|
2252
|
+
ig_timeline_dictation_media: "incomplete",
|
|
2253
|
+
ig_timeline_chapter_order: "invalid",
|
|
2254
|
+
ig_timeline_chapter_title: "incomplete",
|
|
2206
2255
|
// gap-select
|
|
2207
2256
|
gs_passage_required: "incomplete",
|
|
2208
2257
|
gs_gaps_required: "incomplete",
|
|
@@ -3984,6 +4033,15 @@ var MEDIA_FIELD_POLICY = {
|
|
|
3984
4033
|
url: "public",
|
|
3985
4034
|
alt: "public",
|
|
3986
4035
|
captionsUrl: "public",
|
|
4036
|
+
poster: "public",
|
|
4037
|
+
// Applies to every element of the array.
|
|
4038
|
+
tracks: {
|
|
4039
|
+
kind: "public",
|
|
4040
|
+
src: "public",
|
|
4041
|
+
srclang: "public",
|
|
4042
|
+
label: "public",
|
|
4043
|
+
default: "public"
|
|
4044
|
+
},
|
|
3987
4045
|
playback: {
|
|
3988
4046
|
controls: "public",
|
|
3989
4047
|
maxPlays: "public",
|
|
@@ -4367,5 +4425,6 @@ registerActivityType(readAloudType);
|
|
|
4367
4425
|
|
|
4368
4426
|
|
|
4369
4427
|
|
|
4370
|
-
|
|
4371
|
-
|
|
4428
|
+
|
|
4429
|
+
exports.ActivitySchemaError = ActivitySchemaError; exports.UnknownActivityTypeError = UnknownActivityTypeError; exports.RedactedScoringError = RedactedScoringError; exports.DeferredScoringError = DeferredScoringError; exports.withValidationScope = withValidationScope; exports.DICTATION_MAX_TRANSCRIPT_LENGTH = DICTATION_MAX_TRANSCRIPT_LENGTH; exports.DICTATION_MAX_TEXT_LENGTH = DICTATION_MAX_TEXT_LENGTH; exports.DICTATION_MAX_EQUIVALENCE_LENGTH = DICTATION_MAX_EQUIVALENCE_LENGTH; exports.DICTATION_MAX_EQUIVALENCES = DICTATION_MAX_EQUIVALENCES; exports.DICTATION_MAX_ACCEPTED_TRANSCRIPTS = DICTATION_MAX_ACCEPTED_TRANSCRIPTS; exports.codePointLength = codePointLength; exports.normalizeDictationText = normalizeDictationText; exports.FeedbackSchema = FeedbackSchema; exports.MediaUrlSchema = MediaUrlSchema; exports.NativeControlHintSchema = NativeControlHintSchema; exports.MediaPlaybackSchema = MediaPlaybackSchema; exports.MediaTrackSchema = MediaTrackSchema; exports.MediaSchema = MediaSchema; exports.RedactedMediaSchema = RedactedMediaSchema; exports.DictationSlowMediaSchema = DictationSlowMediaSchema; exports.DictationEquivalenceSchema = DictationEquivalenceSchema; exports.DictationToleranceSchema = DictationToleranceSchema; exports.DictationDataSchema = DictationDataSchema; exports.groupCaptionsRevealDictation = groupCaptionsRevealDictation; exports.GROUP_CAPTIONS_REVEAL_DICTATION = GROUP_CAPTIONS_REVEAL_DICTATION; exports.DRAFT_ISSUE_SEVERITY = DRAFT_ISSUE_SEVERITY; exports.issue = issue; exports.isRecord = isRecord; exports.refusesEmpty = refusesEmpty; exports.isUnset = isUnset; exports.isUnwritten = isUnwritten; exports.isMissingId = isMissingId; exports.checkMedia = checkMedia; exports.covers = covers; exports.pathKey = pathKey; exports.coveredPathsOf = coveredPathsOf; exports.TextMatchPolicySchema = TextMatchPolicySchema; exports.BlankConfigSchema = BlankConfigSchema; exports.FillInTheBlanksDataSchema = FillInTheBlanksDataSchema; exports.MultipleChoiceOptionMediaSchema = MultipleChoiceOptionMediaSchema; exports.MultipleChoiceOptionSchema = MultipleChoiceOptionSchema; exports.MultipleChoiceDataSchema = MultipleChoiceDataSchema; exports.READ_ALOUD_MAX_REFERENCE_LENGTH = READ_ALOUD_MAX_REFERENCE_LENGTH; exports.READ_ALOUD_MAX_SECONDS = READ_ALOUD_MAX_SECONDS; exports.READ_ALOUD_MAX_TAKES = READ_ALOUD_MAX_TAKES; exports.READ_ALOUD_MAX_DIMENSION_WEIGHT = READ_ALOUD_MAX_DIMENSION_WEIGHT; exports.SPEECH_ASSESSMENT_MAX_WORDS = SPEECH_ASSESSMENT_MAX_WORDS; exports.SPEECH_ASSESSMENT_MAX_TEXT_LENGTH = SPEECH_ASSESSMENT_MAX_TEXT_LENGTH; exports.CANONICAL_LOCALE_RE = CANONICAL_LOCALE_RE; exports.ReadAloudSlowMediaSchema = ReadAloudSlowMediaSchema; exports.ReadAloudDataSchema = ReadAloudDataSchema; exports.countWords = countWords; exports.GapSelectChoiceSchema = GapSelectChoiceSchema; exports.GapSelectBankSchema = GapSelectBankSchema; exports.GapSelectGapSchema = GapSelectGapSchema; exports.GapSelectDataSchema = GapSelectDataSchema; exports.WrittenResponseRubricCriterionSchema = WrittenResponseRubricCriterionSchema; exports.WrittenResponseRubricSchema = WrittenResponseRubricSchema; exports.WrittenResponseDataSchema = WrittenResponseDataSchema; exports.RedactedMultipleChoiceOptionMediaSchema = RedactedMultipleChoiceOptionMediaSchema; exports.RedactedMultipleChoiceOptionSchema = RedactedMultipleChoiceOptionSchema; exports.RedactedMultipleChoiceDataSchema = RedactedMultipleChoiceDataSchema; exports.RedactedBlankConfigSchema = RedactedBlankConfigSchema; exports.RedactedFillInTheBlanksDataSchema = RedactedFillInTheBlanksDataSchema; exports.RedactedGapSelectChoiceSchema = RedactedGapSelectChoiceSchema; exports.RedactedGapSelectBankSchema = RedactedGapSelectBankSchema; exports.RedactedGapSelectGapSchema = RedactedGapSelectGapSchema; exports.RedactedGapSelectDataSchema = RedactedGapSelectDataSchema; exports.RedactedWrittenResponseDataSchema = RedactedWrittenResponseDataSchema; exports.RedactedDictationSlowMediaSchema = RedactedDictationSlowMediaSchema; exports.RedactedDictationDataSchema = RedactedDictationDataSchema; exports.RedactedReadAloudDataSchema = RedactedReadAloudDataSchema; exports.dictationReferenceWords = dictationReferenceWords; exports.alignDictation = alignDictation; exports.STEP = STEP; exports.alignSequences = alignSequences; exports.levenshteinDistance = levenshteinDistance; exports.matchText = matchText; exports.defineActivityType = defineActivityType; exports.registerActivityType = registerActivityType; exports.getActivityTypeDescriptor = getActivityTypeDescriptor; exports.registeredActivityTypes = registeredActivityTypes; exports.MEDIA_FIELD_POLICY = MEDIA_FIELD_POLICY; exports.multipleChoiceType = multipleChoiceType; exports.fillInTheBlanksType = fillInTheBlanksType; exports.writtenResponseType = writtenResponseType; exports.gapSelectType = gapSelectType; exports.dictationType = dictationType; exports.readAloudType = readAloudType;
|
|
4430
|
+
//# sourceMappingURL=chunk-QFWEF5ST.cjs.map
|