@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.
- package/dist/{chunk-m7qcd4j8.js → chunk-3bz9d5vy.js} +68 -54
- package/dist/errors.d.ts +144 -1
- package/dist/errors.js +1 -1
- package/dist/index.d.ts +1401 -790
- package/dist/index.js +246 -77
- package/dist/public-types.d.ts +3 -966
- package/package.json +2 -2
- package/dist/errors.d.ts.map +0 -1
- package/dist/index.d.ts.map +0 -1
- package/dist/public-types.d.ts.map +0 -1
|
@@ -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
|
-
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
|
|
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.
|
|
649
|
-
this.
|
|
650
|
-
this.
|
|
651
|
-
this.
|
|
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.
|
|
663
|
+
authUrl: this._authUrl
|
|
655
664
|
},
|
|
656
665
|
edubridge: {
|
|
657
666
|
baseUrl: platformEndpoints.api[env],
|
|
658
|
-
authUrl: this.
|
|
667
|
+
authUrl: this._authUrl
|
|
659
668
|
},
|
|
660
669
|
powerpath: {
|
|
661
670
|
baseUrl: platformEndpoints.api[env],
|
|
662
|
-
authUrl: this.
|
|
671
|
+
authUrl: this._authUrl
|
|
663
672
|
},
|
|
664
673
|
clr: {
|
|
665
674
|
baseUrl: platformEndpoints.api[env],
|
|
666
|
-
authUrl: this.
|
|
675
|
+
authUrl: this._authUrl
|
|
667
676
|
},
|
|
668
677
|
case: {
|
|
669
678
|
baseUrl: platformEndpoints.api[env],
|
|
670
|
-
authUrl: this.
|
|
679
|
+
authUrl: this._authUrl
|
|
671
680
|
},
|
|
672
681
|
caliper: {
|
|
673
682
|
baseUrl: platformEndpoints.caliper[env],
|
|
674
|
-
authUrl: this.
|
|
683
|
+
authUrl: this._authUrl
|
|
675
684
|
},
|
|
676
685
|
webhooks: {
|
|
677
686
|
baseUrl: platformEndpoints.caliper[env],
|
|
678
|
-
authUrl: this.
|
|
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.
|
|
695
|
+
authUrl: this._authUrl
|
|
683
696
|
}
|
|
684
697
|
};
|
|
685
698
|
} else if (isExplicitConfig(config)) {
|
|
686
699
|
this.auth = config.auth;
|
|
687
|
-
this.
|
|
688
|
-
this.
|
|
689
|
-
this.
|
|
690
|
-
oneroster: { baseUrl: config.baseUrl, authUrl: this.
|
|
691
|
-
edubridge: { baseUrl: config.baseUrl, authUrl: this.
|
|
692
|
-
powerpath: { baseUrl: config.baseUrl, authUrl: this.
|
|
693
|
-
clr: { baseUrl: config.baseUrl, authUrl: this.
|
|
694
|
-
case: { baseUrl: config.baseUrl, authUrl: this.
|
|
695
|
-
caliper: { baseUrl: config.baseUrl, authUrl: this.
|
|
696
|
-
webhooks: { baseUrl: config.baseUrl, authUrl: this.
|
|
697
|
-
|
|
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.
|
|
702
|
-
this.
|
|
703
|
-
this.
|
|
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.
|
|
720
|
+
this._endpoints[service] = {
|
|
707
721
|
baseUrl,
|
|
708
|
-
authUrl: this.
|
|
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.
|
|
716
|
-
if (this.
|
|
717
|
-
delete this.
|
|
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.
|
|
736
|
+
const endpoint = this._endpoints[service];
|
|
723
737
|
if (!endpoint) {
|
|
724
738
|
const pathKey = service;
|
|
725
|
-
if (pathKey in this.
|
|
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.
|
|
747
|
+
return service in this._endpoints;
|
|
734
748
|
}
|
|
735
749
|
getAvailableServices() {
|
|
736
|
-
return Object.keys(this.
|
|
750
|
+
return Object.keys(this._endpoints);
|
|
737
751
|
}
|
|
738
752
|
getTokenUrl() {
|
|
739
|
-
return this.
|
|
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.
|
|
761
|
+
return this._pathProfiles;
|
|
748
762
|
}
|
|
749
763
|
getServicePaths(service) {
|
|
750
|
-
const paths = this.
|
|
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.
|
|
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.
|
|
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.
|
|
790
|
+
scope: this._tokenScope
|
|
777
791
|
});
|
|
778
|
-
this.
|
|
792
|
+
this._tokenManagers.set(authUrl, manager);
|
|
779
793
|
}
|
|
780
794
|
return manager;
|
|
781
795
|
}
|
|
782
796
|
async checkAuth() {
|
|
783
|
-
if (!this.
|
|
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.
|
|
801
|
+
let manager = this._tokenManagers.get(this._authUrl);
|
|
788
802
|
if (!manager) {
|
|
789
803
|
manager = new TokenManager({
|
|
790
|
-
tokenUrl: this.
|
|
804
|
+
tokenUrl: this._authUrl,
|
|
791
805
|
credentials: {
|
|
792
806
|
clientId: this.auth.clientId,
|
|
793
807
|
clientSecret: this.auth.clientSecret
|
|
794
808
|
},
|
|
795
|
-
scope: this.
|
|
809
|
+
scope: this._tokenScope
|
|
796
810
|
});
|
|
797
|
-
this.
|
|
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.
|
|
830
|
+
for (const manager of this._tokenManagers.values()) {
|
|
817
831
|
manager.invalidate?.();
|
|
818
832
|
}
|
|
819
|
-
this.
|
|
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
|
-
|
|
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 };
|