@timeback/core 0.2.1 → 0.2.2-beta.20260320221119
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-aw1d6bdn.js → chunk-2mkbbgd8.js} +1 -1
- package/dist/{chunk-2z9zawsc.js → chunk-bjb7ngh9.js} +210 -210
- package/dist/errors.d.ts +94 -4
- package/dist/errors.js +1 -1
- package/dist/index.d.ts +1350 -16
- package/dist/index.js +24 -6
- package/dist/qti.d.ts +1 -11
- package/dist/types.d.ts +704 -4
- package/dist/utils.d.ts +1 -8
- package/dist/utils.js +2 -2
- package/package.json +1 -1
- package/dist/client.d.ts +0 -228
- package/dist/client.d.ts.map +0 -1
- package/dist/constants.d.ts +0 -24
- package/dist/constants.d.ts.map +0 -1
- package/dist/errors.d.ts.map +0 -1
- package/dist/index.d.ts.map +0 -1
- package/dist/lib/broadcast-results.d.ts +0 -20
- package/dist/lib/broadcast-results.d.ts.map +0 -1
- package/dist/manager.d.ts +0 -129
- package/dist/manager.d.ts.map +0 -1
- package/dist/qti.d.ts.map +0 -1
- package/dist/types/index.d.ts +0 -246
- package/dist/types/index.d.ts.map +0 -1
- package/dist/types.d.ts.map +0 -1
- package/dist/utils.d.ts.map +0 -1
|
@@ -3,157 +3,6 @@ import {
|
|
|
3
3
|
__toESM
|
|
4
4
|
} from "./chunk-3j7jywnx.js";
|
|
5
5
|
|
|
6
|
-
// ../../internal/client-infra/src/errors/errors.ts
|
|
7
|
-
class ApiError extends Error {
|
|
8
|
-
statusCode;
|
|
9
|
-
response;
|
|
10
|
-
name = "ApiError";
|
|
11
|
-
constructor(message, statusCode, response) {
|
|
12
|
-
super(message);
|
|
13
|
-
this.statusCode = statusCode;
|
|
14
|
-
this.response = response;
|
|
15
|
-
}
|
|
16
|
-
get minorCodes() {
|
|
17
|
-
const ims = this.response;
|
|
18
|
-
if (!ims?.imsx_CodeMinor?.imsx_codeMinorField) {
|
|
19
|
-
return [];
|
|
20
|
-
}
|
|
21
|
-
return ims.imsx_CodeMinor.imsx_codeMinorField.map((field) => ({
|
|
22
|
-
field: field.imsx_codeMinorFieldName,
|
|
23
|
-
value: field.imsx_codeMinorFieldValue
|
|
24
|
-
}));
|
|
25
|
-
}
|
|
26
|
-
get details() {
|
|
27
|
-
const ims = this.response;
|
|
28
|
-
return ims?.imsx_error_details ?? [];
|
|
29
|
-
}
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
class UnauthorizedError extends ApiError {
|
|
33
|
-
name = "UnauthorizedError";
|
|
34
|
-
constructor(message = "Unauthorized", response) {
|
|
35
|
-
super(message, 401, response);
|
|
36
|
-
}
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
class ForbiddenError extends ApiError {
|
|
40
|
-
name = "ForbiddenError";
|
|
41
|
-
constructor(message = "Forbidden", response) {
|
|
42
|
-
super(message, 403, response);
|
|
43
|
-
}
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
class NotFoundError extends ApiError {
|
|
47
|
-
name = "NotFoundError";
|
|
48
|
-
constructor(message = "Not Found", response) {
|
|
49
|
-
super(message, 404, response);
|
|
50
|
-
}
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
class ValidationError extends ApiError {
|
|
54
|
-
name = "ValidationError";
|
|
55
|
-
constructor(message = "Validation Error", response) {
|
|
56
|
-
super(message, 422, response);
|
|
57
|
-
}
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
class InputValidationError extends ApiError {
|
|
61
|
-
name = "InputValidationError";
|
|
62
|
-
issues;
|
|
63
|
-
constructor(message, issues) {
|
|
64
|
-
const response = {
|
|
65
|
-
imsx_codeMajor: "failure",
|
|
66
|
-
imsx_severity: "error",
|
|
67
|
-
imsx_description: message,
|
|
68
|
-
imsx_error_details: issues.map((issue) => ({
|
|
69
|
-
path: issue.path,
|
|
70
|
-
message: issue.message
|
|
71
|
-
}))
|
|
72
|
-
};
|
|
73
|
-
super(message, 400, response);
|
|
74
|
-
this.issues = issues;
|
|
75
|
-
}
|
|
76
|
-
}
|
|
77
|
-
function createInputValidationError(message, issues) {
|
|
78
|
-
return new InputValidationError(message, issues);
|
|
79
|
-
}
|
|
80
|
-
function isApiError(error) {
|
|
81
|
-
if (!(error instanceof Error))
|
|
82
|
-
return false;
|
|
83
|
-
return "statusCode" in error && "response" in error;
|
|
84
|
-
}
|
|
85
|
-
// ../../internal/client-infra/src/filter/where/where.ts
|
|
86
|
-
function escapeValue(value) {
|
|
87
|
-
if (value instanceof Date) {
|
|
88
|
-
return value.toISOString();
|
|
89
|
-
}
|
|
90
|
-
if (typeof value === "boolean") {
|
|
91
|
-
return value ? "true" : "false";
|
|
92
|
-
}
|
|
93
|
-
if (typeof value === "number") {
|
|
94
|
-
return String(value);
|
|
95
|
-
}
|
|
96
|
-
return value.replaceAll("'", "''");
|
|
97
|
-
}
|
|
98
|
-
function formatValue(value) {
|
|
99
|
-
const escaped = escapeValue(value);
|
|
100
|
-
const needsQuotes = typeof value === "string" || value instanceof Date;
|
|
101
|
-
return needsQuotes ? `'${escaped}'` : escaped;
|
|
102
|
-
}
|
|
103
|
-
function fieldToConditions(field, condition) {
|
|
104
|
-
if (typeof condition === "string" || typeof condition === "number" || typeof condition === "boolean" || condition instanceof Date) {
|
|
105
|
-
return [`${field}=${formatValue(condition)}`];
|
|
106
|
-
}
|
|
107
|
-
if (typeof condition === "object" && condition !== null) {
|
|
108
|
-
const ops = condition;
|
|
109
|
-
const conditions = [];
|
|
110
|
-
if (ops.ne !== undefined) {
|
|
111
|
-
conditions.push(`${field}!=${formatValue(ops.ne)}`);
|
|
112
|
-
}
|
|
113
|
-
if (ops.gt !== undefined) {
|
|
114
|
-
conditions.push(`${field}>${formatValue(ops.gt)}`);
|
|
115
|
-
}
|
|
116
|
-
if (ops.gte !== undefined) {
|
|
117
|
-
conditions.push(`${field}>=${formatValue(ops.gte)}`);
|
|
118
|
-
}
|
|
119
|
-
if (ops.lt !== undefined) {
|
|
120
|
-
conditions.push(`${field}<${formatValue(ops.lt)}`);
|
|
121
|
-
}
|
|
122
|
-
if (ops.lte !== undefined) {
|
|
123
|
-
conditions.push(`${field}<=${formatValue(ops.lte)}`);
|
|
124
|
-
}
|
|
125
|
-
if (ops.contains !== undefined) {
|
|
126
|
-
conditions.push(`${field}~${formatValue(ops.contains)}`);
|
|
127
|
-
}
|
|
128
|
-
if (ops.in !== undefined && ops.in.length > 0) {
|
|
129
|
-
const inConditions = ops.in.map((v) => `${field}=${formatValue(v)}`);
|
|
130
|
-
const joined = inConditions.join(" OR ");
|
|
131
|
-
conditions.push(inConditions.length > 1 ? `(${joined})` : joined);
|
|
132
|
-
}
|
|
133
|
-
if (ops.notIn !== undefined && ops.notIn.length > 0) {
|
|
134
|
-
const notInConditions = ops.notIn.map((v) => `${field}!=${formatValue(v)}`);
|
|
135
|
-
conditions.push(notInConditions.join(" AND "));
|
|
136
|
-
}
|
|
137
|
-
return conditions;
|
|
138
|
-
}
|
|
139
|
-
return [];
|
|
140
|
-
}
|
|
141
|
-
function isOrCondition(clause) {
|
|
142
|
-
return "OR" in clause && Array.isArray(clause.OR);
|
|
143
|
-
}
|
|
144
|
-
function whereToFilter(where) {
|
|
145
|
-
if (isOrCondition(where)) {
|
|
146
|
-
const orParts = where.OR.map((clause) => whereToFilter(clause)).filter((s) => s !== undefined);
|
|
147
|
-
return orParts.length > 0 ? orParts.join(" OR ") : undefined;
|
|
148
|
-
}
|
|
149
|
-
const conditions = [];
|
|
150
|
-
for (const [field, condition] of Object.entries(where)) {
|
|
151
|
-
if (condition !== undefined) {
|
|
152
|
-
conditions.push(...fieldToConditions(field, condition));
|
|
153
|
-
}
|
|
154
|
-
}
|
|
155
|
-
return conditions.length > 0 ? conditions.join(" AND ") : undefined;
|
|
156
|
-
}
|
|
157
6
|
// ../../internal/constants/src/endpoints.ts
|
|
158
7
|
var PLATFORM_BEYOND_AI = "BEYOND_AI";
|
|
159
8
|
var PLATFORM_LEARNWITH_AI = "LEARNWITH_AI";
|
|
@@ -383,9 +232,9 @@ var LEVEL_PREFIX = {
|
|
|
383
232
|
error: "[ERROR]"
|
|
384
233
|
};
|
|
385
234
|
function formatContext2(context) {
|
|
386
|
-
return Object.entries(context).map(([key, value]) => `${key}=${
|
|
235
|
+
return Object.entries(context).map(([key, value]) => `${key}=${formatValue(value)}`).join(" ");
|
|
387
236
|
}
|
|
388
|
-
function
|
|
237
|
+
function formatValue(value) {
|
|
389
238
|
if (typeof value === "string")
|
|
390
239
|
return value;
|
|
391
240
|
if (typeof value === "number")
|
|
@@ -709,11 +558,11 @@ class TimebackProvider {
|
|
|
709
558
|
env;
|
|
710
559
|
auth;
|
|
711
560
|
timeout;
|
|
712
|
-
|
|
713
|
-
|
|
714
|
-
|
|
715
|
-
|
|
716
|
-
|
|
561
|
+
_endpoints;
|
|
562
|
+
_authUrl;
|
|
563
|
+
_tokenScope;
|
|
564
|
+
_pathProfiles;
|
|
565
|
+
_tokenManagers = new Map;
|
|
717
566
|
constructor(config) {
|
|
718
567
|
this.timeout = config.timeout ?? 30000;
|
|
719
568
|
if (isEnvConfig(config)) {
|
|
@@ -726,89 +575,89 @@ class TimebackProvider {
|
|
|
726
575
|
if (!platformEndpoints) {
|
|
727
576
|
throw new Error(`Unknown platform: ${platform}`);
|
|
728
577
|
}
|
|
729
|
-
this.
|
|
730
|
-
this.
|
|
731
|
-
this.
|
|
732
|
-
this.
|
|
578
|
+
this._authUrl = platformEndpoints.token[env];
|
|
579
|
+
this._tokenScope = platformEndpoints.tokenScope ?? undefined;
|
|
580
|
+
this._pathProfiles = PLATFORM_PATHS[platform] ?? BEYONDAI_PATHS;
|
|
581
|
+
this._endpoints = {
|
|
733
582
|
oneroster: {
|
|
734
583
|
baseUrl: platformEndpoints.api[env],
|
|
735
|
-
authUrl: this.
|
|
584
|
+
authUrl: this._authUrl
|
|
736
585
|
},
|
|
737
586
|
edubridge: {
|
|
738
587
|
baseUrl: platformEndpoints.api[env],
|
|
739
|
-
authUrl: this.
|
|
588
|
+
authUrl: this._authUrl
|
|
740
589
|
},
|
|
741
590
|
powerpath: {
|
|
742
591
|
baseUrl: platformEndpoints.api[env],
|
|
743
|
-
authUrl: this.
|
|
592
|
+
authUrl: this._authUrl
|
|
744
593
|
},
|
|
745
594
|
clr: {
|
|
746
595
|
baseUrl: platformEndpoints.api[env],
|
|
747
|
-
authUrl: this.
|
|
596
|
+
authUrl: this._authUrl
|
|
748
597
|
},
|
|
749
598
|
case: {
|
|
750
599
|
baseUrl: platformEndpoints.api[env],
|
|
751
|
-
authUrl: this.
|
|
600
|
+
authUrl: this._authUrl
|
|
752
601
|
},
|
|
753
602
|
caliper: {
|
|
754
603
|
baseUrl: platformEndpoints.caliper[env],
|
|
755
|
-
authUrl: this.
|
|
604
|
+
authUrl: this._authUrl
|
|
756
605
|
},
|
|
757
606
|
webhooks: {
|
|
758
607
|
baseUrl: platformEndpoints.caliper[env],
|
|
759
|
-
authUrl: this.
|
|
608
|
+
authUrl: this._authUrl
|
|
760
609
|
},
|
|
761
610
|
reporting: {
|
|
762
611
|
baseUrl: platformEndpoints.api[env],
|
|
763
|
-
authUrl: this.
|
|
612
|
+
authUrl: this._authUrl
|
|
764
613
|
},
|
|
765
614
|
qti: {
|
|
766
615
|
baseUrl: platformEndpoints.qti[env],
|
|
767
|
-
authUrl: this.
|
|
616
|
+
authUrl: this._authUrl
|
|
768
617
|
}
|
|
769
618
|
};
|
|
770
619
|
} else if (isExplicitConfig(config)) {
|
|
771
620
|
this.auth = config.auth;
|
|
772
|
-
this.
|
|
773
|
-
this.
|
|
774
|
-
this.
|
|
775
|
-
oneroster: { baseUrl: config.baseUrl, authUrl: this.
|
|
776
|
-
edubridge: { baseUrl: config.baseUrl, authUrl: this.
|
|
777
|
-
powerpath: { baseUrl: config.baseUrl, authUrl: this.
|
|
778
|
-
clr: { baseUrl: config.baseUrl, authUrl: this.
|
|
779
|
-
case: { baseUrl: config.baseUrl, authUrl: this.
|
|
780
|
-
caliper: { baseUrl: config.baseUrl, authUrl: this.
|
|
781
|
-
webhooks: { baseUrl: config.baseUrl, authUrl: this.
|
|
782
|
-
reporting: { baseUrl: config.baseUrl, authUrl: this.
|
|
783
|
-
qti: { baseUrl: config.baseUrl, authUrl: this.
|
|
621
|
+
this._authUrl = config.authUrl;
|
|
622
|
+
this._pathProfiles = resolvePathProfiles(config.pathProfile, config.paths);
|
|
623
|
+
this._endpoints = {
|
|
624
|
+
oneroster: { baseUrl: config.baseUrl, authUrl: this._authUrl },
|
|
625
|
+
edubridge: { baseUrl: config.baseUrl, authUrl: this._authUrl },
|
|
626
|
+
powerpath: { baseUrl: config.baseUrl, authUrl: this._authUrl },
|
|
627
|
+
clr: { baseUrl: config.baseUrl, authUrl: this._authUrl },
|
|
628
|
+
case: { baseUrl: config.baseUrl, authUrl: this._authUrl },
|
|
629
|
+
caliper: { baseUrl: config.baseUrl, authUrl: this._authUrl },
|
|
630
|
+
webhooks: { baseUrl: config.baseUrl, authUrl: this._authUrl },
|
|
631
|
+
reporting: { baseUrl: config.baseUrl, authUrl: this._authUrl },
|
|
632
|
+
qti: { baseUrl: config.baseUrl, authUrl: this._authUrl }
|
|
784
633
|
};
|
|
785
634
|
} else if (isServicesConfig(config)) {
|
|
786
635
|
this.auth = config.auth;
|
|
787
|
-
this.
|
|
788
|
-
this.
|
|
789
|
-
this.
|
|
636
|
+
this._authUrl = config.authUrl;
|
|
637
|
+
this._pathProfiles = resolvePathProfiles(config.pathProfile, config.paths);
|
|
638
|
+
this._endpoints = {};
|
|
790
639
|
for (const [service, baseUrl] of Object.entries(config.services)) {
|
|
791
640
|
if (baseUrl) {
|
|
792
|
-
this.
|
|
641
|
+
this._endpoints[service] = {
|
|
793
642
|
baseUrl,
|
|
794
|
-
authUrl: this.
|
|
643
|
+
authUrl: this._authUrl
|
|
795
644
|
};
|
|
796
645
|
}
|
|
797
646
|
}
|
|
798
647
|
} else {
|
|
799
648
|
throw new Error("Invalid provider configuration");
|
|
800
649
|
}
|
|
801
|
-
for (const service of Object.keys(this.
|
|
802
|
-
if (this.
|
|
803
|
-
delete this.
|
|
650
|
+
for (const service of Object.keys(this._pathProfiles)) {
|
|
651
|
+
if (this._pathProfiles[service] === null) {
|
|
652
|
+
delete this._endpoints[service];
|
|
804
653
|
}
|
|
805
654
|
}
|
|
806
655
|
}
|
|
807
656
|
getEndpoint(service) {
|
|
808
|
-
const endpoint = this.
|
|
657
|
+
const endpoint = this._endpoints[service];
|
|
809
658
|
if (!endpoint) {
|
|
810
659
|
const pathKey = service;
|
|
811
|
-
if (pathKey in this.
|
|
660
|
+
if (pathKey in this._pathProfiles && this._pathProfiles[pathKey] === null) {
|
|
812
661
|
throw new Error(`Service "${service}" is not supported on ${this.platform ?? "this"} platform.`);
|
|
813
662
|
}
|
|
814
663
|
throw new Error(`Service "${service}" is not configured in this provider`);
|
|
@@ -816,13 +665,13 @@ class TimebackProvider {
|
|
|
816
665
|
return endpoint;
|
|
817
666
|
}
|
|
818
667
|
hasService(service) {
|
|
819
|
-
return service in this.
|
|
668
|
+
return service in this._endpoints;
|
|
820
669
|
}
|
|
821
670
|
getAvailableServices() {
|
|
822
|
-
return Object.keys(this.
|
|
671
|
+
return Object.keys(this._endpoints);
|
|
823
672
|
}
|
|
824
673
|
getTokenUrl() {
|
|
825
|
-
return this.
|
|
674
|
+
return this._authUrl;
|
|
826
675
|
}
|
|
827
676
|
getEndpointWithPaths(service) {
|
|
828
677
|
const endpoint = this.getEndpoint(service);
|
|
@@ -830,17 +679,17 @@ class TimebackProvider {
|
|
|
830
679
|
return { ...endpoint, paths };
|
|
831
680
|
}
|
|
832
681
|
getPaths() {
|
|
833
|
-
return this.
|
|
682
|
+
return this._pathProfiles;
|
|
834
683
|
}
|
|
835
684
|
getServicePaths(service) {
|
|
836
|
-
const paths = this.
|
|
685
|
+
const paths = this._pathProfiles[service];
|
|
837
686
|
if (!paths) {
|
|
838
687
|
throw new Error(`Service "${service}" is not supported on ${this.platform ?? "this"} platform.`);
|
|
839
688
|
}
|
|
840
689
|
return paths;
|
|
841
690
|
}
|
|
842
691
|
hasServiceSupport(service) {
|
|
843
|
-
return this.
|
|
692
|
+
return this._pathProfiles[service] !== null;
|
|
844
693
|
}
|
|
845
694
|
getTokenProvider(service) {
|
|
846
695
|
const endpoint = this.getEndpoint(service);
|
|
@@ -851,7 +700,7 @@ class TimebackProvider {
|
|
|
851
700
|
if (!this.auth) {
|
|
852
701
|
throw new Error(`Service "${service}" requires authentication but no credentials were provided`);
|
|
853
702
|
}
|
|
854
|
-
let manager = this.
|
|
703
|
+
let manager = this._tokenManagers.get(authUrl);
|
|
855
704
|
if (!manager) {
|
|
856
705
|
manager = new TokenManager({
|
|
857
706
|
tokenUrl: authUrl,
|
|
@@ -859,28 +708,28 @@ class TimebackProvider {
|
|
|
859
708
|
clientId: this.auth.clientId,
|
|
860
709
|
clientSecret: this.auth.clientSecret
|
|
861
710
|
},
|
|
862
|
-
scope: this.
|
|
711
|
+
scope: this._tokenScope
|
|
863
712
|
});
|
|
864
|
-
this.
|
|
713
|
+
this._tokenManagers.set(authUrl, manager);
|
|
865
714
|
}
|
|
866
715
|
return manager;
|
|
867
716
|
}
|
|
868
717
|
async checkAuth() {
|
|
869
|
-
if (!this.
|
|
718
|
+
if (!this._authUrl || !this.auth) {
|
|
870
719
|
throw new Error("No auth configured on this provider");
|
|
871
720
|
}
|
|
872
721
|
const startTime = Date.now();
|
|
873
|
-
let manager = this.
|
|
722
|
+
let manager = this._tokenManagers.get(this._authUrl);
|
|
874
723
|
if (!manager) {
|
|
875
724
|
manager = new TokenManager({
|
|
876
|
-
tokenUrl: this.
|
|
725
|
+
tokenUrl: this._authUrl,
|
|
877
726
|
credentials: {
|
|
878
727
|
clientId: this.auth.clientId,
|
|
879
728
|
clientSecret: this.auth.clientSecret
|
|
880
729
|
},
|
|
881
|
-
scope: this.
|
|
730
|
+
scope: this._tokenScope
|
|
882
731
|
});
|
|
883
|
-
this.
|
|
732
|
+
this._tokenManagers.set(this._authUrl, manager);
|
|
884
733
|
}
|
|
885
734
|
try {
|
|
886
735
|
await manager.getToken();
|
|
@@ -899,10 +748,10 @@ class TimebackProvider {
|
|
|
899
748
|
}
|
|
900
749
|
}
|
|
901
750
|
invalidateTokens() {
|
|
902
|
-
for (const manager of this.
|
|
751
|
+
for (const manager of this._tokenManagers.values()) {
|
|
903
752
|
manager.invalidate?.();
|
|
904
753
|
}
|
|
905
|
-
this.
|
|
754
|
+
this._tokenManagers.clear();
|
|
906
755
|
}
|
|
907
756
|
}
|
|
908
757
|
// ../../internal/client-infra/src/utils/utils.ts
|
|
@@ -1166,6 +1015,157 @@ function resolveToProvider(config, envVars, registry = DEFAULT_PROVIDER_REGISTRY
|
|
|
1166
1015
|
}
|
|
1167
1016
|
throw new Error(buildMissingEnvError(envVars));
|
|
1168
1017
|
}
|
|
1018
|
+
// ../../internal/client-infra/src/errors/errors.ts
|
|
1019
|
+
class ApiError extends Error {
|
|
1020
|
+
statusCode;
|
|
1021
|
+
response;
|
|
1022
|
+
name = "ApiError";
|
|
1023
|
+
constructor(message, statusCode, response) {
|
|
1024
|
+
super(message);
|
|
1025
|
+
this.statusCode = statusCode;
|
|
1026
|
+
this.response = response;
|
|
1027
|
+
}
|
|
1028
|
+
get minorCodes() {
|
|
1029
|
+
const ims = this.response;
|
|
1030
|
+
if (!ims?.imsx_CodeMinor?.imsx_codeMinorField) {
|
|
1031
|
+
return [];
|
|
1032
|
+
}
|
|
1033
|
+
return ims.imsx_CodeMinor.imsx_codeMinorField.map((field) => ({
|
|
1034
|
+
field: field.imsx_codeMinorFieldName,
|
|
1035
|
+
value: field.imsx_codeMinorFieldValue
|
|
1036
|
+
}));
|
|
1037
|
+
}
|
|
1038
|
+
get details() {
|
|
1039
|
+
const ims = this.response;
|
|
1040
|
+
return ims?.imsx_error_details ?? [];
|
|
1041
|
+
}
|
|
1042
|
+
}
|
|
1043
|
+
|
|
1044
|
+
class UnauthorizedError extends ApiError {
|
|
1045
|
+
name = "UnauthorizedError";
|
|
1046
|
+
constructor(message = "Unauthorized", response) {
|
|
1047
|
+
super(message, 401, response);
|
|
1048
|
+
}
|
|
1049
|
+
}
|
|
1050
|
+
|
|
1051
|
+
class ForbiddenError extends ApiError {
|
|
1052
|
+
name = "ForbiddenError";
|
|
1053
|
+
constructor(message = "Forbidden", response) {
|
|
1054
|
+
super(message, 403, response);
|
|
1055
|
+
}
|
|
1056
|
+
}
|
|
1057
|
+
|
|
1058
|
+
class NotFoundError extends ApiError {
|
|
1059
|
+
name = "NotFoundError";
|
|
1060
|
+
constructor(message = "Not Found", response) {
|
|
1061
|
+
super(message, 404, response);
|
|
1062
|
+
}
|
|
1063
|
+
}
|
|
1064
|
+
|
|
1065
|
+
class ValidationError extends ApiError {
|
|
1066
|
+
name = "ValidationError";
|
|
1067
|
+
constructor(message = "Validation Error", response) {
|
|
1068
|
+
super(message, 422, response);
|
|
1069
|
+
}
|
|
1070
|
+
}
|
|
1071
|
+
|
|
1072
|
+
class InputValidationError extends ApiError {
|
|
1073
|
+
name = "InputValidationError";
|
|
1074
|
+
issues;
|
|
1075
|
+
constructor(message, issues) {
|
|
1076
|
+
const response = {
|
|
1077
|
+
imsx_codeMajor: "failure",
|
|
1078
|
+
imsx_severity: "error",
|
|
1079
|
+
imsx_description: message,
|
|
1080
|
+
imsx_error_details: issues.map((issue) => ({
|
|
1081
|
+
path: issue.path,
|
|
1082
|
+
message: issue.message
|
|
1083
|
+
}))
|
|
1084
|
+
};
|
|
1085
|
+
super(message, 400, response);
|
|
1086
|
+
this.issues = issues;
|
|
1087
|
+
}
|
|
1088
|
+
}
|
|
1089
|
+
function createInputValidationError(message, issues) {
|
|
1090
|
+
return new InputValidationError(message, issues);
|
|
1091
|
+
}
|
|
1092
|
+
function isApiError(error) {
|
|
1093
|
+
if (!(error instanceof Error))
|
|
1094
|
+
return false;
|
|
1095
|
+
return "statusCode" in error && "response" in error;
|
|
1096
|
+
}
|
|
1097
|
+
// ../../internal/client-infra/src/filter/where/where.ts
|
|
1098
|
+
function escapeValue(value) {
|
|
1099
|
+
if (value instanceof Date) {
|
|
1100
|
+
return value.toISOString();
|
|
1101
|
+
}
|
|
1102
|
+
if (typeof value === "boolean") {
|
|
1103
|
+
return value ? "true" : "false";
|
|
1104
|
+
}
|
|
1105
|
+
if (typeof value === "number") {
|
|
1106
|
+
return String(value);
|
|
1107
|
+
}
|
|
1108
|
+
return value.replaceAll("'", "''");
|
|
1109
|
+
}
|
|
1110
|
+
function formatValue2(value) {
|
|
1111
|
+
const escaped = escapeValue(value);
|
|
1112
|
+
const needsQuotes = typeof value === "string" || value instanceof Date;
|
|
1113
|
+
return needsQuotes ? `'${escaped}'` : escaped;
|
|
1114
|
+
}
|
|
1115
|
+
function fieldToConditions(field, condition) {
|
|
1116
|
+
if (typeof condition === "string" || typeof condition === "number" || typeof condition === "boolean" || condition instanceof Date) {
|
|
1117
|
+
return [`${field}=${formatValue2(condition)}`];
|
|
1118
|
+
}
|
|
1119
|
+
if (typeof condition === "object" && condition !== null) {
|
|
1120
|
+
const ops = condition;
|
|
1121
|
+
const conditions = [];
|
|
1122
|
+
if (ops.ne !== undefined) {
|
|
1123
|
+
conditions.push(`${field}!=${formatValue2(ops.ne)}`);
|
|
1124
|
+
}
|
|
1125
|
+
if (ops.gt !== undefined) {
|
|
1126
|
+
conditions.push(`${field}>${formatValue2(ops.gt)}`);
|
|
1127
|
+
}
|
|
1128
|
+
if (ops.gte !== undefined) {
|
|
1129
|
+
conditions.push(`${field}>=${formatValue2(ops.gte)}`);
|
|
1130
|
+
}
|
|
1131
|
+
if (ops.lt !== undefined) {
|
|
1132
|
+
conditions.push(`${field}<${formatValue2(ops.lt)}`);
|
|
1133
|
+
}
|
|
1134
|
+
if (ops.lte !== undefined) {
|
|
1135
|
+
conditions.push(`${field}<=${formatValue2(ops.lte)}`);
|
|
1136
|
+
}
|
|
1137
|
+
if (ops.contains !== undefined) {
|
|
1138
|
+
conditions.push(`${field}~${formatValue2(ops.contains)}`);
|
|
1139
|
+
}
|
|
1140
|
+
if (ops.in !== undefined && ops.in.length > 0) {
|
|
1141
|
+
const inConditions = ops.in.map((v) => `${field}=${formatValue2(v)}`);
|
|
1142
|
+
const joined = inConditions.join(" OR ");
|
|
1143
|
+
conditions.push(inConditions.length > 1 ? `(${joined})` : joined);
|
|
1144
|
+
}
|
|
1145
|
+
if (ops.notIn !== undefined && ops.notIn.length > 0) {
|
|
1146
|
+
const notInConditions = ops.notIn.map((v) => `${field}!=${formatValue2(v)}`);
|
|
1147
|
+
conditions.push(notInConditions.join(" AND "));
|
|
1148
|
+
}
|
|
1149
|
+
return conditions;
|
|
1150
|
+
}
|
|
1151
|
+
return [];
|
|
1152
|
+
}
|
|
1153
|
+
function isOrCondition(clause) {
|
|
1154
|
+
return "OR" in clause && Array.isArray(clause.OR);
|
|
1155
|
+
}
|
|
1156
|
+
function whereToFilter(where) {
|
|
1157
|
+
if (isOrCondition(where)) {
|
|
1158
|
+
const orParts = where.OR.map((clause) => whereToFilter(clause)).filter((s) => s !== undefined);
|
|
1159
|
+
return orParts.length > 0 ? orParts.join(" OR ") : undefined;
|
|
1160
|
+
}
|
|
1161
|
+
const conditions = [];
|
|
1162
|
+
for (const [field, condition] of Object.entries(where)) {
|
|
1163
|
+
if (condition !== undefined) {
|
|
1164
|
+
conditions.push(...fieldToConditions(field, condition));
|
|
1165
|
+
}
|
|
1166
|
+
}
|
|
1167
|
+
return conditions.length > 0 ? conditions.join(" AND ") : undefined;
|
|
1168
|
+
}
|
|
1169
1169
|
// ../../internal/client-infra/src/transport/constants.ts
|
|
1170
1170
|
var MAX_RETRIES = 3;
|
|
1171
1171
|
var RETRY_STATUS_CODES = [429, 503];
|
|
@@ -1640,4 +1640,4 @@ function validateUuid(value, context) {
|
|
|
1640
1640
|
]);
|
|
1641
1641
|
}
|
|
1642
1642
|
}
|
|
1643
|
-
export { PLATFORM_LEARNWITH_AI, DEFAULT_PLATFORM, PLATFORM_ENDPOINTS, createScopedLogger, DEFAULT_PROVIDER_REGISTRY, resolveToProvider, ApiError, UnauthorizedError, ForbiddenError, NotFoundError, ValidationError, createInputValidationError, isApiError, BaseTransport, whereToFilter, Paginator, parseHeaderPagination, parseBodyPaginationRaw, validateWithSchema, validateNonEmptyString, validateOffsetListParams, validatePageListParams, validateSourcedId, validateUuid };
|
|
1643
|
+
export { PLATFORM_LEARNWITH_AI, DEFAULT_PLATFORM, PLATFORM_ENDPOINTS, TimebackProvider, createScopedLogger, DEFAULT_PROVIDER_REGISTRY, resolveToProvider, ApiError, UnauthorizedError, ForbiddenError, NotFoundError, ValidationError, createInputValidationError, isApiError, BaseTransport, whereToFilter, Paginator, parseHeaderPagination, parseBodyPaginationRaw, validateWithSchema, validateNonEmptyString, validateOffsetListParams, validatePageListParams, validateSourcedId, validateUuid };
|
package/dist/errors.d.ts
CHANGED
|
@@ -1,7 +1,97 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Error Classes
|
|
2
|
+
* API Error Classes
|
|
3
3
|
*
|
|
4
|
-
*
|
|
4
|
+
* Base error classes for HTTP API failures.
|
|
5
|
+
* Includes IMS Global error response parsing (OneRoster, QTI, etc.).
|
|
5
6
|
*/
|
|
6
|
-
|
|
7
|
-
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* Base error class for all API errors.
|
|
10
|
+
*
|
|
11
|
+
* Provides access to the HTTP status code and raw response body.
|
|
12
|
+
* Includes IMS Global error parsing (minorCodes, details) for
|
|
13
|
+
* IMS-standard APIs like OneRoster and QTI.
|
|
14
|
+
*
|
|
15
|
+
* @example
|
|
16
|
+
* ```typescript
|
|
17
|
+
* // Catching and inspecting errors
|
|
18
|
+
* try {
|
|
19
|
+
* await client.users.get('non-existent-id')
|
|
20
|
+
* } catch (error) {
|
|
21
|
+
* if (error instanceof ApiError) {
|
|
22
|
+
* console.log(`Error ${error.statusCode}: ${error.message}`)
|
|
23
|
+
* console.log('Minor codes:', error.minorCodes)
|
|
24
|
+
* console.log('Details:', error.details)
|
|
25
|
+
* }
|
|
26
|
+
* }
|
|
27
|
+
* ```
|
|
28
|
+
*/
|
|
29
|
+
declare class ApiError extends Error {
|
|
30
|
+
readonly statusCode?: number | undefined;
|
|
31
|
+
readonly response?: unknown;
|
|
32
|
+
readonly name: string;
|
|
33
|
+
/**
|
|
34
|
+
* Creates a new ApiError.
|
|
35
|
+
*
|
|
36
|
+
* @param message - Human-readable error message
|
|
37
|
+
* @param statusCode - HTTP status code
|
|
38
|
+
* @param response - Raw response body (if available)
|
|
39
|
+
*/
|
|
40
|
+
constructor(message: string, statusCode?: number | undefined, response?: unknown);
|
|
41
|
+
/**
|
|
42
|
+
* Minor error codes from IMS Global error response.
|
|
43
|
+
*
|
|
44
|
+
* For IMS-standard APIs (OneRoster, QTI), provides specific error codes
|
|
45
|
+
* like "unknownobject" or "invaliddata".
|
|
46
|
+
*
|
|
47
|
+
* @returns Array of field/value pairs, or empty array if not IMS format
|
|
48
|
+
*/
|
|
49
|
+
get minorCodes(): Array<{
|
|
50
|
+
field: string;
|
|
51
|
+
value: string;
|
|
52
|
+
}>;
|
|
53
|
+
/**
|
|
54
|
+
* Additional error details from IMS Global response.
|
|
55
|
+
*
|
|
56
|
+
* May contain field-level validation errors or other structured details.
|
|
57
|
+
*
|
|
58
|
+
* @returns Array of key-value objects, or empty array if not present
|
|
59
|
+
*/
|
|
60
|
+
get details(): Array<Record<string, string>>;
|
|
61
|
+
}
|
|
62
|
+
/**
|
|
63
|
+
* Error thrown when authentication fails (HTTP 401).
|
|
64
|
+
*
|
|
65
|
+
* Typically indicates invalid or expired credentials.
|
|
66
|
+
*/
|
|
67
|
+
declare class UnauthorizedError extends ApiError {
|
|
68
|
+
readonly name = "UnauthorizedError";
|
|
69
|
+
constructor(message?: string, response?: unknown);
|
|
70
|
+
}
|
|
71
|
+
/**
|
|
72
|
+
* Error thrown when the client lacks permission for the operation (HTTP 403).
|
|
73
|
+
*
|
|
74
|
+
* The credentials are valid, but the client is not authorized for this action.
|
|
75
|
+
*/
|
|
76
|
+
declare class ForbiddenError extends ApiError {
|
|
77
|
+
readonly name = "ForbiddenError";
|
|
78
|
+
constructor(message?: string, response?: unknown);
|
|
79
|
+
}
|
|
80
|
+
/**
|
|
81
|
+
* Error thrown when a requested resource is not found (HTTP 404).
|
|
82
|
+
*/
|
|
83
|
+
declare class NotFoundError extends ApiError {
|
|
84
|
+
readonly name = "NotFoundError";
|
|
85
|
+
constructor(message?: string, response?: unknown);
|
|
86
|
+
}
|
|
87
|
+
/**
|
|
88
|
+
* Error thrown when request data is invalid (HTTP 422).
|
|
89
|
+
*
|
|
90
|
+
* Check the `details` property for field-level validation errors.
|
|
91
|
+
*/
|
|
92
|
+
declare class ValidationError extends ApiError {
|
|
93
|
+
readonly name = "ValidationError";
|
|
94
|
+
constructor(message?: string, response?: unknown);
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
export { ApiError, ForbiddenError, NotFoundError, UnauthorizedError, ValidationError };
|