@intellectif/lk-core 1.10.0 → 1.11.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 (80) hide show
  1. package/CHANGELOG.md +27 -0
  2. package/dist/{ai-zhc9yhRj.d.cts → ai-Cu17iVHa.d.cts} +429 -2
  3. package/dist/ai-Cu17iVHa.d.cts.map +1 -0
  4. package/dist/{ai-zhc9yhRj.d.ts → ai-Cu17iVHa.d.ts} +429 -2
  5. package/dist/ai-Cu17iVHa.d.ts.map +1 -0
  6. package/dist/ai-check.cjs +2 -2
  7. package/dist/ai-check.d.cts +1 -1
  8. package/dist/ai-check.d.ts +1 -1
  9. package/dist/ai-check.js +2 -2
  10. package/dist/{ai-writing-B1pKVkG7.cjs → ai-writing-C7f6aKNW.cjs} +27 -4
  11. package/dist/ai-writing-C7f6aKNW.cjs.map +1 -0
  12. package/dist/{ai-writing-DLvzBiZN.js → ai-writing-Dl1bJQbL.js} +22 -5
  13. package/dist/ai-writing-Dl1bJQbL.js.map +1 -0
  14. package/dist/{index-CxkqS62X.d.ts → index-B1zEN1Ur.d.ts} +25 -3
  15. package/dist/index-B1zEN1Ur.d.ts.map +1 -0
  16. package/dist/{index-Byar5VVs.d.ts → index-BTZWUwOe.d.ts} +2 -2
  17. package/dist/{index-Byar5VVs.d.ts.map → index-BTZWUwOe.d.ts.map} +1 -1
  18. package/dist/{index-f4YuMgFb.d.ts → index-BfUyl6ml.d.ts} +2 -2
  19. package/dist/{index-f4YuMgFb.d.ts.map → index-BfUyl6ml.d.ts.map} +1 -1
  20. package/dist/{index-DLsUnGHt.d.cts → index-CpamCGyZ.d.cts} +25 -3
  21. package/dist/index-CpamCGyZ.d.cts.map +1 -0
  22. package/dist/{index-BeC8tAWf.d.cts → index-DYnacygI.d.cts} +2 -2
  23. package/dist/{index-BeC8tAWf.d.cts.map → index-DYnacygI.d.cts.map} +1 -1
  24. package/dist/{index-Ccj8oL_E.d.cts → index-DjZ1vIVg.d.cts} +2 -2
  25. package/dist/{index-Ccj8oL_E.d.cts.map → index-DjZ1vIVg.d.cts.map} +1 -1
  26. package/dist/index.cjs +763 -6
  27. package/dist/index.cjs.map +1 -1
  28. package/dist/index.d.cts +189 -5
  29. package/dist/index.d.cts.map +1 -1
  30. package/dist/index.d.ts +189 -5
  31. package/dist/index.d.ts.map +1 -1
  32. package/dist/index.js +735 -7
  33. package/dist/index.js.map +1 -1
  34. package/dist/item-group-D7M3E7K2.cjs +1506 -0
  35. package/dist/item-group-D7M3E7K2.cjs.map +1 -0
  36. package/dist/item-group-uNAT5EX5.js +1338 -0
  37. package/dist/item-group-uNAT5EX5.js.map +1 -0
  38. package/dist/{registry-C9O9txy5.cjs → registry-RPfZZEqi.cjs} +28 -1
  39. package/dist/registry-RPfZZEqi.cjs.map +1 -0
  40. package/dist/{registry-Bw9grsCN.js → registry-kTqbi4Lb.js} +28 -1
  41. package/dist/registry-kTqbi4Lb.js.map +1 -0
  42. package/dist/{schemas-DcEAuAeU.cjs → schemas-C4V5wfOS.cjs} +3 -3
  43. package/dist/{schemas-DcEAuAeU.cjs.map → schemas-C4V5wfOS.cjs.map} +1 -1
  44. package/dist/{schemas-D14-tnNl.js → schemas-rDgIN4Vu.js} +3 -3
  45. package/dist/{schemas-D14-tnNl.js.map → schemas-rDgIN4Vu.js.map} +1 -1
  46. package/dist/schemas.cjs +3 -3
  47. package/dist/schemas.d.cts +1 -1
  48. package/dist/schemas.d.ts +1 -1
  49. package/dist/schemas.js +3 -3
  50. package/dist/{scoring-BGKdff2i.js → scoring-DshU9i7e.js} +49 -17
  51. package/dist/scoring-DshU9i7e.js.map +1 -0
  52. package/dist/{scoring-Db1CZeAn.cjs → scoring-KpYfR0lO.cjs} +49 -17
  53. package/dist/scoring-KpYfR0lO.cjs.map +1 -0
  54. package/dist/scoring.cjs +2 -2
  55. package/dist/scoring.d.cts +2 -2
  56. package/dist/scoring.d.ts +2 -2
  57. package/dist/scoring.js +2 -2
  58. package/dist/{xapi-DOAqH9__.cjs → xapi-CaM7f1sD.cjs} +2 -2
  59. package/dist/{xapi-DOAqH9__.cjs.map → xapi-CaM7f1sD.cjs.map} +1 -1
  60. package/dist/{xapi-BtBm8AWZ.js → xapi-fFq9KEXG.js} +2 -2
  61. package/dist/{xapi-BtBm8AWZ.js.map → xapi-fFq9KEXG.js.map} +1 -1
  62. package/dist/xapi.cjs +1 -1
  63. package/dist/xapi.d.cts +1 -1
  64. package/dist/xapi.d.ts +1 -1
  65. package/dist/xapi.js +1 -1
  66. package/package.json +1 -1
  67. package/dist/ai-writing-B1pKVkG7.cjs.map +0 -1
  68. package/dist/ai-writing-DLvzBiZN.js.map +0 -1
  69. package/dist/ai-zhc9yhRj.d.cts.map +0 -1
  70. package/dist/ai-zhc9yhRj.d.ts.map +0 -1
  71. package/dist/index-CxkqS62X.d.ts.map +0 -1
  72. package/dist/index-DLsUnGHt.d.cts.map +0 -1
  73. package/dist/item-group-C9boy5Mk.cjs +0 -513
  74. package/dist/item-group-C9boy5Mk.cjs.map +0 -1
  75. package/dist/item-group-Cqng1LPl.js +0 -453
  76. package/dist/item-group-Cqng1LPl.js.map +0 -1
  77. package/dist/registry-Bw9grsCN.js.map +0 -1
  78. package/dist/registry-C9O9txy5.cjs.map +0 -1
  79. package/dist/scoring-BGKdff2i.js.map +0 -1
  80. package/dist/scoring-Db1CZeAn.cjs.map +0 -1
@@ -1,5 +1,5 @@
1
- const require_registry = require("./registry-C9O9txy5.cjs");
2
- const require_item_group = require("./item-group-C9boy5Mk.cjs");
1
+ const require_registry = require("./registry-RPfZZEqi.cjs");
2
+ const require_item_group = require("./item-group-D7M3E7K2.cjs");
3
3
  let zod_v4 = require("zod/v4");
4
4
  zod_v4 = require_registry.__toESM(zod_v4, 1);
5
5
  // src/schemas/json-schema.ts
@@ -282,4 +282,4 @@ Object.defineProperty(exports, "writtenResponseJsonSchema", {
282
282
  }
283
283
  });
284
284
 
285
- //# sourceMappingURL=schemas-DcEAuAeU.cjs.map
285
+ //# sourceMappingURL=schemas-C4V5wfOS.cjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"schemas-DcEAuAeU.cjs","names":["z","StimulusSchema","ItemGroupSchema","GapSelectDataSchema","DictationDataSchema","ReadAloudDataSchema","MultipleChoiceDataSchema","FillInTheBlanksDataSchema","WrittenResponseDataSchema","getActivityTypeDescriptor","UnknownActivityTypeError","isOwnSchema","standardJsonSchemaOf","registeredActivityTypes","readSchema","MediaSchema","MultipleChoiceOptionMediaSchema","getActivityTypeDescriptor","UnknownActivityTypeError"],"sources":["../src/schemas/json-schema.ts","../src/schemas/index.ts"],"sourcesContent":["import * as z from 'zod/v4';\nimport { UnknownActivityTypeError } from '../errors.js';\nimport { getActivityTypeDescriptor, registeredActivityTypes } 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/** The JSON Schema drafts the SDK writes. */\nexport type JsonSchemaTarget = 'draft-2020-12' | 'draft-7';\n\n/** What the Standard JSON Schema converter calls each draft. */\nconst STANDARD_TARGET = { 'draft-7': 'draft-07', 'draft-2020-12': 'draft-2020-12' } as const;\n\n/**\n * Derives the JSON Schema for any REGISTERED activity type — the live,\n * registry-backed replacement for the static per-type exports above, and the\n * building block for AI generation pipelines (R6.1): pass the result as a\n * structured-output schema so a model can only emit valid items.\n *\n * Draft 7 unless `target` says `'draft-2020-12'`. For a type you registered,\n * it is the descriptor's `jsonSchema` when you gave one, in whatever draft you\n * wrote it, or else what the schema produces through the Standard JSON Schema\n * converter (`'~standard'.jsonSchema`) in the draft asked for — a zod 4.6\n * schema has one. A fresh copy 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(\n type: string,\n options: { target?: JsonSchemaTarget } = {},\n): Record<string, unknown> {\n const target = options.target ?? 'draft-7';\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 }) as Record<string, unknown>;\n }\n if (descriptor.jsonSchema !== undefined) {\n return structuredClone(descriptor.jsonSchema) as Record<string, unknown>;\n }\n const generated = standardJsonSchemaOf(descriptor.schema, STANDARD_TARGET[target]);\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\n/** A schema without its `$schema`, to sit inside another document. */\nfunction body(schema: Record<string, unknown>): Record<string, unknown> {\n const { $schema: _draft, ...rest } = schema;\n return rest;\n}\n\n/**\n * One JSON Schema document for content an outside tool writes: the root is a\n * `SequenceEntry` — an activity of any registered type, or an item group whose\n * items are typed too. Each type, the stimulus and the item group sit under\n * `$defs` (`definitions` in draft 7), so a tool can also point at one of them.\n * Draft 2020-12 unless `target` says `'draft-7'`.\n *\n * Structural, as every exported schema is: rules that span fields (one key in\n * a single-answer question, a blank for each marker, a slow recording that is\n * another file) cannot be written in JSON Schema. On import, `validateDraft`\n * and `validateItemGroupDraft` decide. It includes the author-only fields\n * (`transcript`, `script`), so a tool can write them.\n *\n * ```ts\n * writeFileSync('schema.json', JSON.stringify(contentJsonSchema(), null, 2));\n * ```\n */\nexport function contentJsonSchema(\n options: { target?: JsonSchemaTarget } = {},\n): Record<string, unknown> {\n const target = options.target ?? 'draft-2020-12';\n const definitions = target === 'draft-7' ? 'definitions' : '$defs';\n const ref = (name: string) => ({ $ref: `#/${definitions}/${name}` });\n const types = registeredActivityTypes();\n const anyActivity = { oneOf: types.map(ref) };\n\n const group = body(z.toJSONSchema(ItemGroupSchema, { target }) as Record<string, unknown>);\n const properties = group.properties as Record<string, Record<string, unknown>>;\n group.properties = {\n ...properties,\n stimulus: ref('stimulus'),\n // The container's own rule for an item (a `type`, an `id`, a `slotKey`),\n // and the item's type's whole contract.\n items: { ...properties.items, items: { allOf: [properties.items?.items, anyActivity] } },\n };\n\n return {\n $schema:\n target === 'draft-7'\n ? 'http://json-schema.org/draft-07/schema#'\n : 'https://json-schema.org/draft/2020-12/schema',\n title: 'SequenceEntry',\n description:\n 'One entry of a question set or an exam section: an activity, or an item group. Structural only: validateDraft and validateItemGroupDraft decide.',\n oneOf: [...types.map(ref), ref('item-group')],\n [definitions]: {\n ...Object.fromEntries(types.map((type) => [type, body(jsonSchemaFor(type, { target }))])),\n stimulus: body(z.toJSONSchema(StimulusSchema, { target }) as Record<string, unknown>),\n 'item-group': group,\n },\n };\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 contentJsonSchema,\n dictationJsonSchema,\n fillInTheBlanksJsonSchema,\n gapSelectJsonSchema,\n itemGroupJsonSchema,\n type JsonSchemaTarget,\n jsonSchemaFor,\n multipleChoiceJsonSchema,\n readAloudJsonSchema,\n stimulusJsonSchema,\n writtenResponseJsonSchema,\n} from './json-schema.js';\nexport { SCRIPT_MAX_TURNS } from './media.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"],"mappings":"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"}
1
+ {"version":3,"file":"schemas-C4V5wfOS.cjs","names":["z","StimulusSchema","ItemGroupSchema","GapSelectDataSchema","DictationDataSchema","ReadAloudDataSchema","MultipleChoiceDataSchema","FillInTheBlanksDataSchema","WrittenResponseDataSchema","getActivityTypeDescriptor","UnknownActivityTypeError","isOwnSchema","standardJsonSchemaOf","registeredActivityTypes","readSchema","MediaSchema","MultipleChoiceOptionMediaSchema","getActivityTypeDescriptor","UnknownActivityTypeError"],"sources":["../src/schemas/json-schema.ts","../src/schemas/index.ts"],"sourcesContent":["import * as z from 'zod/v4';\nimport { UnknownActivityTypeError } from '../errors.js';\nimport { getActivityTypeDescriptor, registeredActivityTypes } 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/** The JSON Schema drafts the SDK writes. */\nexport type JsonSchemaTarget = 'draft-2020-12' | 'draft-7';\n\n/** What the Standard JSON Schema converter calls each draft. */\nconst STANDARD_TARGET = { 'draft-7': 'draft-07', 'draft-2020-12': 'draft-2020-12' } as const;\n\n/**\n * Derives the JSON Schema for any REGISTERED activity type — the live,\n * registry-backed replacement for the static per-type exports above, and the\n * building block for AI generation pipelines (R6.1): pass the result as a\n * structured-output schema so a model can only emit valid items.\n *\n * Draft 7 unless `target` says `'draft-2020-12'`. For a type you registered,\n * it is the descriptor's `jsonSchema` when you gave one, in whatever draft you\n * wrote it, or else what the schema produces through the Standard JSON Schema\n * converter (`'~standard'.jsonSchema`) in the draft asked for — a zod 4.6\n * schema has one. A fresh copy 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(\n type: string,\n options: { target?: JsonSchemaTarget } = {},\n): Record<string, unknown> {\n const target = options.target ?? 'draft-7';\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 }) as Record<string, unknown>;\n }\n if (descriptor.jsonSchema !== undefined) {\n return structuredClone(descriptor.jsonSchema) as Record<string, unknown>;\n }\n const generated = standardJsonSchemaOf(descriptor.schema, STANDARD_TARGET[target]);\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\n/** A schema without its `$schema`, to sit inside another document. */\nfunction body(schema: Record<string, unknown>): Record<string, unknown> {\n const { $schema: _draft, ...rest } = schema;\n return rest;\n}\n\n/**\n * One JSON Schema document for content an outside tool writes: the root is a\n * `SequenceEntry` — an activity of any registered type, or an item group whose\n * items are typed too. Each type, the stimulus and the item group sit under\n * `$defs` (`definitions` in draft 7), so a tool can also point at one of them.\n * Draft 2020-12 unless `target` says `'draft-7'`.\n *\n * Structural, as every exported schema is: rules that span fields (one key in\n * a single-answer question, a blank for each marker, a slow recording that is\n * another file) cannot be written in JSON Schema. On import, `validateDraft`\n * and `validateItemGroupDraft` decide. It includes the author-only fields\n * (`transcript`, `script`), so a tool can write them.\n *\n * ```ts\n * writeFileSync('schema.json', JSON.stringify(contentJsonSchema(), null, 2));\n * ```\n */\nexport function contentJsonSchema(\n options: { target?: JsonSchemaTarget } = {},\n): Record<string, unknown> {\n const target = options.target ?? 'draft-2020-12';\n const definitions = target === 'draft-7' ? 'definitions' : '$defs';\n const ref = (name: string) => ({ $ref: `#/${definitions}/${name}` });\n const types = registeredActivityTypes();\n const anyActivity = { oneOf: types.map(ref) };\n\n const group = body(z.toJSONSchema(ItemGroupSchema, { target }) as Record<string, unknown>);\n const properties = group.properties as Record<string, Record<string, unknown>>;\n group.properties = {\n ...properties,\n stimulus: ref('stimulus'),\n // The container's own rule for an item (a `type`, an `id`, a `slotKey`),\n // and the item's type's whole contract.\n items: { ...properties.items, items: { allOf: [properties.items?.items, anyActivity] } },\n };\n\n return {\n $schema:\n target === 'draft-7'\n ? 'http://json-schema.org/draft-07/schema#'\n : 'https://json-schema.org/draft/2020-12/schema',\n title: 'SequenceEntry',\n description:\n 'One entry of a question set or an exam section: an activity, or an item group. Structural only: validateDraft and validateItemGroupDraft decide.',\n oneOf: [...types.map(ref), ref('item-group')],\n [definitions]: {\n ...Object.fromEntries(types.map((type) => [type, body(jsonSchemaFor(type, { target }))])),\n stimulus: body(z.toJSONSchema(StimulusSchema, { target }) as Record<string, unknown>),\n 'item-group': group,\n },\n };\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 contentJsonSchema,\n dictationJsonSchema,\n fillInTheBlanksJsonSchema,\n gapSelectJsonSchema,\n itemGroupJsonSchema,\n type JsonSchemaTarget,\n jsonSchemaFor,\n multipleChoiceJsonSchema,\n readAloudJsonSchema,\n stimulusJsonSchema,\n writtenResponseJsonSchema,\n} from './json-schema.js';\nexport { SCRIPT_MAX_TURNS } from './media.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"],"mappings":"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"}
@@ -1,5 +1,5 @@
1
- import { Et as FillInTheBlanksDataSchema, O as MultipleChoiceDataSchema, Ot as MediaSchema, Q as DictationDataSchema, _ as GapSelectDataSchema, a as readSchema, b as ReadAloudDataSchema, g as WrittenResponseDataSchema, i as isOwnSchema, it as UnknownActivityTypeError, k as MultipleChoiceOptionMediaSchema, o as standardJsonSchemaOf, r as registeredActivityTypes, t as getActivityTypeDescriptor } from "./registry-Bw9grsCN.js";
2
- import { r as StimulusSchema, t as ItemGroupSchema } from "./item-group-Cqng1LPl.js";
1
+ import { Et as FillInTheBlanksDataSchema, O as MultipleChoiceDataSchema, Ot as MediaSchema, Q as DictationDataSchema, _ as GapSelectDataSchema, a as readSchema, b as ReadAloudDataSchema, g as WrittenResponseDataSchema, i as isOwnSchema, it as UnknownActivityTypeError, k as MultipleChoiceOptionMediaSchema, o as standardJsonSchemaOf, r as registeredActivityTypes, t as getActivityTypeDescriptor } from "./registry-kTqbi4Lb.js";
2
+ import { r as StimulusSchema, t as ItemGroupSchema } from "./item-group-uNAT5EX5.js";
3
3
  import * as z from "zod/v4";
4
4
  // src/schemas/json-schema.ts
5
5
  /**
@@ -204,4 +204,4 @@ function validateActivity(type, data) {
204
204
  }
205
205
  export { dictationJsonSchema as a, itemGroupJsonSchema as c, readAloudJsonSchema as d, stimulusJsonSchema as f, contentJsonSchema as i, jsonSchemaFor as l, validateMedia as n, fillInTheBlanksJsonSchema as o, writtenResponseJsonSchema as p, validateOptionMedia as r, gapSelectJsonSchema as s, validateActivity as t, multipleChoiceJsonSchema as u };
206
206
 
207
- //# sourceMappingURL=schemas-D14-tnNl.js.map
207
+ //# sourceMappingURL=schemas-rDgIN4Vu.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"schemas-D14-tnNl.js","names":[],"sources":["../src/schemas/json-schema.ts","../src/schemas/index.ts"],"sourcesContent":["import * as z from 'zod/v4';\nimport { UnknownActivityTypeError } from '../errors.js';\nimport { getActivityTypeDescriptor, registeredActivityTypes } 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/** The JSON Schema drafts the SDK writes. */\nexport type JsonSchemaTarget = 'draft-2020-12' | 'draft-7';\n\n/** What the Standard JSON Schema converter calls each draft. */\nconst STANDARD_TARGET = { 'draft-7': 'draft-07', 'draft-2020-12': 'draft-2020-12' } as const;\n\n/**\n * Derives the JSON Schema for any REGISTERED activity type — the live,\n * registry-backed replacement for the static per-type exports above, and the\n * building block for AI generation pipelines (R6.1): pass the result as a\n * structured-output schema so a model can only emit valid items.\n *\n * Draft 7 unless `target` says `'draft-2020-12'`. For a type you registered,\n * it is the descriptor's `jsonSchema` when you gave one, in whatever draft you\n * wrote it, or else what the schema produces through the Standard JSON Schema\n * converter (`'~standard'.jsonSchema`) in the draft asked for — a zod 4.6\n * schema has one. A fresh copy 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(\n type: string,\n options: { target?: JsonSchemaTarget } = {},\n): Record<string, unknown> {\n const target = options.target ?? 'draft-7';\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 }) as Record<string, unknown>;\n }\n if (descriptor.jsonSchema !== undefined) {\n return structuredClone(descriptor.jsonSchema) as Record<string, unknown>;\n }\n const generated = standardJsonSchemaOf(descriptor.schema, STANDARD_TARGET[target]);\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\n/** A schema without its `$schema`, to sit inside another document. */\nfunction body(schema: Record<string, unknown>): Record<string, unknown> {\n const { $schema: _draft, ...rest } = schema;\n return rest;\n}\n\n/**\n * One JSON Schema document for content an outside tool writes: the root is a\n * `SequenceEntry` — an activity of any registered type, or an item group whose\n * items are typed too. Each type, the stimulus and the item group sit under\n * `$defs` (`definitions` in draft 7), so a tool can also point at one of them.\n * Draft 2020-12 unless `target` says `'draft-7'`.\n *\n * Structural, as every exported schema is: rules that span fields (one key in\n * a single-answer question, a blank for each marker, a slow recording that is\n * another file) cannot be written in JSON Schema. On import, `validateDraft`\n * and `validateItemGroupDraft` decide. It includes the author-only fields\n * (`transcript`, `script`), so a tool can write them.\n *\n * ```ts\n * writeFileSync('schema.json', JSON.stringify(contentJsonSchema(), null, 2));\n * ```\n */\nexport function contentJsonSchema(\n options: { target?: JsonSchemaTarget } = {},\n): Record<string, unknown> {\n const target = options.target ?? 'draft-2020-12';\n const definitions = target === 'draft-7' ? 'definitions' : '$defs';\n const ref = (name: string) => ({ $ref: `#/${definitions}/${name}` });\n const types = registeredActivityTypes();\n const anyActivity = { oneOf: types.map(ref) };\n\n const group = body(z.toJSONSchema(ItemGroupSchema, { target }) as Record<string, unknown>);\n const properties = group.properties as Record<string, Record<string, unknown>>;\n group.properties = {\n ...properties,\n stimulus: ref('stimulus'),\n // The container's own rule for an item (a `type`, an `id`, a `slotKey`),\n // and the item's type's whole contract.\n items: { ...properties.items, items: { allOf: [properties.items?.items, anyActivity] } },\n };\n\n return {\n $schema:\n target === 'draft-7'\n ? 'http://json-schema.org/draft-07/schema#'\n : 'https://json-schema.org/draft/2020-12/schema',\n title: 'SequenceEntry',\n description:\n 'One entry of a question set or an exam section: an activity, or an item group. Structural only: validateDraft and validateItemGroupDraft decide.',\n oneOf: [...types.map(ref), ref('item-group')],\n [definitions]: {\n ...Object.fromEntries(types.map((type) => [type, body(jsonSchemaFor(type, { target }))])),\n stimulus: body(z.toJSONSchema(StimulusSchema, { target }) as Record<string, unknown>),\n 'item-group': group,\n },\n };\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 contentJsonSchema,\n dictationJsonSchema,\n fillInTheBlanksJsonSchema,\n gapSelectJsonSchema,\n itemGroupJsonSchema,\n type JsonSchemaTarget,\n jsonSchemaFor,\n multipleChoiceJsonSchema,\n readAloudJsonSchema,\n stimulusJsonSchema,\n writtenResponseJsonSchema,\n} from './json-schema.js';\nexport { SCRIPT_MAX_TURNS } from './media.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"],"mappings":"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"}
1
+ {"version":3,"file":"schemas-rDgIN4Vu.js","names":[],"sources":["../src/schemas/json-schema.ts","../src/schemas/index.ts"],"sourcesContent":["import * as z from 'zod/v4';\nimport { UnknownActivityTypeError } from '../errors.js';\nimport { getActivityTypeDescriptor, registeredActivityTypes } 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/** The JSON Schema drafts the SDK writes. */\nexport type JsonSchemaTarget = 'draft-2020-12' | 'draft-7';\n\n/** What the Standard JSON Schema converter calls each draft. */\nconst STANDARD_TARGET = { 'draft-7': 'draft-07', 'draft-2020-12': 'draft-2020-12' } as const;\n\n/**\n * Derives the JSON Schema for any REGISTERED activity type — the live,\n * registry-backed replacement for the static per-type exports above, and the\n * building block for AI generation pipelines (R6.1): pass the result as a\n * structured-output schema so a model can only emit valid items.\n *\n * Draft 7 unless `target` says `'draft-2020-12'`. For a type you registered,\n * it is the descriptor's `jsonSchema` when you gave one, in whatever draft you\n * wrote it, or else what the schema produces through the Standard JSON Schema\n * converter (`'~standard'.jsonSchema`) in the draft asked for — a zod 4.6\n * schema has one. A fresh copy 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(\n type: string,\n options: { target?: JsonSchemaTarget } = {},\n): Record<string, unknown> {\n const target = options.target ?? 'draft-7';\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 }) as Record<string, unknown>;\n }\n if (descriptor.jsonSchema !== undefined) {\n return structuredClone(descriptor.jsonSchema) as Record<string, unknown>;\n }\n const generated = standardJsonSchemaOf(descriptor.schema, STANDARD_TARGET[target]);\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\n/** A schema without its `$schema`, to sit inside another document. */\nfunction body(schema: Record<string, unknown>): Record<string, unknown> {\n const { $schema: _draft, ...rest } = schema;\n return rest;\n}\n\n/**\n * One JSON Schema document for content an outside tool writes: the root is a\n * `SequenceEntry` — an activity of any registered type, or an item group whose\n * items are typed too. Each type, the stimulus and the item group sit under\n * `$defs` (`definitions` in draft 7), so a tool can also point at one of them.\n * Draft 2020-12 unless `target` says `'draft-7'`.\n *\n * Structural, as every exported schema is: rules that span fields (one key in\n * a single-answer question, a blank for each marker, a slow recording that is\n * another file) cannot be written in JSON Schema. On import, `validateDraft`\n * and `validateItemGroupDraft` decide. It includes the author-only fields\n * (`transcript`, `script`), so a tool can write them.\n *\n * ```ts\n * writeFileSync('schema.json', JSON.stringify(contentJsonSchema(), null, 2));\n * ```\n */\nexport function contentJsonSchema(\n options: { target?: JsonSchemaTarget } = {},\n): Record<string, unknown> {\n const target = options.target ?? 'draft-2020-12';\n const definitions = target === 'draft-7' ? 'definitions' : '$defs';\n const ref = (name: string) => ({ $ref: `#/${definitions}/${name}` });\n const types = registeredActivityTypes();\n const anyActivity = { oneOf: types.map(ref) };\n\n const group = body(z.toJSONSchema(ItemGroupSchema, { target }) as Record<string, unknown>);\n const properties = group.properties as Record<string, Record<string, unknown>>;\n group.properties = {\n ...properties,\n stimulus: ref('stimulus'),\n // The container's own rule for an item (a `type`, an `id`, a `slotKey`),\n // and the item's type's whole contract.\n items: { ...properties.items, items: { allOf: [properties.items?.items, anyActivity] } },\n };\n\n return {\n $schema:\n target === 'draft-7'\n ? 'http://json-schema.org/draft-07/schema#'\n : 'https://json-schema.org/draft/2020-12/schema',\n title: 'SequenceEntry',\n description:\n 'One entry of a question set or an exam section: an activity, or an item group. Structural only: validateDraft and validateItemGroupDraft decide.',\n oneOf: [...types.map(ref), ref('item-group')],\n [definitions]: {\n ...Object.fromEntries(types.map((type) => [type, body(jsonSchemaFor(type, { target }))])),\n stimulus: body(z.toJSONSchema(StimulusSchema, { target }) as Record<string, unknown>),\n 'item-group': group,\n },\n };\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 contentJsonSchema,\n dictationJsonSchema,\n fillInTheBlanksJsonSchema,\n gapSelectJsonSchema,\n itemGroupJsonSchema,\n type JsonSchemaTarget,\n jsonSchemaFor,\n multipleChoiceJsonSchema,\n readAloudJsonSchema,\n stimulusJsonSchema,\n writtenResponseJsonSchema,\n} from './json-schema.js';\nexport { SCRIPT_MAX_TURNS } from './media.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"],"mappings":"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"}
package/dist/schemas.cjs CHANGED
@@ -1,7 +1,7 @@
1
1
  Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
2
- const require_registry = require("./registry-C9O9txy5.cjs");
3
- const require_item_group = require("./item-group-C9boy5Mk.cjs");
4
- const require_schemas = require("./schemas-DcEAuAeU.cjs");
2
+ const require_registry = require("./registry-RPfZZEqi.cjs");
3
+ const require_item_group = require("./item-group-D7M3E7K2.cjs");
4
+ const require_schemas = require("./schemas-C4V5wfOS.cjs");
5
5
  exports.SCRIPT_MAX_TURNS = require_registry.SCRIPT_MAX_TURNS;
6
6
  exports.contentJsonSchema = require_schemas.contentJsonSchema;
7
7
  exports.dictationJsonSchema = require_schemas.dictationJsonSchema;
@@ -1,2 +1,2 @@
1
- import { A as RedactedStimulus, C as RedactedGapSelectChoice, D as RedactedMultipleChoiceOption, E as RedactedMultipleChoiceData, O as RedactedMultipleChoiceOptionMedia, S as RedactedGapSelectBank, T as RedactedGapSelectGap, _ as RedactedActivity, a as JsonSchemaTarget, b as RedactedDictationSlowMedia, c as fillInTheBlanksJsonSchema, d as jsonSchemaFor, f as multipleChoiceJsonSchema, g as validateItemGroup, h as writtenResponseJsonSchema, i as SCRIPT_MAX_TURNS, j as RedactedWrittenResponseData, k as RedactedReadAloudData, l as gapSelectJsonSchema, m as stimulusJsonSchema, n as validateMedia, o as contentJsonSchema, p as readAloudJsonSchema, r as validateOptionMedia, s as dictationJsonSchema, t as validateActivity, u as itemGroupJsonSchema, v as RedactedBlankConfig, w as RedactedGapSelectData, x as RedactedFillInTheBlanksData, y as RedactedDictationData } from "./index-Ccj8oL_E.cjs";
1
+ import { A as RedactedStimulus, C as RedactedGapSelectChoice, D as RedactedMultipleChoiceOption, E as RedactedMultipleChoiceData, O as RedactedMultipleChoiceOptionMedia, S as RedactedGapSelectBank, T as RedactedGapSelectGap, _ as RedactedActivity, a as JsonSchemaTarget, b as RedactedDictationSlowMedia, c as fillInTheBlanksJsonSchema, d as jsonSchemaFor, f as multipleChoiceJsonSchema, g as validateItemGroup, h as writtenResponseJsonSchema, i as SCRIPT_MAX_TURNS, j as RedactedWrittenResponseData, k as RedactedReadAloudData, l as gapSelectJsonSchema, m as stimulusJsonSchema, n as validateMedia, o as contentJsonSchema, p as readAloudJsonSchema, r as validateOptionMedia, s as dictationJsonSchema, t as validateActivity, u as itemGroupJsonSchema, v as RedactedBlankConfig, w as RedactedGapSelectData, x as RedactedFillInTheBlanksData, y as RedactedDictationData } from "./index-DjZ1vIVg.cjs";
2
2
  export { type JsonSchemaTarget, type RedactedActivity, type RedactedBlankConfig, type RedactedDictationData, type RedactedDictationSlowMedia, type RedactedFillInTheBlanksData, type RedactedGapSelectBank, type RedactedGapSelectChoice, type RedactedGapSelectData, type RedactedGapSelectGap, type RedactedMultipleChoiceData, type RedactedMultipleChoiceOption, type RedactedMultipleChoiceOptionMedia, type RedactedReadAloudData, type RedactedStimulus, type RedactedWrittenResponseData, SCRIPT_MAX_TURNS, contentJsonSchema, dictationJsonSchema, fillInTheBlanksJsonSchema, gapSelectJsonSchema, itemGroupJsonSchema, jsonSchemaFor, multipleChoiceJsonSchema, readAloudJsonSchema, stimulusJsonSchema, validateActivity, validateItemGroup, validateMedia, validateOptionMedia, writtenResponseJsonSchema };
package/dist/schemas.d.ts CHANGED
@@ -1,2 +1,2 @@
1
- import { A as RedactedStimulus, C as RedactedGapSelectChoice, D as RedactedMultipleChoiceOption, E as RedactedMultipleChoiceData, O as RedactedMultipleChoiceOptionMedia, S as RedactedGapSelectBank, T as RedactedGapSelectGap, _ as RedactedActivity, a as JsonSchemaTarget, b as RedactedDictationSlowMedia, c as fillInTheBlanksJsonSchema, d as jsonSchemaFor, f as multipleChoiceJsonSchema, g as validateItemGroup, h as writtenResponseJsonSchema, i as SCRIPT_MAX_TURNS, j as RedactedWrittenResponseData, k as RedactedReadAloudData, l as gapSelectJsonSchema, m as stimulusJsonSchema, n as validateMedia, o as contentJsonSchema, p as readAloudJsonSchema, r as validateOptionMedia, s as dictationJsonSchema, t as validateActivity, u as itemGroupJsonSchema, v as RedactedBlankConfig, w as RedactedGapSelectData, x as RedactedFillInTheBlanksData, y as RedactedDictationData } from "./index-f4YuMgFb.js";
1
+ import { A as RedactedStimulus, C as RedactedGapSelectChoice, D as RedactedMultipleChoiceOption, E as RedactedMultipleChoiceData, O as RedactedMultipleChoiceOptionMedia, S as RedactedGapSelectBank, T as RedactedGapSelectGap, _ as RedactedActivity, a as JsonSchemaTarget, b as RedactedDictationSlowMedia, c as fillInTheBlanksJsonSchema, d as jsonSchemaFor, f as multipleChoiceJsonSchema, g as validateItemGroup, h as writtenResponseJsonSchema, i as SCRIPT_MAX_TURNS, j as RedactedWrittenResponseData, k as RedactedReadAloudData, l as gapSelectJsonSchema, m as stimulusJsonSchema, n as validateMedia, o as contentJsonSchema, p as readAloudJsonSchema, r as validateOptionMedia, s as dictationJsonSchema, t as validateActivity, u as itemGroupJsonSchema, v as RedactedBlankConfig, w as RedactedGapSelectData, x as RedactedFillInTheBlanksData, y as RedactedDictationData } from "./index-BfUyl6ml.js";
2
2
  export { type JsonSchemaTarget, type RedactedActivity, type RedactedBlankConfig, type RedactedDictationData, type RedactedDictationSlowMedia, type RedactedFillInTheBlanksData, type RedactedGapSelectBank, type RedactedGapSelectChoice, type RedactedGapSelectData, type RedactedGapSelectGap, type RedactedMultipleChoiceData, type RedactedMultipleChoiceOption, type RedactedMultipleChoiceOptionMedia, type RedactedReadAloudData, type RedactedStimulus, type RedactedWrittenResponseData, SCRIPT_MAX_TURNS, contentJsonSchema, dictationJsonSchema, fillInTheBlanksJsonSchema, gapSelectJsonSchema, itemGroupJsonSchema, jsonSchemaFor, multipleChoiceJsonSchema, readAloudJsonSchema, stimulusJsonSchema, validateActivity, validateItemGroup, validateMedia, validateOptionMedia, writtenResponseJsonSchema };
package/dist/schemas.js CHANGED
@@ -1,4 +1,4 @@
1
- import { At as SCRIPT_MAX_TURNS } from "./registry-Bw9grsCN.js";
2
- import { i as validateItemGroup } from "./item-group-Cqng1LPl.js";
3
- import { a as dictationJsonSchema, c as itemGroupJsonSchema, d as readAloudJsonSchema, f as stimulusJsonSchema, i as contentJsonSchema, l as jsonSchemaFor, n as validateMedia, o as fillInTheBlanksJsonSchema, p as writtenResponseJsonSchema, r as validateOptionMedia, s as gapSelectJsonSchema, t as validateActivity, u as multipleChoiceJsonSchema } from "./schemas-D14-tnNl.js";
1
+ import { At as SCRIPT_MAX_TURNS } from "./registry-kTqbi4Lb.js";
2
+ import { i as validateItemGroup } from "./item-group-uNAT5EX5.js";
3
+ import { a as dictationJsonSchema, c as itemGroupJsonSchema, d as readAloudJsonSchema, f as stimulusJsonSchema, i as contentJsonSchema, l as jsonSchemaFor, n as validateMedia, o as fillInTheBlanksJsonSchema, p as writtenResponseJsonSchema, r as validateOptionMedia, s as gapSelectJsonSchema, t as validateActivity, u as multipleChoiceJsonSchema } from "./schemas-rDgIN4Vu.js";
4
4
  export { SCRIPT_MAX_TURNS, contentJsonSchema, dictationJsonSchema, fillInTheBlanksJsonSchema, gapSelectJsonSchema, itemGroupJsonSchema, jsonSchemaFor, multipleChoiceJsonSchema, readAloudJsonSchema, stimulusJsonSchema, validateActivity, validateItemGroup, validateMedia, validateOptionMedia, writtenResponseJsonSchema };
@@ -1,4 +1,4 @@
1
- import { B as countWords, D as SPEECH_ASSESSMENT_MAX_WORDS, E as SPEECH_ASSESSMENT_MAX_TEXT_LENGTH, L as levelDistribution, Mt as maxUnits, R as levelKey, at as STEP, b as ReadAloudDataSchema, ct as dictationReferenceWords, ht as normalizeDictationText, it as UnknownActivityTypeError, mt as codePointLength, nt as DeferredScoringError, rt as RedactedScoringError, st as alignSequences, t as getActivityTypeDescriptor, tt as ActivitySchemaError, x as CANONICAL_LOCALE_RE, y as SpeakingResponseDataSchema, z as readRubricLevels } from "./registry-Bw9grsCN.js";
1
+ import { B as countWords, D as SPEECH_ASSESSMENT_MAX_WORDS, E as SPEECH_ASSESSMENT_MAX_TEXT_LENGTH, L as levelDistribution, Mt as maxUnits, R as levelKey, at as STEP, b as ReadAloudDataSchema, ct as dictationReferenceWords, ht as normalizeDictationText, it as UnknownActivityTypeError, mt as codePointLength, nt as DeferredScoringError, rt as RedactedScoringError, st as alignSequences, t as getActivityTypeDescriptor, tt as ActivitySchemaError, x as CANONICAL_LOCALE_RE, y as SpeakingResponseDataSchema, z as readRubricLevels } from "./registry-kTqbi4Lb.js";
2
2
  import * as z from "zod/v4";
3
3
  // src/scoring/grade-numbers.ts
4
4
  /**
@@ -222,16 +222,27 @@ const ROUNDING_MODES = [
222
222
  const MAX_ROUNDING_DP = 15;
223
223
  /**
224
224
  * The rounding policy `value` holds, or `undefined` for none (`undefined` or
225
- * `null`). A malformed one would reach {@link gte} as `10 ** undefined` and
226
- * turn a perfect score into a fail with no error, so it throws here instead.
225
+ * `null`): the check for an optional `rounding`. Anything else is checked by
226
+ * {@link requireRoundingPolicy}.
227
227
  *
228
- * Internal. Every function that takes a `rounding` option checks it here, so
229
- * each refuses the same policies with the same message; `scoring/index.ts`
230
- * does not re-export it.
228
+ * Internal, as is {@link requireRoundingPolicy}: `scoring/index.ts` re-exports
229
+ * neither.
231
230
  */
232
231
  function roundingPolicyOf(value) {
233
- if (value === void 0 || value === null) return;
234
- const { mode, dp } = value;
232
+ return value === void 0 || value === null ? void 0 : requireRoundingPolicy(value);
233
+ }
234
+ /**
235
+ * The rounding policy `value` holds. A malformed one would reach the rounding
236
+ * as `10 ** undefined` and turn a perfect score into a fail with no error, so
237
+ * it throws here instead; so does a missing one, `undefined` or `null`, where a
238
+ * policy is required.
239
+ *
240
+ * Every function that takes a policy, as an argument or a `rounding` option,
241
+ * checks it here or through {@link roundingPolicyOf}, so each refuses the same
242
+ * policies with the same message.
243
+ */
244
+ function requireRoundingPolicy(value) {
245
+ const { mode, dp } = value ?? {};
235
246
  if (!ROUNDING_MODES.includes(mode) || typeof dp !== "number" || !Number.isInteger(dp) || dp < 0 || dp > MAX_ROUNDING_DP) {
236
247
  const describe = (field) => typeof field === "string" ? JSON.stringify(field) : typeof field === "number" || field === void 0 ? String(field) : typeof field === "object" ? "an object" : `a ${typeof field}`;
237
248
  throw new RangeError(`Invalid rounding policy (mode ${describe(mode)}, dp ${describe(dp)}): expected { mode: 'half-up' | 'half-even' | 'floor' | 'ceil', dp: a whole number from 0 to ${MAX_ROUNDING_DP} }.`);
@@ -262,8 +273,9 @@ function scaled(value, dp) {
262
273
  * Normalises `-0` to `0` without touching anything else. `-0` JSON-serialises
263
274
  * as `0` but fails `Object.is(-0, 0)`, which surprises a strict-equality
264
275
  * gradebook comparison. Deliberately NOT `|| 0`: that also swallowed `NaN`
265
- * (reachable with an absurd `dp`, where `10 ** dp` overflows to Infinity) and
266
- * turned a visible failure into a plausible-looking grade of zero.
276
+ * (reached with an absurd `dp`, where `10 ** dp` overflows to Infinity, before
277
+ * policies were checked) and turned a visible failure into a plausible-looking
278
+ * grade of zero.
267
279
  */
268
280
  function noNegZero(value) {
269
281
  return Object.is(value, -0) ? 0 : value;
@@ -274,8 +286,15 @@ function noNegZero(value) {
274
286
  * Idempotent for every mode: rounding an already-rounded value returns it
275
287
  * unchanged. That matters because a composed score is rounded once and then
276
288
  * compared through {@link gte}, which rounds again.
289
+ *
290
+ * @throws RangeError when `policy` is not a {@link RoundingPolicy} — for a
291
+ * non-finite `value` too, which a policy returns unchanged.
277
292
  */
278
293
  function roundGrade(value, policy) {
294
+ return round(value, requireRoundingPolicy(policy));
295
+ }
296
+ /** {@link roundGrade} under a policy {@link requireRoundingPolicy} returned. */
297
+ function round(value, policy) {
279
298
  if (!Number.isFinite(value)) return value;
280
299
  const factor = 10 ** policy.dp;
281
300
  const raw = scaled(value, policy.dp);
@@ -306,9 +325,13 @@ function halfAway(raw) {
306
325
  * shown one number and recorded against another. Rounding both sides — and
307
326
  * allowing an epsilon — makes "what the learner sees" and "what the gradebook
308
327
  * decides" the same comparison.
328
+ *
329
+ * @throws RangeError when `policy` is not a {@link RoundingPolicy}. It is read
330
+ * once, so both sides are rounded under the same one.
309
331
  */
310
332
  function gte(value, threshold, policy) {
311
- return roundGrade(value, policy) >= roundGrade(threshold, policy) - EPSILON;
333
+ const checked = requireRoundingPolicy(policy);
334
+ return round(value, checked) >= round(threshold, checked) - EPSILON;
312
335
  }
313
336
  /**
314
337
  * Classifies a value into a band by **flooring**: the highest band whose `min`
@@ -337,10 +360,16 @@ const DEFAULT_PASS_THRESHOLD = .7;
337
360
  * the rounding band, and this SDK does not alter historical grades without an
338
361
  * explicit decision. Absent, the comparison is the exact raw `>=` it has
339
362
  * always been.
363
+ *
364
+ * The policy is checked at the call, as `score()`'s `rounding` option is:
365
+ * `null` reads as no policy, and one that cannot be applied — an unknown
366
+ * `mode`, or a `dp` that is not a whole number from 0 to 15 — throws a
367
+ * `RangeError` instead of quietly failing the comparison.
340
368
  */
341
369
  function computePassThreshold(activityData, score, rounding) {
370
+ const policy = roundingPolicyOf(rounding);
342
371
  const threshold = activityData.passThreshold ?? .7;
343
- return rounding === void 0 ? score >= threshold : gte(score, threshold, rounding);
372
+ return policy === void 0 ? score >= threshold : gte(score, threshold, policy);
344
373
  }
345
374
  /**
346
375
  * Selects the authored overall feedback for a result: `feedback.correct` when
@@ -1161,8 +1190,11 @@ function rejectedField(slotIds) {
1161
1190
  * until every item has a grade. An outcome whose score cannot be a grade out of
1162
1191
  * its `maxScore` is not a grade either: it is held the same way and named in
1163
1192
  * `rejectedSlotIds`.
1193
+ *
1194
+ * @throws RangeError when `policy.rounding` is not a `RoundingPolicy`.
1164
1195
  */
1165
1196
  function composeAssessmentScore(sections, policy) {
1197
+ const rounding = requireRoundingPolicy(policy.rounding);
1166
1198
  const pendingAll = [];
1167
1199
  const rejectedAll = [];
1168
1200
  const unscorableAll = [];
@@ -1200,7 +1232,7 @@ function composeAssessmentScore(sections, policy) {
1200
1232
  earnedPoints,
1201
1233
  gradedMaxPoints,
1202
1234
  maxPoints,
1203
- score: roundGrade(raw, policy.rounding),
1235
+ score: roundGrade(raw, rounding),
1204
1236
  appliedThreshold,
1205
1237
  pendingSlotIds,
1206
1238
  rejectedSlotIds,
@@ -1217,13 +1249,13 @@ function composeAssessmentScore(sections, policy) {
1217
1249
  gradedMaxPoints: partial.gradedMaxPoints,
1218
1250
  maxPoints: partial.maxPoints,
1219
1251
  score: partial.score,
1220
- passed: partial.appliedThreshold === null || partial.gradedMaxPoints === 0 ? true : gte(partial.score, partial.appliedThreshold, policy.rounding),
1252
+ passed: partial.appliedThreshold === null || partial.gradedMaxPoints === 0 ? true : gte(partial.score, partial.appliedThreshold, rounding),
1221
1253
  appliedThreshold: partial.appliedThreshold,
1222
1254
  pendingSlotIds: partial.pendingSlotIds,
1223
1255
  ...rejectedField(partial.rejectedSlotIds),
1224
1256
  unscorableSlotIds: partial.unscorableSlotIds
1225
1257
  }));
1226
- const score = roundGrade(scored.reduce((sum, section) => sum + section.score * section.normalizedWeight, 0), policy.rounding);
1258
+ const score = roundGrade(scored.reduce((sum, section) => sum + section.score * section.normalizedWeight, 0), rounding);
1227
1259
  const status = pendingAll.length > 0 ? "provisional" : "final";
1228
1260
  if (status === "provisional") return {
1229
1261
  sections: scored,
@@ -1245,7 +1277,7 @@ function composeAssessmentScore(sections, policy) {
1245
1277
  ...rejectedField(rejectedAll),
1246
1278
  unscorableSlotIds: unscorableAll
1247
1279
  };
1248
- const overallOk = gte(score, policy.passThreshold, policy.rounding);
1280
+ const overallOk = gte(score, policy.passThreshold, rounding);
1249
1281
  const sectionsOk = scored.every((section) => section.passed);
1250
1282
  const passed = overallOk && sectionsOk;
1251
1283
  return {
@@ -2423,4 +2455,4 @@ function costed(data, opening, graded, rules, rounding) {
2423
2455
  }
2424
2456
  export { roundGrade as A, canonicalJson as C, computePassThreshold as D, DEFAULT_PASS_THRESHOLD as E, validateItemScoringPolicy as F, isGradeInRange as I, ITEM_SCORING_MAX_RETRIES as M, resolveItemScoringPolicy as N, classifyBand as O, scoreTries as P, graderConfiguration as S, fingerprint as T, gradeFromJudgement as _, inspectWav as a, outcomeFromGrade as b, alignReadAloud as c, composeAssessmentScore as d, inAuditSample as f, seededShuffle as g, hashSeed as h, outcomeFromUnscorable as i, DEFAULT_ITEM_SCORING_POLICY as j, gte as k, validateSpeechAssessment as l, routeGrade as m, evaluateTries as n, gradeSpeakingResponse as o, outcomeFromRoutedGrade as p, score as r, gradeReadAloud as s, evaluate as t, diffDictationChars as u, gradeFromRubric as v, contentHash as w, calibrationReport as x, hasGrade as y };
2425
2457
 
2426
- //# sourceMappingURL=scoring-BGKdff2i.js.map
2458
+ //# sourceMappingURL=scoring-DshU9i7e.js.map