diff --git a/packages/types/src/index.ts b/packages/types/src/index.ts index 3cad565..d001dc6 100644 --- a/packages/types/src/index.ts +++ b/packages/types/src/index.ts @@ -1 +1,34 @@ -export * from './openapi.js'; +/** + * Public type surface for `@scormflow/types`. + * + * The `paths` and `components` interfaces are generated from the backend's + * OpenAPI spec by `pnpm run types:generate` at the workspace root. The named + * aliases below give consumers stable, ergonomic names without forcing them to + * index into `components['schemas']` everywhere. + */ +export type { components, paths, operations } from './openapi.js'; +import type { components } from './openapi.js'; + +type Schemas = components['schemas']; + +export type Course = Schemas['Course']; +export type Sco = Schemas['Sco']; +export type ManifestMetadata = Schemas['ManifestMetadata']; +export type CourseListResponse = Schemas['CourseListResponse']; +export type ValidationReport = Schemas['ValidationReport']; + +export type Attempt = Schemas['Attempt']; +export type Score = Schemas['Score']; + +export type RuntimeState = Schemas['RuntimeState']; +export type CommitRequest = Schemas['CommitRequest']; +export type CommitResponse = Schemas['CommitResponse']; +export type CommitWarning = Schemas['CommitWarning']; + +export type AnalyticsOverview = Schemas['AnalyticsOverview']; +export type CourseAnalytics = Schemas['CourseAnalytics']; +export type LearnerAnalytics = Schemas['LearnerAnalytics']; + +export type ApiError = Schemas['Error']; +export type Pagination = Schemas['Pagination']; +export type ScormVersion = Schemas['ScormVersion']; diff --git a/packages/types/src/openapi.d.ts b/packages/types/src/openapi.d.ts new file mode 100644 index 0000000..92d7d17 --- /dev/null +++ b/packages/types/src/openapi.d.ts @@ -0,0 +1,1246 @@ +/** + * This file was auto-generated by openapi-typescript. + * Do not make direct changes to the file. + */ + +export interface paths { + "/health": { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + /** Liveness probe */ + get: { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description Engine is alive */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": { + /** @enum {string} */ + status?: "ok"; + version?: string; + }; + }; + }; + }; + }; + put?: never; + post?: never; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + "/ready": { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + /** Readiness probe (DB + storage reachable) */ + get: { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description Ready */ + 200: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + /** @description Not ready */ + 503: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + put?: never; + post?: never; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + "/play/{attemptId}": { + parameters: { + query?: never; + header?: never; + path: { + attemptId: components["parameters"]["AttemptId"]; + }; + cookie?: never; + }; + /** + * Self-contained iframe player page + * @description Returns an HTML page that loads the SCO, injects the SCORM runtime API + * (`window.API` / `window.API_1484_11`), and persists progress to this engine. + * Host with a single ` + * ``` + */ + get: { + parameters: { + query: { + attemptId: string; + /** @description Attempt JWT (issued by `/auth/attempt-token`). */ + token: string; + }; + header?: never; + path?: never; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description JavaScript runtime bridge */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + "application/javascript": string; + "text/javascript": string; + }; + }; + }; + }; + put?: never; + post?: never; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + "/auth/attempt-token": { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + get?: never; + put?: never; + /** + * Issue a short-lived JWT scoped to a single attempt + * @description Called by the LMS backend to mint a token the browser-side player can use + * without exposing the long-lived API key. Token TTL defaults to the attempt + * duration limit (configurable, max 24h). + */ + post: { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + requestBody: { + content: { + "application/json": { + /** Format: uuid */ + attemptId: string; + /** @default 3600 */ + ttlSeconds?: number; + }; + }; + }; + responses: { + /** @description Token issued */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": { + token?: string; + /** Format: date-time */ + expiresAt?: string; + }; + }; + }; + 404: components["responses"]["NotFound"]; + }; + }; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + "/courses": { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + /** List courses */ + get: { + parameters: { + query?: { + limit?: components["parameters"]["Limit"]; + /** @description Opaque pagination cursor returned by the previous page. */ + cursor?: components["parameters"]["Cursor"]; + /** @description Free-text search on course title. */ + q?: string; + }; + header?: never; + path?: never; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description Paginated course list */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": components["schemas"]["CourseListResponse"]; + }; + }; + }; + }; + put?: never; + /** + * Upload a SCORM package + * @description Accepts a SCORM 1.2 or 2004 ZIP package. The engine extracts the package, + * parses `imsmanifest.xml`, persists metadata, and stores the package files + * via the configured storage adapter. + * + * For large files prefer the two-step flow: + * 1. `POST /courses/upload-url` to get a presigned upload URL. + * 2. `POST /courses` with `{ uploadKey }` to register the uploaded package. + */ + post: { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + requestBody: { + content: { + "multipart/form-data": { + /** + * Format: binary + * @description SCORM package ZIP. + */ + file: string; + /** @description Override the title parsed from the manifest. */ + title?: string; + }; + "application/json": { + /** @description Storage key returned by /courses/upload-url */ + uploadKey: string; + title?: string; + }; + }; + }; + responses: { + /** @description Course created */ + 201: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": components["schemas"]["Course"]; + }; + }; + 400: components["responses"]["BadRequest"]; + /** @description Invalid SCORM package (malformed ZIP or manifest) */ + 422: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": components["schemas"]["Error"]; + }; + }; + }; + }; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + "/courses/upload-url": { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + get?: never; + put?: never; + /** Get a presigned URL for direct package upload */ + post: { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + requestBody: { + content: { + "application/json": { + filename: string; + sizeBytes: number; + /** @default application/zip */ + contentType?: string; + }; + }; + }; + responses: { + /** @description Upload URL issued */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": { + /** Format: uri */ + uploadUrl?: string; + uploadKey?: string; + /** Format: date-time */ + expiresAt?: string; + /** @enum {string} */ + method?: "PUT" | "POST"; + headers?: { + [key: string]: string; + }; + }; + }; + }; + }; + }; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + "/courses/{courseId}": { + parameters: { + query?: never; + header?: never; + path: { + courseId: components["parameters"]["CourseId"]; + }; + cookie?: never; + }; + /** Get a course */ + get: { + parameters: { + query?: never; + header?: never; + path: { + courseId: components["parameters"]["CourseId"]; + }; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description Course */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": components["schemas"]["Course"]; + }; + }; + 404: components["responses"]["NotFound"]; + }; + }; + put?: never; + post?: never; + /** Delete a course and all its attempts */ + delete: { + parameters: { + query?: never; + header?: never; + path: { + courseId: components["parameters"]["CourseId"]; + }; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description Deleted */ + 204: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + 404: components["responses"]["NotFound"]; + }; + }; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + "/courses/{courseId}/launch-url": { + parameters: { + query?: never; + header?: never; + path: { + courseId: components["parameters"]["CourseId"]; + }; + cookie?: never; + }; + /** + * Get a signed launch URL for the course's primary SCO + * @description Returns a short-lived URL pointing at the SCO entry point on the engine's + * static asset host. The player loads this in an iframe. + */ + get: { + parameters: { + query?: { + /** @description Optional — defaults to the manifest's primary SCO. */ + scoId?: string; + }; + header?: never; + path: { + courseId: components["parameters"]["CourseId"]; + }; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description Launch URL */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": { + /** Format: uri */ + launchUrl?: string; + /** Format: date-time */ + expiresAt?: string; + }; + }; + }; + }; + }; + put?: never; + post?: never; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + "/courses/validate": { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + get?: never; + put?: never; + /** + * Validate a SCORM package without registering it + * @description Useful for CI / authoring pipelines. No course is persisted. + */ + post: { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + requestBody: { + content: { + "multipart/form-data": { + /** Format: binary */ + file: string; + }; + }; + }; + responses: { + /** @description Validation report */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": components["schemas"]["ValidationReport"]; + }; + }; + }; + }; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + "/attempts": { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + get?: never; + put?: never; + /** + * Start a new attempt + * @description Creates a new attempt for a learner against a course. If a non-completed + * attempt already exists and `resume=true`, returns that attempt instead. + */ + post: { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + requestBody: { + content: { + "application/json": { + /** Format: uuid */ + courseId: string; + /** + * @description Opaque identifier from the host LMS. The engine never stores PII — + * this is the only learner identifier it knows. + */ + learnerId: string; + /** @description Optional display name passed to the SCO as `cmi.core.student_name`. */ + learnerName?: string; + /** + * @description If true, return the latest in-progress attempt instead of creating a new one. + * @default true + */ + resume?: boolean; + }; + }; + }; + responses: { + /** @description Attempt created (or resumed) */ + 201: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": components["schemas"]["Attempt"]; + }; + }; + 404: components["responses"]["NotFound"]; + }; + }; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + "/attempts/{attemptId}": { + parameters: { + query?: never; + header?: never; + path: { + attemptId: components["parameters"]["AttemptId"]; + }; + cookie?: never; + }; + /** Get an attempt */ + get: { + parameters: { + query?: never; + header?: never; + path: { + attemptId: components["parameters"]["AttemptId"]; + }; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description Attempt */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": components["schemas"]["Attempt"]; + }; + }; + 404: components["responses"]["NotFound"]; + }; + }; + put?: never; + post?: never; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + "/attempts/{attemptId}/finish": { + parameters: { + query?: never; + header?: never; + path: { + attemptId: components["parameters"]["AttemptId"]; + }; + cookie?: never; + }; + get?: never; + put?: never; + /** + * Force-finalize an attempt + * @description Normally an attempt is terminated by the SCO via `/runtime/{attemptId}/terminate`. + * This endpoint exists for LMS-driven workflows (e.g. timeout, admin intervention). + */ + post: { + parameters: { + query?: never; + header?: never; + path: { + attemptId: components["parameters"]["AttemptId"]; + }; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description Attempt finalized */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": components["schemas"]["Attempt"]; + }; + }; + 404: components["responses"]["NotFound"]; + }; + }; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + "/runtime/{attemptId}/initialize": { + parameters: { + query?: never; + header?: never; + path: { + attemptId: components["parameters"]["AttemptId"]; + }; + cookie?: never; + }; + get?: never; + put?: never; + /** + * Initialize a runtime session + * @description Called by the player when the SCO invokes `LMSInitialize` / `Initialize`. + * Returns the full CMI data model snapshot (empty for a new attempt, populated + * for a resume). + */ + post: { + parameters: { + query?: never; + header?: never; + path: { + attemptId: components["parameters"]["AttemptId"]; + }; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description Runtime state */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": components["schemas"]["RuntimeState"]; + }; + }; + /** @description Attempt already terminated. */ + 409: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": components["schemas"]["Error"]; + }; + }; + }; + }; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + "/runtime/{attemptId}/commit": { + parameters: { + query?: never; + header?: never; + path: { + attemptId: components["parameters"]["AttemptId"]; + }; + cookie?: never; + }; + get?: never; + put?: never; + /** + * Commit a batch of CMI value changes + * @description Persists a batch of CMI changes. The player should call this: + * - On `LMSCommit` / `Commit` from the SCO. + * - On a debounced interval (e.g. every 10s) to reduce data loss risk. + * - On `beforeunload` (with `keepalive: true`). + * + * Keys use SCORM-version-native naming: + * - SCORM 1.2: `cmi.core.lesson_status`, `cmi.suspend_data`, ... + * - SCORM 2004: `cmi.completion_status`, `cmi.success_status`, ... + * + * **Validation policy:** the engine mirrors real-world LMS behavior — invalid + * or unknown CMI keys are silently accepted and surfaced as `warnings` in the + * response (and in server logs) rather than rejecting the batch. This matches + * what certified commercial LMSes do; SCORM content in the wild routinely + * violates the spec and rejecting commits would break otherwise-functional + * courses. Use the `warnings` array for observability, not for control flow. + */ + post: { + parameters: { + query?: never; + header?: never; + path: { + attemptId: components["parameters"]["AttemptId"]; + }; + cookie?: never; + }; + requestBody: { + content: { + "application/json": components["schemas"]["CommitRequest"]; + }; + }; + responses: { + /** @description Commit accepted (possibly with warnings). */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": components["schemas"]["CommitResponse"]; + }; + }; + }; + }; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + "/runtime/{attemptId}/terminate": { + parameters: { + query?: never; + header?: never; + path: { + attemptId: components["parameters"]["AttemptId"]; + }; + cookie?: never; + }; + get?: never; + put?: never; + /** + * Terminate a runtime session + * @description Called by the player when the SCO invokes `LMSFinish` / `Terminate`. + * Persists any final batch of values and finalizes the attempt. + */ + post: { + parameters: { + query?: never; + header?: never; + path: { + attemptId: components["parameters"]["AttemptId"]; + }; + cookie?: never; + }; + requestBody?: { + content: { + "application/json": { + /** @description Final batch of CMI values to persist before termination. */ + values?: { + [key: string]: unknown; + }; + }; + }; + }; + responses: { + /** @description Attempt terminated */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": { + attempt?: components["schemas"]["Attempt"]; + }; + }; + }; + }; + }; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + "/analytics/overview": { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + /** Tenant-wide analytics overview */ + get: { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description Overview */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": components["schemas"]["AnalyticsOverview"]; + }; + }; + }; + }; + put?: never; + post?: never; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + "/analytics/courses/{courseId}": { + parameters: { + query?: never; + header?: never; + path: { + courseId: components["parameters"]["CourseId"]; + }; + cookie?: never; + }; + /** Analytics for a single course */ + get: { + parameters: { + query?: never; + header?: never; + path: { + courseId: components["parameters"]["CourseId"]; + }; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description Course analytics */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": components["schemas"]["CourseAnalytics"]; + }; + }; + }; + }; + put?: never; + post?: never; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + "/analytics/learners/{learnerId}": { + parameters: { + query?: never; + header?: never; + path: { + learnerId: string; + }; + cookie?: never; + }; + /** Analytics for a single learner */ + get: { + parameters: { + query?: never; + header?: never; + path: { + learnerId: string; + }; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description Learner analytics */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": components["schemas"]["LearnerAnalytics"]; + }; + }; + }; + }; + put?: never; + post?: never; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; +} +export type webhooks = Record; +export interface components { + schemas: { + Error: { + /** @description Stable machine-readable error code (e.g. `course_not_found`). */ + code: string; + message: string; + details?: { + [key: string]: unknown; + }; + requestId?: string; + }; + Pagination: { + nextCursor?: string | null; + hasMore?: boolean; + }; + /** @enum {string} */ + ScormVersion: "SCORM_1_2" | "SCORM_2004_2" | "SCORM_2004_3" | "SCORM_2004_4"; + Course: { + /** Format: uuid */ + id: string; + title: string; + description?: string | null; + version: components["schemas"]["ScormVersion"]; + /** @enum {string} */ + status: "processing" | "ready" | "failed"; + scos?: components["schemas"]["Sco"][]; + /** @description Default SCO launched when the player starts. */ + primaryScoId?: string; + /** @description 0-100 mastery threshold parsed from the manifest. */ + masteryScore?: number | null; + manifest?: components["schemas"]["ManifestMetadata"]; + sizeBytes?: number; + /** Format: date-time */ + createdAt: string; + /** Format: date-time */ + updatedAt?: string; + }; + Sco: { + id: string; + /** @description Manifest `identifier` attribute. */ + identifier: string; + title: string; + /** @description Relative path within the package to the SCO entry point. */ + launchHref: string; + parameters?: string | null; + masteryScore?: number | null; + }; + ManifestMetadata: { + identifier?: string; + title?: string; + description?: string | null; + keywords?: string[]; + schemaVersion?: string; + defaultOrganization?: string | null; + }; + CourseListResponse: { + data?: components["schemas"]["Course"][]; + pagination?: components["schemas"]["Pagination"]; + }; + ValidationReport: { + valid?: boolean; + version?: components["schemas"]["ScormVersion"] | null; + errors?: { + code?: string; + message?: string; + path?: string | null; + }[]; + warnings?: { + code?: string; + message?: string; + }[]; + }; + Attempt: { + /** Format: uuid */ + id: string; + /** Format: uuid */ + courseId: string; + learnerId: string; + learnerName?: string | null; + /** @description 1-indexed sequence of attempts by this learner on this course. */ + attemptNumber: number; + /** @enum {string} */ + status: "not_started" | "in_progress" | "completed" | "passed" | "failed" | "terminated"; + /** + * @description SCORM 2004 completion status; mapped from `cmi.completion_status`. + * @enum {string} + */ + completionStatus?: "unknown" | "completed" | "incomplete" | "not_attempted"; + /** + * @description SCORM 2004 success status; mapped from `cmi.success_status`. + * @enum {string} + */ + successStatus?: "unknown" | "passed" | "failed"; + score?: components["schemas"]["Score"]; + progressMeasure?: number | null; + /** @description Total accumulated session time across all sessions in this attempt. */ + totalTimeSeconds?: number; + /** @description Bookmark (`cmi.core.lesson_location` / `cmi.location`). */ + location?: string | null; + /** Format: date-time */ + startedAt: string; + /** Format: date-time */ + lastAccessedAt?: string; + /** Format: date-time */ + completedAt?: string | null; + }; + Score: { + raw?: number | null; + min?: number | null; + max?: number | null; + /** @description SCORM 2004 normalized score (-1..1). */ + scaled?: number | null; + }; + RuntimeState: { + /** Format: uuid */ + attemptId: string; + version: components["schemas"]["ScormVersion"]; + /** + * @description Full CMI data model snapshot, keyed by SCORM-native paths. Empty object + * for a new attempt; for a resume, contains every previously-committed key. + * @example { + * "cmi.core.lesson_status": "incomplete", + * "cmi.core.lesson_location": "page_4", + * "cmi.suspend_data": "{\"chapter\":2,\"answers\":[1,3,2]}", + * "cmi.core.score.raw": 42 + * } + */ + cmi: { + [key: string]: unknown; + }; + learner?: { + id?: string; + name?: string | null; + }; + /** + * @description SCORM `cmi.core.entry` / `cmi.entry`. + * @enum {string} + */ + entry?: "ab_initio" | "resume" | ""; + }; + CommitRequest: { + /** + * @description Object of CMI key → value pairs to persist. Keys must match the + * SCORM version of the course (validated server-side). + * @example { + * "cmi.core.lesson_status": "completed", + * "cmi.core.score.raw": 87, + * "cmi.suspend_data": "{\"chapter\":3}" + * } + */ + values: { + [key: string]: unknown; + }; + /** + * @description Additional session time to add to the attempt's running total. Sent by + * the player rather than the SCO so the server controls the authoritative + * elapsed time. + */ + sessionTimeDeltaSeconds?: number; + }; + CommitResponse: { + ok: boolean; + /** Format: date-time */ + committedAt: string; + attempt: components["schemas"]["Attempt"]; + /** + * @description Non-fatal issues with the committed batch. Values are still persisted + * (see endpoint description for rationale). Use for observability and + * content-author feedback, not for retry logic. + */ + warnings?: components["schemas"]["CommitWarning"][]; + }; + CommitWarning: { + /** + * @description Stable warning code for filtering / metrics. + * @enum {string} + */ + code: "unknown_key" | "read_only_key" | "invalid_value_type" | "out_of_range" | "invalid_format" | "version_mismatch"; + key: string; + value?: unknown; + message: string; + }; + AnalyticsOverview: { + courseCount?: number; + learnerCount?: number; + attemptCount?: number; + completionRate?: number; + averageScore?: number | null; + }; + CourseAnalytics: { + /** Format: uuid */ + courseId?: string; + attemptCount?: number; + completionCount?: number; + completionRate?: number; + averageScore?: number | null; + averageTimeSeconds?: number | null; + passRate?: number | null; + recentAttempts?: components["schemas"]["Attempt"][]; + }; + LearnerAnalytics: { + learnerId?: string; + attemptCount?: number; + completedCourseCount?: number; + totalTimeSeconds?: number; + recentAttempts?: components["schemas"]["Attempt"][]; + }; + }; + responses: { + /** @description Request was malformed. */ + BadRequest: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": components["schemas"]["Error"]; + }; + }; + /** @description Resource not found. */ + NotFound: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": components["schemas"]["Error"]; + }; + }; + /** @description Missing or invalid credentials. */ + Unauthorized: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": components["schemas"]["Error"]; + }; + }; + }; + parameters: { + CourseId: string; + AttemptId: string; + Limit: number; + /** @description Opaque pagination cursor returned by the previous page. */ + Cursor: string; + }; + requestBodies: never; + headers: never; + pathItems: never; +} +export type $defs = Record; +export type operations = Record; diff --git a/packages/types/src/openapi.ts b/packages/types/src/openapi.ts deleted file mode 100644 index cb0ff5c..0000000 --- a/packages/types/src/openapi.ts +++ /dev/null @@ -1 +0,0 @@ -export {};