@timeback/caliper 0.1.5 → 0.1.6
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/dist/index.d.ts +1381 -52
- package/dist/public-types.d.ts +879 -0
- package/dist/public-types.d.ts.map +1 -0
- package/package.json +3 -3
- /package/dist/{types.js → public-types.js} +0 -0
|
@@ -0,0 +1,879 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Timeback Shared Primitives
|
|
3
|
+
*
|
|
4
|
+
* Core types used across multiple Timeback protocols.
|
|
5
|
+
*
|
|
6
|
+
* Organization:
|
|
7
|
+
* - Shared types (this file): Used by multiple protocols (Caliper, OneRoster, etc.)
|
|
8
|
+
* - Protocol-specific types: Live in their respective protocols/X/primitives.ts files
|
|
9
|
+
*
|
|
10
|
+
* What belongs here:
|
|
11
|
+
* - TimebackSubject - Used in OneRoster courses AND Caliper events
|
|
12
|
+
* - TimebackGrade - Used across OneRoster, Caliper, and QTI
|
|
13
|
+
* - IMSErrorResponse - IMS Global standard used by multiple 1EdTech protocols
|
|
14
|
+
*
|
|
15
|
+
* What doesn't belong here:
|
|
16
|
+
* - OneRoster-specific: protocols/oneroster/primitives.ts
|
|
17
|
+
* - QTI-specific: protocols/qti/primitives.ts
|
|
18
|
+
*/
|
|
19
|
+
|
|
20
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
21
|
+
// TIMEBACK SHARED TYPES
|
|
22
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* Valid Timeback subject values.
|
|
26
|
+
* Used in OneRoster courses and Caliper events.
|
|
27
|
+
*/
|
|
28
|
+
type TimebackSubject =
|
|
29
|
+
| 'Reading'
|
|
30
|
+
| 'Language'
|
|
31
|
+
| 'Vocabulary'
|
|
32
|
+
| 'Social Studies'
|
|
33
|
+
| 'Writing'
|
|
34
|
+
| 'Science'
|
|
35
|
+
| 'FastMath'
|
|
36
|
+
| 'Math'
|
|
37
|
+
| 'None'
|
|
38
|
+
| 'Other'
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
* Timeback Profile Types
|
|
42
|
+
*
|
|
43
|
+
* First-class types for the Timeback Caliper profile, including
|
|
44
|
+
* ActivityCompletedEvent and TimeSpentEvent.
|
|
45
|
+
*/
|
|
46
|
+
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
// ═══════════════════════════════════════════════════════════════════════════════
|
|
50
|
+
// TIMEBACK ACTIVITY CONTEXT
|
|
51
|
+
// ═══════════════════════════════════════════════════════════════════════════════
|
|
52
|
+
|
|
53
|
+
// ═══════════════════════════════════════════════════════════════════════════════
|
|
54
|
+
// TIMEBACK USER
|
|
55
|
+
// ═══════════════════════════════════════════════════════════════════════════════
|
|
56
|
+
|
|
57
|
+
/**
|
|
58
|
+
* User role in the Timeback platform.
|
|
59
|
+
*/
|
|
60
|
+
type TimebackUserRole = 'student' | 'teacher' | 'admin' | 'guide'
|
|
61
|
+
|
|
62
|
+
/**
|
|
63
|
+
* Timeback user entity.
|
|
64
|
+
*
|
|
65
|
+
* Represents a user in the Timeback platform. The `id` should ideally be
|
|
66
|
+
* the OneRoster URL for the user when available.
|
|
67
|
+
*
|
|
68
|
+
* @example
|
|
69
|
+
* ```typescript
|
|
70
|
+
* const user: TimebackUser = {
|
|
71
|
+
* id: 'https://api.alpha-1edtech.ai/ims/oneroster/rostering/v1p2/users/123',
|
|
72
|
+
* type: 'TimebackUser',
|
|
73
|
+
* email: 'student@example.edu',
|
|
74
|
+
* name: 'Jane Doe',
|
|
75
|
+
* role: 'student',
|
|
76
|
+
* }
|
|
77
|
+
* ```
|
|
78
|
+
*/
|
|
79
|
+
interface TimebackUser {
|
|
80
|
+
/** User identifier (IRI format, preferably OneRoster URL) */
|
|
81
|
+
id: string
|
|
82
|
+
/** Must be 'TimebackUser' */
|
|
83
|
+
type: 'TimebackUser'
|
|
84
|
+
/** User email address */
|
|
85
|
+
email: string
|
|
86
|
+
/** User display name */
|
|
87
|
+
name?: string
|
|
88
|
+
/** User role */
|
|
89
|
+
role?: TimebackUserRole
|
|
90
|
+
/** Additional custom attributes */
|
|
91
|
+
extensions?: Record<string, unknown>
|
|
92
|
+
/** Index signature for Caliper compatibility */
|
|
93
|
+
[key: string]: unknown
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
/**
|
|
97
|
+
* Application reference within activity context.
|
|
98
|
+
*/
|
|
99
|
+
interface TimebackApp {
|
|
100
|
+
/** Application identifier (IRI format) */
|
|
101
|
+
id?: string
|
|
102
|
+
/** Application name */
|
|
103
|
+
name: string
|
|
104
|
+
/** Additional custom attributes */
|
|
105
|
+
extensions?: Record<string, unknown>
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
/**
|
|
109
|
+
* Course reference within activity context.
|
|
110
|
+
*/
|
|
111
|
+
interface TimebackCourse {
|
|
112
|
+
/** Course identifier (IRI format, preferably OneRoster URL) */
|
|
113
|
+
id?: string
|
|
114
|
+
/** Course name */
|
|
115
|
+
name: string
|
|
116
|
+
/** Additional custom attributes */
|
|
117
|
+
extensions?: Record<string, unknown>
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
/**
|
|
121
|
+
* Activity reference within activity context.
|
|
122
|
+
*/
|
|
123
|
+
interface TimebackActivity {
|
|
124
|
+
/** Activity identifier (IRI format) */
|
|
125
|
+
id?: string
|
|
126
|
+
/** Activity name */
|
|
127
|
+
name: string
|
|
128
|
+
/** Additional custom attributes */
|
|
129
|
+
extensions?: Record<string, unknown>
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
/**
|
|
133
|
+
* Timeback activity context.
|
|
134
|
+
*
|
|
135
|
+
* Represents the context where an event was recorded, including
|
|
136
|
+
* subject, application, course, and activity information.
|
|
137
|
+
*
|
|
138
|
+
* @example
|
|
139
|
+
* ```typescript
|
|
140
|
+
* const context: TimebackActivityContext = {
|
|
141
|
+
* id: 'https://myapp.example.com/activities/123',
|
|
142
|
+
* type: 'TimebackActivityContext',
|
|
143
|
+
* subject: 'Math',
|
|
144
|
+
* app: { name: 'My Learning App' },
|
|
145
|
+
* course: { name: 'Algebra 101' },
|
|
146
|
+
* activity: { name: 'Chapter 1 Quiz' },
|
|
147
|
+
* }
|
|
148
|
+
* ```
|
|
149
|
+
*/
|
|
150
|
+
interface TimebackActivityContext {
|
|
151
|
+
/** Context identifier (IRI format) */
|
|
152
|
+
id: string
|
|
153
|
+
/** Must be 'TimebackActivityContext' */
|
|
154
|
+
type: 'TimebackActivityContext'
|
|
155
|
+
/** Subject area */
|
|
156
|
+
subject: TimebackSubject
|
|
157
|
+
/** Application where event was recorded */
|
|
158
|
+
app: TimebackApp
|
|
159
|
+
/** Course where event was recorded */
|
|
160
|
+
course?: TimebackCourse
|
|
161
|
+
/** Activity where event was recorded */
|
|
162
|
+
activity?: TimebackActivity
|
|
163
|
+
/** Whether to process this event */
|
|
164
|
+
process?: boolean
|
|
165
|
+
/** Index signature for Caliper compatibility */
|
|
166
|
+
[key: string]: unknown
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
// ═══════════════════════════════════════════════════════════════════════════════
|
|
170
|
+
// ACTIVITY METRICS
|
|
171
|
+
// ═══════════════════════════════════════════════════════════════════════════════
|
|
172
|
+
|
|
173
|
+
/**
|
|
174
|
+
* Types of activity metrics.
|
|
175
|
+
*/
|
|
176
|
+
type ActivityMetricType =
|
|
177
|
+
| 'xpEarned'
|
|
178
|
+
| 'totalQuestions'
|
|
179
|
+
| 'correctQuestions'
|
|
180
|
+
| 'masteredUnits'
|
|
181
|
+
|
|
182
|
+
/**
|
|
183
|
+
* Individual activity metric.
|
|
184
|
+
*
|
|
185
|
+
* @example
|
|
186
|
+
* ```typescript
|
|
187
|
+
* const metric: TimebackActivityMetric = {
|
|
188
|
+
* type: 'correctQuestions',
|
|
189
|
+
* value: 8,
|
|
190
|
+
* }
|
|
191
|
+
* ```
|
|
192
|
+
*/
|
|
193
|
+
interface TimebackActivityMetric {
|
|
194
|
+
/** Metric type */
|
|
195
|
+
type: ActivityMetricType
|
|
196
|
+
/** Metric value */
|
|
197
|
+
value: number
|
|
198
|
+
/** Additional custom attributes */
|
|
199
|
+
extensions?: Record<string, unknown>
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
/**
|
|
203
|
+
* Collection of activity metrics.
|
|
204
|
+
*
|
|
205
|
+
* @example
|
|
206
|
+
* ```typescript
|
|
207
|
+
* const metrics: TimebackActivityMetricsCollection = {
|
|
208
|
+
* id: 'https://myapp.example.com/metrics/123',
|
|
209
|
+
* type: 'TimebackActivityMetricsCollection',
|
|
210
|
+
* attempt: 1,
|
|
211
|
+
* items: [
|
|
212
|
+
* { type: 'totalQuestions', value: 10 },
|
|
213
|
+
* { type: 'correctQuestions', value: 8 },
|
|
214
|
+
* { type: 'xpEarned', value: 150 },
|
|
215
|
+
* ],
|
|
216
|
+
* extensions: { pctCompleteApp: 67 },
|
|
217
|
+
* }
|
|
218
|
+
* ```
|
|
219
|
+
*/
|
|
220
|
+
interface TimebackActivityMetricsCollection {
|
|
221
|
+
/** Collection identifier (IRI format) */
|
|
222
|
+
id: string
|
|
223
|
+
/** Must be 'TimebackActivityMetricsCollection' */
|
|
224
|
+
type: 'TimebackActivityMetricsCollection'
|
|
225
|
+
/** Attempt number (1-based) */
|
|
226
|
+
attempt?: number
|
|
227
|
+
/** Array of metrics */
|
|
228
|
+
items: TimebackActivityMetric[]
|
|
229
|
+
/**
|
|
230
|
+
* Additional custom attributes.
|
|
231
|
+
*
|
|
232
|
+
* Common fields:
|
|
233
|
+
* - `pctCompleteApp`: App-defined course completion percentage (0–100)
|
|
234
|
+
*/
|
|
235
|
+
extensions?: Record<string, unknown>
|
|
236
|
+
/** Index signature for Caliper compatibility */
|
|
237
|
+
[key: string]: unknown
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
// ═══════════════════════════════════════════════════════════════════════════════
|
|
241
|
+
// TIME SPENT METRICS
|
|
242
|
+
// ═══════════════════════════════════════════════════════════════════════════════
|
|
243
|
+
|
|
244
|
+
/**
|
|
245
|
+
* Types of time spent metrics.
|
|
246
|
+
*/
|
|
247
|
+
type TimeSpentMetricType = 'active' | 'inactive' | 'waste' | 'unknown' | 'anti-pattern'
|
|
248
|
+
|
|
249
|
+
/**
|
|
250
|
+
* Individual time spent metric.
|
|
251
|
+
*
|
|
252
|
+
* @example
|
|
253
|
+
* ```typescript
|
|
254
|
+
* const metric: TimeSpentMetric = {
|
|
255
|
+
* type: 'active',
|
|
256
|
+
* value: 1800, // 30 minutes in seconds
|
|
257
|
+
* startDate: '2024-01-15T10:00:00Z',
|
|
258
|
+
* endDate: '2024-01-15T10:30:00Z',
|
|
259
|
+
* }
|
|
260
|
+
* ```
|
|
261
|
+
*/
|
|
262
|
+
interface TimeSpentMetric {
|
|
263
|
+
/** Metric type */
|
|
264
|
+
type: TimeSpentMetricType
|
|
265
|
+
/** Time spent in seconds (max 86400 = 24 hours) */
|
|
266
|
+
value: number
|
|
267
|
+
/** Sub-type for additional categorization */
|
|
268
|
+
subType?: string
|
|
269
|
+
/** Start of the time period */
|
|
270
|
+
startDate?: string
|
|
271
|
+
/** End of the time period */
|
|
272
|
+
endDate?: string
|
|
273
|
+
/** Additional custom attributes */
|
|
274
|
+
extensions?: Record<string, unknown>
|
|
275
|
+
}
|
|
276
|
+
|
|
277
|
+
/**
|
|
278
|
+
* Collection of time spent metrics.
|
|
279
|
+
*
|
|
280
|
+
* @example
|
|
281
|
+
* ```typescript
|
|
282
|
+
* const metrics: TimebackTimeSpentMetricsCollection = {
|
|
283
|
+
* id: 'https://myapp.example.com/time-metrics/123',
|
|
284
|
+
* type: 'TimebackTimeSpentMetricsCollection',
|
|
285
|
+
* items: [
|
|
286
|
+
* { type: 'active', value: 1800 },
|
|
287
|
+
* { type: 'inactive', value: 300 },
|
|
288
|
+
* ],
|
|
289
|
+
* }
|
|
290
|
+
* ```
|
|
291
|
+
*/
|
|
292
|
+
interface TimebackTimeSpentMetricsCollection {
|
|
293
|
+
/** Collection identifier (IRI format) */
|
|
294
|
+
id: string
|
|
295
|
+
/** Must be 'TimebackTimeSpentMetricsCollection' */
|
|
296
|
+
type: 'TimebackTimeSpentMetricsCollection'
|
|
297
|
+
/** Array of time spent metrics */
|
|
298
|
+
items: TimeSpentMetric[]
|
|
299
|
+
/** Additional custom attributes */
|
|
300
|
+
extensions?: Record<string, unknown>
|
|
301
|
+
/** Index signature for Caliper compatibility */
|
|
302
|
+
[key: string]: unknown
|
|
303
|
+
}
|
|
304
|
+
|
|
305
|
+
// ═══════════════════════════════════════════════════════════════════════════════
|
|
306
|
+
// TIMEBACK EVENTS
|
|
307
|
+
// ═══════════════════════════════════════════════════════════════════════════════
|
|
308
|
+
|
|
309
|
+
/**
|
|
310
|
+
* Base properties common to all Timeback events.
|
|
311
|
+
*/
|
|
312
|
+
interface TimebackEventBase {
|
|
313
|
+
/** JSON-LD context */
|
|
314
|
+
'@context': 'http://purl.imsglobal.org/ctx/caliper/v1p2'
|
|
315
|
+
/** Unique identifier (URN UUID format) */
|
|
316
|
+
id: string
|
|
317
|
+
/** The user who performed the action */
|
|
318
|
+
actor: TimebackUser
|
|
319
|
+
/** The activity context */
|
|
320
|
+
object: TimebackActivityContext
|
|
321
|
+
/** ISO 8601 datetime when event occurred */
|
|
322
|
+
eventTime: string
|
|
323
|
+
/** Must be 'TimebackProfile' */
|
|
324
|
+
profile: 'TimebackProfile'
|
|
325
|
+
/** Application context (IRI or entity) */
|
|
326
|
+
edApp?: string | Record<string, unknown>
|
|
327
|
+
/** Target segment within object */
|
|
328
|
+
target?: string | Record<string, unknown>
|
|
329
|
+
/** Referring context */
|
|
330
|
+
referrer?: string | Record<string, unknown>
|
|
331
|
+
/** Organization/group context */
|
|
332
|
+
group?: string | Record<string, unknown>
|
|
333
|
+
/** User's membership/role */
|
|
334
|
+
membership?: string | Record<string, unknown>
|
|
335
|
+
/** Current user session */
|
|
336
|
+
session?: string | Record<string, unknown>
|
|
337
|
+
/** LTI session context */
|
|
338
|
+
federatedSession?: string | Record<string, unknown>
|
|
339
|
+
/** Additional custom attributes */
|
|
340
|
+
extensions?: Record<string, unknown>
|
|
341
|
+
}
|
|
342
|
+
|
|
343
|
+
/**
|
|
344
|
+
* Timeback Activity Completed Event.
|
|
345
|
+
*
|
|
346
|
+
* Records when a student completes an activity, along with performance metrics.
|
|
347
|
+
*
|
|
348
|
+
* @example
|
|
349
|
+
* ```typescript
|
|
350
|
+
* const event: ActivityCompletedEvent = {
|
|
351
|
+
* '@context': 'http://purl.imsglobal.org/ctx/caliper/v1p2',
|
|
352
|
+
* id: 'urn:uuid:c51570e4-f8ed-4c18-bb3a-dfe51b2cc594',
|
|
353
|
+
* type: 'ActivityEvent',
|
|
354
|
+
* action: 'Completed',
|
|
355
|
+
* actor: {
|
|
356
|
+
* id: 'https://api.example.com/users/123',
|
|
357
|
+
* type: 'TimebackUser',
|
|
358
|
+
* email: 'student@example.edu',
|
|
359
|
+
* },
|
|
360
|
+
* object: {
|
|
361
|
+
* id: 'https://myapp.example.com/activities/456',
|
|
362
|
+
* type: 'TimebackActivityContext',
|
|
363
|
+
* subject: 'Math',
|
|
364
|
+
* app: { name: 'My Learning App' },
|
|
365
|
+
* },
|
|
366
|
+
* eventTime: '2024-01-15T14:30:00Z',
|
|
367
|
+
* profile: 'TimebackProfile',
|
|
368
|
+
* generated: {
|
|
369
|
+
* id: 'https://myapp.example.com/metrics/789',
|
|
370
|
+
* type: 'TimebackActivityMetricsCollection',
|
|
371
|
+
* items: [
|
|
372
|
+
* { type: 'totalQuestions', value: 10 },
|
|
373
|
+
* { type: 'correctQuestions', value: 8 },
|
|
374
|
+
* ],
|
|
375
|
+
* },
|
|
376
|
+
* }
|
|
377
|
+
* ```
|
|
378
|
+
*/
|
|
379
|
+
interface ActivityCompletedEvent extends TimebackEventBase {
|
|
380
|
+
/** Must be 'ActivityEvent' */
|
|
381
|
+
type: 'ActivityEvent'
|
|
382
|
+
/** Must be 'Completed' */
|
|
383
|
+
action: 'Completed'
|
|
384
|
+
/** Activity metrics generated from this completion */
|
|
385
|
+
generated: TimebackActivityMetricsCollection
|
|
386
|
+
}
|
|
387
|
+
|
|
388
|
+
/**
|
|
389
|
+
* Timeback Time Spent Event.
|
|
390
|
+
*
|
|
391
|
+
* Records time spent on an activity, categorized by engagement type.
|
|
392
|
+
*
|
|
393
|
+
* @example
|
|
394
|
+
* ```typescript
|
|
395
|
+
* const event: TimeSpentEvent = {
|
|
396
|
+
* '@context': 'http://purl.imsglobal.org/ctx/caliper/v1p2',
|
|
397
|
+
* id: 'urn:uuid:d62681f5-g9fe-5d29-cc4b-efg62c3dd695',
|
|
398
|
+
* type: 'TimeSpentEvent',
|
|
399
|
+
* action: 'SpentTime',
|
|
400
|
+
* actor: {
|
|
401
|
+
* id: 'https://api.example.com/users/123',
|
|
402
|
+
* type: 'TimebackUser',
|
|
403
|
+
* email: 'student@example.edu',
|
|
404
|
+
* },
|
|
405
|
+
* object: {
|
|
406
|
+
* id: 'https://myapp.example.com/activities/456',
|
|
407
|
+
* type: 'TimebackActivityContext',
|
|
408
|
+
* subject: 'Reading',
|
|
409
|
+
* app: { name: 'My Learning App' },
|
|
410
|
+
* },
|
|
411
|
+
* eventTime: '2024-01-15T15:00:00Z',
|
|
412
|
+
* profile: 'TimebackProfile',
|
|
413
|
+
* generated: {
|
|
414
|
+
* id: 'https://myapp.example.com/time-metrics/789',
|
|
415
|
+
* type: 'TimebackTimeSpentMetricsCollection',
|
|
416
|
+
* items: [
|
|
417
|
+
* { type: 'active', value: 1800 },
|
|
418
|
+
* { type: 'inactive', value: 300 },
|
|
419
|
+
* ],
|
|
420
|
+
* },
|
|
421
|
+
* }
|
|
422
|
+
* ```
|
|
423
|
+
*/
|
|
424
|
+
interface TimeSpentEvent extends TimebackEventBase {
|
|
425
|
+
/** Must be 'TimeSpentEvent' */
|
|
426
|
+
type: 'TimeSpentEvent'
|
|
427
|
+
/** Must be 'SpentTime' */
|
|
428
|
+
action: 'SpentTime'
|
|
429
|
+
/** Time spent metrics generated from this session */
|
|
430
|
+
generated: TimebackTimeSpentMetricsCollection
|
|
431
|
+
}
|
|
432
|
+
|
|
433
|
+
/**
|
|
434
|
+
* Union of all Timeback event types.
|
|
435
|
+
*/
|
|
436
|
+
type TimebackEvent = ActivityCompletedEvent | TimeSpentEvent
|
|
437
|
+
|
|
438
|
+
/**
|
|
439
|
+
* Caliper Event Types
|
|
440
|
+
*
|
|
441
|
+
* Types for Caliper Analytics events and envelopes.
|
|
442
|
+
*/
|
|
443
|
+
|
|
444
|
+
|
|
445
|
+
|
|
446
|
+
/**
|
|
447
|
+
* Supported Caliper profiles.
|
|
448
|
+
*/
|
|
449
|
+
type CaliperProfile =
|
|
450
|
+
| 'AnnotationProfile'
|
|
451
|
+
| 'AssessmentProfile'
|
|
452
|
+
| 'ToolUseProfile'
|
|
453
|
+
| 'GeneralProfile'
|
|
454
|
+
| 'FeedbackProfile'
|
|
455
|
+
| 'MediaProfile'
|
|
456
|
+
| 'SurveyProfile'
|
|
457
|
+
| 'ResourceManagementProfile'
|
|
458
|
+
| 'ForumProfile'
|
|
459
|
+
| 'AssignableProfile'
|
|
460
|
+
| 'GradingProfile'
|
|
461
|
+
| 'ReadingProfile'
|
|
462
|
+
| 'SessionProfile'
|
|
463
|
+
| 'SearchProfile'
|
|
464
|
+
| 'ToolLaunchProfile'
|
|
465
|
+
| 'TimebackProfile'
|
|
466
|
+
|
|
467
|
+
/**
|
|
468
|
+
* Base Caliper entity - can be a URI string or an object with properties.
|
|
469
|
+
*/
|
|
470
|
+
type CaliperEntity = string | { [key: string]: unknown }
|
|
471
|
+
|
|
472
|
+
/**
|
|
473
|
+
* Caliper actor entity (for sending events).
|
|
474
|
+
*
|
|
475
|
+
* Timeback API requires actors to have extensions.email.
|
|
476
|
+
*/
|
|
477
|
+
interface CaliperActor {
|
|
478
|
+
/** Unique identifier (IRI format) */
|
|
479
|
+
id: string
|
|
480
|
+
/** Entity type (e.g., 'Person', 'TimebackUser') */
|
|
481
|
+
type: string
|
|
482
|
+
/** Extensions - email is required by Timeback API */
|
|
483
|
+
extensions: {
|
|
484
|
+
/** Actor's email address (required by Timeback) */
|
|
485
|
+
email: string
|
|
486
|
+
/** Additional extension properties */
|
|
487
|
+
[key: string]: unknown
|
|
488
|
+
}
|
|
489
|
+
}
|
|
490
|
+
|
|
491
|
+
/**
|
|
492
|
+
* Caliper Event.
|
|
493
|
+
*
|
|
494
|
+
* Represents a learning activity event conforming to IMS Caliper v1.2.
|
|
495
|
+
*/
|
|
496
|
+
interface CaliperEvent {
|
|
497
|
+
/** JSON-LD context */
|
|
498
|
+
'@context'?: string
|
|
499
|
+
/** Unique identifier (URN UUID format) */
|
|
500
|
+
id: string
|
|
501
|
+
/** Event type */
|
|
502
|
+
type: string
|
|
503
|
+
/** The agent who initiated the event (string URL, CaliperActor, or TimebackUser) */
|
|
504
|
+
actor: string | CaliperActor | TimebackUser
|
|
505
|
+
/** The action or predicate */
|
|
506
|
+
action: string
|
|
507
|
+
/** The object of the interaction */
|
|
508
|
+
object: CaliperEntity
|
|
509
|
+
/** ISO 8601 datetime when event occurred */
|
|
510
|
+
eventTime: string
|
|
511
|
+
/** Profile governing interpretation */
|
|
512
|
+
profile: CaliperProfile
|
|
513
|
+
/** Application context */
|
|
514
|
+
edApp?: CaliperEntity
|
|
515
|
+
/** Entity generated as result */
|
|
516
|
+
generated?: CaliperEntity
|
|
517
|
+
/** Target segment within object */
|
|
518
|
+
target?: CaliperEntity
|
|
519
|
+
/** Referring context */
|
|
520
|
+
referrer?: CaliperEntity
|
|
521
|
+
/** Organization/group context */
|
|
522
|
+
group?: CaliperEntity
|
|
523
|
+
/** User's membership/role */
|
|
524
|
+
membership?: CaliperEntity
|
|
525
|
+
/** Current user session */
|
|
526
|
+
session?: CaliperEntity
|
|
527
|
+
/** LTI session context */
|
|
528
|
+
federatedSession?: CaliperEntity
|
|
529
|
+
/** Additional custom attributes */
|
|
530
|
+
extensions?: Record<string, unknown>
|
|
531
|
+
}
|
|
532
|
+
|
|
533
|
+
/**
|
|
534
|
+
* Caliper Envelope.
|
|
535
|
+
*
|
|
536
|
+
* Container for transmitting Caliper events to the API.
|
|
537
|
+
*/
|
|
538
|
+
interface CaliperEnvelope {
|
|
539
|
+
/** Sensor identifier (IRI format) */
|
|
540
|
+
sensor: string
|
|
541
|
+
/** ISO 8601 datetime when data was sent */
|
|
542
|
+
sendTime: string
|
|
543
|
+
/** Caliper data version */
|
|
544
|
+
dataVersion: 'http://purl.imsglobal.org/ctx/caliper/v1p2'
|
|
545
|
+
/** Array of events or entities */
|
|
546
|
+
data: CaliperEvent[]
|
|
547
|
+
}
|
|
548
|
+
|
|
549
|
+
/**
|
|
550
|
+
* Result of sending events.
|
|
551
|
+
*/
|
|
552
|
+
interface SendEventsResult {
|
|
553
|
+
/** Job ID for tracking async processing */
|
|
554
|
+
jobId: string
|
|
555
|
+
}
|
|
556
|
+
|
|
557
|
+
/**
|
|
558
|
+
* Individual event result from job completion.
|
|
559
|
+
*/
|
|
560
|
+
interface EventResult {
|
|
561
|
+
/** Allocated internal ID */
|
|
562
|
+
allocatedId: string
|
|
563
|
+
/** External event ID */
|
|
564
|
+
externalId: string
|
|
565
|
+
}
|
|
566
|
+
|
|
567
|
+
/**
|
|
568
|
+
* Job status response.
|
|
569
|
+
*/
|
|
570
|
+
interface JobStatus {
|
|
571
|
+
id: string
|
|
572
|
+
state: 'waiting' | 'active' | 'completed' | 'failed'
|
|
573
|
+
returnValue?: {
|
|
574
|
+
status: 'success' | 'error'
|
|
575
|
+
results: EventResult[]
|
|
576
|
+
}
|
|
577
|
+
processedOn?: string | null
|
|
578
|
+
}
|
|
579
|
+
|
|
580
|
+
/**
|
|
581
|
+
* Stored Caliper event (from list/get).
|
|
582
|
+
*
|
|
583
|
+
* This represents an event as returned by the API, which differs from the
|
|
584
|
+
* input CaliperEvent format. The API adds internal fields and transforms
|
|
585
|
+
* the original event ID to `externalId`.
|
|
586
|
+
*
|
|
587
|
+
* @remarks
|
|
588
|
+
* **API Docs Drift**: The official OpenAPI spec (caliper-api.yaml) does not
|
|
589
|
+
* accurately document this response structure. This type was derived from
|
|
590
|
+
* actual API responses. Key differences:
|
|
591
|
+
* - `id` is a number (internal DB ID), not a string
|
|
592
|
+
* - `externalId` contains the original URN UUID (use this for `get()` calls)
|
|
593
|
+
* - Response is wrapped in `{ events: StoredEvent[] }` for list, `{ event: StoredEvent }` for get
|
|
594
|
+
*/
|
|
595
|
+
interface StoredEvent {
|
|
596
|
+
/** Internal numeric ID (allocated by the database) */
|
|
597
|
+
id: number
|
|
598
|
+
/** Original event ID (URN UUID format) - use this for get() calls */
|
|
599
|
+
externalId: string
|
|
600
|
+
/** Sensor that sent the event */
|
|
601
|
+
sensor: string
|
|
602
|
+
/** Event type (e.g., 'ActivityEvent', 'Event') */
|
|
603
|
+
type: string
|
|
604
|
+
/** Caliper profile (e.g., 'TimebackProfile') */
|
|
605
|
+
profile?: string
|
|
606
|
+
/** The action or predicate */
|
|
607
|
+
action: string
|
|
608
|
+
/** When the event occurred */
|
|
609
|
+
eventTime: string
|
|
610
|
+
/** When the event was sent */
|
|
611
|
+
sendTime: string
|
|
612
|
+
/** When the record was last updated */
|
|
613
|
+
updated_at: string | null
|
|
614
|
+
/** When the record was created */
|
|
615
|
+
created_at: string
|
|
616
|
+
/** When the record was deleted (soft delete) */
|
|
617
|
+
deleted_at: string | null
|
|
618
|
+
/** The agent who initiated the event */
|
|
619
|
+
actor: CaliperEntity
|
|
620
|
+
/** The object of the event */
|
|
621
|
+
object: CaliperEntity
|
|
622
|
+
/** Generated entity (e.g., result, score) */
|
|
623
|
+
generated?: CaliperEntity | null
|
|
624
|
+
/** Target entity */
|
|
625
|
+
target?: CaliperEntity | null
|
|
626
|
+
/** Referrer entity */
|
|
627
|
+
referrer?: CaliperEntity | null
|
|
628
|
+
/** EdApp entity */
|
|
629
|
+
edApp?: CaliperEntity | null
|
|
630
|
+
/** Group/organization entity */
|
|
631
|
+
group?: CaliperEntity | null
|
|
632
|
+
/** Membership entity */
|
|
633
|
+
membership?: CaliperEntity | null
|
|
634
|
+
/** Session entity */
|
|
635
|
+
session?: CaliperEntity | null
|
|
636
|
+
/** Federated session entity */
|
|
637
|
+
federatedSession?: CaliperEntity | null
|
|
638
|
+
/** Extension data */
|
|
639
|
+
extensions?: Record<string, unknown> | null
|
|
640
|
+
/** Client application ID */
|
|
641
|
+
clientAppId?: string | null
|
|
642
|
+
}
|
|
643
|
+
|
|
644
|
+
/**
|
|
645
|
+
* Result from listing events.
|
|
646
|
+
*/
|
|
647
|
+
interface ListEventsResult {
|
|
648
|
+
events: StoredEvent[]
|
|
649
|
+
pagination: PaginationMeta
|
|
650
|
+
}
|
|
651
|
+
|
|
652
|
+
/**
|
|
653
|
+
* API Response Types
|
|
654
|
+
*
|
|
655
|
+
* Types for Caliper API responses.
|
|
656
|
+
*
|
|
657
|
+
* @remarks
|
|
658
|
+
* **IMPORTANT - API Docs Drift**: The official API documentation (caliper/response.yaml
|
|
659
|
+
* and caliper-api.yaml) does NOT accurately reflect actual API responses. The types
|
|
660
|
+
* in this file were derived from testing actual API responses. See individual type
|
|
661
|
+
* comments for specific discrepancies.
|
|
662
|
+
*/
|
|
663
|
+
|
|
664
|
+
|
|
665
|
+
|
|
666
|
+
/**
|
|
667
|
+
* Generic API response wrapper.
|
|
668
|
+
*/
|
|
669
|
+
interface ApiResponse<T> {
|
|
670
|
+
status: 'success' | 'error'
|
|
671
|
+
message?: string
|
|
672
|
+
data?: T
|
|
673
|
+
}
|
|
674
|
+
|
|
675
|
+
/**
|
|
676
|
+
* Pagination metadata returned by list endpoints.
|
|
677
|
+
*/
|
|
678
|
+
interface PaginationMeta {
|
|
679
|
+
/** Total number of items across all pages */
|
|
680
|
+
total: number
|
|
681
|
+
/** Total number of pages */
|
|
682
|
+
totalPages: number
|
|
683
|
+
/** Current page number (1-indexed) */
|
|
684
|
+
currentPage: number
|
|
685
|
+
/** Number of items per page */
|
|
686
|
+
limit: number
|
|
687
|
+
}
|
|
688
|
+
|
|
689
|
+
/**
|
|
690
|
+
* Response from GET /caliper/events (list events).
|
|
691
|
+
*
|
|
692
|
+
* @remarks
|
|
693
|
+
* **API Docs Drift**: Official docs (caliper/response.yaml) incorrectly show
|
|
694
|
+
* `{ status, message, errors? }`. Actual response is `{ events, pagination }`.
|
|
695
|
+
*/
|
|
696
|
+
interface ListEventsResponse {
|
|
697
|
+
/** Array of stored events */
|
|
698
|
+
events: StoredEvent[]
|
|
699
|
+
/** Pagination metadata */
|
|
700
|
+
pagination: PaginationMeta
|
|
701
|
+
}
|
|
702
|
+
|
|
703
|
+
/**
|
|
704
|
+
* Response from GET /caliper/events/:externalId (get single event).
|
|
705
|
+
*
|
|
706
|
+
* @remarks
|
|
707
|
+
* **API Docs Drift**: Official docs (caliper/response.yaml) incorrectly show
|
|
708
|
+
* `{ status, message, errors? }`. Actual response is `{ status, event }`.
|
|
709
|
+
*/
|
|
710
|
+
interface GetEventResponse {
|
|
711
|
+
/** Status indicator */
|
|
712
|
+
status: 'success' | 'error'
|
|
713
|
+
/** The requested event */
|
|
714
|
+
event: StoredEvent
|
|
715
|
+
}
|
|
716
|
+
|
|
717
|
+
/**
|
|
718
|
+
* Response from POST /caliper/event (send events).
|
|
719
|
+
*
|
|
720
|
+
* @remarks
|
|
721
|
+
* **API Docs Drift**: Official docs (caliper/response.yaml) incorrectly show
|
|
722
|
+
* `{ status, message, errors? }`. Actual response is `{ jobId }`.
|
|
723
|
+
* Use the jobId with `jobs.getStatus()` to track processing.
|
|
724
|
+
*/
|
|
725
|
+
interface SendEventsResponse {
|
|
726
|
+
/** Job ID for tracking async processing */
|
|
727
|
+
jobId: string
|
|
728
|
+
}
|
|
729
|
+
|
|
730
|
+
/**
|
|
731
|
+
* Job status response payload (GET /jobs/{jobId}/status).
|
|
732
|
+
*
|
|
733
|
+
* @remarks
|
|
734
|
+
* This endpoint is correctly documented in caliper/response.yaml.
|
|
735
|
+
*/
|
|
736
|
+
interface JobStatusResponse {
|
|
737
|
+
job: JobStatus
|
|
738
|
+
}
|
|
739
|
+
|
|
740
|
+
/**
|
|
741
|
+
* Options for waitForCompletion polling.
|
|
742
|
+
*/
|
|
743
|
+
interface WaitForCompletionOptions {
|
|
744
|
+
/** Maximum time to wait in milliseconds (default: 30000) */
|
|
745
|
+
timeoutMs?: number
|
|
746
|
+
/** Interval between status checks in milliseconds (default: 1000) */
|
|
747
|
+
pollIntervalMs?: number
|
|
748
|
+
}
|
|
749
|
+
|
|
750
|
+
/**
|
|
751
|
+
* Validation result from the validate endpoint.
|
|
752
|
+
*/
|
|
753
|
+
interface ValidationResult {
|
|
754
|
+
/** Whether validation succeeded */
|
|
755
|
+
status: 'success' | 'error'
|
|
756
|
+
/** Human-readable message */
|
|
757
|
+
message?: string
|
|
758
|
+
/** Validation errors (if any) */
|
|
759
|
+
errors?: unknown
|
|
760
|
+
}
|
|
761
|
+
|
|
762
|
+
/**
|
|
763
|
+
* Caliper Constants
|
|
764
|
+
*
|
|
765
|
+
* Configuration constants for the Caliper Analytics client.
|
|
766
|
+
*/
|
|
767
|
+
|
|
768
|
+
/**
|
|
769
|
+
* Caliper JSON-LD context version.
|
|
770
|
+
*/
|
|
771
|
+
declare const CALIPER_DATA_VERSION = "http://purl.imsglobal.org/ctx/caliper/v1p2";
|
|
772
|
+
|
|
773
|
+
type input<T> = T extends {
|
|
774
|
+
_zod: {
|
|
775
|
+
input: any;
|
|
776
|
+
};
|
|
777
|
+
} ? T["_zod"]["input"] : unknown;
|
|
778
|
+
|
|
779
|
+
/**
|
|
780
|
+
* Caliper Schemas
|
|
781
|
+
*
|
|
782
|
+
* Zod schemas for the IMS Caliper Analytics standard with Timeback Profile.
|
|
783
|
+
*/
|
|
784
|
+
|
|
785
|
+
|
|
786
|
+
|
|
787
|
+
// ═══════════════════════════════════════════════════════════════════════════════
|
|
788
|
+
// BUILDER INPUTS
|
|
789
|
+
// ═══════════════════════════════════════════════════════════════════════════════
|
|
790
|
+
|
|
791
|
+
declare const ActivityCompletedInput = z
|
|
792
|
+
.object({
|
|
793
|
+
actor: TimebackUser,
|
|
794
|
+
object: TimebackActivityContext,
|
|
795
|
+
metrics: z.array(TimebackActivityMetric).min(1, 'metrics must contain at least one metric'),
|
|
796
|
+
eventTime: IsoDateTimeString.optional(),
|
|
797
|
+
metricsId: z.string().optional(),
|
|
798
|
+
id: z.string().optional(),
|
|
799
|
+
/** Event-level extensions */
|
|
800
|
+
extensions: z.record(z.string(), z.unknown()).optional(),
|
|
801
|
+
/**
|
|
802
|
+
* Application context (IRI or entity).
|
|
803
|
+
*
|
|
804
|
+
* Maps to `edApp` in the Caliper event. Identifies the educational
|
|
805
|
+
* application where the event occurred.
|
|
806
|
+
*/
|
|
807
|
+
edApp: z.union([z.string(), z.record(z.string(), z.unknown())]).optional(),
|
|
808
|
+
/**
|
|
809
|
+
* Session context (IRI or entity).
|
|
810
|
+
*
|
|
811
|
+
* Maps to `session` in the Caliper event. Used for event-to-session
|
|
812
|
+
* correlation (e.g., linking heartbeats with completions via runId).
|
|
813
|
+
*/
|
|
814
|
+
session: z.union([z.string(), z.record(z.string(), z.unknown())]).optional(),
|
|
815
|
+
/**
|
|
816
|
+
* Attempt number (1-based).
|
|
817
|
+
*
|
|
818
|
+
* Maps to `generated.attempt` in the Caliper event.
|
|
819
|
+
*/
|
|
820
|
+
attempt: z.number().int().min(1).optional(),
|
|
821
|
+
/**
|
|
822
|
+
* Extensions for the generated metrics collection.
|
|
823
|
+
*
|
|
824
|
+
* Maps to `generated.extensions` in the Caliper event.
|
|
825
|
+
* Use `generatedExtensions.pctCompleteApp` (0–100) for app-reported course progress.
|
|
826
|
+
*/
|
|
827
|
+
generatedExtensions: z
|
|
828
|
+
.object({
|
|
829
|
+
/**
|
|
830
|
+
* App-reported course progress (per enrollment), as a percentage from 0–100.
|
|
831
|
+
*
|
|
832
|
+
* This is emitted to Caliper as `generated.extensions.pctCompleteApp`.
|
|
833
|
+
*
|
|
834
|
+
* @remarks
|
|
835
|
+
* This value is not clamped here (Caliper client keeps the raw shape).
|
|
836
|
+
*/
|
|
837
|
+
pctCompleteApp: z.number().optional(),
|
|
838
|
+
})
|
|
839
|
+
.loose()
|
|
840
|
+
.optional(),
|
|
841
|
+
})
|
|
842
|
+
.strict()
|
|
843
|
+
|
|
844
|
+
// ═══════════════════════════════════════════════════════════════════════════════
|
|
845
|
+
// TYPE EXPORTS (REQUEST INPUTS)
|
|
846
|
+
// ═══════════════════════════════════════════════════════════════════════════════
|
|
847
|
+
|
|
848
|
+
type ActivityCompletedInput = input<typeof ActivityCompletedInput>
|
|
849
|
+
|
|
850
|
+
declare const TimeSpentInput = z
|
|
851
|
+
.object({
|
|
852
|
+
actor: TimebackUser,
|
|
853
|
+
object: TimebackActivityContext,
|
|
854
|
+
metrics: z.array(TimebackTimeMetric).min(1, 'metrics must contain at least one metric'),
|
|
855
|
+
eventTime: IsoDateTimeString.optional(),
|
|
856
|
+
metricsId: z.string().optional(),
|
|
857
|
+
id: z.string().optional(),
|
|
858
|
+
extensions: z.record(z.string(), z.unknown()).optional(),
|
|
859
|
+
edApp: z.union([z.string(), z.record(z.string(), z.unknown())]).optional(),
|
|
860
|
+
session: z.union([z.string(), z.record(z.string(), z.unknown())]).optional(),
|
|
861
|
+
})
|
|
862
|
+
.strict()
|
|
863
|
+
type TimeSpentInput = input<typeof TimeSpentInput>
|
|
864
|
+
|
|
865
|
+
declare const CaliperListEventsParams = z
|
|
866
|
+
.object({
|
|
867
|
+
limit: z.number().int().positive().optional(),
|
|
868
|
+
offset: z.number().int().min(0).optional(),
|
|
869
|
+
sensor: z.string().min(1).optional(),
|
|
870
|
+
startDate: IsoDateTimeString.optional(),
|
|
871
|
+
endDate: IsoDateTimeString.optional(),
|
|
872
|
+
actorId: z.string().min(1).optional(),
|
|
873
|
+
actorEmail: z.email().optional(),
|
|
874
|
+
})
|
|
875
|
+
.strict()
|
|
876
|
+
type CaliperListEventsParams = input<typeof CaliperListEventsParams>
|
|
877
|
+
|
|
878
|
+
export { ActivityCompletedInput, CALIPER_DATA_VERSION, CaliperListEventsParams as ListEventsParams, TimeSpentInput };
|
|
879
|
+
export type { ActivityCompletedEvent, ActivityMetricType, ApiResponse, CaliperActor, CaliperEntity, CaliperEnvelope, CaliperEvent, CaliperProfile, EventResult, GetEventResponse, JobStatus, JobStatusResponse, ListEventsResponse, ListEventsResult, PaginationMeta, SendEventsResponse, SendEventsResult, StoredEvent, TimeSpentEvent, TimeSpentMetric, TimeSpentMetricType, TimebackActivity, TimebackActivityContext, TimebackActivityMetric, TimebackActivityMetricsCollection, TimebackApp, TimebackCourse, TimebackEvent, TimebackEventBase, TimebackSubject, TimebackTimeSpentMetricsCollection, TimebackUser, TimebackUserRole, ValidationResult, WaitForCompletionOptions };
|