@intellectif/lk-core 1.4.0 → 1.6.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 (89) hide show
  1. package/CHANGELOG.md +102 -0
  2. package/README.md +2 -0
  3. package/dist/ai-check.cjs +175 -17
  4. package/dist/ai-check.cjs.map +1 -1
  5. package/dist/ai-check.d.cts +13 -5
  6. package/dist/ai-check.d.cts.map +1 -1
  7. package/dist/ai-check.d.ts +13 -5
  8. package/dist/ai-check.d.ts.map +1 -1
  9. package/dist/ai-check.js +175 -17
  10. package/dist/ai-check.js.map +1 -1
  11. package/dist/{ai-CnmLPMzd.d.ts → ai-i3jwXnpX.d.cts} +242 -7
  12. package/dist/ai-i3jwXnpX.d.cts.map +1 -0
  13. package/dist/{ai-CnmLPMzd.d.cts → ai-i3jwXnpX.d.ts} +242 -7
  14. package/dist/ai-i3jwXnpX.d.ts.map +1 -0
  15. package/dist/{ai-writing-G6tnCGzw.cjs → ai-writing-C4YRVrFi.cjs} +683 -72
  16. package/dist/ai-writing-C4YRVrFi.cjs.map +1 -0
  17. package/dist/{ai-writing-CPpH9Qxq.js → ai-writing-OJ5m_1EB.js} +663 -88
  18. package/dist/ai-writing-OJ5m_1EB.js.map +1 -0
  19. package/dist/{index-BqMXWuNC.d.cts → index--U7hHV0s.d.cts} +2 -2
  20. package/dist/{index-BqMXWuNC.d.cts.map → index--U7hHV0s.d.cts.map} +1 -1
  21. package/dist/{index-B54baFUA.d.ts → index-CFRgZLhH.d.cts} +45 -12
  22. package/dist/index-CFRgZLhH.d.cts.map +1 -0
  23. package/dist/{index-CVWvymVb.d.ts → index-DeD8EI1D.d.ts} +327 -3
  24. package/dist/index-DeD8EI1D.d.ts.map +1 -0
  25. package/dist/{index-CcHDTxIZ.d.ts → index-Dj92T76o.d.ts} +2 -2
  26. package/dist/{index-CcHDTxIZ.d.ts.map → index-Dj92T76o.d.ts.map} +1 -1
  27. package/dist/{index-BAfEHCnD.d.cts → index-Uh1u57yq.d.cts} +327 -3
  28. package/dist/index-Uh1u57yq.d.cts.map +1 -0
  29. package/dist/{index-2nigSf4N.d.cts → index-WBHSrIUU.d.ts} +45 -12
  30. package/dist/index-WBHSrIUU.d.ts.map +1 -0
  31. package/dist/index.cjs +88 -131
  32. package/dist/index.cjs.map +1 -1
  33. package/dist/index.d.cts +217 -95
  34. package/dist/index.d.cts.map +1 -1
  35. package/dist/index.d.ts +217 -95
  36. package/dist/index.d.ts.map +1 -1
  37. package/dist/index.js +60 -118
  38. package/dist/index.js.map +1 -1
  39. package/dist/{item-group-DXiR8nOr.js → item-group-BbvvH_Ob.js} +3 -2
  40. package/dist/item-group-BbvvH_Ob.js.map +1 -0
  41. package/dist/{item-group-DroFXgLb.cjs → item-group-CQRbb8Rx.cjs} +3 -2
  42. package/dist/item-group-CQRbb8Rx.cjs.map +1 -0
  43. package/dist/{registry-Dsx9mNsS.js → registry-B23o9UWh.js} +218 -21
  44. package/dist/registry-B23o9UWh.js.map +1 -0
  45. package/dist/{registry-DVi0LR_i.cjs → registry-Ih5n4PVZ.cjs} +265 -20
  46. package/dist/registry-Ih5n4PVZ.cjs.map +1 -0
  47. package/dist/{schemas-DVbAOrtd.cjs → schemas-Q2dyOgc2.cjs} +77 -14
  48. package/dist/schemas-Q2dyOgc2.cjs.map +1 -0
  49. package/dist/{schemas-Bdw0nGPo.js → schemas-yId-bJhD.js} +72 -15
  50. package/dist/schemas-yId-bJhD.js.map +1 -0
  51. package/dist/schemas.cjs +5 -2
  52. package/dist/schemas.d.cts +2 -2
  53. package/dist/schemas.d.ts +2 -2
  54. package/dist/schemas.js +4 -3
  55. package/dist/{scoring-BZqUkuDF.js → scoring-CLMdk8i9.js} +657 -3
  56. package/dist/scoring-CLMdk8i9.js.map +1 -0
  57. package/dist/{scoring-B2_HEhMT.cjs → scoring-CaPS6q8b.cjs} +722 -2
  58. package/dist/scoring-CaPS6q8b.cjs.map +1 -0
  59. package/dist/scoring.cjs +8 -2
  60. package/dist/scoring.d.cts +3 -3
  61. package/dist/scoring.d.ts +3 -3
  62. package/dist/scoring.js +3 -3
  63. package/dist/{xapi-DNzkSJ0S.cjs → xapi-BX0hvRRB.cjs} +2 -2
  64. package/dist/{xapi-DNzkSJ0S.cjs.map → xapi-BX0hvRRB.cjs.map} +1 -1
  65. package/dist/{xapi-CMTph7wG.js → xapi-Cdk9fTvV.js} +2 -2
  66. package/dist/{xapi-CMTph7wG.js.map → xapi-Cdk9fTvV.js.map} +1 -1
  67. package/dist/xapi.cjs +1 -1
  68. package/dist/xapi.d.cts +1 -1
  69. package/dist/xapi.d.ts +1 -1
  70. package/dist/xapi.js +1 -2
  71. package/package.json +2 -2
  72. package/vectors/README.md +24 -1
  73. package/vectors/scoring.json +18182 -1
  74. package/dist/ai-CnmLPMzd.d.cts.map +0 -1
  75. package/dist/ai-CnmLPMzd.d.ts.map +0 -1
  76. package/dist/ai-writing-CPpH9Qxq.js.map +0 -1
  77. package/dist/ai-writing-G6tnCGzw.cjs.map +0 -1
  78. package/dist/index-2nigSf4N.d.cts.map +0 -1
  79. package/dist/index-B54baFUA.d.ts.map +0 -1
  80. package/dist/index-BAfEHCnD.d.cts.map +0 -1
  81. package/dist/index-CVWvymVb.d.ts.map +0 -1
  82. package/dist/item-group-DXiR8nOr.js.map +0 -1
  83. package/dist/item-group-DroFXgLb.cjs.map +0 -1
  84. package/dist/registry-DVi0LR_i.cjs.map +0 -1
  85. package/dist/registry-Dsx9mNsS.js.map +0 -1
  86. package/dist/schemas-Bdw0nGPo.js.map +0 -1
  87. package/dist/schemas-DVbAOrtd.cjs.map +0 -1
  88. package/dist/scoring-B2_HEhMT.cjs.map +0 -1
  89. package/dist/scoring-BZqUkuDF.js.map +0 -1
package/dist/index.js CHANGED
@@ -1,81 +1,9 @@
1
- import { A as AI_TEXT_MAX_LENGTH, B as readAiTextResult, C as validateItemGroupDraft, D as checkAiCoaching, E as aiCoachingRequest, F as aiSupports, I as buildAiFacts, L as checkAiExplanation, M as aiExplanationRequest, N as aiGradeOf, O as AI_EXPLANATION_TYPES, P as aiHintRequest, R as checkAiHint, S as critiqueItemGroupDraft, T as AI_COACHING_MAX_WORDS, V as AI_MATERIAL_MAX_LENGTH, _ as critiqueDraft, a as AI_DRAFTS_MAX_COUNT, b as createItemGroupDraft, c as aiDraftsRequest, d as interactiveVideoFromDrafts, f as AI_CRITIQUE_MAX_FIELD_LENGTH, g as createDraft, h as checkAiCritique, i as checkAiWritingFeedback, j as aiAllowedByContent, k as AI_HINT_TYPES, l as checkAiDrafts, m as aiCritiqueRequest, n as AI_WRITING_MAX_FIELD_LENGTH, o as AI_DRAFTS_MAX_REPAIRS, p as AI_CRITIQUE_MAX_FINDINGS, r as aiWritingFeedbackRequest, s as aiDraftsRepairRequest, t as AI_WRITING_MAX_CORRECTIONS, u as generateDrafts, v as validateDraft, w as AI_COACHING_MAX_TIP_LENGTH, x as critiqueDrafts, y as createInteractiveVideoDraft, z as hintRevealsAnswer } from "./ai-writing-CPpH9Qxq.js";
2
- import { $ as dictationReferenceWords, A as matchText, J as RedactedScoringError, K as ActivitySchemaError, S as READ_ALOUD_MAX_TAKES, Y as UnknownActivityTypeError, Z as alignDictation, a as readSchema, b as READ_ALOUD_MAX_REFERENCE_LENGTH, c as dictationType, ct as BUILT_IN_ACTIVITY_TYPES, d as multipleChoiceType, et as DICTATION_MAX_ACCEPTED_TRANSCRIPTS, f as readAloudType, it as DICTATION_MAX_TRANSCRIPT_LENGTH, j as countWords, k as levenshteinDistance, l as fillInTheBlanksType, m as defineActivityType, n as registerActivityType, nt as DICTATION_MAX_EQUIVALENCE_LENGTH, p as writtenResponseType, q as DeferredScoringError, r as registeredActivityTypes, rt as DICTATION_MAX_TEXT_LENGTH, s as MEDIA_FIELD_POLICY, t as getActivityTypeDescriptor, tt as DICTATION_MAX_EQUIVALENCES, u as gapSelectType, ut as isBuiltInActivityType, w as SPEECH_ASSESSMENT_MAX_WORDS, x as READ_ALOUD_MAX_SECONDS, y as READ_ALOUD_MAX_DIMENSION_WEIGHT } from "./registry-Dsx9mNsS.js";
3
- import { C as validateItemScoringPolicy, S as scoreTries, _ as gte, a as inspectWav, b as ITEM_SCORING_MAX_RETRIES, c as validateSpeechAssessment, d as gradeFromRubric, f as hasGrade, g as classifyBand, h as computePassThreshold, i as outcomeFromUnscorable, l as diffDictationChars, m as DEFAULT_PASS_THRESHOLD, n as evaluateTries, o as gradeReadAloud, p as outcomeFromGrade, r as score, s as alignReadAloud, t as evaluate, u as composeAssessmentScore, v as roundGrade, x as resolveItemScoringPolicy, y as DEFAULT_ITEM_SCORING_POLICY } from "./scoring-BZqUkuDF.js";
4
- import { a as INTERACTIVE_VIDEO_ITEM_TYPES, c as TIMELINE_MAX_QUIZZES, i as validateItemGroup, l as TIMELINE_MAX_TITLE_LENGTH, n as RedactedItemGroupSchema, o as TIMELINE_MAX_CHAPTERS, s as TIMELINE_MAX_ITEMS, u as isInteractiveVideoItemType } from "./item-group-DXiR8nOr.js";
5
- import { a as fillInTheBlanksJsonSchema, c as jsonSchemaFor, d as stimulusJsonSchema, f as writtenResponseJsonSchema, i as dictationJsonSchema, l as multipleChoiceJsonSchema, n as validateMedia, o as gapSelectJsonSchema, r as validateOptionMedia, s as itemGroupJsonSchema, t as validateActivity, u as readAloudJsonSchema } from "./schemas-Bdw0nGPo.js";
6
- import { a as validateXAPIStatement, i as XAPI_VERB_DISPLAY, n as xapiDefinitionFor, r as XAPIVerb, t as xAPIBuilder } from "./xapi-CMTph7wG.js";
7
- //#region src/content-hash.ts
8
- /**
9
- * Content fingerprinting — "is this the same content the learner was served?"
10
- *
11
- * A recorded attempt outlives the content it was taken against. Papers get
12
- * corrected, a typo is fixed, an option is reworded — and six months later a
13
- * remark, an appeal, or a per-item analysis is run against content that is no
14
- * longer what the learner saw. Nothing warns anybody, because the ids all still
15
- * match. A fingerprint stored with the attempt turns that silent drift into a
16
- * question somebody can answer.
17
- */
18
- /**
19
- * Deterministic JSON: object keys sorted, arrays left in order, `undefined`
20
- * omitted from objects (matching `JSON.stringify`) and rendered as `null`
21
- * inside arrays.
22
- *
23
- * Key order is the whole point. Two objects that differ only in the order
24
- * their keys happened to be written are the SAME content, and a fingerprint
25
- * that disagreed would raise a false alarm every time a payload made a
26
- * round-trip through a different serializer.
27
- */
28
- function canonicalJson(value, seen = /* @__PURE__ */ new Set()) {
29
- if (value === null) return "null";
30
- if (typeof value === "number") return Number.isFinite(value) ? JSON.stringify(value === 0 ? 0 : value) : `"#${String(value)}"`;
31
- if (typeof value === "string" || typeof value === "boolean") return JSON.stringify(value);
32
- if (typeof value === "bigint") return `"#${value.toString()}n"`;
33
- if (typeof value === "object") {
34
- if (seen.has(value)) throw new Error("canonicalJson: the value contains a circular reference and cannot be fingerprinted.");
35
- seen.add(value);
36
- try {
37
- if (Array.isArray(value)) return `[${value.map((element) => element === void 0 ? "null" : canonicalJson(element, seen)).join(",")}]`;
38
- const source = value;
39
- const parts = [];
40
- for (const key of Object.keys(source).sort()) {
41
- const entry = source[key];
42
- if (entry === void 0) continue;
43
- parts.push(`${JSON.stringify(key)}:${canonicalJson(entry, seen)}`);
44
- }
45
- return `{${parts.join(",")}}`;
46
- } finally {
47
- seen.delete(value);
48
- }
49
- }
50
- return "null";
51
- }
52
- const FNV_OFFSET = 14695981039346656037n;
53
- const FNV_PRIME = 1099511628211n;
54
- const MASK64 = (1n << 64n) - 1n;
55
- /**
56
- * FNV-1a over the UTF-8 bytes of `input`, as 16 lowercase hex digits.
57
- *
58
- * **This is a change-detection fingerprint, not a tamper-evident signature.**
59
- * It is deterministic across runtimes and dependency-free, which is what makes
60
- * it usable in a stored grade record — but an adversary who can edit content
61
- * can also, with effort, preserve the fingerprint. If you need the stronger
62
- * property, sign the plan with a key the content author does not hold; this
63
- * exists to catch honest edits, which is what actually happens.
64
- */
65
- function fingerprint(input) {
66
- const bytes = new TextEncoder().encode(input);
67
- let hash = FNV_OFFSET;
68
- for (const byte of bytes) hash = (hash ^ BigInt(byte)) * FNV_PRIME & MASK64;
69
- return hash.toString(16).padStart(16, "0");
70
- }
71
- /**
72
- * Fingerprints any JSON-serialisable value through {@link canonicalJson}, so
73
- * the result depends on the content and not on how it was written.
74
- */
75
- function contentHash(value) {
76
- return fingerprint(canonicalJson(value));
77
- }
78
- //#endregion
1
+ import { A as AI_COACHING_MAX_TIP_LENGTH, B as aiHintRequest, C as createItemGroupDraft, D as listMediaRefs, E as validateItemGroupDraft, F as AI_HINT_TYPES, G as hintRevealsAnswer, H as buildAiFacts, I as AI_TEXT_MAX_LENGTH, K as readAiTextResult, L as aiAllowedByContent, M as aiCoachingRequest, N as checkAiCoaching, O as mapMediaRefs, P as AI_EXPLANATION_TYPES, R as aiExplanationRequest, S as createInteractiveVideoDraft, T as critiqueItemGroupDraft, U as checkAiExplanation, V as aiSupports, W as checkAiHint, _ as aiCritiqueRequest, a as checkAiGrading, b as critiqueDraft, c as AI_DRAFTS_MAX_COUNT, d as aiDraftsRequest, f as checkAiDrafts, g as AI_CRITIQUE_MAX_FINDINGS, h as AI_CRITIQUE_MAX_FIELD_LENGTH, i as aiGradingRequest, j as AI_COACHING_MAX_WORDS, k as transcriptOf, l as AI_DRAFTS_MAX_REPAIRS, m as interactiveVideoFromDrafts, n as checkAiWritingFeedback, o as AI_WRITING_MAX_CORRECTIONS, p as generateDrafts, q as AI_MATERIAL_MAX_LENGTH, r as AI_GRADING_PROBABILITY_TOLERANCE, s as AI_WRITING_MAX_FIELD_LENGTH, t as aiWritingFeedbackRequest, u as aiDraftsRepairRequest, v as checkAiCritique, w as critiqueDrafts, x as validateDraft, y as createDraft, z as aiGradeOf } from "./ai-writing-OJ5m_1EB.js";
2
+ import { $ as DeferredScoringError, C as READ_ALOUD_MAX_TAKES, L as countWords, M as matchText, Q as ActivitySchemaError, S as READ_ALOUD_MAX_SECONDS, T as SPEECH_ASSESSMENT_MAX_WORDS, Tt as SCRIPT_MAX_TURNS, a as readSchema, at as dictationReferenceWords, b as READ_ALOUD_MAX_DIMENSION_WEIGHT, c as dictationType, ct as DICTATION_MAX_EQUIVALENCE_LENGTH, d as multipleChoiceType, et as RedactedScoringError, f as readAloudType, gt as isBuiltInActivityType, h as defineActivityType, j as levenshteinDistance, l as fillInTheBlanksType, lt as DICTATION_MAX_TEXT_LENGTH, m as guardOf, mt as BUILT_IN_ACTIVITY_TYPES, n as registerActivityType, ot as DICTATION_MAX_ACCEPTED_TRANSCRIPTS, p as writtenResponseType, r as registeredActivityTypes, rt as alignDictation, s as MEDIA_FIELD_POLICY, st as DICTATION_MAX_EQUIVALENCES, t as getActivityTypeDescriptor, tt as UnknownActivityTypeError, u as gapSelectType, ut as DICTATION_MAX_TRANSCRIPT_LENGTH, x as READ_ALOUD_MAX_REFERENCE_LENGTH } from "./registry-B23o9UWh.js";
3
+ import { A as DEFAULT_ITEM_SCORING_POLICY, C as contentHash, D as classifyBand, E as computePassThreshold, M as resolveItemScoringPolicy, N as scoreTries, O as gte, P as validateItemScoringPolicy, S as canonicalJson, T as DEFAULT_PASS_THRESHOLD, _ as gradeFromRubric, a as inspectWav, b as calibrationReport, c as validateSpeechAssessment, d as inAuditSample, f as outcomeFromRoutedGrade, g as gradeFromJudgement, h as seededShuffle, i as outcomeFromUnscorable, j as ITEM_SCORING_MAX_RETRIES, k as roundGrade, l as diffDictationChars, m as hashSeed, n as evaluateTries, o as gradeReadAloud, p as routeGrade, r as score, s as alignReadAloud, t as evaluate, u as composeAssessmentScore, v as hasGrade, w as fingerprint, x as graderConfiguration, y as outcomeFromGrade } from "./scoring-CLMdk8i9.js";
4
+ import { a as INTERACTIVE_VIDEO_ITEM_TYPES, c as TIMELINE_MAX_QUIZZES, i as validateItemGroup, l as TIMELINE_MAX_TITLE_LENGTH, n as RedactedItemGroupSchema, o as TIMELINE_MAX_CHAPTERS, s as TIMELINE_MAX_ITEMS, u as isInteractiveVideoItemType } from "./item-group-BbvvH_Ob.js";
5
+ 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-yId-bJhD.js";
6
+ import { a as validateXAPIStatement, i as XAPI_VERB_DISPLAY, n as xapiDefinitionFor, r as XAPIVerb, t as xAPIBuilder } from "./xapi-Cdk9fTvV.js";
79
7
  //#region src/delivery.ts
80
8
  /**
81
9
  * The policy that restricts nothing: every setting `true`. It is what an absent
@@ -231,44 +159,6 @@ function validateDeliveryPolicy(policy) {
231
159
  };
232
160
  }
233
161
  //#endregion
234
- //#region src/shuffle.ts
235
- /**
236
- * Seeded, deterministic shuffling — the ONE algorithm every presentation-order
237
- * decision in the SDK goes through: option order in a multiple-choice item,
238
- * item order inside an item group, entry order in a sequence. A server and a
239
- * client holding the same seed derive the same order, and an order recorded
240
- * against an attempt can be rebuilt later from nothing but its seed.
241
- *
242
- * STABILITY: the hash and the generator are part of the wire contract. A
243
- * stored attempt may hold only a seed and rely on this function to reproduce
244
- * the order it presented; changing either would silently re-order every
245
- * recorded attempt. Any change here is a package major, and the pinned
246
- * permutation test exists so an accidental one fails loudly.
247
- */
248
- /** FNV-1a hash of a string → unsigned 32-bit integer. */
249
- function hashSeed(input) {
250
- let h = 2166136261;
251
- for (let i = 0; i < input.length; i += 1) {
252
- h ^= input.charCodeAt(i);
253
- h = Math.imul(h, 16777619) >>> 0;
254
- }
255
- return h;
256
- }
257
- /** LCG-driven Fisher–Yates over a 32-bit seed; returns a permutation (no loss, no duplicate). */
258
- function shuffleWithSeed(items, seed, version) {
259
- const out = [...items];
260
- let s = seed >>> 0 || 1;
261
- for (let i = out.length - 1; i > 0; i -= 1) {
262
- s = Math.imul(s, 1664525) + 1013904223 >>> 0;
263
- const j = version === 2 ? Math.floor(s / 4294967296 * (i + 1)) : s % (i + 1);
264
- [out[i], out[j]] = [out[j], out[i]];
265
- }
266
- return out;
267
- }
268
- function seededShuffle(items, seed, options = {}) {
269
- return shuffleWithSeed(items, hashSeed(seed), options.version ?? 1);
270
- }
271
- //#endregion
272
162
  //#region src/item-group.ts
273
163
  /** Narrows a sequence entry to an item group. */
274
164
  function isItemGroup(entry) {
@@ -924,6 +814,8 @@ function redactValue(value, policy, reveal) {
924
814
  if (keepField(classification, reveal)) output[key] = fieldValue;
925
815
  continue;
926
816
  }
817
+ const guard = guardOf(classification);
818
+ if (guard !== void 0 && !guard(fieldValue)) continue;
927
819
  const nested = redactValue(fieldValue, classification, reveal);
928
820
  if (nested !== void 0 && !isEmptyObject(nested)) output[key] = nested;
929
821
  }
@@ -1014,7 +906,8 @@ const ITEM_GROUP_FIELD_POLICY = {
1014
906
  media: MEDIA_FIELD_POLICY,
1015
907
  locale: "public",
1016
908
  attribution: "public",
1017
- transcript: "author-only"
909
+ transcript: "author-only",
910
+ script: "author-only"
1018
911
  },
1019
912
  timeline: {
1020
913
  cues: {
@@ -1101,6 +994,55 @@ function assertRedactedItemGroup(data) {
1101
994
  }
1102
995
  });
1103
996
  }
997
+ /** A deep copy of plain data with every field its policy calls `author-only` left out. */
998
+ function withoutAuthorOnlyValue(value, policy) {
999
+ if (Array.isArray(value)) return value.map((element) => withoutAuthorOnlyValue(element, policy));
1000
+ if (value === null || typeof value !== "object") return value;
1001
+ const output = {};
1002
+ for (const [key, field] of Object.entries(value)) {
1003
+ const classification = policy?.[key];
1004
+ if (classification === "author-only") continue;
1005
+ output[key] = withoutAuthorOnlyValue(field, classification === void 0 || isSensitivity(classification) ? void 0 : classification);
1006
+ }
1007
+ return output;
1008
+ }
1009
+ /** The policy an activity is stripped under; the same one `redact()` reads. */
1010
+ function policyOf(type) {
1011
+ const descriptor = typeof type === "string" ? getActivityTypeDescriptor(type) : void 0;
1012
+ if (descriptor === void 0) throw new UnknownActivityTypeError(String(type));
1013
+ if (descriptor.fieldPolicy === void 0) throw new Error(`Activity type "${descriptor.type}" has no fieldPolicy; withoutAuthorOnly() cannot tell which of its fields are author-only.`);
1014
+ return descriptor.fieldPolicy;
1015
+ }
1016
+ /**
1017
+ * A copy of an activity or an item group without its `author-only` fields:
1018
+ * a recording's `transcript` and `script`, on an item's media, a
1019
+ * multiple-choice option's recording, a stimulus or its media. Everything
1020
+ * else is kept as stored, the answer key and your own fields included, and
1021
+ * the copy is not marked redacted, so it scores exactly as the stored item.
1022
+ *
1023
+ * For practice an app scores in the browser, where the learner may hold the
1024
+ * key but not the author's material. It is NOT a learner-safe projection: an
1025
+ * exam, or anything a learner must not be able to answer from the payload,
1026
+ * goes through {@link redact} / {@link redactItemGroup}, whose output a scorer
1027
+ * refuses.
1028
+ *
1029
+ * ```ts
1030
+ * res.json(withoutAuthorOnly(practiceItem));
1031
+ * ```
1032
+ *
1033
+ * @throws UnknownActivityTypeError when an activity's type is not registered,
1034
+ * and Error when it declares no `fieldPolicy`.
1035
+ */
1036
+ function withoutAuthorOnly(entry) {
1037
+ if (typeof entry !== "object" || entry === null || Array.isArray(entry)) throw new TypeError("withoutAuthorOnly: expects an activity or an item group.");
1038
+ const record = entry;
1039
+ if (record.type !== "item-group") return withoutAuthorOnlyValue(entry, policyOf(record.type));
1040
+ const { items, ...container } = record;
1041
+ return {
1042
+ ...withoutAuthorOnlyValue(container, ITEM_GROUP_FIELD_POLICY),
1043
+ ...Array.isArray(items) ? { items: items.map((item) => withoutAuthorOnlyValue(item, policyOf(item?.type))) } : items !== void 0 ? { items } : {}
1044
+ };
1045
+ }
1104
1046
  //#endregion
1105
1047
  //#region src/timeline.ts
1106
1048
  /**
@@ -1157,6 +1099,6 @@ function composeTimelineScore(entryKey, items, policy) {
1157
1099
  }], policy);
1158
1100
  }
1159
1101
  //#endregion
1160
- export { AI_COACHING_MAX_TIP_LENGTH, AI_COACHING_MAX_WORDS, AI_CRITIQUE_MAX_FIELD_LENGTH, AI_CRITIQUE_MAX_FINDINGS, AI_DRAFTS_MAX_COUNT, AI_DRAFTS_MAX_REPAIRS, AI_EXPLANATION_TYPES, AI_HINT_TYPES, AI_MATERIAL_MAX_LENGTH, AI_TEXT_MAX_LENGTH, AI_WRITING_MAX_CORRECTIONS, AI_WRITING_MAX_FIELD_LENGTH, ActivitySchemaError, BUILT_IN_ACTIVITY_TYPES, DEFAULT_ITEM_SCORING_POLICY, DEFAULT_PASS_THRESHOLD, DICTATION_MAX_ACCEPTED_TRANSCRIPTS, DICTATION_MAX_EQUIVALENCES, DICTATION_MAX_EQUIVALENCE_LENGTH, DICTATION_MAX_TEXT_LENGTH, DICTATION_MAX_TRANSCRIPT_LENGTH, DeferredScoringError, INTERACTIVE_VIDEO_ITEM_TYPES, ITEM_SCORING_MAX_RETRIES, OPEN_DELIVERY_POLICY, READ_ALOUD_MAX_DIMENSION_WEIGHT, READ_ALOUD_MAX_REFERENCE_LENGTH, READ_ALOUD_MAX_SECONDS, READ_ALOUD_MAX_TAKES, RedactedScoringError, SPEECH_ASSESSMENT_MAX_WORDS, TIMELINE_MAX_CHAPTERS, TIMELINE_MAX_ITEMS, TIMELINE_MAX_QUIZZES, TIMELINE_MAX_TITLE_LENGTH, UnknownActivityTypeError, XAPIVerb, XAPI_VERB_DISPLAY, aiAllowedByContent, aiCoachingRequest, aiCritiqueRequest, aiDraftsRepairRequest, aiDraftsRequest, aiExplanationRequest, aiGradeOf, aiHintRequest, aiSupports, aiWritingFeedbackRequest, alignDictation, alignReadAloud, assertRedacted, assertRedactedItemGroup, buildAiFacts, canonicalJson, checkAiCoaching, checkAiCritique, checkAiDrafts, checkAiExplanation, checkAiHint, checkAiWritingFeedback, classifyBand, combineDeliveryPolicies, composeAssessmentScore, composeTimelineScore, computePassThreshold, contentHash, countWords, createDraft, createInteractiveVideoDraft, createItemGroupDraft, critiqueDraft, critiqueDrafts, critiqueItemGroupDraft, defineActivityType, dictationJsonSchema, dictationReferenceWords, dictationType, diffDictationChars, diffResponses, entryKeyOf, evaluate, evaluateTries, fillInTheBlanksJsonSchema, fillInTheBlanksType, fingerprint, flattenSequence, gapSelectJsonSchema, gapSelectType, generateDrafts, getActivityTypeDescriptor, gradeFromRubric, gradeReadAloud, gte, hasGrade, hashSeed, hintRevealsAnswer, inspectWav, interactiveVideoFromDrafts, isBuiltInActivityType, isInteractiveVideoItemType, isItemGroup, itemGroupJsonSchema, jsonSchemaFor, levenshteinDistance, matchText, multipleChoiceJsonSchema, multipleChoiceType, outcomeFromGrade, outcomeFromUnscorable, planAttempt, planMediaBudgets, readAiTextResult, readAloudJsonSchema, readAloudType, readMediaProgress, redact, redactItemGroup, registerActivityType, registeredActivityTypes, resolveDeliveryPolicy, resolveItemScoringPolicy, resolvePlaybackPolicy, restoreAttemptState, restoreMediaPlayLedger, roundGrade, score, scoreTries, scoredItemsFromPlan, seededShuffle, serializeAttemptState, serializeMediaPlayLedger, slotMediaKey, stimulusJsonSchema, stimulusMediaKey, validateActivity, validateDeliveryPolicy, validateDraft, validateItemGroup, validateItemGroupDraft, validateItemScoringPolicy, validateMedia, validateOptionMedia, validateSpeechAssessment, validateXAPIStatement, verifyAttemptPlan, writtenResponseJsonSchema, writtenResponseType, xAPIBuilder, xapiDefinitionFor };
1102
+ export { AI_COACHING_MAX_TIP_LENGTH, AI_COACHING_MAX_WORDS, AI_CRITIQUE_MAX_FIELD_LENGTH, AI_CRITIQUE_MAX_FINDINGS, AI_DRAFTS_MAX_COUNT, AI_DRAFTS_MAX_REPAIRS, AI_EXPLANATION_TYPES, AI_GRADING_PROBABILITY_TOLERANCE, AI_HINT_TYPES, AI_MATERIAL_MAX_LENGTH, AI_TEXT_MAX_LENGTH, AI_WRITING_MAX_CORRECTIONS, AI_WRITING_MAX_FIELD_LENGTH, ActivitySchemaError, BUILT_IN_ACTIVITY_TYPES, DEFAULT_ITEM_SCORING_POLICY, DEFAULT_PASS_THRESHOLD, DICTATION_MAX_ACCEPTED_TRANSCRIPTS, DICTATION_MAX_EQUIVALENCES, DICTATION_MAX_EQUIVALENCE_LENGTH, DICTATION_MAX_TEXT_LENGTH, DICTATION_MAX_TRANSCRIPT_LENGTH, DeferredScoringError, INTERACTIVE_VIDEO_ITEM_TYPES, ITEM_SCORING_MAX_RETRIES, OPEN_DELIVERY_POLICY, READ_ALOUD_MAX_DIMENSION_WEIGHT, READ_ALOUD_MAX_REFERENCE_LENGTH, READ_ALOUD_MAX_SECONDS, READ_ALOUD_MAX_TAKES, RedactedScoringError, SCRIPT_MAX_TURNS, SPEECH_ASSESSMENT_MAX_WORDS, TIMELINE_MAX_CHAPTERS, TIMELINE_MAX_ITEMS, TIMELINE_MAX_QUIZZES, TIMELINE_MAX_TITLE_LENGTH, UnknownActivityTypeError, XAPIVerb, XAPI_VERB_DISPLAY, aiAllowedByContent, aiCoachingRequest, aiCritiqueRequest, aiDraftsRepairRequest, aiDraftsRequest, aiExplanationRequest, aiGradeOf, aiGradingRequest, aiHintRequest, aiSupports, aiWritingFeedbackRequest, alignDictation, alignReadAloud, assertRedacted, assertRedactedItemGroup, buildAiFacts, calibrationReport, canonicalJson, checkAiCoaching, checkAiCritique, checkAiDrafts, checkAiExplanation, checkAiGrading, checkAiHint, checkAiWritingFeedback, classifyBand, combineDeliveryPolicies, composeAssessmentScore, composeTimelineScore, computePassThreshold, contentHash, contentJsonSchema, countWords, createDraft, createInteractiveVideoDraft, createItemGroupDraft, critiqueDraft, critiqueDrafts, critiqueItemGroupDraft, defineActivityType, dictationJsonSchema, dictationReferenceWords, dictationType, diffDictationChars, diffResponses, entryKeyOf, evaluate, evaluateTries, fillInTheBlanksJsonSchema, fillInTheBlanksType, fingerprint, flattenSequence, gapSelectJsonSchema, gapSelectType, generateDrafts, getActivityTypeDescriptor, gradeFromJudgement, gradeFromRubric, gradeReadAloud, graderConfiguration, gte, hasGrade, hashSeed, hintRevealsAnswer, inAuditSample, inspectWav, interactiveVideoFromDrafts, isBuiltInActivityType, isInteractiveVideoItemType, isItemGroup, itemGroupJsonSchema, jsonSchemaFor, levenshteinDistance, listMediaRefs, mapMediaRefs, matchText, multipleChoiceJsonSchema, multipleChoiceType, outcomeFromGrade, outcomeFromRoutedGrade, outcomeFromUnscorable, planAttempt, planMediaBudgets, readAiTextResult, readAloudJsonSchema, readAloudType, readMediaProgress, redact, redactItemGroup, registerActivityType, registeredActivityTypes, resolveDeliveryPolicy, resolveItemScoringPolicy, resolvePlaybackPolicy, restoreAttemptState, restoreMediaPlayLedger, roundGrade, routeGrade, score, scoreTries, scoredItemsFromPlan, seededShuffle, serializeAttemptState, serializeMediaPlayLedger, slotMediaKey, stimulusJsonSchema, stimulusMediaKey, transcriptOf, validateActivity, validateDeliveryPolicy, validateDraft, validateItemGroup, validateItemGroupDraft, validateItemScoringPolicy, validateMedia, validateOptionMedia, validateSpeechAssessment, validateXAPIStatement, verifyAttemptPlan, withoutAuthorOnly, writtenResponseJsonSchema, writtenResponseType, xAPIBuilder, xapiDefinitionFor };
1161
1103
 
1162
1104
  //# sourceMappingURL=index.js.map