@edpire/sdk 0.6.12 → 0.7.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/bin/create.js CHANGED
File without changes
package/dist/client.d.mts CHANGED
@@ -225,23 +225,6 @@ interface Submission {
225
225
  result: unknown;
226
226
  }>;
227
227
  }
228
- interface Collection {
229
- id: string;
230
- name: string;
231
- slug: string;
232
- description: string | null;
233
- status: string;
234
- item_count: number;
235
- created_at: string;
236
- updated_at: string;
237
- }
238
- interface CollectionDetail extends Collection {
239
- items: Array<{
240
- id: string;
241
- position: number;
242
- assessment: Assessment;
243
- }>;
244
- }
245
228
  interface Webhook {
246
229
  id: string;
247
230
  url: string;
@@ -375,39 +358,6 @@ declare class EdpireClient {
375
358
  page?: number;
376
359
  limit?: number;
377
360
  }): Promise<PaginatedResponse<Submission>>;
378
- /**
379
- * List collections in your org.
380
- *
381
- * @param params.page - Page number (default 1).
382
- * @param params.limit - Items per page (default 20, max 100).
383
- * @returns Paginated list of collections with item counts.
384
- */
385
- getCollections(params?: {
386
- page?: number;
387
- limit?: number;
388
- }): Promise<PaginatedResponse<Collection>>;
389
- /**
390
- * Fetch a collection with its assessment items.
391
- *
392
- * @param id - Collection UUID.
393
- * @returns Collection detail with ordered assessment items.
394
- * @throws {EdpireError} 404 if not found.
395
- */
396
- getCollection(id: string): Promise<CollectionDetail>;
397
- /**
398
- * Fetch aggregated results across all assessments in a collection.
399
- *
400
- * @param id - Collection UUID.
401
- * @param params.page - Page number (default 1).
402
- * @param params.limit - Items per page (default 50, max 100).
403
- * @returns Paginated flat list of submissions with assessment titles.
404
- */
405
- getCollectionResults(id: string, params?: {
406
- page?: number;
407
- limit?: number;
408
- }): Promise<PaginatedResponse<Submission & {
409
- assessment_title: string;
410
- }>>;
411
361
  /**
412
362
  * Register a webhook endpoint.
413
363
  *
@@ -578,4 +528,4 @@ declare function createEdpireTokenHandler(opts: EdpireTokenHandlerOptions): (req
578
528
  */
579
529
  declare function toNodeHandler(handler: (req: Request) => Promise<Response>): (req: ConnectRequest, res: ConnectResponse) => void;
580
530
 
581
- export { type Assessment, type AssessmentExercise, type AssessmentQuestion, type AssessmentSummary, type CheckOptions, type CheckResult, type Collection, type CollectionDetail, EdpireClient, type EdpireClientOptions, EdpireError, type EdpireTokenHandlerOptions, type EmbedToken, type GradeResult, type PaginatedResponse, type StoredAnswer, type Submission, type SubmitOptions, type Webhook, type WebhookWithSecret, createEdpireTokenHandler, toNodeHandler };
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 };
package/dist/client.mjs CHANGED
@@ -201,46 +201,6 @@ var EdpireClient = class {
201
201
  `/learners/${encodeURIComponent(learnerRef)}/results?${query.toString()}`
202
202
  );
203
203
  }
204
- // ── Collections ────────────────────────────────────────────────────────
205
- /**
206
- * List collections in your org.
207
- *
208
- * @param params.page - Page number (default 1).
209
- * @param params.limit - Items per page (default 20, max 100).
210
- * @returns Paginated list of collections with item counts.
211
- */
212
- async getCollections(params) {
213
- const query = new URLSearchParams();
214
- if (params?.page) query.set("page", String(params.page));
215
- if (params?.limit) query.set("limit", String(params.limit));
216
- const qs = query.toString();
217
- return this.requestPaginated("GET", `/collections${qs ? `?${qs}` : ""}`);
218
- }
219
- /**
220
- * Fetch a collection with its assessment items.
221
- *
222
- * @param id - Collection UUID.
223
- * @returns Collection detail with ordered assessment items.
224
- * @throws {EdpireError} 404 if not found.
225
- */
226
- async getCollection(id) {
227
- return this.request("GET", `/collections/${id}`);
228
- }
229
- /**
230
- * Fetch aggregated results across all assessments in a collection.
231
- *
232
- * @param id - Collection UUID.
233
- * @param params.page - Page number (default 1).
234
- * @param params.limit - Items per page (default 50, max 100).
235
- * @returns Paginated flat list of submissions with assessment titles.
236
- */
237
- async getCollectionResults(id, params) {
238
- const query = new URLSearchParams();
239
- if (params?.page) query.set("page", String(params.page));
240
- if (params?.limit) query.set("limit", String(params.limit));
241
- const qs = query.toString();
242
- return this.requestPaginated("GET", `/collections/${id}/results${qs ? `?${qs}` : ""}`);
243
- }
244
204
  // ── Webhooks ───────────────────────────────────────────────────────────
245
205
  /**
246
206
  * Register a webhook endpoint.
package/dist/core.d.mts CHANGED
@@ -146,4 +146,38 @@ interface FlatStep {
146
146
  */
147
147
  declare function flattenAssessment(assessment: Assessment): FlatStep[];
148
148
 
149
- export { type FlatStep, type StoredAnswer, buildSubmitPayload, flattenAssessment };
149
+ /**
150
+ * "Did the learner actually answer this?"
151
+ *
152
+ * Used to warn before submit when questions are left blank. The whole module
153
+ * exists because the obvious implementation is wrong: every player emits a
154
+ * RuntimeAnswer on mount, so a freshly-opened assessment already reports one
155
+ * answer per node. A typed blank emits `{ mode: "typed", text: "" }`, a choice
156
+ * set emits `{ selectedIds: [] }`. Counting answers would report every
157
+ * assessment fully answered and the warning would never fire.
158
+ *
159
+ * The expected node count comes from the content AST, never from `answerKeys`.
160
+ * A learner-facing payload ships `answerKeys: []` on purpose (see
161
+ * `getAssessmentForTaking`), so a key-based count works in the builder preview
162
+ * and silently never fires for a real learner, which is the worst of both.
163
+ */
164
+
165
+ /**
166
+ * True when this answer carries something the learner actually supplied.
167
+ *
168
+ * The `switch` is exhaustive over RuntimeAnswer so adding a variant upstream
169
+ * fails the build here rather than silently defaulting. The runtime fallback is
170
+ * still `true`: a variant we do not recognise should not make the learner sit
171
+ * through a warning they cannot clear, because a warning that cries wolf gets
172
+ * clicked through and stops protecting anyone.
173
+ */
174
+ declare function isAnswered(answer: RuntimeAnswer): boolean;
175
+ /**
176
+ * How many inputs this question's content AST presents to the learner.
177
+ *
178
+ * Walks the tree rather than the top level: blanks are inline inside
179
+ * paragraphs, and any node can sit inside a table cell or blockquote.
180
+ */
181
+ declare function countAnswerableNodes(content: unknown): number;
182
+
183
+ export { type FlatStep, type StoredAnswer, buildSubmitPayload, countAnswerableNodes, flattenAssessment, isAnswered };
package/dist/core.mjs CHANGED
@@ -1 +1 @@
1
- function i(r){let s=[],e=0;for(let t of r.exercises)for(let n of t.questions)s.push({exerciseId:t.id,questionId:n.id,content:n.content_ast,points:n.points,sequenceNumber:n.sequence_number,index:e++});return s}function o(r){let s=new Map;for(let e of r)s.has(e.exerciseId)||s.set(e.exerciseId,[]),s.get(e.exerciseId).push({questionId:e.questionId,answers:e.answers});return{exerciseAnswers:Array.from(s.entries()).map(([e,t])=>({exerciseId:e,questionAnswers:t}))}}export{o as buildSubmitPayload,i as flattenAssessment};
1
+ function c(e){let n=[],t=0;for(let s of e.exercises)for(let r of s.questions)n.push({exerciseId:s.id,questionId:r.id,content:r.content_ast,points:r.points,sequenceNumber:r.sequence_number,index:t++});return n}function u(e){let n=new Map;for(let t of e)n.has(t.exerciseId)||n.set(t.exerciseId,[]),n.get(t.exerciseId).push({questionId:t.questionId,answers:t.answers});return{exerciseAnswers:Array.from(n.entries()).map(([t,s])=>({exerciseId:t,questionAnswers:s}))}}var a=new Set(["choiceSet","inlineChoiceSet","blank","aiAnswerInput","matchingSet","openResponseNode","mathResponse","codingResponse"]),f=new Set(["blankPool","inlinePool"]);function d(e){switch(e.type){case"choiceSet":case"inlineChoiceSet":return e.answer.selectedIds.length>0;case"blank":return e.answer.mode==="choice"?e.answer.choiceId.length>0:e.answer.text.trim().length>0;case"matchingSet":return e.answer.connections.length>0;case"aiAnswer":return e.answer.text.trim().length>0;case"openResponse":{let n=e.answer;return n.recording||n.files&&n.files.length>0?!0:(n.text?.wordCount??0)>0}case"mathResponse":return e.answer.latex.trim().length>0;case"codingResponse":return e.answer.source.trim().length>0;default:{let n=e;return!0}}}function m(e){let n=0,t=s=>{if(Array.isArray(s)){for(let i of s)t(i);return}if(!s||typeof s!="object")return;let{type:r,content:o}=s;if(typeof r=="string"){if(a.has(r)){n+=1;return}if(f.has(r))return}o!==void 0&&t(o)};return t(e),n}export{u as buildSubmitPayload,m as countAnswerableNodes,c as flattenAssessment,d as isAnswered};
package/dist/index.d.mts CHANGED
@@ -30,6 +30,28 @@ interface TakeBranding {
30
30
  showPoweredBy?: boolean;
31
31
  } | null;
32
32
  }
33
+ /**
34
+ * Geometry of the question column. Branding covers colour and type; this covers
35
+ * the one thing branding could not reach.
36
+ */
37
+ interface ShellLayout {
38
+ /**
39
+ * Max width of the question column. Any CSS length, or `"none"` to fill the
40
+ * container. Default `"48rem"` (768px).
41
+ *
42
+ * The default is a reading measure, not an arbitrary cap: at the runtime's
43
+ * base size it yields roughly 70–90 characters per line, already the top of
44
+ * the comfortable range. Past about `"60rem"` the eye starts losing its place
45
+ * on the return sweep, which costs a learner more on a long comprehension
46
+ * passage than the empty gutters ever did.
47
+ *
48
+ * Keep the default when the player owns the whole page (`h-dvh`, no host
49
+ * chrome) — that is what it was measured for. Set `"none"` when you mount the
50
+ * player inside your own layout and your container already supplies the
51
+ * measure, otherwise learners see a column inside a column.
52
+ */
53
+ maxWidth?: string;
54
+ }
33
55
  type NodeDetail = {
34
56
  type: "choiceSet";
35
57
  correctChoiceIds: string[];
@@ -189,6 +211,15 @@ interface MountOptions {
189
211
  * — useful for white-labelling.
190
212
  */
191
213
  branding?: TakeBranding;
214
+ /**
215
+ * Geometry of the question column, for the cases branding cannot reach.
216
+ *
217
+ * The player fills the container you give it, but inside that the questions
218
+ * sit in a centred 768px reading column. That is right when the player owns
219
+ * the page and wrong when you mount it inside your own layout, where it reads
220
+ * as a column inside a column. Pass `{ maxWidth: "none" }` for the latter.
221
+ */
222
+ layout?: ShellLayout;
192
223
  /**
193
224
  * When set, the post-submit "View Full Report" button redirects the browser
194
225
  * to this URL with `?submission_id=...&score=...&max_score=...` appended.
@@ -434,4 +465,4 @@ declare const EdpireAssessment: {
434
465
  mount(options: MountOptions): EmbedInstance;
435
466
  };
436
467
 
437
- export { EdpireAssessment, type EmbedError, type EmbedInstance, type EmbedResult, type ExerciseFeedbackData, type FlatStep, type MountOptions, type OverlayConfig, type QuestionInstance, type RenderQuestionOptions, type ShellLocale, type SpinnerTheme, type StoredAnswer, type SubmitResult, type TakeBranding, buildSubmitPayload, flattenAssessment, renderQuestion };
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 };