@edpire/sdk 0.7.0 → 0.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.
- package/CHANGELOG.md +59 -0
- package/README.md +14 -2
- package/dist/client.d.mts +204 -1
- package/dist/client.mjs +18 -0
- package/dist/core.d.mts +252 -1
- package/dist/core.mjs +1 -1
- package/dist/index.d.mts +201 -1
- package/dist/index.mjs +11 -11
- package/dist/react.d.mts +28 -4
- package/dist/react.mjs +10 -10
- package/dist/umd/index.global.js +153 -153
- package/package.json +1 -1
package/dist/index.d.mts
CHANGED
|
@@ -176,6 +176,12 @@ interface EmbedResult {
|
|
|
176
176
|
rightId: string;
|
|
177
177
|
}>;
|
|
178
178
|
};
|
|
179
|
+
/**
|
|
180
|
+
* The teacher's written feedback on an open response. Only ever present
|
|
181
|
+
* in a review (`GET /submissions/{id}/review`), since at submit time no
|
|
182
|
+
* teacher has graded anything yet.
|
|
183
|
+
*/
|
|
184
|
+
teacher_feedback?: RichContent[];
|
|
179
185
|
}>;
|
|
180
186
|
}>;
|
|
181
187
|
}>;
|
|
@@ -252,6 +258,66 @@ interface EmbedInstance {
|
|
|
252
258
|
/** Unmounts the assessment player and cleans up event listeners. */
|
|
253
259
|
unmount: () => void;
|
|
254
260
|
}
|
|
261
|
+
/**
|
|
262
|
+
* Response of `GET /api/v1/submissions/{id}/review`: one finished attempt, with
|
|
263
|
+
* everything needed to draw it as the corrected paper. Fetch it on your server
|
|
264
|
+
* (it needs an API key with `read:results`), send it to the browser, and pass it
|
|
265
|
+
* to `EdpireAssessment.review()` unchanged.
|
|
266
|
+
*/
|
|
267
|
+
interface SubmissionReview {
|
|
268
|
+
submission: {
|
|
269
|
+
id: string;
|
|
270
|
+
assessment_id: string;
|
|
271
|
+
learner_ref: string | null;
|
|
272
|
+
status: string;
|
|
273
|
+
attempt_number: number;
|
|
274
|
+
/** How many attempts this learner has made at this assessment, this one included. */
|
|
275
|
+
total_attempts: number;
|
|
276
|
+
score: number;
|
|
277
|
+
max_score: number;
|
|
278
|
+
percentage: number;
|
|
279
|
+
passed: boolean;
|
|
280
|
+
passing_score_percent: number;
|
|
281
|
+
is_fully_graded: boolean;
|
|
282
|
+
/**
|
|
283
|
+
* True while a teacher still has open responses to grade. `score`,
|
|
284
|
+
* `percentage` and `passed` are provisional until it turns false, and the
|
|
285
|
+
* player hides them.
|
|
286
|
+
*/
|
|
287
|
+
awaiting_manual_grading: boolean;
|
|
288
|
+
submitted_at: string | null;
|
|
289
|
+
};
|
|
290
|
+
assessment: AssessmentLoaderResponse["assessment"];
|
|
291
|
+
meta: Omit<AssessmentLoaderResponse["meta"], "type">;
|
|
292
|
+
branding?: TakeBranding | null;
|
|
293
|
+
/** The learner's answers, in the shape the player collected them. */
|
|
294
|
+
answers: {
|
|
295
|
+
exerciseAnswers: Array<{
|
|
296
|
+
exerciseId: string;
|
|
297
|
+
questionAnswers: Array<{
|
|
298
|
+
questionId: string;
|
|
299
|
+
answers: RuntimeAnswer[];
|
|
300
|
+
}>;
|
|
301
|
+
}>;
|
|
302
|
+
};
|
|
303
|
+
exercise_feedback: EmbedResult["exercise_feedback"];
|
|
304
|
+
}
|
|
305
|
+
interface ReviewOptions {
|
|
306
|
+
/** The response of `GET /api/v1/submissions/{id}/review`, passed through untouched. */
|
|
307
|
+
review: SubmissionReview;
|
|
308
|
+
/** Where to mount the corrected paper. CSS selector string or DOM element. */
|
|
309
|
+
container: string | HTMLElement;
|
|
310
|
+
/** Player UI language. Defaults to the assessment's own language. */
|
|
311
|
+
locale?: ShellLocale;
|
|
312
|
+
/** Branding overrides. Defaults to the org branding carried in the review. */
|
|
313
|
+
branding?: TakeBranding;
|
|
314
|
+
/** Geometry of the question column. Same as `MountOptions.layout`. */
|
|
315
|
+
layout?: ShellLayout;
|
|
316
|
+
/** Shows a back button in the top bar and calls this when it is clicked. */
|
|
317
|
+
onBack?: () => void;
|
|
318
|
+
/** Custom label for the back button. */
|
|
319
|
+
backLabel?: string;
|
|
320
|
+
}
|
|
255
321
|
interface RenderQuestionOptions {
|
|
256
322
|
/**
|
|
257
323
|
* DOM element or CSS selector string to mount into.
|
|
@@ -273,6 +339,11 @@ interface RenderQuestionOptions {
|
|
|
273
339
|
* Pre-fill answers.
|
|
274
340
|
*/
|
|
275
341
|
initialAnswers?: RuntimeAnswer[];
|
|
342
|
+
/**
|
|
343
|
+
* Lock the question: answers show but cannot be changed. Since 0.8.0. For
|
|
344
|
+
* reviewing a past attempt one question at a time; see `flattenReview()`.
|
|
345
|
+
*/
|
|
346
|
+
readOnly?: boolean;
|
|
276
347
|
/**
|
|
277
348
|
* Text direction for the question container.
|
|
278
349
|
*/
|
|
@@ -298,6 +369,55 @@ interface QuestionInstance {
|
|
|
298
369
|
*/
|
|
299
370
|
unmount(): void;
|
|
300
371
|
}
|
|
372
|
+
interface AssessmentLoaderResponse {
|
|
373
|
+
assessment: {
|
|
374
|
+
/**
|
|
375
|
+
* Assessment-level annex — reading texts, figures, formula sheets. The
|
|
376
|
+
* player shows it as a side panel on wide screens and a drawer on narrow
|
|
377
|
+
* ones. Null when the assessment has none.
|
|
378
|
+
*/
|
|
379
|
+
annex?: unknown | null;
|
|
380
|
+
exercises: Array<{
|
|
381
|
+
id: string;
|
|
382
|
+
sharedContext: unknown | null;
|
|
383
|
+
questions: Array<{
|
|
384
|
+
id: string;
|
|
385
|
+
version: "1.0";
|
|
386
|
+
content: unknown;
|
|
387
|
+
/** Sent by the content loader, not by a review. Nothing in the player reads either. */
|
|
388
|
+
points?: number;
|
|
389
|
+
sequenceNumber?: number;
|
|
390
|
+
answerKeys: never[];
|
|
391
|
+
}>;
|
|
392
|
+
}>;
|
|
393
|
+
};
|
|
394
|
+
meta: {
|
|
395
|
+
id: string;
|
|
396
|
+
title: string;
|
|
397
|
+
type: string;
|
|
398
|
+
category?: string | null;
|
|
399
|
+
/**
|
|
400
|
+
* The assessment's learner-facing language, which also decides text
|
|
401
|
+
* direction. The player uses this unless the host passes `locale`
|
|
402
|
+
* explicitly, so a French assessment reads left-to-right even when embedded
|
|
403
|
+
* in a right-to-left product.
|
|
404
|
+
*/
|
|
405
|
+
language?: "en" | "fr" | "ar";
|
|
406
|
+
settings: {
|
|
407
|
+
time_limit_minutes: number | null;
|
|
408
|
+
passing_score_percent: number;
|
|
409
|
+
allowed_attempts: number;
|
|
410
|
+
show_solutions: string;
|
|
411
|
+
};
|
|
412
|
+
};
|
|
413
|
+
attempt_info: {
|
|
414
|
+
attempt_number: number;
|
|
415
|
+
can_retry: boolean;
|
|
416
|
+
attempts_remaining: number | null;
|
|
417
|
+
};
|
|
418
|
+
/** Org branding loaded server-side. May be overridden by MountOptions.branding. */
|
|
419
|
+
branding?: TakeBranding | null;
|
|
420
|
+
}
|
|
301
421
|
|
|
302
422
|
/** Flat per-question answer collected during a custom player session. */
|
|
303
423
|
interface StoredAnswer {
|
|
@@ -447,6 +567,71 @@ declare function flattenAssessment(assessment: Assessment): FlatStep[];
|
|
|
447
567
|
|
|
448
568
|
declare function renderQuestion(options: RenderQuestionOptions): QuestionInstance;
|
|
449
569
|
|
|
570
|
+
/**
|
|
571
|
+
* flattenReview: a finished attempt as a linear sequence of steps, one per
|
|
572
|
+
* question, each ready to hand to `renderQuestion()` read-only.
|
|
573
|
+
*
|
|
574
|
+
* The review counterpart of `flattenAssessment()`. Where the full paper
|
|
575
|
+
* (`EdpireAssessment.review()`) draws the whole attempt at once, this is for
|
|
576
|
+
* flows that show one question per screen, Arcade-style, and want the learner
|
|
577
|
+
* to page back through a past attempt the same way they took it.
|
|
578
|
+
*
|
|
579
|
+
* @example
|
|
580
|
+
* const review = await fetch(`/api/attempts/${id}/review`).then((r) => r.json())
|
|
581
|
+
* const steps = flattenReview(review)
|
|
582
|
+
*
|
|
583
|
+
* const q = renderQuestion({
|
|
584
|
+
* container: "#question",
|
|
585
|
+
* content: steps[i].content,
|
|
586
|
+
* initialAnswers: steps[i].answers,
|
|
587
|
+
* feedback: steps[i].feedback,
|
|
588
|
+
* readOnly: true,
|
|
589
|
+
* })
|
|
590
|
+
* // steps[i].status, steps[i].score / steps[i].maxScore for your own chrome
|
|
591
|
+
*
|
|
592
|
+
* Pure: no React, no DOM. Also exported from `@edpire/sdk/core`.
|
|
593
|
+
*/
|
|
594
|
+
|
|
595
|
+
interface ReviewStep {
|
|
596
|
+
exerciseId: string;
|
|
597
|
+
questionId: string;
|
|
598
|
+
/** ContentAST. Pass to renderQuestion's `content`. */
|
|
599
|
+
content: unknown;
|
|
600
|
+
/**
|
|
601
|
+
* The exercise's shared context (reading passage, figure, worked example),
|
|
602
|
+
* or null. Unlike `flattenAssessment()`, carried on every step: a
|
|
603
|
+
* comprehension question reviewed without its passage makes no sense.
|
|
604
|
+
* Render it with renderQuestion too; it is plain content.
|
|
605
|
+
*/
|
|
606
|
+
sharedContext: unknown | null;
|
|
607
|
+
/** What the learner answered. Pass to renderQuestion's `initialAnswers`. */
|
|
608
|
+
answers: RuntimeAnswer[];
|
|
609
|
+
/**
|
|
610
|
+
* The marking, in the same shape POST /check returns, so it goes straight
|
|
611
|
+
* into renderQuestion's `feedback`. Includes the expected answer on anything
|
|
612
|
+
* missed and the teacher's comment on an open response.
|
|
613
|
+
*/
|
|
614
|
+
feedback: Record<string, unknown>;
|
|
615
|
+
score: number;
|
|
616
|
+
maxScore: number;
|
|
617
|
+
/**
|
|
618
|
+
* The question as a whole. `awaiting_review` while a teacher has yet to mark
|
|
619
|
+
* any part of it; its score is then provisional. `unscored` when it is worth
|
|
620
|
+
* nothing (no answerable input, or 0 points): there was nothing to get
|
|
621
|
+
* wrong, so do not show it as wrong.
|
|
622
|
+
*/
|
|
623
|
+
status: "correct" | "partial" | "incorrect" | "awaiting_review" | "unscored";
|
|
624
|
+
/** 0-based position, in the order the assessment presents questions. */
|
|
625
|
+
index: number;
|
|
626
|
+
}
|
|
627
|
+
/**
|
|
628
|
+
* The order is the assessment's (exercises, then questions within each), not
|
|
629
|
+
* the order a shuffled Arcade attempt happened to show. Edpire does not record
|
|
630
|
+
* the order an attempt was presented in; store it yourself if you need to
|
|
631
|
+
* replay it exactly.
|
|
632
|
+
*/
|
|
633
|
+
declare function flattenReview(review: SubmissionReview): ReviewStep[];
|
|
634
|
+
|
|
450
635
|
declare const EdpireAssessment: {
|
|
451
636
|
/**
|
|
452
637
|
* Mount an Edpire assessment into the given container.
|
|
@@ -463,6 +648,21 @@ declare const EdpireAssessment: {
|
|
|
463
648
|
* })
|
|
464
649
|
*/
|
|
465
650
|
mount(options: MountOptions): EmbedInstance;
|
|
651
|
+
/**
|
|
652
|
+
* Render a finished attempt as the corrected paper: the learner's answers,
|
|
653
|
+
* locked, with every mark, expected answer and teacher comment.
|
|
654
|
+
*
|
|
655
|
+
* Pass the response of `GET /api/v1/submissions/{id}/review` unchanged. Your
|
|
656
|
+
* server fetches it with an API key, after checking the attempt belongs to
|
|
657
|
+
* the signed-in learner. No token, and no request from the browser to Edpire,
|
|
658
|
+
* so the origin allow-list does not apply.
|
|
659
|
+
*
|
|
660
|
+
* @example
|
|
661
|
+
* const review = await fetch(`/api/attempts/${submissionId}/review`).then((r) => r.json())
|
|
662
|
+
* const view = EdpireAssessment.review({ review, container: "#paper" })
|
|
663
|
+
* view.unmount()
|
|
664
|
+
*/
|
|
665
|
+
review(options: ReviewOptions): EmbedInstance;
|
|
466
666
|
};
|
|
467
667
|
|
|
468
|
-
export { EdpireAssessment, type EmbedError, type EmbedInstance, type EmbedResult, type ExerciseFeedbackData, type FlatStep, type MountOptions, type OverlayConfig, type QuestionInstance, type RenderQuestionOptions, type ShellLayout, type ShellLocale, type SpinnerTheme, type StoredAnswer, type SubmitResult, type TakeBranding, buildSubmitPayload, flattenAssessment, renderQuestion };
|
|
668
|
+
export { EdpireAssessment, type EmbedError, type EmbedInstance, type EmbedResult, type ExerciseFeedbackData, type FlatStep, type MountOptions, type OverlayConfig, type QuestionInstance, type RenderQuestionOptions, type ReviewOptions, type ReviewStep, type ShellLayout, type ShellLocale, type SpinnerTheme, type StoredAnswer, type SubmissionReview, type SubmitResult, type TakeBranding, buildSubmitPayload, flattenAssessment, flattenReview, renderQuestion };
|