@timeback/caliper 0.2.0 → 0.2.1-beta.20260331190459

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.
@@ -572,6 +572,13 @@ var BEYONDAI_PATHS = {
572
572
  webhookFilterUpdate: "/webhook-filters/{id}",
573
573
  webhookFilterDelete: "/webhook-filters/{id}",
574
574
  webhookFiltersByWebhook: "/webhook-filters/webhook/{webhookId}"
575
+ },
576
+ reporting: {
577
+ mcp: "/mcp/reporting",
578
+ savedQueryExecute: "/reporting/saved-queries/{id}",
579
+ adminGroupCheck: "/mcp/admin/users/{email}/group",
580
+ adminGroupAdd: "/mcp/admin/users/{email}/group",
581
+ adminGroupRemove: "/mcp/admin/users/{email}/group"
575
582
  }
576
583
  };
577
584
  var LEARNWITHAI_PATHS = {
@@ -588,6 +595,7 @@ var LEARNWITHAI_PATHS = {
588
595
  resources: "/resources/1.0"
589
596
  },
590
597
  webhooks: null,
598
+ reporting: null,
591
599
  edubridge: null,
592
600
  powerpath: null,
593
601
  clr: null,
@@ -616,6 +624,7 @@ function resolvePathProfiles(pathProfile, customPaths) {
616
624
  caliper: customPaths?.caliper ?? basePaths.caliper,
617
625
  oneroster: customPaths?.oneroster ?? basePaths.oneroster,
618
626
  webhooks: customPaths?.webhooks ?? basePaths.webhooks,
627
+ reporting: customPaths?.reporting ?? basePaths.reporting,
619
628
  edubridge: customPaths?.edubridge ?? basePaths.edubridge,
620
629
  powerpath: customPaths?.powerpath ?? basePaths.powerpath,
621
630
  clr: customPaths?.clr ?? basePaths.clr,
@@ -628,11 +637,11 @@ class TimebackProvider {
628
637
  env;
629
638
  auth;
630
639
  timeout;
631
- endpoints;
632
- authUrl;
633
- tokenScope;
634
- pathProfiles;
635
- tokenManagers = new Map;
640
+ _endpoints;
641
+ _authUrl;
642
+ _tokenScope;
643
+ _pathProfiles;
644
+ _tokenManagers = new Map;
636
645
  constructor(config) {
637
646
  this.timeout = config.timeout ?? 30000;
638
647
  if (isEnvConfig(config)) {
@@ -645,84 +654,89 @@ class TimebackProvider {
645
654
  if (!platformEndpoints) {
646
655
  throw new Error(`Unknown platform: ${platform}`);
647
656
  }
648
- this.authUrl = platformEndpoints.token[env];
649
- this.tokenScope = platformEndpoints.tokenScope ?? undefined;
650
- this.pathProfiles = PLATFORM_PATHS[platform] ?? BEYONDAI_PATHS;
651
- this.endpoints = {
657
+ this._authUrl = platformEndpoints.token[env];
658
+ this._tokenScope = platformEndpoints.tokenScope ?? undefined;
659
+ this._pathProfiles = PLATFORM_PATHS[platform] ?? BEYONDAI_PATHS;
660
+ this._endpoints = {
652
661
  oneroster: {
653
662
  baseUrl: platformEndpoints.api[env],
654
- authUrl: this.authUrl
663
+ authUrl: this._authUrl
655
664
  },
656
665
  edubridge: {
657
666
  baseUrl: platformEndpoints.api[env],
658
- authUrl: this.authUrl
667
+ authUrl: this._authUrl
659
668
  },
660
669
  powerpath: {
661
670
  baseUrl: platformEndpoints.api[env],
662
- authUrl: this.authUrl
671
+ authUrl: this._authUrl
663
672
  },
664
673
  clr: {
665
674
  baseUrl: platformEndpoints.api[env],
666
- authUrl: this.authUrl
675
+ authUrl: this._authUrl
667
676
  },
668
677
  case: {
669
678
  baseUrl: platformEndpoints.api[env],
670
- authUrl: this.authUrl
679
+ authUrl: this._authUrl
671
680
  },
672
681
  caliper: {
673
682
  baseUrl: platformEndpoints.caliper[env],
674
- authUrl: this.authUrl
683
+ authUrl: this._authUrl
675
684
  },
676
685
  webhooks: {
677
686
  baseUrl: platformEndpoints.caliper[env],
678
- authUrl: this.authUrl
687
+ authUrl: this._authUrl
688
+ },
689
+ reporting: {
690
+ baseUrl: platformEndpoints.api[env],
691
+ authUrl: this._authUrl
679
692
  },
680
693
  qti: {
681
694
  baseUrl: platformEndpoints.qti[env],
682
- authUrl: this.authUrl
695
+ authUrl: this._authUrl
683
696
  }
684
697
  };
685
698
  } else if (isExplicitConfig(config)) {
686
699
  this.auth = config.auth;
687
- this.authUrl = config.authUrl;
688
- this.pathProfiles = resolvePathProfiles(config.pathProfile, config.paths);
689
- this.endpoints = {
690
- oneroster: { baseUrl: config.baseUrl, authUrl: this.authUrl },
691
- edubridge: { baseUrl: config.baseUrl, authUrl: this.authUrl },
692
- powerpath: { baseUrl: config.baseUrl, authUrl: this.authUrl },
693
- clr: { baseUrl: config.baseUrl, authUrl: this.authUrl },
694
- case: { baseUrl: config.baseUrl, authUrl: this.authUrl },
695
- caliper: { baseUrl: config.baseUrl, authUrl: this.authUrl },
696
- webhooks: { baseUrl: config.baseUrl, authUrl: this.authUrl },
697
- qti: { baseUrl: config.baseUrl, authUrl: this.authUrl }
700
+ this._authUrl = config.authUrl;
701
+ this._pathProfiles = resolvePathProfiles(config.pathProfile, config.paths);
702
+ this._endpoints = {
703
+ oneroster: { baseUrl: config.baseUrl, authUrl: this._authUrl },
704
+ edubridge: { baseUrl: config.baseUrl, authUrl: this._authUrl },
705
+ powerpath: { baseUrl: config.baseUrl, authUrl: this._authUrl },
706
+ clr: { baseUrl: config.baseUrl, authUrl: this._authUrl },
707
+ case: { baseUrl: config.baseUrl, authUrl: this._authUrl },
708
+ caliper: { baseUrl: config.baseUrl, authUrl: this._authUrl },
709
+ webhooks: { baseUrl: config.baseUrl, authUrl: this._authUrl },
710
+ reporting: { baseUrl: config.baseUrl, authUrl: this._authUrl },
711
+ qti: { baseUrl: config.baseUrl, authUrl: this._authUrl }
698
712
  };
699
713
  } else if (isServicesConfig(config)) {
700
714
  this.auth = config.auth;
701
- this.authUrl = config.authUrl;
702
- this.pathProfiles = resolvePathProfiles(config.pathProfile, config.paths);
703
- this.endpoints = {};
715
+ this._authUrl = config.authUrl;
716
+ this._pathProfiles = resolvePathProfiles(config.pathProfile, config.paths);
717
+ this._endpoints = {};
704
718
  for (const [service, baseUrl] of Object.entries(config.services)) {
705
719
  if (baseUrl) {
706
- this.endpoints[service] = {
720
+ this._endpoints[service] = {
707
721
  baseUrl,
708
- authUrl: this.authUrl
722
+ authUrl: this._authUrl
709
723
  };
710
724
  }
711
725
  }
712
726
  } else {
713
727
  throw new Error("Invalid provider configuration");
714
728
  }
715
- for (const service of Object.keys(this.pathProfiles)) {
716
- if (this.pathProfiles[service] === null) {
717
- delete this.endpoints[service];
729
+ for (const service of Object.keys(this._pathProfiles)) {
730
+ if (this._pathProfiles[service] === null) {
731
+ delete this._endpoints[service];
718
732
  }
719
733
  }
720
734
  }
721
735
  getEndpoint(service) {
722
- const endpoint = this.endpoints[service];
736
+ const endpoint = this._endpoints[service];
723
737
  if (!endpoint) {
724
738
  const pathKey = service;
725
- if (pathKey in this.pathProfiles && this.pathProfiles[pathKey] === null) {
739
+ if (pathKey in this._pathProfiles && this._pathProfiles[pathKey] === null) {
726
740
  throw new Error(`Service "${service}" is not supported on ${this.platform ?? "this"} platform.`);
727
741
  }
728
742
  throw new Error(`Service "${service}" is not configured in this provider`);
@@ -730,13 +744,13 @@ class TimebackProvider {
730
744
  return endpoint;
731
745
  }
732
746
  hasService(service) {
733
- return service in this.endpoints;
747
+ return service in this._endpoints;
734
748
  }
735
749
  getAvailableServices() {
736
- return Object.keys(this.endpoints);
750
+ return Object.keys(this._endpoints);
737
751
  }
738
752
  getTokenUrl() {
739
- return this.authUrl;
753
+ return this._authUrl;
740
754
  }
741
755
  getEndpointWithPaths(service) {
742
756
  const endpoint = this.getEndpoint(service);
@@ -744,17 +758,17 @@ class TimebackProvider {
744
758
  return { ...endpoint, paths };
745
759
  }
746
760
  getPaths() {
747
- return this.pathProfiles;
761
+ return this._pathProfiles;
748
762
  }
749
763
  getServicePaths(service) {
750
- const paths = this.pathProfiles[service];
764
+ const paths = this._pathProfiles[service];
751
765
  if (!paths) {
752
766
  throw new Error(`Service "${service}" is not supported on ${this.platform ?? "this"} platform.`);
753
767
  }
754
768
  return paths;
755
769
  }
756
770
  hasServiceSupport(service) {
757
- return this.pathProfiles[service] !== null;
771
+ return this._pathProfiles[service] !== null;
758
772
  }
759
773
  getTokenProvider(service) {
760
774
  const endpoint = this.getEndpoint(service);
@@ -765,7 +779,7 @@ class TimebackProvider {
765
779
  if (!this.auth) {
766
780
  throw new Error(`Service "${service}" requires authentication but no credentials were provided`);
767
781
  }
768
- let manager = this.tokenManagers.get(authUrl);
782
+ let manager = this._tokenManagers.get(authUrl);
769
783
  if (!manager) {
770
784
  manager = new TokenManager({
771
785
  tokenUrl: authUrl,
@@ -773,28 +787,28 @@ class TimebackProvider {
773
787
  clientId: this.auth.clientId,
774
788
  clientSecret: this.auth.clientSecret
775
789
  },
776
- scope: this.tokenScope
790
+ scope: this._tokenScope
777
791
  });
778
- this.tokenManagers.set(authUrl, manager);
792
+ this._tokenManagers.set(authUrl, manager);
779
793
  }
780
794
  return manager;
781
795
  }
782
796
  async checkAuth() {
783
- if (!this.authUrl || !this.auth) {
797
+ if (!this._authUrl || !this.auth) {
784
798
  throw new Error("No auth configured on this provider");
785
799
  }
786
800
  const startTime = Date.now();
787
- let manager = this.tokenManagers.get(this.authUrl);
801
+ let manager = this._tokenManagers.get(this._authUrl);
788
802
  if (!manager) {
789
803
  manager = new TokenManager({
790
- tokenUrl: this.authUrl,
804
+ tokenUrl: this._authUrl,
791
805
  credentials: {
792
806
  clientId: this.auth.clientId,
793
807
  clientSecret: this.auth.clientSecret
794
808
  },
795
- scope: this.tokenScope
809
+ scope: this._tokenScope
796
810
  });
797
- this.tokenManagers.set(this.authUrl, manager);
811
+ this._tokenManagers.set(this._authUrl, manager);
798
812
  }
799
813
  try {
800
814
  await manager.getToken();
@@ -813,10 +827,10 @@ class TimebackProvider {
813
827
  }
814
828
  }
815
829
  invalidateTokens() {
816
- for (const manager of this.tokenManagers.values()) {
830
+ for (const manager of this._tokenManagers.values()) {
817
831
  manager.invalidate?.();
818
832
  }
819
- this.tokenManagers.clear();
833
+ this._tokenManagers.clear();
820
834
  }
821
835
  }
822
836
  // ../../internal/client-infra/src/utils/utils.ts
package/dist/errors.d.ts CHANGED
@@ -1 +1,144 @@
1
- export { ApiError as CaliperError, ForbiddenError, InputValidationError, NotFoundError, UnauthorizedError, ValidationError } from '@timeback/internal-client-infra';
1
+ /**
2
+ * Error Types
3
+ *
4
+ * Shared types for error helpers.
5
+ */
6
+ /**
7
+ * Validation issue from client-side input validation.
8
+ */
9
+ interface ValidationIssue {
10
+ /** Field path (e.g. "sourcedId", "metadata.email") */
11
+ path: string;
12
+ /** Human-readable error message */
13
+ message: string;
14
+ }
15
+
16
+ /**
17
+ * API Error Classes
18
+ *
19
+ * Base error classes for HTTP API failures.
20
+ * Includes IMS Global error response parsing (OneRoster, QTI, etc.).
21
+ */
22
+
23
+ /**
24
+ * Base error class for all API errors.
25
+ *
26
+ * Provides access to the HTTP status code and raw response body.
27
+ * Includes IMS Global error parsing (minorCodes, details) for
28
+ * IMS-standard APIs like OneRoster and QTI.
29
+ *
30
+ * @example
31
+ * ```typescript
32
+ * // Catching and inspecting errors
33
+ * try {
34
+ * await client.users.get('non-existent-id')
35
+ * } catch (error) {
36
+ * if (error instanceof ApiError) {
37
+ * console.log(`Error ${error.statusCode}: ${error.message}`)
38
+ * console.log('Minor codes:', error.minorCodes)
39
+ * console.log('Details:', error.details)
40
+ * }
41
+ * }
42
+ * ```
43
+ */
44
+ declare class ApiError extends Error {
45
+ readonly statusCode?: number | undefined;
46
+ readonly response?: unknown;
47
+ readonly name: string;
48
+ /**
49
+ * Creates a new ApiError.
50
+ *
51
+ * @param message - Human-readable error message
52
+ * @param statusCode - HTTP status code
53
+ * @param response - Raw response body (if available)
54
+ */
55
+ constructor(message: string, statusCode?: number | undefined, response?: unknown);
56
+ /**
57
+ * Minor error codes from IMS Global error response.
58
+ *
59
+ * For IMS-standard APIs (OneRoster, QTI), provides specific error codes
60
+ * like "unknownobject" or "invaliddata".
61
+ *
62
+ * @returns Array of field/value pairs, or empty array if not IMS format
63
+ */
64
+ get minorCodes(): Array<{
65
+ field: string;
66
+ value: string;
67
+ }>;
68
+ /**
69
+ * Additional error details from IMS Global response.
70
+ *
71
+ * May contain field-level validation errors or other structured details.
72
+ *
73
+ * @returns Array of key-value objects, or empty array if not present
74
+ */
75
+ get details(): Array<Record<string, string>>;
76
+ }
77
+ /**
78
+ * Error thrown when authentication fails (HTTP 401).
79
+ *
80
+ * Typically indicates invalid or expired credentials.
81
+ */
82
+ declare class UnauthorizedError extends ApiError {
83
+ readonly name = "UnauthorizedError";
84
+ constructor(message?: string, response?: unknown);
85
+ }
86
+ /**
87
+ * Error thrown when the client lacks permission for the operation (HTTP 403).
88
+ *
89
+ * The credentials are valid, but the client is not authorized for this action.
90
+ */
91
+ declare class ForbiddenError extends ApiError {
92
+ readonly name = "ForbiddenError";
93
+ constructor(message?: string, response?: unknown);
94
+ }
95
+ /**
96
+ * Error thrown when a requested resource is not found (HTTP 404).
97
+ */
98
+ declare class NotFoundError extends ApiError {
99
+ readonly name = "NotFoundError";
100
+ constructor(message?: string, response?: unknown);
101
+ }
102
+ /**
103
+ * Error thrown when request data is invalid (HTTP 422).
104
+ *
105
+ * Check the `details` property for field-level validation errors.
106
+ */
107
+ declare class ValidationError extends ApiError {
108
+ readonly name = "ValidationError";
109
+ constructor(message?: string, response?: unknown);
110
+ }
111
+ /**
112
+ * Validation issue from client-side input validation.
113
+ */
114
+ /**
115
+ * Error thrown when client-side input validation fails.
116
+ *
117
+ * This is thrown **before** making a network request, providing fast feedback
118
+ * with actionable, path-based error messages.
119
+ *
120
+ * Uses statusCode 400 (Bad Request) to distinguish from server-side 422 errors.
121
+ * Formats like IMS errors via `imsx_error_details` so existing error formatters work.
122
+ *
123
+ * @example
124
+ * ```typescript
125
+ * try {
126
+ * await client.users.create({}) // missing required fields
127
+ * } catch (error) {
128
+ * if (error instanceof InputValidationError) {
129
+ * console.log('Invalid input:', error.issues)
130
+ * // [{ path: 'sourcedId', message: 'Required' }]
131
+ * }
132
+ * }
133
+ * ```
134
+ */
135
+ declare class InputValidationError extends ApiError {
136
+ readonly name = "InputValidationError";
137
+ /**
138
+ * The validation issues that caused this error.
139
+ */
140
+ readonly issues: ValidationIssue[];
141
+ constructor(message: string, issues: ValidationIssue[]);
142
+ }
143
+
144
+ export { ApiError as CaliperError, ForbiddenError, InputValidationError, NotFoundError, UnauthorizedError, ValidationError };
package/dist/errors.js CHANGED
@@ -5,7 +5,7 @@ import {
5
5
  NotFoundError,
6
6
  UnauthorizedError,
7
7
  ValidationError
8
- } from "./chunk-m7qcd4j8.js";
8
+ } from "./chunk-3bz9d5vy.js";
9
9
  import"./chunk-6jf1natv.js";
10
10
  export {
11
11
  ValidationError,