@intellectif/lk-core 0.16.0 → 0.18.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 (48) hide show
  1. package/CHANGELOG.md +75 -0
  2. package/README.md +2 -2
  3. package/dist/{activity-DcxtpX7Z.d.cts → activity-HH8dxN1v.d.cts} +234 -4
  4. package/dist/{activity-DcxtpX7Z.d.ts → activity-HH8dxN1v.d.ts} +234 -4
  5. package/dist/{chunk-FJJ2GVBA.cjs → chunk-2CV6NU32.cjs} +19 -19
  6. package/dist/{chunk-FJJ2GVBA.cjs.map → chunk-2CV6NU32.cjs.map} +1 -1
  7. package/dist/{chunk-6P6XK2LI.cjs → chunk-COBK2RUX.cjs} +74 -39
  8. package/dist/chunk-COBK2RUX.cjs.map +1 -0
  9. package/dist/{chunk-IRUD73IQ.js → chunk-D3GP5MET.js} +683 -638
  10. package/dist/chunk-D3GP5MET.js.map +1 -0
  11. package/dist/{chunk-F7UOLKWV.cjs → chunk-D4TOPSHV.cjs} +518 -473
  12. package/dist/chunk-D4TOPSHV.cjs.map +1 -0
  13. package/dist/{chunk-VFTVZJO5.cjs → chunk-EOFWSGLU.cjs} +4 -4
  14. package/dist/{chunk-VFTVZJO5.cjs.map → chunk-EOFWSGLU.cjs.map} +1 -1
  15. package/dist/{chunk-S63IOKFP.js → chunk-MMEQKFFQ.js} +44 -9
  16. package/dist/chunk-MMEQKFFQ.js.map +1 -0
  17. package/dist/{chunk-OXF7VT7S.js → chunk-X5DAXBJI.js} +2 -2
  18. package/dist/{chunk-GOZGBVJP.js → chunk-Z7QQZ53L.js} +2 -2
  19. package/dist/{chunk-GOZGBVJP.js.map → chunk-Z7QQZ53L.js.map} +1 -1
  20. package/dist/{index-DRJqwO2y.d.ts → index-BrBBUb1i.d.ts} +141 -83
  21. package/dist/{index-BWpwZRQw.d.cts → index-DejnxQpK.d.cts} +141 -83
  22. package/dist/index.cjs +547 -127
  23. package/dist/index.cjs.map +1 -1
  24. package/dist/index.d.cts +145 -9
  25. package/dist/index.d.ts +145 -9
  26. package/dist/index.js +427 -7
  27. package/dist/index.js.map +1 -1
  28. package/dist/schemas.cjs +5 -3
  29. package/dist/schemas.cjs.map +1 -1
  30. package/dist/schemas.d.cts +2 -2
  31. package/dist/schemas.d.ts +2 -2
  32. package/dist/schemas.js +4 -2
  33. package/dist/scoring.cjs +3 -3
  34. package/dist/scoring.d.cts +33 -5
  35. package/dist/scoring.d.ts +33 -5
  36. package/dist/scoring.js +2 -2
  37. package/dist/xapi.cjs +3 -3
  38. package/dist/xapi.d.cts +1 -1
  39. package/dist/xapi.d.ts +1 -1
  40. package/dist/xapi.js +2 -2
  41. package/package.json +1 -1
  42. package/vectors/README.md +9 -3
  43. package/vectors/scoring.json +1258 -10
  44. package/dist/chunk-6P6XK2LI.cjs.map +0 -1
  45. package/dist/chunk-F7UOLKWV.cjs.map +0 -1
  46. package/dist/chunk-IRUD73IQ.js.map +0 -1
  47. package/dist/chunk-S63IOKFP.js.map +0 -1
  48. /package/dist/{chunk-OXF7VT7S.js.map → chunk-X5DAXBJI.js.map} +0 -0
@@ -1,7 +1,7 @@
1
1
  "use strict";Object.defineProperty(exports, "__esModule", {value: true}); function _optionalChain(ops) { let lastAccessLHS = undefined; let value = ops[0]; let i = 1; while (i < ops.length) { const op = ops[i]; const fn = ops[i + 1]; i += 2; if ((op === 'optionalAccess' || op === 'optionalCall') && value == null) { return undefined; } if (op === 'access' || op === 'optionalAccess') { lastAccessLHS = value; value = fn(value); } else if (op === 'call' || op === 'optionalCall') { value = fn((...args) => value.call(lastAccessLHS, ...args)); lastAccessLHS = undefined; } } return value; }
2
2
 
3
3
 
4
- var _chunkF7UOLKWVcjs = require('./chunk-F7UOLKWV.cjs');
4
+ var _chunkD4TOPSHVcjs = require('./chunk-D4TOPSHV.cjs');
5
5
 
6
6
  // src/xapi/validators.ts
7
7
  var _v4 = require('zod/v4');
@@ -86,7 +86,7 @@ function validateXAPIStatement(statement) {
86
86
  console.warn("[learning-kit] Invalid xAPI statement (sent anyway):", errors);
87
87
  return;
88
88
  }
89
- throw new (0, _chunkF7UOLKWVcjs.ActivitySchemaError)("xAPIStatement", errors);
89
+ throw new (0, _chunkD4TOPSHVcjs.ActivitySchemaError)("xAPIStatement", errors);
90
90
  }
91
91
 
92
92
  // src/xapi/verbs.ts
@@ -249,7 +249,7 @@ var xAPIBuilder = {
249
249
  }
250
250
  };
251
251
  function xapiDefinitionFor(data) {
252
- const descriptor = _chunkF7UOLKWVcjs.getActivityTypeDescriptor.call(void 0, data.type);
252
+ const descriptor = _chunkD4TOPSHVcjs.getActivityTypeDescriptor.call(void 0, data.type);
253
253
  const interop = _optionalChain([descriptor, 'optionalAccess', _3 => _3.interop]);
254
254
  if (interop === void 0) {
255
255
  return {};
@@ -269,4 +269,4 @@ function xapiDefinitionFor(data) {
269
269
 
270
270
 
271
271
  exports.validateXAPIStatement = validateXAPIStatement; exports.XAPIVerb = XAPIVerb; exports.XAPI_VERB_DISPLAY = XAPI_VERB_DISPLAY; exports.xAPIBuilder = xAPIBuilder; exports.xapiDefinitionFor = xapiDefinitionFor;
272
- //# sourceMappingURL=chunk-VFTVZJO5.cjs.map
272
+ //# sourceMappingURL=chunk-EOFWSGLU.cjs.map
@@ -1 +1 @@
1
- {"version":3,"sources":["/home/runner/work/learning-kit/learning-kit/packages/lk-core/dist/chunk-VFTVZJO5.cjs","../src/xapi/validators.ts","../src/xapi/verbs.ts","../src/xapi/builder.ts"],"names":[],"mappings":"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ACF,EAAA;AAEA,EAAA;AACE,IAAA;AACE,MAAA;AACA,MAAA;AACA,MAAA;AACA,MAAA;AACE,QAAA;AACA,QAAA;AACA,QAAA;AACA,QAAA;AACF,MAAA;AACI,MAAA;AACL,IAAA;AACH,EAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAQA,EAAA;AACE,IAAA;AACE,MAAA;AACA,MAAA;AACA,MAAA;AACA,MAAA;AACE,QAAA;AACA,QAAA;AACA,QAAA;AACF,MAAA;AACI,MAAA;AACL,IAAA;AACH,EAAA;AAEA,EAAA;AACE,IAAA;AACE,MAAA;AACA,MAAA;AACA,MAAA;AACA,MAAA;AACE,QAAA;AACA,QAAA;AACA,QAAA;AACA,QAAA;AACF,MAAA;AACI,MAAA;AACL,IAAA;AACH,EAAA;AACF;AAgBgB;AACR,EAAA;AACA,EAAA;AACF,EAAA;AACF,IAAA;AACF,EAAA;AACM,EAAA;AACC,EAAA;AACD,IAAA;AACA,IAAA;AAGA,IAAA;AACN,EAAA;AACF;AHLU;AACA;AACA;AACA;AACA;AACA;AACA;AACA","file":"/home/runner/work/learning-kit/learning-kit/packages/lk-core/dist/chunk-VFTVZJO5.cjs","sourcesContent":[null,"import { 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 (design decision recorded per Task 25.4).\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 (Req 22.7).\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"]}
1
+ {"version":3,"sources":["/home/runner/work/learning-kit/learning-kit/packages/lk-core/dist/chunk-EOFWSGLU.cjs","../src/xapi/validators.ts","../src/xapi/verbs.ts","../src/xapi/builder.ts"],"names":[],"mappings":"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ACF,EAAA;AAEA,EAAA;AACE,IAAA;AACE,MAAA;AACA,MAAA;AACA,MAAA;AACA,MAAA;AACE,QAAA;AACA,QAAA;AACA,QAAA;AACA,QAAA;AACF,MAAA;AACI,MAAA;AACL,IAAA;AACH,EAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAQA,EAAA;AACE,IAAA;AACE,MAAA;AACA,MAAA;AACA,MAAA;AACA,MAAA;AACE,QAAA;AACA,QAAA;AACA,QAAA;AACF,MAAA;AACI,MAAA;AACL,IAAA;AACH,EAAA;AAEA,EAAA;AACE,IAAA;AACE,MAAA;AACA,MAAA;AACA,MAAA;AACA,MAAA;AACE,QAAA;AACA,QAAA;AACA,QAAA;AACA,QAAA;AACF,MAAA;AACI,MAAA;AACL,IAAA;AACH,EAAA;AACF;AAgBgB;AACR,EAAA;AACA,EAAA;AACF,EAAA;AACF,IAAA;AACF,EAAA;AACM,EAAA;AACC,EAAA;AACD,IAAA;AACA,IAAA;AAGA,IAAA;AACN,EAAA;AACF;AHLU;AACA;AACA;AACA;AACA;AACA;AACA;AACA","file":"/home/runner/work/learning-kit/learning-kit/packages/lk-core/dist/chunk-EOFWSGLU.cjs","sourcesContent":[null,"import { 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 (design decision recorded per Task 25.4).\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 (Req 22.7).\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"]}
@@ -14,7 +14,7 @@ import {
14
14
  dictationReferenceWords,
15
15
  getActivityTypeDescriptor,
16
16
  normalizeDictationText
17
- } from "./chunk-IRUD73IQ.js";
17
+ } from "./chunk-D3GP5MET.js";
18
18
 
19
19
  // src/is-redacted.ts
20
20
  function isRedacted(data) {
@@ -99,6 +99,12 @@ function selectFeedback(activityData, passed) {
99
99
  return (passed ? feedback.correct : feedback.incorrect) ?? null;
100
100
  }
101
101
 
102
+ // src/scoring/grade-numbers.ts
103
+ var OVERSHOOT = 1e-9;
104
+ function isGradeInRange(score2, maxScore) {
105
+ return Number.isFinite(maxScore) && maxScore > 0 && Number.isFinite(score2) && score2 >= 0 && score2 - maxScore <= maxScore * OVERSHOOT;
106
+ }
107
+
102
108
  // src/grading.ts
103
109
  function gradeFromRubric(criteria, activityData, options = {}) {
104
110
  const rounding = roundingPolicyOf(options?.rounding);
@@ -147,12 +153,19 @@ function gradeFromRubric(criteria, activityData, options = {}) {
147
153
  reason: "Criterion weights do not sum to a positive number, so the weighted total is undefined."
148
154
  };
149
155
  }
156
+ const negativeWeight = scoreable.find((criterion) => (criterion.weight ?? 1) < 0);
157
+ if (negativeWeight !== void 0) {
158
+ return {
159
+ unscorable: true,
160
+ reason: `Criterion "${negativeWeight.name}" has weight ${String(negativeWeight.weight)}; a weight must be zero or more.`
161
+ };
162
+ }
150
163
  const weighted = scoreable.reduce(
151
164
  (sum, criterion) => sum + ratioOf(criterion) * (criterion.weight ?? 1),
152
165
  0
153
166
  );
154
167
  const rawScore = weighted / totalWeight;
155
- if (!Number.isFinite(rawScore)) {
168
+ if (!Number.isFinite(totalWeight) || !Number.isFinite(rawScore)) {
156
169
  return {
157
170
  unscorable: true,
158
171
  reason: "The weighted total is not a finite number, so no grade can be produced."
@@ -170,11 +183,15 @@ function gradeFromRubric(criteria, activityData, options = {}) {
170
183
  };
171
184
  }
172
185
  function outcomeFromGrade(grade) {
186
+ const { score: score2, maxScore } = grade;
187
+ if (!isGradeInRange(score2, maxScore)) {
188
+ return { status: "deferred", reason: "grade_rejected", maxScore: 1, rejectedGrade: grade };
189
+ }
173
190
  return {
174
191
  status: "graded",
175
192
  grade,
176
- score: grade.score,
177
- maxScore: grade.maxScore,
193
+ score: score2,
194
+ maxScore,
178
195
  passed: grade.passed,
179
196
  feedback: grade.feedback
180
197
  };
@@ -187,29 +204,41 @@ function hasGrade(outcome) {
187
204
  function earned(item) {
188
205
  const { outcome } = item;
189
206
  if (hasGrade(outcome)) {
190
- const max = outcome.maxScore > 0 ? outcome.maxScore : 1;
191
- return { state: "graded", points: outcome.score / max * item.points };
207
+ const { score: score2, maxScore } = outcome;
208
+ if (!isGradeInRange(score2, maxScore)) {
209
+ return { state: "rejected" };
210
+ }
211
+ return { state: "graded", points: score2 / maxScore * item.points };
192
212
  }
193
213
  if (outcome.status === "deferred") {
194
- return { state: "pending" };
214
+ return outcome.reason === "grade_rejected" ? { state: "rejected" } : { state: "pending" };
195
215
  }
196
216
  return { state: "unscorable" };
197
217
  }
218
+ function rejectedField(slotIds) {
219
+ return slotIds.length > 0 ? { rejectedSlotIds: slotIds } : {};
220
+ }
198
221
  function composeAssessmentScore(sections, policy) {
199
222
  const pendingAll = [];
223
+ const rejectedAll = [];
200
224
  const unscorableAll = [];
201
225
  const partials = sections.map((section) => {
202
226
  let earnedPoints = 0;
203
227
  let gradedMaxPoints = 0;
204
228
  let maxPoints = 0;
205
229
  const pendingSlotIds = [];
230
+ const rejectedSlotIds = [];
206
231
  const unscorableSlotIds = [];
207
232
  for (const item of section.items) {
208
233
  maxPoints += item.points;
209
234
  const contribution = earned(item);
210
- if (contribution.state === "pending") {
235
+ if (contribution.state === "pending" || contribution.state === "rejected") {
211
236
  pendingSlotIds.push(item.slotId);
212
237
  pendingAll.push(item.slotId);
238
+ if (contribution.state === "rejected") {
239
+ rejectedSlotIds.push(item.slotId);
240
+ rejectedAll.push(item.slotId);
241
+ }
213
242
  continue;
214
243
  }
215
244
  if (contribution.state === "unscorable") {
@@ -230,6 +259,7 @@ function composeAssessmentScore(sections, policy) {
230
259
  score: roundGrade(raw, policy.rounding),
231
260
  appliedThreshold,
232
261
  pendingSlotIds,
262
+ rejectedSlotIds,
233
263
  unscorableSlotIds
234
264
  };
235
265
  });
@@ -250,6 +280,7 @@ function composeAssessmentScore(sections, policy) {
250
280
  passed: partial.appliedThreshold === null || partial.gradedMaxPoints === 0 ? true : gte(partial.score, partial.appliedThreshold, policy.rounding),
251
281
  appliedThreshold: partial.appliedThreshold,
252
282
  pendingSlotIds: partial.pendingSlotIds,
283
+ ...rejectedField(partial.rejectedSlotIds),
253
284
  unscorableSlotIds: partial.unscorableSlotIds
254
285
  }));
255
286
  const weightedRaw = scored.reduce(
@@ -266,6 +297,7 @@ function composeAssessmentScore(sections, policy) {
266
297
  passFailureReason: null,
267
298
  status,
268
299
  pendingSlotIds: pendingAll,
300
+ ...rejectedField(rejectedAll),
269
301
  unscorableSlotIds: unscorableAll
270
302
  };
271
303
  }
@@ -277,6 +309,7 @@ function composeAssessmentScore(sections, policy) {
277
309
  passFailureReason: null,
278
310
  status,
279
311
  pendingSlotIds: pendingAll,
312
+ ...rejectedField(rejectedAll),
280
313
  unscorableSlotIds: unscorableAll
281
314
  };
282
315
  }
@@ -291,6 +324,7 @@ function composeAssessmentScore(sections, policy) {
291
324
  passFailureReason,
292
325
  status,
293
326
  pendingSlotIds: pendingAll,
327
+ ...rejectedField(rejectedAll),
294
328
  unscorableSlotIds: unscorableAll
295
329
  };
296
330
  }
@@ -1013,6 +1047,7 @@ function evaluate(data, response, options) {
1013
1047
  }
1014
1048
 
1015
1049
  export {
1050
+ isGradeInRange,
1016
1051
  roundGrade,
1017
1052
  gte,
1018
1053
  classifyBand,
@@ -1031,4 +1066,4 @@ export {
1031
1066
  score,
1032
1067
  evaluate
1033
1068
  };
1034
- //# sourceMappingURL=chunk-S63IOKFP.js.map
1069
+ //# sourceMappingURL=chunk-MMEQKFFQ.js.map