@telebort/question-banks
v2.3.0
Published
Question Banks SDK with three-tier access: Free (schemas), Standard (validation), Premium (full access + grading)
Maintainers
Readme
@telebort/question-banks
Question Banks SDK for Telebort educational assessments. Provides Zod schemas, TypeScript types, client-side quiz generation, v2.0 Knowledge Graph access, and CAT (Computerized Adaptive Testing) orchestration.
v2.3.0 - Expanded schema validation for all 27 courses, full CAT engine with Sympson-Hetter exposure control, IRT 4PL calibration, and 1.45M+ question bank access.
Installation
# SDK + CLI (recommended)
npm install @telebort/question-banks zod
# CLI only (no install required)
npx @telebort/question-banks <command>Quick Start (3 Scenarios)
Scenario A: Validate Course Files (CLI)
Quickly validate JSON files against schemas:
# Validate all course files in a directory
npx @telebort/question-banks validate ./data/courses/ --verbose
# Show question bank statistics
npx @telebort/question-banks stats --data-dir ./data/courses/
# Run guessability analysis (anti-guessing QA)
npx @telebort/question-banks score ./data/courses/ai-1.jsonScenario B: Build a Quiz App (SDK)
Use the factory function to create a fully-featured SDK instance:
import { createQuestionBanksSDK } from '@telebort/question-banks'
const sdk = createQuestionBanksSDK({
dataSource: {
async loadCourses() {
const res = await fetch('https://content-warehouse.vercel.app/question-banks/v2.0/courses/CS1.json')
return [await res.json()]
}
}
})
// Generate a quiz
const quiz = await sdk.quiz.generateQuiz({ questionCount: 5 })
// Check an answer with feedback
const result = await sdk.validate.checkAnswer('cs-1-l1-q1', 'B', 'formative')
// { isCorrect: true, feedback: {...}, misconceptionId: null }Scenario C: Validate Data Structures (Schemas Only)
Import just the Zod schemas for lightweight validation:
import { QuestionSchema, CourseSchema } from '@telebort/question-banks/schemas'
const result = QuestionSchema.safeParse(myQuestion)
if (!result.success) {
console.error('Validation failed:', result.error.issues)
}
// TypeScript type inference
import type { Question, Course } from '@telebort/question-banks'Entry Points
| Import Path | Purpose | Use Case |
|-------------|---------|----------|
| @telebort/question-banks | Full SDK factory | Quiz apps, data access |
| @telebort/question-banks/schemas | Zod schemas only | Lightweight validation |
| @telebort/question-banks/validation | ValidationClient | Answer checking |
| @telebort/question-banks/premium | PremiumClient (JWT) | Full API access |
| @telebort/question-banks/irt-calibration | IRT calibration tools | Psychometric analysis |
| @telebort/question-banks/cat | CAT engine | Adaptive testing |
⚠️ Migration Notice
If you're using the deprecated CLI package:
# Uninstall old CLI package
npm uninstall @telebort/question-banks-cli
# Use the canonical package (CLI included)
npx @telebort/question-banks validate ./data/What's New in v2.1.x
CAT Orchestration Engine
- Sympson-Hetter Exposure Control: Industry-standard algorithm (used in GRE, GMAT) to prevent item overexposure
- Stopping Rules: SE-threshold + fixed-length dual criteria for test termination
- Content Balancing: Blueprint constraint satisfaction for topic coverage
- IRT 4PL: Full 4-parameter logistic model with
estimateAbilityEAP()Bayesian estimation
Scale
- 1.45M+ Questions: 120 JSON files (2.7GB) with 26 CDN shards for global delivery
- CS Algorithms: 1.35M procedurally generated questions (arrays, DP, graphs, recursion, sorting, strings)
- Malaysian Math: 94K bilingual questions (KSSR 30K + KSSM 22K + SPM 34K + STPM 8K)
- Knowledge Graph v2.0: 4-level taxonomy with topic-based queries
Previous Additions (v1.4.x)
- Malaysian Math Module:
sdk.malaysiaMathfor procedural question generation - 104 Templates: KSSR, KSSM, SPM Add Maths, STPM covering Years 1-6, Forms 1-6
- Bilingual: Bahasa Malaysia and English support
Architecture
The SDK provides client-side access to question bank data via CDN:
┌─────────────────────────────────────────────────────────────┐
│ SDK Access Patterns │
├─────────────────────────────────────────────────────────────┤
│ │
│ v1.x Compatibility (Course-based) │
│ └── sdk.data.getCourse('CS1') │
│ │
│ v2.0 Knowledge Graph (Topic-based) │
│ ├── sdk.knowledge.getByTopic('algorithms/sorting') │
│ └── sdk.taxonomy.getDomains() │
│ │
│ Premium API (JWT-authenticated) │
│ └── PremiumClient with offline fallback │
│ │
└─────────────────────────────────────────────────────────────┘No server required - all operations work client-side.
Quick Start (CDN Mode)
Fetch questions from CDN for automatic updates:
import { createQuestionBanksSDK } from '@telebort/question-banks'
const CDN_BASE = 'https://content-warehouse.vercel.app/question-banks/v1.1/courses'
const sdk = createQuestionBanksSDK({
dataSource: {
async loadCourses() {
const codes = ['AI1', 'M1', 'W1', 'CS1']
const courses = await Promise.all(
codes.map(code => fetch(`${CDN_BASE}/${code}.json`).then(r => r.json()))
)
return courses
}
}
})
// Generate a quiz
const quiz = await sdk.quiz.generateQuiz({ questionCount: 5 })
// Check an answer with feedback
const result = await sdk.validate.checkAnswer('ai-1-l1-q1', 'B', 'formative')
// { isCorrect: true, feedback: {...}, misconceptionId: null }v2.0 Knowledge Graph
Access questions by topic instead of course. Query across curricula with the 4-level taxonomy.
Full Guide: See KNOWLEDGE-GRAPH.md for complete API reference and examples.
Taxonomy Structure
Domain (L1) Strand (L2) Topic (L3)
│ │ │
computer-science ──→ algorithms ──────→ sorting
data-structures ──→ arrays, trees, graphs
web-development ──→ javascript ───────→ arrow-functions, promises
html-css ─────────→ flexbox, grid6 Domains: computer-science, artificial-intelligence, web-development, mathematics, computational-thinking, mobile-development
Basic Usage
import { createKnowledgeModule, createTaxonomyModule } from '@telebort/question-banks'
const CDN_BASE = 'https://content-warehouse.vercel.app'
// Create modules
const knowledge = createKnowledgeModule({ cdnBase: CDN_BASE })
const taxonomy = createTaxonomyModule({ cdnBase: CDN_BASE })
// Get questions by topic path
const sorting = await knowledge.getByTopic('computer-science/algorithms/sorting')
console.log(`${sorting.length} sorting questions`) // Returns TopicQuestionRef[]
// Browse taxonomy
const domains = await taxonomy.getDomains()
const strands = await taxonomy.getStrands('computer-science')Advanced Search with Filters
// Find medium-difficulty sorting questions from CS1
const results = await knowledge.search({
domain: 'computer-science',
strand: 'algorithms',
topic: 'sorting',
difficulty: 'medium',
courseCode: 'CS1',
limit: 10,
offset: 0
})
// Paginate through all web-dev questions
let page = await knowledge.search({ domain: 'web-development', limit: 50, offset: 0 })Error Handling with Debug Logging
const knowledge = createKnowledgeModule({
cdnBase: CDN_BASE,
cacheEnabled: true, // Enable caching
debug: true, // Log to console
onError: (error, context) => {
console.error(`[${context}]`, error.message)
// Send to monitoring: Sentry.captureException(error)
}
})v2.0 CDN Structure
/question-banks/v2.0/
├── courses/{CODE}.json # Course-based (v1.x compatible)
├── by-topic/{domain}/{strand}/{topic}.json # Topic-based indexes
├── taxonomy/topics.json # 4-level topic tree
└── master/
├── knowledge-bank-index.json # Shard metadata (50KB)
└── shards/shard-{00001-00026}.json # 10K questions each (~20MB)Total: 1,449,830+ questions in 26 CDN shards for global delivery.
CDN Endpoints
Base URL: https://content-warehouse.vercel.app
| Endpoint | Size | Content |
|----------|------|---------|
| /question-banks/v2.0/courses/{CODE}.json | ~400KB | Single course |
| /question-banks/v2.0/taxonomy/topics.json | ~49KB | 4-level taxonomy |
| /question-banks/v2.0/master/knowledge-bank-index.json | ~7KB | Shard metadata |
| /question-banks/v2.0/master/shards/shard-{00001-00026}.json | ~20MB | 10K questions each |
Available Courses: AI1, AI2, AI25, AI3, M1, M2, M3, W1, W2, W3, W35, W4, F1, F2, JC, BBW, BBP, BBD, BBAI, CS1, CS2, CS3, CS4
Static Mode (Bundled JSON)
For offline-first apps, bundle the JSON with your build:
import { createQuestionBanksSDK } from '@telebort/question-banks'
import coursesData from './data/courses.json'
const sdk = createQuestionBanksSDK({
dataSource: {
async loadCourses() {
return coursesData.courses
}
}
})
// All SDK features work offline
const courses = await sdk.data.getCourses()
const quiz = await sdk.quiz.generateQuiz({ questionCount: 5 })
const result = await sdk.validate.checkAnswer('ai-1-l1-q1', 'B', 'formative')Premium Client (JWT-Authenticated)
For full API access with offline fallback (v1.3.0+):
import { PremiumClient } from '@telebort/question-banks/premium'
const client = new PremiumClient({
token: 'your-jwt-token',
// Offline support (v1.3.0)
offlineFallback: true, // Use cache when network fails
cacheTTL: 300000, // 5 minutes cache TTL
// Rate limiting (built-in: 10 req/s, burst 20)
timeout: 30000, // Request timeout
// Debug logging
logger: (msg, level) => console.log(`[${level}] ${msg}`),
})
// Preload courses for offline use
await client.preloadForOffline(['cs-1', 'cs-2', 'ai-1'])
// Fetch questions (uses cache if offline)
const { questions, total, hasMore } = await client.getQuestions({
courseId: 'cs-1',
difficulty: 'medium',
limit: 10,
})
// Grade an assessment
const result = await client.gradeAssessment({
assessmentId: 'uuid-here',
courseId: 'cs-1',
submittedAt: new Date().toISOString(),
responses: [
{ questionId: 'q1', selectedAnswer: 'A' },
{ questionId: 'q2', selectedAnswer: 'B' },
]
})
// Cache management
const stats = client.getCacheStats()
console.log(`Cached entries: ${stats.entries}`)
client.clearCache()SDK API Reference
The SDK is organized into focused modules. Each module handles a specific domain:
| Module | Purpose | Key Methods |
|--------|---------|-------------|
| sdk.data | Data access | getCourses(), getCourse(), getQuestion() |
| sdk.quiz | Quiz generation | generateQuiz(), getLessonQuiz() |
| sdk.validate | Answer checking | checkAnswer() |
| sdk.query | Filtering | filterQuestions(), getRandomQuestions() |
| sdk.search | Full-text search | search(), searchByTags() |
| sdk.analytics | Statistics | getStatistics(), getCourseStatistics() |
| sdk.knowledge | v2.0 Knowledge Graph | getByTopic(), getByDomain(), search() |
| sdk.taxonomy | Topic taxonomy | getDomains(), getTopics() |
Common Workflows
Build a quiz from a specific course:
const quiz = await sdk.quiz.generateQuiz({
courseId: 'cs-1',
questionCount: 10,
difficulty: 'medium'
})Check an answer with feedback:
const result = await sdk.validate.checkAnswer('cs-1-l1-q1', 'B', 'formative')
// Returns: { isCorrect, feedback, misconceptionId }Search by topic (v2.0 Knowledge Graph):
const questions = await sdk.knowledge.getByTopic('computer-science/algorithms/sorting')Get course statistics:
const stats = await sdk.analytics.getCourseStatistics('ai-1')
// Returns: { totalQuestions, byDifficulty, byType, ... }SDK Interface (TypeScript)
interface QuestionBanksSDK {
// v1.x Course-based access
data: {
getCourses(): Promise<Course[]>
getCourse(courseId: string): Promise<Course | null>
getLesson(courseId: string, lessonNumber: number): Promise<Lesson | null>
getQuestion(questionId: string): Promise<Question | null>
getAllQuestions(): Promise<Question[]>
}
query: {
filterQuestions(filters: QuestionFilters): Promise<QueryResult<Question>>
getRandomQuestions(count: number, filters?: QuestionFilters): Promise<Question[]>
}
quiz: {
generateQuiz(criteria: QuizCriteria): Promise<{ questions: Question[]; metadata: object }>
getLessonQuiz(courseId: string, lessonNumber: number): Promise<Question[]>
}
search: {
search(options: SearchOptions): Promise<QueryResult<Question>>
searchByTags(tags: string[], matchAll?: boolean): Promise<Question[]>
}
analytics: {
getStatistics(): Promise<Statistics>
getCourseStatistics(courseId: string): Promise<Statistics>
}
validate: {
checkAnswer(questionId: string, answer: string, mode: 'formative' | 'summative'): Promise<AnswerResult>
}
// v2.0 Topic-based access (NEW)
knowledge: {
getByTopic(topicPath: string): Promise<TopicIndex>
getByDomain(domainId: string): Promise<Question[]>
search(filters: KnowledgeFilters): Promise<Question[]>
}
taxonomy: {
getDomains(): Promise<string[]>
getTopics(): Promise<TaxonomyTree>
}
}Zod Schemas (Free Validation)
Import Zod schemas for offline validation:
import { QuestionSchema, CourseSchema } from '@telebort/question-banks/schemas'
import { z } from 'zod'
// Validate a question
const result = QuestionSchema.safeParse(myQuestion)
if (!result.success) {
console.error(result.error.issues)
}
// Type inference
type Question = z.infer<typeof QuestionSchema>Available Schemas
// Question schemas
QuestionSchema // Full question with v1.1 enhancements
OptionSchema // Answer option with misconception tracking
FeedbackSchema // Structured feedback (short/detailed/socraticHint)
// Course schemas
CourseSchema // Course with lessons and questions
LessonSchema // Lesson with questions
// Assessment schemas
AssessmentSubmissionSchema // User assessment submission
GradedAssessmentSchema // Graded result with misconception analysisCLI Reference
The CLI provides validation, statistics, and QA tools. Use via npx (no install) or globally:
npx @telebort/question-banks <command> [options]Commands
| Command | Description |
|---------|-------------|
| validate <path> | Validate JSON files against schemas |
| stats | Show question bank statistics |
| quiz | Generate sample quizzes |
| score | Guessability analysis (anti-guessing QA) |
validate - Schema Validation
# Validate a single file
npx @telebort/question-banks validate ./data/courses/ai-1.json
# Validate all files in a directory
npx @telebort/question-banks validate ./data/courses/
# Verbose output with all errors
npx @telebort/question-banks validate ./data/courses/ --verbosestats - Question Bank Statistics
# Show aggregate statistics across all courses
npx @telebort/question-banks stats --data-dir ./data/courses/
# Statistics for a specific course
npx @telebort/question-banks stats --course ai-1 --data-dir ./data/courses/quiz - Sample Quiz Generation
# Generate 5 random questions
npx @telebort/question-banks quiz --data-dir ./data/courses/
# Generate 10 questions from a specific course
npx @telebort/question-banks quiz --course ai-1 --count 10 --data-dir ./data/courses/
# Filter by difficulty and show correct answers
npx @telebort/question-banks quiz --difficulty hard --show-answers --data-dir ./data/courses/score - Guessability Analysis
Run psychometric QA analysis to detect testwiseness vulnerabilities:
# Analyze a single course file
npx @telebort/question-banks score ./data/courses/ai-1.json
# Analyze with detailed output
npx @telebort/question-banks score ./data/courses/ --verboseOutput includes:
- Guessability score (0-100, lower is better)
- Distractor quality metrics
- Option length bias detection
- Grammatical cue warnings
Question Schema (v1.1)
Questions include v1.1 enhancements for misconception tracking:
interface Question {
questionId: string // "ai-1-l1-q1"
globalId: string // "exit-ticket-0351"
questionType: QuestionType // vocabulary, code_understanding, etc.
questionArchetype?: string // vocabulary, trace, bebras, blockmodel
prompt: string
hasCodeBlock: boolean
codeLanguage: string | null
codeContent: string | null
// v1.1: Misconception targeting
misconceptionTargets?: string[]
options: Option[] // 4 options with misconception feedback
correctAnswer: 'A' | 'B' | 'C' | 'D'
metadata: {
difficulty: 'easy' | 'medium' | 'hard' | 'challenge'
bloomsTaxonomy: 'remember' | 'understand' | 'apply' | ...
tags: string[]
}
}
interface Option {
key: 'A' | 'B' | 'C' | 'D'
text: string
isCorrect: boolean
// v1.1: Misconception feedback
misconceptionId?: string // "INPUT_PROMPT_VS_OUTPUT"
feedback?: {
short: string // "Not quite! That's the prompt."
detailed: string // Full explanation
socraticHint?: string // "Where does the program display its result?"
}
}TypeScript Support
All types are inferred from Zod schemas:
import type {
Question,
Course,
AssessmentSubmission,
GradedAssessment
} from '@telebort/question-banks'License
MIT
Related Documentation
- ARCHITECTURE.md - Technical deep-dive (CAT, IRT, CDN)
- KNOWLEDGE-GRAPH.md - Topic-based query guide
- ../ECOSYSTEM-OVERVIEW.md - High-level ecosystem overview
Support
- Issues: GitHub Issues
