@go-avro/avro-js 0.0.2-beta.6 → 0.0.2-beta.60
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/client/QueryClient.d.ts +254 -10
- package/dist/client/QueryClient.js +124 -178
- 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 +87 -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 +307 -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 +154 -0
- package/dist/client/hooks/users.d.ts +1 -0
- package/dist/client/hooks/users.js +93 -0
- package/dist/index.d.ts +13 -0
- package/dist/index.js +13 -0
- package/dist/types/api.d.ts +106 -23
- package/dist/types/api.js +6 -1
- package/package.json +5 -1
|
@@ -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 {};
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
import { AvroQueryClient } from '../../client/QueryClient';
|
|
2
|
+
import { StandardError } from '../../types/error';
|
|
3
|
+
AvroQueryClient.prototype._xhr = function (method, path, body, cancelToken, headers = {}, isIdempotent = false, retryCount = 0, progressUpdateCallback) {
|
|
4
|
+
const checkCancelled = () => {
|
|
5
|
+
if (cancelToken?.isCancelled()) {
|
|
6
|
+
return new StandardError(0, 'Request cancelled');
|
|
7
|
+
}
|
|
8
|
+
return null;
|
|
9
|
+
};
|
|
10
|
+
return new Promise((resolve, reject) => {
|
|
11
|
+
this.config.authManager.accessToken().then(token => {
|
|
12
|
+
const cancelErr = checkCancelled();
|
|
13
|
+
if (cancelErr)
|
|
14
|
+
return reject(cancelErr);
|
|
15
|
+
const xhr = new XMLHttpRequest();
|
|
16
|
+
const url = this.config.baseUrl + path;
|
|
17
|
+
xhr.open(method, url, true);
|
|
18
|
+
if (token)
|
|
19
|
+
xhr.setRequestHeader('Authorization', `Bearer ${token}`);
|
|
20
|
+
Object.entries(headers).forEach(([key, value]) => xhr.setRequestHeader(key, value));
|
|
21
|
+
xhr.onload = () => {
|
|
22
|
+
const cancelErr = checkCancelled();
|
|
23
|
+
if (cancelErr)
|
|
24
|
+
return reject(cancelErr);
|
|
25
|
+
if (xhr.status === 401 && this.config.authManager.refreshTokens && retryCount === 0) {
|
|
26
|
+
this.config.authManager
|
|
27
|
+
.refreshTokens()
|
|
28
|
+
.then(() => {
|
|
29
|
+
this._xhr(method, path, body, cancelToken, headers, isIdempotent, retryCount + 1).then(resolve, reject);
|
|
30
|
+
})
|
|
31
|
+
.catch(() => reject(new StandardError(401, 'Unauthorized (refresh failed)')));
|
|
32
|
+
return;
|
|
33
|
+
}
|
|
34
|
+
if (xhr.status >= 200 && xhr.status < 300) {
|
|
35
|
+
try {
|
|
36
|
+
resolve(JSON.parse(xhr.responseText));
|
|
37
|
+
}
|
|
38
|
+
catch {
|
|
39
|
+
resolve(xhr.responseText);
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
else {
|
|
43
|
+
if (retryCount < this.config.maxRetries) {
|
|
44
|
+
const delay = this.getDelay(this.config.retryStrategy, retryCount);
|
|
45
|
+
setTimeout(() => {
|
|
46
|
+
this._xhr(method, path, body, cancelToken, headers, isIdempotent, retryCount + 1).then(resolve, reject);
|
|
47
|
+
}, delay);
|
|
48
|
+
}
|
|
49
|
+
else {
|
|
50
|
+
let msg = xhr.statusText;
|
|
51
|
+
try {
|
|
52
|
+
const parsed = JSON.parse(xhr.responseText);
|
|
53
|
+
msg = parsed.msg || msg;
|
|
54
|
+
}
|
|
55
|
+
catch {
|
|
56
|
+
console.warn('Failed to parse error response:', xhr.responseText);
|
|
57
|
+
}
|
|
58
|
+
reject(new StandardError(xhr.status, msg));
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
};
|
|
62
|
+
if (progressUpdateCallback && xhr.upload) {
|
|
63
|
+
xhr.upload.onprogress = (event) => {
|
|
64
|
+
if (event.lengthComputable) {
|
|
65
|
+
progressUpdateCallback(event.loaded, event.total);
|
|
66
|
+
}
|
|
67
|
+
};
|
|
68
|
+
}
|
|
69
|
+
xhr.onerror = () => {
|
|
70
|
+
if (retryCount < this.config.maxRetries) {
|
|
71
|
+
const delay = this.getDelay(this.config.retryStrategy, retryCount);
|
|
72
|
+
setTimeout(() => {
|
|
73
|
+
this._xhr(method, path, body, cancelToken, headers, isIdempotent, retryCount + 1).then(resolve, reject);
|
|
74
|
+
}, delay);
|
|
75
|
+
}
|
|
76
|
+
else {
|
|
77
|
+
reject(new StandardError(0, 'Network Error'));
|
|
78
|
+
}
|
|
79
|
+
};
|
|
80
|
+
if (this.config.timeout) {
|
|
81
|
+
xhr.timeout = this.config.timeout;
|
|
82
|
+
xhr.ontimeout = () => reject(new StandardError(0, 'Request timed out'));
|
|
83
|
+
}
|
|
84
|
+
xhr.send(body);
|
|
85
|
+
});
|
|
86
|
+
});
|
|
87
|
+
};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,141 @@
|
|
|
1
|
+
import { useQueryClient, useInfiniteQuery, useQuery, useMutation } from '@tanstack/react-query';
|
|
2
|
+
import { AvroQueryClient } from '../../client/QueryClient';
|
|
3
|
+
AvroQueryClient.prototype.useGetBills = function (companyGuid, body) {
|
|
4
|
+
const queryClient = useQueryClient();
|
|
5
|
+
const result = useInfiniteQuery({
|
|
6
|
+
queryKey: [
|
|
7
|
+
'bills',
|
|
8
|
+
companyGuid,
|
|
9
|
+
body.query ?? "",
|
|
10
|
+
body.known_ids ?? [],
|
|
11
|
+
body.unknown_ids ?? [],
|
|
12
|
+
body.paid ?? false,
|
|
13
|
+
],
|
|
14
|
+
initialPageParam: 0,
|
|
15
|
+
getNextPageParam: (lastPage, allPages) => {
|
|
16
|
+
if (lastPage.length < (body.amt ?? 50))
|
|
17
|
+
return undefined;
|
|
18
|
+
return allPages.flat().length; // next offset
|
|
19
|
+
},
|
|
20
|
+
queryFn: ({ pageParam = 0 }) => this.fetchBills(companyGuid, { ...body, offset: pageParam }),
|
|
21
|
+
});
|
|
22
|
+
if (result.data) {
|
|
23
|
+
result.data.pages.forEach((data_page) => {
|
|
24
|
+
data_page.forEach((bill) => {
|
|
25
|
+
queryClient.setQueryData(['bill', bill.id], bill);
|
|
26
|
+
});
|
|
27
|
+
});
|
|
28
|
+
}
|
|
29
|
+
return result;
|
|
30
|
+
};
|
|
31
|
+
AvroQueryClient.prototype.useGetBill = function (billId) {
|
|
32
|
+
return useQuery({
|
|
33
|
+
queryKey: ['bill', billId],
|
|
34
|
+
queryFn: () => this.get(`/bill/${billId}`),
|
|
35
|
+
enabled: Boolean(billId),
|
|
36
|
+
});
|
|
37
|
+
};
|
|
38
|
+
AvroQueryClient.prototype.useCreateBill = function () {
|
|
39
|
+
const queryClient = useQueryClient();
|
|
40
|
+
return useMutation({
|
|
41
|
+
mutationFn: async ({ companyId, data, }) => {
|
|
42
|
+
const body = {
|
|
43
|
+
events: data.line_items.filter(item => item.line_item_type === 'EVENT').map(item => item.id),
|
|
44
|
+
months: data.line_items.filter(item => item.line_item_type === 'SERVICE_MONTH').map(item => item.id),
|
|
45
|
+
line_items: data.line_items.filter(item => item.line_item_type === 'CUSTOM'),
|
|
46
|
+
manual_emails: data.custom_emails,
|
|
47
|
+
users: data.users,
|
|
48
|
+
due_date: data.due_date,
|
|
49
|
+
};
|
|
50
|
+
return this.post(`/company/${companyId}/bill`, JSON.stringify(body), undefined, {
|
|
51
|
+
'Content-Type': 'application/json',
|
|
52
|
+
});
|
|
53
|
+
},
|
|
54
|
+
onMutate: async ({ companyId }) => {
|
|
55
|
+
await queryClient.cancelQueries({ queryKey: ['bills', companyId] });
|
|
56
|
+
const previousBills = queryClient.getQueryData(['bills', companyId]);
|
|
57
|
+
// TODO: Create a fake bill object for optimistic update and update events and months accordingly
|
|
58
|
+
return { previousBills };
|
|
59
|
+
},
|
|
60
|
+
onError: (_err, _variables, context) => {
|
|
61
|
+
if (context?.previousBills) {
|
|
62
|
+
queryClient.setQueryData(['bills'], context.previousBills);
|
|
63
|
+
}
|
|
64
|
+
},
|
|
65
|
+
onSettled: (_data, _error, variables) => {
|
|
66
|
+
queryClient.invalidateQueries({ queryKey: ['bills', variables.companyId] });
|
|
67
|
+
queryClient.invalidateQueries({ queryKey: ['events', variables.companyId] });
|
|
68
|
+
queryClient.invalidateQueries({ queryKey: ['months', variables.companyId] });
|
|
69
|
+
},
|
|
70
|
+
});
|
|
71
|
+
};
|
|
72
|
+
AvroQueryClient.prototype.useUpdateBill = function () {
|
|
73
|
+
const queryClient = useQueryClient();
|
|
74
|
+
return useMutation({
|
|
75
|
+
mutationFn: ({ billId, updates }) => {
|
|
76
|
+
return this.put(`/bill/${billId}`, JSON.stringify(updates), undefined, {
|
|
77
|
+
"Content-Type": "application/json",
|
|
78
|
+
});
|
|
79
|
+
},
|
|
80
|
+
onMutate: async ({ billId, updates }) => {
|
|
81
|
+
await queryClient.cancelQueries({ queryKey: ['bills'] });
|
|
82
|
+
await queryClient.cancelQueries({ queryKey: ['bill', billId] });
|
|
83
|
+
const previousBills = queryClient.getQueryData(['bills']);
|
|
84
|
+
const previousBill = queryClient.getQueryData(['bill', billId]);
|
|
85
|
+
queryClient.setQueryData(['bill', billId], (oldData) => oldData ? { ...oldData, ...updates } : undefined);
|
|
86
|
+
queryClient.setQueriesData({ queryKey: ['bills'] }, (oldData) => {
|
|
87
|
+
if (!oldData)
|
|
88
|
+
return oldData;
|
|
89
|
+
if (oldData.pages) {
|
|
90
|
+
return {
|
|
91
|
+
...oldData,
|
|
92
|
+
pages: oldData.pages.map((page) => page.map((bill) => bill.id === billId ? { ...bill, ...updates } : bill)),
|
|
93
|
+
};
|
|
94
|
+
}
|
|
95
|
+
if (Array.isArray(oldData)) {
|
|
96
|
+
return oldData.map((bill) => bill.id === billId ? { ...bill, ...updates } : bill);
|
|
97
|
+
}
|
|
98
|
+
return oldData;
|
|
99
|
+
});
|
|
100
|
+
return { previousBills, previousBill };
|
|
101
|
+
},
|
|
102
|
+
onError: (err, variables, context) => {
|
|
103
|
+
const { billId } = variables;
|
|
104
|
+
if (context?.previousBills) {
|
|
105
|
+
queryClient.setQueryData(['bills'], context.previousBills);
|
|
106
|
+
}
|
|
107
|
+
if (context?.previousBill) {
|
|
108
|
+
queryClient.setQueryData(['bill', billId], context.previousBill);
|
|
109
|
+
}
|
|
110
|
+
},
|
|
111
|
+
onSettled: (data, error, variables) => {
|
|
112
|
+
const { billId } = variables;
|
|
113
|
+
queryClient.invalidateQueries({ queryKey: ['bills'] });
|
|
114
|
+
queryClient.invalidateQueries({ queryKey: ['bill', billId] });
|
|
115
|
+
},
|
|
116
|
+
});
|
|
117
|
+
};
|
|
118
|
+
AvroQueryClient.prototype.useDeleteBill = function () {
|
|
119
|
+
const queryClient = useQueryClient();
|
|
120
|
+
return useMutation({
|
|
121
|
+
mutationFn: async ({ billId }) => {
|
|
122
|
+
return this.delete(`/bill/${billId}`);
|
|
123
|
+
},
|
|
124
|
+
onMutate: async ({ billId }) => {
|
|
125
|
+
await queryClient.cancelQueries({ queryKey: ['bills'] });
|
|
126
|
+
const previousBills = queryClient.getQueryData(['bills']);
|
|
127
|
+
// TODO: Create a fake bill object for optimistic update and update events and months accordingly
|
|
128
|
+
return { previousBills };
|
|
129
|
+
},
|
|
130
|
+
onError: (_err, _variables, context) => {
|
|
131
|
+
if (context?.previousBills) {
|
|
132
|
+
queryClient.setQueryData(['bills'], context.previousBills);
|
|
133
|
+
}
|
|
134
|
+
},
|
|
135
|
+
onSettled: (_data, _error) => {
|
|
136
|
+
queryClient.invalidateQueries({ queryKey: ['bills'] });
|
|
137
|
+
queryClient.invalidateQueries({ queryKey: ['events'] });
|
|
138
|
+
queryClient.invalidateQueries({ queryKey: ['months'] });
|
|
139
|
+
},
|
|
140
|
+
});
|
|
141
|
+
};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import { useMutation, useQuery, useQueryClient } from '@tanstack/react-query';
|
|
2
|
+
import { AvroQueryClient } from '../../client/QueryClient';
|
|
3
|
+
AvroQueryClient.prototype.useGetCompanies = function (options = {}) {
|
|
4
|
+
return useQuery({
|
|
5
|
+
queryKey: ['/company/list'],
|
|
6
|
+
queryFn: () => this.get('/company/list'),
|
|
7
|
+
...options,
|
|
8
|
+
});
|
|
9
|
+
};
|
|
10
|
+
AvroQueryClient.prototype.useGetCompany = function (companyId) {
|
|
11
|
+
return useQuery({
|
|
12
|
+
queryKey: ['company', companyId],
|
|
13
|
+
queryFn: () => this.get(`/company/${companyId}`),
|
|
14
|
+
enabled: Boolean(companyId),
|
|
15
|
+
});
|
|
16
|
+
};
|
|
17
|
+
AvroQueryClient.prototype.useUpdateCompany = function () {
|
|
18
|
+
const queryClient = useQueryClient();
|
|
19
|
+
return useMutation({
|
|
20
|
+
mutationFn: async ({ companyId, companyData, }) => {
|
|
21
|
+
return this.put(`/company/${companyId}`, JSON.stringify(companyData), undefined, { "Content-Type": "application/json" });
|
|
22
|
+
},
|
|
23
|
+
onMutate: async ({ companyId, companyData }) => {
|
|
24
|
+
await queryClient.cancelQueries({ queryKey: ['company', companyId] });
|
|
25
|
+
await queryClient.cancelQueries({ queryKey: ['/company/list'] });
|
|
26
|
+
const previousCompany = queryClient.getQueryData(['company', companyId]);
|
|
27
|
+
const previousCompanyList = queryClient.getQueryData(['/company/list']);
|
|
28
|
+
queryClient.setQueryData(['company', companyId], (oldData) => oldData ? { ...oldData, ...companyData } : undefined);
|
|
29
|
+
queryClient.setQueryData(['/company/list'], (oldList) => {
|
|
30
|
+
if (!oldList)
|
|
31
|
+
return oldList;
|
|
32
|
+
return oldList.map((company) => company.id === companyId ? { ...company, ...companyData } : company);
|
|
33
|
+
});
|
|
34
|
+
return { previousCompany, previousCompanyList };
|
|
35
|
+
},
|
|
36
|
+
onError: (_err, variables, context) => {
|
|
37
|
+
const { companyId } = variables;
|
|
38
|
+
if (context?.previousCompany) {
|
|
39
|
+
queryClient.setQueryData(['company', companyId], context.previousCompany);
|
|
40
|
+
}
|
|
41
|
+
if (context?.previousCompanyList) {
|
|
42
|
+
queryClient.setQueryData(['/company/list'], context.previousCompanyList);
|
|
43
|
+
}
|
|
44
|
+
},
|
|
45
|
+
onSettled: (_data, _error, variables) => {
|
|
46
|
+
const { companyId } = variables;
|
|
47
|
+
queryClient.invalidateQueries({ queryKey: ['company', companyId] });
|
|
48
|
+
queryClient.invalidateQueries({ queryKey: ['/company/list'] });
|
|
49
|
+
},
|
|
50
|
+
});
|
|
51
|
+
};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|