@telebort/question-banks 1.0.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/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2024 Telebort Engineering
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,415 @@
1
+ # @telebort/exit-tickets
2
+
3
+ Exit Tickets SDK for Telebort educational assessments. Provides Zod schemas, validation clients, and full question access through a three-tier architecture.
4
+
5
+ ## Installation
6
+
7
+ ```bash
8
+ npm install @telebort/exit-tickets zod
9
+ ```
10
+
11
+ ## Three-Tier Architecture
12
+
13
+ | Tier | Access | Use Case |
14
+ |------|--------|----------|
15
+ | **Free** | Zod schemas | Offline validation, type safety |
16
+ | **Standard** | Validation API | SaaS validation without answer exposure |
17
+ | **Premium** | Full access + grading | LMS integration, misconception analysis |
18
+
19
+ ---
20
+
21
+ ## Free Tier - Schemas
22
+
23
+ Import Zod schemas for offline validation. No API calls required.
24
+
25
+ ```typescript
26
+ import { QuestionSchema, AssessmentSubmissionSchema } from '@telebort/exit-tickets/schemas'
27
+ import { z } from 'zod'
28
+
29
+ // Validate a question
30
+ const result = QuestionSchema.safeParse(myQuestion)
31
+ if (!result.success) {
32
+ console.error(result.error.issues)
33
+ }
34
+
35
+ // Type inference
36
+ type Question = z.infer<typeof QuestionSchema>
37
+ type Assessment = z.infer<typeof AssessmentSubmissionSchema>
38
+ ```
39
+
40
+ ### Available Schemas
41
+
42
+ ```typescript
43
+ // Question schemas
44
+ QuestionSchema // Full question with v1.1 enhancements
45
+ OptionSchema // Answer option with misconception tracking
46
+ FeedbackSchema // Structured feedback (short/detailed/socraticHint)
47
+
48
+ // Course schemas
49
+ CourseSchema // Course with lessons and questions
50
+ LessonSchema // Lesson with questions
51
+
52
+ // Assessment schemas
53
+ AssessmentSubmissionSchema // User assessment submission
54
+ GradedAssessmentSchema // Graded result with misconception analysis
55
+ ValidationResultSchema // Schema validation result (no answers)
56
+ ```
57
+
58
+ ---
59
+
60
+ ## Standard Tier - Validation API
61
+
62
+ Validate assessments without exposing correct answers. Requires API key.
63
+
64
+ ```typescript
65
+ import { ValidationClient } from '@telebort/exit-tickets/validation'
66
+
67
+ const client = new ValidationClient({
68
+ apiKey: 'sk_test_...',
69
+ baseUrl: 'https://api.telebort.com/exit-tickets/v1' // optional
70
+ })
71
+
72
+ // Validate an assessment
73
+ const result = await client.validateAssessment({
74
+ courseId: 'ai-1',
75
+ lessonId: 'ai-1-lesson-1',
76
+ responses: [
77
+ { questionId: 'ai-1-l1-q1', selectedAnswer: 'B' },
78
+ { questionId: 'ai-1-l1-q2', selectedAnswer: 'A' }
79
+ ],
80
+ submittedAt: new Date().toISOString()
81
+ })
82
+
83
+ console.log(result)
84
+ // { valid: true, isComplete: true, questionCount: 2, answeredCount: 2 }
85
+
86
+ // Offline validation (no API call)
87
+ const offlineResult = client.validateOffline(assessment)
88
+ ```
89
+
90
+ ### Rate Limits
91
+
92
+ | Tier | Requests/minute |
93
+ |------|-----------------|
94
+ | Standard | 100 |
95
+
96
+ ---
97
+
98
+ ## Premium Tier - Full Access
99
+
100
+ Full question access, grading, and misconception analysis. Requires JWT.
101
+
102
+ ```typescript
103
+ import { PremiumClient } from '@telebort/exit-tickets/premium'
104
+
105
+ const client = new PremiumClient({
106
+ token: 'eyJhbGciOiJIUzI1NiIs...',
107
+ baseUrl: 'https://api.telebort.com/exit-tickets/v1'
108
+ })
109
+
110
+ // Get questions with full content
111
+ const { questions } = await client.getQuestions({
112
+ courseId: 'ai-1',
113
+ lessonNumber: 1
114
+ })
115
+
116
+ // Get all courses
117
+ const courses = await client.getCourses()
118
+
119
+ // Grade an assessment
120
+ const result = await client.gradeAssessment({
121
+ courseId: 'ai-1',
122
+ responses: [
123
+ { questionId: 'ai-1-l1-q1', selectedAnswer: 'B' },
124
+ { questionId: 'ai-1-l1-q2', selectedAnswer: 'A' }
125
+ ],
126
+ submittedAt: new Date().toISOString()
127
+ })
128
+
129
+ console.log(result)
130
+ // {
131
+ // score: 50,
132
+ // passed: false,
133
+ // correctCount: 1,
134
+ // incorrectCount: 1,
135
+ // misconceptions: [{ misconceptionId: 'INPUT_PROMPT_VS_OUTPUT', count: 1 }],
136
+ // responses: [...]
137
+ // }
138
+
139
+ // Get statistics
140
+ const stats = await client.getStatistics()
141
+ ```
142
+
143
+ ### Rate Limits
144
+
145
+ | Tier | Requests/minute |
146
+ |------|-----------------|
147
+ | Premium | 1000 |
148
+
149
+ ---
150
+
151
+ ## CDN Mode (Recommended for Dynamic Updates)
152
+
153
+ Fetch questions from CDN for automatic updates without redeploying your app:
154
+
155
+ ```typescript
156
+ import { createExitTicketsSDK } from '@telebort/exit-tickets'
157
+
158
+ const CDN_BASE = 'https://content-warehouse.vercel.app/exit-tickets'
159
+
160
+ const sdk = createExitTicketsSDK({
161
+ dataSource: {
162
+ async loadCourses() {
163
+ const res = await fetch(`${CDN_BASE}/v1.0/full/all.json`)
164
+ const data = await res.json()
165
+ return data.courses
166
+ }
167
+ }
168
+ })
169
+
170
+ // All SDK features work:
171
+ const courses = await sdk.data.getCourses()
172
+ const quiz = await sdk.quiz.generateQuiz({ questionCount: 5 })
173
+ const result = await sdk.validate.checkAnswer('ai-1-l1-q1', 'B', 'formative')
174
+ ```
175
+
176
+ **CDN Endpoints:** (Base: `https://content-warehouse.vercel.app`)
177
+ - `GET /exit-tickets/v1.0/index.json` - Course catalog (6KB)
178
+ - `GET /exit-tickets/v1.0/courses/AI1.json` - Single course (~400KB)
179
+ - `GET /exit-tickets/v1.0/full/all.json` - All 17 courses (3.5MB)
180
+
181
+ ---
182
+
183
+ ## Static Mode (Bundled JSON)
184
+
185
+ For offline-first apps, bundle the JSON with your app:
186
+
187
+ ```typescript
188
+ import { createExitTicketsSDK } from '@telebort/exit-tickets'
189
+
190
+ // Option 1: Fetch from local static exports
191
+ const sdk = createExitTicketsSDK({
192
+ dataSource: {
193
+ async loadCourses() {
194
+ const res = await fetch('/exports/v1.0/full/all.json')
195
+ const data = await res.json()
196
+ return data.courses
197
+ }
198
+ }
199
+ })
200
+
201
+ // Option 2: Import bundled JSON (with bundler support)
202
+ import coursesData from '../exit-tickets-api/exports/v1.0/full/all.json'
203
+
204
+ const sdk = createExitTicketsSDK({
205
+ dataSource: {
206
+ async loadCourses() {
207
+ return coursesData.courses
208
+ }
209
+ }
210
+ })
211
+
212
+ // All SDK features work locally:
213
+ const courses = await sdk.data.getCourses() // ✅ Works
214
+ const quiz = await sdk.quiz.generateQuiz({ questionCount: 5 }) // ✅ Works
215
+ const result = await sdk.validate.checkAnswer(...) // ✅ Works
216
+ ```
217
+
218
+ > **Note:** `ValidationClient` and `PremiumClient` require an API endpoint. For static deployments, use the SDK Factory instead—it provides all the same features client-side.
219
+
220
+ ---
221
+
222
+ ## SDK Factory - Custom Data Source
223
+
224
+ For self-hosted deployments or custom data sources:
225
+
226
+ ```typescript
227
+ import { createExitTicketsSDK } from '@telebort/exit-tickets'
228
+ import coursesData from './data/courses.json'
229
+
230
+ const sdk = createExitTicketsSDK({
231
+ dataSource: {
232
+ async loadCourses() {
233
+ return coursesData // Or fetch from your own API
234
+ }
235
+ }
236
+ })
237
+
238
+ // Now use SDK methods
239
+ const courses = await sdk.data.getCourses()
240
+ const questions = await sdk.query.filterQuestions({ courseId: 'ai-1' })
241
+ const quiz = await sdk.quiz.generateQuiz({ questionCount: 10 })
242
+ const result = await sdk.validate.checkAnswer('ai-1-l1-q1', 'B', 'formative')
243
+ ```
244
+
245
+ ### SDK Interface
246
+
247
+ ```typescript
248
+ interface ExitTicketsSDK {
249
+ data: {
250
+ getCourses(): Promise<Course[]>
251
+ getCourse(courseId: string): Promise<Course | null>
252
+ getLesson(courseId: string, lessonNumber: number): Promise<Lesson | null>
253
+ getQuestion(questionId: string): Promise<Question | null>
254
+ getAllQuestions(): Promise<Question[]>
255
+ }
256
+
257
+ query: {
258
+ filterQuestions(filters: QuestionFilters): Promise<QueryResult<Question>>
259
+ getRandomQuestions(count: number, filters?: QuestionFilters): Promise<Question[]>
260
+ }
261
+
262
+ quiz: {
263
+ generateQuiz(criteria: QuizCriteria): Promise<{ questions: Question[]; metadata: object }>
264
+ getLessonQuiz(courseId: string, lessonNumber: number): Promise<Question[]>
265
+ }
266
+
267
+ search: {
268
+ search(options: SearchOptions): Promise<QueryResult<Question>>
269
+ searchByTags(tags: string[], matchAll?: boolean): Promise<Question[]>
270
+ }
271
+
272
+ analytics: {
273
+ getStatistics(): Promise<Statistics>
274
+ getCourseStatistics(courseId: string): Promise<Statistics>
275
+ }
276
+
277
+ validate: {
278
+ checkAnswer(questionId: string, answer: string, mode: 'formative' | 'summative'): Promise<ValidationResult>
279
+ }
280
+ }
281
+ ```
282
+
283
+ ---
284
+
285
+ ## CLI Tools
286
+
287
+ The SDK includes command-line tools for working with exit ticket data:
288
+
289
+ ```bash
290
+ # Install globally
291
+ npm install -g @telebort/exit-tickets
292
+
293
+ # Or use via npx
294
+ npx @telebort/exit-tickets <command>
295
+ ```
296
+
297
+ ### Commands
298
+
299
+ #### `validate` - Validate Course JSON Files
300
+
301
+ ```bash
302
+ # Validate a single file
303
+ exit-tickets validate ./data/courses/ai-1.json
304
+
305
+ # Validate all files in a directory
306
+ exit-tickets validate ./data/courses/
307
+
308
+ # Show all validation errors (not just first 5)
309
+ exit-tickets validate ./data/courses/ --verbose
310
+ ```
311
+
312
+ #### `stats` - Show Statistics
313
+
314
+ ```bash
315
+ # Show aggregate statistics across all courses
316
+ exit-tickets stats --data-dir ./data/courses/
317
+
318
+ # Show statistics for a specific course
319
+ exit-tickets stats --course ai-1 --data-dir ./data/courses/
320
+
321
+ # Output as JSON
322
+ exit-tickets stats --json --data-dir ./data/courses/
323
+ ```
324
+
325
+ #### `quiz` - Generate Sample Quizzes
326
+
327
+ ```bash
328
+ # Generate 5 random questions
329
+ exit-tickets quiz --data-dir ./data/courses/
330
+
331
+ # Generate 10 questions from a specific course
332
+ exit-tickets quiz --course ai-1 --count 10 --data-dir ./data/courses/
333
+
334
+ # Filter by difficulty and show answers
335
+ exit-tickets quiz --difficulty hard --show-answers --data-dir ./data/courses/
336
+
337
+ # Output as JSON (for integration)
338
+ exit-tickets quiz --count 20 --json --data-dir ./data/courses/
339
+ ```
340
+
341
+ ---
342
+
343
+ ## Question Schema (v1.1)
344
+
345
+ > ⚠️ **Preview Feature**: v1.1 misconception tracking is currently available for ~5 questions (AI-1 only). Full course migration to v1.1 is planned. Questions without v1.1 data will have `misconceptionTargets: undefined` and options without feedback.
346
+
347
+ Questions include v1.1 enhancements for misconception tracking:
348
+
349
+ ```typescript
350
+ interface Question {
351
+ questionId: string // "ai-1-l1-q1"
352
+ globalId: string // "exit-ticket-0351"
353
+ questionType: QuestionType // vocabulary, code_understanding, etc.
354
+ questionArchetype?: string // vocabulary, trace, bebras, blockmodel
355
+
356
+ prompt: string
357
+ hasCodeBlock: boolean
358
+ codeLanguage: string | null
359
+ codeContent: string | null
360
+
361
+ // v1.1: Misconception targeting
362
+ misconceptionTargets?: string[]
363
+
364
+ options: Option[] // 4 options with misconception feedback
365
+ correctAnswer: 'A' | 'B' | 'C' | 'D'
366
+
367
+ metadata: {
368
+ difficulty: 'easy' | 'medium' | 'hard' | 'challenge'
369
+ bloomsTaxonomy: 'remember' | 'understand' | 'apply' | ...
370
+ tags: string[]
371
+ }
372
+ }
373
+
374
+ interface Option {
375
+ key: 'A' | 'B' | 'C' | 'D'
376
+ text: string
377
+ isCorrect: boolean
378
+
379
+ // v1.1: Misconception feedback
380
+ misconceptionId?: string // "INPUT_PROMPT_VS_OUTPUT"
381
+ feedback?: {
382
+ short: string // "Not quite! That's the prompt."
383
+ detailed: string // Full explanation
384
+ socraticHint?: string // "Where does the program display its result?"
385
+ }
386
+ }
387
+ ```
388
+
389
+ ---
390
+
391
+ ## TypeScript Support
392
+
393
+ All types are inferred from Zod schemas:
394
+
395
+ ```typescript
396
+ import type {
397
+ Question,
398
+ Course,
399
+ AssessmentSubmission,
400
+ GradedAssessment
401
+ } from '@telebort/exit-tickets'
402
+ ```
403
+
404
+ ---
405
+
406
+ ## License
407
+
408
+ MIT
409
+
410
+ ---
411
+
412
+ ## Support
413
+
414
+ - Issues: [GitHub Issues](https://github.com/telebort/exit-tickets-sdk/issues)
415
+ - Documentation: [API Docs](https://docs.telebort.com/exit-tickets)
@@ -0,0 +1,16 @@
1
+ #!/usr/bin/env node
2
+
3
+ /**
4
+ * Exit Tickets CLI - Binary Shim
5
+ *
6
+ * This file is the entry point for the `exit-tickets` command.
7
+ * It loads and executes the compiled CLI module.
8
+ */
9
+
10
+ // Use dynamic import for ESM compatibility
11
+ import('../dist/cli/index.js')
12
+ .then(({ run }) => run())
13
+ .catch((error) => {
14
+ console.error('Failed to start CLI:', error.message)
15
+ process.exit(2)
16
+ })