@go-avro/avro-js 0.0.2-beta.80 → 0.0.2-beta.82
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/auth/AuthManager.js
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { StandardError } from '../types/error';
|
|
1
2
|
export class AuthManager {
|
|
2
3
|
constructor({ baseUrl, storage, }) {
|
|
3
4
|
this.tokenRefreshedCallbacks = [];
|
|
@@ -76,7 +77,7 @@ export class AuthManager {
|
|
|
76
77
|
storage.clear();
|
|
77
78
|
}
|
|
78
79
|
}
|
|
79
|
-
throw new
|
|
80
|
+
throw new StandardError(410, 'Failed to refresh tokens from all storages');
|
|
80
81
|
}
|
|
81
82
|
async accessToken() {
|
|
82
83
|
if (!this.storages.length) {
|
|
@@ -108,7 +109,9 @@ export class AuthManager {
|
|
|
108
109
|
}
|
|
109
110
|
catch (error) {
|
|
110
111
|
this.tokenRefreshFailedCallbacks.forEach(cb => cb());
|
|
111
|
-
|
|
112
|
+
if (error?.status !== 410) {
|
|
113
|
+
console.error('Failed to refresh tokens:', error);
|
|
114
|
+
}
|
|
112
115
|
return null;
|
|
113
116
|
}
|
|
114
117
|
}
|
|
@@ -17,6 +17,7 @@ declare module '../client/QueryClient' {
|
|
|
17
17
|
_xhr<T>(method: string, path: string, body: any, cancelToken?: CancelToken, headers?: Record<string, string>, isIdempotent?: boolean, retryCount?: number, progressUpdateCallback?: (loaded: number, total: number) => void): Promise<T>;
|
|
18
18
|
_fetch<T>(method: string, path: string, body: any, cancelToken?: CancelToken, headers?: Record<string, string>, isIdempotent?: boolean, retryCount?: number): Promise<T>;
|
|
19
19
|
getDelay(strategy: RetryStrategy, attempt: number): number;
|
|
20
|
+
sleep(ms: number): Promise<void>;
|
|
20
21
|
useGetRoot(): UseQueryResult<ApiInfo, StandardError>;
|
|
21
22
|
useGetJobs(companyGuid: string, body: {
|
|
22
23
|
amt?: number;
|
|
@@ -104,7 +104,7 @@ export class AvroQueryClient {
|
|
|
104
104
|
const queryClient = useQueryClient();
|
|
105
105
|
return useMutation({
|
|
106
106
|
mutationFn: async ({ token, cancelToken }) => {
|
|
107
|
-
const resp = await this.
|
|
107
|
+
const resp = await this._xhr('POST', `/google/authorize?token=${token}`, {}, cancelToken, { 'Content-Type': 'application/json' });
|
|
108
108
|
if (!resp || !('access_token' in resp)) {
|
|
109
109
|
if (resp.msg === "TOTP email sent") {
|
|
110
110
|
return LoginResponse.NEEDS_TOTP;
|
|
@@ -123,7 +123,7 @@ export class AvroQueryClient {
|
|
|
123
123
|
},
|
|
124
124
|
onError: (err) => {
|
|
125
125
|
this.config.authManager.clearTokens();
|
|
126
|
-
throw new StandardError(
|
|
126
|
+
throw new StandardError(err.status, err.message || 'Google Login failed');
|
|
127
127
|
}
|
|
128
128
|
});
|
|
129
129
|
}
|
|
@@ -1,67 +1,63 @@
|
|
|
1
1
|
import { AvroQueryClient } from '../../client/QueryClient';
|
|
2
2
|
import { StandardError } from '../../types/error';
|
|
3
|
-
AvroQueryClient.prototype._fetch = function (method, path, body, cancelToken, headers = {}, isIdempotent = false, retryCount = 0) {
|
|
3
|
+
AvroQueryClient.prototype._fetch = async function (method, path, body, cancelToken, headers = {}, isIdempotent = false, retryCount = 0) {
|
|
4
4
|
const checkCancelled = () => {
|
|
5
5
|
try {
|
|
6
6
|
if (cancelToken?.isCancelled()) {
|
|
7
|
-
|
|
7
|
+
throw new StandardError(0, 'Request cancelled');
|
|
8
8
|
}
|
|
9
9
|
}
|
|
10
10
|
catch (error) {
|
|
11
|
-
throw new StandardError(0, `Error checking cancellation
|
|
11
|
+
throw new StandardError(0, `Error checking cancellation: ${error.message}`);
|
|
12
12
|
}
|
|
13
|
-
return null;
|
|
14
13
|
};
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
14
|
+
try {
|
|
15
|
+
checkCancelled();
|
|
16
|
+
const token = await this.config.authManager.accessToken();
|
|
17
|
+
checkCancelled();
|
|
19
18
|
const url = this.config.baseUrl + path;
|
|
20
19
|
const requestHeaders = {
|
|
21
20
|
'Content-Type': 'application/json',
|
|
21
|
+
Authorization: `Bearer ${token}`,
|
|
22
22
|
...headers,
|
|
23
23
|
};
|
|
24
|
-
if (token) {
|
|
25
|
-
requestHeaders['Authorization'] = `Bearer ${token}`;
|
|
26
|
-
}
|
|
27
24
|
const options = {
|
|
28
25
|
method,
|
|
29
26
|
headers: requestHeaders,
|
|
30
|
-
body: body ? JSON.stringify(body) :
|
|
27
|
+
body: body ? JSON.stringify(body) : undefined,
|
|
31
28
|
};
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
.catch(() => Promise.reject(new StandardError(401, 'Unauthorized (refresh failed)')));
|
|
38
|
-
}
|
|
39
|
-
if (!response.ok) {
|
|
40
|
-
if (retryCount < this.config.maxRetries) {
|
|
41
|
-
const delay = this.getDelay(this.config.retryStrategy, retryCount);
|
|
42
|
-
return new Promise((resolve, reject) => {
|
|
43
|
-
setTimeout(() => {
|
|
44
|
-
this._fetch(method, path, body, cancelToken, headers, isIdempotent, retryCount + 1)
|
|
45
|
-
.then(resolve)
|
|
46
|
-
.catch(reject);
|
|
47
|
-
}, delay);
|
|
48
|
-
});
|
|
49
|
-
}
|
|
50
|
-
else {
|
|
51
|
-
return response.text().then(text => {
|
|
52
|
-
let msg = response.statusText;
|
|
53
|
-
try {
|
|
54
|
-
const parsed = JSON.parse(text);
|
|
55
|
-
msg = parsed.message || msg;
|
|
56
|
-
}
|
|
57
|
-
catch {
|
|
58
|
-
console.warn('Failed to parse error response:', text);
|
|
59
|
-
}
|
|
60
|
-
throw new StandardError(response.status, msg);
|
|
61
|
-
});
|
|
62
|
-
}
|
|
29
|
+
const response = await fetch(url, options);
|
|
30
|
+
if (response.ok) {
|
|
31
|
+
const text = await response.text();
|
|
32
|
+
if (!text) {
|
|
33
|
+
return undefined;
|
|
63
34
|
}
|
|
64
|
-
return
|
|
65
|
-
}
|
|
66
|
-
|
|
35
|
+
return JSON.parse(text);
|
|
36
|
+
}
|
|
37
|
+
if (response.status === 401 && this.config.authManager.refreshTokens && retryCount === 0) {
|
|
38
|
+
await this.config.authManager.refreshTokens();
|
|
39
|
+
return this._fetch(method, path, body, cancelToken, headers, isIdempotent, 1);
|
|
40
|
+
}
|
|
41
|
+
if (retryCount < this.config.maxRetries) {
|
|
42
|
+
const delay = this.getDelay(this.config.retryStrategy, retryCount);
|
|
43
|
+
await this.sleep(delay);
|
|
44
|
+
return this._fetch(method, path, body, cancelToken, headers, isIdempotent, retryCount + 1);
|
|
45
|
+
}
|
|
46
|
+
let errorMessage = response.statusText;
|
|
47
|
+
try {
|
|
48
|
+
const parsedError = await response.json();
|
|
49
|
+
errorMessage = parsedError.message ?? parsedError.msg ?? errorMessage;
|
|
50
|
+
}
|
|
51
|
+
catch (e) {
|
|
52
|
+
console.error('Ignoring:', e);
|
|
53
|
+
}
|
|
54
|
+
throw new StandardError(response.status, errorMessage);
|
|
55
|
+
}
|
|
56
|
+
catch (error) {
|
|
57
|
+
if (error instanceof StandardError) {
|
|
58
|
+
throw error;
|
|
59
|
+
}
|
|
60
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
61
|
+
throw new StandardError(0, `Request failed: ${message}`);
|
|
62
|
+
}
|
|
67
63
|
};
|
package/dist/client/core/xhr.js
CHANGED
|
@@ -1,87 +1,84 @@
|
|
|
1
1
|
import { AvroQueryClient } from '../../client/QueryClient';
|
|
2
2
|
import { StandardError } from '../../types/error';
|
|
3
|
-
AvroQueryClient.prototype._xhr = function (method, path, body, cancelToken, headers = {}, isIdempotent = false, retryCount = 0, progressUpdateCallback) {
|
|
3
|
+
AvroQueryClient.prototype._xhr = async function (method, path, body, cancelToken, headers = {}, isIdempotent = false, retryCount = 0, progressUpdateCallback) {
|
|
4
4
|
const checkCancelled = () => {
|
|
5
5
|
if (cancelToken?.isCancelled()) {
|
|
6
|
-
|
|
6
|
+
throw new StandardError(0, 'Request cancelled');
|
|
7
7
|
}
|
|
8
|
-
return null;
|
|
9
8
|
};
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
const
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
if (xhr.status >= 200 && xhr.status < 300) {
|
|
35
|
-
try {
|
|
36
|
-
resolve(JSON.parse(xhr.responseText));
|
|
37
|
-
}
|
|
38
|
-
catch {
|
|
39
|
-
resolve(xhr.responseText);
|
|
40
|
-
}
|
|
41
|
-
}
|
|
42
|
-
else {
|
|
43
|
-
if (retryCount < this.config.maxRetries) {
|
|
44
|
-
const delay = this.getDelay(this.config.retryStrategy, retryCount);
|
|
45
|
-
setTimeout(() => {
|
|
46
|
-
this._xhr(method, path, body, cancelToken, headers, isIdempotent, retryCount + 1).then(resolve, reject);
|
|
47
|
-
}, delay);
|
|
9
|
+
for (let attempt = 0; attempt <= this.config.maxRetries; attempt++) {
|
|
10
|
+
try {
|
|
11
|
+
checkCancelled();
|
|
12
|
+
const token = await this.config.authManager.accessToken();
|
|
13
|
+
checkCancelled();
|
|
14
|
+
const result = await new Promise((resolve, reject) => {
|
|
15
|
+
const xhr = new XMLHttpRequest();
|
|
16
|
+
const url = this.config.baseUrl + path;
|
|
17
|
+
xhr.open(method, url, true);
|
|
18
|
+
if (token)
|
|
19
|
+
xhr.setRequestHeader('Authorization', `Bearer ${token}`);
|
|
20
|
+
Object.entries(headers).forEach(([key, value]) => xhr.setRequestHeader(key, value));
|
|
21
|
+
xhr.onload = () => {
|
|
22
|
+
if (xhr.status >= 200 && xhr.status < 300) {
|
|
23
|
+
try {
|
|
24
|
+
const responseText = xhr.responseText;
|
|
25
|
+
if (!responseText) {
|
|
26
|
+
return resolve(undefined);
|
|
27
|
+
}
|
|
28
|
+
resolve(JSON.parse(responseText));
|
|
29
|
+
}
|
|
30
|
+
catch (e) {
|
|
31
|
+
reject(new StandardError(0, `Failed to parse successful response: ${e.message}`));
|
|
32
|
+
}
|
|
48
33
|
}
|
|
49
34
|
else {
|
|
50
|
-
let msg = xhr.statusText;
|
|
35
|
+
let msg = xhr.responseText || xhr.statusText;
|
|
51
36
|
try {
|
|
52
37
|
const parsed = JSON.parse(xhr.responseText);
|
|
53
|
-
msg = parsed.msg
|
|
38
|
+
msg = parsed.message ?? parsed.msg ?? msg;
|
|
54
39
|
}
|
|
55
|
-
catch {
|
|
56
|
-
console.
|
|
40
|
+
catch (e) {
|
|
41
|
+
console.error('Ignoring:', e);
|
|
57
42
|
}
|
|
58
43
|
reject(new StandardError(xhr.status, msg));
|
|
59
44
|
}
|
|
60
|
-
}
|
|
61
|
-
};
|
|
62
|
-
if (progressUpdateCallback && xhr.upload) {
|
|
63
|
-
xhr.upload.onprogress = (event) => {
|
|
64
|
-
if (event.lengthComputable) {
|
|
65
|
-
progressUpdateCallback(event.loaded, event.total);
|
|
66
|
-
}
|
|
67
45
|
};
|
|
46
|
+
xhr.onerror = () => reject(new StandardError(0, 'Network Error'));
|
|
47
|
+
if (this.config.timeout) {
|
|
48
|
+
xhr.timeout = this.config.timeout;
|
|
49
|
+
xhr.ontimeout = () => reject(new StandardError(0, 'Request timed out'));
|
|
50
|
+
}
|
|
51
|
+
if (progressUpdateCallback && xhr.upload) {
|
|
52
|
+
xhr.upload.onprogress = (event) => {
|
|
53
|
+
if (event.lengthComputable) {
|
|
54
|
+
progressUpdateCallback(event.loaded, event.total);
|
|
55
|
+
}
|
|
56
|
+
};
|
|
57
|
+
}
|
|
58
|
+
xhr.send(body);
|
|
59
|
+
});
|
|
60
|
+
return result;
|
|
61
|
+
}
|
|
62
|
+
catch (error) {
|
|
63
|
+
if (!(error instanceof StandardError)) {
|
|
64
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
65
|
+
throw new StandardError(0, `An unexpected error occurred: ${message}`);
|
|
68
66
|
}
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
this._xhr(method, path, body, cancelToken, headers, isIdempotent, retryCount + 1).then(resolve, reject);
|
|
74
|
-
}, delay);
|
|
67
|
+
if (error.status === 401 && this.config.authManager.refreshTokens && attempt === 0) {
|
|
68
|
+
try {
|
|
69
|
+
await this.config.authManager.refreshTokens();
|
|
70
|
+
continue;
|
|
75
71
|
}
|
|
76
|
-
|
|
77
|
-
|
|
72
|
+
catch (refreshError) {
|
|
73
|
+
throw new StandardError(401, 'Unauthorized (refresh failed)');
|
|
78
74
|
}
|
|
79
|
-
};
|
|
80
|
-
if (this.config.timeout) {
|
|
81
|
-
xhr.timeout = this.config.timeout;
|
|
82
|
-
xhr.ontimeout = () => reject(new StandardError(0, 'Request timed out'));
|
|
83
75
|
}
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
76
|
+
if (attempt >= this.config.maxRetries) {
|
|
77
|
+
throw error;
|
|
78
|
+
}
|
|
79
|
+
const delay = this.getDelay(this.config.retryStrategy, attempt);
|
|
80
|
+
await this.sleep(delay);
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
throw new StandardError(0, 'Request failed after maximum retries.');
|
|
87
84
|
};
|