@edpire/sdk 0.5.0 → 0.6.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/dist/client.d.mts +127 -3
- package/dist/client.mjs +88 -1
- package/dist/index.mjs +1 -1
- package/dist/react.d.mts +204 -28
- package/dist/react.mjs +6 -6
- package/dist/umd/index.global.js +1 -1
- package/examples/nextjs/.env.example +6 -0
- package/examples/nextjs/README.md +66 -0
- package/examples/nextjs/app/api/edpire/token/route.ts +38 -0
- package/examples/nextjs/app/globals.css +9 -0
- package/examples/nextjs/app/layout.tsx +13 -0
- package/examples/nextjs/app/page.tsx +51 -0
- package/examples/nextjs/next.config.ts +8 -0
- package/examples/nextjs/package.json +22 -0
- package/examples/nextjs/tsconfig.json +20 -0
- package/examples/vite-express/.env.example +10 -0
- package/examples/vite-express/README.md +69 -0
- package/examples/vite-express/index.html +16 -0
- package/examples/vite-express/package.json +31 -0
- package/examples/vite-express/server.ts +84 -0
- package/examples/vite-express/src/App.tsx +56 -0
- package/examples/vite-express/src/main.tsx +9 -0
- package/examples/vite-express/tsconfig.json +17 -0
- package/examples/vite-express/tsconfig.server.json +12 -0
- package/examples/vite-express/vite.config.ts +18 -0
- package/package.json +3 -2
- package/src/styles/shell.css +1 -1
package/dist/react.d.mts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
|
-
import { RuntimeAnswer, AssessmentContent, AssessmentAnswers
|
|
2
|
+
import { RuntimeAnswer, QuestionRuntimeProps, AssessmentContent, AssessmentAnswers } from '@youssefalmia/edpire-runtime';
|
|
3
3
|
export { RuntimeAnswer } from '@youssefalmia/edpire-runtime';
|
|
4
4
|
import * as react_jsx_runtime from 'react/jsx-runtime';
|
|
5
5
|
import { RichContent } from '@youssefalmia/edpire-schema/authoring';
|
|
@@ -52,32 +52,6 @@ interface EdpireQuestionProps {
|
|
|
52
52
|
}
|
|
53
53
|
declare const EdpireQuestion: React.NamedExoticComponent<EdpireQuestionProps>;
|
|
54
54
|
|
|
55
|
-
type SpinnerTheme = "default" | "dots" | "pulse" | "bars";
|
|
56
|
-
interface GradingOverlayProps {
|
|
57
|
-
visible: boolean;
|
|
58
|
-
bgColor?: string;
|
|
59
|
-
accentColor?: string;
|
|
60
|
-
text?: string;
|
|
61
|
-
aiText?: string;
|
|
62
|
-
spinnerTheme?: SpinnerTheme;
|
|
63
|
-
animationUrl?: string;
|
|
64
|
-
hasAiNodes?: boolean;
|
|
65
|
-
contained?: boolean;
|
|
66
|
-
}
|
|
67
|
-
type OverlayConfig = Pick<GradingOverlayProps, "bgColor" | "accentColor" | "text" | "spinnerTheme" | "animationUrl">;
|
|
68
|
-
|
|
69
|
-
/**
|
|
70
|
-
* Standalone, dependency-free i18n for the SDK shell.
|
|
71
|
-
*
|
|
72
|
-
* Replaces the web app's `useTranslations("learner.taking")` so the shell can
|
|
73
|
-
* be rendered in any React environment (Vite, CRA, Astro, UMD CDN, mobile
|
|
74
|
-
* WebView). Locale is passed as a prop — there is no React context to set up.
|
|
75
|
-
*
|
|
76
|
-
* Strings mirror `packages/i18n/messages/{en,fr,ar}.json` under `learner.taking.*`.
|
|
77
|
-
* Keep in sync if those copies are edited.
|
|
78
|
-
*/
|
|
79
|
-
type ShellLocale = "en" | "fr" | "ar";
|
|
80
|
-
|
|
81
55
|
/**
|
|
82
56
|
* Public types for the polished Assessment Shell.
|
|
83
57
|
*
|
|
@@ -152,6 +126,208 @@ interface SubmitResult {
|
|
|
152
126
|
awaitingManualGrading?: boolean;
|
|
153
127
|
}
|
|
154
128
|
|
|
129
|
+
type SpinnerTheme = "default" | "dots" | "pulse" | "bars";
|
|
130
|
+
interface GradingOverlayProps {
|
|
131
|
+
visible: boolean;
|
|
132
|
+
bgColor?: string;
|
|
133
|
+
accentColor?: string;
|
|
134
|
+
text?: string;
|
|
135
|
+
aiText?: string;
|
|
136
|
+
spinnerTheme?: SpinnerTheme;
|
|
137
|
+
animationUrl?: string;
|
|
138
|
+
hasAiNodes?: boolean;
|
|
139
|
+
contained?: boolean;
|
|
140
|
+
}
|
|
141
|
+
type OverlayConfig = Pick<GradingOverlayProps, "bgColor" | "accentColor" | "text" | "spinnerTheme" | "animationUrl">;
|
|
142
|
+
|
|
143
|
+
/**
|
|
144
|
+
* Standalone, dependency-free i18n for the SDK shell.
|
|
145
|
+
*
|
|
146
|
+
* Replaces the web app's `useTranslations("learner.taking")` so the shell can
|
|
147
|
+
* be rendered in any React environment (Vite, CRA, Astro, UMD CDN, mobile
|
|
148
|
+
* WebView). Locale is passed as a prop — there is no React context to set up.
|
|
149
|
+
*
|
|
150
|
+
* Strings mirror `packages/i18n/messages/{en,fr,ar}.json` under `learner.taking.*`.
|
|
151
|
+
* Keep in sync if those copies are edited.
|
|
152
|
+
*/
|
|
153
|
+
type ShellLocale = "en" | "fr" | "ar";
|
|
154
|
+
|
|
155
|
+
/**
|
|
156
|
+
* Public types for the Edpire Embeddable JS SDK.
|
|
157
|
+
*/
|
|
158
|
+
|
|
159
|
+
type NodeFeedbackStatus = "correct" | "partial" | "incorrect" | "awaiting_review";
|
|
160
|
+
interface EmbedResult {
|
|
161
|
+
submission_id: string;
|
|
162
|
+
score: number;
|
|
163
|
+
max_score: number;
|
|
164
|
+
percentage: number;
|
|
165
|
+
passed: boolean;
|
|
166
|
+
passing_score_percent: number;
|
|
167
|
+
attempt_number: number;
|
|
168
|
+
/** True when the submission contains open-response nodes still pending teacher review. */
|
|
169
|
+
awaiting_manual_grading?: boolean;
|
|
170
|
+
exercise_results: Array<{
|
|
171
|
+
exercise_id: string;
|
|
172
|
+
total_score: number;
|
|
173
|
+
max_score: number;
|
|
174
|
+
question_results: Array<{
|
|
175
|
+
question_id: string;
|
|
176
|
+
score: number;
|
|
177
|
+
correct: boolean;
|
|
178
|
+
points: number;
|
|
179
|
+
}>;
|
|
180
|
+
}>;
|
|
181
|
+
exercise_feedback: Array<{
|
|
182
|
+
exercise_id: string;
|
|
183
|
+
questions: Array<{
|
|
184
|
+
question_id: string;
|
|
185
|
+
node_results: Array<{
|
|
186
|
+
node_id: string;
|
|
187
|
+
status: NodeFeedbackStatus;
|
|
188
|
+
score: number;
|
|
189
|
+
max_score: number;
|
|
190
|
+
feedback?: string;
|
|
191
|
+
display_answer?: string;
|
|
192
|
+
detail?: {
|
|
193
|
+
type: "choiceSet";
|
|
194
|
+
correctChoiceIds: string[];
|
|
195
|
+
} | {
|
|
196
|
+
type: "matchingSet";
|
|
197
|
+
pairFeedback: Array<{
|
|
198
|
+
leftId: string;
|
|
199
|
+
rightId: string;
|
|
200
|
+
correct: boolean;
|
|
201
|
+
}>;
|
|
202
|
+
correctPairings: Array<{
|
|
203
|
+
leftId: string;
|
|
204
|
+
rightId: string;
|
|
205
|
+
}>;
|
|
206
|
+
};
|
|
207
|
+
}>;
|
|
208
|
+
}>;
|
|
209
|
+
}>;
|
|
210
|
+
}
|
|
211
|
+
interface EmbedError {
|
|
212
|
+
code: "TOKEN_INVALID" | "TOKEN_EXPIRED" | "TOKEN_USED" | "ORIGIN_NOT_ALLOWED" | "ASSESSMENT_NOT_FOUND" | "MAX_ATTEMPTS_REACHED" | "NETWORK_ERROR" | "UNKNOWN";
|
|
213
|
+
message: string;
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
interface EdpireAssessmentPlayerProps {
|
|
217
|
+
/**
|
|
218
|
+
* URL of YOUR server endpoint that returns `{ token }`.
|
|
219
|
+
*
|
|
220
|
+
* The component POSTs `{ assessmentId, ...tokenBody }` here and uses the
|
|
221
|
+
* returned `token` to mount the player. Your endpoint should resolve the
|
|
222
|
+
* learner from your session — never from the request body.
|
|
223
|
+
*
|
|
224
|
+
* Pair with `createEdpireTokenHandler()` from `@edpire/sdk/client` to build
|
|
225
|
+
* the endpoint in one line.
|
|
226
|
+
*
|
|
227
|
+
* @example "/api/edpire/token"
|
|
228
|
+
*/
|
|
229
|
+
tokenEndpoint: string;
|
|
230
|
+
/** Assessment UUID to embed. Sent to `tokenEndpoint` in the POST body. */
|
|
231
|
+
assessmentId: string;
|
|
232
|
+
/**
|
|
233
|
+
* Extra body fields merged into the POST to `tokenEndpoint`.
|
|
234
|
+
* Useful for passing context your server needs beyond `assessmentId`
|
|
235
|
+
* (e.g. a course ID for allow-list validation).
|
|
236
|
+
*/
|
|
237
|
+
tokenBody?: Record<string, unknown>;
|
|
238
|
+
/** Base URL of the Edpire instance. Defaults to `"https://edpire.com"`. */
|
|
239
|
+
baseUrl?: string;
|
|
240
|
+
/** UI language. Defaults to `"en"`. RTL layout is applied automatically for `"ar"`. */
|
|
241
|
+
locale?: ShellLocale;
|
|
242
|
+
/** Branding overrides. Org branding loads from Edpire automatically; pass this to override (white-labelling). */
|
|
243
|
+
branding?: TakeBranding;
|
|
244
|
+
/**
|
|
245
|
+
* When set, the post-submit "View Full Report" button redirects here with
|
|
246
|
+
* `?submission_id=...&score=...&max_score=...` appended. Omit to hide the button.
|
|
247
|
+
*/
|
|
248
|
+
returnUrl?: string;
|
|
249
|
+
/** Custom label for the post-submit report/redirect button. */
|
|
250
|
+
reportLabel?: string;
|
|
251
|
+
/** Called when the learner clicks Back (shown only before submission). */
|
|
252
|
+
onBack?: () => void;
|
|
253
|
+
/** Custom label for the back button. */
|
|
254
|
+
backLabel?: string;
|
|
255
|
+
/** Customise the grading overlay (spinner theme, animation, colors). */
|
|
256
|
+
overlayConfig?: OverlayConfig;
|
|
257
|
+
/**
|
|
258
|
+
* Media upload/recording handler.
|
|
259
|
+
*
|
|
260
|
+
* **Required** if the assessment contains OpenResponse questions with
|
|
261
|
+
* file-upload or audio/video recording modes. Without it those questions
|
|
262
|
+
* will not function correctly.
|
|
263
|
+
*
|
|
264
|
+
* @example
|
|
265
|
+
* ```typescript
|
|
266
|
+
* mediaHandler: {
|
|
267
|
+
* upload: async (file, { onProgress }) => {
|
|
268
|
+
* const form = new FormData()
|
|
269
|
+
* form.append("file", file)
|
|
270
|
+
* const res = await fetch("/api/upload", { method: "POST", body: form })
|
|
271
|
+
* const { url } = await res.json()
|
|
272
|
+
* return { url }
|
|
273
|
+
* },
|
|
274
|
+
* }
|
|
275
|
+
* ```
|
|
276
|
+
*/
|
|
277
|
+
mediaHandler?: QuestionRuntimeProps["mediaHandler"];
|
|
278
|
+
/** Called when the learner successfully submits the assessment. */
|
|
279
|
+
onComplete?: (result: EmbedResult) => void;
|
|
280
|
+
/**
|
|
281
|
+
* Called when a non-recoverable error occurs (token fetch failure, invalid
|
|
282
|
+
* token, origin not allowed, etc.).
|
|
283
|
+
*/
|
|
284
|
+
onError?: (error: EmbedError) => void;
|
|
285
|
+
/**
|
|
286
|
+
* CSS class name for the container `<div>`. Use this to control the player size.
|
|
287
|
+
*
|
|
288
|
+
* The player fills its container — you own the outer dimensions.
|
|
289
|
+
*
|
|
290
|
+
* @example "h-screen" // full viewport height
|
|
291
|
+
* @example "h-[600px] w-full" // fixed height
|
|
292
|
+
*/
|
|
293
|
+
className?: string;
|
|
294
|
+
/**
|
|
295
|
+
* Inline style for the container `<div>`.
|
|
296
|
+
*
|
|
297
|
+
* When `className` is not set, defaults to `{ width: "100%", height: "100%" }`.
|
|
298
|
+
* Provide this (or `className`) to size the player — a zero-height container
|
|
299
|
+
* will collapse the player.
|
|
300
|
+
*/
|
|
301
|
+
style?: React.CSSProperties;
|
|
302
|
+
}
|
|
303
|
+
/**
|
|
304
|
+
* Drop-in React component for the Edpire Embedded Player.
|
|
305
|
+
*
|
|
306
|
+
* Handles token fetching from your server, player mounting/unmounting, and
|
|
307
|
+
* React StrictMode double-invoke cleanup — the plumbing you'd otherwise write
|
|
308
|
+
* by hand with `useRef` + `useEffect`.
|
|
309
|
+
*
|
|
310
|
+
* The player fills its container: size it via `className` or `style`.
|
|
311
|
+
*
|
|
312
|
+
* @example
|
|
313
|
+
* ```tsx
|
|
314
|
+
* import { EdpireAssessmentPlayer } from "@edpire/sdk/react"
|
|
315
|
+
*
|
|
316
|
+
* function AssessmentPage({ assessmentId }: { assessmentId: string }) {
|
|
317
|
+
* return (
|
|
318
|
+
* <EdpireAssessmentPlayer
|
|
319
|
+
* tokenEndpoint="/api/edpire/token"
|
|
320
|
+
* assessmentId={assessmentId}
|
|
321
|
+
* onComplete={(r) => console.log("Score:", r.score, "/", r.max_score)}
|
|
322
|
+
* onError={(e) => console.error(e.code, e.message)}
|
|
323
|
+
* className="h-screen"
|
|
324
|
+
* />
|
|
325
|
+
* )
|
|
326
|
+
* }
|
|
327
|
+
* ```
|
|
328
|
+
*/
|
|
329
|
+
declare function EdpireAssessmentPlayer({ tokenEndpoint, assessmentId, tokenBody, className, style, onComplete, onError, ...mountOptions }: EdpireAssessmentPlayerProps): react_jsx_runtime.JSX.Element;
|
|
330
|
+
|
|
155
331
|
interface AssessmentShellProps {
|
|
156
332
|
assessment: AssessmentContent;
|
|
157
333
|
meta: {
|
|
@@ -197,4 +373,4 @@ interface AssessmentShellProps {
|
|
|
197
373
|
}
|
|
198
374
|
declare function AssessmentShell({ assessment, meta, locale, branding, timeLimitMinutes, startedAt, onSubmit, onViewReport, reportLabel, onBack, backLabel, allowReset, onReset, overlayConfig, contained, onClose, mediaHandler, fallbackLogoUrl, }: AssessmentShellProps): react_jsx_runtime.JSX.Element;
|
|
199
375
|
|
|
200
|
-
export { AssessmentShell, type AssessmentShellProps, EdpireQuestion, type EdpireQuestionProps, type ExerciseFeedbackData, type NodeDetail, type NodeFeedback, type OverlayConfig, type QuestionFeedback, type ShellLocale, type SpinnerTheme, type SubmitResult, type TakeBranding };
|
|
376
|
+
export { AssessmentShell, type AssessmentShellProps, EdpireAssessmentPlayer, type EdpireAssessmentPlayerProps, EdpireQuestion, type EdpireQuestionProps, type ExerciseFeedbackData, type NodeDetail, type NodeFeedback, type OverlayConfig, type QuestionFeedback, type ShellLocale, type SpinnerTheme, type SubmitResult, type TakeBranding };
|