@edpire/sdk 0.7.0 → 0.8.1
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 +77 -0
- package/README.md +14 -2
- package/dist/client.d.mts +221 -1
- package/dist/client.mjs +18 -0
- package/dist/core.d.mts +256 -1
- package/dist/core.mjs +1 -1
- package/dist/index.d.mts +211 -1
- package/dist/index.mjs +11 -11
- package/dist/react.d.mts +36 -4
- package/dist/react.mjs +10 -10
- package/dist/umd/index.global.js +153 -153
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -9,6 +9,83 @@ integrators pin a version and had no way to tell what a bump would change.
|
|
|
9
9
|
The format follows [Keep a Changelog](https://keepachangelog.com/en/1.1.0/) and
|
|
10
10
|
the package follows [semantic versioning](https://semver.org/spec/v2.0.0.html).
|
|
11
11
|
|
|
12
|
+
## [0.8.1] - 2026-09-29
|
|
13
|
+
|
|
14
|
+
### Fixed
|
|
15
|
+
|
|
16
|
+
- **An AI-marked answer that has no mark yet is no longer described as a
|
|
17
|
+
teacher reviewing open responses.** When the AI does not answer in time, the
|
|
18
|
+
player's banner now says the answers are still being marked ("Being marked",
|
|
19
|
+
in en/fr/ar), and still hides the score. Driven by the new `ai_pending` field
|
|
20
|
+
of the submit and review responses; older servers that do not send it keep
|
|
21
|
+
the previous banner.
|
|
22
|
+
|
|
23
|
+
### Added
|
|
24
|
+
|
|
25
|
+
- `ai_pending?: boolean` on `EmbedResult`, on `SubmissionReview.submission`,
|
|
26
|
+
and on `GradeResult` (`POST /assessments/{id}/submit`). True when an
|
|
27
|
+
AI-marked answer has no mark yet: treat the score as provisional, never as a
|
|
28
|
+
final 0.
|
|
29
|
+
|
|
30
|
+
## [0.8.0] - 2026-09-23
|
|
31
|
+
|
|
32
|
+
### Added
|
|
33
|
+
|
|
34
|
+
- **`EdpireAssessment.review({ review, container })`**: reopens a finished
|
|
35
|
+
attempt as the corrected paper. The learner's answers are replayed into
|
|
36
|
+
locked questions, with every mark, the expected answer on anything missed,
|
|
37
|
+
and the teacher's comments on open responses. It is the screen the player
|
|
38
|
+
shows on submit, available again afterwards.
|
|
39
|
+
|
|
40
|
+
```javascript
|
|
41
|
+
const review = await fetch(`/api/attempts/${id}/review`).then((r) => r.json())
|
|
42
|
+
EdpireAssessment.review({ review, container: "#paper" })
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
`review` is the response of the new `GET /api/v1/submissions/{id}/review`,
|
|
46
|
+
passed through unchanged. Your server fetches it with an API key after
|
|
47
|
+
checking ownership, so there is no token and no browser request to Edpire,
|
|
48
|
+
and the origin allow-list does not apply.
|
|
49
|
+
|
|
50
|
+
- **`flattenReview(review)`**: the same attempt as one step per question, for
|
|
51
|
+
flows that show one question per screen. Each step carries the content, the
|
|
52
|
+
learner's answers, feedback in `/check`'s shape, the score and a status, plus
|
|
53
|
+
the exercise's shared context. Pure, so also in `@edpire/sdk/core` and on the
|
|
54
|
+
CDN global.
|
|
55
|
+
|
|
56
|
+
```javascript
|
|
57
|
+
const steps = flattenReview(review)
|
|
58
|
+
renderQuestion({ container, content: steps[i].content, initialAnswers: steps[i].answers,
|
|
59
|
+
feedback: steps[i].feedback, readOnly: true })
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
- **`readOnly`** on `renderQuestion()` and `EdpireQuestion`: answers show but
|
|
63
|
+
cannot change.
|
|
64
|
+
|
|
65
|
+
- **`EdpireClient.getSubmissionReview(id, { learnerRef })`** for that fetch.
|
|
66
|
+
With `learnerRef`, a submission belonging to anyone else is a 404.
|
|
67
|
+
|
|
68
|
+
- **`EdpireClient.getLearnerResults(ref, { assessmentId })`**: one
|
|
69
|
+
assessment's attempt history.
|
|
70
|
+
|
|
71
|
+
- **`AssessmentShellProps.review`** and the **`ShellReview`** type, for React
|
|
72
|
+
consumers rendering the shell directly. **`SubmissionReview`**,
|
|
73
|
+
**`ReviewOptions`** and **`ReviewStep`** types.
|
|
74
|
+
|
|
75
|
+
- **`teacher_feedback`** on `EmbedResult` node results. Only ever present in a
|
|
76
|
+
review: at submit time no teacher has marked anything yet.
|
|
77
|
+
|
|
78
|
+
### Changed
|
|
79
|
+
|
|
80
|
+
- The back button (`onBack`) now also shows in review mode. Before submission it
|
|
81
|
+
behaves as before.
|
|
82
|
+
|
|
83
|
+
### Notes for integrators
|
|
84
|
+
|
|
85
|
+
No breaking changes. Review needs the new endpoint, which is live on
|
|
86
|
+
edpire.com from this release. See the attempt history guide:
|
|
87
|
+
https://docs.edpire.com/developer/attempt-history
|
|
88
|
+
|
|
12
89
|
## [0.7.0] - 2026-09-22
|
|
13
90
|
|
|
14
91
|
### Added
|
package/README.md
CHANGED
|
@@ -90,7 +90,7 @@ embed.unmount()
|
|
|
90
90
|
**CDN (no bundler):**
|
|
91
91
|
|
|
92
92
|
```html
|
|
93
|
-
<script src="https://cdn.jsdelivr.net/npm/@edpire/sdk@0.
|
|
93
|
+
<script src="https://cdn.jsdelivr.net/npm/@edpire/sdk@0.8.1/dist/umd/index.global.js"></script>
|
|
94
94
|
<script>
|
|
95
95
|
EdpireSDK.EdpireAssessment.mount({ token, container: "#root", onComplete: handleDone })
|
|
96
96
|
</script>
|
|
@@ -248,6 +248,18 @@ If omitted, rate limiting falls back to `learner_ref`, which accumulates across
|
|
|
248
248
|
|
|
249
249
|
**Required API key scopes:** `read:assessments` (for fetching and checking) + `write:submissions` (for the final submit).
|
|
250
250
|
|
|
251
|
+
**Reviewing a past attempt, one question at a time** (since 0.8.0): fetch it on your server with `client.getSubmissionReview(id, { learnerRef })`, then in the browser:
|
|
252
|
+
|
|
253
|
+
```typescript
|
|
254
|
+
const steps = flattenReview(review)
|
|
255
|
+
renderQuestion({
|
|
256
|
+
container, content: steps[i].content,
|
|
257
|
+
initialAnswers: steps[i].answers, feedback: steps[i].feedback, readOnly: true,
|
|
258
|
+
})
|
|
259
|
+
```
|
|
260
|
+
|
|
261
|
+
For the whole attempt at once: `EdpireAssessment.review({ review, container })`. See the [attempt history guide](https://docs.edpire.com/developer/attempt-history).
|
|
262
|
+
|
|
251
263
|
**When to use:** You want full control over pacing, navigation, animations, or scoring UX. You're building a Duolingo-style flow, a timed drill, a practice mode, or any experience that goes beyond a linear "answer all → submit" form.
|
|
252
264
|
|
|
253
265
|
---
|
|
@@ -316,7 +328,7 @@ The integration uses two parts:
|
|
|
316
328
|
</head>
|
|
317
329
|
<body>
|
|
318
330
|
<div id="root"></div>
|
|
319
|
-
<script src="https://cdn.jsdelivr.net/npm/@edpire/sdk@0.
|
|
331
|
+
<script src="https://cdn.jsdelivr.net/npm/@edpire/sdk@0.8.1/dist/umd/index.global.js"></script>
|
|
320
332
|
<script>
|
|
321
333
|
EdpireSDK.EdpireAssessment.mount({
|
|
322
334
|
token: "{{EMBED_TOKEN}}", // replace server-side before loading
|
package/dist/client.d.mts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { RuntimeAnswer } from '@youssefalmia/edpire-runtime';
|
|
2
|
+
import { RichContent } from '@youssefalmia/edpire-schema/authoring';
|
|
2
3
|
|
|
3
4
|
/** Flat per-question answer collected during a custom player session. */
|
|
4
5
|
interface StoredAnswer {
|
|
@@ -10,6 +11,195 @@ interface StoredAnswer {
|
|
|
10
11
|
answers: RuntimeAnswer[];
|
|
11
12
|
}
|
|
12
13
|
|
|
14
|
+
/**
|
|
15
|
+
* Public types for the polished Assessment Shell.
|
|
16
|
+
*
|
|
17
|
+
* The shell renders the same UI used at edpire.com's hosted player.
|
|
18
|
+
* Consumers using the EdpireAssessment.mount() API get these types
|
|
19
|
+
* indirectly via MountOptions; consumers rendering <AssessmentShell>
|
|
20
|
+
* directly import them from "@edpire/sdk/react".
|
|
21
|
+
*/
|
|
22
|
+
|
|
23
|
+
/** Branding payload accepted by AssessmentShell. Mirrors what edpire.com sends. */
|
|
24
|
+
interface TakeBranding {
|
|
25
|
+
/** Org display name — shown as the alt text on the logo. */
|
|
26
|
+
name: string;
|
|
27
|
+
/** Logo URL (any https URL). When absent, the Edpire logo is shown. */
|
|
28
|
+
logoUrl: string | null;
|
|
29
|
+
branding: {
|
|
30
|
+
/** CSS color for the primary action buttons (Submit, View Report, etc.). */
|
|
31
|
+
primaryColor?: string;
|
|
32
|
+
/** CSS color used as the background of the top bar and per-exercise headers. */
|
|
33
|
+
accentColor?: string;
|
|
34
|
+
/** font-family applied to the shell. Pair with `fontUrl` for non-system fonts. */
|
|
35
|
+
fontFamily?: string;
|
|
36
|
+
/** A Google Fonts stylesheet URL; the shell injects a <link> tag at mount. */
|
|
37
|
+
fontUrl?: string;
|
|
38
|
+
/** When false, the "Powered by Edpire" watermark is hidden. Default true. */
|
|
39
|
+
showPoweredBy?: boolean;
|
|
40
|
+
} | null;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
/**
|
|
44
|
+
* Public types for the Edpire Embeddable JS SDK.
|
|
45
|
+
*/
|
|
46
|
+
|
|
47
|
+
type NodeFeedbackStatus = "correct" | "partial" | "incorrect" | "awaiting_review";
|
|
48
|
+
interface EmbedResult {
|
|
49
|
+
submission_id: string;
|
|
50
|
+
score: number;
|
|
51
|
+
max_score: number;
|
|
52
|
+
percentage: number;
|
|
53
|
+
passed: boolean;
|
|
54
|
+
passing_score_percent: number;
|
|
55
|
+
attempt_number: number;
|
|
56
|
+
/** True when the submission contains open-response nodes still pending teacher review. */
|
|
57
|
+
awaiting_manual_grading?: boolean;
|
|
58
|
+
/** True when an AI-marked answer has no mark yet: it is being marked, not scored 0. */
|
|
59
|
+
ai_pending?: boolean;
|
|
60
|
+
exercise_results: Array<{
|
|
61
|
+
exercise_id: string;
|
|
62
|
+
total_score: number;
|
|
63
|
+
max_score: number;
|
|
64
|
+
question_results: Array<{
|
|
65
|
+
question_id: string;
|
|
66
|
+
score: number;
|
|
67
|
+
correct: boolean;
|
|
68
|
+
points: number;
|
|
69
|
+
}>;
|
|
70
|
+
}>;
|
|
71
|
+
exercise_feedback: Array<{
|
|
72
|
+
exercise_id: string;
|
|
73
|
+
questions: Array<{
|
|
74
|
+
question_id: string;
|
|
75
|
+
node_results: Array<{
|
|
76
|
+
node_id: string;
|
|
77
|
+
status: NodeFeedbackStatus;
|
|
78
|
+
score: number;
|
|
79
|
+
max_score: number;
|
|
80
|
+
feedback?: string;
|
|
81
|
+
display_answer?: string;
|
|
82
|
+
detail?: {
|
|
83
|
+
type: "choiceSet";
|
|
84
|
+
correctChoiceIds: string[];
|
|
85
|
+
} | {
|
|
86
|
+
type: "matchingSet";
|
|
87
|
+
pairFeedback: Array<{
|
|
88
|
+
leftId: string;
|
|
89
|
+
rightId: string;
|
|
90
|
+
correct: boolean;
|
|
91
|
+
}>;
|
|
92
|
+
correctPairings: Array<{
|
|
93
|
+
leftId: string;
|
|
94
|
+
rightId: string;
|
|
95
|
+
}>;
|
|
96
|
+
};
|
|
97
|
+
/**
|
|
98
|
+
* The teacher's written feedback on an open response. Only ever present
|
|
99
|
+
* in a review (`GET /submissions/{id}/review`), since at submit time no
|
|
100
|
+
* teacher has graded anything yet.
|
|
101
|
+
*/
|
|
102
|
+
teacher_feedback?: RichContent[];
|
|
103
|
+
}>;
|
|
104
|
+
}>;
|
|
105
|
+
}>;
|
|
106
|
+
}
|
|
107
|
+
/**
|
|
108
|
+
* Response of `GET /api/v1/submissions/{id}/review`: one finished attempt, with
|
|
109
|
+
* everything needed to draw it as the corrected paper. Fetch it on your server
|
|
110
|
+
* (it needs an API key with `read:results`), send it to the browser, and pass it
|
|
111
|
+
* to `EdpireAssessment.review()` unchanged.
|
|
112
|
+
*/
|
|
113
|
+
interface SubmissionReview {
|
|
114
|
+
submission: {
|
|
115
|
+
id: string;
|
|
116
|
+
assessment_id: string;
|
|
117
|
+
learner_ref: string | null;
|
|
118
|
+
status: string;
|
|
119
|
+
attempt_number: number;
|
|
120
|
+
/** How many attempts this learner has made at this assessment, this one included. */
|
|
121
|
+
total_attempts: number;
|
|
122
|
+
score: number;
|
|
123
|
+
max_score: number;
|
|
124
|
+
percentage: number;
|
|
125
|
+
passed: boolean;
|
|
126
|
+
passing_score_percent: number;
|
|
127
|
+
is_fully_graded: boolean;
|
|
128
|
+
/**
|
|
129
|
+
* True while a teacher still has open responses to grade. `score`,
|
|
130
|
+
* `percentage` and `passed` are provisional until it turns false, and the
|
|
131
|
+
* player hides them.
|
|
132
|
+
*/
|
|
133
|
+
awaiting_manual_grading: boolean;
|
|
134
|
+
/** True while an AI-marked answer has no mark yet. Optional: older servers did not send it. */
|
|
135
|
+
ai_pending?: boolean;
|
|
136
|
+
submitted_at: string | null;
|
|
137
|
+
};
|
|
138
|
+
assessment: AssessmentLoaderResponse["assessment"];
|
|
139
|
+
meta: Omit<AssessmentLoaderResponse["meta"], "type">;
|
|
140
|
+
branding?: TakeBranding | null;
|
|
141
|
+
/** The learner's answers, in the shape the player collected them. */
|
|
142
|
+
answers: {
|
|
143
|
+
exerciseAnswers: Array<{
|
|
144
|
+
exerciseId: string;
|
|
145
|
+
questionAnswers: Array<{
|
|
146
|
+
questionId: string;
|
|
147
|
+
answers: RuntimeAnswer[];
|
|
148
|
+
}>;
|
|
149
|
+
}>;
|
|
150
|
+
};
|
|
151
|
+
exercise_feedback: EmbedResult["exercise_feedback"];
|
|
152
|
+
}
|
|
153
|
+
interface AssessmentLoaderResponse {
|
|
154
|
+
assessment: {
|
|
155
|
+
/**
|
|
156
|
+
* Assessment-level annex — reading texts, figures, formula sheets. The
|
|
157
|
+
* player shows it as a side panel on wide screens and a drawer on narrow
|
|
158
|
+
* ones. Null when the assessment has none.
|
|
159
|
+
*/
|
|
160
|
+
annex?: unknown | null;
|
|
161
|
+
exercises: Array<{
|
|
162
|
+
id: string;
|
|
163
|
+
sharedContext: unknown | null;
|
|
164
|
+
questions: Array<{
|
|
165
|
+
id: string;
|
|
166
|
+
version: "1.0";
|
|
167
|
+
content: unknown;
|
|
168
|
+
/** Sent by the content loader, not by a review. Nothing in the player reads either. */
|
|
169
|
+
points?: number;
|
|
170
|
+
sequenceNumber?: number;
|
|
171
|
+
answerKeys: never[];
|
|
172
|
+
}>;
|
|
173
|
+
}>;
|
|
174
|
+
};
|
|
175
|
+
meta: {
|
|
176
|
+
id: string;
|
|
177
|
+
title: string;
|
|
178
|
+
type: string;
|
|
179
|
+
category?: string | null;
|
|
180
|
+
/**
|
|
181
|
+
* The assessment's learner-facing language, which also decides text
|
|
182
|
+
* direction. The player uses this unless the host passes `locale`
|
|
183
|
+
* explicitly, so a French assessment reads left-to-right even when embedded
|
|
184
|
+
* in a right-to-left product.
|
|
185
|
+
*/
|
|
186
|
+
language?: "en" | "fr" | "ar";
|
|
187
|
+
settings: {
|
|
188
|
+
time_limit_minutes: number | null;
|
|
189
|
+
passing_score_percent: number;
|
|
190
|
+
allowed_attempts: number;
|
|
191
|
+
show_solutions: string;
|
|
192
|
+
};
|
|
193
|
+
};
|
|
194
|
+
attempt_info: {
|
|
195
|
+
attempt_number: number;
|
|
196
|
+
can_retry: boolean;
|
|
197
|
+
attempts_remaining: number | null;
|
|
198
|
+
};
|
|
199
|
+
/** Org branding loaded server-side. May be overridden by MountOptions.branding. */
|
|
200
|
+
branding?: TakeBranding | null;
|
|
201
|
+
}
|
|
202
|
+
|
|
13
203
|
/**
|
|
14
204
|
* @edpire/sdk/client — Server-side API client for Edpire.
|
|
15
205
|
*
|
|
@@ -146,6 +336,12 @@ interface GradeResult {
|
|
|
146
336
|
* the `submission.grading.completed` webhook.
|
|
147
337
|
*/
|
|
148
338
|
awaiting_manual_grading: boolean;
|
|
339
|
+
/**
|
|
340
|
+
* True when an AI-marked answer has no mark yet (the AI did not answer in
|
|
341
|
+
* time). It is being marked, not scored 0: treat the score as provisional.
|
|
342
|
+
* Optional because servers before 2026-09-29 did not send it.
|
|
343
|
+
*/
|
|
344
|
+
ai_pending?: boolean;
|
|
149
345
|
exercise_results: Array<{
|
|
150
346
|
exercise_id: string;
|
|
151
347
|
total_score: number;
|
|
@@ -193,6 +389,13 @@ interface CheckResult {
|
|
|
193
389
|
correct: boolean;
|
|
194
390
|
score: number;
|
|
195
391
|
max_score: number;
|
|
392
|
+
/**
|
|
393
|
+
* True when an AI-graded part of the question could not be graded in time.
|
|
394
|
+
* That node's feedback carries `pending: true` and no score, and `correct` /
|
|
395
|
+
* `score` cover only what was graded. Not a wrong answer: do not penalise it.
|
|
396
|
+
* Optional because servers before 2026-09-29 did not send it.
|
|
397
|
+
*/
|
|
398
|
+
ai_pending?: boolean;
|
|
196
399
|
feedback: Record<string, unknown>;
|
|
197
400
|
}
|
|
198
401
|
interface Submission {
|
|
@@ -345,16 +548,33 @@ declare class EdpireClient {
|
|
|
345
548
|
* @throws {EdpireError} 404 if not found, 401/403 for auth issues.
|
|
346
549
|
*/
|
|
347
550
|
getSubmission(id: string): Promise<Submission>;
|
|
551
|
+
/**
|
|
552
|
+
* Fetch one finished attempt as the corrected paper: content, the learner's
|
|
553
|
+
* answers and the marking. Send the result to the browser and pass it to
|
|
554
|
+
* `EdpireAssessment.review()` unchanged.
|
|
555
|
+
*
|
|
556
|
+
* @param id - Submission UUID.
|
|
557
|
+
* @param params.learnerRef - The learner you believe owns it. When given, a
|
|
558
|
+
* submission belonging to anyone else is a 404, so a bug in your own
|
|
559
|
+
* ownership check cannot show one learner another's paper. Always pass it.
|
|
560
|
+
* @throws {EdpireError} 404 (not found, or not this learner's), 409 (not
|
|
561
|
+
* submitted yet, or the assessment has been unpublished since).
|
|
562
|
+
*/
|
|
563
|
+
getSubmissionReview(id: string, params?: {
|
|
564
|
+
learnerRef?: string;
|
|
565
|
+
}): Promise<SubmissionReview>;
|
|
348
566
|
/**
|
|
349
567
|
* Fetch all submissions for a learner.
|
|
350
568
|
*
|
|
351
569
|
* @param learnerRef - Your stable user ID (the `learner_ref` you passed during submit).
|
|
570
|
+
* @param params.assessmentId - Only this assessment's attempts.
|
|
352
571
|
* @param params.page - Page number (default 1).
|
|
353
572
|
* @param params.limit - Items per page (default 50, max 100).
|
|
354
573
|
* @returns Paginated list of submissions.
|
|
355
574
|
* @throws {EdpireError} 401/403 for auth issues.
|
|
356
575
|
*/
|
|
357
576
|
getLearnerResults(learnerRef: string, params?: {
|
|
577
|
+
assessmentId?: string;
|
|
358
578
|
page?: number;
|
|
359
579
|
limit?: number;
|
|
360
580
|
}): Promise<PaginatedResponse<Submission>>;
|
|
@@ -528,4 +748,4 @@ declare function createEdpireTokenHandler(opts: EdpireTokenHandlerOptions): (req
|
|
|
528
748
|
*/
|
|
529
749
|
declare function toNodeHandler(handler: (req: Request) => Promise<Response>): (req: ConnectRequest, res: ConnectResponse) => void;
|
|
530
750
|
|
|
531
|
-
export { type Assessment, type AssessmentExercise, type AssessmentQuestion, type AssessmentSummary, type CheckOptions, type CheckResult, EdpireClient, type EdpireClientOptions, EdpireError, type EdpireTokenHandlerOptions, type EmbedToken, type GradeResult, type PaginatedResponse, type StoredAnswer, type Submission, type SubmitOptions, type Webhook, type WebhookWithSecret, createEdpireTokenHandler, toNodeHandler };
|
|
751
|
+
export { type Assessment, type AssessmentExercise, type AssessmentQuestion, type AssessmentSummary, type CheckOptions, type CheckResult, EdpireClient, type EdpireClientOptions, EdpireError, type EdpireTokenHandlerOptions, type EmbedToken, type GradeResult, type PaginatedResponse, type StoredAnswer, type Submission, type SubmissionReview, type SubmitOptions, type Webhook, type WebhookWithSecret, createEdpireTokenHandler, toNodeHandler };
|
package/dist/client.mjs
CHANGED
|
@@ -182,10 +182,27 @@ var EdpireClient = class {
|
|
|
182
182
|
async getSubmission(id) {
|
|
183
183
|
return this.request("GET", `/submissions/${id}`);
|
|
184
184
|
}
|
|
185
|
+
/**
|
|
186
|
+
* Fetch one finished attempt as the corrected paper: content, the learner's
|
|
187
|
+
* answers and the marking. Send the result to the browser and pass it to
|
|
188
|
+
* `EdpireAssessment.review()` unchanged.
|
|
189
|
+
*
|
|
190
|
+
* @param id - Submission UUID.
|
|
191
|
+
* @param params.learnerRef - The learner you believe owns it. When given, a
|
|
192
|
+
* submission belonging to anyone else is a 404, so a bug in your own
|
|
193
|
+
* ownership check cannot show one learner another's paper. Always pass it.
|
|
194
|
+
* @throws {EdpireError} 404 (not found, or not this learner's), 409 (not
|
|
195
|
+
* submitted yet, or the assessment has been unpublished since).
|
|
196
|
+
*/
|
|
197
|
+
async getSubmissionReview(id, params) {
|
|
198
|
+
const query = params?.learnerRef ? `?learner_ref=${encodeURIComponent(params.learnerRef)}` : "";
|
|
199
|
+
return this.request("GET", `/submissions/${id}/review${query}`);
|
|
200
|
+
}
|
|
185
201
|
/**
|
|
186
202
|
* Fetch all submissions for a learner.
|
|
187
203
|
*
|
|
188
204
|
* @param learnerRef - Your stable user ID (the `learner_ref` you passed during submit).
|
|
205
|
+
* @param params.assessmentId - Only this assessment's attempts.
|
|
189
206
|
* @param params.page - Page number (default 1).
|
|
190
207
|
* @param params.limit - Items per page (default 50, max 100).
|
|
191
208
|
* @returns Paginated list of submissions.
|
|
@@ -194,6 +211,7 @@ var EdpireClient = class {
|
|
|
194
211
|
async getLearnerResults(learnerRef, params) {
|
|
195
212
|
const query = new URLSearchParams();
|
|
196
213
|
query.set("learner_ref", learnerRef);
|
|
214
|
+
if (params?.assessmentId) query.set("assessment_id", params.assessmentId);
|
|
197
215
|
if (params?.page) query.set("page", String(params.page));
|
|
198
216
|
if (params?.limit) query.set("limit", String(params.limit));
|
|
199
217
|
return this.requestPaginated(
|