@intellectif/lk-core 1.7.0 → 1.8.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 +16 -0
  2. package/dist/{ai-B1wYrqcB.d.cts → ai-Cnm0qE8v.d.cts} +296 -2
  3. package/dist/ai-Cnm0qE8v.d.cts.map +1 -0
  4. package/dist/{ai-B1wYrqcB.d.ts → ai-Cnm0qE8v.d.ts} +296 -2
  5. package/dist/ai-Cnm0qE8v.d.ts.map +1 -0
  6. package/dist/ai-check.cjs +77 -3
  7. package/dist/ai-check.cjs.map +1 -1
  8. package/dist/ai-check.d.cts +11 -3
  9. package/dist/ai-check.d.cts.map +1 -1
  10. package/dist/ai-check.d.ts +11 -3
  11. package/dist/ai-check.d.ts.map +1 -1
  12. package/dist/ai-check.js +77 -3
  13. package/dist/ai-check.js.map +1 -1
  14. package/dist/{ai-writing-DrPTV3R2.cjs → ai-writing-Bh2Y53cY.cjs} +2539 -178
  15. package/dist/ai-writing-Bh2Y53cY.cjs.map +1 -0
  16. package/dist/{ai-writing-B7oMCt66.js → ai-writing-DeIV-GfN.js} +2389 -136
  17. package/dist/ai-writing-DeIV-GfN.js.map +1 -0
  18. package/dist/{index-BU99GFTl.d.ts → index-CtoPhJAH.d.ts} +2 -2
  19. package/dist/{index-BU99GFTl.d.ts.map → index-CtoPhJAH.d.ts.map} +1 -1
  20. package/dist/{index-XCCoPoTU.d.cts → index-DMh3OYSb.d.cts} +2 -2
  21. package/dist/{index-XCCoPoTU.d.cts.map → index-DMh3OYSb.d.cts.map} +1 -1
  22. package/dist/{index-BdXs4-en.d.ts → index-HXvg0YRQ.d.ts} +2 -2
  23. package/dist/{index-BdXs4-en.d.ts.map → index-HXvg0YRQ.d.ts.map} +1 -1
  24. package/dist/{index-DP9rvyOz.d.cts → index-fZ67k-WR.d.cts} +2 -2
  25. package/dist/{index-DP9rvyOz.d.cts.map → index-fZ67k-WR.d.cts.map} +1 -1
  26. package/dist/{index-BTkMQtws.d.ts → index-g-EWIugp.d.ts} +2 -2
  27. package/dist/{index-BTkMQtws.d.ts.map → index-g-EWIugp.d.ts.map} +1 -1
  28. package/dist/{index-BM8LeDWn.d.cts → index-oST8GBFa.d.cts} +2 -2
  29. package/dist/{index-BM8LeDWn.d.cts.map → index-oST8GBFa.d.cts.map} +1 -1
  30. package/dist/index.cjs +280 -6
  31. package/dist/index.cjs.map +1 -1
  32. package/dist/index.d.cts +227 -5
  33. package/dist/index.d.cts.map +1 -1
  34. package/dist/index.d.ts +227 -5
  35. package/dist/index.d.ts.map +1 -1
  36. package/dist/index.js +269 -7
  37. package/dist/index.js.map +1 -1
  38. package/dist/{item-group-CeDk7mfM.js → item-group-BceUoxoM.js} +2 -2
  39. package/dist/{item-group-CeDk7mfM.js.map → item-group-BceUoxoM.js.map} +1 -1
  40. package/dist/{item-group-8P3WFuUK.cjs → item-group-KV4hYu3a.cjs} +2 -2
  41. package/dist/{item-group-8P3WFuUK.cjs.map → item-group-KV4hYu3a.cjs.map} +1 -1
  42. package/dist/{registry-hzrkTeIT.cjs → registry-Cymq7Ah0.cjs} +37 -2
  43. package/dist/registry-Cymq7Ah0.cjs.map +1 -0
  44. package/dist/{registry-D92hz9iA.js → registry-tkacvJUI.js} +20 -3
  45. package/dist/registry-tkacvJUI.js.map +1 -0
  46. package/dist/{schemas-C7TViWCg.js → schemas-DM8sN_f0.js} +3 -3
  47. package/dist/{schemas-C7TViWCg.js.map → schemas-DM8sN_f0.js.map} +1 -1
  48. package/dist/{schemas-BWeskONy.cjs → schemas-wDzbKdKa.cjs} +3 -3
  49. package/dist/{schemas-BWeskONy.cjs.map → schemas-wDzbKdKa.cjs.map} +1 -1
  50. package/dist/schemas.cjs +3 -3
  51. package/dist/schemas.d.cts +1 -1
  52. package/dist/schemas.d.ts +1 -1
  53. package/dist/schemas.js +3 -3
  54. package/dist/{scoring-CtkCFyFT.cjs → scoring-D9tFvPEG.cjs} +2 -2
  55. package/dist/{scoring-CtkCFyFT.cjs.map → scoring-D9tFvPEG.cjs.map} +1 -1
  56. package/dist/{scoring-DD1GHcLI.js → scoring-DIBmo_cy.js} +2 -2
  57. package/dist/{scoring-DD1GHcLI.js.map → scoring-DIBmo_cy.js.map} +1 -1
  58. package/dist/scoring.cjs +2 -2
  59. package/dist/scoring.d.cts +2 -2
  60. package/dist/scoring.d.ts +2 -2
  61. package/dist/scoring.js +2 -2
  62. package/dist/{xapi-7btSpx6v.cjs → xapi-Dyqcl3JK.cjs} +2 -2
  63. package/dist/{xapi-7btSpx6v.cjs.map → xapi-Dyqcl3JK.cjs.map} +1 -1
  64. package/dist/{xapi-Cgicg-zU.js → xapi-gCAo549Q.js} +2 -2
  65. package/dist/{xapi-Cgicg-zU.js.map → xapi-gCAo549Q.js.map} +1 -1
  66. package/dist/xapi.cjs +1 -1
  67. package/dist/xapi.d.cts +1 -1
  68. package/dist/xapi.d.ts +1 -1
  69. package/dist/xapi.js +1 -1
  70. package/package.json +2 -2
  71. package/vectors/README.md +23 -0
  72. package/vectors/variants.d.mts +20 -0
  73. package/vectors/variants.json +5753 -0
  74. package/vectors/variants.mjs +67 -0
  75. package/dist/ai-B1wYrqcB.d.cts.map +0 -1
  76. package/dist/ai-B1wYrqcB.d.ts.map +0 -1
  77. package/dist/ai-writing-B7oMCt66.js.map +0 -1
  78. package/dist/ai-writing-DrPTV3R2.cjs.map +0 -1
  79. package/dist/registry-D92hz9iA.js.map +0 -1
  80. package/dist/registry-hzrkTeIT.cjs.map +0 -1
package/dist/scoring.cjs CHANGED
@@ -1,6 +1,6 @@
1
1
  Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
2
- const require_registry = require("./registry-hzrkTeIT.cjs");
3
- const require_scoring = require("./scoring-CtkCFyFT.cjs");
2
+ const require_registry = require("./registry-Cymq7Ah0.cjs");
3
+ const require_scoring = require("./scoring-D9tFvPEG.cjs");
4
4
  exports.DEFAULT_ITEM_SCORING_POLICY = require_scoring.DEFAULT_ITEM_SCORING_POLICY;
5
5
  exports.DEFAULT_PASS_THRESHOLD = require_scoring.DEFAULT_PASS_THRESHOLD;
6
6
  exports.DICTATION_MAX_ACCEPTED_TRANSCRIPTS = require_registry.DICTATION_MAX_ACCEPTED_TRANSCRIPTS;
@@ -1,3 +1,3 @@
1
- import { Gn as matchText, Hn as TextMatchPolicy, Jt as ItemOutcome, Nn as GradeRecord, Un as TextMatchResult, Wn as levenshteinDistance, in as ReadAloudData, sn as ReadAloudLearnerResponse, un as RecordingRef } from "./ai-B1wYrqcB.cjs";
2
- import { A as diffDictationChars, At as Band, B as outcomeFromRoutedGrade, C as validateItemScoringPolicy, Ct as SpeechSyllable, D as DICTATION_MAX_TEXT_LENGTH, Dt as SpeechWordError, E as DICTATION_MAX_EQUIVALENCE_LENGTH, Et as SpeechWord, F as dictationReferenceWords, Ft as roundGrade, G as CalibrationReport, H as GradeFromJudgementOptions, I as CalibrationThresholds, J as TotalCalibration, K as CalibrationScope, L as GradeRoutingContext, M as DictationReference, Mt as RoundingPolicy, N as DictationWordAlignment, Nt as classifyBand, O as DICTATION_MAX_TRANSCRIPT_LENGTH, Ot as WavInspection, P as alignDictation, Pt as gte, R as GradeRoutingPolicy, S as scoreTries, St as SpeechPlausibilityPolicy, T as DICTATION_MAX_EQUIVALENCES, Tt as SpeechUnscorableCode, U as gradeFromJudgement, V as routeGrade, W as CalibrationPair, X as graderConfiguration, Y as calibrationReport, _ as DEFAULT_PASS_THRESHOLD, _t as ReadAloudWordState, a as evaluateTries, at as ItemTry, b as ITEM_SCORING_MAX_RETRIES, bt as SpeechPhoneme, c as inspectWav, ct as AssessmentScore, d as READ_ALOUD_MAX_SECONDS, dt as PassFailureReason, f as READ_ALOUD_MAX_TAKES, ft as ScoredItem, g as alignReadAloud, gt as ReadAloudWordAlignment, h as validateSpeechAssessment, ht as GradeReadAloudOptions, i as evaluate, it as ItemTriesScore, j as DictationAlignment, jt as RoundingMode, k as DictationCharOp, kt as WavInspectionPolicy, l as READ_ALOUD_MAX_DIMENSION_WEIGHT, lt as AssessmentSectionInput, m as gradeReadAloud, mt as composeAssessmentScore, n as ItemTriesOutcome, nt as ItemScoringPolicy, o as score, ot as ItemTryScore, p as SPEECH_ASSESSMENT_MAX_WORDS, pt as SectionScore, q as CriterionCalibration, r as ScoringOptions, rt as ItemScoringPolicyIssue, s as outcomeFromUnscorable, st as ResolvedItemScoringPolicy, t as EvaluateOptions, tt as ItemScoringCount, u as READ_ALOUD_MAX_REFERENCE_LENGTH, ut as CompositionPolicy, v as computePassThreshold, vt as SpeechAssessment, w as DICTATION_MAX_ACCEPTED_TRANSCRIPTS, wt as SpeechUnscorable, x as resolveItemScoringPolicy, xt as SpeechPhonemeCandidate, y as DEFAULT_ITEM_SCORING_POLICY, yt as SpeechMeasurement, z as inAuditSample } from "./index-BM8LeDWn.cjs";
1
+ import { On as RecordingRef, Sn as ReadAloudData, Tn as ReadAloudLearnerResponse, Zn as GradeRecord, cr as levenshteinDistance, fn as ItemOutcome, lr as matchText, or as TextMatchPolicy, sr as TextMatchResult } from "./ai-Cnm0qE8v.cjs";
2
+ import { A as diffDictationChars, At as Band, B as outcomeFromRoutedGrade, C as validateItemScoringPolicy, Ct as SpeechSyllable, D as DICTATION_MAX_TEXT_LENGTH, Dt as SpeechWordError, E as DICTATION_MAX_EQUIVALENCE_LENGTH, Et as SpeechWord, F as dictationReferenceWords, Ft as roundGrade, G as CalibrationReport, H as GradeFromJudgementOptions, I as CalibrationThresholds, J as TotalCalibration, K as CalibrationScope, L as GradeRoutingContext, M as DictationReference, Mt as RoundingPolicy, N as DictationWordAlignment, Nt as classifyBand, O as DICTATION_MAX_TRANSCRIPT_LENGTH, Ot as WavInspection, P as alignDictation, Pt as gte, R as GradeRoutingPolicy, S as scoreTries, St as SpeechPlausibilityPolicy, T as DICTATION_MAX_EQUIVALENCES, Tt as SpeechUnscorableCode, U as gradeFromJudgement, V as routeGrade, W as CalibrationPair, X as graderConfiguration, Y as calibrationReport, _ as DEFAULT_PASS_THRESHOLD, _t as ReadAloudWordState, a as evaluateTries, at as ItemTry, b as ITEM_SCORING_MAX_RETRIES, bt as SpeechPhoneme, c as inspectWav, ct as AssessmentScore, d as READ_ALOUD_MAX_SECONDS, dt as PassFailureReason, f as READ_ALOUD_MAX_TAKES, ft as ScoredItem, g as alignReadAloud, gt as ReadAloudWordAlignment, h as validateSpeechAssessment, ht as GradeReadAloudOptions, i as evaluate, it as ItemTriesScore, j as DictationAlignment, jt as RoundingMode, k as DictationCharOp, kt as WavInspectionPolicy, l as READ_ALOUD_MAX_DIMENSION_WEIGHT, lt as AssessmentSectionInput, m as gradeReadAloud, mt as composeAssessmentScore, n as ItemTriesOutcome, nt as ItemScoringPolicy, o as score, ot as ItemTryScore, p as SPEECH_ASSESSMENT_MAX_WORDS, pt as SectionScore, q as CriterionCalibration, r as ScoringOptions, rt as ItemScoringPolicyIssue, s as outcomeFromUnscorable, st as ResolvedItemScoringPolicy, t as EvaluateOptions, tt as ItemScoringCount, u as READ_ALOUD_MAX_REFERENCE_LENGTH, ut as CompositionPolicy, v as computePassThreshold, vt as SpeechAssessment, w as DICTATION_MAX_ACCEPTED_TRANSCRIPTS, wt as SpeechUnscorable, x as resolveItemScoringPolicy, xt as SpeechPhonemeCandidate, y as DEFAULT_ITEM_SCORING_POLICY, yt as SpeechMeasurement, z as inAuditSample } from "./index-oST8GBFa.cjs";
3
3
  export { type AssessmentScore, type AssessmentSectionInput, type Band, type CalibrationPair, type CalibrationReport, type CalibrationScope, type CalibrationThresholds, type CompositionPolicy, type CriterionCalibration, 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, type DictationAlignment, type DictationCharOp, type DictationReference, type DictationWordAlignment, EvaluateOptions, type GradeFromJudgementOptions, type GradeReadAloudOptions, type GradeRecord, type GradeRoutingContext, type GradeRoutingPolicy, ITEM_SCORING_MAX_RETRIES, type ItemOutcome, type ItemScoringCount, type ItemScoringPolicy, type ItemScoringPolicyIssue, ItemTriesOutcome, type ItemTriesScore, type ItemTry, type ItemTryScore, type PassFailureReason, READ_ALOUD_MAX_DIMENSION_WEIGHT, READ_ALOUD_MAX_REFERENCE_LENGTH, READ_ALOUD_MAX_SECONDS, READ_ALOUD_MAX_TAKES, type ReadAloudData, type ReadAloudLearnerResponse, type ReadAloudWordAlignment, type ReadAloudWordState, type RecordingRef, type ResolvedItemScoringPolicy, type RoundingMode, type RoundingPolicy, SPEECH_ASSESSMENT_MAX_WORDS, type ScoredItem, ScoringOptions, type SectionScore, type SpeechAssessment, type SpeechMeasurement, type SpeechPhoneme, type SpeechPhonemeCandidate, type SpeechPlausibilityPolicy, type SpeechSyllable, type SpeechUnscorable, type SpeechUnscorableCode, type SpeechWord, type SpeechWordError, type TextMatchPolicy, type TextMatchResult, type TotalCalibration, type WavInspection, type WavInspectionPolicy, alignDictation, alignReadAloud, calibrationReport, classifyBand, composeAssessmentScore, computePassThreshold, dictationReferenceWords, diffDictationChars, evaluate, evaluateTries, gradeFromJudgement, gradeReadAloud, graderConfiguration, gte, inAuditSample, inspectWav, levenshteinDistance, matchText, outcomeFromRoutedGrade, outcomeFromUnscorable, resolveItemScoringPolicy, roundGrade, routeGrade, score, scoreTries, validateItemScoringPolicy, validateSpeechAssessment };
package/dist/scoring.d.ts CHANGED
@@ -1,3 +1,3 @@
1
- import { Gn as matchText, Hn as TextMatchPolicy, Jt as ItemOutcome, Nn as GradeRecord, Un as TextMatchResult, Wn as levenshteinDistance, in as ReadAloudData, sn as ReadAloudLearnerResponse, un as RecordingRef } from "./ai-B1wYrqcB.js";
2
- import { A as diffDictationChars, At as Band, B as outcomeFromRoutedGrade, C as validateItemScoringPolicy, Ct as SpeechSyllable, D as DICTATION_MAX_TEXT_LENGTH, Dt as SpeechWordError, E as DICTATION_MAX_EQUIVALENCE_LENGTH, Et as SpeechWord, F as dictationReferenceWords, Ft as roundGrade, G as CalibrationReport, H as GradeFromJudgementOptions, I as CalibrationThresholds, J as TotalCalibration, K as CalibrationScope, L as GradeRoutingContext, M as DictationReference, Mt as RoundingPolicy, N as DictationWordAlignment, Nt as classifyBand, O as DICTATION_MAX_TRANSCRIPT_LENGTH, Ot as WavInspection, P as alignDictation, Pt as gte, R as GradeRoutingPolicy, S as scoreTries, St as SpeechPlausibilityPolicy, T as DICTATION_MAX_EQUIVALENCES, Tt as SpeechUnscorableCode, U as gradeFromJudgement, V as routeGrade, W as CalibrationPair, X as graderConfiguration, Y as calibrationReport, _ as DEFAULT_PASS_THRESHOLD, _t as ReadAloudWordState, a as evaluateTries, at as ItemTry, b as ITEM_SCORING_MAX_RETRIES, bt as SpeechPhoneme, c as inspectWav, ct as AssessmentScore, d as READ_ALOUD_MAX_SECONDS, dt as PassFailureReason, f as READ_ALOUD_MAX_TAKES, ft as ScoredItem, g as alignReadAloud, gt as ReadAloudWordAlignment, h as validateSpeechAssessment, ht as GradeReadAloudOptions, i as evaluate, it as ItemTriesScore, j as DictationAlignment, jt as RoundingMode, k as DictationCharOp, kt as WavInspectionPolicy, l as READ_ALOUD_MAX_DIMENSION_WEIGHT, lt as AssessmentSectionInput, m as gradeReadAloud, mt as composeAssessmentScore, n as ItemTriesOutcome, nt as ItemScoringPolicy, o as score, ot as ItemTryScore, p as SPEECH_ASSESSMENT_MAX_WORDS, pt as SectionScore, q as CriterionCalibration, r as ScoringOptions, rt as ItemScoringPolicyIssue, s as outcomeFromUnscorable, st as ResolvedItemScoringPolicy, t as EvaluateOptions, tt as ItemScoringCount, u as READ_ALOUD_MAX_REFERENCE_LENGTH, ut as CompositionPolicy, v as computePassThreshold, vt as SpeechAssessment, w as DICTATION_MAX_ACCEPTED_TRANSCRIPTS, wt as SpeechUnscorable, x as resolveItemScoringPolicy, xt as SpeechPhonemeCandidate, y as DEFAULT_ITEM_SCORING_POLICY, yt as SpeechMeasurement, z as inAuditSample } from "./index-BTkMQtws.js";
1
+ import { On as RecordingRef, Sn as ReadAloudData, Tn as ReadAloudLearnerResponse, Zn as GradeRecord, cr as levenshteinDistance, fn as ItemOutcome, lr as matchText, or as TextMatchPolicy, sr as TextMatchResult } from "./ai-Cnm0qE8v.js";
2
+ import { A as diffDictationChars, At as Band, B as outcomeFromRoutedGrade, C as validateItemScoringPolicy, Ct as SpeechSyllable, D as DICTATION_MAX_TEXT_LENGTH, Dt as SpeechWordError, E as DICTATION_MAX_EQUIVALENCE_LENGTH, Et as SpeechWord, F as dictationReferenceWords, Ft as roundGrade, G as CalibrationReport, H as GradeFromJudgementOptions, I as CalibrationThresholds, J as TotalCalibration, K as CalibrationScope, L as GradeRoutingContext, M as DictationReference, Mt as RoundingPolicy, N as DictationWordAlignment, Nt as classifyBand, O as DICTATION_MAX_TRANSCRIPT_LENGTH, Ot as WavInspection, P as alignDictation, Pt as gte, R as GradeRoutingPolicy, S as scoreTries, St as SpeechPlausibilityPolicy, T as DICTATION_MAX_EQUIVALENCES, Tt as SpeechUnscorableCode, U as gradeFromJudgement, V as routeGrade, W as CalibrationPair, X as graderConfiguration, Y as calibrationReport, _ as DEFAULT_PASS_THRESHOLD, _t as ReadAloudWordState, a as evaluateTries, at as ItemTry, b as ITEM_SCORING_MAX_RETRIES, bt as SpeechPhoneme, c as inspectWav, ct as AssessmentScore, d as READ_ALOUD_MAX_SECONDS, dt as PassFailureReason, f as READ_ALOUD_MAX_TAKES, ft as ScoredItem, g as alignReadAloud, gt as ReadAloudWordAlignment, h as validateSpeechAssessment, ht as GradeReadAloudOptions, i as evaluate, it as ItemTriesScore, j as DictationAlignment, jt as RoundingMode, k as DictationCharOp, kt as WavInspectionPolicy, l as READ_ALOUD_MAX_DIMENSION_WEIGHT, lt as AssessmentSectionInput, m as gradeReadAloud, mt as composeAssessmentScore, n as ItemTriesOutcome, nt as ItemScoringPolicy, o as score, ot as ItemTryScore, p as SPEECH_ASSESSMENT_MAX_WORDS, pt as SectionScore, q as CriterionCalibration, r as ScoringOptions, rt as ItemScoringPolicyIssue, s as outcomeFromUnscorable, st as ResolvedItemScoringPolicy, t as EvaluateOptions, tt as ItemScoringCount, u as READ_ALOUD_MAX_REFERENCE_LENGTH, ut as CompositionPolicy, v as computePassThreshold, vt as SpeechAssessment, w as DICTATION_MAX_ACCEPTED_TRANSCRIPTS, wt as SpeechUnscorable, x as resolveItemScoringPolicy, xt as SpeechPhonemeCandidate, y as DEFAULT_ITEM_SCORING_POLICY, yt as SpeechMeasurement, z as inAuditSample } from "./index-g-EWIugp.js";
3
3
  export { type AssessmentScore, type AssessmentSectionInput, type Band, type CalibrationPair, type CalibrationReport, type CalibrationScope, type CalibrationThresholds, type CompositionPolicy, type CriterionCalibration, 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, type DictationAlignment, type DictationCharOp, type DictationReference, type DictationWordAlignment, EvaluateOptions, type GradeFromJudgementOptions, type GradeReadAloudOptions, type GradeRecord, type GradeRoutingContext, type GradeRoutingPolicy, ITEM_SCORING_MAX_RETRIES, type ItemOutcome, type ItemScoringCount, type ItemScoringPolicy, type ItemScoringPolicyIssue, ItemTriesOutcome, type ItemTriesScore, type ItemTry, type ItemTryScore, type PassFailureReason, READ_ALOUD_MAX_DIMENSION_WEIGHT, READ_ALOUD_MAX_REFERENCE_LENGTH, READ_ALOUD_MAX_SECONDS, READ_ALOUD_MAX_TAKES, type ReadAloudData, type ReadAloudLearnerResponse, type ReadAloudWordAlignment, type ReadAloudWordState, type RecordingRef, type ResolvedItemScoringPolicy, type RoundingMode, type RoundingPolicy, SPEECH_ASSESSMENT_MAX_WORDS, type ScoredItem, ScoringOptions, type SectionScore, type SpeechAssessment, type SpeechMeasurement, type SpeechPhoneme, type SpeechPhonemeCandidate, type SpeechPlausibilityPolicy, type SpeechSyllable, type SpeechUnscorable, type SpeechUnscorableCode, type SpeechWord, type SpeechWordError, type TextMatchPolicy, type TextMatchResult, type TotalCalibration, type WavInspection, type WavInspectionPolicy, alignDictation, alignReadAloud, calibrationReport, classifyBand, composeAssessmentScore, computePassThreshold, dictationReferenceWords, diffDictationChars, evaluate, evaluateTries, gradeFromJudgement, gradeReadAloud, graderConfiguration, gte, inAuditSample, inspectWav, levenshteinDistance, matchText, outcomeFromRoutedGrade, outcomeFromUnscorable, resolveItemScoringPolicy, roundGrade, routeGrade, score, scoreTries, validateItemScoringPolicy, validateSpeechAssessment };
package/dist/scoring.js CHANGED
@@ -1,3 +1,3 @@
1
- import { C as READ_ALOUD_MAX_TAKES, M as matchText, S as READ_ALOUD_MAX_SECONDS, T as SPEECH_ASSESSMENT_MAX_WORDS, at as dictationReferenceWords, b as READ_ALOUD_MAX_DIMENSION_WEIGHT, ct as DICTATION_MAX_EQUIVALENCE_LENGTH, j as levenshteinDistance, lt as DICTATION_MAX_TEXT_LENGTH, ot as DICTATION_MAX_ACCEPTED_TRANSCRIPTS, rt as alignDictation, st as DICTATION_MAX_EQUIVALENCES, ut as DICTATION_MAX_TRANSCRIPT_LENGTH, x as READ_ALOUD_MAX_REFERENCE_LENGTH } from "./registry-D92hz9iA.js";
2
- import { A as DEFAULT_ITEM_SCORING_POLICY, D as classifyBand, E as computePassThreshold, M as resolveItemScoringPolicy, N as scoreTries, O as gte, P as validateItemScoringPolicy, T as DEFAULT_PASS_THRESHOLD, a as inspectWav, b as calibrationReport, c as validateSpeechAssessment, d as inAuditSample, f as outcomeFromRoutedGrade, g as gradeFromJudgement, i as outcomeFromUnscorable, j as ITEM_SCORING_MAX_RETRIES, k as roundGrade, l as diffDictationChars, n as evaluateTries, o as gradeReadAloud, p as routeGrade, r as score, s as alignReadAloud, t as evaluate, u as composeAssessmentScore, x as graderConfiguration } from "./scoring-DD1GHcLI.js";
1
+ import { C as READ_ALOUD_MAX_TAKES, M as levenshteinDistance, N as matchText, S as READ_ALOUD_MAX_SECONDS, T as SPEECH_ASSESSMENT_MAX_WORDS, b as READ_ALOUD_MAX_DIMENSION_WEIGHT, ct as DICTATION_MAX_EQUIVALENCES, dt as DICTATION_MAX_TRANSCRIPT_LENGTH, it as alignDictation, lt as DICTATION_MAX_EQUIVALENCE_LENGTH, ot as dictationReferenceWords, st as DICTATION_MAX_ACCEPTED_TRANSCRIPTS, ut as DICTATION_MAX_TEXT_LENGTH, x as READ_ALOUD_MAX_REFERENCE_LENGTH } from "./registry-tkacvJUI.js";
2
+ import { A as DEFAULT_ITEM_SCORING_POLICY, D as classifyBand, E as computePassThreshold, M as resolveItemScoringPolicy, N as scoreTries, O as gte, P as validateItemScoringPolicy, T as DEFAULT_PASS_THRESHOLD, a as inspectWav, b as calibrationReport, c as validateSpeechAssessment, d as inAuditSample, f as outcomeFromRoutedGrade, g as gradeFromJudgement, i as outcomeFromUnscorable, j as ITEM_SCORING_MAX_RETRIES, k as roundGrade, l as diffDictationChars, n as evaluateTries, o as gradeReadAloud, p as routeGrade, r as score, s as alignReadAloud, t as evaluate, u as composeAssessmentScore, x as graderConfiguration } from "./scoring-DIBmo_cy.js";
3
3
  export { 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, ITEM_SCORING_MAX_RETRIES, READ_ALOUD_MAX_DIMENSION_WEIGHT, READ_ALOUD_MAX_REFERENCE_LENGTH, READ_ALOUD_MAX_SECONDS, READ_ALOUD_MAX_TAKES, SPEECH_ASSESSMENT_MAX_WORDS, alignDictation, alignReadAloud, calibrationReport, classifyBand, composeAssessmentScore, computePassThreshold, dictationReferenceWords, diffDictationChars, evaluate, evaluateTries, gradeFromJudgement, gradeReadAloud, graderConfiguration, gte, inAuditSample, inspectWav, levenshteinDistance, matchText, outcomeFromRoutedGrade, outcomeFromUnscorable, resolveItemScoringPolicy, roundGrade, routeGrade, score, scoreTries, validateItemScoringPolicy, validateSpeechAssessment };
@@ -1,4 +1,4 @@
1
- const require_registry = require("./registry-hzrkTeIT.cjs");
1
+ const require_registry = require("./registry-Cymq7Ah0.cjs");
2
2
  let zod_v4 = require("zod/v4");
3
3
  zod_v4 = require_registry.__toESM(zod_v4, 1);
4
4
  // src/xapi/validators.ts
@@ -356,4 +356,4 @@ Object.defineProperty(exports, "xapiDefinitionFor", {
356
356
  }
357
357
  });
358
358
 
359
- //# sourceMappingURL=xapi-7btSpx6v.cjs.map
359
+ //# sourceMappingURL=xapi-Dyqcl3JK.cjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"xapi-7btSpx6v.cjs","names":["z","ActivitySchemaError","getActivityTypeDescriptor"],"sources":["../src/xapi/validators.ts","../src/xapi/verbs.ts","../src/xapi/builder.ts"],"sourcesContent":["import * as z from 'zod/v4';\nimport { ActivitySchemaError } from '../errors.js';\nimport type { ValidationError } from '../types/activity.js';\nimport type { XAPIStatement } from '../types/xapi.js';\n\nconst UUID_V4 = /^[0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i;\n// Minimal IRI/URI check: a scheme followed by ':'.\nconst IRI = /^[a-z][a-z0-9+.-]*:/i;\n\nconst langMap = z.record(z.string(), z.string());\nconst extensions = z.record(z.string(), z.unknown());\n\nconst actorSchema = z\n .object({\n objectType: z.literal('Agent'),\n name: z.string().optional(),\n mbox: z\n .string()\n .regex(/^mailto:/, 'mbox must be a mailto IRI')\n .optional(),\n account: z.object({ homePage: z.string(), name: z.string() }).optional(),\n })\n .refine((actor) => actor.mbox !== undefined || actor.account !== undefined, {\n error: 'actor must be identified by an mbox or an account',\n });\n\nconst statementSchema = z.object({\n id: z.string().regex(UUID_V4, 'id must be a UUID v4'),\n actor: actorSchema,\n verb: z.object({\n id: z.string().regex(IRI, 'verb.id must be an IRI'),\n display: langMap,\n }),\n object: z.object({\n objectType: z.literal('Activity'),\n id: z.string().regex(IRI, 'object.id must be an IRI'),\n definition: z\n .object({\n name: langMap.optional(),\n description: langMap.optional(),\n type: z.string().optional(),\n interactionType: z.string().optional(),\n correctResponsesPattern: z.array(z.string()).optional(),\n choices: z.array(z.object({ id: z.string(), description: langMap.optional() })).optional(),\n extensions: extensions.optional(),\n })\n .optional(),\n }),\n result: z\n .object({\n // xAPI 1.0.3 permits scaled in [-1, 1]; the SDK only emits [0, 1].\n score: z\n .object({\n scaled: z.number().min(-1).max(1),\n raw: z.number().optional(),\n min: z.number().optional(),\n max: z.number().optional(),\n })\n .optional(),\n success: z.boolean().optional(),\n completion: z.boolean().optional(),\n duration: z.string().regex(/^P/, 'duration must be an ISO 8601 duration').optional(),\n response: z.string().optional(),\n extensions: extensions.optional(),\n })\n .optional(),\n context: z\n .object({\n platform: z.string().optional(),\n language: z.string().optional(),\n contextActivities: z\n .object({\n parent: z\n .array(z.object({ objectType: z.literal('Activity'), id: z.string() }))\n .optional(),\n grouping: z\n .array(z.object({ objectType: z.literal('Activity'), id: z.string() }))\n .optional(),\n category: z\n .array(z.object({ objectType: z.literal('Activity'), id: z.string() }))\n .optional(),\n other: z\n .array(z.object({ objectType: z.literal('Activity'), id: z.string() }))\n .optional(),\n })\n .optional(),\n extensions: extensions.optional(),\n })\n .optional(),\n timestamp: z\n .string()\n .refine((value) => !Number.isNaN(Date.parse(value)), 'timestamp must be ISO 8601'),\n version: z.literal('1.0.3'),\n});\n\n/**\n * The one global this module reads by name. Declared here, not globally: this\n * package compiles without Node's types on purpose, and nothing else in it may\n * come to rely on `process`.\n */\ndeclare const process: { env: { NODE_ENV?: string } };\n\n/**\n * Whether this is a production build.\n *\n * **The literal `process.env.NODE_ENV`, spelled exactly so.** It is the one\n * expression bundlers replace at build time, and a browser has no `process` to\n * read at run time. The reading this replaces,\n * `globalThis.process?.env?.NODE_ENV`, is not that expression, so no bundler\n * touched it, and in a browser it found no `process` and answered \"not\n * production\" in every production app — so a malformed statement threw there\n * instead of being logged and sent. Tests running in Node never saw it,\n * because Node has a `process`.\n *\n * This package's own build must leave the literal in its output, for the\n * consumer's bundler to replace. The `try` covers code that reaches a runtime\n * unbundled, with no `process` at all: that is not production, as it always\n * was.\n */\nfunction isProduction(): boolean {\n try {\n return process.env.NODE_ENV === 'production';\n } catch {\n return false;\n }\n}\n\n/**\n * Validates a constructed {@link XAPIStatement} against the xAPI 1.0.3\n * structural contract.\n *\n * In development a structural failure throws (caught early); in production it\n * logs a warning and returns (the statement is still sent — see the design's\n * Error Handling table). Uses a `zod/v4` schema rather than `ajv` + an\n * external JSON Schema to keep `lk-core` dependency-free.\n *\n * NOTE: `ActivitySchemaError` is reused here per the task spec; its\n * `activityType` field carries the sentinel `'xAPIStatement'`. A dedicated\n * `XAPIValidationError` would be semantically cleaner — flagged for review.\n */\nexport function validateXAPIStatement(statement: XAPIStatement): void {\n const result = statementSchema.safeParse(statement);\n if (result.success) {\n return;\n }\n\n const errors: ValidationError[] = result.error.issues.map((issue) => ({\n path: issue.path.map(String),\n message: issue.message,\n code: issue.code,\n }));\n\n if (isProduction()) {\n console.warn('[learning-kit] Invalid xAPI statement (sent anyway):', errors);\n return;\n }\n\n throw new ActivitySchemaError('xAPIStatement', errors);\n}\n","/**\n * The set of xAPI verbs emitted by SDK activities, keyed by a stable\n * identifier mapped to its canonical xAPI verb IRI (xAPI 1.0.3 / ADL registry).\n */\nexport const XAPIVerb = {\n ANSWERED: 'http://adlnet.gov/expapi/verbs/answered',\n COMPLETED: 'http://adlnet.gov/expapi/verbs/completed',\n EXPERIENCED: 'http://adlnet.gov/expapi/verbs/experienced',\n INTERACTED: 'http://adlnet.gov/expapi/verbs/interacted',\n ATTEMPTED: 'http://adlnet.gov/expapi/verbs/attempted',\n PASSED: 'http://adlnet.gov/expapi/verbs/passed',\n FAILED: 'http://adlnet.gov/expapi/verbs/failed',\n WATCHED: 'https://w3id.org/xapi/video/verbs/watched',\n /**\n * Emitted for deferred-grading submissions (e.g. written-response): the\n * learner has submitted work whose grade does not exist yet, so `answered`\n * (which implies a scored response) would be wrong. xAPI 1.0.3 defines no\n * canonical \"submit\" verb; the Activity Streams 1.0 IRI is the established\n * community choice.\n */\n SUBMITTED: 'http://activitystrea.ms/schema/1.0/submit',\n /**\n * Emitted when an asynchronous grader produces a grade for work that was\n * previously only SUBMITTED. Distinct from `answered`, which asserts the\n * grade existed at submission time — here the learner acted earlier and the\n * grade arrived later, often from a different actor (an AI or a teacher).\n */\n SCORED: 'http://adlnet.gov/expapi/verbs/scored',\n} as const;\n\n/** Union of the valid `XAPIVerb` keys. */\nexport type XAPIVerbKey = keyof typeof XAPIVerb;\n\n/**\n * Default `en-US` display label for each verb, used to populate\n * `XAPIVerbObject.display` when the builder resolves a verb key.\n */\nexport const XAPI_VERB_DISPLAY: Record<XAPIVerbKey, Record<string, string>> = {\n ANSWERED: { 'en-US': 'answered' },\n COMPLETED: { 'en-US': 'completed' },\n EXPERIENCED: { 'en-US': 'experienced' },\n INTERACTED: { 'en-US': 'interacted' },\n ATTEMPTED: { 'en-US': 'attempted' },\n PASSED: { 'en-US': 'passed' },\n FAILED: { 'en-US': 'failed' },\n WATCHED: { 'en-US': 'watched' },\n SUBMITTED: { 'en-US': 'submitted' },\n SCORED: { 'en-US': 'scored' },\n};\n","import { getActivityTypeDescriptor } from '../registry/index.js';\nimport type { ScoringResult } from '../types/activity.js';\nimport type {\n XAPIActor,\n XAPIContext,\n XAPIObject,\n XAPIResult,\n XAPIStatement,\n} from '../types/xapi.js';\nimport { validateXAPIStatement } from './validators.js';\nimport { XAPI_VERB_DISPLAY, XAPIVerb, type XAPIVerbKey } from './verbs.js';\n\n/** Caller-supplied activity object descriptor (mapped to an xAPI Activity). */\nexport interface XAPIObjectParams {\n /** Activity IRI. */\n id: string;\n name?: Record<string, string>;\n description?: Record<string, string>;\n /** Activity type IRI. */\n type?: string;\n /** xAPI cmi.interaction type (e.g. `choice`, `fill-in`, `long-fill-in`). */\n interactionType?: string;\n /** Correct-responses patterns, per the xAPI CRP format. */\n correctResponsesPattern?: string[];\n /** For choice-family interactions: the available components. */\n choices?: Array<{ id: string; description?: Record<string, string> }>;\n}\n\n/** Parameters for the generic {@link xAPIBuilder.buildStatement}. */\nexport interface XAPIStatementParams {\n actor: XAPIActor;\n verb: XAPIVerbKey;\n object: XAPIObjectParams;\n result?: XAPIResult;\n context?: XAPIContext;\n}\n\n/** Parameters for {@link xAPIBuilder.buildAnsweredStatement} (verb = ANSWERED). */\nexport interface AnsweredStatementParams {\n actor: XAPIActor;\n object: XAPIObjectParams;\n scoringResult: ScoringResult;\n timeSpentMs: number;\n /** Serialized learner response string. */\n response?: string;\n context?: XAPIContext;\n resultExtensions?: Record<string, unknown>;\n}\n\n/**\n * Parameters for {@link xAPIBuilder.buildSubmittedStatement} (verb =\n * SUBMITTED — deferred-grading submissions). Carries NO score, success, or\n * completion: the grade does not exist yet.\n */\nexport interface SubmittedStatementParams {\n actor: XAPIActor;\n object: XAPIObjectParams;\n timeSpentMs: number;\n /** Serialized learner response string (e.g. the submitted text). */\n response?: string;\n context?: XAPIContext;\n resultExtensions?: Record<string, unknown>;\n}\n\n/** Parameters for {@link xAPIBuilder.buildCompletedStatement} (verb = COMPLETED). */\nexport interface CompletedStatementParams {\n actor: XAPIActor;\n object: XAPIObjectParams;\n scoringResult?: ScoringResult;\n timeSpentMs: number;\n context?: XAPIContext;\n resultExtensions?: Record<string, unknown>;\n}\n\n/**\n * Converts a millisecond duration to an ISO 8601 seconds string with\n * centisecond precision (`PT1.23S`), per the xAPI 1.0.3 recommendation of\n * 0.01-second accuracy. Sub-second durations are preserved (previously any\n * duration under 500 ms collapsed to `PT0S`). Negative inputs (clock skew)\n * clamp to zero — a negative ISO duration is invalid.\n */\nfunction msToIsoDuration(ms: number): string {\n return `PT${(Math.round(Math.max(0, ms) / 10) / 100).toFixed(2)}S`;\n}\n\n/**\n * UUID v4 that works outside secure contexts. `crypto.randomUUID` is\n * SecureContext-gated (undefined on plain-http LAN/staging origins), and a\n * statement is built at SUBMIT time — throwing here would lose the learner's\n * answer. `crypto.getRandomValues` is NOT gated, so the fallback still emits\n * a spec-valid v4 UUID (the statement validator enforces the v4 format).\n */\nfunction uuidv4(): string {\n const c = (\n globalThis as {\n crypto?: { randomUUID?: () => string; getRandomValues?: (a: Uint8Array) => Uint8Array };\n }\n ).crypto;\n if (c?.randomUUID) {\n return c.randomUUID();\n }\n const bytes = new Uint8Array(16);\n if (c?.getRandomValues) {\n c.getRandomValues(bytes);\n } else {\n for (let i = 0; i < 16; i += 1) {\n bytes[i] = Math.floor(Math.random() * 256);\n }\n }\n bytes[6] = ((bytes[6] as number) & 0x0f) | 0x40;\n bytes[8] = ((bytes[8] as number) & 0x3f) | 0x80;\n const hex = [...bytes].map((b) => b.toString(16).padStart(2, '0')).join('');\n return `${hex.slice(0, 8)}-${hex.slice(8, 12)}-${hex.slice(12, 16)}-${hex.slice(16, 20)}-${hex.slice(20)}`;\n}\n\n/** Builds the xAPI Activity object, including `definition` only when populated. */\nfunction buildObject(params: XAPIObjectParams): XAPIObject {\n const definition: NonNullable<XAPIObject['definition']> = {\n ...(params.name !== undefined ? { name: params.name } : {}),\n ...(params.description !== undefined ? { description: params.description } : {}),\n ...(params.type !== undefined ? { type: params.type } : {}),\n ...(params.interactionType !== undefined ? { interactionType: params.interactionType } : {}),\n ...(params.correctResponsesPattern !== undefined\n ? { correctResponsesPattern: params.correctResponsesPattern }\n : {}),\n ...(params.choices !== undefined ? { choices: params.choices } : {}),\n };\n return {\n objectType: 'Activity',\n id: params.id,\n ...(Object.keys(definition).length > 0 ? { definition } : {}),\n };\n}\n\n/**\n * Maps a {@link ScoringResult} + timing to an {@link XAPIResult} per the\n * normative mapping in the design document.\n */\nfunction buildResult(\n timeSpentMs: number,\n scoringResult: ScoringResult | undefined,\n resultExtensions: Record<string, unknown> | undefined,\n response: string | undefined,\n): XAPIResult {\n return {\n completion: true,\n duration: msToIsoDuration(timeSpentMs),\n ...(scoringResult !== undefined\n ? {\n score: {\n scaled: scoringResult.score,\n raw: scoringResult.score,\n min: 0,\n max: scoringResult.maxScore,\n },\n success: scoringResult.passed,\n }\n : {}),\n ...(response !== undefined ? { response } : {}),\n ...(resultExtensions !== undefined ? { extensions: resultExtensions } : {}),\n };\n}\n\n/**\n * Constructs xAPI 1.0.3 Statements. Every call stamps a fresh UUID v4 `id`,\n * an ISO 8601 `timestamp`, and `version: '1.0.3'`. Not pure by design —\n * statements are unique events.\n */\nexport const xAPIBuilder = {\n buildStatement(params: XAPIStatementParams): XAPIStatement {\n const statement: XAPIStatement = {\n id: uuidv4(),\n actor: params.actor,\n verb: {\n id: XAPIVerb[params.verb],\n display: XAPI_VERB_DISPLAY[params.verb],\n },\n object: buildObject(params.object),\n ...(params.result !== undefined ? { result: params.result } : {}),\n ...(params.context !== undefined ? { context: params.context } : {}),\n timestamp: new Date().toISOString(),\n version: '1.0.3',\n };\n // Design xAPIBuilder step 4: validate every statement (throws in dev,\n // warns in prod). All build*Statement helpers route through here.\n validateXAPIStatement(statement);\n return statement;\n },\n\n buildAnsweredStatement(params: AnsweredStatementParams): XAPIStatement {\n return this.buildStatement({\n actor: params.actor,\n verb: 'ANSWERED',\n object: params.object,\n result: buildResult(\n params.timeSpentMs,\n params.scoringResult,\n params.resultExtensions,\n params.response,\n ),\n ...(params.context !== undefined ? { context: params.context } : {}),\n });\n },\n\n /**\n * Builds a statement for a deferred-grading submission (e.g. a written\n * response). Verb is SUBMITTED and the result deliberately omits `score`,\n * `success`, and `completion` — none of them exist until the asynchronous\n * grader runs; only `duration`, `response`, and extensions are recorded.\n */\n buildSubmittedStatement(params: SubmittedStatementParams): XAPIStatement {\n return this.buildStatement({\n actor: params.actor,\n verb: 'SUBMITTED',\n object: params.object,\n result: {\n duration: msToIsoDuration(params.timeSpentMs),\n ...(params.response !== undefined ? { response: params.response } : {}),\n ...(params.resultExtensions !== undefined ? { extensions: params.resultExtensions } : {}),\n },\n ...(params.context !== undefined ? { context: params.context } : {}),\n });\n },\n\n buildCompletedStatement(params: CompletedStatementParams): XAPIStatement {\n return this.buildStatement({\n actor: params.actor,\n verb: 'COMPLETED',\n object: params.object,\n result: buildResult(\n params.timeSpentMs,\n params.scoringResult,\n params.resultExtensions,\n undefined,\n ),\n ...(params.context !== undefined ? { context: params.context } : {}),\n });\n },\n};\n\n/**\n * Builds the xAPI `object.definition` interop fields for an activity from its\n * REGISTERED descriptor, rather than having every renderer hand-roll them.\n *\n * `ActivityTypeDescriptor.interop` declares the activity-type IRI, the\n * cmi.interaction type and how to derive `correctResponsesPattern`; before\n * this, those fields had no reader anywhere and each component rebuilt the\n * same strings inline — the same \"declared but never used\" defect the SDK\n * fixed elsewhere. Reading them here also means a consumer-registered type\n * gets correct interop for free.\n *\n * Returns an empty object for an unregistered type or one that declares no\n * interop, so it is always safe to spread.\n */\nexport function xapiDefinitionFor(data: { type: string }): Partial<XAPIObjectParams> {\n const descriptor = getActivityTypeDescriptor(data.type);\n const interop = descriptor?.interop;\n if (interop === undefined) {\n return {};\n }\n const pattern = interop.correctResponsesPattern?.(data);\n return {\n ...(interop.xapiActivityTypeIri !== undefined ? { type: interop.xapiActivityTypeIri } : {}),\n ...(interop.xapiInteractionType !== undefined\n ? { interactionType: interop.xapiInteractionType }\n : {}),\n ...(pattern !== undefined && pattern.length > 0 ? { correctResponsesPattern: pattern } : {}),\n };\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"xapi-Dyqcl3JK.cjs","names":["z","ActivitySchemaError","getActivityTypeDescriptor"],"sources":["../src/xapi/validators.ts","../src/xapi/verbs.ts","../src/xapi/builder.ts"],"sourcesContent":["import * as z from 'zod/v4';\nimport { ActivitySchemaError } from '../errors.js';\nimport type { ValidationError } from '../types/activity.js';\nimport type { XAPIStatement } from '../types/xapi.js';\n\nconst UUID_V4 = /^[0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i;\n// Minimal IRI/URI check: a scheme followed by ':'.\nconst IRI = /^[a-z][a-z0-9+.-]*:/i;\n\nconst langMap = z.record(z.string(), z.string());\nconst extensions = z.record(z.string(), z.unknown());\n\nconst actorSchema = z\n .object({\n objectType: z.literal('Agent'),\n name: z.string().optional(),\n mbox: z\n .string()\n .regex(/^mailto:/, 'mbox must be a mailto IRI')\n .optional(),\n account: z.object({ homePage: z.string(), name: z.string() }).optional(),\n })\n .refine((actor) => actor.mbox !== undefined || actor.account !== undefined, {\n error: 'actor must be identified by an mbox or an account',\n });\n\nconst statementSchema = z.object({\n id: z.string().regex(UUID_V4, 'id must be a UUID v4'),\n actor: actorSchema,\n verb: z.object({\n id: z.string().regex(IRI, 'verb.id must be an IRI'),\n display: langMap,\n }),\n object: z.object({\n objectType: z.literal('Activity'),\n id: z.string().regex(IRI, 'object.id must be an IRI'),\n definition: z\n .object({\n name: langMap.optional(),\n description: langMap.optional(),\n type: z.string().optional(),\n interactionType: z.string().optional(),\n correctResponsesPattern: z.array(z.string()).optional(),\n choices: z.array(z.object({ id: z.string(), description: langMap.optional() })).optional(),\n extensions: extensions.optional(),\n })\n .optional(),\n }),\n result: z\n .object({\n // xAPI 1.0.3 permits scaled in [-1, 1]; the SDK only emits [0, 1].\n score: z\n .object({\n scaled: z.number().min(-1).max(1),\n raw: z.number().optional(),\n min: z.number().optional(),\n max: z.number().optional(),\n })\n .optional(),\n success: z.boolean().optional(),\n completion: z.boolean().optional(),\n duration: z.string().regex(/^P/, 'duration must be an ISO 8601 duration').optional(),\n response: z.string().optional(),\n extensions: extensions.optional(),\n })\n .optional(),\n context: z\n .object({\n platform: z.string().optional(),\n language: z.string().optional(),\n contextActivities: z\n .object({\n parent: z\n .array(z.object({ objectType: z.literal('Activity'), id: z.string() }))\n .optional(),\n grouping: z\n .array(z.object({ objectType: z.literal('Activity'), id: z.string() }))\n .optional(),\n category: z\n .array(z.object({ objectType: z.literal('Activity'), id: z.string() }))\n .optional(),\n other: z\n .array(z.object({ objectType: z.literal('Activity'), id: z.string() }))\n .optional(),\n })\n .optional(),\n extensions: extensions.optional(),\n })\n .optional(),\n timestamp: z\n .string()\n .refine((value) => !Number.isNaN(Date.parse(value)), 'timestamp must be ISO 8601'),\n version: z.literal('1.0.3'),\n});\n\n/**\n * The one global this module reads by name. Declared here, not globally: this\n * package compiles without Node's types on purpose, and nothing else in it may\n * come to rely on `process`.\n */\ndeclare const process: { env: { NODE_ENV?: string } };\n\n/**\n * Whether this is a production build.\n *\n * **The literal `process.env.NODE_ENV`, spelled exactly so.** It is the one\n * expression bundlers replace at build time, and a browser has no `process` to\n * read at run time. The reading this replaces,\n * `globalThis.process?.env?.NODE_ENV`, is not that expression, so no bundler\n * touched it, and in a browser it found no `process` and answered \"not\n * production\" in every production app — so a malformed statement threw there\n * instead of being logged and sent. Tests running in Node never saw it,\n * because Node has a `process`.\n *\n * This package's own build must leave the literal in its output, for the\n * consumer's bundler to replace. The `try` covers code that reaches a runtime\n * unbundled, with no `process` at all: that is not production, as it always\n * was.\n */\nfunction isProduction(): boolean {\n try {\n return process.env.NODE_ENV === 'production';\n } catch {\n return false;\n }\n}\n\n/**\n * Validates a constructed {@link XAPIStatement} against the xAPI 1.0.3\n * structural contract.\n *\n * In development a structural failure throws (caught early); in production it\n * logs a warning and returns (the statement is still sent — see the design's\n * Error Handling table). Uses a `zod/v4` schema rather than `ajv` + an\n * external JSON Schema to keep `lk-core` dependency-free.\n *\n * NOTE: `ActivitySchemaError` is reused here per the task spec; its\n * `activityType` field carries the sentinel `'xAPIStatement'`. A dedicated\n * `XAPIValidationError` would be semantically cleaner — flagged for review.\n */\nexport function validateXAPIStatement(statement: XAPIStatement): void {\n const result = statementSchema.safeParse(statement);\n if (result.success) {\n return;\n }\n\n const errors: ValidationError[] = result.error.issues.map((issue) => ({\n path: issue.path.map(String),\n message: issue.message,\n code: issue.code,\n }));\n\n if (isProduction()) {\n console.warn('[learning-kit] Invalid xAPI statement (sent anyway):', errors);\n return;\n }\n\n throw new ActivitySchemaError('xAPIStatement', errors);\n}\n","/**\n * The set of xAPI verbs emitted by SDK activities, keyed by a stable\n * identifier mapped to its canonical xAPI verb IRI (xAPI 1.0.3 / ADL registry).\n */\nexport const XAPIVerb = {\n ANSWERED: 'http://adlnet.gov/expapi/verbs/answered',\n COMPLETED: 'http://adlnet.gov/expapi/verbs/completed',\n EXPERIENCED: 'http://adlnet.gov/expapi/verbs/experienced',\n INTERACTED: 'http://adlnet.gov/expapi/verbs/interacted',\n ATTEMPTED: 'http://adlnet.gov/expapi/verbs/attempted',\n PASSED: 'http://adlnet.gov/expapi/verbs/passed',\n FAILED: 'http://adlnet.gov/expapi/verbs/failed',\n WATCHED: 'https://w3id.org/xapi/video/verbs/watched',\n /**\n * Emitted for deferred-grading submissions (e.g. written-response): the\n * learner has submitted work whose grade does not exist yet, so `answered`\n * (which implies a scored response) would be wrong. xAPI 1.0.3 defines no\n * canonical \"submit\" verb; the Activity Streams 1.0 IRI is the established\n * community choice.\n */\n SUBMITTED: 'http://activitystrea.ms/schema/1.0/submit',\n /**\n * Emitted when an asynchronous grader produces a grade for work that was\n * previously only SUBMITTED. Distinct from `answered`, which asserts the\n * grade existed at submission time — here the learner acted earlier and the\n * grade arrived later, often from a different actor (an AI or a teacher).\n */\n SCORED: 'http://adlnet.gov/expapi/verbs/scored',\n} as const;\n\n/** Union of the valid `XAPIVerb` keys. */\nexport type XAPIVerbKey = keyof typeof XAPIVerb;\n\n/**\n * Default `en-US` display label for each verb, used to populate\n * `XAPIVerbObject.display` when the builder resolves a verb key.\n */\nexport const XAPI_VERB_DISPLAY: Record<XAPIVerbKey, Record<string, string>> = {\n ANSWERED: { 'en-US': 'answered' },\n COMPLETED: { 'en-US': 'completed' },\n EXPERIENCED: { 'en-US': 'experienced' },\n INTERACTED: { 'en-US': 'interacted' },\n ATTEMPTED: { 'en-US': 'attempted' },\n PASSED: { 'en-US': 'passed' },\n FAILED: { 'en-US': 'failed' },\n WATCHED: { 'en-US': 'watched' },\n SUBMITTED: { 'en-US': 'submitted' },\n SCORED: { 'en-US': 'scored' },\n};\n","import { getActivityTypeDescriptor } from '../registry/index.js';\nimport type { ScoringResult } from '../types/activity.js';\nimport type {\n XAPIActor,\n XAPIContext,\n XAPIObject,\n XAPIResult,\n XAPIStatement,\n} from '../types/xapi.js';\nimport { validateXAPIStatement } from './validators.js';\nimport { XAPI_VERB_DISPLAY, XAPIVerb, type XAPIVerbKey } from './verbs.js';\n\n/** Caller-supplied activity object descriptor (mapped to an xAPI Activity). */\nexport interface XAPIObjectParams {\n /** Activity IRI. */\n id: string;\n name?: Record<string, string>;\n description?: Record<string, string>;\n /** Activity type IRI. */\n type?: string;\n /** xAPI cmi.interaction type (e.g. `choice`, `fill-in`, `long-fill-in`). */\n interactionType?: string;\n /** Correct-responses patterns, per the xAPI CRP format. */\n correctResponsesPattern?: string[];\n /** For choice-family interactions: the available components. */\n choices?: Array<{ id: string; description?: Record<string, string> }>;\n}\n\n/** Parameters for the generic {@link xAPIBuilder.buildStatement}. */\nexport interface XAPIStatementParams {\n actor: XAPIActor;\n verb: XAPIVerbKey;\n object: XAPIObjectParams;\n result?: XAPIResult;\n context?: XAPIContext;\n}\n\n/** Parameters for {@link xAPIBuilder.buildAnsweredStatement} (verb = ANSWERED). */\nexport interface AnsweredStatementParams {\n actor: XAPIActor;\n object: XAPIObjectParams;\n scoringResult: ScoringResult;\n timeSpentMs: number;\n /** Serialized learner response string. */\n response?: string;\n context?: XAPIContext;\n resultExtensions?: Record<string, unknown>;\n}\n\n/**\n * Parameters for {@link xAPIBuilder.buildSubmittedStatement} (verb =\n * SUBMITTED — deferred-grading submissions). Carries NO score, success, or\n * completion: the grade does not exist yet.\n */\nexport interface SubmittedStatementParams {\n actor: XAPIActor;\n object: XAPIObjectParams;\n timeSpentMs: number;\n /** Serialized learner response string (e.g. the submitted text). */\n response?: string;\n context?: XAPIContext;\n resultExtensions?: Record<string, unknown>;\n}\n\n/** Parameters for {@link xAPIBuilder.buildCompletedStatement} (verb = COMPLETED). */\nexport interface CompletedStatementParams {\n actor: XAPIActor;\n object: XAPIObjectParams;\n scoringResult?: ScoringResult;\n timeSpentMs: number;\n context?: XAPIContext;\n resultExtensions?: Record<string, unknown>;\n}\n\n/**\n * Converts a millisecond duration to an ISO 8601 seconds string with\n * centisecond precision (`PT1.23S`), per the xAPI 1.0.3 recommendation of\n * 0.01-second accuracy. Sub-second durations are preserved (previously any\n * duration under 500 ms collapsed to `PT0S`). Negative inputs (clock skew)\n * clamp to zero — a negative ISO duration is invalid.\n */\nfunction msToIsoDuration(ms: number): string {\n return `PT${(Math.round(Math.max(0, ms) / 10) / 100).toFixed(2)}S`;\n}\n\n/**\n * UUID v4 that works outside secure contexts. `crypto.randomUUID` is\n * SecureContext-gated (undefined on plain-http LAN/staging origins), and a\n * statement is built at SUBMIT time — throwing here would lose the learner's\n * answer. `crypto.getRandomValues` is NOT gated, so the fallback still emits\n * a spec-valid v4 UUID (the statement validator enforces the v4 format).\n */\nfunction uuidv4(): string {\n const c = (\n globalThis as {\n crypto?: { randomUUID?: () => string; getRandomValues?: (a: Uint8Array) => Uint8Array };\n }\n ).crypto;\n if (c?.randomUUID) {\n return c.randomUUID();\n }\n const bytes = new Uint8Array(16);\n if (c?.getRandomValues) {\n c.getRandomValues(bytes);\n } else {\n for (let i = 0; i < 16; i += 1) {\n bytes[i] = Math.floor(Math.random() * 256);\n }\n }\n bytes[6] = ((bytes[6] as number) & 0x0f) | 0x40;\n bytes[8] = ((bytes[8] as number) & 0x3f) | 0x80;\n const hex = [...bytes].map((b) => b.toString(16).padStart(2, '0')).join('');\n return `${hex.slice(0, 8)}-${hex.slice(8, 12)}-${hex.slice(12, 16)}-${hex.slice(16, 20)}-${hex.slice(20)}`;\n}\n\n/** Builds the xAPI Activity object, including `definition` only when populated. */\nfunction buildObject(params: XAPIObjectParams): XAPIObject {\n const definition: NonNullable<XAPIObject['definition']> = {\n ...(params.name !== undefined ? { name: params.name } : {}),\n ...(params.description !== undefined ? { description: params.description } : {}),\n ...(params.type !== undefined ? { type: params.type } : {}),\n ...(params.interactionType !== undefined ? { interactionType: params.interactionType } : {}),\n ...(params.correctResponsesPattern !== undefined\n ? { correctResponsesPattern: params.correctResponsesPattern }\n : {}),\n ...(params.choices !== undefined ? { choices: params.choices } : {}),\n };\n return {\n objectType: 'Activity',\n id: params.id,\n ...(Object.keys(definition).length > 0 ? { definition } : {}),\n };\n}\n\n/**\n * Maps a {@link ScoringResult} + timing to an {@link XAPIResult} per the\n * normative mapping in the design document.\n */\nfunction buildResult(\n timeSpentMs: number,\n scoringResult: ScoringResult | undefined,\n resultExtensions: Record<string, unknown> | undefined,\n response: string | undefined,\n): XAPIResult {\n return {\n completion: true,\n duration: msToIsoDuration(timeSpentMs),\n ...(scoringResult !== undefined\n ? {\n score: {\n scaled: scoringResult.score,\n raw: scoringResult.score,\n min: 0,\n max: scoringResult.maxScore,\n },\n success: scoringResult.passed,\n }\n : {}),\n ...(response !== undefined ? { response } : {}),\n ...(resultExtensions !== undefined ? { extensions: resultExtensions } : {}),\n };\n}\n\n/**\n * Constructs xAPI 1.0.3 Statements. Every call stamps a fresh UUID v4 `id`,\n * an ISO 8601 `timestamp`, and `version: '1.0.3'`. Not pure by design —\n * statements are unique events.\n */\nexport const xAPIBuilder = {\n buildStatement(params: XAPIStatementParams): XAPIStatement {\n const statement: XAPIStatement = {\n id: uuidv4(),\n actor: params.actor,\n verb: {\n id: XAPIVerb[params.verb],\n display: XAPI_VERB_DISPLAY[params.verb],\n },\n object: buildObject(params.object),\n ...(params.result !== undefined ? { result: params.result } : {}),\n ...(params.context !== undefined ? { context: params.context } : {}),\n timestamp: new Date().toISOString(),\n version: '1.0.3',\n };\n // Design xAPIBuilder step 4: validate every statement (throws in dev,\n // warns in prod). All build*Statement helpers route through here.\n validateXAPIStatement(statement);\n return statement;\n },\n\n buildAnsweredStatement(params: AnsweredStatementParams): XAPIStatement {\n return this.buildStatement({\n actor: params.actor,\n verb: 'ANSWERED',\n object: params.object,\n result: buildResult(\n params.timeSpentMs,\n params.scoringResult,\n params.resultExtensions,\n params.response,\n ),\n ...(params.context !== undefined ? { context: params.context } : {}),\n });\n },\n\n /**\n * Builds a statement for a deferred-grading submission (e.g. a written\n * response). Verb is SUBMITTED and the result deliberately omits `score`,\n * `success`, and `completion` — none of them exist until the asynchronous\n * grader runs; only `duration`, `response`, and extensions are recorded.\n */\n buildSubmittedStatement(params: SubmittedStatementParams): XAPIStatement {\n return this.buildStatement({\n actor: params.actor,\n verb: 'SUBMITTED',\n object: params.object,\n result: {\n duration: msToIsoDuration(params.timeSpentMs),\n ...(params.response !== undefined ? { response: params.response } : {}),\n ...(params.resultExtensions !== undefined ? { extensions: params.resultExtensions } : {}),\n },\n ...(params.context !== undefined ? { context: params.context } : {}),\n });\n },\n\n buildCompletedStatement(params: CompletedStatementParams): XAPIStatement {\n return this.buildStatement({\n actor: params.actor,\n verb: 'COMPLETED',\n object: params.object,\n result: buildResult(\n params.timeSpentMs,\n params.scoringResult,\n params.resultExtensions,\n undefined,\n ),\n ...(params.context !== undefined ? { context: params.context } : {}),\n });\n },\n};\n\n/**\n * Builds the xAPI `object.definition` interop fields for an activity from its\n * REGISTERED descriptor, rather than having every renderer hand-roll them.\n *\n * `ActivityTypeDescriptor.interop` declares the activity-type IRI, the\n * cmi.interaction type and how to derive `correctResponsesPattern`; before\n * this, those fields had no reader anywhere and each component rebuilt the\n * same strings inline — the same \"declared but never used\" defect the SDK\n * fixed elsewhere. Reading them here also means a consumer-registered type\n * gets correct interop for free.\n *\n * Returns an empty object for an unregistered type or one that declares no\n * interop, so it is always safe to spread.\n */\nexport function xapiDefinitionFor(data: { type: string }): Partial<XAPIObjectParams> {\n const descriptor = getActivityTypeDescriptor(data.type);\n const interop = descriptor?.interop;\n if (interop === undefined) {\n return {};\n }\n const pattern = interop.correctResponsesPattern?.(data);\n return {\n ...(interop.xapiActivityTypeIri !== undefined ? { type: interop.xapiActivityTypeIri } : {}),\n ...(interop.xapiInteractionType !== undefined\n ? { interactionType: interop.xapiInteractionType }\n : {}),\n ...(pattern !== undefined && pattern.length > 0 ? { correctResponsesPattern: pattern } : {}),\n };\n}\n"],"mappings":"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"}
@@ -1,4 +1,4 @@
1
- import { Q as ActivitySchemaError, t as getActivityTypeDescriptor } from "./registry-D92hz9iA.js";
1
+ import { $ as ActivitySchemaError, t as getActivityTypeDescriptor } from "./registry-tkacvJUI.js";
2
2
  import * as z from "zod/v4";
3
3
  // src/xapi/validators.ts
4
4
  const UUID_V4 = /^[0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i;
@@ -326,4 +326,4 @@ function xapiDefinitionFor(data) {
326
326
  }
327
327
  export { validateXAPIStatement as a, XAPI_VERB_DISPLAY as i, xapiDefinitionFor as n, XAPIVerb as r, xAPIBuilder as t };
328
328
 
329
- //# sourceMappingURL=xapi-Cgicg-zU.js.map
329
+ //# sourceMappingURL=xapi-gCAo549Q.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"xapi-Cgicg-zU.js","names":[],"sources":["../src/xapi/validators.ts","../src/xapi/verbs.ts","../src/xapi/builder.ts"],"sourcesContent":["import * as z from 'zod/v4';\nimport { ActivitySchemaError } from '../errors.js';\nimport type { ValidationError } from '../types/activity.js';\nimport type { XAPIStatement } from '../types/xapi.js';\n\nconst UUID_V4 = /^[0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i;\n// Minimal IRI/URI check: a scheme followed by ':'.\nconst IRI = /^[a-z][a-z0-9+.-]*:/i;\n\nconst langMap = z.record(z.string(), z.string());\nconst extensions = z.record(z.string(), z.unknown());\n\nconst actorSchema = z\n .object({\n objectType: z.literal('Agent'),\n name: z.string().optional(),\n mbox: z\n .string()\n .regex(/^mailto:/, 'mbox must be a mailto IRI')\n .optional(),\n account: z.object({ homePage: z.string(), name: z.string() }).optional(),\n })\n .refine((actor) => actor.mbox !== undefined || actor.account !== undefined, {\n error: 'actor must be identified by an mbox or an account',\n });\n\nconst statementSchema = z.object({\n id: z.string().regex(UUID_V4, 'id must be a UUID v4'),\n actor: actorSchema,\n verb: z.object({\n id: z.string().regex(IRI, 'verb.id must be an IRI'),\n display: langMap,\n }),\n object: z.object({\n objectType: z.literal('Activity'),\n id: z.string().regex(IRI, 'object.id must be an IRI'),\n definition: z\n .object({\n name: langMap.optional(),\n description: langMap.optional(),\n type: z.string().optional(),\n interactionType: z.string().optional(),\n correctResponsesPattern: z.array(z.string()).optional(),\n choices: z.array(z.object({ id: z.string(), description: langMap.optional() })).optional(),\n extensions: extensions.optional(),\n })\n .optional(),\n }),\n result: z\n .object({\n // xAPI 1.0.3 permits scaled in [-1, 1]; the SDK only emits [0, 1].\n score: z\n .object({\n scaled: z.number().min(-1).max(1),\n raw: z.number().optional(),\n min: z.number().optional(),\n max: z.number().optional(),\n })\n .optional(),\n success: z.boolean().optional(),\n completion: z.boolean().optional(),\n duration: z.string().regex(/^P/, 'duration must be an ISO 8601 duration').optional(),\n response: z.string().optional(),\n extensions: extensions.optional(),\n })\n .optional(),\n context: z\n .object({\n platform: z.string().optional(),\n language: z.string().optional(),\n contextActivities: z\n .object({\n parent: z\n .array(z.object({ objectType: z.literal('Activity'), id: z.string() }))\n .optional(),\n grouping: z\n .array(z.object({ objectType: z.literal('Activity'), id: z.string() }))\n .optional(),\n category: z\n .array(z.object({ objectType: z.literal('Activity'), id: z.string() }))\n .optional(),\n other: z\n .array(z.object({ objectType: z.literal('Activity'), id: z.string() }))\n .optional(),\n })\n .optional(),\n extensions: extensions.optional(),\n })\n .optional(),\n timestamp: z\n .string()\n .refine((value) => !Number.isNaN(Date.parse(value)), 'timestamp must be ISO 8601'),\n version: z.literal('1.0.3'),\n});\n\n/**\n * The one global this module reads by name. Declared here, not globally: this\n * package compiles without Node's types on purpose, and nothing else in it may\n * come to rely on `process`.\n */\ndeclare const process: { env: { NODE_ENV?: string } };\n\n/**\n * Whether this is a production build.\n *\n * **The literal `process.env.NODE_ENV`, spelled exactly so.** It is the one\n * expression bundlers replace at build time, and a browser has no `process` to\n * read at run time. The reading this replaces,\n * `globalThis.process?.env?.NODE_ENV`, is not that expression, so no bundler\n * touched it, and in a browser it found no `process` and answered \"not\n * production\" in every production app — so a malformed statement threw there\n * instead of being logged and sent. Tests running in Node never saw it,\n * because Node has a `process`.\n *\n * This package's own build must leave the literal in its output, for the\n * consumer's bundler to replace. The `try` covers code that reaches a runtime\n * unbundled, with no `process` at all: that is not production, as it always\n * was.\n */\nfunction isProduction(): boolean {\n try {\n return process.env.NODE_ENV === 'production';\n } catch {\n return false;\n }\n}\n\n/**\n * Validates a constructed {@link XAPIStatement} against the xAPI 1.0.3\n * structural contract.\n *\n * In development a structural failure throws (caught early); in production it\n * logs a warning and returns (the statement is still sent — see the design's\n * Error Handling table). Uses a `zod/v4` schema rather than `ajv` + an\n * external JSON Schema to keep `lk-core` dependency-free.\n *\n * NOTE: `ActivitySchemaError` is reused here per the task spec; its\n * `activityType` field carries the sentinel `'xAPIStatement'`. A dedicated\n * `XAPIValidationError` would be semantically cleaner — flagged for review.\n */\nexport function validateXAPIStatement(statement: XAPIStatement): void {\n const result = statementSchema.safeParse(statement);\n if (result.success) {\n return;\n }\n\n const errors: ValidationError[] = result.error.issues.map((issue) => ({\n path: issue.path.map(String),\n message: issue.message,\n code: issue.code,\n }));\n\n if (isProduction()) {\n console.warn('[learning-kit] Invalid xAPI statement (sent anyway):', errors);\n return;\n }\n\n throw new ActivitySchemaError('xAPIStatement', errors);\n}\n","/**\n * The set of xAPI verbs emitted by SDK activities, keyed by a stable\n * identifier mapped to its canonical xAPI verb IRI (xAPI 1.0.3 / ADL registry).\n */\nexport const XAPIVerb = {\n ANSWERED: 'http://adlnet.gov/expapi/verbs/answered',\n COMPLETED: 'http://adlnet.gov/expapi/verbs/completed',\n EXPERIENCED: 'http://adlnet.gov/expapi/verbs/experienced',\n INTERACTED: 'http://adlnet.gov/expapi/verbs/interacted',\n ATTEMPTED: 'http://adlnet.gov/expapi/verbs/attempted',\n PASSED: 'http://adlnet.gov/expapi/verbs/passed',\n FAILED: 'http://adlnet.gov/expapi/verbs/failed',\n WATCHED: 'https://w3id.org/xapi/video/verbs/watched',\n /**\n * Emitted for deferred-grading submissions (e.g. written-response): the\n * learner has submitted work whose grade does not exist yet, so `answered`\n * (which implies a scored response) would be wrong. xAPI 1.0.3 defines no\n * canonical \"submit\" verb; the Activity Streams 1.0 IRI is the established\n * community choice.\n */\n SUBMITTED: 'http://activitystrea.ms/schema/1.0/submit',\n /**\n * Emitted when an asynchronous grader produces a grade for work that was\n * previously only SUBMITTED. Distinct from `answered`, which asserts the\n * grade existed at submission time — here the learner acted earlier and the\n * grade arrived later, often from a different actor (an AI or a teacher).\n */\n SCORED: 'http://adlnet.gov/expapi/verbs/scored',\n} as const;\n\n/** Union of the valid `XAPIVerb` keys. */\nexport type XAPIVerbKey = keyof typeof XAPIVerb;\n\n/**\n * Default `en-US` display label for each verb, used to populate\n * `XAPIVerbObject.display` when the builder resolves a verb key.\n */\nexport const XAPI_VERB_DISPLAY: Record<XAPIVerbKey, Record<string, string>> = {\n ANSWERED: { 'en-US': 'answered' },\n COMPLETED: { 'en-US': 'completed' },\n EXPERIENCED: { 'en-US': 'experienced' },\n INTERACTED: { 'en-US': 'interacted' },\n ATTEMPTED: { 'en-US': 'attempted' },\n PASSED: { 'en-US': 'passed' },\n FAILED: { 'en-US': 'failed' },\n WATCHED: { 'en-US': 'watched' },\n SUBMITTED: { 'en-US': 'submitted' },\n SCORED: { 'en-US': 'scored' },\n};\n","import { getActivityTypeDescriptor } from '../registry/index.js';\nimport type { ScoringResult } from '../types/activity.js';\nimport type {\n XAPIActor,\n XAPIContext,\n XAPIObject,\n XAPIResult,\n XAPIStatement,\n} from '../types/xapi.js';\nimport { validateXAPIStatement } from './validators.js';\nimport { XAPI_VERB_DISPLAY, XAPIVerb, type XAPIVerbKey } from './verbs.js';\n\n/** Caller-supplied activity object descriptor (mapped to an xAPI Activity). */\nexport interface XAPIObjectParams {\n /** Activity IRI. */\n id: string;\n name?: Record<string, string>;\n description?: Record<string, string>;\n /** Activity type IRI. */\n type?: string;\n /** xAPI cmi.interaction type (e.g. `choice`, `fill-in`, `long-fill-in`). */\n interactionType?: string;\n /** Correct-responses patterns, per the xAPI CRP format. */\n correctResponsesPattern?: string[];\n /** For choice-family interactions: the available components. */\n choices?: Array<{ id: string; description?: Record<string, string> }>;\n}\n\n/** Parameters for the generic {@link xAPIBuilder.buildStatement}. */\nexport interface XAPIStatementParams {\n actor: XAPIActor;\n verb: XAPIVerbKey;\n object: XAPIObjectParams;\n result?: XAPIResult;\n context?: XAPIContext;\n}\n\n/** Parameters for {@link xAPIBuilder.buildAnsweredStatement} (verb = ANSWERED). */\nexport interface AnsweredStatementParams {\n actor: XAPIActor;\n object: XAPIObjectParams;\n scoringResult: ScoringResult;\n timeSpentMs: number;\n /** Serialized learner response string. */\n response?: string;\n context?: XAPIContext;\n resultExtensions?: Record<string, unknown>;\n}\n\n/**\n * Parameters for {@link xAPIBuilder.buildSubmittedStatement} (verb =\n * SUBMITTED — deferred-grading submissions). Carries NO score, success, or\n * completion: the grade does not exist yet.\n */\nexport interface SubmittedStatementParams {\n actor: XAPIActor;\n object: XAPIObjectParams;\n timeSpentMs: number;\n /** Serialized learner response string (e.g. the submitted text). */\n response?: string;\n context?: XAPIContext;\n resultExtensions?: Record<string, unknown>;\n}\n\n/** Parameters for {@link xAPIBuilder.buildCompletedStatement} (verb = COMPLETED). */\nexport interface CompletedStatementParams {\n actor: XAPIActor;\n object: XAPIObjectParams;\n scoringResult?: ScoringResult;\n timeSpentMs: number;\n context?: XAPIContext;\n resultExtensions?: Record<string, unknown>;\n}\n\n/**\n * Converts a millisecond duration to an ISO 8601 seconds string with\n * centisecond precision (`PT1.23S`), per the xAPI 1.0.3 recommendation of\n * 0.01-second accuracy. Sub-second durations are preserved (previously any\n * duration under 500 ms collapsed to `PT0S`). Negative inputs (clock skew)\n * clamp to zero — a negative ISO duration is invalid.\n */\nfunction msToIsoDuration(ms: number): string {\n return `PT${(Math.round(Math.max(0, ms) / 10) / 100).toFixed(2)}S`;\n}\n\n/**\n * UUID v4 that works outside secure contexts. `crypto.randomUUID` is\n * SecureContext-gated (undefined on plain-http LAN/staging origins), and a\n * statement is built at SUBMIT time — throwing here would lose the learner's\n * answer. `crypto.getRandomValues` is NOT gated, so the fallback still emits\n * a spec-valid v4 UUID (the statement validator enforces the v4 format).\n */\nfunction uuidv4(): string {\n const c = (\n globalThis as {\n crypto?: { randomUUID?: () => string; getRandomValues?: (a: Uint8Array) => Uint8Array };\n }\n ).crypto;\n if (c?.randomUUID) {\n return c.randomUUID();\n }\n const bytes = new Uint8Array(16);\n if (c?.getRandomValues) {\n c.getRandomValues(bytes);\n } else {\n for (let i = 0; i < 16; i += 1) {\n bytes[i] = Math.floor(Math.random() * 256);\n }\n }\n bytes[6] = ((bytes[6] as number) & 0x0f) | 0x40;\n bytes[8] = ((bytes[8] as number) & 0x3f) | 0x80;\n const hex = [...bytes].map((b) => b.toString(16).padStart(2, '0')).join('');\n return `${hex.slice(0, 8)}-${hex.slice(8, 12)}-${hex.slice(12, 16)}-${hex.slice(16, 20)}-${hex.slice(20)}`;\n}\n\n/** Builds the xAPI Activity object, including `definition` only when populated. */\nfunction buildObject(params: XAPIObjectParams): XAPIObject {\n const definition: NonNullable<XAPIObject['definition']> = {\n ...(params.name !== undefined ? { name: params.name } : {}),\n ...(params.description !== undefined ? { description: params.description } : {}),\n ...(params.type !== undefined ? { type: params.type } : {}),\n ...(params.interactionType !== undefined ? { interactionType: params.interactionType } : {}),\n ...(params.correctResponsesPattern !== undefined\n ? { correctResponsesPattern: params.correctResponsesPattern }\n : {}),\n ...(params.choices !== undefined ? { choices: params.choices } : {}),\n };\n return {\n objectType: 'Activity',\n id: params.id,\n ...(Object.keys(definition).length > 0 ? { definition } : {}),\n };\n}\n\n/**\n * Maps a {@link ScoringResult} + timing to an {@link XAPIResult} per the\n * normative mapping in the design document.\n */\nfunction buildResult(\n timeSpentMs: number,\n scoringResult: ScoringResult | undefined,\n resultExtensions: Record<string, unknown> | undefined,\n response: string | undefined,\n): XAPIResult {\n return {\n completion: true,\n duration: msToIsoDuration(timeSpentMs),\n ...(scoringResult !== undefined\n ? {\n score: {\n scaled: scoringResult.score,\n raw: scoringResult.score,\n min: 0,\n max: scoringResult.maxScore,\n },\n success: scoringResult.passed,\n }\n : {}),\n ...(response !== undefined ? { response } : {}),\n ...(resultExtensions !== undefined ? { extensions: resultExtensions } : {}),\n };\n}\n\n/**\n * Constructs xAPI 1.0.3 Statements. Every call stamps a fresh UUID v4 `id`,\n * an ISO 8601 `timestamp`, and `version: '1.0.3'`. Not pure by design —\n * statements are unique events.\n */\nexport const xAPIBuilder = {\n buildStatement(params: XAPIStatementParams): XAPIStatement {\n const statement: XAPIStatement = {\n id: uuidv4(),\n actor: params.actor,\n verb: {\n id: XAPIVerb[params.verb],\n display: XAPI_VERB_DISPLAY[params.verb],\n },\n object: buildObject(params.object),\n ...(params.result !== undefined ? { result: params.result } : {}),\n ...(params.context !== undefined ? { context: params.context } : {}),\n timestamp: new Date().toISOString(),\n version: '1.0.3',\n };\n // Design xAPIBuilder step 4: validate every statement (throws in dev,\n // warns in prod). All build*Statement helpers route through here.\n validateXAPIStatement(statement);\n return statement;\n },\n\n buildAnsweredStatement(params: AnsweredStatementParams): XAPIStatement {\n return this.buildStatement({\n actor: params.actor,\n verb: 'ANSWERED',\n object: params.object,\n result: buildResult(\n params.timeSpentMs,\n params.scoringResult,\n params.resultExtensions,\n params.response,\n ),\n ...(params.context !== undefined ? { context: params.context } : {}),\n });\n },\n\n /**\n * Builds a statement for a deferred-grading submission (e.g. a written\n * response). Verb is SUBMITTED and the result deliberately omits `score`,\n * `success`, and `completion` — none of them exist until the asynchronous\n * grader runs; only `duration`, `response`, and extensions are recorded.\n */\n buildSubmittedStatement(params: SubmittedStatementParams): XAPIStatement {\n return this.buildStatement({\n actor: params.actor,\n verb: 'SUBMITTED',\n object: params.object,\n result: {\n duration: msToIsoDuration(params.timeSpentMs),\n ...(params.response !== undefined ? { response: params.response } : {}),\n ...(params.resultExtensions !== undefined ? { extensions: params.resultExtensions } : {}),\n },\n ...(params.context !== undefined ? { context: params.context } : {}),\n });\n },\n\n buildCompletedStatement(params: CompletedStatementParams): XAPIStatement {\n return this.buildStatement({\n actor: params.actor,\n verb: 'COMPLETED',\n object: params.object,\n result: buildResult(\n params.timeSpentMs,\n params.scoringResult,\n params.resultExtensions,\n undefined,\n ),\n ...(params.context !== undefined ? { context: params.context } : {}),\n });\n },\n};\n\n/**\n * Builds the xAPI `object.definition` interop fields for an activity from its\n * REGISTERED descriptor, rather than having every renderer hand-roll them.\n *\n * `ActivityTypeDescriptor.interop` declares the activity-type IRI, the\n * cmi.interaction type and how to derive `correctResponsesPattern`; before\n * this, those fields had no reader anywhere and each component rebuilt the\n * same strings inline — the same \"declared but never used\" defect the SDK\n * fixed elsewhere. Reading them here also means a consumer-registered type\n * gets correct interop for free.\n *\n * Returns an empty object for an unregistered type or one that declares no\n * interop, so it is always safe to spread.\n */\nexport function xapiDefinitionFor(data: { type: string }): Partial<XAPIObjectParams> {\n const descriptor = getActivityTypeDescriptor(data.type);\n const interop = descriptor?.interop;\n if (interop === undefined) {\n return {};\n }\n const pattern = interop.correctResponsesPattern?.(data);\n return {\n ...(interop.xapiActivityTypeIri !== undefined ? { type: interop.xapiActivityTypeIri } : {}),\n ...(interop.xapiInteractionType !== undefined\n ? { interactionType: interop.xapiInteractionType }\n : {}),\n ...(pattern !== undefined && pattern.length > 0 ? { correctResponsesPattern: pattern } : {}),\n };\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"xapi-gCAo549Q.js","names":[],"sources":["../src/xapi/validators.ts","../src/xapi/verbs.ts","../src/xapi/builder.ts"],"sourcesContent":["import * as z from 'zod/v4';\nimport { ActivitySchemaError } from '../errors.js';\nimport type { ValidationError } from '../types/activity.js';\nimport type { XAPIStatement } from '../types/xapi.js';\n\nconst UUID_V4 = /^[0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i;\n// Minimal IRI/URI check: a scheme followed by ':'.\nconst IRI = /^[a-z][a-z0-9+.-]*:/i;\n\nconst langMap = z.record(z.string(), z.string());\nconst extensions = z.record(z.string(), z.unknown());\n\nconst actorSchema = z\n .object({\n objectType: z.literal('Agent'),\n name: z.string().optional(),\n mbox: z\n .string()\n .regex(/^mailto:/, 'mbox must be a mailto IRI')\n .optional(),\n account: z.object({ homePage: z.string(), name: z.string() }).optional(),\n })\n .refine((actor) => actor.mbox !== undefined || actor.account !== undefined, {\n error: 'actor must be identified by an mbox or an account',\n });\n\nconst statementSchema = z.object({\n id: z.string().regex(UUID_V4, 'id must be a UUID v4'),\n actor: actorSchema,\n verb: z.object({\n id: z.string().regex(IRI, 'verb.id must be an IRI'),\n display: langMap,\n }),\n object: z.object({\n objectType: z.literal('Activity'),\n id: z.string().regex(IRI, 'object.id must be an IRI'),\n definition: z\n .object({\n name: langMap.optional(),\n description: langMap.optional(),\n type: z.string().optional(),\n interactionType: z.string().optional(),\n correctResponsesPattern: z.array(z.string()).optional(),\n choices: z.array(z.object({ id: z.string(), description: langMap.optional() })).optional(),\n extensions: extensions.optional(),\n })\n .optional(),\n }),\n result: z\n .object({\n // xAPI 1.0.3 permits scaled in [-1, 1]; the SDK only emits [0, 1].\n score: z\n .object({\n scaled: z.number().min(-1).max(1),\n raw: z.number().optional(),\n min: z.number().optional(),\n max: z.number().optional(),\n })\n .optional(),\n success: z.boolean().optional(),\n completion: z.boolean().optional(),\n duration: z.string().regex(/^P/, 'duration must be an ISO 8601 duration').optional(),\n response: z.string().optional(),\n extensions: extensions.optional(),\n })\n .optional(),\n context: z\n .object({\n platform: z.string().optional(),\n language: z.string().optional(),\n contextActivities: z\n .object({\n parent: z\n .array(z.object({ objectType: z.literal('Activity'), id: z.string() }))\n .optional(),\n grouping: z\n .array(z.object({ objectType: z.literal('Activity'), id: z.string() }))\n .optional(),\n category: z\n .array(z.object({ objectType: z.literal('Activity'), id: z.string() }))\n .optional(),\n other: z\n .array(z.object({ objectType: z.literal('Activity'), id: z.string() }))\n .optional(),\n })\n .optional(),\n extensions: extensions.optional(),\n })\n .optional(),\n timestamp: z\n .string()\n .refine((value) => !Number.isNaN(Date.parse(value)), 'timestamp must be ISO 8601'),\n version: z.literal('1.0.3'),\n});\n\n/**\n * The one global this module reads by name. Declared here, not globally: this\n * package compiles without Node's types on purpose, and nothing else in it may\n * come to rely on `process`.\n */\ndeclare const process: { env: { NODE_ENV?: string } };\n\n/**\n * Whether this is a production build.\n *\n * **The literal `process.env.NODE_ENV`, spelled exactly so.** It is the one\n * expression bundlers replace at build time, and a browser has no `process` to\n * read at run time. The reading this replaces,\n * `globalThis.process?.env?.NODE_ENV`, is not that expression, so no bundler\n * touched it, and in a browser it found no `process` and answered \"not\n * production\" in every production app — so a malformed statement threw there\n * instead of being logged and sent. Tests running in Node never saw it,\n * because Node has a `process`.\n *\n * This package's own build must leave the literal in its output, for the\n * consumer's bundler to replace. The `try` covers code that reaches a runtime\n * unbundled, with no `process` at all: that is not production, as it always\n * was.\n */\nfunction isProduction(): boolean {\n try {\n return process.env.NODE_ENV === 'production';\n } catch {\n return false;\n }\n}\n\n/**\n * Validates a constructed {@link XAPIStatement} against the xAPI 1.0.3\n * structural contract.\n *\n * In development a structural failure throws (caught early); in production it\n * logs a warning and returns (the statement is still sent — see the design's\n * Error Handling table). Uses a `zod/v4` schema rather than `ajv` + an\n * external JSON Schema to keep `lk-core` dependency-free.\n *\n * NOTE: `ActivitySchemaError` is reused here per the task spec; its\n * `activityType` field carries the sentinel `'xAPIStatement'`. A dedicated\n * `XAPIValidationError` would be semantically cleaner — flagged for review.\n */\nexport function validateXAPIStatement(statement: XAPIStatement): void {\n const result = statementSchema.safeParse(statement);\n if (result.success) {\n return;\n }\n\n const errors: ValidationError[] = result.error.issues.map((issue) => ({\n path: issue.path.map(String),\n message: issue.message,\n code: issue.code,\n }));\n\n if (isProduction()) {\n console.warn('[learning-kit] Invalid xAPI statement (sent anyway):', errors);\n return;\n }\n\n throw new ActivitySchemaError('xAPIStatement', errors);\n}\n","/**\n * The set of xAPI verbs emitted by SDK activities, keyed by a stable\n * identifier mapped to its canonical xAPI verb IRI (xAPI 1.0.3 / ADL registry).\n */\nexport const XAPIVerb = {\n ANSWERED: 'http://adlnet.gov/expapi/verbs/answered',\n COMPLETED: 'http://adlnet.gov/expapi/verbs/completed',\n EXPERIENCED: 'http://adlnet.gov/expapi/verbs/experienced',\n INTERACTED: 'http://adlnet.gov/expapi/verbs/interacted',\n ATTEMPTED: 'http://adlnet.gov/expapi/verbs/attempted',\n PASSED: 'http://adlnet.gov/expapi/verbs/passed',\n FAILED: 'http://adlnet.gov/expapi/verbs/failed',\n WATCHED: 'https://w3id.org/xapi/video/verbs/watched',\n /**\n * Emitted for deferred-grading submissions (e.g. written-response): the\n * learner has submitted work whose grade does not exist yet, so `answered`\n * (which implies a scored response) would be wrong. xAPI 1.0.3 defines no\n * canonical \"submit\" verb; the Activity Streams 1.0 IRI is the established\n * community choice.\n */\n SUBMITTED: 'http://activitystrea.ms/schema/1.0/submit',\n /**\n * Emitted when an asynchronous grader produces a grade for work that was\n * previously only SUBMITTED. Distinct from `answered`, which asserts the\n * grade existed at submission time — here the learner acted earlier and the\n * grade arrived later, often from a different actor (an AI or a teacher).\n */\n SCORED: 'http://adlnet.gov/expapi/verbs/scored',\n} as const;\n\n/** Union of the valid `XAPIVerb` keys. */\nexport type XAPIVerbKey = keyof typeof XAPIVerb;\n\n/**\n * Default `en-US` display label for each verb, used to populate\n * `XAPIVerbObject.display` when the builder resolves a verb key.\n */\nexport const XAPI_VERB_DISPLAY: Record<XAPIVerbKey, Record<string, string>> = {\n ANSWERED: { 'en-US': 'answered' },\n COMPLETED: { 'en-US': 'completed' },\n EXPERIENCED: { 'en-US': 'experienced' },\n INTERACTED: { 'en-US': 'interacted' },\n ATTEMPTED: { 'en-US': 'attempted' },\n PASSED: { 'en-US': 'passed' },\n FAILED: { 'en-US': 'failed' },\n WATCHED: { 'en-US': 'watched' },\n SUBMITTED: { 'en-US': 'submitted' },\n SCORED: { 'en-US': 'scored' },\n};\n","import { getActivityTypeDescriptor } from '../registry/index.js';\nimport type { ScoringResult } from '../types/activity.js';\nimport type {\n XAPIActor,\n XAPIContext,\n XAPIObject,\n XAPIResult,\n XAPIStatement,\n} from '../types/xapi.js';\nimport { validateXAPIStatement } from './validators.js';\nimport { XAPI_VERB_DISPLAY, XAPIVerb, type XAPIVerbKey } from './verbs.js';\n\n/** Caller-supplied activity object descriptor (mapped to an xAPI Activity). */\nexport interface XAPIObjectParams {\n /** Activity IRI. */\n id: string;\n name?: Record<string, string>;\n description?: Record<string, string>;\n /** Activity type IRI. */\n type?: string;\n /** xAPI cmi.interaction type (e.g. `choice`, `fill-in`, `long-fill-in`). */\n interactionType?: string;\n /** Correct-responses patterns, per the xAPI CRP format. */\n correctResponsesPattern?: string[];\n /** For choice-family interactions: the available components. */\n choices?: Array<{ id: string; description?: Record<string, string> }>;\n}\n\n/** Parameters for the generic {@link xAPIBuilder.buildStatement}. */\nexport interface XAPIStatementParams {\n actor: XAPIActor;\n verb: XAPIVerbKey;\n object: XAPIObjectParams;\n result?: XAPIResult;\n context?: XAPIContext;\n}\n\n/** Parameters for {@link xAPIBuilder.buildAnsweredStatement} (verb = ANSWERED). */\nexport interface AnsweredStatementParams {\n actor: XAPIActor;\n object: XAPIObjectParams;\n scoringResult: ScoringResult;\n timeSpentMs: number;\n /** Serialized learner response string. */\n response?: string;\n context?: XAPIContext;\n resultExtensions?: Record<string, unknown>;\n}\n\n/**\n * Parameters for {@link xAPIBuilder.buildSubmittedStatement} (verb =\n * SUBMITTED — deferred-grading submissions). Carries NO score, success, or\n * completion: the grade does not exist yet.\n */\nexport interface SubmittedStatementParams {\n actor: XAPIActor;\n object: XAPIObjectParams;\n timeSpentMs: number;\n /** Serialized learner response string (e.g. the submitted text). */\n response?: string;\n context?: XAPIContext;\n resultExtensions?: Record<string, unknown>;\n}\n\n/** Parameters for {@link xAPIBuilder.buildCompletedStatement} (verb = COMPLETED). */\nexport interface CompletedStatementParams {\n actor: XAPIActor;\n object: XAPIObjectParams;\n scoringResult?: ScoringResult;\n timeSpentMs: number;\n context?: XAPIContext;\n resultExtensions?: Record<string, unknown>;\n}\n\n/**\n * Converts a millisecond duration to an ISO 8601 seconds string with\n * centisecond precision (`PT1.23S`), per the xAPI 1.0.3 recommendation of\n * 0.01-second accuracy. Sub-second durations are preserved (previously any\n * duration under 500 ms collapsed to `PT0S`). Negative inputs (clock skew)\n * clamp to zero — a negative ISO duration is invalid.\n */\nfunction msToIsoDuration(ms: number): string {\n return `PT${(Math.round(Math.max(0, ms) / 10) / 100).toFixed(2)}S`;\n}\n\n/**\n * UUID v4 that works outside secure contexts. `crypto.randomUUID` is\n * SecureContext-gated (undefined on plain-http LAN/staging origins), and a\n * statement is built at SUBMIT time — throwing here would lose the learner's\n * answer. `crypto.getRandomValues` is NOT gated, so the fallback still emits\n * a spec-valid v4 UUID (the statement validator enforces the v4 format).\n */\nfunction uuidv4(): string {\n const c = (\n globalThis as {\n crypto?: { randomUUID?: () => string; getRandomValues?: (a: Uint8Array) => Uint8Array };\n }\n ).crypto;\n if (c?.randomUUID) {\n return c.randomUUID();\n }\n const bytes = new Uint8Array(16);\n if (c?.getRandomValues) {\n c.getRandomValues(bytes);\n } else {\n for (let i = 0; i < 16; i += 1) {\n bytes[i] = Math.floor(Math.random() * 256);\n }\n }\n bytes[6] = ((bytes[6] as number) & 0x0f) | 0x40;\n bytes[8] = ((bytes[8] as number) & 0x3f) | 0x80;\n const hex = [...bytes].map((b) => b.toString(16).padStart(2, '0')).join('');\n return `${hex.slice(0, 8)}-${hex.slice(8, 12)}-${hex.slice(12, 16)}-${hex.slice(16, 20)}-${hex.slice(20)}`;\n}\n\n/** Builds the xAPI Activity object, including `definition` only when populated. */\nfunction buildObject(params: XAPIObjectParams): XAPIObject {\n const definition: NonNullable<XAPIObject['definition']> = {\n ...(params.name !== undefined ? { name: params.name } : {}),\n ...(params.description !== undefined ? { description: params.description } : {}),\n ...(params.type !== undefined ? { type: params.type } : {}),\n ...(params.interactionType !== undefined ? { interactionType: params.interactionType } : {}),\n ...(params.correctResponsesPattern !== undefined\n ? { correctResponsesPattern: params.correctResponsesPattern }\n : {}),\n ...(params.choices !== undefined ? { choices: params.choices } : {}),\n };\n return {\n objectType: 'Activity',\n id: params.id,\n ...(Object.keys(definition).length > 0 ? { definition } : {}),\n };\n}\n\n/**\n * Maps a {@link ScoringResult} + timing to an {@link XAPIResult} per the\n * normative mapping in the design document.\n */\nfunction buildResult(\n timeSpentMs: number,\n scoringResult: ScoringResult | undefined,\n resultExtensions: Record<string, unknown> | undefined,\n response: string | undefined,\n): XAPIResult {\n return {\n completion: true,\n duration: msToIsoDuration(timeSpentMs),\n ...(scoringResult !== undefined\n ? {\n score: {\n scaled: scoringResult.score,\n raw: scoringResult.score,\n min: 0,\n max: scoringResult.maxScore,\n },\n success: scoringResult.passed,\n }\n : {}),\n ...(response !== undefined ? { response } : {}),\n ...(resultExtensions !== undefined ? { extensions: resultExtensions } : {}),\n };\n}\n\n/**\n * Constructs xAPI 1.0.3 Statements. Every call stamps a fresh UUID v4 `id`,\n * an ISO 8601 `timestamp`, and `version: '1.0.3'`. Not pure by design —\n * statements are unique events.\n */\nexport const xAPIBuilder = {\n buildStatement(params: XAPIStatementParams): XAPIStatement {\n const statement: XAPIStatement = {\n id: uuidv4(),\n actor: params.actor,\n verb: {\n id: XAPIVerb[params.verb],\n display: XAPI_VERB_DISPLAY[params.verb],\n },\n object: buildObject(params.object),\n ...(params.result !== undefined ? { result: params.result } : {}),\n ...(params.context !== undefined ? { context: params.context } : {}),\n timestamp: new Date().toISOString(),\n version: '1.0.3',\n };\n // Design xAPIBuilder step 4: validate every statement (throws in dev,\n // warns in prod). All build*Statement helpers route through here.\n validateXAPIStatement(statement);\n return statement;\n },\n\n buildAnsweredStatement(params: AnsweredStatementParams): XAPIStatement {\n return this.buildStatement({\n actor: params.actor,\n verb: 'ANSWERED',\n object: params.object,\n result: buildResult(\n params.timeSpentMs,\n params.scoringResult,\n params.resultExtensions,\n params.response,\n ),\n ...(params.context !== undefined ? { context: params.context } : {}),\n });\n },\n\n /**\n * Builds a statement for a deferred-grading submission (e.g. a written\n * response). Verb is SUBMITTED and the result deliberately omits `score`,\n * `success`, and `completion` — none of them exist until the asynchronous\n * grader runs; only `duration`, `response`, and extensions are recorded.\n */\n buildSubmittedStatement(params: SubmittedStatementParams): XAPIStatement {\n return this.buildStatement({\n actor: params.actor,\n verb: 'SUBMITTED',\n object: params.object,\n result: {\n duration: msToIsoDuration(params.timeSpentMs),\n ...(params.response !== undefined ? { response: params.response } : {}),\n ...(params.resultExtensions !== undefined ? { extensions: params.resultExtensions } : {}),\n },\n ...(params.context !== undefined ? { context: params.context } : {}),\n });\n },\n\n buildCompletedStatement(params: CompletedStatementParams): XAPIStatement {\n return this.buildStatement({\n actor: params.actor,\n verb: 'COMPLETED',\n object: params.object,\n result: buildResult(\n params.timeSpentMs,\n params.scoringResult,\n params.resultExtensions,\n undefined,\n ),\n ...(params.context !== undefined ? { context: params.context } : {}),\n });\n },\n};\n\n/**\n * Builds the xAPI `object.definition` interop fields for an activity from its\n * REGISTERED descriptor, rather than having every renderer hand-roll them.\n *\n * `ActivityTypeDescriptor.interop` declares the activity-type IRI, the\n * cmi.interaction type and how to derive `correctResponsesPattern`; before\n * this, those fields had no reader anywhere and each component rebuilt the\n * same strings inline — the same \"declared but never used\" defect the SDK\n * fixed elsewhere. Reading them here also means a consumer-registered type\n * gets correct interop for free.\n *\n * Returns an empty object for an unregistered type or one that declares no\n * interop, so it is always safe to spread.\n */\nexport function xapiDefinitionFor(data: { type: string }): Partial<XAPIObjectParams> {\n const descriptor = getActivityTypeDescriptor(data.type);\n const interop = descriptor?.interop;\n if (interop === undefined) {\n return {};\n }\n const pattern = interop.correctResponsesPattern?.(data);\n return {\n ...(interop.xapiActivityTypeIri !== undefined ? { type: interop.xapiActivityTypeIri } : {}),\n ...(interop.xapiInteractionType !== undefined\n ? { interactionType: interop.xapiInteractionType }\n : {}),\n ...(pattern !== undefined && pattern.length > 0 ? { correctResponsesPattern: pattern } : {}),\n };\n}\n"],"mappings":"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"}
package/dist/xapi.cjs CHANGED
@@ -1,5 +1,5 @@
1
1
  Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
2
- const require_xapi = require("./xapi-7btSpx6v.cjs");
2
+ const require_xapi = require("./xapi-Dyqcl3JK.cjs");
3
3
  exports.XAPIVerb = require_xapi.XAPIVerb;
4
4
  exports.XAPI_VERB_DISPLAY = require_xapi.XAPI_VERB_DISPLAY;
5
5
  exports.validateXAPIStatement = require_xapi.validateXAPIStatement;
package/dist/xapi.d.cts CHANGED
@@ -1,2 +1,2 @@
1
- import { a as XAPIObjectParams, c as xapiDefinitionFor, d as XAPI_VERB_DISPLAY, i as SubmittedStatementParams, l as XAPIVerb, n as AnsweredStatementParams, o as XAPIStatementParams, r as CompletedStatementParams, s as xAPIBuilder, t as validateXAPIStatement, u as XAPIVerbKey } from "./index-XCCoPoTU.cjs";
1
+ import { a as XAPIObjectParams, c as xapiDefinitionFor, d as XAPI_VERB_DISPLAY, i as SubmittedStatementParams, l as XAPIVerb, n as AnsweredStatementParams, o as XAPIStatementParams, r as CompletedStatementParams, s as xAPIBuilder, t as validateXAPIStatement, u as XAPIVerbKey } from "./index-DMh3OYSb.cjs";
2
2
  export { type AnsweredStatementParams, type CompletedStatementParams, type SubmittedStatementParams, type XAPIObjectParams, type XAPIStatementParams, XAPIVerb, type XAPIVerbKey, XAPI_VERB_DISPLAY, validateXAPIStatement, xAPIBuilder, xapiDefinitionFor };
package/dist/xapi.d.ts CHANGED
@@ -1,2 +1,2 @@
1
- import { a as XAPIObjectParams, c as xapiDefinitionFor, d as XAPI_VERB_DISPLAY, i as SubmittedStatementParams, l as XAPIVerb, n as AnsweredStatementParams, o as XAPIStatementParams, r as CompletedStatementParams, s as xAPIBuilder, t as validateXAPIStatement, u as XAPIVerbKey } from "./index-BU99GFTl.js";
1
+ import { a as XAPIObjectParams, c as xapiDefinitionFor, d as XAPI_VERB_DISPLAY, i as SubmittedStatementParams, l as XAPIVerb, n as AnsweredStatementParams, o as XAPIStatementParams, r as CompletedStatementParams, s as xAPIBuilder, t as validateXAPIStatement, u as XAPIVerbKey } from "./index-CtoPhJAH.js";
2
2
  export { type AnsweredStatementParams, type CompletedStatementParams, type SubmittedStatementParams, type XAPIObjectParams, type XAPIStatementParams, XAPIVerb, type XAPIVerbKey, XAPI_VERB_DISPLAY, validateXAPIStatement, xAPIBuilder, xapiDefinitionFor };
package/dist/xapi.js CHANGED
@@ -1 +1 @@
1
- export { r as XAPIVerb, i as XAPI_VERB_DISPLAY, a as validateXAPIStatement, t as xAPIBuilder, n as xapiDefinitionFor } from "./xapi-Cgicg-zU.js";
1
+ export { r as XAPIVerb, i as XAPI_VERB_DISPLAY, a as validateXAPIStatement, t as xAPIBuilder, n as xapiDefinitionFor } from "./xapi-gCAo549Q.js";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@intellectif/lk-core",
3
- "version": "1.7.0",
3
+ "version": "1.8.0",
4
4
  "description": "Framework-free assessment core: activity validation, pure scoring, rubric & deferred grading, weighted assessment composition, exam attempt plans, and xAPI 1.0.3. Custom activity types take any Standard Schema.",
5
5
  "keywords": [
6
6
  "assessment",
@@ -96,7 +96,7 @@
96
96
  "devDependencies": {
97
97
  "@vitest/coverage-v8": "^4.1.6",
98
98
  "fast-check": "^4.10.2",
99
- "tsdown": "0.23.2",
99
+ "tsdown": "0.23.3",
100
100
  "vitest": "^4.1.6"
101
101
  },
102
102
  "license": "MIT",
package/vectors/README.md CHANGED
@@ -232,3 +232,26 @@ the one you installed; record that yourself beside any grade you store.
232
232
  Adding a regenerate-after-version step to the release was considered and
233
233
  rejected: it would put a step that can fail *after* the version bump, which is
234
234
  strictly worse than a string that reads one version behind.
235
+
236
+ ## The variants corpus (1.8)
237
+
238
+ `variants.json` holds requests to `aiVariantsRequest`, canned model replies, and
239
+ what `checkAiVariants` made of them — plus two papers for the paper codes of
240
+ `critiqueDrafts`: a correct reply, each structure fault a variant can have, a
241
+ length out of band, a near copy of the exemplar and of another form, a repeated
242
+ key, a missing variant, a recording with nothing to say what it says, a picture
243
+ to describe, and keys spread from a fixed seed. Ids come from a counter, so
244
+ every outcome is the same on every run.
245
+
246
+ It records the outcome a host branches on — each variant's status, the codes
247
+ and paths of its issues, mismatches and findings, its pairs, skipped and
248
+ missing exemplars, and the option order where keys were spread — not the
249
+ messages. Unlike `scoring.json` it is not a grade-stability promise: a minor may
250
+ refine a rule behind a code, and the corpus moves with it. Replay it to see what
251
+ changed in the build you install:
252
+
253
+ ```js
254
+ const { replayVariants } = await import(pathToFileURL(join(root, 'vectors/variants.mjs')).href);
255
+ const variants = JSON.parse(readFileSync(join(root, 'vectors/variants.json'), 'utf8'));
256
+ const changed = replayVariants(core, variants).filter((result) => !result.ok);
257
+ ```
@@ -0,0 +1,20 @@
1
+ export interface VariantVectorCase {
2
+ name: string;
3
+ call: 'variants' | 'critiqueDrafts';
4
+ input?: unknown;
5
+ reply?: unknown;
6
+ entries?: unknown[];
7
+ expected: unknown;
8
+ }
9
+
10
+ export interface VariantVectorCorpus {
11
+ corpusVersion: string;
12
+ cases: VariantVectorCase[];
13
+ }
14
+
15
+ export function outcomeOf(core: unknown, one: VariantVectorCase): unknown;
16
+
17
+ export function replayVariants(
18
+ core: unknown,
19
+ corpus: VariantVectorCorpus,
20
+ ): { name: string; ok: boolean; actual: unknown; expected: unknown }[];