0.4.0 • Published 3d ago
@timeback/qti
Licence
—
Version
0.4.0
Deps
2
Size
286 kB
Vulns
0
Weekly
0
@timeback/qti
TypeScript client for the QTI 3.0 assessment API.
Installation
bun add @timeback/qti
Quick Start
import { QtiClient } from '@timeback/qti'
const client = new QtiClient({
env: 'staging',
auth: { clientId: '...', clientSecret: '...' },
})
const { items } = await client.assessmentItems.list({ query: 'fractions', limit: 20 })
const { items: stimuli } = await client.stimuli.list({ query: 'fractions', limit: 20 })
const item = await client.assessmentItems.get('item-123')
Resources
| Namespace | Methods |
|---|---|
client.assessmentItems |
List, get, create, update, delete assessment items |
client.assessmentTests |
List, get, create, update, delete assessment tests; fetch questions |
client.stimuli |
List, get, create, update, delete stimuli (passages) |
client.validate |
Validate QTI XML against schema (single and batch) |
client.lesson |
Lesson feedback operations |
client.general |
General/utility endpoints |
Filtering
The top-level assessment-item and assessment-test lists accept the same type-safe where clause as the other Timeback clients, compiled to the server-side filter expression:
// Exact match
const drafts = await client.assessmentTests.list({
where: { title: 'Unit 5 Final' },
})
// Substring/regex match (case-insensitive)
const mine = await client.assessmentItems.list({
where: { identifier: { contains: '^playcademy-test-' } },
})
// Streams filter server-side too
for await (const test of client.assessmentTests.stream({
where: { title: { contains: 'math' } },
})) {
console.log(test.identifier)
}
Filterable fields are curated per entity (AssessmentItemFilterFields, AssessmentTestFilterFields from @timeback/types). Nested lists (test parts, sections, stimuli) do not support filtering.
Configuration
The client supports three configuration modes:
// Environment mode — resolves URLs automatically
new QtiClient({ env: 'staging', auth: { clientId, clientSecret } })
// Explicit mode — custom API endpoint
new QtiClient({ baseUrl: 'https://qti.example.com/api', auth: { clientId, clientSecret, authUrl } })
// Environment variables fallback
// QTI_BASE_URL, QTI_TOKEN_URL, QTI_CLIENT_ID, QTI_CLIENT_SECRET
new QtiClient()
Parsing QTI XML
@timeback/qti/parse provides dependency-free utilities for extracting structured data from QTI 3.0 XML. Works in any runtime (browser, Node, Bun).
import { parseQtiXml } from '@timeback/qti/parse'
const item = parseQtiXml(xml)
item.prompt // "What is 2 + 2?"
item.choices // [{ identifier: "A", text: "3" }, { identifier: "B", text: "4" }]
item.correctAnswer // "B"
item.feedback // inline feedback per choice
item.modalFeedback // modal feedback (correct/incorrect)
Individual extractors are also available for fine-grained control:
import { extractChoices, extractCorrectResponse, extractPrompt } from '@timeback/qti/parse'
const prompt = extractPrompt(xml)
const choices = extractChoices(xml)
const answer = extractCorrectResponse(xml)
Additional Exports
| Entry point | Purpose |
|---|---|
@timeback/qti/parse |
QTI XML parsing (see above) |
@timeback/qti/errors |
Error classes: QtiError, NotFoundError, ValidationError, etc. |
@timeback/qti/types |
All public TypeScript types |