@timeback/oneroster 0.1.6 → 0.1.7

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.
@@ -0,0 +1,1885 @@
1
+ /**
2
+ * OneRoster Primitives
3
+ *
4
+ * Enums and literal types specific to the OneRoster protocol.
5
+ * For shared Timeback primitives (TimebackGrade, TimebackSubject), see `@timeback/types`.
6
+ */
7
+
8
+ /**
9
+ * OneRoster assessment result score status values.
10
+ * @see https://www.imsglobal.org/oneroster-v11-final-specification
11
+ */
12
+ type ScoreStatus =
13
+ | 'exempt'
14
+ | 'fully graded'
15
+ | 'not submitted'
16
+ | 'partially graded'
17
+ | 'submitted'
18
+
19
+ /**
20
+ * OneRoster organization types.
21
+ * @see https://www.imsglobal.org/oneroster-v11-final-specification
22
+ */
23
+ type OrganizationType = 'department' | 'school' | 'district' | 'local' | 'state' | 'national'
24
+
25
+ /**
26
+ * OneRoster user role types.
27
+ * @see https://www.imsglobal.org/oneroster-v11-final-specification
28
+ */
29
+ type OneRosterUserRole =
30
+ | 'administrator'
31
+ | 'aide'
32
+ | 'guardian'
33
+ | 'parent'
34
+ | 'proctor'
35
+ | 'relative'
36
+ | 'student'
37
+ | 'teacher'
38
+
39
+ /**
40
+ * Timeback Shared Primitives
41
+ *
42
+ * Core types used across multiple Timeback protocols.
43
+ *
44
+ * Organization:
45
+ * - Shared types (this file): Used by multiple protocols (Caliper, OneRoster, etc.)
46
+ * - Protocol-specific types: Live in their respective protocols/X/primitives.ts files
47
+ *
48
+ * What belongs here:
49
+ * - TimebackSubject - Used in OneRoster courses AND Caliper events
50
+ * - TimebackGrade - Used across OneRoster, Caliper, and QTI
51
+ * - IMSErrorResponse - IMS Global standard used by multiple 1EdTech protocols
52
+ *
53
+ * What doesn't belong here:
54
+ * - OneRoster-specific: protocols/oneroster/primitives.ts
55
+ * - QTI-specific: protocols/qti/primitives.ts
56
+ */
57
+
58
+ // ─────────────────────────────────────────────────────────────────────────────
59
+ // TIMEBACK SHARED TYPES
60
+ // ─────────────────────────────────────────────────────────────────────────────
61
+
62
+ /**
63
+ * Valid Timeback subject values.
64
+ * Used in OneRoster courses and Caliper events.
65
+ */
66
+ type TimebackSubject =
67
+ | 'Reading'
68
+ | 'Language'
69
+ | 'Vocabulary'
70
+ | 'Social Studies'
71
+ | 'Writing'
72
+ | 'Science'
73
+ | 'FastMath'
74
+ | 'Math'
75
+ | 'None'
76
+ | 'Other'
77
+
78
+ /**
79
+ * Grade levels per Timeback OneRoster GradeEnum (numeric).
80
+ * -1 = Pre-K, 0 = Kindergarten, 1-12 = Grades 1-12, 13 = AP
81
+ *
82
+ * Use for input types where numbers are accepted.
83
+ */
84
+ type TimebackGrade = -1 | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13
85
+
86
+ // ─────────────────────────────────────────────────────────────────────────────
87
+ // IMS GLOBAL COMMON TYPES
88
+ // ─────────────────────────────────────────────────────────────────────────────
89
+
90
+ /**
91
+ * IMS Global error response format.
92
+ * Used across OneRoster, Caliper, and other 1EdTech protocols.
93
+ */
94
+ interface IMSErrorResponse {
95
+ imsx_codeMajor: 'failure' | 'success'
96
+ imsx_severity: 'error' | 'warning' | 'status'
97
+ imsx_description: string
98
+ imsx_CodeMinor?: {
99
+ imsx_codeMinorField: Array<{
100
+ imsx_codeMinorFieldName: string
101
+ imsx_codeMinorFieldValue: string
102
+ }>
103
+ }
104
+ imsx_error_details?: Array<Record<string, string>>
105
+ }
106
+
107
+ /**
108
+ * QTI Primitives
109
+ *
110
+ * Enums and literal types specific to the QTI protocol.
111
+ * For shared Timeback primitives (TimebackGrade, TimebackSubject), see `@timeback/types`.
112
+ */
113
+
114
+ /**
115
+ * Lesson types for PowerPath integration.
116
+ * Used to categorize assessment content by delivery mode.
117
+ */
118
+ type LessonType =
119
+ | 'powerpath-100'
120
+ | 'quiz'
121
+ | 'test-out'
122
+ | 'placement'
123
+ | 'unit-test'
124
+ | 'alpha-read-article'
125
+ | null
126
+
127
+ /**
128
+ * OneRoster Base Types
129
+ *
130
+ * Common types used across all OneRoster entities.
131
+ *
132
+ * - OneRoster-specific primitives: `./primitives.ts`
133
+ * - Shared Timeback primitives: `@timeback/types`
134
+ */
135
+
136
+
137
+
138
+ /**
139
+ * Base interface for all OneRoster entities.
140
+ *
141
+ * All OneRoster resources share these common fields for identification,
142
+ * status tracking, and extensibility.
143
+ */
144
+ interface Base {
145
+ /**
146
+ * Globally unique identifier for the entity.
147
+ * Typically a UUID assigned by the source system.
148
+ */
149
+ sourcedId?: string
150
+
151
+ /**
152
+ * The status of the entity.
153
+ * - `active`: Entity is current and valid
154
+ * - `tobedeleted`: Entity is marked for deletion
155
+ */
156
+ status?: 'active' | 'tobedeleted'
157
+
158
+ /**
159
+ * ISO 8601 timestamp of the last modification.
160
+ * @example
161
+ * // "2024-01-15T10:30:00Z"
162
+ */
163
+ dateLastModified?: string
164
+
165
+ /**
166
+ * Extensible metadata object for custom properties.
167
+ * Used for vendor-specific extensions.
168
+ */
169
+ metadata?: Record<string, unknown> | null
170
+ }
171
+
172
+ /**
173
+ * A score for a specific learning objective.
174
+ */
175
+ interface LearningObjectiveResult {
176
+ /** Identifier of the learning objective */
177
+ learningObjectiveId: string
178
+ /** Numeric score */
179
+ score?: number
180
+ /** Text-based score (e.g., "Proficient") */
181
+ textScore?: string
182
+ }
183
+
184
+ /**
185
+ * A set of learning objectives with optional results.
186
+ */
187
+ interface LearningObjectiveSetItem {
188
+ /** Source system for these learning objectives */
189
+ source: string
190
+ /** Learning objective IDs (for line items) */
191
+ learningObjectiveIds?: string[]
192
+ /** Learning objective results (for results) */
193
+ learningObjectiveResults?: LearningObjectiveResult[]
194
+ }
195
+
196
+ /**
197
+ * Array of learning objective sets, or null if not applicable.
198
+ */
199
+ type LearningObjectiveSet = LearningObjectiveSetItem[] | null
200
+
201
+ /**
202
+ * A reference to another OneRoster entity by sourcedId.
203
+ */
204
+ interface Ref {
205
+ /** The sourcedId of the referenced entity */
206
+ sourcedId: string
207
+ }
208
+
209
+ /**
210
+ * A reference with an optional type discriminator.
211
+ */
212
+ interface RefWithType extends Ref {
213
+ /** The type of the referenced entity (e.g., "user", "class") */
214
+ type?: string
215
+ }
216
+
217
+ /**
218
+ * A fully-qualified reference with href and type.
219
+ * Commonly returned in API responses for navigable links.
220
+ */
221
+ interface RefWithHref extends Ref {
222
+ /** The URL to fetch the referenced entity */
223
+ href: string
224
+ /** The type of the referenced entity */
225
+ type: string
226
+ }
227
+
228
+ /**
229
+ * Response returned when creating a new entity.
230
+ * Contains the mapping between supplied and allocated IDs.
231
+ */
232
+ interface CreateResponse {
233
+ sourcedIdPairs: {
234
+ /** The sourcedId provided in the create request */
235
+ suppliedSourcedId: string
236
+ /** The sourcedId allocated by the server (may differ) */
237
+ allocatedSourcedId: string
238
+ }
239
+ }
240
+
241
+ /**
242
+ * Filter Field Types
243
+ *
244
+ * These types define the server-side filterable fields for each OneRoster entity.
245
+ * They may differ from the entity structure (e.g., `role` vs `roles`).
246
+ */
247
+
248
+
249
+
250
+ // ═══════════════════════════════════════════════════════════════════════════════
251
+ // COMMON FILTER FIELDS
252
+ // ═══════════════════════════════════════════════════════════════════════════════
253
+
254
+ /**
255
+ * Base fields available for filtering on all entities.
256
+ */
257
+ interface BaseFilterFields {
258
+ sourcedId: string
259
+ status: 'active' | 'tobedeleted'
260
+ dateLastModified: Date
261
+ }
262
+
263
+ // ═══════════════════════════════════════════════════════════════════════════════
264
+ // USER FILTER FIELDS
265
+ // ═══════════════════════════════════════════════════════════════════════════════
266
+
267
+ /**
268
+ * Filterable fields for User entities.
269
+ *
270
+ * Note: The server accepts `role` (singular) even though the entity has `roles` (array).
271
+ */
272
+ interface UserFilterFields extends BaseFilterFields {
273
+ givenName: string
274
+ familyName: string
275
+ email: string
276
+ username: string
277
+ enabledUser: string
278
+ identifier: string
279
+ userMasterIdentifier: string
280
+ /** Server accepts singular `role` for filtering, even though entity has `roles` array */
281
+ role: OneRosterUserRole
282
+ }
283
+
284
+ // ═══════════════════════════════════════════════════════════════════════════════
285
+ // ORGANIZATION FILTER FIELDS
286
+ // ═══════════════════════════════════════════════════════════════════════════════
287
+
288
+ /**
289
+ * Filterable fields for Organization/School entities.
290
+ */
291
+ interface OrganizationFilterFields extends BaseFilterFields {
292
+ name: string
293
+ identifier: string
294
+ type: OrganizationType
295
+ }
296
+
297
+ // ═══════════════════════════════════════════════════════════════════════════════
298
+ // CLASS FILTER FIELDS
299
+ // ═══════════════════════════════════════════════════════════════════════════════
300
+
301
+ /**
302
+ * Filterable fields for Class entities.
303
+ */
304
+ interface ClassFilterFields extends BaseFilterFields {
305
+ title: string
306
+ classCode: string
307
+ classType: 'homeroom' | 'scheduled'
308
+ location: string
309
+ grades: string
310
+ }
311
+
312
+ // ═══════════════════════════════════════════════════════════════════════════════
313
+ // COURSE FILTER FIELDS
314
+ // ═══════════════════════════════════════════════════════════════════════════════
315
+
316
+ /**
317
+ * Filterable fields for Course entities.
318
+ */
319
+ interface CourseFilterFields extends BaseFilterFields {
320
+ title: string
321
+ courseCode: string
322
+ grades: string
323
+ subjects: string
324
+ }
325
+
326
+ // ═══════════════════════════════════════════════════════════════════════════════
327
+ // ENROLLMENT FILTER FIELDS
328
+ // ═══════════════════════════════════════════════════════════════════════════════
329
+
330
+ /**
331
+ * Filterable fields for Enrollment entities.
332
+ */
333
+ interface EnrollmentFilterFields extends BaseFilterFields {
334
+ role: OneRosterUserRole
335
+ primary: string
336
+ beginDate: Date
337
+ endDate: Date
338
+ 'user.sourcedId': string
339
+ 'class.sourcedId': string
340
+ }
341
+
342
+ // ═══════════════════════════════════════════════════════════════════════════════
343
+ // ACADEMIC SESSION FILTER FIELDS
344
+ // ═══════════════════════════════════════════════════════════════════════════════
345
+
346
+ /**
347
+ * Filterable fields for AcademicSession entities.
348
+ */
349
+ interface AcademicSessionFilterFields extends BaseFilterFields {
350
+ title: string
351
+ type: 'gradingPeriod' | 'semester' | 'schoolYear' | 'term'
352
+ startDate: Date
353
+ endDate: Date
354
+ schoolYear: string
355
+ }
356
+
357
+ // ═══════════════════════════════════════════════════════════════════════════════
358
+ // LINE ITEM FILTER FIELDS
359
+ // ═══════════════════════════════════════════════════════════════════════════════
360
+
361
+ /**
362
+ * Filterable fields for LineItem (gradebook) entities.
363
+ */
364
+ interface LineItemFilterFields extends BaseFilterFields {
365
+ title: string
366
+ description: string
367
+ assignDate: Date
368
+ dueDate: Date
369
+ }
370
+
371
+ // ═══════════════════════════════════════════════════════════════════════════════
372
+ // RESULT FILTER FIELDS
373
+ // ═══════════════════════════════════════════════════════════════════════════════
374
+
375
+ /**
376
+ * Filterable fields for Result (grade) entities.
377
+ */
378
+ interface ResultFilterFields extends BaseFilterFields {
379
+ score: number
380
+ scoreDate: Date
381
+ scoreStatus: 'exempt' | 'fully graded' | 'not submitted' | 'partially graded' | 'submitted'
382
+ }
383
+
384
+ // ═══════════════════════════════════════════════════════════════════════════════
385
+ // COURSE COMPONENT FILTER FIELDS
386
+ // ═══════════════════════════════════════════════════════════════════════════════
387
+
388
+ /**
389
+ * Filterable fields for CourseComponent entities.
390
+ */
391
+ interface CourseComponentFilterFields extends BaseFilterFields {
392
+ title: string
393
+ resourceType: string
394
+ 'course.sourcedId': string
395
+ }
396
+
397
+ // ═══════════════════════════════════════════════════════════════════════════════
398
+ // COMPONENT RESOURCE FILTER FIELDS
399
+ // ═══════════════════════════════════════════════════════════════════════════════
400
+
401
+ /**
402
+ * Filterable fields for ComponentResource entities.
403
+ */
404
+ interface ComponentResourceFilterFields extends BaseFilterFields {
405
+ title: string
406
+ lessonType: string
407
+ 'courseComponent.sourcedId': string
408
+ }
409
+
410
+ // ═══════════════════════════════════════════════════════════════════════════════
411
+ // ASSESSMENT FILTER FIELDS
412
+ // ═══════════════════════════════════════════════════════════════════════════════
413
+
414
+ /**
415
+ * Filterable fields for AssessmentLineItem entities.
416
+ */
417
+ interface AssessmentLineItemFilterFields extends BaseFilterFields {
418
+ title: string
419
+ description: string
420
+ assignDate: Date
421
+ dueDate: Date
422
+ }
423
+
424
+ /**
425
+ * Filterable fields for AssessmentResult entities.
426
+ *
427
+ * Includes nested filter keys for efficient querying by line item and student.
428
+ */
429
+ interface AssessmentResultFilterFields extends BaseFilterFields {
430
+ score: number
431
+ scoreDate: Date
432
+ scoreStatus: string
433
+ 'assessmentLineItem.sourcedId': string
434
+ 'student.sourcedId': string
435
+ }
436
+
437
+ // ═══════════════════════════════════════════════════════════════════════════════
438
+ // DEMOGRAPHICS FILTER FIELDS
439
+ // ═══════════════════════════════════════════════════════════════════════════════
440
+
441
+ /**
442
+ * Filterable fields for Demographics entities.
443
+ */
444
+ interface DemographicsFilterFields extends BaseFilterFields {
445
+ birthDate: string
446
+ sex: 'male' | 'female'
447
+ }
448
+
449
+ // ═══════════════════════════════════════════════════════════════════════════════
450
+ // CATEGORY FILTER FIELDS
451
+ // ═══════════════════════════════════════════════════════════════════════════════
452
+
453
+ /**
454
+ * Filterable fields for Category entities.
455
+ */
456
+ interface CategoryFilterFields extends BaseFilterFields {
457
+ title: string
458
+ }
459
+
460
+ // ═══════════════════════════════════════════════════════════════════════════════
461
+ // SCORE SCALE FILTER FIELDS
462
+ // ═══════════════════════════════════════════════════════════════════════════════
463
+
464
+ /**
465
+ * Filterable fields for ScoreScale entities.
466
+ */
467
+ interface ScoreScaleFilterFields extends BaseFilterFields {
468
+ title: string
469
+ }
470
+
471
+ // ═══════════════════════════════════════════════════════════════════════════════
472
+ // RESOURCE FILTER FIELDS
473
+ // ═══════════════════════════════════════════════════════════════════════════════
474
+
475
+ /**
476
+ * Filterable fields for Resource entities.
477
+ */
478
+ interface ResourceFilterFields extends BaseFilterFields {
479
+ title: string
480
+ vendorResourceId: string
481
+ importance: 'primary' | 'secondary'
482
+ }
483
+
484
+ // ═══════════════════════════════════════════════════════════════════════════════
485
+ // RESOURCE FILTER FIELDS
486
+ // ═══════════════════════════════════════════════════════════════════════════════
487
+
488
+ /**
489
+ * Filterable fields for Resource entities.
490
+ */
491
+ interface ResourceFilterFields extends BaseFilterFields {
492
+ title: string
493
+ vendorResourceId: string
494
+ vendorId: string
495
+ applicationId: string
496
+ }
497
+
498
+ /**
499
+ * OneRoster Gradebook Types
500
+ *
501
+ * Types for gradebook entities: results, line items, categories, score scales, assessments.
502
+ */
503
+
504
+
505
+
506
+ /**
507
+ * A value within a score scale (e.g., "A" = 90-100).
508
+ */
509
+ interface ScoreScaleValue {
510
+ /** Left-hand side of the range (e.g., "90") */
511
+ itemValueLHS: string
512
+ /** Right-hand side of the range (e.g., "100") */
513
+ itemValueRHS: string
514
+ /** Display value (e.g., "A") */
515
+ value?: string
516
+ /** Description of this score level */
517
+ description?: string
518
+ }
519
+
520
+ /**
521
+ * A grading scale defining how scores are interpreted.
522
+ *
523
+ * Score scales can be associated with classes or courses and define
524
+ * the mapping between numeric scores and letter grades.
525
+ */
526
+ interface ScoreScale extends Base {
527
+ /** Scale title (e.g., "Standard Grading Scale") */
528
+ title: string
529
+ /** Type of scale */
530
+ type?: string
531
+ /** Class this scale applies to */
532
+ class?: Ref
533
+ /** Course this scale applies to */
534
+ course?: Ref | null
535
+ /** Values defining the scale */
536
+ scoreScaleValue?: ScoreScaleValue[]
537
+ /** Minimum possible score */
538
+ minScore?: number
539
+ /** Maximum possible score */
540
+ maxScore?: number
541
+ }
542
+
543
+ /**
544
+ * A category for organizing line items (e.g., "Homework", "Tests", "Projects").
545
+ */
546
+ interface Category extends Base {
547
+ /** Category name */
548
+ title: string
549
+ /** Weight for grade calculation (0.0 to 1.0) */
550
+ weight?: number | null
551
+ }
552
+
553
+ /**
554
+ * A line item (assignment, test, or other gradable item).
555
+ *
556
+ * Line items represent work that students complete and receive grades for.
557
+ */
558
+ interface LineItem extends Base {
559
+ /** Title of the assignment */
560
+ title: string
561
+ /** Description of the assignment */
562
+ description?: string | null
563
+ /** Date the assignment was given (ISO 8601 datetime) */
564
+ assignDate: string
565
+ /** Due date for the assignment (ISO 8601 datetime) */
566
+ dueDate: string
567
+ /** Class this line item belongs to */
568
+ class: Ref
569
+ /** School */
570
+ school: Ref
571
+ /** Category for this line item */
572
+ category: Ref
573
+ /** Grading period */
574
+ gradingPeriod?: Ref | null
575
+ /** Academic session */
576
+ academicSession?: Ref | null
577
+ /** Score scale to use for grading */
578
+ scoreScale?: Ref | null
579
+ /** Minimum possible score */
580
+ resultValueMin?: number | null
581
+ /** Maximum possible score */
582
+ resultValueMax?: number | null
583
+ /** Associated learning objectives */
584
+ learningObjectiveSet?: LearningObjectiveSet
585
+ }
586
+
587
+ /**
588
+ * A result (grade) for a student on a line item.
589
+ *
590
+ * Results record the score a student received on an assignment.
591
+ */
592
+ interface Result extends Base {
593
+ /** Line item this result is for */
594
+ lineItem: Ref
595
+ /** Student who received this grade */
596
+ student: Ref
597
+ /** Class (optional, for context) */
598
+ class?: Ref | null
599
+ /** Score scale used */
600
+ scoreScale?: Ref | null
601
+ /** Status of the score */
602
+ scoreStatus: ScoreStatus
603
+ /** Numeric score */
604
+ score?: number | null
605
+ /** Text-based score */
606
+ textScore?: string | null
607
+ /** Date the score was recorded */
608
+ scoreDate: string
609
+ /** Teacher comment */
610
+ comment?: string | null
611
+ /** Learning objective scores */
612
+ learningObjectiveSet?: LearningObjectiveSet
613
+ /** Whether work is in progress */
614
+ inProgress?: string
615
+ /** Whether work is incomplete */
616
+ incomplete?: string
617
+ /** Whether submission was late */
618
+ late?: string
619
+ /** Whether submission is missing */
620
+ missing?: string
621
+ }
622
+
623
+ /**
624
+ * An assessment line item for standardized or formal assessments.
625
+ *
626
+ * Assessment line items are similar to line items but designed for
627
+ * formal assessments with more detailed tracking capabilities.
628
+ */
629
+ interface AssessmentLineItem extends Base {
630
+ /** Assessment title */
631
+ title: string
632
+ /** Assessment description */
633
+ description?: string | null
634
+ /** Class this assessment is for */
635
+ class?: Ref | null
636
+ /** Parent assessment (for hierarchical assessments) */
637
+ parentAssessmentLineItem?: Ref | null
638
+ /** Score scale */
639
+ scoreScale?: Ref | null
640
+ /** Minimum possible score */
641
+ resultValueMin?: number | null
642
+ /** Maximum possible score */
643
+ resultValueMax?: number | null
644
+ /** Course component reference (proprietary extension) */
645
+ component?: Ref | null
646
+ /** Component resource reference (proprietary extension) */
647
+ componentResource?: Ref | null
648
+ /** Learning objectives */
649
+ learningObjectiveSet?: LearningObjectiveSet
650
+ /** Course reference (proprietary extension) */
651
+ course?: Ref | null
652
+ }
653
+
654
+ /**
655
+ * A result for an assessment line item.
656
+ */
657
+ interface AssessmentResult extends Base {
658
+ /** Assessment this result is for */
659
+ assessmentLineItem: Ref
660
+ /** Student who took the assessment */
661
+ student: Ref
662
+ /** Numeric score */
663
+ score?: number | null
664
+ /** Text-based score */
665
+ textScore?: string | null
666
+ /** Date of the assessment */
667
+ scoreDate: string
668
+ /** Score scale used */
669
+ scoreScale?: Ref | null
670
+ /** Percentile ranking */
671
+ scorePercentile?: number | null
672
+ /** Status of the score */
673
+ scoreStatus: ScoreStatus
674
+ /** Teacher/grader comment */
675
+ comment?: string | null
676
+ /** Learning objective scores */
677
+ learningObjectiveSet?: LearningObjectiveSet
678
+ /** Whether assessment is in progress */
679
+ inProgress?: string | null
680
+ /** Whether assessment is incomplete */
681
+ incomplete?: string | null
682
+ /** Whether submission was late */
683
+ late?: string | null
684
+ /** Whether assessment is missing */
685
+ missing?: string | null
686
+ }
687
+
688
+ /**
689
+ * OneRoster Resources Types
690
+ *
691
+ * Types for digital learning resources and content.
692
+ */
693
+
694
+
695
+
696
+ /**
697
+ * Resource type - determines which path prefix to use.
698
+ */
699
+ type ResourceType = 'rostering' | 'gradebook' | 'resources'
700
+
701
+ /**
702
+ * Common metadata fields shared across all resource types.
703
+ */
704
+ interface BaseResourceMetadata {
705
+ /** Academic subject area (e.g., "Math", "Science", "Language") */
706
+ subject?: string
707
+ /** Array or range of grade levels (e.g., ["03", "04"]) */
708
+ grades?: string[]
709
+ /** Language of the content, using standard IETF BCP 47 codes (e.g., "en-US") */
710
+ language?: string
711
+ /** Experience points (XP) assigned for completing this resource */
712
+ xp?: number
713
+ /** Learning objectives this resource is aligned to */
714
+ learningObjectiveSet?: LearningObjectiveSet
715
+ /** Array of topic-related tags or important terms covered by the content */
716
+ keywords?: string[]
717
+ /** Direct content URL or support URL */
718
+ url?: string
719
+ /** Estimated seconds for a student to consume the content */
720
+ timeLength?: number
721
+ /** UI label for the activity badge (e.g., "Article", "Exercise", "Quiz", "Video"). */
722
+ activityType?: string
723
+ /** Extensible for custom vendor-specific fields */
724
+ [key: string]: unknown
725
+ }
726
+
727
+ /**
728
+ * Metadata for QTI (IMS Question and Test Interoperability) resources.
729
+ */
730
+ interface QtiResourceMetadata extends BaseResourceMetadata {
731
+ type: 'qti'
732
+ /** Specific QTI type: "qti-question", "qti-test", "qti-test-bank", "qti-stimulus" */
733
+ subType?: 'qti-question' | 'qti-test' | 'qti-test-bank' | 'qti-stimulus'
734
+ }
735
+
736
+ /**
737
+ * Metadata for textual resources (PDFs, eBooks, etc.).
738
+ */
739
+ interface TextualResourceMetadata extends BaseResourceMetadata {
740
+ type: 'text'
741
+ /** File or content format (e.g., "pdf", "epub", "docx", "html") */
742
+ format?: string
743
+ /** Name of the person or organization that created the content */
744
+ author?: string
745
+ /** Number of pages if applicable */
746
+ pageCount?: number
747
+ /** Number of words in the content */
748
+ wordLength?: number
749
+ }
750
+
751
+ /**
752
+ * Metadata for audio recordings.
753
+ */
754
+ interface AudioResourceMetadata extends BaseResourceMetadata {
755
+ type: 'audio'
756
+ /** Length of the audio in HH:MM:SS format */
757
+ duration?: string
758
+ /** Audio format (e.g., "mp3", "wav") */
759
+ format?: string
760
+ /** Name of the speaker or narrator */
761
+ speaker?: string
762
+ }
763
+
764
+ /**
765
+ * Metadata for video content.
766
+ */
767
+ interface VideoResourceMetadata extends BaseResourceMetadata {
768
+ type: 'video'
769
+ /** Length of the video in HH:MM:SS format */
770
+ duration?: string
771
+ /** Indicates if closed captions are available */
772
+ captionsAvailable?: boolean
773
+ /** Video format (e.g., "mp4", "webm", "mov") */
774
+ format?: string
775
+ }
776
+
777
+ /**
778
+ * Metadata for interactive 3rd party tools (Desmos, LTI apps, etc.).
779
+ */
780
+ interface InteractiveResourceMetadata extends BaseResourceMetadata {
781
+ type: 'interactive'
782
+ /** The URL used to launch the tool, often via LTI or similar protocols */
783
+ launchUrl?: string
784
+ /** Name of the external tool provider (e.g., "Desmos", "Khan Academy") */
785
+ toolProvider?: string
786
+ /** Teaching method supported (e.g., "exploratory", "direct-instruction") */
787
+ instructionalMethod?: string
788
+ }
789
+
790
+ /**
791
+ * Metadata for visual resources (images, diagrams, etc.).
792
+ */
793
+ interface VisualResourceMetadata extends BaseResourceMetadata {
794
+ type: 'visual'
795
+ /** Image format (e.g., "png", "jpeg", "svg", "pdf") */
796
+ format?: string
797
+ /** Dimensions in pixels (e.g., "1920x1080") */
798
+ resolution?: string
799
+ }
800
+
801
+ /**
802
+ * Metadata for structured course materials.
803
+ */
804
+ interface CourseMaterialResourceMetadata extends BaseResourceMetadata {
805
+ type: 'course-material'
806
+ /** Material classification: "unit", "course", "resource-collection" */
807
+ subType?: 'unit' | 'course' | 'resource-collection'
808
+ /** Name of the person or organization who created the material */
809
+ author?: string
810
+ /** File format (e.g., "docx", "pdf", "cc") */
811
+ format?: string
812
+ /** Teaching method supported (e.g., "direct-instruction", "project-based") */
813
+ instructionalMethod?: string
814
+ }
815
+
816
+ /**
817
+ * Metadata for a collection of assessments served in sequence.
818
+ */
819
+ interface AssessmentBankResourceMetadata extends BaseResourceMetadata {
820
+ type: 'assessment-bank'
821
+ /** Array of individual test Resource IDs included in this bank */
822
+ resources: string[]
823
+ }
824
+
825
+ /**
826
+ * Union of all valid resource metadata types.
827
+ * Uses the `type` field as a discriminator.
828
+ */
829
+ type ResourceMetadata =
830
+ | QtiResourceMetadata
831
+ | TextualResourceMetadata
832
+ | AudioResourceMetadata
833
+ | VideoResourceMetadata
834
+ | InteractiveResourceMetadata
835
+ | VisualResourceMetadata
836
+ | CourseMaterialResourceMetadata
837
+ | AssessmentBankResourceMetadata
838
+ | BaseResourceMetadata // Fallback for unknown types
839
+
840
+ /**
841
+ * A digital learning resource (content, activity, or material).
842
+ *
843
+ * Resources represent external content that can be assigned to
844
+ * students through courses and classes.
845
+ */
846
+ interface Resource extends Base {
847
+ /** Resource title */
848
+ title: string
849
+ /** Roles this resource is intended for */
850
+ roles?: ('primary' | 'secondary')[]
851
+ /** Importance level of this resource */
852
+ importance?: 'primary' | 'secondary'
853
+ /** Vendor's identifier for this resource */
854
+ vendorResourceId: string
855
+ /** Vendor identifier */
856
+ vendorId?: string
857
+ /** Application identifier */
858
+ applicationId?: string
859
+ /** Content-specific metadata */
860
+ metadata?: ResourceMetadata | null
861
+ }
862
+
863
+ /**
864
+ * A resource linked to a course component.
865
+ *
866
+ * Component resources map digital content to specific parts
867
+ * of a course structure.
868
+ */
869
+ interface ComponentResource extends Base {
870
+ /** Resource title */
871
+ title: string
872
+ /** Course component this resource belongs to */
873
+ courseComponent: Ref
874
+ /** The resource being linked */
875
+ resource: Ref
876
+ /** Display order within the component */
877
+ sortOrder?: number
878
+ /** Type of lesson (proprietary extension) */
879
+ lessonType?: LessonType
880
+ }
881
+
882
+ /**
883
+ * OneRoster Rostering Types
884
+ *
885
+ * Types for rostering entities: users, orgs, courses, classes, enrollments, terms.
886
+ */
887
+
888
+
889
+
890
+ /**
891
+ * An organization such as a school, district, or department.
892
+ *
893
+ * Organizations form a hierarchy with parent/child relationships.
894
+ * Schools are a specific type of organization.
895
+ */
896
+ interface Organization extends Base {
897
+ /** Display name of the organization */
898
+ name: string
899
+ /** Type of organization (school, district, department, etc.) */
900
+ type: OrganizationType
901
+ /** External identifier (e.g., state school ID) */
902
+ identifier?: string
903
+ /** Reference to parent organization */
904
+ parent?: RefWithHref | null
905
+ /** References to child organizations */
906
+ children?: RefWithHref[] | null
907
+ }
908
+
909
+ /**
910
+ * An external user identifier from another system.
911
+ */
912
+ interface UserId {
913
+ /** Type of identifier (e.g., "SIS", "LDAP") */
914
+ type: string
915
+ /** The identifier value */
916
+ identifier: string
917
+ }
918
+
919
+ /**
920
+ * A role assignment for a user at a specific organization.
921
+ */
922
+ interface UserRole {
923
+ /** Whether this is the user's primary or secondary role */
924
+ roleType: 'primary' | 'secondary'
925
+ /** The role type (student, teacher, administrator, etc.) */
926
+ role: OneRosterUserRole
927
+ /** The organization where this role applies */
928
+ org: RefWithHref
929
+ /** Associated user profile identifier */
930
+ userProfile?: string
931
+ /** Role-specific metadata */
932
+ metadata?: Record<string, unknown> | null
933
+ /** When this role assignment begins */
934
+ beginDate?: string | null
935
+ /** When this role assignment ends */
936
+ endDate?: string | null
937
+ }
938
+
939
+ /** @internal */
940
+ interface UserProfileCredential {
941
+ id: string
942
+ type: string
943
+ username: string
944
+ password?: string | null
945
+ }
946
+
947
+ /** @internal */
948
+ interface UserProfileApp {
949
+ sourcedId: string
950
+ name: string
951
+ description?: string | null
952
+ domain: string[]
953
+ metadata?: Record<string, unknown> | null
954
+ }
955
+
956
+ /** @internal */
957
+ interface UserProfile {
958
+ profileId: string
959
+ profileType: string
960
+ vendorId: string
961
+ applicationId: string
962
+ description?: string | null
963
+ app: UserProfileApp
964
+ credentials: UserProfileCredential[]
965
+ }
966
+
967
+ /**
968
+ * A user in the OneRoster system.
969
+ *
970
+ * Users can be students, teachers, parents, administrators, or other roles.
971
+ * A user may have multiple roles at different organizations.
972
+ */
973
+ interface User extends Base {
974
+ /** Master identifier for cross-system user matching */
975
+ userMasterIdentifier?: string | null
976
+ /** Login username */
977
+ username?: string | null
978
+ /** External identifiers from other systems */
979
+ userIds?: UserId[]
980
+ /** Whether the user account is enabled */
981
+ enabledUser: boolean
982
+ /** User's first name */
983
+ givenName: string
984
+ /** User's last name */
985
+ familyName: string
986
+ /** User's middle name */
987
+ middleName?: string | null
988
+ /** External identifier */
989
+ identifier?: string | null
990
+ /** User's email address */
991
+ email?: string
992
+ /** Role assignments at organizations */
993
+ roles: UserRole[]
994
+ /** References to related users (e.g., parents for students) */
995
+ agents?: RefWithHref[]
996
+ /** Application-specific profiles */
997
+ userProfiles?: UserProfile[]
998
+ /** User's primary organization */
999
+ primaryOrg?: RefWithHref & { name?: string | null }
1000
+ /** Preferred first name */
1001
+ preferredFirstName?: string | null
1002
+ /** Preferred middle name */
1003
+ preferredMiddleName?: string | null
1004
+ /** Preferred last name */
1005
+ preferredLastName?: string | null
1006
+ /** User's pronouns */
1007
+ pronouns?: string | null
1008
+ /** Grade levels associated with the user */
1009
+ grades?: TimebackGrade[]
1010
+ /** Password (write-only, not returned in responses) */
1011
+ password?: string | null
1012
+ /** SMS phone number */
1013
+ sms?: string | null
1014
+ /** Phone number */
1015
+ phone?: string | null
1016
+ /** Demographic information */
1017
+ demographics?: Demographics | null
1018
+ }
1019
+
1020
+ /**
1021
+ * Demographic information for a user.
1022
+ *
1023
+ * Contains sensitive PII data including birth date, race, and ethnicity.
1024
+ */
1025
+ interface Demographics extends Base {
1026
+ /** Birth date in YYYY-MM-DD format */
1027
+ birthDate?: string | null
1028
+ /** Biological sex */
1029
+ sex?: 'male' | 'female' | 'other' | 'unspecified' | null
1030
+ americanIndianOrAlaskaNative?: string | null
1031
+ asian?: string | null
1032
+ blackOrAfricanAmerican?: string | null
1033
+ nativeHawaiianOrOtherPacificIslander?: string | null
1034
+ white?: string | null
1035
+ demographicRaceTwoOrMoreRaces?: string | null
1036
+ hispanicOrLatinoEthnicity?: string | null
1037
+ countryOfBirthCode?: string | null
1038
+ stateOfBirthAbbreviation?: string | null
1039
+ cityOfBirth?: string | null
1040
+ publicSchoolResidenceStatus?: string | null
1041
+ }
1042
+
1043
+ /**
1044
+ * Daily learning goals for a course or enrollment.
1045
+ */
1046
+ interface CourseGoals {
1047
+ /** Target XP to earn per day */
1048
+ dailyXp?: number
1049
+ /** Target lessons to complete per day */
1050
+ dailyLessons?: number
1051
+ /** Target active learning minutes per day */
1052
+ dailyActiveMinutes?: number
1053
+ /** Target accuracy percentage */
1054
+ dailyAccuracy?: number
1055
+ /** Target mastered units per day */
1056
+ dailyMasteredUnits?: number
1057
+ }
1058
+
1059
+ /**
1060
+ * Aggregate metrics for a course.
1061
+ */
1062
+ interface CourseMetrics {
1063
+ /** Total XP available in the course */
1064
+ totalXp?: number
1065
+ /** Total number of lessons/activities */
1066
+ totalLessons?: number
1067
+ /** Total grade levels covered */
1068
+ totalGrades?: number
1069
+ /** Course classification type */
1070
+ courseType?: 'base' | 'hole-filling' | 'optional' | 'Base' | 'Hole-Filling' | 'Optional'
1071
+ /** Whether this is supplemental content */
1072
+ isSupplemental?: boolean
1073
+ }
1074
+
1075
+ /**
1076
+ * Extended metadata for courses.
1077
+ */
1078
+ interface CourseMetadata extends Record<string, unknown> {
1079
+ /** Course classification (base, hole-filling, optional) */
1080
+ courseType?: 'base' | 'hole-filling' | 'optional'
1081
+ /** Whether this is supplemental content */
1082
+ isSupplemental?: boolean
1083
+ /** Whether this is a custom course for a specific student */
1084
+ isCustom?: boolean
1085
+ /** Publication status of the course */
1086
+ publishStatus?: 'draft' | 'testing' | 'published' | 'deactivated'
1087
+ /** Contact email for course issues */
1088
+ contactEmail?: string
1089
+ /** Primary application identifier */
1090
+ primaryApp?: string
1091
+ /** Daily learning goals */
1092
+ goals?: CourseGoals
1093
+ /** Aggregate metrics */
1094
+ metrics?: CourseMetrics
1095
+ }
1096
+
1097
+ /**
1098
+ * A course in the curriculum.
1099
+ *
1100
+ * Courses define the content to be taught and can have multiple classes
1101
+ * (sections) associated with them.
1102
+ */
1103
+ interface Course extends Omit<Base, 'metadata'> {
1104
+ /** Course-specific metadata */
1105
+ metadata?: CourseMetadata | null
1106
+ /** Course title */
1107
+ title: string
1108
+ /** Course code (e.g., "MATH101") */
1109
+ courseCode?: string
1110
+ /** Grade levels for this course */
1111
+ grades?: TimebackGrade[]
1112
+ /** Subject areas */
1113
+ subjects?: TimebackSubject[]
1114
+ /** Subject codes */
1115
+ subjectCodes?: string[]
1116
+ /** Organization offering this course */
1117
+ org: Ref
1118
+ /** Course level (e.g., "AP", "Honors") */
1119
+ level?: string
1120
+ /** Grading scheme identifier */
1121
+ gradingScheme?: string
1122
+ /** Associated academic session */
1123
+ academicSession?: Ref
1124
+ /** School year reference */
1125
+ schoolYear?: RefWithHref
1126
+ /** Learning resources for this course */
1127
+ resources?: RefWithHref[]
1128
+ }
1129
+
1130
+ /**
1131
+ * A single item in a QTI-derived course structure.
1132
+ *
1133
+ * Represents metadata about a lesson/skill from QTI test content.
1134
+ */
1135
+ interface CourseStructureItem {
1136
+ /** URL to the QTI content */
1137
+ url: string
1138
+ /** Skill code identifier */
1139
+ skillCode: string
1140
+ /** Lesson code identifier */
1141
+ lessonCode: string
1142
+ /** Title of the lesson/skill */
1143
+ title: string
1144
+ /** Title of the containing unit */
1145
+ 'unit-title': string
1146
+ /** Status of the content */
1147
+ status: string
1148
+ /** Experience points value */
1149
+ xp: number
1150
+ /** Optional stimulus content */
1151
+ stimulus?: {
1152
+ title: string
1153
+ identifier: string
1154
+ }
1155
+ /** Optional video content */
1156
+ video?: {
1157
+ url: string
1158
+ title: string
1159
+ }
1160
+ }
1161
+
1162
+ /**
1163
+ * A component or module within a course.
1164
+ */
1165
+ interface CourseComponent extends Base {
1166
+ /** Display title */
1167
+ title: string
1168
+ /** Parent course reference */
1169
+ course: Ref
1170
+ /** Nested course component reference */
1171
+ courseComponent?: Ref | null
1172
+ /** Parent component reference */
1173
+ parent?: Ref | null
1174
+ /** Display order */
1175
+ sortOrder?: number
1176
+ /** Prerequisite component IDs */
1177
+ prerequisites?: string[]
1178
+ /** Whether all or any prerequisites are required */
1179
+ prerequisiteCriteria?: 'ALL' | 'ANY'
1180
+ /** Date when component becomes available */
1181
+ unlockDate?: string
1182
+ }
1183
+
1184
+ /**
1185
+ * A class (section) where students and teachers meet.
1186
+ *
1187
+ * Classes are instances of courses for specific terms and locations.
1188
+ */
1189
+ interface Class extends Base {
1190
+ /** Class title */
1191
+ title: string
1192
+ /** Class code/section identifier */
1193
+ classCode?: string | null
1194
+ /** Type of class */
1195
+ classType?: 'homeroom' | 'scheduled'
1196
+ /** Physical location */
1197
+ location?: string | null
1198
+ /** Grade levels */
1199
+ grades?: TimebackGrade[]
1200
+ /** Subject areas */
1201
+ subjects?: TimebackSubject[]
1202
+ /** Subject codes */
1203
+ subjectCodes?: string[]
1204
+ /** Period/time slot identifiers */
1205
+ periods?: string[]
1206
+ /** Associated terms */
1207
+ terms?: RefWithHref[]
1208
+ /** Course this class is a section of */
1209
+ course?: RefWithHref | null
1210
+ /** School where this class is held */
1211
+ school?: RefWithHref | null
1212
+ /** Learning resources for this class */
1213
+ resources?: RefWithHref[]
1214
+ }
1215
+
1216
+ /**
1217
+ * Goals for an individual enrollment.
1218
+ */
1219
+ interface EnrollmentGoals {
1220
+ dailyXp?: number
1221
+ dailyLessons?: number
1222
+ dailyActiveMinutes?: number
1223
+ dailyAccuracy?: number
1224
+ dailyMasteredUnits?: number
1225
+ }
1226
+
1227
+ /**
1228
+ * Metrics for an enrollment.
1229
+ */
1230
+ interface EnrollmentMetrics {
1231
+ totalXp?: number
1232
+ totalLessons?: number
1233
+ totalGrades?: number
1234
+ courseType?: string
1235
+ isSupplemental?: boolean
1236
+ }
1237
+
1238
+ /**
1239
+ * Extended metadata for enrollments.
1240
+ */
1241
+ interface EnrollmentMetadata extends Record<string, unknown> {
1242
+ /** Individual learning goals */
1243
+ goals?: EnrollmentGoals
1244
+ /** Progress metrics */
1245
+ metrics?: EnrollmentMetrics
1246
+ }
1247
+
1248
+ /**
1249
+ * An enrollment linking a user to a class.
1250
+ *
1251
+ * Enrollments define the relationship between users and classes,
1252
+ * including their role (student, teacher) and the time period.
1253
+ */
1254
+ interface Enrollment extends Omit<Base, 'metadata'> {
1255
+ /** Enrollment-specific metadata with goals and metrics */
1256
+ metadata?: EnrollmentMetadata | null
1257
+ /** The enrolled user */
1258
+ user: RefWithHref & { name?: string }
1259
+ /** The class the user is enrolled in */
1260
+ class: RefWithHref & { name?: string }
1261
+ /** The school */
1262
+ school: RefWithHref & { name?: string }
1263
+ /** The course */
1264
+ course: RefWithHref & { name?: string }
1265
+ /** Role in this enrollment (student, teacher, etc.) */
1266
+ role: OneRosterUserRole
1267
+ /** Whether this is the user's primary class ("true"/"false") */
1268
+ primary?: string | null
1269
+ /** Start date of enrollment */
1270
+ beginDate?: string | null
1271
+ /** End date of enrollment */
1272
+ endDate?: string | null
1273
+ }
1274
+
1275
+ /**
1276
+ * An academic session such as a term, semester, or school year.
1277
+ *
1278
+ * Academic sessions define time periods for scheduling and can be
1279
+ * nested (e.g., terms within a school year).
1280
+ */
1281
+ interface AcademicSession extends Base {
1282
+ /** Session title (e.g., "Fall 2024") */
1283
+ title: string
1284
+ /** Start date in YYYY-MM-DD format */
1285
+ startDate: string
1286
+ /** End date in YYYY-MM-DD format */
1287
+ endDate: string
1288
+ /** Type of session */
1289
+ type: 'gradingPeriod' | 'semester' | 'schoolYear' | 'term'
1290
+ /** Parent session reference */
1291
+ parent?: RefWithHref | null
1292
+ /** School year as a number (e.g., 2024) */
1293
+ schoolYear: number
1294
+ /** Organization this session belongs to */
1295
+ org: RefWithHref
1296
+ /** Child sessions */
1297
+ children?: RefWithHref[] | null
1298
+ }
1299
+
1300
+ /**
1301
+ * A term within an academic year.
1302
+ * Alias for AcademicSession with type 'term'.
1303
+ */
1304
+ type Term = AcademicSession
1305
+
1306
+ /**
1307
+ * A grading period within a term or semester.
1308
+ * Alias for AcademicSession with type 'gradingPeriod'.
1309
+ */
1310
+ type GradingPeriod = AcademicSession
1311
+
1312
+ // ═══════════════════════════════════════════════════════════════════════════════
1313
+ // AGENT/CREDENTIAL TYPES
1314
+ // ═══════════════════════════════════════════════════════════════════════════════
1315
+
1316
+ /**
1317
+ * Response from creating user credentials.
1318
+ */
1319
+ interface CredentialCreateResponse {
1320
+ /** The user profile ID */
1321
+ userProfileId: string
1322
+ /** The created credential ID */
1323
+ credentialId: string
1324
+ /** Status message */
1325
+ message: string
1326
+ }
1327
+
1328
+ /**
1329
+ * Response from decrypting user credentials.
1330
+ */
1331
+ interface DecryptedCredential {
1332
+ /** The decrypted password */
1333
+ password: string
1334
+ }
1335
+
1336
+ type input<T> = T extends {
1337
+ _zod: {
1338
+ input: any;
1339
+ };
1340
+ } ? T["_zod"]["input"] : unknown;
1341
+
1342
+ /**
1343
+ * OneRoster Schemas
1344
+ *
1345
+ * Zod schemas for OneRoster inputs used across CLI and SDK clients.
1346
+ */
1347
+
1348
+
1349
+
1350
+ /**
1351
+ * Input for assigning a role to a user.
1352
+ */
1353
+ declare const OneRosterUserRoleInput = z
1354
+ .object({
1355
+ roleType: z.enum(['primary', 'secondary']),
1356
+ role: OneRosterUserRole,
1357
+ org: Ref,
1358
+ userProfile: z.string().optional(),
1359
+ metadata: Metadata,
1360
+ beginDate: OneRosterDateString.optional(),
1361
+ endDate: OneRosterDateString.optional(),
1362
+ })
1363
+ .strict()
1364
+
1365
+ // ═══════════════════════════════════════════════════════════════════════════════
1366
+ // USERS
1367
+ // ═══════════════════════════════════════════════════════════════════════════════
1368
+
1369
+ /**
1370
+ * Input for creating a OneRoster user.
1371
+ *
1372
+ * Enforces required fields while allowing additional fields via passthrough.
1373
+ */
1374
+ declare const OneRosterUserCreateInput = z
1375
+ .object({
1376
+ sourcedId: NonEmptyString.describe('sourcedId must be a non-empty string'),
1377
+ status: Status.optional(),
1378
+ enabledUser: z.boolean(),
1379
+ givenName: NonEmptyString.describe('givenName must be a non-empty string'),
1380
+ familyName: NonEmptyString.describe('familyName must be a non-empty string'),
1381
+ middleName: NonEmptyString.optional(),
1382
+ username: NonEmptyString.optional(),
1383
+ email: z.email().optional(),
1384
+ roles: z.array(OneRosterUserRoleInput).min(1, 'roles must include at least one role'),
1385
+ userIds: z
1386
+ .array(
1387
+ z
1388
+ .object({
1389
+ type: NonEmptyString,
1390
+ identifier: NonEmptyString,
1391
+ })
1392
+ .strict(),
1393
+ )
1394
+ .optional(),
1395
+ agents: z.array(Ref).optional(),
1396
+ grades: z.array(TimebackGrade).optional(),
1397
+ identifier: NonEmptyString.optional(),
1398
+ sms: NonEmptyString.optional(),
1399
+ phone: NonEmptyString.optional(),
1400
+ pronouns: NonEmptyString.optional(),
1401
+ password: NonEmptyString.optional(),
1402
+ metadata: Metadata,
1403
+ })
1404
+ .strict()
1405
+
1406
+ // ═══════════════════════════════════════════════════════════════════════════════
1407
+ // COURSES
1408
+ // ═══════════════════════════════════════════════════════════════════════════════
1409
+
1410
+ /**
1411
+ * Input for creating a OneRoster course.
1412
+ *
1413
+ * Enforces required fields while allowing additional fields.
1414
+ */
1415
+ declare const OneRosterCourseCreateInput = z
1416
+ .object({
1417
+ sourcedId: NonEmptyString.describe('sourcedId must be a non-empty string').optional(),
1418
+ status: Status.optional(),
1419
+ title: NonEmptyString.describe('title must be a non-empty string'),
1420
+ org: Ref,
1421
+ courseCode: NonEmptyString.optional(),
1422
+ subjects: z.array(TimebackSubject).optional(),
1423
+ grades: z.array(TimebackGrade).optional(),
1424
+ level: NonEmptyString.optional(),
1425
+ metadata: Metadata,
1426
+ })
1427
+ .strict()
1428
+
1429
+ // ═══════════════════════════════════════════════════════════════════════════════
1430
+ // CLASSES
1431
+ // ═══════════════════════════════════════════════════════════════════════════════
1432
+
1433
+ /**
1434
+ * Input for creating a OneRoster class.
1435
+ *
1436
+ * Enforces required fields while allowing additional fields.
1437
+ */
1438
+ declare const OneRosterClassCreateInput = z
1439
+ .object({
1440
+ sourcedId: NonEmptyString.describe('sourcedId must be a non-empty string').optional(),
1441
+ status: Status.optional(),
1442
+ title: NonEmptyString.describe('title must be a non-empty string'),
1443
+ terms: z.array(Ref).min(1, 'terms must have at least one item'),
1444
+ course: Ref,
1445
+ org: Ref,
1446
+ classCode: NonEmptyString.optional(),
1447
+ classType: z.enum(['homeroom', 'scheduled']).optional(),
1448
+ location: NonEmptyString.optional(),
1449
+ grades: z.array(TimebackGrade).optional(),
1450
+ subjects: z.array(TimebackSubject).optional(),
1451
+ subjectCodes: z.array(NonEmptyString).optional(),
1452
+ periods: z.array(NonEmptyString).optional(),
1453
+ metadata: Metadata,
1454
+ })
1455
+ .strict()
1456
+
1457
+ declare const OneRosterEnrollmentCreateInput = z
1458
+ .object({
1459
+ sourcedId: NonEmptyString.describe('sourcedId must be a non-empty string').optional(),
1460
+ status: Status.optional(),
1461
+ user: Ref,
1462
+ class: Ref,
1463
+ school: Ref.optional(),
1464
+ role: OneRosterUserRole,
1465
+ primary: StringBoolean.optional(),
1466
+ beginDate: OneRosterDateString.optional(),
1467
+ endDate: OneRosterDateString.optional(),
1468
+ metadata: Metadata,
1469
+ })
1470
+ .strict()
1471
+
1472
+ // ═══════════════════════════════════════════════════════════════════════════════
1473
+ // CATEGORIES (GRADEBOOK)
1474
+ // ═══════════════════════════════════════════════════════════════════════════════
1475
+
1476
+ /**
1477
+ * Input for creating a OneRoster category.
1478
+ *
1479
+ * Enforces title and status while allowing additional fields.
1480
+ */
1481
+ declare const OneRosterCategoryCreateInput = z
1482
+ .object({
1483
+ sourcedId: NonEmptyString.optional(),
1484
+ title: NonEmptyString.describe('title must be a non-empty string'),
1485
+ status: Status,
1486
+ weight: z.number().nullable().optional(),
1487
+ metadata: Metadata,
1488
+ })
1489
+ .strict()
1490
+
1491
+ // ═══════════════════════════════════════════════════════════════════════════════
1492
+ // LINE ITEMS (GRADEBOOK)
1493
+ // ═══════════════════════════════════════════════════════════════════════════════
1494
+
1495
+ /**
1496
+ * Input for creating a OneRoster line item.
1497
+ *
1498
+ * Enforces required fields: title, class, school, category, assignDate, dueDate, status.
1499
+ */
1500
+ declare const OneRosterLineItemCreateInput = z
1501
+ .object({
1502
+ sourcedId: NonEmptyString.optional(),
1503
+ title: NonEmptyString.describe('title must be a non-empty string'),
1504
+ class: Ref,
1505
+ school: Ref,
1506
+ category: Ref,
1507
+ assignDate: OneRosterDateString,
1508
+ dueDate: OneRosterDateString,
1509
+ status: Status,
1510
+ description: z.string().optional(),
1511
+ resultValueMin: z.number().nullable().optional(),
1512
+ resultValueMax: z.number().nullable().optional(),
1513
+ scoreScale: Ref.optional(),
1514
+ metadata: Metadata,
1515
+ })
1516
+ .strict()
1517
+
1518
+ // ═══════════════════════════════════════════════════════════════════════════════
1519
+ // RESULTS (GRADEBOOK)
1520
+ // ═══════════════════════════════════════════════════════════════════════════════
1521
+
1522
+ /**
1523
+ * Input for creating a OneRoster result (grade).
1524
+ *
1525
+ * Enforces required fields: lineItem, student, scoreDate, scoreStatus, status.
1526
+ */
1527
+ declare const OneRosterResultCreateInput = z
1528
+ .object({
1529
+ sourcedId: NonEmptyString.optional(),
1530
+ lineItem: Ref,
1531
+ student: Ref,
1532
+ class: Ref.optional(),
1533
+ scoreDate: OneRosterDateString,
1534
+ scoreStatus: z.enum([
1535
+ 'exempt',
1536
+ 'fully graded',
1537
+ 'not submitted',
1538
+ 'partially graded',
1539
+ 'submitted',
1540
+ ]),
1541
+ score: z.number().nullable().optional(),
1542
+ textScore: z.string().nullable().optional(),
1543
+ status: Status,
1544
+ comment: z.string().nullable().optional(),
1545
+ metadata: Metadata,
1546
+ })
1547
+ .strict()
1548
+
1549
+ // ═══════════════════════════════════════════════════════════════════════════════
1550
+ // SCORE SCALES (GRADEBOOK)
1551
+ // ═══════════════════════════════════════════════════════════════════════════════
1552
+
1553
+ /**
1554
+ * Input for creating a OneRoster score scale.
1555
+ *
1556
+ * Enforces title while allowing additional fields.
1557
+ */
1558
+ declare const OneRosterScoreScaleCreateInput = z
1559
+ .object({
1560
+ sourcedId: NonEmptyString.optional(),
1561
+ title: NonEmptyString.describe('title must be a non-empty string'),
1562
+ status: Status.optional(),
1563
+ type: z.string().optional(),
1564
+ class: Ref.optional(),
1565
+ course: Ref.nullable().optional(),
1566
+ scoreScaleValue: z
1567
+ .array(
1568
+ z
1569
+ .object({
1570
+ itemValueLHS: NonEmptyString,
1571
+ itemValueRHS: NonEmptyString,
1572
+ value: z.string().optional(),
1573
+ description: z.string().optional(),
1574
+ })
1575
+ .strict(),
1576
+ )
1577
+ .optional(),
1578
+ minScore: z.number().optional(),
1579
+ maxScore: z.number().optional(),
1580
+ metadata: Metadata,
1581
+ })
1582
+ .strict()
1583
+
1584
+ // ═══════════════════════════════════════════════════════════════════════════════
1585
+ // ASSESSMENT LINE ITEMS
1586
+ // ═══════════════════════════════════════════════════════════════════════════════
1587
+
1588
+ /**
1589
+ * Input for creating a OneRoster assessment line item.
1590
+ * Matches Timeback server `AssessmentLineItemSchema` (beyond-timeback-api-2).
1591
+ */
1592
+ declare const OneRosterAssessmentLineItemCreateInput = z
1593
+ .object({
1594
+ sourcedId: NonEmptyString.optional(),
1595
+ status: Status.optional(),
1596
+ dateLastModified: IsoDateTimeString.optional(),
1597
+ title: NonEmptyString.describe('title must be a non-empty string'),
1598
+ description: z.string().nullable().optional(),
1599
+ class: Ref.nullable().optional(),
1600
+ parentAssessmentLineItem: Ref.nullable().optional(),
1601
+ scoreScale: Ref.nullable().optional(),
1602
+ resultValueMin: z.number().nullable().optional(),
1603
+ resultValueMax: z.number().nullable().optional(),
1604
+ // Proprietary extensions
1605
+ component: Ref.nullable().optional(),
1606
+ componentResource: Ref.nullable().optional(),
1607
+ learningObjectiveSet: z
1608
+ .array(
1609
+ z.object({
1610
+ source: z.string(),
1611
+ learningObjectiveIds: z.array(z.string()),
1612
+ }),
1613
+ )
1614
+ .optional()
1615
+ .nullable(),
1616
+ course: Ref.nullable().optional(),
1617
+ metadata: Metadata,
1618
+ })
1619
+ .strict()
1620
+
1621
+ /**
1622
+ * Input for creating a OneRoster assessment result.
1623
+ * Matches Timeback server `AssessmentResultSchema` (beyond-timeback-api-2).
1624
+ */
1625
+ declare const OneRosterAssessmentResultCreateInput = z
1626
+ .object({
1627
+ sourcedId: NonEmptyString.optional(),
1628
+ status: Status.optional(),
1629
+ dateLastModified: IsoDateTimeString.optional(),
1630
+ metadata: Metadata,
1631
+ assessmentLineItem: Ref,
1632
+ student: Ref,
1633
+ score: z.number().nullable().optional(),
1634
+ textScore: z.string().nullable().optional(),
1635
+ scoreDate: z.string().datetime(),
1636
+ scoreScale: Ref.nullable().optional(),
1637
+ scorePercentile: z.number().nullable().optional(),
1638
+ scoreStatus: z.enum([
1639
+ 'exempt',
1640
+ 'fully graded',
1641
+ 'not submitted',
1642
+ 'partially graded',
1643
+ 'submitted',
1644
+ ]),
1645
+ comment: z.string().nullable().optional(),
1646
+ learningObjectiveSet: LearningObjectiveScoreSetSchema.nullable().optional(),
1647
+ inProgress: z.string().nullable().optional(),
1648
+ incomplete: z.string().nullable().optional(),
1649
+ late: z.string().nullable().optional(),
1650
+ missing: z.string().nullable().optional(),
1651
+ })
1652
+ .strict()
1653
+
1654
+ // ═══════════════════════════════════════════════════════════════════════════════
1655
+ // ORGANIZATIONS
1656
+ // ═══════════════════════════════════════════════════════════════════════════════
1657
+
1658
+ /**
1659
+ * Input for creating a OneRoster organization.
1660
+ *
1661
+ * Enforces name and type while allowing additional fields.
1662
+ */
1663
+ declare const OneRosterOrgCreateInput = z
1664
+ .object({
1665
+ sourcedId: NonEmptyString.optional(),
1666
+ status: Status.optional(),
1667
+ name: NonEmptyString.describe('name must be a non-empty string'),
1668
+ type: OrganizationType,
1669
+ identifier: NonEmptyString.optional(),
1670
+ parent: Ref.optional(),
1671
+ metadata: Metadata,
1672
+ })
1673
+ .strict()
1674
+
1675
+ /**
1676
+ * Input for creating a OneRoster school (org with type='school').
1677
+ *
1678
+ * Enforces name and optionally validates type.
1679
+ */
1680
+ declare const OneRosterSchoolCreateInput = z
1681
+ .object({
1682
+ sourcedId: NonEmptyString.optional(),
1683
+ status: Status.optional(),
1684
+ name: NonEmptyString.describe('name must be a non-empty string'),
1685
+ type: z.literal('school').optional(),
1686
+ identifier: NonEmptyString.optional(),
1687
+ parent: Ref.optional(),
1688
+ metadata: Metadata,
1689
+ })
1690
+ .strict()
1691
+
1692
+ // ═══════════════════════════════════════════════════════════════════════════════
1693
+ // ACADEMIC SESSIONS
1694
+ // ═══════════════════════════════════════════════════════════════════════════════
1695
+
1696
+ /**
1697
+ * Input for creating a OneRoster academic session.
1698
+ *
1699
+ * Enforces required fields: sourcedId, status, title, startDate, endDate, type, schoolYear, org.
1700
+ */
1701
+ declare const OneRosterAcademicSessionCreateInput = z
1702
+ .object({
1703
+ sourcedId: NonEmptyString.describe('sourcedId must be a non-empty string'),
1704
+ status: Status,
1705
+ title: NonEmptyString.describe('title must be a non-empty string'),
1706
+ startDate: OneRosterDateString,
1707
+ endDate: OneRosterDateString,
1708
+ type: z.enum(['gradingPeriod', 'semester', 'schoolYear', 'term']),
1709
+ schoolYear: NonEmptyString.describe('schoolYear must be a non-empty string'),
1710
+ org: Ref,
1711
+ parent: Ref.optional(),
1712
+ children: z.array(Ref).optional(),
1713
+ metadata: Metadata,
1714
+ })
1715
+ .strict()
1716
+
1717
+ // ═══════════════════════════════════════════════════════════════════════════════
1718
+ // COMPONENT RESOURCES
1719
+ // ═══════════════════════════════════════════════════════════════════════════════
1720
+
1721
+ /**
1722
+ * Input for creating a OneRoster component resource.
1723
+ *
1724
+ * Enforces required fields while allowing additional fields.
1725
+ */
1726
+ declare const OneRosterComponentResourceCreateInput = z
1727
+ .object({
1728
+ sourcedId: NonEmptyString.optional(),
1729
+ title: NonEmptyString.describe('title must be a non-empty string'),
1730
+ courseComponent: Ref,
1731
+ resource: Ref,
1732
+ status: Status,
1733
+ metadata: Metadata,
1734
+ })
1735
+ .strict()
1736
+
1737
+ // ═══════════════════════════════════════════════════════════════════════════════
1738
+ // COURSE COMPONENTS
1739
+ // ═══════════════════════════════════════════════════════════════════════════════
1740
+
1741
+ /**
1742
+ * Input for creating a OneRoster course component.
1743
+ *
1744
+ * Enforces title, course, and status while allowing additional fields.
1745
+ */
1746
+ declare const OneRosterCourseComponentCreateInput = z
1747
+ .object({
1748
+ sourcedId: NonEmptyString.optional(),
1749
+ title: NonEmptyString.describe('title must be a non-empty string'),
1750
+ course: Ref,
1751
+ status: Status,
1752
+ metadata: Metadata,
1753
+ })
1754
+ .strict()
1755
+
1756
+ // ═══════════════════════════════════════════════════════════════════════════════
1757
+ // ENROLL INPUT (CONVENIENCE)
1758
+ // ═══════════════════════════════════════════════════════════════════════════════
1759
+
1760
+ /**
1761
+ * Input for enrolling a user in a class (convenience method).
1762
+ *
1763
+ * Enforces sourcedId and role while allowing additional fields.
1764
+ */
1765
+ declare const OneRosterEnrollInput = z
1766
+ .object({
1767
+ sourcedId: NonEmptyString.describe('sourcedId must be a non-empty string'),
1768
+ role: z.enum(['student', 'teacher']),
1769
+ primary: StringBoolean.optional(),
1770
+ beginDate: OneRosterDateString.optional(),
1771
+ endDate: OneRosterDateString.optional(),
1772
+ metadata: Metadata,
1773
+ })
1774
+ .strict()
1775
+
1776
+ // ═══════════════════════════════════════════════════════════════════════════════
1777
+ // AGENT INPUT
1778
+ // ═══════════════════════════════════════════════════════════════════════════════
1779
+
1780
+ /**
1781
+ * Input for adding an agent (parent/guardian) relationship.
1782
+ *
1783
+ * Enforces agentSourcedId.
1784
+ */
1785
+ declare const OneRosterAgentInput = z
1786
+ .object({
1787
+ agentSourcedId: NonEmptyString.describe('agentSourcedId must be a non-empty string'),
1788
+ })
1789
+ .strict()
1790
+
1791
+ // ═══════════════════════════════════════════════════════════════════════════════
1792
+ // DEMOGRAPHICS INPUT
1793
+ // ═══════════════════════════════════════════════════════════════════════════════
1794
+
1795
+ /**
1796
+ * Input for creating/updating demographics.
1797
+ *
1798
+ * Enforces sourcedId while allowing additional fields.
1799
+ */
1800
+ declare const OneRosterDemographicsCreateInput = z
1801
+ .object({
1802
+ sourcedId: NonEmptyString.describe('sourcedId must be a non-empty string'),
1803
+ })
1804
+ .loose()
1805
+
1806
+ // ═══════════════════════════════════════════════════════════════════════════════
1807
+ // RESOURCE INPUT
1808
+ // ═══════════════════════════════════════════════════════════════════════════════
1809
+
1810
+ /**
1811
+ * Input for creating/updating resources.
1812
+ *
1813
+ * Enforces title and vendorResourceId while allowing additional fields.
1814
+ */
1815
+ declare const OneRosterResourceCreateInput = z
1816
+ .object({
1817
+ sourcedId: NonEmptyString.optional(),
1818
+ title: NonEmptyString.describe('title must be a non-empty string'),
1819
+ vendorResourceId: NonEmptyString.describe('vendorResourceId must be a non-empty string'),
1820
+ roles: z.array(z.enum(['primary', 'secondary'])).optional(),
1821
+ importance: z.enum(['primary', 'secondary']).optional(),
1822
+ vendorId: z.string().optional(),
1823
+ applicationId: z.string().optional(),
1824
+ status: Status.optional(),
1825
+ metadata: ResourceMetadataSchema.nullable().optional(),
1826
+ })
1827
+ .strict()
1828
+
1829
+ /**
1830
+ * Input for creating a course structure from QTI tests.
1831
+ *
1832
+ * Enforces course required fields and courseStructure shape.
1833
+ */
1834
+ declare const OneRosterCourseStructureInput = z
1835
+ .object({
1836
+ course: z
1837
+ .object({
1838
+ sourcedId: NonEmptyString.describe(
1839
+ 'course.sourcedId must be a non-empty string',
1840
+ ).optional(),
1841
+ title: NonEmptyString.describe('course.title must be a non-empty string'),
1842
+ org: Ref,
1843
+ status: Status,
1844
+ metadata: Metadata,
1845
+ })
1846
+ .strict(),
1847
+ courseStructure: z.record(z.string(), CourseStructureItem),
1848
+ })
1849
+ .strict()
1850
+
1851
+ /**
1852
+ * Input array for bulk result creation.
1853
+ */
1854
+ declare const OneRosterBulkResultsInput = z
1855
+ .array(OneRosterBulkResultItem)
1856
+ .min(1, 'results must have at least one item')
1857
+
1858
+ // ═══════════════════════════════════════════════════════════════════════════════
1859
+ // TYPE EXPORTS (REQUEST INPUTS)
1860
+ // ═══════════════════════════════════════════════════════════════════════════════
1861
+
1862
+ type OrgCreateInput = input<typeof OneRosterOrgCreateInput>
1863
+ type SchoolCreateInput = input<typeof OneRosterSchoolCreateInput>
1864
+ type UserRoleInput = input<typeof OneRosterUserRoleInput>
1865
+ type UserCreateInput = input<typeof OneRosterUserCreateInput>
1866
+ type DemographicsCreateInput = input<typeof OneRosterDemographicsCreateInput>
1867
+ type CourseCreateInput = input<typeof OneRosterCourseCreateInput>
1868
+ type CourseStructureInput = input<typeof OneRosterCourseStructureInput>
1869
+ type CourseComponentCreateInput = input<typeof OneRosterCourseComponentCreateInput>
1870
+ type ClassCreateInput = input<typeof OneRosterClassCreateInput>
1871
+ type EnrollmentCreateInput = input<typeof OneRosterEnrollmentCreateInput>
1872
+ type EnrollInput = input<typeof OneRosterEnrollInput>
1873
+ type AcademicSessionCreateInput = input<typeof OneRosterAcademicSessionCreateInput>
1874
+ type AgentInput = input<typeof OneRosterAgentInput>
1875
+ type CategoryCreateInput = input<typeof OneRosterCategoryCreateInput>
1876
+ type LineItemCreateInput = input<typeof OneRosterLineItemCreateInput>
1877
+ type ResultCreateInput = input<typeof OneRosterResultCreateInput>
1878
+ type ComponentResourceCreateInput = input<typeof OneRosterComponentResourceCreateInput>
1879
+ type ResourceCreateInput = input<typeof OneRosterResourceCreateInput>
1880
+ type ScoreScaleCreateInput = input<typeof OneRosterScoreScaleCreateInput>
1881
+ type AssessmentLineItemCreateInput = input<typeof OneRosterAssessmentLineItemCreateInput>
1882
+ type AssessmentResultCreateInput = input<typeof OneRosterAssessmentResultCreateInput>
1883
+ type BulkResultsInput = input<typeof OneRosterBulkResultsInput>
1884
+
1885
+ export type { AcademicSession, AcademicSessionCreateInput, AcademicSessionFilterFields, AgentInput, AssessmentBankResourceMetadata, AssessmentLineItem, AssessmentLineItemCreateInput, AssessmentLineItemFilterFields, AssessmentResult, AssessmentResultCreateInput, AssessmentResultFilterFields, AudioResourceMetadata, Base, BaseFilterFields, BaseResourceMetadata, BulkResultsInput, Category, CategoryCreateInput, CategoryFilterFields, Class, ClassCreateInput, ClassFilterFields, ComponentResource, ComponentResourceCreateInput, ComponentResourceFilterFields, Course, CourseComponent, CourseComponentCreateInput, CourseComponentFilterFields, CourseCreateInput, CourseFilterFields, CourseGoals, CourseMaterialResourceMetadata, CourseMetadata, CourseMetrics, CourseStructureInput, CourseStructureItem, CreateResponse, CredentialCreateResponse, DecryptedCredential, Demographics, DemographicsCreateInput, DemographicsFilterFields, EnrollInput, Enrollment, EnrollmentCreateInput, EnrollmentFilterFields, EnrollmentGoals, EnrollmentMetadata, EnrollmentMetrics, GradingPeriod, IMSErrorResponse, InteractiveResourceMetadata, LearningObjectiveResult, LearningObjectiveSet, LearningObjectiveSetItem, LessonType, LineItem, LineItemCreateInput, LineItemFilterFields, OneRosterUserRole, OrgCreateInput, Organization, OrganizationFilterFields, OrganizationType, QtiResourceMetadata, Ref, RefWithHref, RefWithType, Resource, ResourceCreateInput, ResourceFilterFields, ResourceMetadata, ResourceType, Result, ResultCreateInput, ResultFilterFields, SchoolCreateInput, ScoreScale, ScoreScaleCreateInput, ScoreScaleFilterFields, ScoreScaleValue, ScoreStatus, Term, TextualResourceMetadata, TimebackGrade, TimebackSubject, User, UserCreateInput, UserFilterFields, UserId, UserProfile, UserProfileApp, UserProfileCredential, UserRole, UserRoleInput, VideoResourceMetadata, VisualResourceMetadata };