@go-avro/avro-js 0.0.2-beta.9 → 0.0.2-beta.91
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/README.md +1 -0
- package/dist/auth/AuthManager.d.ts +4 -0
- package/dist/auth/AuthManager.js +18 -2
- package/dist/client/QueryClient.d.ts +349 -15
- package/dist/client/QueryClient.js +303 -195
- package/dist/client/core/fetch.d.ts +1 -0
- package/dist/client/core/fetch.js +62 -0
- package/dist/client/core/utils.d.ts +1 -0
- package/dist/client/core/utils.js +14 -0
- package/dist/client/core/xhr.d.ts +1 -0
- package/dist/client/core/xhr.js +84 -0
- package/dist/client/hooks/analytics.d.ts +1 -0
- package/dist/client/hooks/analytics.js +10 -0
- package/dist/client/hooks/avro.d.ts +1 -0
- package/dist/client/hooks/avro.js +9 -0
- package/dist/client/hooks/bills.d.ts +1 -0
- package/dist/client/hooks/bills.js +141 -0
- package/dist/client/hooks/chats.d.ts +1 -0
- package/dist/client/hooks/chats.js +37 -0
- package/dist/client/hooks/companies.d.ts +1 -0
- package/dist/client/hooks/companies.js +79 -0
- package/dist/client/hooks/events.d.ts +1 -0
- package/dist/client/hooks/events.js +307 -0
- package/dist/client/hooks/jobs.d.ts +1 -0
- package/dist/client/hooks/jobs.js +185 -0
- package/dist/client/hooks/messages.d.ts +1 -0
- package/dist/client/hooks/messages.js +30 -0
- package/dist/client/hooks/months.d.ts +1 -0
- package/dist/client/hooks/months.js +92 -0
- package/dist/client/hooks/plans.d.ts +1 -0
- package/dist/client/hooks/plans.js +9 -0
- package/dist/client/hooks/root.d.ts +1 -0
- package/dist/client/hooks/root.js +8 -0
- package/dist/client/hooks/routes.d.ts +1 -0
- package/dist/client/hooks/routes.js +123 -0
- package/dist/client/hooks/sessions.d.ts +1 -0
- package/dist/client/hooks/sessions.js +154 -0
- package/dist/client/hooks/teams.d.ts +1 -0
- package/dist/client/hooks/teams.js +117 -0
- package/dist/client/hooks/users.d.ts +1 -0
- package/dist/client/hooks/users.js +104 -0
- package/dist/index.d.ts +19 -0
- package/dist/index.js +19 -0
- package/dist/types/api.d.ts +118 -29
- package/dist/types/api.js +10 -1
- package/package.json +6 -1
|
@@ -1,6 +1,10 @@
|
|
|
1
|
+
import io from 'socket.io-client';
|
|
2
|
+
import { useMutation, useQueryClient } from '@tanstack/react-query';
|
|
3
|
+
import { LoginResponse } from '../types/api';
|
|
1
4
|
import { StandardError } from '../types/error';
|
|
2
5
|
export class AvroQueryClient {
|
|
3
6
|
constructor(config) {
|
|
7
|
+
this._isAuthenticated = false;
|
|
4
8
|
this.config = {
|
|
5
9
|
baseUrl: config.baseUrl,
|
|
6
10
|
authManager: config.authManager,
|
|
@@ -8,228 +12,249 @@ export class AvroQueryClient {
|
|
|
8
12
|
retryStrategy: config.retryStrategy ?? 'fixed',
|
|
9
13
|
timeout: config.timeout ?? 0,
|
|
10
14
|
};
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
15
|
+
config.authManager.isAuthenticated().then(isAuth => {
|
|
16
|
+
this._isAuthenticated = isAuth;
|
|
17
|
+
});
|
|
18
|
+
this.socket = io(config.baseUrl, { autoConnect: false, transports: ["websocket"], });
|
|
19
|
+
if (!this.socket.connected) {
|
|
20
|
+
this.config.authManager.accessToken().then(token => {
|
|
21
|
+
console.log('Initializing socket connection with token...');
|
|
22
|
+
this.socket.auth = { token: token };
|
|
23
|
+
this.socket.connect();
|
|
24
|
+
});
|
|
18
25
|
}
|
|
19
|
-
|
|
20
|
-
|
|
26
|
+
this.socket.on('connect', () => {
|
|
27
|
+
this._isAuthenticated = true;
|
|
28
|
+
console.log(`Socket connected with ID: ${this.socket?.id}`);
|
|
29
|
+
});
|
|
30
|
+
this.socket.on('disconnect', (reason) => {
|
|
31
|
+
console.log(`Socket disconnected: ${reason}`);
|
|
32
|
+
});
|
|
33
|
+
this.socket.on('connect_error', (err) => {
|
|
34
|
+
console.error(`Socket connection error: ${err.message}`);
|
|
35
|
+
});
|
|
36
|
+
this.config.authManager.onTokenRefreshed((newAccessToken) => {
|
|
37
|
+
if (this.socket && newAccessToken) {
|
|
38
|
+
this._isAuthenticated = true;
|
|
39
|
+
console.log('Access token refreshed, updating socket auth...');
|
|
40
|
+
this.socket.auth = { token: newAccessToken };
|
|
41
|
+
this.socket.disconnect().connect();
|
|
42
|
+
}
|
|
43
|
+
});
|
|
44
|
+
config.authManager.onTokenRefreshFailed(() => {
|
|
45
|
+
this._isAuthenticated = false;
|
|
46
|
+
if (this.socket && this.socket.connected) {
|
|
47
|
+
this.socket.disconnect();
|
|
48
|
+
}
|
|
49
|
+
});
|
|
50
|
+
}
|
|
51
|
+
emit(eventName, data) {
|
|
52
|
+
if (!this.socket?.connected) {
|
|
53
|
+
console.error('Socket is not connected. Cannot emit event.');
|
|
54
|
+
return;
|
|
21
55
|
}
|
|
22
|
-
|
|
56
|
+
this.socket.emit(eventName, data);
|
|
23
57
|
}
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
return this.config.
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
this.config.authManager
|
|
51
|
-
.refreshTokens()
|
|
52
|
-
.then(() => {
|
|
53
|
-
this._xhr(method, path, body, cancelToken, headers, isIdempotent, retryCount + 1).then(resolve, reject);
|
|
54
|
-
})
|
|
55
|
-
.catch(() => {
|
|
56
|
-
reject(new StandardError(401, 'Unauthorized (refresh failed)'));
|
|
57
|
-
});
|
|
58
|
-
return;
|
|
59
|
-
}
|
|
60
|
-
if (xhr.status >= 200 && xhr.status < 300) {
|
|
61
|
-
try {
|
|
62
|
-
resolve(JSON.parse(xhr.responseText));
|
|
63
|
-
}
|
|
64
|
-
catch {
|
|
65
|
-
resolve(xhr.responseText);
|
|
66
|
-
}
|
|
67
|
-
}
|
|
68
|
-
else {
|
|
69
|
-
if (retryCount < this.config.maxRetries) {
|
|
70
|
-
const delay = this.getDelay(this.config.retryStrategy, retryCount);
|
|
71
|
-
setTimeout(() => {
|
|
72
|
-
this._xhr(method, path, body, cancelToken, headers, isIdempotent, retryCount + 1).then(resolve, reject);
|
|
73
|
-
}, delay);
|
|
74
|
-
}
|
|
75
|
-
else {
|
|
76
|
-
let msg = xhr.statusText;
|
|
77
|
-
try {
|
|
78
|
-
const parsed = JSON.parse(xhr.responseText);
|
|
79
|
-
msg = parsed.message || msg;
|
|
80
|
-
}
|
|
81
|
-
catch {
|
|
82
|
-
console.warn('Failed to parse error response:', xhr.responseText);
|
|
83
|
-
}
|
|
84
|
-
reject(new StandardError(xhr.status, msg));
|
|
85
|
-
}
|
|
86
|
-
}
|
|
87
|
-
};
|
|
88
|
-
xhr.onerror = () => {
|
|
89
|
-
if (retryCount < this.config.maxRetries) {
|
|
90
|
-
const delay = this.getDelay(this.config.retryStrategy, retryCount);
|
|
91
|
-
setTimeout(() => {
|
|
92
|
-
this._xhr(method, path, body, cancelToken, headers, isIdempotent, retryCount + 1).then(resolve, reject);
|
|
93
|
-
}, delay);
|
|
94
|
-
}
|
|
95
|
-
else {
|
|
96
|
-
reject(new StandardError(0, 'Network Error'));
|
|
58
|
+
on(eventName, callback) {
|
|
59
|
+
this.socket?.on(eventName, callback);
|
|
60
|
+
}
|
|
61
|
+
off(eventName, callback) {
|
|
62
|
+
this.socket?.off(eventName, callback);
|
|
63
|
+
}
|
|
64
|
+
get(path, cancelToken, headers = {}, progressUpdateCallback) {
|
|
65
|
+
return this._xhr('GET', path, null, cancelToken, headers, true, this.config.maxRetries, progressUpdateCallback);
|
|
66
|
+
}
|
|
67
|
+
post(path, data, cancelToken, headers = {}, progressUpdateCallback) {
|
|
68
|
+
return this._xhr('POST', path, data, cancelToken, headers, false, this.config.maxRetries, progressUpdateCallback);
|
|
69
|
+
}
|
|
70
|
+
put(path, data, cancelToken, headers = {}, progressUpdateCallback) {
|
|
71
|
+
return this._xhr('PUT', path, data, cancelToken, headers, true, this.config.maxRetries, progressUpdateCallback);
|
|
72
|
+
}
|
|
73
|
+
delete(path, cancelToken, headers = {}, progressUpdateCallback) {
|
|
74
|
+
return this._xhr('DELETE', path, null, cancelToken, headers, false, this.config.maxRetries, progressUpdateCallback);
|
|
75
|
+
}
|
|
76
|
+
useLogin() {
|
|
77
|
+
const queryClient = useQueryClient();
|
|
78
|
+
return useMutation({
|
|
79
|
+
mutationFn: async ({ username, password, code, cancelToken }) => {
|
|
80
|
+
const resp = await this.post('/login', JSON.stringify({ username, password, code }), cancelToken, { 'Content-Type': 'application/json' });
|
|
81
|
+
if (!resp || !('access_token' in resp)) {
|
|
82
|
+
if (resp.msg === "TOTP required") {
|
|
83
|
+
return LoginResponse.NEEDS_TOTP;
|
|
97
84
|
}
|
|
98
|
-
|
|
99
|
-
if (this.config.timeout) {
|
|
100
|
-
xhr.timeout = this.config.timeout;
|
|
101
|
-
xhr.ontimeout = () => reject(new StandardError(0, 'Request timed out'));
|
|
85
|
+
throw new StandardError(401, 'Invalid login response');
|
|
102
86
|
}
|
|
103
|
-
|
|
104
|
-
|
|
87
|
+
this._isAuthenticated = true;
|
|
88
|
+
this.socket.auth = { token: resp.access_token };
|
|
89
|
+
if (!this.socket.connected) {
|
|
90
|
+
this.socket.connect();
|
|
91
|
+
}
|
|
92
|
+
await this.config.authManager.setTokens({ access_token: resp.access_token, refresh_token: resp.refresh_token });
|
|
93
|
+
return LoginResponse.SUCCESS;
|
|
94
|
+
},
|
|
95
|
+
onSettled: () => {
|
|
96
|
+
queryClient.invalidateQueries();
|
|
97
|
+
},
|
|
98
|
+
onError: (err) => {
|
|
99
|
+
this.config.authManager.clearTokens();
|
|
100
|
+
throw new StandardError(401, err.message || 'Login failed');
|
|
101
|
+
}
|
|
105
102
|
});
|
|
106
103
|
}
|
|
107
|
-
|
|
108
|
-
const
|
|
109
|
-
|
|
110
|
-
|
|
104
|
+
useRequestCode() {
|
|
105
|
+
const queryClient = useQueryClient();
|
|
106
|
+
return useMutation({
|
|
107
|
+
mutationFn: async ({ username, email, cancelToken }) => {
|
|
108
|
+
const resp = await this.post('/code', JSON.stringify({ username, email }), cancelToken, { 'Content-Type': 'application/json' });
|
|
109
|
+
return resp;
|
|
110
|
+
},
|
|
111
|
+
onSettled: () => {
|
|
112
|
+
queryClient.invalidateQueries();
|
|
113
|
+
},
|
|
114
|
+
onError: (err) => {
|
|
115
|
+
throw new StandardError(err.status, err.message || 'Request code failed');
|
|
111
116
|
}
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
}
|
|
123
|
-
|
|
124
|
-
|
|
117
|
+
});
|
|
118
|
+
}
|
|
119
|
+
useUpdatePassword() {
|
|
120
|
+
const queryClient = useQueryClient();
|
|
121
|
+
return useMutation({
|
|
122
|
+
mutationFn: async ({ username, email, code, newPassword, cancelToken }) => {
|
|
123
|
+
await this.post('/update-password', JSON.stringify({ username, email, code, password: newPassword }), cancelToken, { 'Content-Type': 'application/json' });
|
|
124
|
+
},
|
|
125
|
+
onSettled: () => {
|
|
126
|
+
queryClient.invalidateQueries();
|
|
127
|
+
},
|
|
128
|
+
onError: (err) => {
|
|
129
|
+
throw new StandardError(err.status, err.message || 'Update password failed');
|
|
125
130
|
}
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
.catch(() => Promise.reject(new StandardError(401, 'Unauthorized (refresh failed)')));
|
|
137
|
-
}
|
|
138
|
-
if (!response.ok) {
|
|
139
|
-
if (retryCount < this.config.maxRetries) {
|
|
140
|
-
const delay = this.getDelay(this.config.retryStrategy, retryCount);
|
|
141
|
-
return new Promise((resolve, reject) => {
|
|
142
|
-
setTimeout(() => {
|
|
143
|
-
this._fetch(method, path, body, cancelToken, headers, isIdempotent, retryCount + 1)
|
|
144
|
-
.then(resolve)
|
|
145
|
-
.catch(reject);
|
|
146
|
-
}, delay);
|
|
147
|
-
});
|
|
148
|
-
}
|
|
149
|
-
else {
|
|
150
|
-
return response.text().then(text => {
|
|
151
|
-
let msg = response.statusText;
|
|
152
|
-
try {
|
|
153
|
-
const parsed = JSON.parse(text);
|
|
154
|
-
msg = parsed.message || msg;
|
|
155
|
-
}
|
|
156
|
-
catch {
|
|
157
|
-
console.warn('Failed to parse error response:', text);
|
|
158
|
-
}
|
|
159
|
-
throw new StandardError(response.status, msg);
|
|
160
|
-
});
|
|
131
|
+
});
|
|
132
|
+
}
|
|
133
|
+
useGoogleLogin() {
|
|
134
|
+
const queryClient = useQueryClient();
|
|
135
|
+
return useMutation({
|
|
136
|
+
mutationFn: async ({ token, cancelToken }) => {
|
|
137
|
+
const resp = await this._xhr('POST', `/google/authorize?token=${token}`, {}, cancelToken, { 'Content-Type': 'application/json' });
|
|
138
|
+
if (!resp || !('access_token' in resp)) {
|
|
139
|
+
if (resp.msg === "TOTP required") {
|
|
140
|
+
return LoginResponse.NEEDS_TOTP;
|
|
161
141
|
}
|
|
142
|
+
throw new StandardError(401, 'Invalid Google login response');
|
|
162
143
|
}
|
|
163
|
-
|
|
164
|
-
|
|
144
|
+
this.socket.auth = { token: resp.access_token };
|
|
145
|
+
if (!this.socket.connected) {
|
|
146
|
+
this.socket.connect();
|
|
147
|
+
}
|
|
148
|
+
await this.config.authManager.setTokens({ access_token: resp.access_token, refresh_token: resp.refresh_token });
|
|
149
|
+
return LoginResponse.SUCCESS;
|
|
150
|
+
},
|
|
151
|
+
onSettled: () => {
|
|
152
|
+
queryClient.invalidateQueries();
|
|
153
|
+
},
|
|
154
|
+
onError: (err) => {
|
|
155
|
+
this.config.authManager.clearTokens();
|
|
156
|
+
throw new StandardError(err.status, err.message || 'Google Login failed');
|
|
157
|
+
}
|
|
165
158
|
});
|
|
166
159
|
}
|
|
167
|
-
|
|
168
|
-
return this.
|
|
160
|
+
setTokens(tokens) {
|
|
161
|
+
return this.config.authManager.setTokens(tokens);
|
|
169
162
|
}
|
|
170
|
-
|
|
171
|
-
return this.
|
|
163
|
+
clearTokens() {
|
|
164
|
+
return this.config.authManager.clearTokens();
|
|
172
165
|
}
|
|
173
|
-
|
|
174
|
-
return this.
|
|
166
|
+
isAuthenticated() {
|
|
167
|
+
return this._isAuthenticated;
|
|
175
168
|
}
|
|
176
|
-
|
|
177
|
-
return this.
|
|
169
|
+
isAuthenticatedAsync() {
|
|
170
|
+
return this.config.authManager.isAuthenticated();
|
|
178
171
|
}
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
172
|
+
useLogout() {
|
|
173
|
+
const queryClient = useQueryClient();
|
|
174
|
+
return useMutation({
|
|
175
|
+
mutationFn: async (cancelToken) => {
|
|
176
|
+
await this.post('/logout', null, cancelToken);
|
|
177
|
+
await this.config.authManager.clearTokens();
|
|
178
|
+
if (this.socket && this.socket.connected) {
|
|
179
|
+
this.socket.disconnect();
|
|
180
|
+
}
|
|
181
|
+
},
|
|
182
|
+
onSettled: () => {
|
|
183
|
+
this._isAuthenticated = false;
|
|
184
|
+
queryClient.invalidateQueries();
|
|
185
|
+
},
|
|
186
|
+
onError: (err) => {
|
|
187
|
+
this.config.authManager.clearTokens();
|
|
188
|
+
console.error('Logout failed:', err);
|
|
189
|
+
throw new StandardError(500, 'Logout failed');
|
|
190
|
+
}
|
|
191
|
+
});
|
|
192
|
+
}
|
|
193
|
+
fetchJobs(companyGuid, body = {}, cancelToken, headers = {}) {
|
|
194
|
+
if (!companyGuid || companyGuid.trim() === '') {
|
|
195
|
+
return Promise.reject(new StandardError(400, 'Company GUID is required'));
|
|
196
|
+
}
|
|
197
|
+
return this._fetch('POST', `/company/${companyGuid}/jobs`, JSON.stringify(body), cancelToken, {
|
|
198
|
+
...headers,
|
|
199
|
+
'Content-Type': 'application/json',
|
|
200
|
+
})
|
|
201
|
+
.then(response => {
|
|
202
|
+
if (!response || !Array.isArray(response)) {
|
|
203
|
+
throw new StandardError(400, 'Invalid jobs response');
|
|
184
204
|
}
|
|
185
|
-
return
|
|
205
|
+
return response;
|
|
186
206
|
})
|
|
187
207
|
.catch(err => {
|
|
188
|
-
console.error('
|
|
189
|
-
throw new StandardError(
|
|
208
|
+
console.error('Failed to fetch jobs:', err);
|
|
209
|
+
throw new StandardError(500, 'Failed to fetch jobs');
|
|
190
210
|
});
|
|
191
211
|
}
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
.
|
|
212
|
+
fetchChats(companyGuid, body = {}, cancelToken, headers = {}) {
|
|
213
|
+
if (!companyGuid || companyGuid.trim() === '') {
|
|
214
|
+
return Promise.reject(new StandardError(400, 'Company GUID is required'));
|
|
215
|
+
}
|
|
216
|
+
return this._fetch('POST', `/company/${companyGuid}/chats`, JSON.stringify(body), cancelToken, {
|
|
217
|
+
...headers,
|
|
218
|
+
'Content-Type': 'application/json',
|
|
219
|
+
})
|
|
220
|
+
.then(response => {
|
|
221
|
+
if (!response || !Array.isArray(response)) {
|
|
222
|
+
throw new StandardError(400, 'Invalid chats response');
|
|
223
|
+
}
|
|
224
|
+
return response;
|
|
225
|
+
})
|
|
195
226
|
.catch(err => {
|
|
196
|
-
console.error('
|
|
197
|
-
throw new StandardError(500, '
|
|
227
|
+
console.error('Failed to fetch chats:', err);
|
|
228
|
+
throw new StandardError(500, 'Failed to fetch chats');
|
|
198
229
|
});
|
|
199
230
|
}
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
known_ids: knownIds,
|
|
204
|
-
unknown_ids: unknownIds,
|
|
205
|
-
query: keyword,
|
|
206
|
-
};
|
|
207
|
-
if (!companyGuid) {
|
|
208
|
-
return Promise.reject(new StandardError(400, 'Company GUID is required'));
|
|
231
|
+
fetchMessages(chatGuid, body = {}, cancelToken, headers = {}) {
|
|
232
|
+
if (!chatGuid || chatGuid.trim() === '') {
|
|
233
|
+
return Promise.reject(new StandardError(400, 'Chat GUID is required'));
|
|
209
234
|
}
|
|
210
|
-
return this._fetch('POST', `/
|
|
235
|
+
return this._fetch('POST', `/chat/${chatGuid}/messages`, JSON.stringify(body), cancelToken, {
|
|
236
|
+
...headers,
|
|
237
|
+
'Content-Type': 'application/json',
|
|
238
|
+
})
|
|
211
239
|
.then(response => {
|
|
212
240
|
if (!response || !Array.isArray(response)) {
|
|
213
|
-
throw new StandardError(400, 'Invalid
|
|
241
|
+
throw new StandardError(400, 'Invalid messages response');
|
|
214
242
|
}
|
|
215
243
|
return response;
|
|
216
244
|
})
|
|
217
245
|
.catch(err => {
|
|
218
|
-
console.error('Failed to fetch
|
|
219
|
-
throw new StandardError(500, 'Failed to fetch
|
|
246
|
+
console.error('Failed to fetch messages:', err);
|
|
247
|
+
throw new StandardError(500, 'Failed to fetch messages');
|
|
220
248
|
});
|
|
221
249
|
}
|
|
222
|
-
fetchEvents(companyGuid,
|
|
223
|
-
|
|
224
|
-
amt,
|
|
225
|
-
known_ids,
|
|
226
|
-
unknown_ids,
|
|
227
|
-
query: keyword,
|
|
228
|
-
};
|
|
229
|
-
if (!companyGuid) {
|
|
250
|
+
fetchEvents(companyGuid, body = {}, cancelToken, headers = {}) {
|
|
251
|
+
if (!companyGuid || companyGuid.trim() === '') {
|
|
230
252
|
return Promise.reject(new StandardError(400, 'Company GUID is required'));
|
|
231
253
|
}
|
|
232
|
-
return this._fetch('POST', `/company/${companyGuid}/events
|
|
254
|
+
return this._fetch('POST', `/company/${companyGuid}/events`, JSON.stringify(body), cancelToken, {
|
|
255
|
+
...headers,
|
|
256
|
+
'Content-Type': 'application/json',
|
|
257
|
+
})
|
|
233
258
|
.then(response => {
|
|
234
259
|
if (!response || !Array.isArray(response)) {
|
|
235
260
|
throw new StandardError(400, 'Invalid events response');
|
|
@@ -241,17 +266,33 @@ export class AvroQueryClient {
|
|
|
241
266
|
throw new StandardError(500, 'Failed to fetch events');
|
|
242
267
|
});
|
|
243
268
|
}
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
amt,
|
|
247
|
-
known_ids,
|
|
248
|
-
unknown_ids,
|
|
249
|
-
query: keyword,
|
|
250
|
-
};
|
|
251
|
-
if (!companyGuid) {
|
|
269
|
+
fetchMonths(companyGuid, body = {}, cancelToken, headers = {}) {
|
|
270
|
+
if (!companyGuid || companyGuid.trim() === '') {
|
|
252
271
|
return Promise.reject(new StandardError(400, 'Company GUID is required'));
|
|
253
272
|
}
|
|
254
|
-
return this._fetch('POST', `/company/${companyGuid}/
|
|
273
|
+
return this._fetch('POST', `/company/${companyGuid}/months`, JSON.stringify(body), cancelToken, {
|
|
274
|
+
...headers,
|
|
275
|
+
'Content-Type': 'application/json',
|
|
276
|
+
})
|
|
277
|
+
.then(response => {
|
|
278
|
+
if (!response || !Array.isArray(response)) {
|
|
279
|
+
throw new StandardError(400, 'Invalid months response');
|
|
280
|
+
}
|
|
281
|
+
return response;
|
|
282
|
+
})
|
|
283
|
+
.catch(err => {
|
|
284
|
+
console.error('Failed to fetch months:', err);
|
|
285
|
+
throw new StandardError(500, 'Failed to fetch months');
|
|
286
|
+
});
|
|
287
|
+
}
|
|
288
|
+
fetchBills(companyGuid, body = {}, cancelToken, headers = {}) {
|
|
289
|
+
if (!companyGuid || companyGuid.trim() === '') {
|
|
290
|
+
return Promise.reject(new StandardError(400, 'Company GUID is required'));
|
|
291
|
+
}
|
|
292
|
+
return this._fetch('POST', `/company/${companyGuid}/bills`, JSON.stringify(body), cancelToken, {
|
|
293
|
+
...headers,
|
|
294
|
+
'Content-Type': 'application/json',
|
|
295
|
+
})
|
|
255
296
|
.then(response => {
|
|
256
297
|
if (!response || !Array.isArray(response)) {
|
|
257
298
|
throw new StandardError(400, 'Invalid bills response');
|
|
@@ -263,4 +304,71 @@ export class AvroQueryClient {
|
|
|
263
304
|
throw new StandardError(500, 'Failed to fetch bills');
|
|
264
305
|
});
|
|
265
306
|
}
|
|
307
|
+
fetchRoutes(companyGuid, body = {}, cancelToken, headers = {}) {
|
|
308
|
+
if (!companyGuid || companyGuid.trim() === '') {
|
|
309
|
+
return Promise.reject(new StandardError(400, 'Company GUID is required'));
|
|
310
|
+
}
|
|
311
|
+
return this._fetch('POST', `/company/${companyGuid}/routes`, JSON.stringify(body), cancelToken, {
|
|
312
|
+
...headers,
|
|
313
|
+
'Content-Type': 'application/json',
|
|
314
|
+
})
|
|
315
|
+
.then(response => {
|
|
316
|
+
if (!response || !Array.isArray(response)) {
|
|
317
|
+
throw new StandardError(400, 'Invalid routes response');
|
|
318
|
+
}
|
|
319
|
+
return response;
|
|
320
|
+
})
|
|
321
|
+
.catch(err => {
|
|
322
|
+
console.error('Failed to fetch routes:', err);
|
|
323
|
+
throw new StandardError(500, 'Failed to fetch routes');
|
|
324
|
+
});
|
|
325
|
+
}
|
|
326
|
+
fetchTeams(companyGuid, body = {}, cancelToken, headers = {}) {
|
|
327
|
+
if (!companyGuid || companyGuid.trim() === '') {
|
|
328
|
+
return Promise.reject(new StandardError(400, 'Company GUID is required'));
|
|
329
|
+
}
|
|
330
|
+
return this._fetch('POST', `/company/${companyGuid}/teams`, JSON.stringify(body), cancelToken, {
|
|
331
|
+
...headers,
|
|
332
|
+
'Content-Type': 'application/json',
|
|
333
|
+
})
|
|
334
|
+
.then(response => {
|
|
335
|
+
if (!response || !Array.isArray(response)) {
|
|
336
|
+
throw new StandardError(400, 'Invalid teams response');
|
|
337
|
+
}
|
|
338
|
+
return response;
|
|
339
|
+
})
|
|
340
|
+
.catch(err => {
|
|
341
|
+
console.error('Failed to fetch teams:', err);
|
|
342
|
+
throw new StandardError(500, 'Failed to fetch teams');
|
|
343
|
+
});
|
|
344
|
+
}
|
|
345
|
+
sendEmail(emailId, formData, progressUpdateCallback) {
|
|
346
|
+
try {
|
|
347
|
+
return this.post(`/email/${emailId}`, formData, undefined, {}, progressUpdateCallback);
|
|
348
|
+
}
|
|
349
|
+
catch (error) {
|
|
350
|
+
throw new StandardError(500, `Failed to send email: ${error}`);
|
|
351
|
+
}
|
|
352
|
+
}
|
|
353
|
+
createBill(companyGuid, data, cancelToken) {
|
|
354
|
+
if (!companyGuid) {
|
|
355
|
+
return Promise.reject(new StandardError(400, 'Company GUID is required'));
|
|
356
|
+
}
|
|
357
|
+
const body = {
|
|
358
|
+
events: data.line_items.filter(item => item.line_item_type === 'EVENT').map(item => item.id),
|
|
359
|
+
months: data.line_items.filter(item => item.line_item_type === 'SERVICE_MONTH').map(item => item.id),
|
|
360
|
+
line_items: data.line_items.filter(item => item.line_item_type === 'CUSTOM'),
|
|
361
|
+
manual_emails: data.custom_emails,
|
|
362
|
+
users: data.users,
|
|
363
|
+
due_date: data.due_date,
|
|
364
|
+
};
|
|
365
|
+
try {
|
|
366
|
+
return this._xhr('POST', `/company/${companyGuid}/bill`, JSON.stringify(body), cancelToken, {
|
|
367
|
+
'Content-Type': 'application/json',
|
|
368
|
+
});
|
|
369
|
+
}
|
|
370
|
+
catch (error) {
|
|
371
|
+
throw new StandardError(500, `Failed to create bill: ${error}`);
|
|
372
|
+
}
|
|
373
|
+
}
|
|
266
374
|
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
import { AvroQueryClient } from '../../client/QueryClient';
|
|
2
|
+
import { StandardError } from '../../types/error';
|
|
3
|
+
AvroQueryClient.prototype._fetch = async function (method, path, body, cancelToken, headers = {}, isIdempotent = false, retryCount = 0) {
|
|
4
|
+
const checkCancelled = () => {
|
|
5
|
+
try {
|
|
6
|
+
if (cancelToken?.isCancelled()) {
|
|
7
|
+
throw new StandardError(0, 'Request cancelled');
|
|
8
|
+
}
|
|
9
|
+
}
|
|
10
|
+
catch (error) {
|
|
11
|
+
throw new StandardError(0, `Error checking cancellation: ${error.message}`);
|
|
12
|
+
}
|
|
13
|
+
};
|
|
14
|
+
try {
|
|
15
|
+
checkCancelled();
|
|
16
|
+
const token = await this.config.authManager.accessToken();
|
|
17
|
+
checkCancelled();
|
|
18
|
+
const url = this.config.baseUrl + path;
|
|
19
|
+
const requestHeaders = {
|
|
20
|
+
Authorization: `Bearer ${token}`,
|
|
21
|
+
...headers,
|
|
22
|
+
};
|
|
23
|
+
const options = {
|
|
24
|
+
method,
|
|
25
|
+
headers: requestHeaders,
|
|
26
|
+
body,
|
|
27
|
+
};
|
|
28
|
+
const response = await fetch(url, options);
|
|
29
|
+
if (response.ok) {
|
|
30
|
+
const text = await response.text();
|
|
31
|
+
if (!text) {
|
|
32
|
+
return undefined;
|
|
33
|
+
}
|
|
34
|
+
return JSON.parse(text);
|
|
35
|
+
}
|
|
36
|
+
if (response.status === 401 && this.config.authManager.refreshTokens && retryCount === 0) {
|
|
37
|
+
await this.config.authManager.refreshTokens();
|
|
38
|
+
return this._fetch(method, path, body, cancelToken, headers, isIdempotent, 1);
|
|
39
|
+
}
|
|
40
|
+
if (retryCount < this.config.maxRetries) {
|
|
41
|
+
const delay = this.getDelay(this.config.retryStrategy, retryCount);
|
|
42
|
+
await this.sleep(delay);
|
|
43
|
+
return this._fetch(method, path, body, cancelToken, headers, isIdempotent, retryCount + 1);
|
|
44
|
+
}
|
|
45
|
+
let errorMessage = response.statusText;
|
|
46
|
+
try {
|
|
47
|
+
const parsedError = await response.json();
|
|
48
|
+
errorMessage = parsedError.message ?? parsedError.msg ?? errorMessage;
|
|
49
|
+
}
|
|
50
|
+
catch (e) {
|
|
51
|
+
console.error('Ignoring:', e);
|
|
52
|
+
}
|
|
53
|
+
throw new StandardError(response.status, errorMessage);
|
|
54
|
+
}
|
|
55
|
+
catch (error) {
|
|
56
|
+
if (error instanceof StandardError) {
|
|
57
|
+
throw error;
|
|
58
|
+
}
|
|
59
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
60
|
+
throw new StandardError(0, `Request failed: ${message}`);
|
|
61
|
+
}
|
|
62
|
+
};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { AvroQueryClient } from '../../client/QueryClient';
|
|
2
|
+
AvroQueryClient.prototype.getDelay = function (strategy, attempt) {
|
|
3
|
+
if (typeof strategy === 'function') {
|
|
4
|
+
return strategy(attempt);
|
|
5
|
+
}
|
|
6
|
+
else if (strategy === 'fixed') {
|
|
7
|
+
return 1000;
|
|
8
|
+
}
|
|
9
|
+
else if (strategy === 'exponential') {
|
|
10
|
+
return Math.pow(2, attempt) * 100;
|
|
11
|
+
}
|
|
12
|
+
throw new Error(`Invalid retry strategy: ${strategy}`);
|
|
13
|
+
};
|
|
14
|
+
AvroQueryClient.prototype.sleep = (ms) => new Promise(resolve => setTimeout(resolve, ms));
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|