@go-avro/avro-js 0.0.2-beta.10 → 0.0.2-beta.100

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