@go-avro/avro-js 0.0.2-beta.8 → 0.0.2-beta.80

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 (46) hide show
  1. package/README.md +1 -0
  2. package/dist/auth/AuthManager.d.ts +4 -0
  3. package/dist/auth/AuthManager.js +13 -0
  4. package/dist/client/QueryClient.d.ts +331 -14
  5. package/dist/client/QueryClient.js +251 -197
  6. package/dist/client/core/fetch.d.ts +1 -0
  7. package/dist/client/core/fetch.js +67 -0
  8. package/dist/client/core/utils.d.ts +1 -0
  9. package/dist/client/core/utils.js +13 -0
  10. package/dist/client/core/xhr.d.ts +1 -0
  11. package/dist/client/core/xhr.js +87 -0
  12. package/dist/client/hooks/analytics.d.ts +1 -0
  13. package/dist/client/hooks/analytics.js +10 -0
  14. package/dist/client/hooks/avro.d.ts +1 -0
  15. package/dist/client/hooks/avro.js +9 -0
  16. package/dist/client/hooks/bills.d.ts +1 -0
  17. package/dist/client/hooks/bills.js +141 -0
  18. package/dist/client/hooks/chats.d.ts +1 -0
  19. package/dist/client/hooks/chats.js +37 -0
  20. package/dist/client/hooks/companies.d.ts +1 -0
  21. package/dist/client/hooks/companies.js +79 -0
  22. package/dist/client/hooks/events.d.ts +1 -0
  23. package/dist/client/hooks/events.js +307 -0
  24. package/dist/client/hooks/jobs.d.ts +1 -0
  25. package/dist/client/hooks/jobs.js +184 -0
  26. package/dist/client/hooks/messages.d.ts +1 -0
  27. package/dist/client/hooks/messages.js +30 -0
  28. package/dist/client/hooks/months.d.ts +1 -0
  29. package/dist/client/hooks/months.js +92 -0
  30. package/dist/client/hooks/plans.d.ts +1 -0
  31. package/dist/client/hooks/plans.js +9 -0
  32. package/dist/client/hooks/root.d.ts +1 -0
  33. package/dist/client/hooks/root.js +8 -0
  34. package/dist/client/hooks/routes.d.ts +1 -0
  35. package/dist/client/hooks/routes.js +123 -0
  36. package/dist/client/hooks/sessions.d.ts +1 -0
  37. package/dist/client/hooks/sessions.js +154 -0
  38. package/dist/client/hooks/teams.d.ts +1 -0
  39. package/dist/client/hooks/teams.js +117 -0
  40. package/dist/client/hooks/users.d.ts +1 -0
  41. package/dist/client/hooks/users.js +104 -0
  42. package/dist/index.d.ts +19 -0
  43. package/dist/index.js +19 -0
  44. package/dist/types/api.d.ts +118 -29
  45. package/dist/types/api.js +10 -1
  46. 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,207 @@ export class AvroQueryClient {
8
12
  retryStrategy: config.retryStrategy ?? 'fixed',
9
13
  timeout: config.timeout ?? 0,
10
14
  };
11
- }
12
- getDelay(strategy, attempt) {
13
- if (typeof strategy === 'function') {
14
- return strategy(attempt);
15
- }
16
- else if (strategy === 'fixed') {
17
- return 1000;
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
- else if (strategy === 'exponential') {
20
- return Math.pow(2, attempt) * 100;
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
- throw new Error(`Invalid retry strategy: ${strategy}`);
56
+ this.socket.emit(eventName, data);
23
57
  }
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'));
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._fetch('POST', '/login', { username, password, code }, cancelToken);
81
+ if (!resp || !('access_token' in resp)) {
82
+ if (resp.msg === "TOTP email sent") {
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
- xhr.send(body);
104
- });
87
+ this.socket.auth = { token: resp.access_token };
88
+ if (!this.socket.connected) {
89
+ this.socket.connect();
90
+ }
91
+ await this.config.authManager.setTokens({ access_token: resp.access_token, refresh_token: resp.refresh_token });
92
+ return LoginResponse.SUCCESS;
93
+ },
94
+ onSettled: () => {
95
+ queryClient.invalidateQueries();
96
+ },
97
+ onError: (err) => {
98
+ this.config.authManager.clearTokens();
99
+ throw new StandardError(401, err.message || 'Login failed');
100
+ }
105
101
  });
106
102
  }
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');
111
- }
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}`;
125
- }
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
- });
103
+ useGoogleLogin() {
104
+ const queryClient = useQueryClient();
105
+ return useMutation({
106
+ mutationFn: async ({ token, cancelToken }) => {
107
+ const resp = await this._fetch('POST', `/google/authorize?token=${token}`, {}, cancelToken, { 'Content-Type': 'application/json' });
108
+ if (!resp || !('access_token' in resp)) {
109
+ if (resp.msg === "TOTP email sent") {
110
+ return LoginResponse.NEEDS_TOTP;
161
111
  }
112
+ throw new StandardError(401, 'Invalid Google login response');
162
113
  }
163
- return response.json();
164
- });
114
+ this.socket.auth = { token: resp.access_token };
115
+ if (!this.socket.connected) {
116
+ this.socket.connect();
117
+ }
118
+ await this.config.authManager.setTokens({ access_token: resp.access_token, refresh_token: resp.refresh_token });
119
+ return LoginResponse.SUCCESS;
120
+ },
121
+ onSettled: () => {
122
+ queryClient.invalidateQueries();
123
+ },
124
+ onError: (err) => {
125
+ this.config.authManager.clearTokens();
126
+ throw new StandardError(401, err.message || 'Google Login failed');
127
+ }
165
128
  });
166
129
  }
167
- get(path, cancelToken, headers = {}) {
168
- return this._xhr('GET', path, null, cancelToken, headers, true);
130
+ setTokens(tokens) {
131
+ return this.config.authManager.setTokens(tokens);
169
132
  }
170
- post(path, data, cancelToken, headers = {}) {
171
- return this._xhr('POST', path, data, cancelToken, headers, false);
133
+ clearTokens() {
134
+ return this.config.authManager.clearTokens();
172
135
  }
173
- put(path, data, cancelToken, headers = {}) {
174
- return this._xhr('PUT', path, data, cancelToken, headers, true);
136
+ isAuthenticated() {
137
+ return this._isAuthenticated;
175
138
  }
176
- delete(path, cancelToken, headers = {}) {
177
- return this._xhr('DELETE', path, null, cancelToken, headers, false);
139
+ isAuthenticatedAsync() {
140
+ return this.config.authManager.isAuthenticated();
178
141
  }
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');
142
+ useLogout() {
143
+ const queryClient = useQueryClient();
144
+ return useMutation({
145
+ mutationFn: async (cancelToken) => {
146
+ await this._fetch('POST', '/logout', null, cancelToken);
147
+ await this.config.authManager.clearTokens();
148
+ if (this.socket && this.socket.connected) {
149
+ this.socket.disconnect();
150
+ }
151
+ },
152
+ onSettled: () => {
153
+ this._isAuthenticated = false;
154
+ queryClient.invalidateQueries();
155
+ },
156
+ onError: (err) => {
157
+ this.config.authManager.clearTokens();
158
+ console.error('Logout failed:', err);
159
+ throw new StandardError(500, 'Logout failed');
160
+ }
161
+ });
162
+ }
163
+ fetchJobs(companyGuid, body = {}, cancelToken, headers = {}) {
164
+ if (!companyGuid || companyGuid.trim() === '') {
165
+ return Promise.reject(new StandardError(400, 'Company GUID is required'));
166
+ }
167
+ return this._fetch('POST', `/company/${companyGuid}/jobs`, body, cancelToken, headers)
168
+ .then(response => {
169
+ if (!response || !Array.isArray(response)) {
170
+ throw new StandardError(400, 'Invalid jobs response');
184
171
  }
185
- return this.config.authManager.setTokens(tokens).then(() => true);
172
+ return response;
186
173
  })
187
174
  .catch(err => {
188
- console.error('Login failed:', err);
189
- throw new StandardError(401, 'Login failed');
175
+ console.error('Failed to fetch jobs:', err);
176
+ throw new StandardError(500, 'Failed to fetch jobs');
190
177
  });
191
178
  }
192
- logout(cancelToken) {
193
- return this._fetch('POST', '/logout', null, cancelToken)
194
- .then(() => this.config.authManager.clearTokens())
179
+ fetchChats(companyGuid, body = {}, cancelToken, headers = {}) {
180
+ if (!companyGuid || companyGuid.trim() === '') {
181
+ return Promise.reject(new StandardError(400, 'Company GUID is required'));
182
+ }
183
+ return this._fetch('POST', `/company/${companyGuid}/chats`, body, cancelToken, headers)
184
+ .then(response => {
185
+ if (!response || !Array.isArray(response)) {
186
+ throw new StandardError(400, 'Invalid chats response');
187
+ }
188
+ return response;
189
+ })
195
190
  .catch(err => {
196
- console.error('Logout failed:', err);
197
- throw new StandardError(500, 'Logout failed');
191
+ console.error('Failed to fetch chats:', err);
192
+ throw new StandardError(500, 'Failed to fetch chats');
198
193
  });
199
194
  }
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'));
195
+ fetchMessages(chatGuid, body = {}, cancelToken, headers = {}) {
196
+ if (!chatGuid || chatGuid.trim() === '') {
197
+ return Promise.reject(new StandardError(400, 'Chat GUID is required'));
209
198
  }
210
- return this._fetch('POST', `/company/${companyGuid}/jobs?amt=${amt}&offset=${offset}`, body, cancelToken, headers)
199
+ return this._fetch('POST', `/chat/${chatGuid}/messages`, body, cancelToken, headers)
211
200
  .then(response => {
212
201
  if (!response || !Array.isArray(response)) {
213
- throw new StandardError(400, 'Invalid jobs response');
202
+ throw new StandardError(400, 'Invalid messages response');
214
203
  }
215
204
  return response;
216
205
  })
217
206
  .catch(err => {
218
- console.error('Failed to fetch jobs:', err);
219
- throw new StandardError(500, 'Failed to fetch jobs');
207
+ console.error('Failed to fetch messages:', err);
208
+ throw new StandardError(500, 'Failed to fetch messages');
220
209
  });
221
210
  }
222
- fetchEvents(companyGuid, amt = 50, known_ids = [], unknown_ids = [], keyword = '', offset = 0, cancelToken, headers = {}) {
223
- const body = {
224
- amt,
225
- known_ids,
226
- unknown_ids,
227
- query: keyword,
228
- };
229
- if (!companyGuid) {
211
+ fetchEvents(companyGuid, body = {}, cancelToken, headers = {}) {
212
+ if (!companyGuid || companyGuid.trim() === '') {
230
213
  return Promise.reject(new StandardError(400, 'Company GUID is required'));
231
214
  }
232
- return this._fetch('POST', `/company/${companyGuid}/events?amt=${amt}&offset=${offset}`, body, cancelToken, headers)
215
+ return this._fetch('POST', `/company/${companyGuid}/events`, body, cancelToken, headers)
233
216
  .then(response => {
234
217
  if (!response || !Array.isArray(response)) {
235
218
  throw new StandardError(400, 'Invalid events response');
@@ -241,17 +224,27 @@ export class AvroQueryClient {
241
224
  throw new StandardError(500, 'Failed to fetch events');
242
225
  });
243
226
  }
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) {
227
+ fetchMonths(companyGuid, body = {}, cancelToken, headers = {}) {
228
+ if (!companyGuid || companyGuid.trim() === '') {
229
+ return Promise.reject(new StandardError(400, 'Company GUID is required'));
230
+ }
231
+ return this._fetch('POST', `/company/${companyGuid}/months`, body, cancelToken, headers)
232
+ .then(response => {
233
+ if (!response || !Array.isArray(response)) {
234
+ throw new StandardError(400, 'Invalid months response');
235
+ }
236
+ return response;
237
+ })
238
+ .catch(err => {
239
+ console.error('Failed to fetch months:', err);
240
+ throw new StandardError(500, 'Failed to fetch months');
241
+ });
242
+ }
243
+ fetchBills(companyGuid, body = {}, cancelToken, headers = {}) {
244
+ if (!companyGuid || companyGuid.trim() === '') {
252
245
  return Promise.reject(new StandardError(400, 'Company GUID is required'));
253
246
  }
254
- return this._fetch('POST', `/company/${companyGuid}/bills?amt=${amt}&offset=${offset}`, body, cancelToken, headers)
247
+ return this._fetch('POST', `/company/${companyGuid}/bills`, body, cancelToken, headers)
255
248
  .then(response => {
256
249
  if (!response || !Array.isArray(response)) {
257
250
  throw new StandardError(400, 'Invalid bills response');
@@ -263,4 +256,65 @@ export class AvroQueryClient {
263
256
  throw new StandardError(500, 'Failed to fetch bills');
264
257
  });
265
258
  }
259
+ fetchRoutes(companyGuid, body = {}, cancelToken, headers = {}) {
260
+ if (!companyGuid || companyGuid.trim() === '') {
261
+ return Promise.reject(new StandardError(400, 'Company GUID is required'));
262
+ }
263
+ return this._fetch('POST', `/company/${companyGuid}/routes`, body, cancelToken, headers)
264
+ .then(response => {
265
+ if (!response || !Array.isArray(response)) {
266
+ throw new StandardError(400, 'Invalid routes response');
267
+ }
268
+ return response;
269
+ })
270
+ .catch(err => {
271
+ console.error('Failed to fetch routes:', err);
272
+ throw new StandardError(500, 'Failed to fetch routes');
273
+ });
274
+ }
275
+ fetchTeams(companyGuid, body = {}, cancelToken, headers = {}) {
276
+ if (!companyGuid || companyGuid.trim() === '') {
277
+ return Promise.reject(new StandardError(400, 'Company GUID is required'));
278
+ }
279
+ return this._fetch('POST', `/company/${companyGuid}/teams`, body, cancelToken, headers)
280
+ .then(response => {
281
+ if (!response || !Array.isArray(response)) {
282
+ throw new StandardError(400, 'Invalid teams response');
283
+ }
284
+ return response;
285
+ })
286
+ .catch(err => {
287
+ console.error('Failed to fetch teams:', err);
288
+ throw new StandardError(500, 'Failed to fetch teams');
289
+ });
290
+ }
291
+ sendEmail(emailId, formData, progressUpdateCallback) {
292
+ try {
293
+ return this.post(`/email/${emailId}`, formData, undefined, {}, progressUpdateCallback);
294
+ }
295
+ catch (error) {
296
+ throw new StandardError(500, `Failed to send email: ${error}`);
297
+ }
298
+ }
299
+ createBill(companyGuid, data, cancelToken) {
300
+ if (!companyGuid) {
301
+ return Promise.reject(new StandardError(400, 'Company GUID is required'));
302
+ }
303
+ const body = {
304
+ events: data.line_items.filter(item => item.line_item_type === 'EVENT').map(item => item.id),
305
+ months: data.line_items.filter(item => item.line_item_type === 'SERVICE_MONTH').map(item => item.id),
306
+ line_items: data.line_items.filter(item => item.line_item_type === 'CUSTOM'),
307
+ manual_emails: data.custom_emails,
308
+ users: data.users,
309
+ due_date: data.due_date,
310
+ };
311
+ try {
312
+ return this._xhr('POST', `/company/${companyGuid}/bill`, JSON.stringify(body), cancelToken, {
313
+ 'Content-Type': 'application/json',
314
+ });
315
+ }
316
+ catch (error) {
317
+ throw new StandardError(500, `Failed to create bill: ${error}`);
318
+ }
319
+ }
266
320
  }
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,67 @@
1
+ import { AvroQueryClient } from '../../client/QueryClient';
2
+ import { StandardError } from '../../types/error';
3
+ AvroQueryClient.prototype._fetch = function (method, path, body, cancelToken, headers = {}, isIdempotent = false, retryCount = 0) {
4
+ const checkCancelled = () => {
5
+ try {
6
+ if (cancelToken?.isCancelled()) {
7
+ return new StandardError(0, 'Request cancelled');
8
+ }
9
+ }
10
+ catch (error) {
11
+ throw new StandardError(0, `Error checking cancellation (${typeof cancelToken}): ${error}`);
12
+ }
13
+ return null;
14
+ };
15
+ return this.config.authManager.accessToken().then(token => {
16
+ const cancelErr = checkCancelled();
17
+ if (cancelErr)
18
+ return Promise.reject(cancelErr);
19
+ const url = this.config.baseUrl + path;
20
+ const requestHeaders = {
21
+ 'Content-Type': 'application/json',
22
+ ...headers,
23
+ };
24
+ if (token) {
25
+ requestHeaders['Authorization'] = `Bearer ${token}`;
26
+ }
27
+ const options = {
28
+ method,
29
+ headers: requestHeaders,
30
+ body: body ? JSON.stringify(body) : null,
31
+ };
32
+ return fetch(url, options).then(response => {
33
+ if (response.status === 401 && this.config.authManager.refreshTokens && retryCount === 0) {
34
+ return this.config.authManager
35
+ .refreshTokens()
36
+ .then(() => this._fetch(method, path, body, cancelToken, headers, isIdempotent, retryCount + 1))
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
+ }
63
+ }
64
+ return response.json();
65
+ });
66
+ });
67
+ };
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,13 @@
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
+ };
@@ -0,0 +1 @@
1
+ export {};