@timeback/caliper 0.1.7-beta.20260309185602 → 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -121,12 +121,14 @@ var LEARNWITHAI_QTI_URLS = {
121
121
  var PLATFORM_ENDPOINTS = {
122
122
  BEYOND_AI: {
123
123
  token: BEYONDAI_TOKEN_URLS,
124
+ tokenScope: undefined,
124
125
  api: BEYONDAI_API_URLS,
125
126
  caliper: BEYONDAI_CALIPER_URLS,
126
127
  qti: BEYONDAI_QTI_URLS
127
128
  },
128
129
  LEARNWITH_AI: {
129
130
  token: LEARNWITHAI_TOKEN_URLS,
131
+ tokenScope: "https://purl.imsglobal.org/spec/caliper/v1p2/scope/events.write",
130
132
  api: LEARNWITHAI_API_URLS,
131
133
  caliper: LEARNWITHAI_CALIPER_URLS,
132
134
  qti: LEARNWITHAI_QTI_URLS
@@ -510,7 +512,7 @@ class TokenManager {
510
512
  Authorization: `Basic ${credentials}`,
511
513
  "Content-Type": "application/x-www-form-urlencoded"
512
514
  },
513
- body: "grant_type=client_credentials"
515
+ body: this.config.scope ? `grant_type=client_credentials&scope=${encodeURIComponent(this.config.scope)}` : "grant_type=client_credentials"
514
516
  });
515
517
  const duration = Math.round(performance.now() - start);
516
518
  if (!response.ok) {
@@ -574,7 +576,7 @@ var BEYONDAI_PATHS = {
574
576
  };
575
577
  var LEARNWITHAI_PATHS = {
576
578
  caliper: {
577
- send: "/events/1.0/",
579
+ send: "/caliper/v1p2",
578
580
  validate: null,
579
581
  list: null,
580
582
  get: null,
@@ -589,7 +591,9 @@ var LEARNWITHAI_PATHS = {
589
591
  edubridge: null,
590
592
  powerpath: null,
591
593
  clr: null,
592
- case: null
594
+ case: {
595
+ base: "/case/1.1"
596
+ }
593
597
  };
594
598
  var PLATFORM_PATHS = {
595
599
  BEYOND_AI: BEYONDAI_PATHS,
@@ -626,6 +630,7 @@ class TimebackProvider {
626
630
  timeout;
627
631
  endpoints;
628
632
  authUrl;
633
+ tokenScope;
629
634
  pathProfiles;
630
635
  tokenManagers = new Map;
631
636
  constructor(config) {
@@ -641,6 +646,7 @@ class TimebackProvider {
641
646
  throw new Error(`Unknown platform: ${platform}`);
642
647
  }
643
648
  this.authUrl = platformEndpoints.token[env];
649
+ this.tokenScope = platformEndpoints.tokenScope ?? undefined;
644
650
  this.pathProfiles = PLATFORM_PATHS[platform] ?? BEYONDAI_PATHS;
645
651
  this.endpoints = {
646
652
  oneroster: {
@@ -766,7 +772,8 @@ class TimebackProvider {
766
772
  credentials: {
767
773
  clientId: this.auth.clientId,
768
774
  clientSecret: this.auth.clientSecret
769
- }
775
+ },
776
+ scope: this.tokenScope
770
777
  });
771
778
  this.tokenManagers.set(authUrl, manager);
772
779
  }
@@ -784,7 +791,8 @@ class TimebackProvider {
784
791
  credentials: {
785
792
  clientId: this.auth.clientId,
786
793
  clientSecret: this.auth.clientSecret
787
- }
794
+ },
795
+ scope: this.tokenScope
788
796
  });
789
797
  this.tokenManagers.set(this.authUrl, manager);
790
798
  }
@@ -1515,7 +1523,7 @@ function issue(path, message) {
1515
1523
  function validateWithSchema(schema, data, context) {
1516
1524
  const result = schema.safeParse(data);
1517
1525
  if (result.success) {
1518
- return;
1526
+ return result.data;
1519
1527
  }
1520
1528
  const issues = result.error.issues.map((errorIssue) => ({
1521
1529
  path: errorIssue.path.join(".") || "(root)",
@@ -6,5 +6,6 @@ var CALIPER_ENV_VARS = {
6
6
  clientSecret: ["TIMEBACK_API_CLIENT_SECRET", "TIMEBACK_CLIENT_SECRET", "CALIPER_CLIENT_SECRET"]
7
7
  };
8
8
  var CALIPER_DATA_VERSION = "http://purl.imsglobal.org/ctx/caliper/v1p2";
9
+ var QUESTION_RESULT_SCORE_TYPE = "QUESTION_RESULT";
9
10
 
10
- export { CALIPER_ENV_VARS, CALIPER_DATA_VERSION };
11
+ export { CALIPER_ENV_VARS, CALIPER_DATA_VERSION, QUESTION_RESULT_SCORE_TYPE };
@@ -21,4 +21,8 @@ export declare const CALIPER_ENV_VARS: {
21
21
  * Caliper JSON-LD context version.
22
22
  */
23
23
  export declare const CALIPER_DATA_VERSION = "http://purl.imsglobal.org/ctx/caliper/v1p2";
24
+ /**
25
+ * Score type for individual question results (LWAI GradeEvent).
26
+ */
27
+ export declare const QUESTION_RESULT_SCORE_TYPE: "QUESTION_RESULT";
24
28
  //# sourceMappingURL=constants.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"constants.d.ts","sourceRoot":"","sources":["../src/constants.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH;;;;;;;GAOG;AACH,eAAO,MAAM,gBAAgB;;;;;CAKnB,CAAA;AAEV;;GAEG;AACH,eAAO,MAAM,oBAAoB,+CAA+C,CAAA"}
1
+ {"version":3,"file":"constants.d.ts","sourceRoot":"","sources":["../src/constants.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH;;;;;;;GAOG;AACH,eAAO,MAAM,gBAAgB;;;;;CAKnB,CAAA;AAEV;;GAEG;AACH,eAAO,MAAM,oBAAoB,+CAA+C,CAAA;AAEhF;;GAEG;AACH,eAAO,MAAM,0BAA0B,mBAA6B,CAAA"}
package/dist/errors.js CHANGED
@@ -5,7 +5,7 @@ import {
5
5
  NotFoundError,
6
6
  UnauthorizedError,
7
7
  ValidationError
8
- } from "./chunk-xkrn9zda.js";
8
+ } from "./chunk-m7qcd4j8.js";
9
9
  import"./chunk-6jf1natv.js";
10
10
  export {
11
11
  ValidationError,
@@ -1 +1 @@
1
- {"version":3,"file":"factory.d.ts","sourceRoot":"","sources":["../src/factory.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AASH,OAAO,EAAE,cAAc,EAAE,YAAY,EAAE,MAAM,aAAa,CAAA;AAG1D,OAAO,KAAK,EAAE,eAAe,EAAE,gBAAgB,EAAE,gBAAgB,EAAE,MAAM,iCAAiC,CAAA;AAC1G,OAAO,KAAK,EAAE,mBAAmB,EAAE,oBAAoB,EAAoB,MAAM,SAAS,CAAA;AAE1F;;;;;GAKG;AACH,wBAAgB,mBAAmB,CAAC,QAAQ,GAAE,gBAA4C;;QAQxF,gBAAgB;;QAGhB,gBAAgB;;QAGhB,iFAAiF;;QAEjF,qFAAqF;;QA+CrF;;;WAGG;;QAKH;;;;WAIG;;;EASJ"}
1
+ {"version":3,"file":"factory.d.ts","sourceRoot":"","sources":["../src/factory.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAOH,OAAO,EAAE,cAAc,EAAE,YAAY,EAAE,MAAM,aAAa,CAAA;AAG1D,OAAO,KAAK,EACX,eAAe,EACf,gBAAgB,EAChB,gBAAgB,EAChB,MAAM,iCAAiC,CAAA;AACxC,OAAO,KAAK,EAAE,mBAAmB,EAAE,oBAAoB,EAAoB,MAAM,SAAS,CAAA;AAE1F;;;;;GAKG;AACH,wBAAgB,mBAAmB,CAAC,QAAQ,GAAE,gBAA4C;;QAQxF,gBAAgB;;QAGhB,gBAAgB;;QAGhB,iFAAiF;;QAEjF,qFAAqF;;QA+CrF;;;WAGG;;QAKH;;;;WAIG;;;EASJ"}
package/dist/index.d.ts CHANGED
@@ -1,5 +1,5 @@
1
1
  import * as _timeback_internal_client_infra from '@timeback/internal-client-infra';
2
- import { ClientConfig, TransportOnlyConfig, CaliperPaths, RequestOptions, PaginatedResponse, ProviderClientConfig, BaseTransportConfig, Paginator as Paginator$1, ListParams, ProviderRegistry, TimebackProvider, AuthCheckResult, BaseTransport } from '@timeback/internal-client-infra';
2
+ import { ClientConfig, TransportOnlyConfig, CaliperPaths, RequestOptions, PaginatedResponse, ProviderClientConfig, BaseTransportConfig, BaseTransport, Paginator as Paginator$1, ListParams, ProviderRegistry, TimebackProvider, AuthCheckResult } from '@timeback/internal-client-infra';
3
3
  export { AuthCheckResult, EnvAuth, Environment, ExplicitAuth } from '@timeback/internal-client-infra';
4
4
 
5
5
  /**
@@ -469,23 +469,28 @@ type CaliperProfile =
469
469
  | 'TimebackProfile'
470
470
 
471
471
  /**
472
- * Base Caliper entity - can be a URI string or an object with properties.
472
+ * Base Caliper entity representation.
473
+ *
474
+ * Many Caliper fields can be provided either as an IRI string or as an
475
+ * object-shaped entity, so the shared protocol model keeps this flexible.
473
476
  */
474
477
  type CaliperEntity = string | { [key: string]: unknown }
475
478
 
476
479
  /**
477
- * Caliper actor entity (for sending events).
480
+ * One actor-object shape for sending events.
478
481
  *
479
- * Timeback API requires actors to have extensions.email.
482
+ * This is a structured actor object with an `id`, a `type`, and an
483
+ * `extensions` bag containing `email`. It is one valid actor-object shape,
484
+ * not the only representation allowed by `CaliperEvent.actor`.
480
485
  */
481
486
  interface CaliperActor {
482
487
  /** Unique identifier (IRI format) */
483
488
  id: string
484
489
  /** Entity type (e.g., 'Person', 'TimebackUser') */
485
490
  type: string
486
- /** Extensions - email is required by Timeback API */
491
+ /** Extensions carried on this actor-object shape */
487
492
  extensions: {
488
- /** Actor's email address (required by Timeback) */
493
+ /** Actor email on this actor-object shape */
489
494
  email: string
490
495
  /** Additional extension properties */
491
496
  [key: string]: unknown
@@ -504,8 +509,8 @@ interface CaliperEvent {
504
509
  id: string
505
510
  /** Event type */
506
511
  type: string
507
- /** The agent who initiated the event (string URL, CaliperActor, or TimebackUser) */
508
- actor: string | CaliperActor | TimebackUser
512
+ /** The agent who initiated the event (IRI string, CaliperActor, TimebackUser, or generic entity) */
513
+ actor: CaliperEntity | CaliperActor | TimebackUser
509
514
  /** The action or predicate */
510
515
  action: string
511
516
  /** The object of the interaction */
@@ -556,8 +561,8 @@ interface CaliperEnvelope {
556
561
  * Result of sending events.
557
562
  */
558
563
  interface SendEventsResult {
559
- /** Job ID for tracking async processing */
560
- jobId: string
564
+ /** Job ID for tracking async processing (undefined when the platform does not return one) */
565
+ jobId: string | undefined
561
566
  }
562
567
 
563
568
  /**
@@ -655,6 +660,34 @@ interface ListEventsResult {
655
660
  pagination: PaginationMeta
656
661
  }
657
662
 
663
+ // ═══════════════════════════════════════════════════════════════════════════════
664
+ // QUESTION EVENT TYPES (Standard Caliper)
665
+ // ═══════════════════════════════════════════════════════════════════════════════
666
+
667
+ /**
668
+ * AssessmentItemEvent (Question Seen / Question Answered).
669
+ *
670
+ * Represents when a student is presented with a question (Started)
671
+ * or submits an answer (Completed).
672
+ */
673
+ interface AssessmentItemEvent extends CaliperEvent {
674
+ type: 'AssessmentItemEvent'
675
+ action: 'Started' | 'Completed'
676
+ profile: 'AssessmentProfile'
677
+ }
678
+
679
+ /**
680
+ * GradeEvent for question-level grading.
681
+ *
682
+ * Represents when a question response is graded, with a Score entity
683
+ * containing `scoreType: "QUESTION_RESULT"` in the `generated` field.
684
+ */
685
+ interface QuestionGradeEvent extends CaliperEvent {
686
+ type: 'GradeEvent'
687
+ action: 'Graded'
688
+ profile: 'GradingProfile'
689
+ }
690
+
658
691
  /**
659
692
  * API Response Types
660
693
  *
@@ -859,19 +892,113 @@ declare const TimeSpentInput = z
859
892
  .strict()
860
893
  type TimeSpentInput = input<typeof TimeSpentInput>
861
894
 
895
+ declare const QuestionSeenInput = z
896
+ .object({
897
+ /** Actor (Person IRI or entity object with id, type, name, etc.) */
898
+ actor: z.union([z.string(), CaliperActor, TimebackUser]),
899
+ /** AssessmentItem being presented */
900
+ object: AssessmentItemObject,
901
+ /** Application identifier (IRI or entity) */
902
+ edApp: CaliperEntity,
903
+ /** Event identifier (auto-generated if omitted) */
904
+ id: z.string().optional(),
905
+ /** ISO 8601 datetime (defaults to now) */
906
+ eventTime: IsoDateTimeString.optional(),
907
+ /** Session context (IRI or entity) */
908
+ session: CaliperEntity.optional(),
909
+ /** Event-level extensions */
910
+ extensions: z.record(z.string(), z.unknown()).optional(),
911
+ })
912
+ .strict()
913
+ type QuestionSeenInput = input<typeof QuestionSeenInput>
914
+
915
+ declare const QuestionAnsweredInput = z
916
+ .object({
917
+ /** Actor (Person IRI or entity object with id, type, name, etc.) */
918
+ actor: z.union([z.string(), CaliperActor, TimebackUser]),
919
+ /** AssessmentItem being answered */
920
+ object: AssessmentItemObject,
921
+ /** Application identifier (IRI or entity) */
922
+ edApp: CaliperEntity,
923
+ /** Response entity with optional attempt and timing */
924
+ generated: ResponseGenerated.optional(),
925
+ /** Event identifier (auto-generated if omitted) */
926
+ id: z.string().optional(),
927
+ /** ISO 8601 datetime (defaults to now) */
928
+ eventTime: IsoDateTimeString.optional(),
929
+ /** Session context (IRI or entity) */
930
+ session: CaliperEntity.optional(),
931
+ /** Event-level extensions */
932
+ extensions: z.record(z.string(), z.unknown()).optional(),
933
+ })
934
+ .strict()
935
+ type QuestionAnsweredInput = input<typeof QuestionAnsweredInput>
936
+
937
+ declare const QuestionGradedInput = z
938
+ .object({
939
+ /** Actor (Person IRI or entity object with id, type, name, etc.) */
940
+ actor: z.union([z.string(), CaliperActor, TimebackUser]),
941
+ /** Attempt being graded (IRI) */
942
+ object: z.string(),
943
+ /** Score awarded for the question */
944
+ generated: ScoreGenerated,
945
+ /** Application identifier (IRI or entity) */
946
+ edApp: CaliperEntity,
947
+ /** Event identifier (auto-generated if omitted) */
948
+ id: z.string().optional(),
949
+ /** ISO 8601 datetime (defaults to now) */
950
+ eventTime: IsoDateTimeString.optional(),
951
+ /** Session context (IRI or entity) */
952
+ session: CaliperEntity.optional(),
953
+ /** Event-level extensions */
954
+ extensions: z.record(z.string(), z.unknown()).optional(),
955
+ })
956
+ .strict()
957
+ type QuestionGradedInput = input<typeof QuestionGradedInput>
958
+
862
959
  declare const CaliperListEventsParams = z
863
960
  .object({
864
961
  limit: z.number().int().positive().optional(),
865
962
  offset: z.number().int().min(0).optional(),
866
- sensor: z.string().min(1).optional(),
963
+ sensor: NonEmptyString.optional(),
867
964
  startDate: IsoDateTimeString.optional(),
868
965
  endDate: IsoDateTimeString.optional(),
869
- actorId: z.string().min(1).optional(),
966
+ actorId: NonEmptyString.optional(),
870
967
  actorEmail: z.email().optional(),
871
968
  })
872
969
  .strict()
873
970
  type CaliperListEventsParams = input<typeof CaliperListEventsParams>
874
971
 
972
+ /**
973
+ * Transport Layer
974
+ *
975
+ * HTTP transport for Caliper API communication.
976
+ */
977
+
978
+ /**
979
+ * HTTP transport layer for Caliper API communication.
980
+ *
981
+ * Extends BaseTransport with Caliper-specific path configuration.
982
+ * Uses body-based pagination (events array + pagination metadata).
983
+ */
984
+ declare class Transport extends BaseTransport {
985
+ /** API path profiles for Caliper operations */
986
+ readonly paths: CaliperPaths;
987
+ constructor(config: CaliperTransportConfig);
988
+ /**
989
+ * Make a paginated request using body-based pagination.
990
+ *
991
+ * Caliper APIs return pagination metadata in the response body:
992
+ * - `events`: Array of items
993
+ * - `pagination`: { total, totalPages, currentPage, limit }
994
+ *
995
+ * @param path - API endpoint path
996
+ * @param options - Request options
997
+ * @returns Normalized paginated response with hasMore and total
998
+ */
999
+ requestPaginated<T>(path: string, options?: RequestOptions): Promise<PaginatedResponse<T>>;
1000
+ }
1001
+
875
1002
  /**
876
1003
  * Pagination Utilities
877
1004
  *
@@ -896,6 +1023,139 @@ declare class Paginator<T> extends Paginator$1<T> {
896
1023
  constructor(transport: CaliperTransportLike, path: string, params?: ListParams);
897
1024
  }
898
1025
 
1026
+ /**
1027
+ * Event Factory Functions
1028
+ *
1029
+ * Pure factory functions for creating Caliper events.
1030
+ * Use these when you want to batch multiple events into a single envelope.
1031
+ */
1032
+
1033
+ /**
1034
+ * Create an ActivityEvent from input.
1035
+ *
1036
+ * Pure factory function - creates the event object without sending.
1037
+ * Use this when you want to batch multiple events into a single envelope.
1038
+ *
1039
+ * @param input - Activity completion data
1040
+ * @returns A fully-formed ActivityCompletedEvent ready to send
1041
+ *
1042
+ * @example
1043
+ * ```typescript
1044
+ * import { createActivityEvent, createTimeSpentEvent } from '@timeback/caliper'
1045
+ *
1046
+ * const activityEvent = createActivityEvent({
1047
+ * actor: { id: '...', type: 'TimebackUser', email: 'student@example.edu' },
1048
+ * object: { id: '...', type: 'TimebackActivityContext', subject: 'Math', app: { name: 'My App' } },
1049
+ * metrics: [
1050
+ * { type: 'totalQuestions', value: 10 },
1051
+ * { type: 'correctQuestions', value: 8 },
1052
+ * ],
1053
+ * })
1054
+ *
1055
+ * const timeSpentEvent = createTimeSpentEvent({
1056
+ * actor: { id: '...', type: 'TimebackUser', email: 'student@example.edu' },
1057
+ * object: { id: '...', type: 'TimebackActivityContext', subject: 'Math', app: { name: 'My App' } },
1058
+ * metrics: [{ type: 'active', value: 1800 }],
1059
+ * })
1060
+ *
1061
+ * // Send both in one envelope
1062
+ * await client.events.send(sensor, [activityEvent, timeSpentEvent])
1063
+ * ```
1064
+ */
1065
+ declare function createActivityEvent(input: ActivityCompletedInput): ActivityCompletedEvent;
1066
+ /**
1067
+ * Create a TimeSpentEvent from input.
1068
+ *
1069
+ * Pure factory function - creates the event object without sending.
1070
+ * Use this when you want to batch multiple events into a single envelope.
1071
+ *
1072
+ * @param input - Time spent data
1073
+ * @returns A fully-formed TimeSpentEvent ready to send
1074
+ *
1075
+ * @example
1076
+ * ```typescript
1077
+ * import { createTimeSpentEvent } from '@timeback/caliper'
1078
+ *
1079
+ * const event = createTimeSpentEvent({
1080
+ * actor: { id: '...', type: 'TimebackUser', email: 'student@example.edu' },
1081
+ * object: { id: '...', type: 'TimebackActivityContext', subject: 'Reading', app: { name: 'My App' } },
1082
+ * metrics: [
1083
+ * { type: 'active', value: 1800 },
1084
+ * { type: 'inactive', value: 300 },
1085
+ * ],
1086
+ * })
1087
+ *
1088
+ * await client.events.send(sensor, [event])
1089
+ * ```
1090
+ */
1091
+ declare function createTimeSpentEvent(input: TimeSpentInput): TimeSpentEvent;
1092
+ /**
1093
+ * Create a Question Seen event (AssessmentItemEvent.Started).
1094
+ *
1095
+ * Fired when a question is presented to the student.
1096
+ *
1097
+ * @param input - Minimal question seen data
1098
+ * @returns A fully-formed AssessmentItemEvent ready to send
1099
+ *
1100
+ * @example
1101
+ * ```typescript
1102
+ * const event = createQuestionSeenEvent({
1103
+ * actor: 'urn:uuid:student-123',
1104
+ * object: { id: 'urn:uuid:q-456', name: 'What is 2+2?' },
1105
+ * edApp: 'https://myapp.example.com',
1106
+ * })
1107
+ *
1108
+ * await client.events.send(sensor, [event])
1109
+ * ```
1110
+ */
1111
+ declare function createQuestionSeenEvent(input: QuestionSeenInput): AssessmentItemEvent;
1112
+ /**
1113
+ * Create a Question Answered event (AssessmentItemEvent.Completed).
1114
+ *
1115
+ * Fired when a student submits an answer to a question.
1116
+ *
1117
+ * @param input - Minimal question answered data
1118
+ * @returns A fully-formed AssessmentItemEvent ready to send
1119
+ *
1120
+ * @example
1121
+ * ```typescript
1122
+ * const event = createQuestionAnsweredEvent({
1123
+ * actor: 'urn:uuid:student-123',
1124
+ * object: { id: 'urn:uuid:q-456', name: 'What is 2+2?' },
1125
+ * edApp: 'https://myapp.example.com',
1126
+ * generated: {
1127
+ * id: 'urn:uuid:response-789',
1128
+ * attempt: 'urn:uuid:attempt-101',
1129
+ * },
1130
+ * })
1131
+ *
1132
+ * await client.events.send(sensor, [event])
1133
+ * ```
1134
+ */
1135
+ declare function createQuestionAnsweredEvent(input: QuestionAnsweredInput): AssessmentItemEvent;
1136
+ /**
1137
+ * Create a Question Graded event (GradeEvent.Graded).
1138
+ *
1139
+ * Fired when a question response is scored. The Score entity is auto-filled
1140
+ * with `type: "Score"` and `scoreType: "QUESTION_RESULT"`.
1141
+ *
1142
+ * @param input - Minimal question graded data
1143
+ * @returns A fully-formed QuestionGradeEvent ready to send
1144
+ *
1145
+ * @example
1146
+ * ```typescript
1147
+ * const event = createQuestionGradedEvent({
1148
+ * actor: 'urn:uuid:student-123',
1149
+ * object: 'urn:uuid:attempt-101',
1150
+ * generated: { scoreGiven: 1, maxScore: 1, attempt: 'urn:uuid:attempt-101' },
1151
+ * edApp: 'https://myapp.example.com',
1152
+ * })
1153
+ *
1154
+ * await client.events.send(sensor, [event])
1155
+ * ```
1156
+ */
1157
+ declare function createQuestionGradedEvent(input: QuestionGradedInput): QuestionGradeEvent;
1158
+
899
1159
  /**
900
1160
  * Events Resource
901
1161
  *
@@ -1140,6 +1400,78 @@ declare class EventsResource {
1140
1400
  * ```
1141
1401
  */
1142
1402
  sendTimeSpent(sensor: string, input: TimeSpentInput): Promise<SendEventsResult>;
1403
+ /**
1404
+ * Send a "question seen" event (AssessmentItemEvent.Started).
1405
+ *
1406
+ * Records when a question is presented to a student.
1407
+ *
1408
+ * @param sensor - Sensor identifier (IRI format)
1409
+ * @param input - Question seen data
1410
+ * @returns Job ID for tracking processing status
1411
+ *
1412
+ * @example
1413
+ * ```typescript
1414
+ * await client.events.sendQuestionSeen(
1415
+ * 'https://myapp.example.com/sensors/main',
1416
+ * {
1417
+ * actor: 'urn:uuid:student-123',
1418
+ * object: { id: 'urn:uuid:q-456', name: 'What is 2+2?' },
1419
+ * edApp: 'https://myapp.example.com',
1420
+ * },
1421
+ * )
1422
+ * ```
1423
+ */
1424
+ sendQuestionSeen(sensor: string, input: QuestionSeenInput): Promise<SendEventsResult>;
1425
+ /**
1426
+ * Send a "question answered" event (AssessmentItemEvent.Completed).
1427
+ *
1428
+ * Records when a student submits an answer to a question.
1429
+ *
1430
+ * @param sensor - Sensor identifier (IRI format)
1431
+ * @param input - Question answered data
1432
+ * @returns Job ID for tracking processing status
1433
+ *
1434
+ * @example
1435
+ * ```typescript
1436
+ * await client.events.sendQuestionAnswered(
1437
+ * 'https://myapp.example.com/sensors/main',
1438
+ * {
1439
+ * actor: 'urn:uuid:student-123',
1440
+ * object: { id: 'urn:uuid:q-456', name: 'What is 2+2?' },
1441
+ * edApp: 'https://myapp.example.com',
1442
+ * generated: {
1443
+ * id: 'urn:uuid:response-789',
1444
+ * attempt: 'urn:uuid:attempt-101',
1445
+ * },
1446
+ * },
1447
+ * )
1448
+ * ```
1449
+ */
1450
+ sendQuestionAnswered(sensor: string, input: QuestionAnsweredInput): Promise<SendEventsResult>;
1451
+ /**
1452
+ * Send a "question graded" event (GradeEvent.Graded).
1453
+ *
1454
+ * Records when a question response is scored. The Score entity is
1455
+ * auto-filled with `scoreType: "QUESTION_RESULT"`.
1456
+ *
1457
+ * @param sensor - Sensor identifier (IRI format)
1458
+ * @param input - Question graded data
1459
+ * @returns Job ID for tracking processing status
1460
+ *
1461
+ * @example
1462
+ * ```typescript
1463
+ * await client.events.sendQuestionGraded(
1464
+ * 'https://myapp.example.com/sensors/main',
1465
+ * {
1466
+ * actor: 'urn:uuid:student-123',
1467
+ * object: 'urn:uuid:attempt-101',
1468
+ * generated: { scoreGiven: 1, maxScore: 1, attempt: 'urn:uuid:attempt-101' },
1469
+ * edApp: 'https://myapp.example.com',
1470
+ * },
1471
+ * )
1472
+ * ```
1473
+ */
1474
+ sendQuestionGraded(sensor: string, input: QuestionGradedInput): Promise<SendEventsResult>;
1143
1475
  }
1144
1476
 
1145
1477
  /**
@@ -1316,107 +1648,14 @@ declare function createCaliperClient(registry?: ProviderRegistry): {
1316
1648
  };
1317
1649
  };
1318
1650
 
1319
- /**
1320
- * Event Factory Functions
1321
- *
1322
- * Pure factory functions for creating Timeback profile events.
1323
- * Use these when you want to batch multiple events into a single envelope.
1324
- */
1325
-
1326
- /**
1327
- * Create an ActivityEvent from input.
1328
- *
1329
- * Pure factory function - creates the event object without sending.
1330
- * Use this when you want to batch multiple events into a single envelope.
1331
- *
1332
- * @param input - Activity completion data
1333
- * @returns A fully-formed ActivityCompletedEvent ready to send
1334
- *
1335
- * @example
1336
- * ```typescript
1337
- * import { createActivityEvent, createTimeSpentEvent } from '@timeback/caliper'
1338
- *
1339
- * const activityEvent = createActivityEvent({
1340
- * actor: { id: '...', type: 'TimebackUser', email: 'student@example.edu' },
1341
- * object: { id: '...', type: 'TimebackActivityContext', subject: 'Math', app: { name: 'My App' } },
1342
- * metrics: [
1343
- * { type: 'totalQuestions', value: 10 },
1344
- * { type: 'correctQuestions', value: 8 },
1345
- * ],
1346
- * })
1347
- *
1348
- * const timeSpentEvent = createTimeSpentEvent({
1349
- * actor: { id: '...', type: 'TimebackUser', email: 'student@example.edu' },
1350
- * object: { id: '...', type: 'TimebackActivityContext', subject: 'Math', app: { name: 'My App' } },
1351
- * metrics: [{ type: 'active', value: 1800 }],
1352
- * })
1353
- *
1354
- * // Send both in one envelope
1355
- * await client.events.send(sensor, [activityEvent, timeSpentEvent])
1356
- * ```
1357
- */
1358
- declare function createActivityEvent(input: ActivityCompletedInput): ActivityCompletedEvent;
1359
- /**
1360
- * Create a TimeSpentEvent from input.
1361
- *
1362
- * Pure factory function - creates the event object without sending.
1363
- * Use this when you want to batch multiple events into a single envelope.
1364
- *
1365
- * @param input - Time spent data
1366
- * @returns A fully-formed TimeSpentEvent ready to send
1367
- *
1368
- * @example
1369
- * ```typescript
1370
- * import { createTimeSpentEvent } from '@timeback/caliper'
1371
- *
1372
- * const event = createTimeSpentEvent({
1373
- * actor: { id: '...', type: 'TimebackUser', email: 'student@example.edu' },
1374
- * object: { id: '...', type: 'TimebackActivityContext', subject: 'Reading', app: { name: 'My App' } },
1375
- * metrics: [
1376
- * { type: 'active', value: 1800 },
1377
- * { type: 'inactive', value: 300 },
1378
- * ],
1379
- * })
1380
- *
1381
- * await client.events.send(sensor, [event])
1382
- * ```
1383
- */
1384
- declare function createTimeSpentEvent(input: TimeSpentInput): TimeSpentEvent;
1385
-
1386
1651
  /**
1387
1652
  * Caliper JSON-LD context version.
1388
1653
  */
1389
1654
  declare const CALIPER_DATA_VERSION = "http://purl.imsglobal.org/ctx/caliper/v1p2";
1390
-
1391
1655
  /**
1392
- * Transport Layer
1393
- *
1394
- * HTTP transport for Caliper API communication.
1395
- */
1396
-
1397
- /**
1398
- * HTTP transport layer for Caliper API communication.
1399
- *
1400
- * Extends BaseTransport with Caliper-specific path configuration.
1401
- * Uses body-based pagination (events array + pagination metadata).
1656
+ * Score type for individual question results (LWAI GradeEvent).
1402
1657
  */
1403
- declare class Transport extends BaseTransport {
1404
- /** API path profiles for Caliper operations */
1405
- readonly paths: CaliperPaths;
1406
- constructor(config: CaliperTransportConfig);
1407
- /**
1408
- * Make a paginated request using body-based pagination.
1409
- *
1410
- * Caliper APIs return pagination metadata in the response body:
1411
- * - `events`: Array of items
1412
- * - `pagination`: { total, totalPages, currentPage, limit }
1413
- *
1414
- * @param path - API endpoint path
1415
- * @param options - Request options
1416
- * @returns Normalized paginated response with hasMore and total
1417
- */
1418
- requestPaginated<T>(path: string, options?: RequestOptions): Promise<PaginatedResponse<T>>;
1419
- }
1658
+ declare const QUESTION_RESULT_SCORE_TYPE: "QUESTION_RESULT";
1420
1659
 
1421
- export { ActivityCompletedInput, CALIPER_DATA_VERSION, CaliperClient, CaliperListEventsParams as ListEventsParams, TimeSpentInput, Transport, createActivityEvent, createCaliperClient, createTimeSpentEvent };
1422
- export type { ActivityCompletedEvent, ActivityMetricType, CaliperClientConfig, CaliperClientInstance, CaliperEnvelope, CaliperEvent, CaliperProfile, JobStatus, SendEventsResult, StoredEvent, TimeSpentEvent, TimeSpentMetric, TimeSpentMetricType, TimebackActivity, TimebackActivityContext, TimebackActivityMetric, TimebackActivityMetricsCollection, TimebackApp, TimebackCourse, TimebackEvent, TimebackSubject, TimebackTimeSpentMetricsCollection, TimebackUser, TimebackUserRole, ValidationResult };
1660
+ export { ActivityCompletedInput, CALIPER_DATA_VERSION, CaliperClient, CaliperListEventsParams as ListEventsParams, QUESTION_RESULT_SCORE_TYPE, QuestionAnsweredInput, QuestionGradedInput, QuestionSeenInput, TimeSpentInput, Transport, createActivityEvent, createCaliperClient, createQuestionAnsweredEvent, createQuestionGradedEvent, createQuestionSeenEvent, createTimeSpentEvent };
1661
+ export type { ActivityCompletedEvent, ActivityMetricType, AssessmentItemEvent, CaliperClientConfig, CaliperClientInstance, CaliperEnvelope, CaliperEvent, CaliperProfile, JobStatus, QuestionGradeEvent, SendEventsResult, StoredEvent, TimeSpentEvent, TimeSpentMetric, TimeSpentMetricType, TimebackActivity, TimebackActivityContext, TimebackActivityMetric, TimebackActivityMetricsCollection, TimebackApp, TimebackCourse, TimebackEvent, TimebackSubject, TimebackTimeSpentMetricsCollection, TimebackUser, TimebackUserRole, ValidationResult };
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAmEG;AAMH,OAAO,EAAE,aAAa,EAAE,MAAM,UAAU,CAAA;AACxC,OAAO,EAAE,mBAAmB,EAAE,MAAM,WAAW,CAAA;AAE/C,YAAY,EAAE,qBAAqB,EAAE,MAAM,UAAU,CAAA;AACrD,YAAY,EAAE,mBAAmB,EAAE,WAAW,EAAE,OAAO,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAA;AAC7F,YAAY,EAAE,eAAe,EAAE,MAAM,iCAAiC,CAAA;AAMtE,OAAO,EAAE,mBAAmB,EAAE,oBAAoB,EAAE,MAAM,uBAAuB,CAAA;AAEjF,YAAY,EACX,YAAY,EACZ,gBAAgB,EAChB,uBAAuB,EACvB,eAAe,EACf,WAAW,EACX,cAAc,EACd,gBAAgB,EAChB,sBAAsB,EACtB,iCAAiC,EACjC,kBAAkB,EAClB,eAAe,EACf,kCAAkC,EAClC,mBAAmB,EACnB,sBAAsB,EACtB,cAAc,EACd,aAAa,GACb,MAAM,mCAAmC,CAAA;AAE1C,YAAY,EACX,sBAAsB,EACtB,cAAc,EACd,uBAAuB,IAAI,gBAAgB,GAC3C,MAAM,qBAAqB,CAAA;AAE5B,OAAO,EAAE,oBAAoB,EAAE,MAAM,aAAa,CAAA;AAElD,YAAY,EACX,eAAe,EACf,YAAY,EACZ,cAAc,EACd,SAAS,EACT,gBAAgB,EAChB,WAAW,EACX,gBAAgB,GAChB,MAAM,mCAAmC,CAAA;AAM1C,OAAO,EAAE,SAAS,EAAE,MAAM,OAAO,CAAA"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAmEG;AAMH,OAAO,EAAE,aAAa,EAAE,MAAM,UAAU,CAAA;AACxC,OAAO,EAAE,mBAAmB,EAAE,MAAM,WAAW,CAAA;AAE/C,YAAY,EAAE,qBAAqB,EAAE,MAAM,UAAU,CAAA;AACrD,YAAY,EAAE,mBAAmB,EAAE,WAAW,EAAE,OAAO,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAA;AAC7F,YAAY,EAAE,eAAe,EAAE,MAAM,iCAAiC,CAAA;AAMtE,OAAO,EACN,mBAAmB,EACnB,2BAA2B,EAC3B,yBAAyB,EACzB,uBAAuB,EACvB,oBAAoB,GACpB,MAAM,OAAO,CAAA;AAEd,YAAY,EACX,YAAY,EACZ,gBAAgB,EAChB,uBAAuB,EACvB,eAAe,EACf,WAAW,EACX,cAAc,EACd,gBAAgB,EAChB,sBAAsB,EACtB,iCAAiC,EACjC,kBAAkB,EAClB,eAAe,EACf,kCAAkC,EAClC,mBAAmB,EACnB,sBAAsB,EACtB,cAAc,EACd,aAAa,GACb,MAAM,mCAAmC,CAAA;AAE1C,YAAY,EACX,sBAAsB,EACtB,qBAAqB,EACrB,mBAAmB,EACnB,iBAAiB,EACjB,cAAc,EACd,uBAAuB,IAAI,gBAAgB,GAC3C,MAAM,qBAAqB,CAAA;AAE5B,OAAO,EAAE,oBAAoB,EAAE,0BAA0B,EAAE,MAAM,aAAa,CAAA;AAE9E,YAAY,EACX,mBAAmB,EACnB,eAAe,EACf,YAAY,EACZ,cAAc,EACd,SAAS,EACT,kBAAkB,EAClB,gBAAgB,EAChB,WAAW,EACX,gBAAgB,GAChB,MAAM,mCAAmC,CAAA;AAM1C,OAAO,EAAE,SAAS,EAAE,MAAM,OAAO,CAAA"}