@go-avro/avro-js 0.0.2-beta.2 → 0.0.2-beta.20
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.d.ts +1 -1
- package/dist/auth/AuthManager.js +54 -25
- package/dist/client/QueryClient.d.ts +13 -0
- package/dist/client/QueryClient.js +138 -3
- package/dist/types/api.d.ts +18 -1
- package/package.json +1 -1
|
@@ -6,7 +6,7 @@ export declare class AuthManager {
|
|
|
6
6
|
baseUrl: string;
|
|
7
7
|
storage: TokenStorage | TokenStorage[];
|
|
8
8
|
});
|
|
9
|
-
|
|
9
|
+
isAuthenticated(): Promise<boolean>;
|
|
10
10
|
fetchNewTokens(): Promise<Tokens>;
|
|
11
11
|
accessToken(): Promise<string | undefined>;
|
|
12
12
|
refreshTokens(): Promise<Tokens | null>;
|
package/dist/auth/AuthManager.js
CHANGED
|
@@ -11,41 +11,70 @@ export class AuthManager {
|
|
|
11
11
|
});
|
|
12
12
|
this.baseUrl = baseUrl;
|
|
13
13
|
}
|
|
14
|
-
async
|
|
14
|
+
async isAuthenticated() {
|
|
15
|
+
if (!this.storages.length) {
|
|
16
|
+
throw new Error('No token storages initialized');
|
|
17
|
+
}
|
|
15
18
|
for (const storage of this.storages) {
|
|
16
19
|
const tokens = await storage.get();
|
|
17
20
|
if (tokens && tokens.access_token) {
|
|
18
|
-
|
|
21
|
+
try {
|
|
22
|
+
const response = await fetch(`${this.baseUrl}/validate`, {
|
|
23
|
+
method: 'POST',
|
|
24
|
+
headers: {
|
|
25
|
+
'Content-Type': 'application/json',
|
|
26
|
+
'Authorization': `Bearer ${tokens.access_token}`,
|
|
27
|
+
},
|
|
28
|
+
});
|
|
29
|
+
if (response.ok) {
|
|
30
|
+
return true;
|
|
31
|
+
}
|
|
32
|
+
else {
|
|
33
|
+
// Attempt token refresh if validation fails
|
|
34
|
+
const newTokens = await this.refreshTokens();
|
|
35
|
+
if (newTokens && newTokens.access_token) {
|
|
36
|
+
const retryResponse = await fetch(`${this.baseUrl}/validate`, {
|
|
37
|
+
method: 'POST',
|
|
38
|
+
headers: {
|
|
39
|
+
'Content-Type': 'application/json',
|
|
40
|
+
'Authorization': `Bearer ${newTokens.access_token}`,
|
|
41
|
+
},
|
|
42
|
+
});
|
|
43
|
+
return retryResponse.ok;
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
catch (error) {
|
|
48
|
+
console.error('Error validating access token:', error);
|
|
49
|
+
}
|
|
19
50
|
}
|
|
20
51
|
}
|
|
21
52
|
return false;
|
|
22
53
|
}
|
|
23
54
|
async fetchNewTokens() {
|
|
24
|
-
const
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
55
|
+
for (const storage of this.storages) {
|
|
56
|
+
const tokens = await storage.get();
|
|
57
|
+
if (!tokens || !tokens.refresh_token)
|
|
58
|
+
continue;
|
|
59
|
+
try {
|
|
60
|
+
const response = await fetch(`${this.baseUrl}/refresh`, {
|
|
61
|
+
method: 'POST',
|
|
62
|
+
headers: {
|
|
63
|
+
'Content-Type': 'application/json',
|
|
64
|
+
'Accept': 'application/json',
|
|
65
|
+
'Authorization': `Bearer ${tokens.refresh_token}`,
|
|
66
|
+
},
|
|
67
|
+
});
|
|
68
|
+
if (response.ok) {
|
|
69
|
+
const newTokens = await response.json();
|
|
70
|
+
return newTokens;
|
|
29
71
|
}
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
throw new Error('No refresh token available');
|
|
35
|
-
}
|
|
36
|
-
const response = await fetch(`${this.baseUrl}/refresh`, {
|
|
37
|
-
method: 'POST',
|
|
38
|
-
headers: {
|
|
39
|
-
'Content-Type': 'application/json',
|
|
40
|
-
'Accept': 'application/json',
|
|
41
|
-
'Authorization': `Bearer ${refreshToken}`,
|
|
42
|
-
},
|
|
43
|
-
});
|
|
44
|
-
if (!response.ok) {
|
|
45
|
-
throw new Error('Failed to refresh tokens');
|
|
72
|
+
}
|
|
73
|
+
catch (error) {
|
|
74
|
+
storage.clear();
|
|
75
|
+
}
|
|
46
76
|
}
|
|
47
|
-
|
|
48
|
-
return tokens;
|
|
77
|
+
throw new Error('Failed to refresh tokens from all storages');
|
|
49
78
|
}
|
|
50
79
|
async accessToken() {
|
|
51
80
|
if (!this.storages.length) {
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { AuthManager } from '../auth/AuthManager';
|
|
2
|
+
import { LineItem } from '../types/api';
|
|
2
3
|
import { CancelToken, RetryStrategy } from '../types/client';
|
|
3
4
|
export interface AvroQueryClientConfig {
|
|
4
5
|
baseUrl: string;
|
|
@@ -21,4 +22,16 @@ export declare class AvroQueryClient {
|
|
|
21
22
|
username: string;
|
|
22
23
|
password: string;
|
|
23
24
|
}, cancelToken?: CancelToken): Promise<Boolean>;
|
|
25
|
+
logout(cancelToken?: CancelToken): Promise<void>;
|
|
26
|
+
fetchJobs(companyGuid: string, amt?: number, knownIds?: string[], unknownIds?: string[], keyword?: string, offset?: number, cancelToken?: CancelToken, headers?: Record<string, string>): Promise<any>;
|
|
27
|
+
fetchEvents(companyGuid: string, amt?: number, knownIds?: string[], unknownIds?: string[], keyword?: string, offset?: number, unbilled?: boolean, billed?: boolean, paid?: boolean, jobId?: string | null, cancelToken?: CancelToken, headers?: Record<string, string>): Promise<any>;
|
|
28
|
+
fetchMonths(companyGuid: string, amt?: number, knownIds?: string[], unknownIds?: string[], keyword?: string, offset?: number, unbilled?: boolean, billed?: boolean, paid?: boolean, jobId?: string | null, cancelToken?: CancelToken, headers?: Record<string, string>): Promise<any>;
|
|
29
|
+
fetchBills(companyGuid: string, amt?: number, knownIds?: string[], unknownIds?: string[], keyword?: string, offset?: number, paid?: boolean, cancelToken?: CancelToken, headers?: Record<string, string>): Promise<any>;
|
|
30
|
+
sendEmail(emailId: string, formData: FormData): Promise<void>;
|
|
31
|
+
createBill(companyGuid: string, data: {
|
|
32
|
+
line_items: LineItem[];
|
|
33
|
+
due_date: number;
|
|
34
|
+
users: string[];
|
|
35
|
+
custom_emails: [string, string][];
|
|
36
|
+
}): Promise<any>;
|
|
24
37
|
}
|
|
@@ -106,8 +106,13 @@ export class AvroQueryClient {
|
|
|
106
106
|
}
|
|
107
107
|
_fetch(method, path, body, cancelToken, headers = {}, isIdempotent = false, retryCount = 0) {
|
|
108
108
|
const checkCancelled = () => {
|
|
109
|
-
|
|
110
|
-
|
|
109
|
+
try {
|
|
110
|
+
if (cancelToken?.isCancelled()) {
|
|
111
|
+
return new StandardError(0, 'Request cancelled');
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
catch (error) {
|
|
115
|
+
throw new StandardError(0, `Error checking cancellation (${typeof cancelToken}): ${error}`);
|
|
111
116
|
}
|
|
112
117
|
return null;
|
|
113
118
|
};
|
|
@@ -176,7 +181,6 @@ export class AvroQueryClient {
|
|
|
176
181
|
delete(path, cancelToken, headers = {}) {
|
|
177
182
|
return this._xhr('DELETE', path, null, cancelToken, headers, false);
|
|
178
183
|
}
|
|
179
|
-
// add login that uses fetch and sets the tokens in the auth manager
|
|
180
184
|
login(data, cancelToken) {
|
|
181
185
|
return this._fetch('POST', '/login', data, cancelToken)
|
|
182
186
|
.then(tokens => {
|
|
@@ -190,4 +194,135 @@ export class AvroQueryClient {
|
|
|
190
194
|
throw new StandardError(401, 'Login failed');
|
|
191
195
|
});
|
|
192
196
|
}
|
|
197
|
+
logout(cancelToken) {
|
|
198
|
+
return this._fetch('POST', '/logout', null, cancelToken)
|
|
199
|
+
.then(() => this.config.authManager.clearTokens())
|
|
200
|
+
.catch(err => {
|
|
201
|
+
console.error('Logout failed:', err);
|
|
202
|
+
throw new StandardError(500, 'Logout failed');
|
|
203
|
+
});
|
|
204
|
+
}
|
|
205
|
+
fetchJobs(companyGuid, amt = 50, knownIds = [], unknownIds = [], keyword = '', offset = 0, cancelToken, headers = {}) {
|
|
206
|
+
const body = {
|
|
207
|
+
amt,
|
|
208
|
+
known_ids: knownIds,
|
|
209
|
+
unknown_ids: unknownIds,
|
|
210
|
+
query: keyword,
|
|
211
|
+
};
|
|
212
|
+
if (!companyGuid) {
|
|
213
|
+
return Promise.reject(new StandardError(400, 'Company GUID is required'));
|
|
214
|
+
}
|
|
215
|
+
return this._fetch('POST', `/company/${companyGuid}/jobs?amt=${amt}&offset=${offset}`, body, cancelToken, headers)
|
|
216
|
+
.then(response => {
|
|
217
|
+
if (!response || !Array.isArray(response)) {
|
|
218
|
+
throw new StandardError(400, 'Invalid jobs response');
|
|
219
|
+
}
|
|
220
|
+
return response;
|
|
221
|
+
})
|
|
222
|
+
.catch(err => {
|
|
223
|
+
console.error('Failed to fetch jobs:', err);
|
|
224
|
+
throw new StandardError(500, 'Failed to fetch jobs');
|
|
225
|
+
});
|
|
226
|
+
}
|
|
227
|
+
fetchEvents(companyGuid, amt = 50, knownIds = [], unknownIds = [], keyword = '', offset = 0, unbilled = true, billed = true, paid = true, jobId = null, cancelToken, headers = {}) {
|
|
228
|
+
const body = {
|
|
229
|
+
amt,
|
|
230
|
+
known_ids: knownIds,
|
|
231
|
+
unknown_ids: unknownIds,
|
|
232
|
+
query: keyword,
|
|
233
|
+
job_id: jobId,
|
|
234
|
+
};
|
|
235
|
+
if (!companyGuid) {
|
|
236
|
+
return Promise.reject(new StandardError(400, 'Company GUID is required'));
|
|
237
|
+
}
|
|
238
|
+
return this._fetch('POST', `/company/${companyGuid}/events?amt=${amt}&offset=${offset}&unbilled=${unbilled}&billed=${billed}&paid=${paid}`, body, cancelToken, headers)
|
|
239
|
+
.then(response => {
|
|
240
|
+
if (!response || !Array.isArray(response)) {
|
|
241
|
+
throw new StandardError(400, 'Invalid events response');
|
|
242
|
+
}
|
|
243
|
+
return response;
|
|
244
|
+
})
|
|
245
|
+
.catch(err => {
|
|
246
|
+
console.error('Failed to fetch events:', err);
|
|
247
|
+
throw new StandardError(500, 'Failed to fetch events');
|
|
248
|
+
});
|
|
249
|
+
}
|
|
250
|
+
fetchMonths(companyGuid, amt = 50, knownIds = [], unknownIds = [], keyword = '', offset = 0, unbilled = true, billed = true, paid = true, jobId = null, cancelToken, headers = {}) {
|
|
251
|
+
const body = {
|
|
252
|
+
amt,
|
|
253
|
+
known_ids: knownIds,
|
|
254
|
+
unknown_ids: unknownIds,
|
|
255
|
+
query: keyword,
|
|
256
|
+
job_id: jobId,
|
|
257
|
+
};
|
|
258
|
+
if (!companyGuid) {
|
|
259
|
+
return Promise.reject(new StandardError(400, 'Company GUID is required'));
|
|
260
|
+
}
|
|
261
|
+
return this._fetch('POST', `/company/${companyGuid}/months?amt=${amt}&offset=${offset}&unbilled=${unbilled}&billed=${billed}&paid=${paid}`, body, cancelToken, headers)
|
|
262
|
+
.then(response => {
|
|
263
|
+
if (!response || !Array.isArray(response)) {
|
|
264
|
+
throw new StandardError(400, 'Invalid months response');
|
|
265
|
+
}
|
|
266
|
+
return response;
|
|
267
|
+
})
|
|
268
|
+
.catch(err => {
|
|
269
|
+
console.error('Failed to fetch months:', err);
|
|
270
|
+
throw new StandardError(500, 'Failed to fetch months');
|
|
271
|
+
});
|
|
272
|
+
}
|
|
273
|
+
fetchBills(companyGuid, amt = 50, knownIds = [], unknownIds = [], keyword = '', offset = 0, paid = true, cancelToken, headers = {}) {
|
|
274
|
+
const body = {
|
|
275
|
+
amt,
|
|
276
|
+
known_ids: knownIds,
|
|
277
|
+
unknown_ids: unknownIds,
|
|
278
|
+
query: keyword,
|
|
279
|
+
};
|
|
280
|
+
if (!companyGuid) {
|
|
281
|
+
return Promise.reject(new StandardError(400, 'Company GUID is required'));
|
|
282
|
+
}
|
|
283
|
+
return this._fetch('POST', `/company/${companyGuid}/bills?amt=${amt}&offset=${offset}&paid=${paid}`, body, cancelToken, headers)
|
|
284
|
+
.then(response => {
|
|
285
|
+
if (!response || !Array.isArray(response)) {
|
|
286
|
+
throw new StandardError(400, 'Invalid bills response');
|
|
287
|
+
}
|
|
288
|
+
return response;
|
|
289
|
+
})
|
|
290
|
+
.catch(err => {
|
|
291
|
+
console.error('Failed to fetch bills:', err);
|
|
292
|
+
throw new StandardError(500, 'Failed to fetch bills');
|
|
293
|
+
});
|
|
294
|
+
}
|
|
295
|
+
sendEmail(emailId, formData) {
|
|
296
|
+
try {
|
|
297
|
+
return this._xhr('POST', `/email/${emailId}`, formData);
|
|
298
|
+
}
|
|
299
|
+
catch (error) {
|
|
300
|
+
console.error('Failed to send email', error);
|
|
301
|
+
throw error;
|
|
302
|
+
}
|
|
303
|
+
}
|
|
304
|
+
createBill(companyGuid, data) {
|
|
305
|
+
if (!companyGuid) {
|
|
306
|
+
return Promise.reject(new StandardError(400, 'Company GUID is required'));
|
|
307
|
+
}
|
|
308
|
+
const body = {
|
|
309
|
+
events: data.line_items.filter(item => item.line_item_type === 'EVENT').map(item => item.id),
|
|
310
|
+
months: data.line_items.filter(item => item.line_item_type === 'SERVICE_MONTH').map(item => item.id),
|
|
311
|
+
line_items: data.line_items.filter(item => item.line_item_type === 'CUSTOM'),
|
|
312
|
+
manual_emails: data.custom_emails,
|
|
313
|
+
users: data.users,
|
|
314
|
+
due_date: data.due_date,
|
|
315
|
+
};
|
|
316
|
+
return this._fetch('POST', `/company/${companyGuid}/bills`, body)
|
|
317
|
+
.then(response => {
|
|
318
|
+
if (!response || !Array.isArray(response)) {
|
|
319
|
+
throw new StandardError(400, 'Invalid bills response');
|
|
320
|
+
}
|
|
321
|
+
return response;
|
|
322
|
+
})
|
|
323
|
+
.catch(err => {
|
|
324
|
+
console.error('Failed to create bill:', err);
|
|
325
|
+
throw new StandardError(500, 'Failed to create bill');
|
|
326
|
+
});
|
|
327
|
+
}
|
|
193
328
|
}
|
package/dist/types/api.d.ts
CHANGED
|
@@ -68,6 +68,16 @@ export interface MemberState {
|
|
|
68
68
|
}
|
|
69
69
|
export interface LineItem {
|
|
70
70
|
id: string;
|
|
71
|
+
line_item_type: "CUSTOM" | "ADDITIONAL_CHARGE" | "EVENT" | "SERVICE_MONTH";
|
|
72
|
+
name: string;
|
|
73
|
+
description: string;
|
|
74
|
+
cost: number | null;
|
|
75
|
+
amount: number | null;
|
|
76
|
+
time_created: number;
|
|
77
|
+
}
|
|
78
|
+
export interface CustomLineItem {
|
|
79
|
+
id: string;
|
|
80
|
+
line_item_type: "CUSTOM";
|
|
71
81
|
name: string;
|
|
72
82
|
description: string;
|
|
73
83
|
cost: number | null;
|
|
@@ -211,13 +221,17 @@ export interface Break {
|
|
|
211
221
|
}
|
|
212
222
|
export interface ServiceMonth {
|
|
213
223
|
id: string;
|
|
224
|
+
line_item_type: "SERVICE_MONTH";
|
|
214
225
|
job_name: string;
|
|
215
226
|
job_id: string | null;
|
|
227
|
+
job_address: string;
|
|
228
|
+
job_labels: string[];
|
|
216
229
|
bill_id: string | null;
|
|
217
230
|
cost: number;
|
|
218
231
|
billed: boolean;
|
|
219
232
|
paid: boolean;
|
|
220
233
|
amount: number;
|
|
234
|
+
tasks: string[];
|
|
221
235
|
time_created: number;
|
|
222
236
|
time_updated: number | null;
|
|
223
237
|
}
|
|
@@ -301,7 +315,7 @@ export interface Bill {
|
|
|
301
315
|
intent_created_at: number;
|
|
302
316
|
intent_last_created_at: number;
|
|
303
317
|
payment: BillPayment | null;
|
|
304
|
-
line_items:
|
|
318
|
+
line_items: CustomLineItem[];
|
|
305
319
|
months: string[];
|
|
306
320
|
due_date: number;
|
|
307
321
|
}
|
|
@@ -473,14 +487,17 @@ export interface taskEndInfo {
|
|
|
473
487
|
}
|
|
474
488
|
export interface AdditionalCharge {
|
|
475
489
|
id: string;
|
|
490
|
+
line_item_type: "ADDITIONAL_CHARGE";
|
|
476
491
|
time_created: number;
|
|
477
492
|
time_updated: number | null;
|
|
478
493
|
name: string;
|
|
494
|
+
description: string;
|
|
479
495
|
amount: number;
|
|
480
496
|
}
|
|
481
497
|
export interface _Event {
|
|
482
498
|
breaks: string[];
|
|
483
499
|
id: string;
|
|
500
|
+
line_item_type: "EVENT";
|
|
484
501
|
name: string;
|
|
485
502
|
internal_notes: string;
|
|
486
503
|
external_notes: string;
|