@go-avro/avro-js 0.0.2-beta.5 → 0.0.2-beta.51
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.js +17 -1
- package/dist/client/QueryClient.d.ts +215 -5
- package/dist/client/QueryClient.js +96 -164
- package/dist/client/core/fetch.d.ts +1 -0
- package/dist/client/core/fetch.js +67 -0
- package/dist/client/core/utils.d.ts +1 -0
- package/dist/client/core/utils.js +13 -0
- package/dist/client/core/xhr.d.ts +1 -0
- package/dist/client/core/xhr.js +80 -0
- package/dist/client/hooks/bills.d.ts +1 -0
- package/dist/client/hooks/bills.js +141 -0
- package/dist/client/hooks/companies.d.ts +1 -0
- package/dist/client/hooks/companies.js +51 -0
- package/dist/client/hooks/events.d.ts +1 -0
- package/dist/client/hooks/events.js +306 -0
- package/dist/client/hooks/jobs.d.ts +1 -0
- package/dist/client/hooks/jobs.js +184 -0
- package/dist/client/hooks/months.d.ts +1 -0
- package/dist/client/hooks/months.js +92 -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 +127 -0
- package/dist/client/hooks/sessions.d.ts +1 -0
- package/dist/client/hooks/sessions.js +77 -0
- package/dist/client/hooks/users.d.ts +1 -0
- package/dist/client/hooks/users.js +38 -0
- package/dist/index.d.ts +13 -0
- package/dist/index.js +13 -0
- package/dist/types/api.d.ts +99 -22
- package/package.json +5 -1
package/README.md
CHANGED
|
@@ -10,6 +10,7 @@ This SDK provides:
|
|
|
10
10
|
- Typed API interfaces for Avro entities (users, jobs, teams, etc.)
|
|
11
11
|
- Pluggable token storage (in-memory, localStorage, SecureStore, etc.)
|
|
12
12
|
- XHR-based requests for compatibility with React Native WebViews and older environments
|
|
13
|
+
- Mutation and Data Hooks for easy plug-in use in React and React Native projects.
|
|
13
14
|
|
|
14
15
|
## Installation
|
|
15
16
|
|
package/dist/auth/AuthManager.js
CHANGED
|
@@ -26,7 +26,23 @@ export class AuthManager {
|
|
|
26
26
|
'Authorization': `Bearer ${tokens.access_token}`,
|
|
27
27
|
},
|
|
28
28
|
});
|
|
29
|
-
|
|
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
|
+
}
|
|
30
46
|
}
|
|
31
47
|
catch (error) {
|
|
32
48
|
console.error('Error validating access token:', error);
|
|
@@ -1,5 +1,8 @@
|
|
|
1
|
+
import { InfiniteData, UseInfiniteQueryResult, useMutation, UseQueryResult } from '@tanstack/react-query';
|
|
1
2
|
import { AuthManager } from '../auth/AuthManager';
|
|
3
|
+
import { _Event, ApiInfo, Bill, Company, Job, LineItem, Route, ServiceMonth, Session, User } from '../types/api';
|
|
2
4
|
import { CancelToken, RetryStrategy } from '../types/client';
|
|
5
|
+
import { StandardError } from '../types/error';
|
|
3
6
|
export interface AvroQueryClientConfig {
|
|
4
7
|
baseUrl: string;
|
|
5
8
|
authManager: AuthManager;
|
|
@@ -7,12 +10,169 @@ export interface AvroQueryClientConfig {
|
|
|
7
10
|
retryStrategy?: RetryStrategy;
|
|
8
11
|
timeout?: number;
|
|
9
12
|
}
|
|
13
|
+
declare module '../client/QueryClient' {
|
|
14
|
+
interface AvroQueryClient {
|
|
15
|
+
_xhr<T>(method: string, path: string, body: any, cancelToken?: CancelToken, headers?: Record<string, string>, isIdempotent?: boolean, retryCount?: number): Promise<T>;
|
|
16
|
+
_fetch<T>(method: string, path: string, body: any, cancelToken?: CancelToken, headers?: Record<string, string>, isIdempotent?: boolean, retryCount?: number): Promise<T>;
|
|
17
|
+
getDelay(strategy: RetryStrategy, attempt: number): number;
|
|
18
|
+
useGetRoot(): UseQueryResult<ApiInfo, StandardError>;
|
|
19
|
+
useGetJobs(companyGuid: string, body: {
|
|
20
|
+
amt?: number;
|
|
21
|
+
query?: string;
|
|
22
|
+
}, total: number, onProgress?: (fraction: number) => void, isMainLoad?: boolean): UseQueryResult<Job[], StandardError>;
|
|
23
|
+
useGetRoutes(companyGuid: string, body: {
|
|
24
|
+
amt?: number;
|
|
25
|
+
query?: string;
|
|
26
|
+
}, total: number, onProgress?: (fraction: number) => void): UseQueryResult<any[], StandardError>;
|
|
27
|
+
useGetEvents(companyGuid: string, body: {
|
|
28
|
+
amt?: number;
|
|
29
|
+
known_ids?: string[];
|
|
30
|
+
unknown_ids?: string[];
|
|
31
|
+
query?: string;
|
|
32
|
+
unbilled?: boolean;
|
|
33
|
+
billed?: boolean;
|
|
34
|
+
paid?: boolean;
|
|
35
|
+
jobId?: string;
|
|
36
|
+
}): UseInfiniteQueryResult<InfiniteData<_Event[], unknown>, StandardError>;
|
|
37
|
+
useGetMonths(companyGuid: string, body: {
|
|
38
|
+
amt?: number;
|
|
39
|
+
known_ids?: string[];
|
|
40
|
+
unknown_ids?: string[];
|
|
41
|
+
query?: string;
|
|
42
|
+
unbilled?: boolean;
|
|
43
|
+
billed?: boolean;
|
|
44
|
+
paid?: boolean;
|
|
45
|
+
jobId?: string;
|
|
46
|
+
}): UseInfiniteQueryResult<InfiniteData<ServiceMonth[], unknown>, StandardError>;
|
|
47
|
+
useGetBills(companyGuid: string, body: {
|
|
48
|
+
amt?: number;
|
|
49
|
+
known_ids?: string[];
|
|
50
|
+
unknown_ids?: string[];
|
|
51
|
+
query?: string;
|
|
52
|
+
paid?: boolean;
|
|
53
|
+
}): UseInfiniteQueryResult<InfiniteData<Bill[], unknown>, StandardError>;
|
|
54
|
+
useGetCompanies(options?: {}): UseQueryResult<{
|
|
55
|
+
name: string;
|
|
56
|
+
id: string;
|
|
57
|
+
}[], StandardError>;
|
|
58
|
+
useGetCompany(companyId: string): UseQueryResult<Company, StandardError>;
|
|
59
|
+
useGetJob(jobId: string): UseQueryResult<Job, StandardError>;
|
|
60
|
+
useGetEvent(eventId: string): UseQueryResult<_Event, StandardError>;
|
|
61
|
+
useGetUser(userId: string): UseQueryResult<User, StandardError>;
|
|
62
|
+
useGetSelf(): UseQueryResult<User, StandardError>;
|
|
63
|
+
useGetBill(billId: string): UseQueryResult<Bill, StandardError>;
|
|
64
|
+
useGetRoute(routeId: string): UseQueryResult<Route, StandardError>;
|
|
65
|
+
useGetUserSessions(): UseQueryResult<Session[], StandardError>;
|
|
66
|
+
useCreateEvent(): ReturnType<typeof useMutation<{
|
|
67
|
+
id: string;
|
|
68
|
+
}, StandardError, {
|
|
69
|
+
companyId: string;
|
|
70
|
+
eventData: Partial<_Event>;
|
|
71
|
+
}>>;
|
|
72
|
+
useCreateUserSession(): ReturnType<typeof useMutation<{
|
|
73
|
+
id: string;
|
|
74
|
+
}, StandardError, {
|
|
75
|
+
companyId: string;
|
|
76
|
+
sessionData: Partial<Session>;
|
|
77
|
+
}>>;
|
|
78
|
+
useCreateBill(): ReturnType<typeof useMutation<{
|
|
79
|
+
id: string;
|
|
80
|
+
invoice_id: number;
|
|
81
|
+
}, StandardError, {
|
|
82
|
+
companyId: string;
|
|
83
|
+
data: {
|
|
84
|
+
line_items: LineItem[];
|
|
85
|
+
due_date: number;
|
|
86
|
+
users: string[];
|
|
87
|
+
custom_emails: [string, string][];
|
|
88
|
+
};
|
|
89
|
+
}>>;
|
|
90
|
+
useCreateJob(): ReturnType<typeof useMutation<{
|
|
91
|
+
id: string;
|
|
92
|
+
}, StandardError, {
|
|
93
|
+
companyId: string;
|
|
94
|
+
jobData: Partial<Job>;
|
|
95
|
+
}>>;
|
|
96
|
+
useUpdateEvent(): ReturnType<typeof useMutation<{
|
|
97
|
+
msg: string;
|
|
98
|
+
}, StandardError, {
|
|
99
|
+
eventId: string;
|
|
100
|
+
updates: Partial<_Event>;
|
|
101
|
+
}>>;
|
|
102
|
+
useUpdateUserSession(): ReturnType<typeof useMutation<{
|
|
103
|
+
msg: string;
|
|
104
|
+
}, StandardError, {
|
|
105
|
+
sessionId: string;
|
|
106
|
+
updates: Partial<Session>;
|
|
107
|
+
}>>;
|
|
108
|
+
useUpdateJob(): ReturnType<typeof useMutation<{
|
|
109
|
+
msg: string;
|
|
110
|
+
}, StandardError, {
|
|
111
|
+
jobId: string;
|
|
112
|
+
updates: Partial<Job>;
|
|
113
|
+
}>>;
|
|
114
|
+
useUpdateBill(): ReturnType<typeof useMutation<{
|
|
115
|
+
msg: string;
|
|
116
|
+
}, StandardError, {
|
|
117
|
+
billId: string;
|
|
118
|
+
updates: Partial<Bill>;
|
|
119
|
+
}>>;
|
|
120
|
+
useUpdateRoute(): ReturnType<typeof useMutation<{
|
|
121
|
+
msg: string;
|
|
122
|
+
}, StandardError, {
|
|
123
|
+
routeId: string;
|
|
124
|
+
updates: Partial<Route>;
|
|
125
|
+
}>>;
|
|
126
|
+
useUpdateEvents(): ReturnType<typeof useMutation<void, StandardError, {
|
|
127
|
+
companyId: string;
|
|
128
|
+
events: (_Event & {
|
|
129
|
+
page?: number;
|
|
130
|
+
})[];
|
|
131
|
+
action: "billed" | "paid";
|
|
132
|
+
}>>;
|
|
133
|
+
useUpdateMonths(): ReturnType<typeof useMutation<void, StandardError, {
|
|
134
|
+
companyId: string;
|
|
135
|
+
months: (ServiceMonth & {
|
|
136
|
+
page?: number;
|
|
137
|
+
})[];
|
|
138
|
+
action: "billed" | "paid";
|
|
139
|
+
}>>;
|
|
140
|
+
useDeleteJob(): ReturnType<typeof useMutation<{
|
|
141
|
+
msg: string;
|
|
142
|
+
}, StandardError, {
|
|
143
|
+
jobId: string;
|
|
144
|
+
}>>;
|
|
145
|
+
useUpdateCompany(): ReturnType<typeof useMutation<{
|
|
146
|
+
msg: string;
|
|
147
|
+
}, StandardError, {
|
|
148
|
+
companyId: string;
|
|
149
|
+
companyData: Partial<Company | {
|
|
150
|
+
logo: File | null;
|
|
151
|
+
}>;
|
|
152
|
+
}>>;
|
|
153
|
+
useDeleteEvent(): ReturnType<typeof useMutation<{
|
|
154
|
+
msg: string;
|
|
155
|
+
}, StandardError, {
|
|
156
|
+
eventId: string;
|
|
157
|
+
}>>;
|
|
158
|
+
useDeleteBill(): ReturnType<typeof useMutation<{
|
|
159
|
+
msg: string;
|
|
160
|
+
}, StandardError, {
|
|
161
|
+
billId: string;
|
|
162
|
+
}>>;
|
|
163
|
+
useDeleteRoute(): ReturnType<typeof useMutation<{
|
|
164
|
+
msg: string;
|
|
165
|
+
}, StandardError, {
|
|
166
|
+
routeId: string;
|
|
167
|
+
}>>;
|
|
168
|
+
useDeleteSelf(): ReturnType<typeof useMutation<{
|
|
169
|
+
msg: string;
|
|
170
|
+
}, StandardError, void>>;
|
|
171
|
+
}
|
|
172
|
+
}
|
|
10
173
|
export declare class AvroQueryClient {
|
|
11
|
-
|
|
174
|
+
protected config: Required<AvroQueryClientConfig>;
|
|
12
175
|
constructor(config: AvroQueryClientConfig);
|
|
13
|
-
getDelay(strategy: RetryStrategy, attempt: number): number;
|
|
14
|
-
private _xhr;
|
|
15
|
-
private _fetch;
|
|
16
176
|
get<T>(path: string, cancelToken?: CancelToken, headers?: Record<string, string>): Promise<T>;
|
|
17
177
|
post<T>(path: string, data: any, cancelToken?: CancelToken, headers?: Record<string, string>): Promise<T>;
|
|
18
178
|
put<T>(path: string, data: any, cancelToken?: CancelToken, headers?: Record<string, string>): Promise<T>;
|
|
@@ -22,5 +182,55 @@ export declare class AvroQueryClient {
|
|
|
22
182
|
password: string;
|
|
23
183
|
}, cancelToken?: CancelToken): Promise<Boolean>;
|
|
24
184
|
logout(cancelToken?: CancelToken): Promise<void>;
|
|
25
|
-
fetchJobs(companyGuid: string,
|
|
185
|
+
fetchJobs(companyGuid: string, body?: {
|
|
186
|
+
amt?: number;
|
|
187
|
+
known_ids?: string[];
|
|
188
|
+
unknown_ids?: string[];
|
|
189
|
+
query?: string;
|
|
190
|
+
offset?: number;
|
|
191
|
+
}, cancelToken?: CancelToken, headers?: Record<string, string>): Promise<any>;
|
|
192
|
+
fetchEvents(companyGuid: string, body?: {
|
|
193
|
+
amt?: number;
|
|
194
|
+
known_ids?: string[];
|
|
195
|
+
unknown_ids?: string[];
|
|
196
|
+
query?: string;
|
|
197
|
+
offset?: number;
|
|
198
|
+
unbilled?: boolean;
|
|
199
|
+
billed?: boolean;
|
|
200
|
+
paid?: boolean;
|
|
201
|
+
jobId?: string | null;
|
|
202
|
+
}, cancelToken?: CancelToken, headers?: Record<string, string>): Promise<any>;
|
|
203
|
+
fetchMonths(companyGuid: string, body?: {
|
|
204
|
+
amt?: number;
|
|
205
|
+
known_ids?: string[];
|
|
206
|
+
unknown_ids?: string[];
|
|
207
|
+
query?: string;
|
|
208
|
+
offset?: number;
|
|
209
|
+
unbilled?: boolean;
|
|
210
|
+
billed?: boolean;
|
|
211
|
+
paid?: boolean;
|
|
212
|
+
jobId?: string | null;
|
|
213
|
+
}, cancelToken?: CancelToken, headers?: Record<string, string>): Promise<any>;
|
|
214
|
+
fetchBills(companyGuid: string, body?: {
|
|
215
|
+
amt?: number;
|
|
216
|
+
known_ids?: string[];
|
|
217
|
+
unknown_ids?: string[];
|
|
218
|
+
query?: string;
|
|
219
|
+
offset?: number;
|
|
220
|
+
paid?: boolean;
|
|
221
|
+
}, cancelToken?: CancelToken, headers?: Record<string, string>): Promise<any>;
|
|
222
|
+
fetchRoutes(companyGuid: string, body?: {
|
|
223
|
+
amt?: number;
|
|
224
|
+
known_ids?: string[];
|
|
225
|
+
unknown_ids?: string[];
|
|
226
|
+
query?: string;
|
|
227
|
+
offset?: number;
|
|
228
|
+
}, cancelToken?: CancelToken, headers?: Record<string, string>): Promise<any>;
|
|
229
|
+
sendEmail(emailId: string, formData: FormData): Promise<void>;
|
|
230
|
+
createBill(companyGuid: string, data: {
|
|
231
|
+
line_items: LineItem[];
|
|
232
|
+
due_date: number;
|
|
233
|
+
users: string[];
|
|
234
|
+
custom_emails: [string, string][];
|
|
235
|
+
}, cancelToken?: CancelToken): Promise<any>;
|
|
26
236
|
}
|
|
@@ -9,161 +9,6 @@ export class AvroQueryClient {
|
|
|
9
9
|
timeout: config.timeout ?? 0,
|
|
10
10
|
};
|
|
11
11
|
}
|
|
12
|
-
getDelay(strategy, attempt) {
|
|
13
|
-
if (typeof strategy === 'function') {
|
|
14
|
-
return strategy(attempt);
|
|
15
|
-
}
|
|
16
|
-
else if (strategy === 'fixed') {
|
|
17
|
-
return 1000;
|
|
18
|
-
}
|
|
19
|
-
else if (strategy === 'exponential') {
|
|
20
|
-
return Math.pow(2, attempt) * 100;
|
|
21
|
-
}
|
|
22
|
-
throw new Error(`Invalid retry strategy: ${strategy}`);
|
|
23
|
-
}
|
|
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'));
|
|
97
|
-
}
|
|
98
|
-
};
|
|
99
|
-
if (this.config.timeout) {
|
|
100
|
-
xhr.timeout = this.config.timeout;
|
|
101
|
-
xhr.ontimeout = () => reject(new StandardError(0, 'Request timed out'));
|
|
102
|
-
}
|
|
103
|
-
xhr.send(body);
|
|
104
|
-
});
|
|
105
|
-
});
|
|
106
|
-
}
|
|
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
|
-
});
|
|
161
|
-
}
|
|
162
|
-
}
|
|
163
|
-
return response.json();
|
|
164
|
-
});
|
|
165
|
-
});
|
|
166
|
-
}
|
|
167
12
|
get(path, cancelToken, headers = {}) {
|
|
168
13
|
return this._xhr('GET', path, null, cancelToken, headers, true);
|
|
169
14
|
}
|
|
@@ -197,17 +42,11 @@ export class AvroQueryClient {
|
|
|
197
42
|
throw new StandardError(500, 'Logout failed');
|
|
198
43
|
});
|
|
199
44
|
}
|
|
200
|
-
fetchJobs(companyGuid,
|
|
201
|
-
|
|
202
|
-
amt,
|
|
203
|
-
known_ids: knownIds,
|
|
204
|
-
unknown_ids: unknownIds,
|
|
205
|
-
query: keyword,
|
|
206
|
-
};
|
|
207
|
-
if (!companyGuid) {
|
|
45
|
+
fetchJobs(companyGuid, body = {}, cancelToken, headers = {}) {
|
|
46
|
+
if (!companyGuid || companyGuid.trim() === '') {
|
|
208
47
|
return Promise.reject(new StandardError(400, 'Company GUID is required'));
|
|
209
48
|
}
|
|
210
|
-
return this._fetch('POST', `/company/${companyGuid}/jobs
|
|
49
|
+
return this._fetch('POST', `/company/${companyGuid}/jobs`, body, cancelToken, headers)
|
|
211
50
|
.then(response => {
|
|
212
51
|
if (!response || !Array.isArray(response)) {
|
|
213
52
|
throw new StandardError(400, 'Invalid jobs response');
|
|
@@ -219,4 +58,97 @@ export class AvroQueryClient {
|
|
|
219
58
|
throw new StandardError(500, 'Failed to fetch jobs');
|
|
220
59
|
});
|
|
221
60
|
}
|
|
61
|
+
fetchEvents(companyGuid, body = {}, cancelToken, headers = {}) {
|
|
62
|
+
if (!companyGuid || companyGuid.trim() === '') {
|
|
63
|
+
return Promise.reject(new StandardError(400, 'Company GUID is required'));
|
|
64
|
+
}
|
|
65
|
+
return this._fetch('POST', `/company/${companyGuid}/events`, body, cancelToken, headers)
|
|
66
|
+
.then(response => {
|
|
67
|
+
if (!response || !Array.isArray(response)) {
|
|
68
|
+
throw new StandardError(400, 'Invalid events response');
|
|
69
|
+
}
|
|
70
|
+
return response;
|
|
71
|
+
})
|
|
72
|
+
.catch(err => {
|
|
73
|
+
console.error('Failed to fetch events:', err);
|
|
74
|
+
throw new StandardError(500, 'Failed to fetch events');
|
|
75
|
+
});
|
|
76
|
+
}
|
|
77
|
+
fetchMonths(companyGuid, body = {}, cancelToken, headers = {}) {
|
|
78
|
+
if (!companyGuid || companyGuid.trim() === '') {
|
|
79
|
+
return Promise.reject(new StandardError(400, 'Company GUID is required'));
|
|
80
|
+
}
|
|
81
|
+
return this._fetch('POST', `/company/${companyGuid}/months`, body, cancelToken, headers)
|
|
82
|
+
.then(response => {
|
|
83
|
+
if (!response || !Array.isArray(response)) {
|
|
84
|
+
throw new StandardError(400, 'Invalid months response');
|
|
85
|
+
}
|
|
86
|
+
return response;
|
|
87
|
+
})
|
|
88
|
+
.catch(err => {
|
|
89
|
+
console.error('Failed to fetch months:', err);
|
|
90
|
+
throw new StandardError(500, 'Failed to fetch months');
|
|
91
|
+
});
|
|
92
|
+
}
|
|
93
|
+
fetchBills(companyGuid, body = {}, cancelToken, headers = {}) {
|
|
94
|
+
if (!companyGuid || companyGuid.trim() === '') {
|
|
95
|
+
return Promise.reject(new StandardError(400, 'Company GUID is required'));
|
|
96
|
+
}
|
|
97
|
+
return this._fetch('POST', `/company/${companyGuid}/bills`, body, cancelToken, headers)
|
|
98
|
+
.then(response => {
|
|
99
|
+
if (!response || !Array.isArray(response)) {
|
|
100
|
+
throw new StandardError(400, 'Invalid bills response');
|
|
101
|
+
}
|
|
102
|
+
return response;
|
|
103
|
+
})
|
|
104
|
+
.catch(err => {
|
|
105
|
+
console.error('Failed to fetch bills:', err);
|
|
106
|
+
throw new StandardError(500, 'Failed to fetch bills');
|
|
107
|
+
});
|
|
108
|
+
}
|
|
109
|
+
fetchRoutes(companyGuid, body = {}, cancelToken, headers = {}) {
|
|
110
|
+
if (!companyGuid || companyGuid.trim() === '') {
|
|
111
|
+
return Promise.reject(new StandardError(400, 'Company GUID is required'));
|
|
112
|
+
}
|
|
113
|
+
return this._fetch('POST', `/company/${companyGuid}/routes`, body, cancelToken, headers)
|
|
114
|
+
.then(response => {
|
|
115
|
+
if (!response || !Array.isArray(response)) {
|
|
116
|
+
throw new StandardError(400, 'Invalid routes response');
|
|
117
|
+
}
|
|
118
|
+
return response;
|
|
119
|
+
})
|
|
120
|
+
.catch(err => {
|
|
121
|
+
console.error('Failed to fetch routes:', err);
|
|
122
|
+
throw new StandardError(500, 'Failed to fetch routes');
|
|
123
|
+
});
|
|
124
|
+
}
|
|
125
|
+
sendEmail(emailId, formData) {
|
|
126
|
+
try {
|
|
127
|
+
return this._xhr('POST', `/email/${emailId}`, formData);
|
|
128
|
+
}
|
|
129
|
+
catch (error) {
|
|
130
|
+
throw new StandardError(500, `Failed to send email: ${error}`);
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
createBill(companyGuid, data, cancelToken) {
|
|
134
|
+
if (!companyGuid) {
|
|
135
|
+
return Promise.reject(new StandardError(400, 'Company GUID is required'));
|
|
136
|
+
}
|
|
137
|
+
const body = {
|
|
138
|
+
events: data.line_items.filter(item => item.line_item_type === 'EVENT').map(item => item.id),
|
|
139
|
+
months: data.line_items.filter(item => item.line_item_type === 'SERVICE_MONTH').map(item => item.id),
|
|
140
|
+
line_items: data.line_items.filter(item => item.line_item_type === 'CUSTOM'),
|
|
141
|
+
manual_emails: data.custom_emails,
|
|
142
|
+
users: data.users,
|
|
143
|
+
due_date: data.due_date,
|
|
144
|
+
};
|
|
145
|
+
try {
|
|
146
|
+
return this._xhr('POST', `/company/${companyGuid}/bill`, JSON.stringify(body), cancelToken, {
|
|
147
|
+
'Content-Type': 'application/json',
|
|
148
|
+
});
|
|
149
|
+
}
|
|
150
|
+
catch (error) {
|
|
151
|
+
throw new StandardError(500, `Failed to create bill: ${error}`);
|
|
152
|
+
}
|
|
153
|
+
}
|
|
222
154
|
}
|
|
@@ -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 {};
|