npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@superapp_men/submit-assessment-results

v1.0.10

Published

Submit assessment results from SuperApp partner applications via iframe/Capacitor

Readme

@superapp_men/submit-assessment-results

Version: 1.0.9 License: MIT Author: SuperApp Team

Package for partner applications (running inside the SuperApp iframe or Capacitor WebView) to submit assessment results to the SuperApp. The SuperApp forwards the payload to the SubmitAssessmentResults backend endpoint (adding academicYearId and periodWeekSubjectId) and returns the exact backend response to the partner.


Table of Contents


Features

  • Builder / factory to construct skills and questions data in a type-safe way.
  • Client-side validation before calling the SuperApp: the same rules as the backend SubmitAssessmentResultsValidator run first. Invalid payloads get immediate 400-style errors with field-level messages without a round-trip.
  • No academicYearId or periodWeekSubjectId in the partner payload — the SuperApp adds them when calling the API.
  • Exact backend response returned: success (200), validation errors (400), functional errors (422), and technical errors (404, 409, 429, 500).
  • Dual transport support: works in both iframe (postMessage to parent) and Capacitor WebView environments.

Current limitation (upcoming feature): subSkills must be null or an empty array []. Sub-skills are not yet supported; each skill must use questions only. Support for nested sub-skills will be added in a future release.


Installation

npm install @superapp_men/submit-assessment-results

Architecture Overview

Partner App (iframe / Capacitor WebView)
  │
  ├── AssessmentSubmission (builder)   → Constructs payload
  ├── validateSubmitAssessmentPayload  → Client-side validation (mirrors backend)
  └── AssessmentSubmissionClient       → submit(payload)
        │
        ├── 1. Runs client-side validation
        │     └── If invalid → returns { ok: false, statusCode: 400, body: ValidationProblemDetails }
        │
        └── 2. If valid → sends postMessage to SuperApp
              │
              SuperApp (host)
              ├── Listens for "assessment:submit-request"
              ├── Enriches with academicYearId + periodWeekSubjectId
              ├── Calls POST api/v1.0/submit-results
              └── Returns "assessment:submit-response" with exact backend HTTP status + body

Data Dictionary

1. SubmitAssessmentResultsPartnerPayload

The root payload sent by partner apps. The SuperApp enriches it with academicYearId and periodWeekSubjectId before forwarding to the backend.

| Property | Type | Required | Max Length | Description | |----------|------|----------|------------|-------------| | studentId | string | Yes | — | Student GUID (UUID format). Identifies the student taking the assessment. | | partnerCode | string | Yes | 50 chars | Partner application code. Must be one of: "bewise", "ltm", "cantoo", "ekinox", "math-scan" (case-insensitive). | | attemptId | string | Yes | 100 chars | Unique attempt identifier used as an idempotency key. Prevents duplicate submissions. | | isAser | boolean | Yes | — | Set true for ASER (Annual Status of Education Report) positioning assessments; false (default) for regular week assessments. Enables additional validation rules when true. | | totalSkillsInWeek | number | Yes | — | Total number of skills for the week. Must be >= 1 and >= the number of submitted skills. | | skills | SubmittedSkillResultPayload[] | Yes | — | Array of skill results. Must contain at least one skill. |

2. SubmittedSkillResultPayload

Represents a single skill result within the submission.

| Property | Type | Required | Constraints | Description | |----------|------|----------|-------------|-------------| | skillCode | string | Yes | Non-empty | Unique code identifying the skill in the curriculum (e.g. "MATH_ADD_01"). Must match an existing skill code in the system. | | skillOrder | number | Yes | >= 0 (1–6 for ASER) | Display order of the skill within its parent context. For ASER assessments: must be between 1 and 6 inclusive. | | passed | boolean | Yes | true or false | Whether the student passed this skill based on the partner's evaluation. | | titleFr | string | Conditional | — | French title of the skill. At least one of titleFr or titleAr is required for ASER assessments. Optional for non-ASER. | | titleAr | string | Conditional | — | Arabic title of the skill. At least one of titleFr or titleAr is required for ASER assessments. Optional for non-ASER. | | descriptionFr | string | Conditional | — | French description of the skill. At least one of descriptionFr or descriptionAr is required for ASER assessments. Optional for non-ASER. | | descriptionAr | string | Conditional | — | Arabic description of the skill. At least one of descriptionFr or descriptionAr is required for ASER assessments. Optional for non-ASER. | | questions | SubmittedQuestionResultPayload[] | Yes* | >= 1 item | List of question results for this skill. *Required until subSkills feature is released. | | subSkills | SubmittedSkillResultPayload[] | No | Must be null or [] | Not yet supported (upcoming feature). Must be null or empty array. Non-empty subSkills will fail validation. |

3. SubmittedQuestionResultPayload

Represents a single question result within a skill.

| Property | Type | Required | Constraints | Description | |----------|------|----------|-------------|-------------| | questionCode | string | Yes | Non-empty | Unique code identifying the question (e.g. "Q001"). Must be unique within the same skill (case-insensitive). | | isCorrect | boolean | Yes | true or false | Whether the student answered the question correctly. | | questionRole | QuestionRole (number) | Yes | 1, 2, 3, or 4 | Pedagogical role of the question. See QuestionRole Enum. | | questionOrder | number | No | 0–255 | Display order of the question within the skill. Defaults to 0 in the builder. | | responseTime | number \| string | No | 0–3,600,000 ms (1 hour) | Time taken to answer. Number = milliseconds (e.g. 5000); String = "hh:mm:ss" format (e.g. "00:00:05"). | | attemptsCount | number | No | >= 0 | Number of attempts the student made on this question. | | questionTextFr | string | No | — | French text of the question (used for auto-creation if the question doesn't exist). | | questionTextAr | string | No | — | Arabic text of the question (used for auto-creation if the question doesn't exist). | | tags | string | No | — | Comma-separated keywords or labels (e.g. "algebra,addition,level1"). | | metadata | string | No | — | JSON string containing arbitrary metadata (e.g. JSON.stringify({ difficulty: "easy", chapter: 3 })). |

4. QuestionRole Enum

Pedagogical role of the question in the assessment. Required for every question.

| Value | Name | Description | |-------|------|-------------| | 1 | POSITIONING | Used to determine initial skill level (typically in ASER assessments). | | 2 | VALIDATION | Used to validate skill mastery (default for most questions in regular assessments). | | 3 | REMEDIATION | Used after failed validation for practice and reinforcement. | | 4 | BONUS | Optional challenge questions beyond the core assessment. |

import { QuestionRole } from "@superapp_men/submit-assessment-results";

QuestionRole.POSITIONING  // 1
QuestionRole.VALIDATION   // 2
QuestionRole.REMEDIATION  // 3
QuestionRole.BONUS        // 4

Validation Rules

The client-side validator mirrors the backend SubmitAssessmentResultsValidator. All rules are checked before sending to the SuperApp.

Payload-Level Validation Rules

| Field | Rules | Error Messages | |-------|-------|----------------| | studentId | Required, non-empty | "StudentId is required." | | partnerCode | Required, non-empty. Must be one of: bewise, ltm, cantoo, ekinox, math-scan (case-insensitive). Max 50 characters. | "PartnerCode is required." / "PartnerCode must be one of: bewise, ltm, cantoo, ekinox, math-scan." / "PartnerCode must not exceed 50 characters." | | attemptId | Required, non-empty. Max 100 characters. | "AttemptId is required." / "AttemptId must not exceed 100 characters." | | totalSkillsInWeek | Must be a number >= 1. Must be >= the number of submitted skills. | "TotalSkillsInWeek must be at least 1." / "TotalSkillsInWeek must be greater than or equal to the number of submitted skills." | | skills | Required, non-null. Must be a non-empty array. No duplicate SkillCodes (case-insensitive). | "Skills collection is required." / "At least one skill must be submitted." / "Duplicate SkillCode detected in submitted skills." |

ASER-Specific Payload Rules

When isAser is true, additional constraints apply:

| Field | Rules | Error Messages | |-------|-------|----------------| | skills | Minimum 3 skills. Maximum 6 skills. | "ASER assessments require at least 3 skills." / "ASER assessments must not exceed 6 skills." | | totalSkillsInWeek | Must be between 3 and 6. Must equal the number of submitted skills. | "For ASER assessments, TotalSkillsInWeek must be between 3 and 6." / "For ASER assessments, TotalSkillsInWeek must equal the number of submitted skills." |

Skill-Level Validation Rules

| Field | Rule | Error Message | |-------|------|---------------| | skillCode | Required, non-empty | "SkillCode is required." | | skillOrder | Must be a number >= 0 | "SkillOrder must be non-negative." | | passed | Required, must be true or false | "Passed is required and must be true or false." | | subSkills | Must be null or empty array | "SubSkills are not yet supported (upcoming feature). SubSkills must be null or an empty array. Use Questions for now." | | (skill) | Must contain either SubSkills or Questions | "A skill must contain either SubSkills or Questions." | | questions | No duplicate QuestionCodes within the same skill (case-insensitive) | "Duplicate QuestionCode detected within the same skill." |

ASER-Specific Skill Rules

When isAser is true, additional constraints apply per skill:

| Field | Rule | Error Message | |-------|------|---------------| | skillOrder | Must be between 1 and 6 (inclusive) | "For ASER assessments, SkillOrder must be between 1 and 6." | | titleFr / titleAr | At least one must be non-empty | "At least one of TitleFr or TitleAr is required for ASER assessments." | | descriptionFr / descriptionAr | At least one must be non-empty | "At least one of DescriptionFr or DescriptionAr is required for ASER assessments." |

Question-Level Validation Rules

| Field | Rules | Error Messages | |-------|-------|----------------| | questionCode | Required, non-empty | "QuestionCode is required." | | isCorrect | Required, must be true or false | "IsCorrect is required and must be true or false." | | questionOrder | If provided, must be a number between 0 and 255 | "QuestionOrder must be non-negative and not exceed 255." | | questionRole | Required, non-null. Must be 1, 2, 3, or 4. | "QuestionRole is required." / "QuestionRole must be a valid value: POSITIONING (1), VALIDATION (2), REMEDIATION (3), or BONUS (4)." | | responseTime | If provided, must be a number (ms) or string "hh:mm:ss". Must be 0–3,600,000 ms (1 hour). | "ResponseTime must be a number (milliseconds) or a string in 'hh:mm:ss' format." / "ResponseTime must be non-negative and not exceed 3600000 milliseconds (1 hour)." | | attemptsCount | If provided, must be a number >= 0 | "AttemptsCount must be non-negative." |

Cross-Field Validation Rules

| Rule | Description | |------|-------------| | totalSkillsInWeek >= skills.length | The total skills declared for the week must be at least the number of skills submitted. | | ASER: totalSkillsInWeek === skills.length | For ASER assessments, all skills must be submitted (total must equal count). | | No duplicate skillCode (case-insensitive) | All skill codes in the skills array must be unique. | | No duplicate questionCode per skill (case-insensitive) | Within each skill, all question codes must be unique. | | ASER: at least one of titleFr / titleAr per skill | For ASER, each skill must have at least a French or Arabic title. | | ASER: at least one of descriptionFr / descriptionAr per skill | For ASER, each skill must have at least a French or Arabic description. |


Builder API

AssessmentSubmission.builder()

Creates a fluent builder for the full partner payload. Chain methods then call .build().

| Method | Required | Description | |--------|----------|-------------| | .setStudentId(studentId: string) | Yes | Student GUID (UUID). | | .setPartnerCode(code: string) | Yes | Partner application code. Must be one of: "bewise", "ltm", "cantoo", "ekinox", "math-scan". | | .setAttemptId(attemptId: string) | Yes | Unique attempt id (idempotency key). Max 100 chars. | | .setAser(isAser: boolean) | No | Set true for ASER positioning assessments. Default: false. | | .setTotalSkillsInWeek(n: number) | Yes | Total number of skills for the week (>= 1, >= skills count). | | .addSkill(skill) | Yes* | Add a single skill (built via AssessmentSubmission.skill()). | | .addSkills(skills[]) | Yes* | Add multiple skills at once. | | .build() | — | Returns SubmitAssessmentResultsPartnerPayload. |

*At least one skill must be added via addSkill() or addSkills().

AssessmentSubmission.skill(skillCode, skillOrder, passed)

Creates a SkillResultBuilder for one skill.

Constructor parameters (required):

| Parameter | Type | Description | |-----------|------|-------------| | skillCode | string | Unique skill code (e.g. "MATH_ADD_01"). | | skillOrder | number | Display order (>= 0; 1–6 for ASER). | | passed | boolean | Whether the student passed this skill. |

Chained methods (optional):

| Method | Description | |--------|-------------| | .title(titleFr?: string, titleAr?: string) | Set French and/or Arabic title. At least one required for ASER. | | .description(descriptionFr?: string, descriptionAr?: string) | Set French and/or Arabic description. At least one required for ASER. | | .questions(questions[]) | Set question results array. Required (until subSkills is supported). | | .subSkills(subSkills[]) | Set sub-skills array. Not yet supported — will fail validation if non-empty. | | .build() | Returns SubmittedSkillResultPayload. |

AssessmentSubmission.question(questionCode, isCorrect, questionRole)

Creates a QuestionResultBuilder for one question.

Constructor parameters (required):

| Parameter | Type | Default | Description | |-----------|------|---------|-------------| | questionCode | string | — | Unique question code (e.g. "Q001"). | | isCorrect | boolean | — | Whether the student answered correctly. | | questionRole | QuestionRole | VALIDATION (2) | Pedagogical role (1–4). |

Chained methods (optional):

| Method | Description | |--------|-------------| | .order(questionOrder: number) | Display order within the skill (0–255). Default: 0. | | .responseTime(value: number \| string) | Time to answer: ms (number) or "hh:mm:ss" (string). Max 1 hour. | | .attemptsCount(count: number) | Number of attempts (>= 0). | | .questionText(fr?: string, ar?: string) | French and/or Arabic question text. | | .tags(tags: string) | Comma-separated keywords (e.g. "algebra,addition"). | | .metadata(metadata: string) | JSON string with arbitrary metadata. | | .build() | Returns SubmittedQuestionResultPayload. |


Client API

AssessmentSubmissionClient

import { AssessmentSubmissionClient } from "@superapp_men/submit-assessment-results";

const client = new AssessmentSubmissionClient({ timeout: 30000, debug: true });

Constructor config:

| Option | Type | Default | Description | |--------|------|---------|-------------| | timeout | number | 30000 | Request timeout in milliseconds. | | debug | boolean | false | Enable debug console logging. |

Methods:

| Method | Returns | Description | |--------|---------|-------------| | submit(payload) | Promise<SubmitAssessmentResultsApiResult> | Validates payload client-side, then sends to SuperApp via postMessage. Returns the exact backend response. | | setDebug(enabled: boolean) | void | Toggle debug logging at runtime. | | destroy() | void | Clean up listeners and pending timeouts. Call when done. |

submit() behavior:

  1. Runs client-side validation (mirrors backend SubmitAssessmentResultsValidator).
  2. If validation fails: returns immediately with { ok: false, statusCode: 400, body: ValidationProblemDetails }.
  3. If validation passes: sends payload to SuperApp via postMessage and waits for the backend response.

Validation-Only API

Run validation without submitting (e.g. to show errors in the UI before submit):

import {
  validateSubmitAssessmentPayload,
  toValidationProblemDetails,
} from "@superapp_men/submit-assessment-results";

const validation = validateSubmitAssessmentPayload(payload);
if (!validation.valid) {
  // validation.errors: Array<{ key: string, message: string }>
  const details = toValidationProblemDetails(validation.errors);
  // details.errors: Record<string, string[]> (backend-compatible format)
}

validateSubmitAssessmentPayload(payload) returns:

{ valid: boolean; errors: Array<{ key: string; message: string }> }

toValidationProblemDetails(errors) converts to backend-style format:

{ status: 400; title: string; errors: Record<string, string[]> }

Response Types

SubmitAssessmentResultsApiResult

Union type returned by client.submit():

// Success
{ ok: true;  statusCode: number; body: SubmitAssessmentResultsResponse }

// Error
{ ok: false; statusCode: number; body: ValidationProblemDetails | ProblemDetails }

SubmitAssessmentResultsResponse (200 Success)

| Field | Type | Description | |-------|------|-------------| | attemptId | string | The attempt ID echoed back. | | isDuplicate | boolean | true if this attemptId was already submitted (idempotent). | | status | string | Status of the submission. | | message | string \| null | Optional message from the backend. | | serverTimeUtc | string | Server timestamp (UTC). |

ValidationProblemDetails (400)

| Field | Type | Description | |-------|------|-------------| | type | string? | Problem type URI. | | title | string? | Short description (e.g. "One or more validation errors occurred."). | | status | number | HTTP status code (400). | | detail | string? | Detailed error message. | | instance | string? | URI identifying the specific occurrence. | | errors | Record<string, string[]>? | Map of field paths to error messages (e.g. { "Skills[0].SkillCode": ["SkillCode is required."] }). |

ProblemDetails (404/409/422/429/500)

| Field | Type | Description | |-------|------|-------------| | type | string? | Problem type URI. | | title | string? | Short description. | | status | number? | HTTP status code. | | detail | string? | Detailed error message. | | instance | string? | URI identifying the specific occurrence. | | [key: string] | unknown | Additional properties may be present. |

HTTP status codes and meanings:

| Status | Meaning | Description | |--------|---------|-------------| | 200 | Success | Assessment results submitted successfully. | | 400 | Validation Error | Payload failed validation (client-side or backend). | | 404 | Not Found | Student, skill, or question not found. | | 409 | Conflict | Conflicting state (e.g. concurrent submission). | | 422 | Unprocessable Entity | Functional/business rule error. | | 429 | Too Many Requests | Rate limit exceeded. | | 500 | Internal Server Error | Unexpected backend error. |


Usage Examples

Regular Assessment (non-ASER)

import {
  AssessmentSubmissionClient,
  AssessmentSubmission,
  QuestionRole,
} from "@superapp_men/submit-assessment-results";

const skill1 = AssessmentSubmission.skill("MATH_ADD_01", 1, true)
  .questions([
    AssessmentSubmission.question("Q001", true, QuestionRole.VALIDATION)
      .order(1)
      .responseTime(5000)
      .build(),
    AssessmentSubmission.question("Q002", false, QuestionRole.VALIDATION)
      .order(2)
      .responseTime("00:00:08")
      .attemptsCount(2)
      .build(),
  ])
  .build();

const payload = AssessmentSubmission.builder()
  .setStudentId("3fa85f64-5717-4562-b3fc-2c963f66afa6")
  .setPartnerCode("bewise")
  .setAttemptId("unique-attempt-id-12345")
  .setAser(false)
  .setTotalSkillsInWeek(10)
  .addSkill(skill1)
  .build();

const client = new AssessmentSubmissionClient({ timeout: 30000, debug: true });
const result = await client.submit(payload);

if (result.ok) {
  console.log("Success:", result.body.attemptId, result.body.status);
} else {
  console.log("Error:", result.statusCode, result.body);
  if (result.statusCode === 400 && "errors" in result.body) {
    console.log("Validation errors:", result.body.errors);
  }
}

// Clean up when done
client.destroy();

ASER Assessment (positioning)

const aserSkills = [
  AssessmentSubmission.skill("ASER_SKILL_1", 1, true)
    .title("Addition simple", "الجمع البسيط")
    .description("Additionner deux nombres < 10", "جمع عددين أصغر من ١٠")
    .questions([
      AssessmentSubmission.question("Q001", true, QuestionRole.POSITIONING).order(1).build(),
    ])
    .build(),
  AssessmentSubmission.skill("ASER_SKILL_2", 2, true)
    .title("Soustraction", "الطرح")
    .description("Soustraire deux nombres", "طرح عددين")
    .questions([
      AssessmentSubmission.question("Q002", true, QuestionRole.POSITIONING).order(1).build(),
    ])
    .build(),
  AssessmentSubmission.skill("ASER_SKILL_3", 3, false)
    .title(undefined, "الضرب")               // Arabic only — valid
    .description("Multiplier deux nombres")   // French only — valid
    .questions([
      AssessmentSubmission.question("Q003", false, QuestionRole.POSITIONING).order(1).build(),
    ])
    .build(),
];

const payload = AssessmentSubmission.builder()
  .setStudentId("3fa85f64-5717-4562-b3fc-2c963f66afa6")
  .setPartnerCode("bewise")
  .setAttemptId("aser-attempt-001")
  .setAser(true)           // ASER mode
  .setTotalSkillsInWeek(3) // Must equal skills.length for ASER
  .addSkills(aserSkills)
  .build();

Question with All Optional Fields

AssessmentSubmission.question("Q001", true, QuestionRole.VALIDATION)
  .order(1)
  .responseTime(5000)                                           // milliseconds
  // .responseTime("00:00:05")                                  // or "hh:mm:ss" string
  .attemptsCount(1)
  .questionText("Combien font 2 + 3 ?", "ما ناتج ٢ + ٣؟")
  .tags("algebra,addition,level1")
  .metadata(JSON.stringify({ difficulty: "easy", chapter: 3 }))
  .build();

Validate Without Submitting

import {
  validateSubmitAssessmentPayload,
  toValidationProblemDetails,
} from "@superapp_men/submit-assessment-results";

const validation = validateSubmitAssessmentPayload(payload);
if (!validation.valid) {
  const details = toValidationProblemDetails(validation.errors);
  console.log("Validation errors:", details.errors);
  // Example output:
  // {
  //   "Skills[0].TitleFr": ["At least one of TitleFr or TitleAr is required for ASER assessments."],
  //   "Skills[0].SkillCode": ["SkillCode is required."]
  // }
}

Communication Protocol

Message Types

| Enum | Value | Direction | Description | |------|-------|-----------|-------------| | AssessmentMessageType.REQUEST | "assessment:submit-request" | Partner -> SuperApp | Partner sends assessment data. | | AssessmentMessageType.RESPONSE | "assessment:submit-response" | SuperApp -> Partner | SuperApp returns backend response. |

Request Message (AssessmentSubmitRequestMessage)

| Field | Type | Description | |-------|------|-------------| | type | "assessment:submit-request" | Message type constant. | | requestId | string | Unique ID generated per request (for matching response). | | payload | SubmitAssessmentResultsPartnerPayload | The assessment payload. | | timestamp | number | Date.now() at time of sending. |

Response Message (AssessmentSubmitResponseMessage)

| Field | Type | Description | |-------|------|-------------| | type | "assessment:submit-response" | Message type constant. | | requestId | string | Matches the request's requestId. | | statusCode | number | HTTP status code from the backend. | | body | SubmitAssessmentResultsResponse \| ValidationProblemDetails \| ProblemDetails | Exact backend response body. | | timestamp | number | Date.now() at time of response. |


SuperApp Integration

The SuperApp must:

  1. Listen for messages with type: "assessment:submit-request".
  2. Enrich the payload with academicYearId and periodWeekSubjectId.
  3. Call POST api/v1.0/submit-results with the enriched body.
  4. Forward the HTTP status and response body back to the partner via postMessage with type: "assessment:submit-response".

SuperApp imports:

import type {
  AssessmentSubmitRequestMessage,
  AssessmentSubmitResponseMessage,
  SubmitAssessmentResultsPartnerPayload,
} from "@superapp_men/submit-assessment-results/superapp";
import { AssessmentMessageType } from "@superapp_men/submit-assessment-results/superapp";

Exported Members

Main entry (@superapp_men/submit-assessment-results)

| Export | Kind | Description | |--------|------|-------------| | AssessmentSubmissionClient | Class | Client for submitting assessments (validates + sends via postMessage). | | AssessmentSubmissionClientConfig | Type | Config interface for the client (timeout, debug). | | AssessmentSubmission | Object | Factory with .builder(), .skill(), .question() methods. | | AssessmentSubmissionBuilder | Class | Fluent builder for the partner payload. | | SkillResultBuilder | Class | Fluent builder for a skill result. | | QuestionResultBuilder | Class | Fluent builder for a question result. | | QuestionRole | Enum | POSITIONING (1), VALIDATION (2), REMEDIATION (3), BONUS (4). | | AssessmentMessageType | Enum | REQUEST, RESPONSE message type constants. | | validateSubmitAssessmentPayload | Function | Validate payload without submitting. Returns { valid, errors }. | | toValidationProblemDetails | Function | Convert ValidationError[] to backend-style { status, title, errors }. | | ValidationResult | Type | { valid: boolean; errors: ValidationError[] }. | | ValidationError | Type | { key: string; message: string }. | | SubmitAssessmentResultsPartnerPayload | Type | Root payload interface. | | SubmittedSkillResultPayload | Type | Skill result interface. | | SubmittedQuestionResultPayload | Type | Question result interface. | | SubmitAssessmentResultsResponse | Type | Backend success response (200). | | SubmitAssessmentResultsApiResult | Type | Union result type from submit(). | | ValidationProblemDetails | Type | Backend validation error response (400). | | ProblemDetails | Type | Backend error response (404/409/422/429/500). | | ResponseTimeInput | Type | number \| string type alias for response time. |

SuperApp entry (@superapp_men/submit-assessment-results/superapp)

| Export | Kind | Description | |--------|------|-------------| | AssessmentMessageType | Enum | Message type constants. | | QuestionRole | Enum | Question role constants. | | All payload/response types | Types | Same type exports as main entry (types only, no builders/client). |


Constants

| Constant | Value | Used In | |----------|-------|---------| | MAX_ATTEMPT_ID_LENGTH | 100 | attemptId max length validation. | | MAX_PARTNER_CODE_LENGTH | 50 | partnerCode max length validation. | | MIN_ASER_SKILL_COUNT | 3 | Minimum skills for ASER assessments. | | MAX_ASER_SKILL_COUNT | 6 | Maximum skills for ASER assessments. | | MAX_RESPONSE_TIME_MS | 3,600,000 (1 hour) | Maximum response time per question. | | VALID_PARTNER_CODES | ["bewise", "ltm", "cantoo", "ekinox", "math-scan"] | Allowed partner code values (case-insensitive). | | VALID_QUESTION_ROLES | [1, 2, 3, 4] | Allowed QuestionRole values. | | Default timeout | 30,000 ms | Client request timeout. |