@timeback/webhooks 0.2.1-beta.20260313023436 → 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-1dmdawx1.js → chunk-9a1sbh56.js} +68 -54
- package/dist/errors.d.ts +144 -1
- package/dist/errors.js +1 -1
- package/dist/index.d.ts +1072 -128
- package/dist/index.js +246 -77
- package/dist/public-types.d.ts +2 -170
- package/dist/public-types.js +1 -0
- 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
|
@@ -571,6 +571,13 @@ var BEYONDAI_PATHS = {
|
|
|
571
571
|
webhookFilterUpdate: "/webhook-filters/{id}",
|
|
572
572
|
webhookFilterDelete: "/webhook-filters/{id}",
|
|
573
573
|
webhookFiltersByWebhook: "/webhook-filters/webhook/{webhookId}"
|
|
574
|
+
},
|
|
575
|
+
reporting: {
|
|
576
|
+
mcp: "/mcp/reporting",
|
|
577
|
+
savedQueryExecute: "/reporting/saved-queries/{id}",
|
|
578
|
+
adminGroupCheck: "/mcp/admin/users/{email}/group",
|
|
579
|
+
adminGroupAdd: "/mcp/admin/users/{email}/group",
|
|
580
|
+
adminGroupRemove: "/mcp/admin/users/{email}/group"
|
|
574
581
|
}
|
|
575
582
|
};
|
|
576
583
|
var LEARNWITHAI_PATHS = {
|
|
@@ -587,6 +594,7 @@ var LEARNWITHAI_PATHS = {
|
|
|
587
594
|
resources: "/resources/1.0"
|
|
588
595
|
},
|
|
589
596
|
webhooks: null,
|
|
597
|
+
reporting: null,
|
|
590
598
|
edubridge: null,
|
|
591
599
|
powerpath: null,
|
|
592
600
|
clr: null,
|
|
@@ -615,6 +623,7 @@ function resolvePathProfiles(pathProfile, customPaths) {
|
|
|
615
623
|
caliper: customPaths?.caliper ?? basePaths.caliper,
|
|
616
624
|
oneroster: customPaths?.oneroster ?? basePaths.oneroster,
|
|
617
625
|
webhooks: customPaths?.webhooks ?? basePaths.webhooks,
|
|
626
|
+
reporting: customPaths?.reporting ?? basePaths.reporting,
|
|
618
627
|
edubridge: customPaths?.edubridge ?? basePaths.edubridge,
|
|
619
628
|
powerpath: customPaths?.powerpath ?? basePaths.powerpath,
|
|
620
629
|
clr: customPaths?.clr ?? basePaths.clr,
|
|
@@ -627,11 +636,11 @@ class TimebackProvider {
|
|
|
627
636
|
env;
|
|
628
637
|
auth;
|
|
629
638
|
timeout;
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
|
|
639
|
+
_endpoints;
|
|
640
|
+
_authUrl;
|
|
641
|
+
_tokenScope;
|
|
642
|
+
_pathProfiles;
|
|
643
|
+
_tokenManagers = new Map;
|
|
635
644
|
constructor(config) {
|
|
636
645
|
this.timeout = config.timeout ?? 30000;
|
|
637
646
|
if (isEnvConfig(config)) {
|
|
@@ -644,84 +653,89 @@ class TimebackProvider {
|
|
|
644
653
|
if (!platformEndpoints) {
|
|
645
654
|
throw new Error(`Unknown platform: ${platform}`);
|
|
646
655
|
}
|
|
647
|
-
this.
|
|
648
|
-
this.
|
|
649
|
-
this.
|
|
650
|
-
this.
|
|
656
|
+
this._authUrl = platformEndpoints.token[env];
|
|
657
|
+
this._tokenScope = platformEndpoints.tokenScope ?? undefined;
|
|
658
|
+
this._pathProfiles = PLATFORM_PATHS[platform] ?? BEYONDAI_PATHS;
|
|
659
|
+
this._endpoints = {
|
|
651
660
|
oneroster: {
|
|
652
661
|
baseUrl: platformEndpoints.api[env],
|
|
653
|
-
authUrl: this.
|
|
662
|
+
authUrl: this._authUrl
|
|
654
663
|
},
|
|
655
664
|
edubridge: {
|
|
656
665
|
baseUrl: platformEndpoints.api[env],
|
|
657
|
-
authUrl: this.
|
|
666
|
+
authUrl: this._authUrl
|
|
658
667
|
},
|
|
659
668
|
powerpath: {
|
|
660
669
|
baseUrl: platformEndpoints.api[env],
|
|
661
|
-
authUrl: this.
|
|
670
|
+
authUrl: this._authUrl
|
|
662
671
|
},
|
|
663
672
|
clr: {
|
|
664
673
|
baseUrl: platformEndpoints.api[env],
|
|
665
|
-
authUrl: this.
|
|
674
|
+
authUrl: this._authUrl
|
|
666
675
|
},
|
|
667
676
|
case: {
|
|
668
677
|
baseUrl: platformEndpoints.api[env],
|
|
669
|
-
authUrl: this.
|
|
678
|
+
authUrl: this._authUrl
|
|
670
679
|
},
|
|
671
680
|
caliper: {
|
|
672
681
|
baseUrl: platformEndpoints.caliper[env],
|
|
673
|
-
authUrl: this.
|
|
682
|
+
authUrl: this._authUrl
|
|
674
683
|
},
|
|
675
684
|
webhooks: {
|
|
676
685
|
baseUrl: platformEndpoints.caliper[env],
|
|
677
|
-
authUrl: this.
|
|
686
|
+
authUrl: this._authUrl
|
|
687
|
+
},
|
|
688
|
+
reporting: {
|
|
689
|
+
baseUrl: platformEndpoints.api[env],
|
|
690
|
+
authUrl: this._authUrl
|
|
678
691
|
},
|
|
679
692
|
qti: {
|
|
680
693
|
baseUrl: platformEndpoints.qti[env],
|
|
681
|
-
authUrl: this.
|
|
694
|
+
authUrl: this._authUrl
|
|
682
695
|
}
|
|
683
696
|
};
|
|
684
697
|
} else if (isExplicitConfig(config)) {
|
|
685
698
|
this.auth = config.auth;
|
|
686
|
-
this.
|
|
687
|
-
this.
|
|
688
|
-
this.
|
|
689
|
-
oneroster: { baseUrl: config.baseUrl, authUrl: this.
|
|
690
|
-
edubridge: { baseUrl: config.baseUrl, authUrl: this.
|
|
691
|
-
powerpath: { baseUrl: config.baseUrl, authUrl: this.
|
|
692
|
-
clr: { baseUrl: config.baseUrl, authUrl: this.
|
|
693
|
-
case: { baseUrl: config.baseUrl, authUrl: this.
|
|
694
|
-
caliper: { baseUrl: config.baseUrl, authUrl: this.
|
|
695
|
-
webhooks: { baseUrl: config.baseUrl, authUrl: this.
|
|
696
|
-
|
|
699
|
+
this._authUrl = config.authUrl;
|
|
700
|
+
this._pathProfiles = resolvePathProfiles(config.pathProfile, config.paths);
|
|
701
|
+
this._endpoints = {
|
|
702
|
+
oneroster: { baseUrl: config.baseUrl, authUrl: this._authUrl },
|
|
703
|
+
edubridge: { baseUrl: config.baseUrl, authUrl: this._authUrl },
|
|
704
|
+
powerpath: { baseUrl: config.baseUrl, authUrl: this._authUrl },
|
|
705
|
+
clr: { baseUrl: config.baseUrl, authUrl: this._authUrl },
|
|
706
|
+
case: { baseUrl: config.baseUrl, authUrl: this._authUrl },
|
|
707
|
+
caliper: { baseUrl: config.baseUrl, authUrl: this._authUrl },
|
|
708
|
+
webhooks: { baseUrl: config.baseUrl, authUrl: this._authUrl },
|
|
709
|
+
reporting: { baseUrl: config.baseUrl, authUrl: this._authUrl },
|
|
710
|
+
qti: { baseUrl: config.baseUrl, authUrl: this._authUrl }
|
|
697
711
|
};
|
|
698
712
|
} else if (isServicesConfig(config)) {
|
|
699
713
|
this.auth = config.auth;
|
|
700
|
-
this.
|
|
701
|
-
this.
|
|
702
|
-
this.
|
|
714
|
+
this._authUrl = config.authUrl;
|
|
715
|
+
this._pathProfiles = resolvePathProfiles(config.pathProfile, config.paths);
|
|
716
|
+
this._endpoints = {};
|
|
703
717
|
for (const [service, baseUrl] of Object.entries(config.services)) {
|
|
704
718
|
if (baseUrl) {
|
|
705
|
-
this.
|
|
719
|
+
this._endpoints[service] = {
|
|
706
720
|
baseUrl,
|
|
707
|
-
authUrl: this.
|
|
721
|
+
authUrl: this._authUrl
|
|
708
722
|
};
|
|
709
723
|
}
|
|
710
724
|
}
|
|
711
725
|
} else {
|
|
712
726
|
throw new Error("Invalid provider configuration");
|
|
713
727
|
}
|
|
714
|
-
for (const service of Object.keys(this.
|
|
715
|
-
if (this.
|
|
716
|
-
delete this.
|
|
728
|
+
for (const service of Object.keys(this._pathProfiles)) {
|
|
729
|
+
if (this._pathProfiles[service] === null) {
|
|
730
|
+
delete this._endpoints[service];
|
|
717
731
|
}
|
|
718
732
|
}
|
|
719
733
|
}
|
|
720
734
|
getEndpoint(service) {
|
|
721
|
-
const endpoint = this.
|
|
735
|
+
const endpoint = this._endpoints[service];
|
|
722
736
|
if (!endpoint) {
|
|
723
737
|
const pathKey = service;
|
|
724
|
-
if (pathKey in this.
|
|
738
|
+
if (pathKey in this._pathProfiles && this._pathProfiles[pathKey] === null) {
|
|
725
739
|
throw new Error(`Service "${service}" is not supported on ${this.platform ?? "this"} platform.`);
|
|
726
740
|
}
|
|
727
741
|
throw new Error(`Service "${service}" is not configured in this provider`);
|
|
@@ -729,13 +743,13 @@ class TimebackProvider {
|
|
|
729
743
|
return endpoint;
|
|
730
744
|
}
|
|
731
745
|
hasService(service) {
|
|
732
|
-
return service in this.
|
|
746
|
+
return service in this._endpoints;
|
|
733
747
|
}
|
|
734
748
|
getAvailableServices() {
|
|
735
|
-
return Object.keys(this.
|
|
749
|
+
return Object.keys(this._endpoints);
|
|
736
750
|
}
|
|
737
751
|
getTokenUrl() {
|
|
738
|
-
return this.
|
|
752
|
+
return this._authUrl;
|
|
739
753
|
}
|
|
740
754
|
getEndpointWithPaths(service) {
|
|
741
755
|
const endpoint = this.getEndpoint(service);
|
|
@@ -743,17 +757,17 @@ class TimebackProvider {
|
|
|
743
757
|
return { ...endpoint, paths };
|
|
744
758
|
}
|
|
745
759
|
getPaths() {
|
|
746
|
-
return this.
|
|
760
|
+
return this._pathProfiles;
|
|
747
761
|
}
|
|
748
762
|
getServicePaths(service) {
|
|
749
|
-
const paths = this.
|
|
763
|
+
const paths = this._pathProfiles[service];
|
|
750
764
|
if (!paths) {
|
|
751
765
|
throw new Error(`Service "${service}" is not supported on ${this.platform ?? "this"} platform.`);
|
|
752
766
|
}
|
|
753
767
|
return paths;
|
|
754
768
|
}
|
|
755
769
|
hasServiceSupport(service) {
|
|
756
|
-
return this.
|
|
770
|
+
return this._pathProfiles[service] !== null;
|
|
757
771
|
}
|
|
758
772
|
getTokenProvider(service) {
|
|
759
773
|
const endpoint = this.getEndpoint(service);
|
|
@@ -764,7 +778,7 @@ class TimebackProvider {
|
|
|
764
778
|
if (!this.auth) {
|
|
765
779
|
throw new Error(`Service "${service}" requires authentication but no credentials were provided`);
|
|
766
780
|
}
|
|
767
|
-
let manager = this.
|
|
781
|
+
let manager = this._tokenManagers.get(authUrl);
|
|
768
782
|
if (!manager) {
|
|
769
783
|
manager = new TokenManager({
|
|
770
784
|
tokenUrl: authUrl,
|
|
@@ -772,28 +786,28 @@ class TimebackProvider {
|
|
|
772
786
|
clientId: this.auth.clientId,
|
|
773
787
|
clientSecret: this.auth.clientSecret
|
|
774
788
|
},
|
|
775
|
-
scope: this.
|
|
789
|
+
scope: this._tokenScope
|
|
776
790
|
});
|
|
777
|
-
this.
|
|
791
|
+
this._tokenManagers.set(authUrl, manager);
|
|
778
792
|
}
|
|
779
793
|
return manager;
|
|
780
794
|
}
|
|
781
795
|
async checkAuth() {
|
|
782
|
-
if (!this.
|
|
796
|
+
if (!this._authUrl || !this.auth) {
|
|
783
797
|
throw new Error("No auth configured on this provider");
|
|
784
798
|
}
|
|
785
799
|
const startTime = Date.now();
|
|
786
|
-
let manager = this.
|
|
800
|
+
let manager = this._tokenManagers.get(this._authUrl);
|
|
787
801
|
if (!manager) {
|
|
788
802
|
manager = new TokenManager({
|
|
789
|
-
tokenUrl: this.
|
|
803
|
+
tokenUrl: this._authUrl,
|
|
790
804
|
credentials: {
|
|
791
805
|
clientId: this.auth.clientId,
|
|
792
806
|
clientSecret: this.auth.clientSecret
|
|
793
807
|
},
|
|
794
|
-
scope: this.
|
|
808
|
+
scope: this._tokenScope
|
|
795
809
|
});
|
|
796
|
-
this.
|
|
810
|
+
this._tokenManagers.set(this._authUrl, manager);
|
|
797
811
|
}
|
|
798
812
|
try {
|
|
799
813
|
await manager.getToken();
|
|
@@ -812,10 +826,10 @@ class TimebackProvider {
|
|
|
812
826
|
}
|
|
813
827
|
}
|
|
814
828
|
invalidateTokens() {
|
|
815
|
-
for (const manager of this.
|
|
829
|
+
for (const manager of this._tokenManagers.values()) {
|
|
816
830
|
manager.invalidate?.();
|
|
817
831
|
}
|
|
818
|
-
this.
|
|
832
|
+
this._tokenManagers.clear();
|
|
819
833
|
}
|
|
820
834
|
}
|
|
821
835
|
// ../../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 { ForbiddenError, InputValidationError, NotFoundError, UnauthorizedError, ValidationError, ApiError as WebhooksError };
|