npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@telebort/question-banks

v2.3.0

Published

Question Banks SDK with three-tier access: Free (schemas), Standard (validation), Premium (full access + grading)

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.json

Scenario 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.malaysiaMath for 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, grid

6 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 analysis

CLI 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/ --verbose

stats - 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/ --verbose

Output 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


Support