@go-avro/avro-js 0.0.42 → 0.0.44
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 +3 -3
- package/dist/auth/AuthManager.js +24 -24
- package/dist/auth/storage.d.ts +1 -1
- package/dist/auth/storage.js +3 -3
- package/dist/client/AvroQueryClientProvider.d.ts +4 -4
- package/dist/client/AvroQueryClientProvider.js +3 -3
- package/dist/client/QueryClient.d.ts +15 -15
- package/dist/client/QueryClient.js +239 -259
- package/dist/client/core/fetch.js +9 -9
- package/dist/client/core/utils.js +4 -4
- package/dist/client/core/xhr.js +21 -21
- package/dist/client/hooks/analytics.js +12 -12
- package/dist/client/hooks/avro.js +4 -4
- package/dist/client/hooks/bills.js +36 -39
- package/dist/client/hooks/catalog_items.js +25 -31
- package/dist/client/hooks/chats.js +6 -6
- package/dist/client/hooks/companies.js +45 -57
- package/dist/client/hooks/email.d.ts +3 -3
- package/dist/client/hooks/email.js +5 -5
- package/dist/client/hooks/events.js +71 -81
- package/dist/client/hooks/groups.js +25 -31
- package/dist/client/hooks/jobs.js +29 -34
- package/dist/client/hooks/labels.js +25 -31
- package/dist/client/hooks/messages.js +7 -7
- package/dist/client/hooks/months.js +21 -21
- package/dist/client/hooks/plans.js +4 -4
- package/dist/client/hooks/prepayments.js +21 -21
- package/dist/client/hooks/proposal.js +11 -11
- package/dist/client/hooks/root.js +4 -4
- package/dist/client/hooks/routes.js +42 -53
- package/dist/client/hooks/sessions.js +33 -45
- package/dist/client/hooks/skills.js +22 -28
- package/dist/client/hooks/teams.js +26 -32
- package/dist/client/hooks/timecards.js +13 -13
- package/dist/client/hooks/users.js +39 -42
- package/dist/client/hooks/waivers.js +23 -23
- package/dist/index.d.ts +38 -38
- package/dist/index.js +37 -37
- package/dist/types/api/AdditionalCharge.d.ts +2 -2
- package/dist/types/api/Avro.d.ts +1 -1
- package/dist/types/api/Bill.d.ts +4 -4
- package/dist/types/api/Bill.js +4 -4
- package/dist/types/api/BillPayment.d.ts +2 -2
- package/dist/types/api/BillUser.d.ts +1 -1
- package/dist/types/api/CatalogItem.d.ts +1 -1
- package/dist/types/api/Chat.d.ts +2 -2
- package/dist/types/api/Company.d.ts +12 -12
- package/dist/types/api/CustomLineItem.d.ts +2 -2
- package/dist/types/api/Email.d.ts +2 -2
- package/dist/types/api/EmailNotification.d.ts +2 -2
- package/dist/types/api/Group.d.ts +1 -1
- package/dist/types/api/Job.d.ts +6 -6
- package/dist/types/api/Job.js +12 -12
- package/dist/types/api/LineItem.d.ts +1 -1
- package/dist/types/api/LineItem.js +12 -12
- package/dist/types/api/MemberState.d.ts +1 -1
- package/dist/types/api/Message.d.ts +1 -1
- package/dist/types/api/PaymentMethod.d.ts +1 -1
- package/dist/types/api/PaymentOption.d.ts +1 -1
- package/dist/types/api/PaymentType.js +2 -2
- package/dist/types/api/PlanPayment.d.ts +1 -1
- package/dist/types/api/Prepayment.d.ts +4 -4
- package/dist/types/api/Prepayment.js +1 -1
- package/dist/types/api/Route.d.ts +2 -2
- package/dist/types/api/Route.js +7 -7
- package/dist/types/api/RouteJob.d.ts +1 -1
- package/dist/types/api/ServiceMonth.d.ts +2 -2
- package/dist/types/api/Session.d.ts +2 -2
- package/dist/types/api/Task.d.ts +7 -7
- package/dist/types/api/Task.js +20 -22
- package/dist/types/api/Timecard.d.ts +1 -1
- package/dist/types/api/Timecard.js +4 -4
- package/dist/types/api/TimecardAction.js +6 -6
- package/dist/types/api/User.d.ts +4 -4
- package/dist/types/api/UserCompanyAssociation.d.ts +2 -2
- package/dist/types/api/UserCompanyAssociation.js +45 -45
- package/dist/types/api/_Event.d.ts +5 -5
- package/dist/types/api/_Event.js +1 -1
- package/dist/types/api.d.ts +44 -44
- package/dist/types/api.js +42 -42
- package/dist/types/cache.d.ts +1 -1
- package/dist/types/client.d.ts +1 -1
- package/package.json +2 -1
|
@@ -1,11 +1,11 @@
|
|
|
1
|
-
import io from
|
|
2
|
-
import { useMutation, useQueryClient, } from
|
|
3
|
-
import { v4 as uuidv4 } from
|
|
4
|
-
import { _Event, Job, LoginResponse, Route, } from
|
|
5
|
-
import { AuthState } from
|
|
6
|
-
import { StandardError } from
|
|
1
|
+
import io from 'socket.io-client';
|
|
2
|
+
import { useMutation, useQueryClient, } from '@tanstack/react-query';
|
|
3
|
+
import { v4 as uuidv4 } from 'uuid';
|
|
4
|
+
import { _Event, Job, LoginResponse, Route, } from '../types/api';
|
|
5
|
+
import { AuthState } from '../types/auth';
|
|
6
|
+
import { StandardError } from '../types/error';
|
|
7
7
|
function isBulkEvent(c) {
|
|
8
|
-
return
|
|
8
|
+
return 'invalidateKeys' in c;
|
|
9
9
|
}
|
|
10
10
|
/**
|
|
11
11
|
* Maps socket event names to cache-update strategies.
|
|
@@ -19,188 +19,188 @@ function isBulkEvent(c) {
|
|
|
19
19
|
const SOCKET_EVENT_CONFIG = {
|
|
20
20
|
// ── Company ──
|
|
21
21
|
create_company: {
|
|
22
|
-
entityKey:
|
|
23
|
-
action:
|
|
22
|
+
entityKey: 'companies',
|
|
23
|
+
action: 'create',
|
|
24
24
|
fetchPath: (id) => `/company/${id}`,
|
|
25
25
|
},
|
|
26
26
|
update_company: {
|
|
27
|
-
entityKey:
|
|
28
|
-
action:
|
|
27
|
+
entityKey: 'companies',
|
|
28
|
+
action: 'update',
|
|
29
29
|
fetchPath: (id) => `/company/${id}`,
|
|
30
30
|
},
|
|
31
|
-
delete_company: { entityKey:
|
|
31
|
+
delete_company: { entityKey: 'companies', action: 'delete', fetchPath: null },
|
|
32
32
|
// ── Users (no single-entity socket events) ──
|
|
33
|
-
user_updated: { invalidateKeys: [[
|
|
34
|
-
update_users: { invalidateKeys: [[
|
|
33
|
+
user_updated: { invalidateKeys: [['users'], ['user']] },
|
|
34
|
+
update_users: { invalidateKeys: [['users'], ['user']] },
|
|
35
35
|
// ── Jobs ──
|
|
36
36
|
create_job: {
|
|
37
|
-
entityKey:
|
|
38
|
-
action:
|
|
37
|
+
entityKey: 'jobs',
|
|
38
|
+
action: 'create',
|
|
39
39
|
fetchPath: (id) => `/job/${id}`,
|
|
40
40
|
construct: (d) => new Job(d),
|
|
41
41
|
},
|
|
42
42
|
update_job: {
|
|
43
|
-
entityKey:
|
|
44
|
-
action:
|
|
43
|
+
entityKey: 'jobs',
|
|
44
|
+
action: 'update',
|
|
45
45
|
fetchPath: (id) => `/job/${id}`,
|
|
46
46
|
construct: (d) => new Job(d),
|
|
47
47
|
},
|
|
48
|
-
delete_job: { entityKey:
|
|
49
|
-
update_jobs: { invalidateKeys: [[
|
|
50
|
-
delete_jobs: { invalidateKeys: [[
|
|
48
|
+
delete_job: { entityKey: 'jobs', action: 'delete', fetchPath: null },
|
|
49
|
+
update_jobs: { invalidateKeys: [['jobs'], ['infinite', 'jobs']] },
|
|
50
|
+
delete_jobs: { invalidateKeys: [['jobs'], ['infinite', 'jobs']] },
|
|
51
51
|
// ── Routes ──
|
|
52
52
|
create_route: {
|
|
53
|
-
entityKey:
|
|
54
|
-
action:
|
|
53
|
+
entityKey: 'routes',
|
|
54
|
+
action: 'create',
|
|
55
55
|
fetchPath: (id) => `/route/${id}`,
|
|
56
56
|
construct: (d) => new Route(d),
|
|
57
57
|
},
|
|
58
58
|
update_route: {
|
|
59
|
-
entityKey:
|
|
60
|
-
action:
|
|
59
|
+
entityKey: 'routes',
|
|
60
|
+
action: 'update',
|
|
61
61
|
fetchPath: (id) => `/route/${id}`,
|
|
62
62
|
construct: (d) => new Route(d),
|
|
63
63
|
},
|
|
64
|
-
delete_route: { entityKey:
|
|
64
|
+
delete_route: { entityKey: 'routes', action: 'delete', fetchPath: null },
|
|
65
65
|
// ── Events (also refetch parent job — overdueness, last_event, etc.) ──
|
|
66
66
|
create_event: {
|
|
67
|
-
entityKey:
|
|
68
|
-
action:
|
|
67
|
+
entityKey: 'events',
|
|
68
|
+
action: 'create',
|
|
69
69
|
fetchPath: (id) => `/event/${id}`,
|
|
70
70
|
construct: (d) => new _Event(d),
|
|
71
71
|
relatedRefetch: [
|
|
72
72
|
{
|
|
73
|
-
entityKey:
|
|
74
|
-
idField:
|
|
73
|
+
entityKey: 'jobs',
|
|
74
|
+
idField: 'job_id',
|
|
75
75
|
fetchPath: (id) => `/job/${id}`,
|
|
76
76
|
construct: (d) => new Job(d),
|
|
77
77
|
},
|
|
78
78
|
],
|
|
79
79
|
},
|
|
80
80
|
update_event: {
|
|
81
|
-
entityKey:
|
|
82
|
-
action:
|
|
81
|
+
entityKey: 'events',
|
|
82
|
+
action: 'update',
|
|
83
83
|
fetchPath: (id) => `/event/${id}`,
|
|
84
84
|
construct: (d) => new _Event(d),
|
|
85
85
|
relatedRefetch: [
|
|
86
86
|
{
|
|
87
|
-
entityKey:
|
|
88
|
-
idField:
|
|
87
|
+
entityKey: 'jobs',
|
|
88
|
+
idField: 'job_id',
|
|
89
89
|
fetchPath: (id) => `/job/${id}`,
|
|
90
90
|
construct: (d) => new Job(d),
|
|
91
91
|
},
|
|
92
92
|
],
|
|
93
93
|
},
|
|
94
94
|
delete_event: {
|
|
95
|
-
entityKey:
|
|
96
|
-
action:
|
|
95
|
+
entityKey: 'events',
|
|
96
|
+
action: 'delete',
|
|
97
97
|
fetchPath: null,
|
|
98
98
|
relatedRefetch: [
|
|
99
99
|
{
|
|
100
|
-
entityKey:
|
|
101
|
-
idField:
|
|
100
|
+
entityKey: 'jobs',
|
|
101
|
+
idField: 'job_id',
|
|
102
102
|
fetchPath: (id) => `/job/${id}`,
|
|
103
103
|
construct: (d) => new Job(d),
|
|
104
104
|
},
|
|
105
105
|
],
|
|
106
106
|
},
|
|
107
|
-
update_events: { invalidateKeys: [[
|
|
107
|
+
update_events: { invalidateKeys: [['events']] },
|
|
108
108
|
// ── Teams ──
|
|
109
|
-
create_team: { entityKey:
|
|
110
|
-
update_team: { entityKey:
|
|
111
|
-
delete_team: { entityKey:
|
|
112
|
-
update_teams: { invalidateKeys: [[
|
|
109
|
+
create_team: { entityKey: 'teams', action: 'create', fetchPath: null },
|
|
110
|
+
update_team: { entityKey: 'teams', action: 'update', fetchPath: null },
|
|
111
|
+
delete_team: { entityKey: 'teams', action: 'delete', fetchPath: null },
|
|
112
|
+
update_teams: { invalidateKeys: [['teams']] },
|
|
113
113
|
// ── Bills ──
|
|
114
114
|
create_bill: {
|
|
115
|
-
entityKey:
|
|
116
|
-
action:
|
|
115
|
+
entityKey: 'bills',
|
|
116
|
+
action: 'create',
|
|
117
117
|
fetchPath: (id) => `/bill/${id}`,
|
|
118
118
|
},
|
|
119
|
-
delete_bill: { entityKey:
|
|
120
|
-
update_bills: { invalidateKeys: [[
|
|
119
|
+
delete_bill: { entityKey: 'bills', action: 'delete', fetchPath: null },
|
|
120
|
+
update_bills: { invalidateKeys: [['bills']] },
|
|
121
121
|
// ── Sessions ──
|
|
122
|
-
create_session: { entityKey:
|
|
123
|
-
update_session: { entityKey:
|
|
122
|
+
create_session: { entityKey: 'sessions', action: 'create', fetchPath: null },
|
|
123
|
+
update_session: { entityKey: 'sessions', action: 'update', fetchPath: null },
|
|
124
124
|
// ── Catalog Items ──
|
|
125
125
|
create_catalog_item: {
|
|
126
|
-
entityKey:
|
|
127
|
-
action:
|
|
126
|
+
entityKey: 'catalog_items',
|
|
127
|
+
action: 'create',
|
|
128
128
|
fetchPath: (id) => `/catalog_item/${id}`,
|
|
129
129
|
},
|
|
130
130
|
update_catalog_item: {
|
|
131
|
-
entityKey:
|
|
132
|
-
action:
|
|
131
|
+
entityKey: 'catalog_items',
|
|
132
|
+
action: 'update',
|
|
133
133
|
fetchPath: (id) => `/catalog_item/${id}`,
|
|
134
134
|
},
|
|
135
135
|
delete_catalog_item: {
|
|
136
|
-
entityKey:
|
|
137
|
-
action:
|
|
136
|
+
entityKey: 'catalog_items',
|
|
137
|
+
action: 'delete',
|
|
138
138
|
fetchPath: null,
|
|
139
139
|
},
|
|
140
140
|
// ── Groups ──
|
|
141
|
-
create_group: { entityKey:
|
|
142
|
-
update_group: { entityKey:
|
|
143
|
-
delete_group: { entityKey:
|
|
141
|
+
create_group: { entityKey: 'groups', action: 'create', fetchPath: null },
|
|
142
|
+
update_group: { entityKey: 'groups', action: 'update', fetchPath: null },
|
|
143
|
+
delete_group: { entityKey: 'groups', action: 'delete', fetchPath: null },
|
|
144
144
|
// ── Labels ──
|
|
145
|
-
create_label: { entityKey:
|
|
146
|
-
update_label: { entityKey:
|
|
147
|
-
delete_label: { entityKey:
|
|
145
|
+
create_label: { entityKey: 'labels', action: 'create', fetchPath: null },
|
|
146
|
+
update_label: { entityKey: 'labels', action: 'update', fetchPath: null },
|
|
147
|
+
delete_label: { entityKey: 'labels', action: 'delete', fetchPath: null },
|
|
148
148
|
// ── Skills ──
|
|
149
|
-
create_skill: { entityKey:
|
|
150
|
-
update_skill: { entityKey:
|
|
151
|
-
delete_skill: { entityKey:
|
|
149
|
+
create_skill: { entityKey: 'skills', action: 'create', fetchPath: null },
|
|
150
|
+
update_skill: { entityKey: 'skills', action: 'update', fetchPath: null },
|
|
151
|
+
delete_skill: { entityKey: 'skills', action: 'delete', fetchPath: null },
|
|
152
152
|
// ── Proposals ──
|
|
153
153
|
create_proposal: {
|
|
154
|
-
entityKey:
|
|
155
|
-
action:
|
|
154
|
+
entityKey: 'proposals',
|
|
155
|
+
action: 'create',
|
|
156
156
|
fetchPath: (id) => `/proposal/${id}`,
|
|
157
157
|
},
|
|
158
158
|
update_proposal: {
|
|
159
|
-
entityKey:
|
|
160
|
-
action:
|
|
159
|
+
entityKey: 'proposals',
|
|
160
|
+
action: 'update',
|
|
161
161
|
fetchPath: (id) => `/proposal/${id}`,
|
|
162
162
|
},
|
|
163
163
|
delete_proposal: {
|
|
164
|
-
entityKey:
|
|
165
|
-
action:
|
|
164
|
+
entityKey: 'proposals',
|
|
165
|
+
action: 'delete',
|
|
166
166
|
fetchPath: null,
|
|
167
167
|
},
|
|
168
168
|
// ── Service Months ──
|
|
169
|
-
create_month: { entityKey:
|
|
170
|
-
update_months: { invalidateKeys: [[
|
|
171
|
-
delete_months: { invalidateKeys: [[
|
|
169
|
+
create_month: { entityKey: 'months', action: 'create', fetchPath: null },
|
|
170
|
+
update_months: { invalidateKeys: [['months']] },
|
|
171
|
+
delete_months: { invalidateKeys: [['months']] },
|
|
172
172
|
// ── Tasks (nested under jobs — target the parent job) ──
|
|
173
173
|
create_task: {
|
|
174
|
-
entityKey:
|
|
175
|
-
action:
|
|
174
|
+
entityKey: 'jobs',
|
|
175
|
+
action: 'update',
|
|
176
176
|
fetchPath: (id) => `/job/${id}`,
|
|
177
|
-
idField:
|
|
177
|
+
idField: 'job_id',
|
|
178
178
|
construct: (d) => new Job(d),
|
|
179
179
|
},
|
|
180
180
|
update_task: {
|
|
181
|
-
entityKey:
|
|
182
|
-
action:
|
|
181
|
+
entityKey: 'jobs',
|
|
182
|
+
action: 'update',
|
|
183
183
|
fetchPath: (id) => `/job/${id}`,
|
|
184
|
-
idField:
|
|
184
|
+
idField: 'job_id',
|
|
185
185
|
construct: (d) => new Job(d),
|
|
186
186
|
},
|
|
187
187
|
delete_task: {
|
|
188
|
-
entityKey:
|
|
189
|
-
action:
|
|
188
|
+
entityKey: 'jobs',
|
|
189
|
+
action: 'update',
|
|
190
190
|
fetchPath: (id) => `/job/${id}`,
|
|
191
|
-
idField:
|
|
191
|
+
idField: 'job_id',
|
|
192
192
|
construct: (d) => new Job(d),
|
|
193
193
|
},
|
|
194
194
|
// ── Scheduling ──
|
|
195
195
|
schedule_complete: {
|
|
196
|
-
invalidateKeys: [[
|
|
196
|
+
invalidateKeys: [['routes'], ['jobs'], ['infinite', 'jobs']],
|
|
197
197
|
},
|
|
198
198
|
// ── Location ──
|
|
199
|
-
location_update: { invalidateKeys: [[
|
|
199
|
+
location_update: { invalidateKeys: [['teams']] },
|
|
200
200
|
// ── Prepayments ──
|
|
201
|
-
update_prepayments: { invalidateKeys: [[
|
|
201
|
+
update_prepayments: { invalidateKeys: [['prepayments']] },
|
|
202
202
|
// ── Chats ──
|
|
203
|
-
new_message: { invalidateKeys: [[
|
|
203
|
+
new_message: { invalidateKeys: [['chats'], ['messages']] },
|
|
204
204
|
};
|
|
205
205
|
/**
|
|
206
206
|
* Returns true when `query.queryKey` belongs to the given entity,
|
|
@@ -208,7 +208,7 @@ const SOCKET_EVENT_CONFIG = {
|
|
|
208
208
|
*/
|
|
209
209
|
function matchesEntityKey(query, entityKey) {
|
|
210
210
|
const k = query.queryKey;
|
|
211
|
-
return k[0] === entityKey || (k[0] ===
|
|
211
|
+
return k[0] === entityKey || (k[0] === 'infinite' && k[1] === entityKey);
|
|
212
212
|
}
|
|
213
213
|
export class AvroQueryClient {
|
|
214
214
|
constructor(config) {
|
|
@@ -224,12 +224,12 @@ export class AvroQueryClient {
|
|
|
224
224
|
baseUrl: config.baseUrl,
|
|
225
225
|
authManager: config.authManager,
|
|
226
226
|
maxRetries: config.maxRetries ?? 3,
|
|
227
|
-
retryStrategy: config.retryStrategy ??
|
|
227
|
+
retryStrategy: config.retryStrategy ?? 'fixed',
|
|
228
228
|
timeout: config.timeout ?? 0,
|
|
229
229
|
};
|
|
230
230
|
this.socket = io(config.baseUrl, {
|
|
231
231
|
autoConnect: false,
|
|
232
|
-
transports: [
|
|
232
|
+
transports: ['websocket'],
|
|
233
233
|
});
|
|
234
234
|
config.authManager.isAuthenticated().then((isAuth) => {
|
|
235
235
|
this.setAuthState(isAuth);
|
|
@@ -237,18 +237,14 @@ export class AvroQueryClient {
|
|
|
237
237
|
// Resolve both companyId and access token before connecting so
|
|
238
238
|
// the 'connect' handler in setupSocketInvalidation can immediately
|
|
239
239
|
// join the company room.
|
|
240
|
-
Promise.all([
|
|
241
|
-
this.getCompanyId(),
|
|
242
|
-
this.config.authManager.accessToken(),
|
|
243
|
-
])
|
|
240
|
+
Promise.all([this.getCompanyId(), this.config.authManager.accessToken()])
|
|
244
241
|
.then(([id, token]) => {
|
|
245
242
|
this.companyId = id;
|
|
246
|
-
console.log("Initializing socket connection with token:", token);
|
|
247
243
|
this.socket.auth = { token: token };
|
|
248
244
|
this.socket.connect();
|
|
249
245
|
})
|
|
250
246
|
.catch((err) => {
|
|
251
|
-
console.error(
|
|
247
|
+
console.error('Not logged in:', err);
|
|
252
248
|
});
|
|
253
249
|
}
|
|
254
250
|
else {
|
|
@@ -258,20 +254,19 @@ export class AvroQueryClient {
|
|
|
258
254
|
});
|
|
259
255
|
}
|
|
260
256
|
});
|
|
261
|
-
this.socket.on(
|
|
257
|
+
this.socket.on('connect', () => {
|
|
262
258
|
this.setAuthState(AuthState.AUTHENTICATED);
|
|
263
259
|
console.log(`Socket connected with ID: ${this.socket?.id}`);
|
|
264
260
|
});
|
|
265
|
-
this.socket.on(
|
|
261
|
+
this.socket.on('disconnect', (reason) => {
|
|
266
262
|
console.log(`Socket disconnected: ${reason}`);
|
|
267
263
|
});
|
|
268
|
-
this.socket.on(
|
|
264
|
+
this.socket.on('connect_error', (err) => {
|
|
269
265
|
console.error(`Socket connection error: ${err.message}`);
|
|
270
266
|
});
|
|
271
267
|
this.config.authManager.onTokenRefreshed((newAccessToken) => {
|
|
272
268
|
if (this.socket && newAccessToken) {
|
|
273
269
|
this.setAuthState(AuthState.AUTHENTICATED);
|
|
274
|
-
console.log("Access token refreshed, updating socket auth...");
|
|
275
270
|
this.socket.auth = { token: newAccessToken };
|
|
276
271
|
this.socket.disconnect().connect();
|
|
277
272
|
}
|
|
@@ -286,7 +281,7 @@ export class AvroQueryClient {
|
|
|
286
281
|
}
|
|
287
282
|
emit(eventName, data) {
|
|
288
283
|
if (!this.socket?.connected) {
|
|
289
|
-
console.error(
|
|
284
|
+
console.error('Socket is not connected. Cannot emit event.');
|
|
290
285
|
return;
|
|
291
286
|
}
|
|
292
287
|
this.socket.emit(eventName, data);
|
|
@@ -328,7 +323,6 @@ export class AvroQueryClient {
|
|
|
328
323
|
if (isBulkEvent(config)) {
|
|
329
324
|
// ── Bulk: invalidate all specified keys ──────────────
|
|
330
325
|
const handler = () => {
|
|
331
|
-
console.log(`[socket-debug] bulk event: ${event}`, config.invalidateKeys);
|
|
332
326
|
for (const key of config.invalidateKeys) {
|
|
333
327
|
queryClient.invalidateQueries({ queryKey: key });
|
|
334
328
|
}
|
|
@@ -338,13 +332,10 @@ export class AvroQueryClient {
|
|
|
338
332
|
}
|
|
339
333
|
else {
|
|
340
334
|
// ── Targeted: surgical cache update ──────────────────
|
|
341
|
-
const { entityKey, action, fetchPath, idField, alsoInvalidate, relatedRefetch
|
|
335
|
+
const { entityKey, action, fetchPath, idField, alsoInvalidate, relatedRefetch } = config;
|
|
342
336
|
const handler = async (data) => {
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
// No id → old backend or malformed payload → full invalidation
|
|
346
|
-
if (!id || typeof id !== "string") {
|
|
347
|
-
console.log(`[socket-debug] no id found, falling back to full invalidation for ${entityKey}`);
|
|
337
|
+
const id = data?.[idField ?? 'id'];
|
|
338
|
+
if (!id || typeof id !== 'string') {
|
|
348
339
|
invalidateEntity(entityKey);
|
|
349
340
|
alsoInvalidate?.forEach((k) => queryClient.invalidateQueries({ queryKey: k }));
|
|
350
341
|
return;
|
|
@@ -364,10 +355,10 @@ export class AvroQueryClient {
|
|
|
364
355
|
if (relatedRefetch) {
|
|
365
356
|
for (const related of relatedRefetch) {
|
|
366
357
|
const relatedId = data?.[related.idField] ?? fetchedItem?.[related.idField];
|
|
367
|
-
if (!relatedId || typeof relatedId !==
|
|
358
|
+
if (!relatedId || typeof relatedId !== 'string')
|
|
368
359
|
continue;
|
|
369
360
|
await client._syncEntity(queryClient, {
|
|
370
|
-
action:
|
|
361
|
+
action: 'update',
|
|
371
362
|
entityKey: related.entityKey,
|
|
372
363
|
id: relatedId,
|
|
373
364
|
fetchPath: related.fetchPath(relatedId),
|
|
@@ -382,29 +373,26 @@ export class AvroQueryClient {
|
|
|
382
373
|
}
|
|
383
374
|
// Auto join/leave company room
|
|
384
375
|
const joinCompanyRoom = () => {
|
|
385
|
-
console.log(`[socket-debug] joinCompanyRoom called, companyId=${this.companyId}, connected=${this.socket.connected}`);
|
|
386
376
|
if (this.companyId) {
|
|
387
|
-
this.socket.emit(
|
|
388
|
-
console.log(`[socket-debug] emitted join_company for ${this.companyId}`);
|
|
377
|
+
this.socket.emit('join_company', { company_id: this.companyId });
|
|
389
378
|
}
|
|
390
379
|
else {
|
|
391
380
|
console.warn(`[socket-debug] joinCompanyRoom skipped — companyId is undefined`);
|
|
392
381
|
}
|
|
393
382
|
};
|
|
394
|
-
this.socket.on(
|
|
395
|
-
handlers.push({ event:
|
|
383
|
+
this.socket.on('connect', joinCompanyRoom);
|
|
384
|
+
handlers.push({ event: 'connect', handler: joinCompanyRoom });
|
|
396
385
|
// If already connected, join immediately
|
|
397
386
|
if (this.socket.connected && this.companyId) {
|
|
398
387
|
joinCompanyRoom();
|
|
399
388
|
}
|
|
400
|
-
console.log(`[socket-debug] setupSocketInvalidation complete, socket.connected=${this.socket.connected}, companyId=${this.companyId}`);
|
|
401
389
|
this._socketInvalidationCleanup = () => {
|
|
402
390
|
for (const { event, handler } of handlers) {
|
|
403
391
|
this.socket.off(event, handler);
|
|
404
392
|
}
|
|
405
393
|
// Leave company room on teardown
|
|
406
394
|
if (this.socket.connected && this.companyId) {
|
|
407
|
-
this.socket.emit(
|
|
395
|
+
this.socket.emit('leave_company', { company_id: this.companyId });
|
|
408
396
|
}
|
|
409
397
|
this._queryClient = null;
|
|
410
398
|
};
|
|
@@ -417,16 +405,16 @@ export class AvroQueryClient {
|
|
|
417
405
|
this._socketInvalidationCleanup = null;
|
|
418
406
|
}
|
|
419
407
|
get({ path, cancelToken, headers, progressUpdateCallback, }) {
|
|
420
|
-
return this._xhr(
|
|
408
|
+
return this._xhr('GET', path, null, cancelToken, headers, true, this.config.maxRetries, progressUpdateCallback);
|
|
421
409
|
}
|
|
422
410
|
post({ path, data, cancelToken, headers, progressUpdateCallback, }) {
|
|
423
|
-
return this._xhr(
|
|
411
|
+
return this._xhr('POST', path, data, cancelToken, headers, false, this.config.maxRetries, progressUpdateCallback);
|
|
424
412
|
}
|
|
425
413
|
put({ path, data, cancelToken, headers, progressUpdateCallback, }) {
|
|
426
|
-
return this._xhr(
|
|
414
|
+
return this._xhr('PUT', path, data, cancelToken, headers, true, this.config.maxRetries, progressUpdateCallback);
|
|
427
415
|
}
|
|
428
416
|
delete({ path, cancelToken, headers, progressUpdateCallback, }) {
|
|
429
|
-
return this._xhr(
|
|
417
|
+
return this._xhr('DELETE', path, null, cancelToken, headers, false, this.config.maxRetries, progressUpdateCallback);
|
|
430
418
|
}
|
|
431
419
|
loginSuccess(tokens) {
|
|
432
420
|
this.setAuthState(AuthState.AUTHENTICATED);
|
|
@@ -441,16 +429,16 @@ export class AvroQueryClient {
|
|
|
441
429
|
return useMutation({
|
|
442
430
|
mutationFn: async ({ username, password, code, cancelToken, }) => {
|
|
443
431
|
const resp = await this.post({
|
|
444
|
-
path:
|
|
432
|
+
path: '/login',
|
|
445
433
|
data: JSON.stringify({ username, password, code }),
|
|
446
434
|
cancelToken,
|
|
447
|
-
headers: {
|
|
435
|
+
headers: { 'Content-Type': 'application/json' },
|
|
448
436
|
});
|
|
449
|
-
if (!resp || !(
|
|
450
|
-
if (resp.msg ===
|
|
437
|
+
if (!resp || !('access_token' in resp)) {
|
|
438
|
+
if (resp.msg === 'TOTP required') {
|
|
451
439
|
return LoginResponse.NEEDS_TOTP;
|
|
452
440
|
}
|
|
453
|
-
throw new StandardError(401,
|
|
441
|
+
throw new StandardError(401, 'Invalid login response');
|
|
454
442
|
}
|
|
455
443
|
await this.loginSuccess({
|
|
456
444
|
access_token: resp.access_token,
|
|
@@ -463,7 +451,7 @@ export class AvroQueryClient {
|
|
|
463
451
|
},
|
|
464
452
|
onError: (err) => {
|
|
465
453
|
this.config.authManager.clearCache();
|
|
466
|
-
throw new StandardError(401, err.message ||
|
|
454
|
+
throw new StandardError(401, err.message || 'Login failed');
|
|
467
455
|
},
|
|
468
456
|
});
|
|
469
457
|
}
|
|
@@ -472,10 +460,10 @@ export class AvroQueryClient {
|
|
|
472
460
|
return useMutation({
|
|
473
461
|
mutationFn: async ({ username, email, cancelToken, }) => {
|
|
474
462
|
const resp = await this.post({
|
|
475
|
-
path:
|
|
463
|
+
path: '/code',
|
|
476
464
|
data: JSON.stringify({ username, email }),
|
|
477
465
|
cancelToken,
|
|
478
|
-
headers: {
|
|
466
|
+
headers: { 'Content-Type': 'application/json' },
|
|
479
467
|
});
|
|
480
468
|
return resp;
|
|
481
469
|
},
|
|
@@ -483,7 +471,7 @@ export class AvroQueryClient {
|
|
|
483
471
|
queryClient.invalidateQueries();
|
|
484
472
|
},
|
|
485
473
|
onError: (err) => {
|
|
486
|
-
throw new StandardError(err.status, err.message ||
|
|
474
|
+
throw new StandardError(err.status, err.message || 'Request code failed');
|
|
487
475
|
},
|
|
488
476
|
});
|
|
489
477
|
}
|
|
@@ -495,14 +483,14 @@ export class AvroQueryClient {
|
|
|
495
483
|
path: `/user/${username ?? email}/password`,
|
|
496
484
|
data: JSON.stringify({ code, password: newPassword }),
|
|
497
485
|
cancelToken,
|
|
498
|
-
headers: {
|
|
486
|
+
headers: { 'Content-Type': 'application/json' },
|
|
499
487
|
});
|
|
500
488
|
},
|
|
501
489
|
onSettled: () => {
|
|
502
490
|
queryClient.invalidateQueries();
|
|
503
491
|
},
|
|
504
492
|
onError: (err) => {
|
|
505
|
-
throw new StandardError(err.status, err.message ||
|
|
493
|
+
throw new StandardError(err.status, err.message || 'Update password failed');
|
|
506
494
|
},
|
|
507
495
|
});
|
|
508
496
|
}
|
|
@@ -510,12 +498,12 @@ export class AvroQueryClient {
|
|
|
510
498
|
const queryClient = this.getQueryClient();
|
|
511
499
|
return useMutation({
|
|
512
500
|
mutationFn: async ({ token, cancelToken, }) => {
|
|
513
|
-
const resp = await this._xhr(
|
|
514
|
-
if (!resp || !(
|
|
515
|
-
if (resp.msg ===
|
|
501
|
+
const resp = await this._xhr('POST', `/google/authorize?token=${token}`, {}, cancelToken, { 'Content-Type': 'application/json' });
|
|
502
|
+
if (!resp || !('access_token' in resp)) {
|
|
503
|
+
if (resp.msg === 'TOTP required') {
|
|
516
504
|
return LoginResponse.NEEDS_TOTP;
|
|
517
505
|
}
|
|
518
|
-
throw new StandardError(401,
|
|
506
|
+
throw new StandardError(401, 'Invalid Google login response');
|
|
519
507
|
}
|
|
520
508
|
this.setAuthState(AuthState.AUTHENTICATED);
|
|
521
509
|
this.socket.auth = { token: resp.access_token };
|
|
@@ -533,7 +521,7 @@ export class AvroQueryClient {
|
|
|
533
521
|
},
|
|
534
522
|
onError: (err) => {
|
|
535
523
|
this.config.authManager.clearCache();
|
|
536
|
-
throw new StandardError(err.status, err.message ||
|
|
524
|
+
throw new StandardError(err.status, err.message || 'Google Login failed');
|
|
537
525
|
},
|
|
538
526
|
});
|
|
539
527
|
}
|
|
@@ -541,12 +529,12 @@ export class AvroQueryClient {
|
|
|
541
529
|
const queryClient = this.getQueryClient();
|
|
542
530
|
return useMutation({
|
|
543
531
|
mutationFn: async ({ token, cancelToken, }) => {
|
|
544
|
-
const resp = await this._xhr(
|
|
545
|
-
if (!resp || !(
|
|
546
|
-
if (resp.msg ===
|
|
532
|
+
const resp = await this._xhr('POST', `/apple/authorize?token=${encodeURIComponent(token)}`, {}, cancelToken, { 'Content-Type': 'application/json' });
|
|
533
|
+
if (!resp || !('access_token' in resp)) {
|
|
534
|
+
if (resp.msg === 'TOTP required') {
|
|
547
535
|
return LoginResponse.NEEDS_TOTP;
|
|
548
536
|
}
|
|
549
|
-
throw new StandardError(401,
|
|
537
|
+
throw new StandardError(401, 'Invalid Apple login response');
|
|
550
538
|
}
|
|
551
539
|
this.setAuthState(AuthState.AUTHENTICATED);
|
|
552
540
|
this.socket.auth = { token: resp.access_token };
|
|
@@ -564,7 +552,7 @@ export class AvroQueryClient {
|
|
|
564
552
|
},
|
|
565
553
|
onError: (err) => {
|
|
566
554
|
this.config.authManager.clearCache();
|
|
567
|
-
throw new StandardError(err.status, err.message ||
|
|
555
|
+
throw new StandardError(err.status, err.message || 'Apple Login failed');
|
|
568
556
|
},
|
|
569
557
|
});
|
|
570
558
|
}
|
|
@@ -580,17 +568,12 @@ export class AvroQueryClient {
|
|
|
580
568
|
setCompanyId(companyId) {
|
|
581
569
|
const previousId = this.companyId;
|
|
582
570
|
this.companyId = companyId;
|
|
583
|
-
console.log(`[socket-debug] setCompanyId called: ${companyId}, socket.connected=${this.socket.connected}, prev=${previousId}`);
|
|
584
571
|
// If the socket is already connected, leave the old room and join the new one.
|
|
585
572
|
if (this.socket.connected) {
|
|
586
573
|
if (previousId && previousId !== companyId) {
|
|
587
|
-
this.socket.emit(
|
|
574
|
+
this.socket.emit('leave_company', { company_id: previousId });
|
|
588
575
|
}
|
|
589
|
-
this.socket.emit(
|
|
590
|
-
console.log(`[socket-debug] setCompanyId emitted join_company for ${companyId}`);
|
|
591
|
-
}
|
|
592
|
-
else {
|
|
593
|
-
console.warn(`[socket-debug] setCompanyId: socket not connected, will join on next connect`);
|
|
576
|
+
this.socket.emit('join_company', { company_id: companyId });
|
|
594
577
|
}
|
|
595
578
|
return this.config.authManager.setCompanyId(companyId);
|
|
596
579
|
}
|
|
@@ -645,13 +628,12 @@ export class AvroQueryClient {
|
|
|
645
628
|
*/
|
|
646
629
|
async _syncEntity(queryClient, params) {
|
|
647
630
|
const { action, entityKey, id, fetchPath, construct } = params;
|
|
648
|
-
console.log(`[socket-debug] _syncEntity: action=${action}, entity=${entityKey}, id=${id}, fetchPath=${fetchPath}`);
|
|
649
631
|
const predicate = (q) => matchesEntityKey(q, entityKey);
|
|
650
632
|
const invalidate = () => queryClient.invalidateQueries({ predicate });
|
|
651
633
|
// ─── DELETE ─────────────────────────────────────────
|
|
652
|
-
if (action ===
|
|
634
|
+
if (action === 'delete') {
|
|
653
635
|
queryClient.removeQueries({ queryKey: [entityKey, id], exact: true });
|
|
654
|
-
queryClient.setQueriesData({ predicate
|
|
636
|
+
queryClient.setQueriesData({ predicate }, (old) => {
|
|
655
637
|
if (!old)
|
|
656
638
|
return old;
|
|
657
639
|
if (old.pages && Array.isArray(old.pages)) {
|
|
@@ -679,10 +661,9 @@ export class AvroQueryClient {
|
|
|
679
661
|
staleTime: 0,
|
|
680
662
|
});
|
|
681
663
|
const item = construct ? construct(raw) : raw;
|
|
682
|
-
console.log(`[socket-debug] _syncEntity fetched ${entityKey}/${id}:`, item);
|
|
683
664
|
queryClient.setQueryData([entityKey, id], item);
|
|
684
|
-
if (action ===
|
|
685
|
-
queryClient.setQueriesData({ predicate
|
|
665
|
+
if (action === 'create') {
|
|
666
|
+
queryClient.setQueriesData({ predicate }, (old) => {
|
|
686
667
|
if (!old)
|
|
687
668
|
return old;
|
|
688
669
|
if (old.pages && Array.isArray(old.pages)) {
|
|
@@ -703,7 +684,7 @@ export class AvroQueryClient {
|
|
|
703
684
|
}
|
|
704
685
|
else {
|
|
705
686
|
// UPDATE — replace in every active list / infinite-query cache
|
|
706
|
-
queryClient.setQueriesData({ predicate
|
|
687
|
+
queryClient.setQueriesData({ predicate }, (old) => {
|
|
707
688
|
if (!old)
|
|
708
689
|
return old;
|
|
709
690
|
if (old.pages && Array.isArray(old.pages)) {
|
|
@@ -718,7 +699,6 @@ export class AvroQueryClient {
|
|
|
718
699
|
return old;
|
|
719
700
|
});
|
|
720
701
|
}
|
|
721
|
-
console.log(`[socket-debug] _syncEntity completed ${action} for ${entityKey}/${id}`);
|
|
722
702
|
return item;
|
|
723
703
|
}
|
|
724
704
|
catch (err) {
|
|
@@ -732,7 +712,7 @@ export class AvroQueryClient {
|
|
|
732
712
|
return useMutation({
|
|
733
713
|
mutationFn: async (cancelToken) => {
|
|
734
714
|
await this.post({
|
|
735
|
-
path:
|
|
715
|
+
path: '/logout',
|
|
736
716
|
cancelToken,
|
|
737
717
|
});
|
|
738
718
|
await this.config.authManager.clearCache();
|
|
@@ -747,276 +727,276 @@ export class AvroQueryClient {
|
|
|
747
727
|
},
|
|
748
728
|
onError: (err) => {
|
|
749
729
|
this.clearCache();
|
|
750
|
-
console.error(
|
|
751
|
-
throw new StandardError(500,
|
|
730
|
+
console.error('Logout failed:', err);
|
|
731
|
+
throw new StandardError(500, 'Logout failed');
|
|
752
732
|
},
|
|
753
733
|
});
|
|
754
734
|
}
|
|
755
735
|
fetchJobs(body = {}, companyId, cancelToken, headers = {}) {
|
|
756
736
|
const companyIdToUse = companyId ?? this.companyId;
|
|
757
|
-
if (!companyIdToUse || companyIdToUse.trim() ===
|
|
758
|
-
throw new StandardError(400,
|
|
737
|
+
if (!companyIdToUse || companyIdToUse.trim() === '') {
|
|
738
|
+
throw new StandardError(400, 'Company ID is required');
|
|
759
739
|
}
|
|
760
|
-
return this._fetch(
|
|
740
|
+
return this._fetch('POST', `/company/${companyIdToUse}/jobs`, JSON.stringify(body), cancelToken, {
|
|
761
741
|
...headers,
|
|
762
|
-
|
|
742
|
+
'Content-Type': 'application/json',
|
|
763
743
|
})
|
|
764
744
|
.then((response) => {
|
|
765
745
|
if (!response || !Array.isArray(response)) {
|
|
766
|
-
throw new StandardError(400,
|
|
746
|
+
throw new StandardError(400, 'Invalid jobs response');
|
|
767
747
|
}
|
|
768
748
|
return response;
|
|
769
749
|
})
|
|
770
750
|
.catch((err) => {
|
|
771
|
-
console.error(
|
|
751
|
+
console.error('Failed to fetch jobs:', err);
|
|
772
752
|
throw new StandardError(500, `Failed to fetch jobs: ${err.message ?? err}`);
|
|
773
753
|
});
|
|
774
754
|
}
|
|
775
755
|
fetchChats(body = {}, cancelToken, headers = {}) {
|
|
776
|
-
if (!this.companyId || this.companyId.trim() ===
|
|
777
|
-
throw new StandardError(400,
|
|
756
|
+
if (!this.companyId || this.companyId.trim() === '') {
|
|
757
|
+
throw new StandardError(400, 'Company ID is required');
|
|
778
758
|
}
|
|
779
|
-
return this._fetch(
|
|
759
|
+
return this._fetch('POST', `/company/${this.companyId}/chats`, JSON.stringify(body), cancelToken, {
|
|
780
760
|
...headers,
|
|
781
|
-
|
|
761
|
+
'Content-Type': 'application/json',
|
|
782
762
|
})
|
|
783
763
|
.then((response) => {
|
|
784
764
|
if (!response || !Array.isArray(response)) {
|
|
785
|
-
throw new StandardError(400,
|
|
765
|
+
throw new StandardError(400, 'Invalid chats response');
|
|
786
766
|
}
|
|
787
767
|
return response;
|
|
788
768
|
})
|
|
789
769
|
.catch((err) => {
|
|
790
|
-
console.error(
|
|
791
|
-
throw new StandardError(500,
|
|
770
|
+
console.error('Failed to fetch chats:', err);
|
|
771
|
+
throw new StandardError(500, 'Failed to fetch chats');
|
|
792
772
|
});
|
|
793
773
|
}
|
|
794
774
|
fetchMessages(chatId, body = {}, cancelToken, headers = {}) {
|
|
795
|
-
if (!chatId || chatId.trim() ===
|
|
796
|
-
throw new StandardError(400,
|
|
775
|
+
if (!chatId || chatId.trim() === '') {
|
|
776
|
+
throw new StandardError(400, 'Chat ID is required');
|
|
797
777
|
}
|
|
798
|
-
return this._fetch(
|
|
778
|
+
return this._fetch('POST', `/chat/${chatId}/messages`, JSON.stringify(body), cancelToken, {
|
|
799
779
|
...headers,
|
|
800
|
-
|
|
780
|
+
'Content-Type': 'application/json',
|
|
801
781
|
})
|
|
802
782
|
.then((response) => {
|
|
803
783
|
if (!response || !Array.isArray(response)) {
|
|
804
|
-
throw new StandardError(400,
|
|
784
|
+
throw new StandardError(400, 'Invalid messages response');
|
|
805
785
|
}
|
|
806
786
|
return response;
|
|
807
787
|
})
|
|
808
788
|
.catch((err) => {
|
|
809
|
-
console.error(
|
|
810
|
-
throw new StandardError(500,
|
|
789
|
+
console.error('Failed to fetch messages:', err);
|
|
790
|
+
throw new StandardError(500, 'Failed to fetch messages');
|
|
811
791
|
});
|
|
812
792
|
}
|
|
813
793
|
async fetchPrepayments(body = {}, cancelToken, headers = {}) {
|
|
814
|
-
if (!this.companyId || this.companyId.trim() ===
|
|
815
|
-
throw new StandardError(400,
|
|
794
|
+
if (!this.companyId || this.companyId.trim() === '') {
|
|
795
|
+
throw new StandardError(400, 'Company ID is required');
|
|
816
796
|
}
|
|
817
|
-
return this._fetch(
|
|
797
|
+
return this._fetch('POST', `/company/${this.companyId}/prepayments`, JSON.stringify(body), cancelToken, {
|
|
818
798
|
...headers,
|
|
819
|
-
|
|
799
|
+
'Content-Type': 'application/json',
|
|
820
800
|
})
|
|
821
801
|
.then((response) => {
|
|
822
802
|
if (!response || !Array.isArray(response)) {
|
|
823
|
-
throw new StandardError(400,
|
|
803
|
+
throw new StandardError(400, 'Invalid prepayments response');
|
|
824
804
|
}
|
|
825
805
|
return response;
|
|
826
806
|
})
|
|
827
807
|
.catch((err) => {
|
|
828
|
-
console.error(
|
|
829
|
-
throw new StandardError(500,
|
|
808
|
+
console.error('Failed to fetch prepayments:', err);
|
|
809
|
+
throw new StandardError(500, 'Failed to fetch prepayments');
|
|
830
810
|
});
|
|
831
811
|
}
|
|
832
812
|
async fetchWaivers(body = {}, cancelToken, headers = {}) {
|
|
833
|
-
if (!this.companyId || this.companyId.trim() ===
|
|
834
|
-
throw new StandardError(400,
|
|
813
|
+
if (!this.companyId || this.companyId.trim() === '') {
|
|
814
|
+
throw new StandardError(400, 'Company ID is required');
|
|
835
815
|
}
|
|
836
|
-
return this._fetch(
|
|
816
|
+
return this._fetch('POST', `/company/${this.companyId}/waivers`, JSON.stringify(body), cancelToken, {
|
|
837
817
|
...headers,
|
|
838
|
-
|
|
818
|
+
'Content-Type': 'application/json',
|
|
839
819
|
})
|
|
840
820
|
.then((response) => {
|
|
841
821
|
if (!response || !Array.isArray(response)) {
|
|
842
|
-
throw new StandardError(400,
|
|
822
|
+
throw new StandardError(400, 'Invalid waivers response');
|
|
843
823
|
}
|
|
844
824
|
return response;
|
|
845
825
|
})
|
|
846
826
|
.catch((err) => {
|
|
847
|
-
console.error(
|
|
848
|
-
throw new StandardError(500,
|
|
827
|
+
console.error('Failed to fetch waivers:', err);
|
|
828
|
+
throw new StandardError(500, 'Failed to fetch waivers');
|
|
849
829
|
});
|
|
850
830
|
}
|
|
851
831
|
async fetchEvents(body = {}, cancelToken, headers = {}) {
|
|
852
|
-
if (!this.companyId || this.companyId.trim() ===
|
|
853
|
-
throw new StandardError(400,
|
|
832
|
+
if (!this.companyId || this.companyId.trim() === '') {
|
|
833
|
+
throw new StandardError(400, 'Company ID is required');
|
|
854
834
|
}
|
|
855
|
-
return this._fetch(
|
|
835
|
+
return this._fetch('POST', `/company/${this.companyId}/events`, JSON.stringify(body), cancelToken, {
|
|
856
836
|
...headers,
|
|
857
|
-
|
|
837
|
+
'Content-Type': 'application/json',
|
|
858
838
|
})
|
|
859
839
|
.then((response) => {
|
|
860
840
|
if (!response || !Array.isArray(response)) {
|
|
861
|
-
throw new StandardError(400,
|
|
841
|
+
throw new StandardError(400, 'Invalid events response');
|
|
862
842
|
}
|
|
863
843
|
return response;
|
|
864
844
|
})
|
|
865
845
|
.catch((err) => {
|
|
866
|
-
console.error(
|
|
867
|
-
throw new StandardError(500,
|
|
846
|
+
console.error('Failed to fetch events:', err);
|
|
847
|
+
throw new StandardError(500, 'Failed to fetch events');
|
|
868
848
|
});
|
|
869
849
|
}
|
|
870
850
|
fetchMonths(body = {}, cancelToken, headers = {}) {
|
|
871
|
-
if (!this.companyId || this.companyId.trim() ===
|
|
872
|
-
throw new StandardError(400,
|
|
851
|
+
if (!this.companyId || this.companyId.trim() === '') {
|
|
852
|
+
throw new StandardError(400, 'Company ID is required');
|
|
873
853
|
}
|
|
874
|
-
return this._fetch(
|
|
854
|
+
return this._fetch('POST', `/company/${this.companyId}/months`, JSON.stringify(body), cancelToken, {
|
|
875
855
|
...headers,
|
|
876
|
-
|
|
856
|
+
'Content-Type': 'application/json',
|
|
877
857
|
})
|
|
878
858
|
.then((response) => {
|
|
879
859
|
if (!response || !Array.isArray(response)) {
|
|
880
|
-
throw new StandardError(400,
|
|
860
|
+
throw new StandardError(400, 'Invalid months response');
|
|
881
861
|
}
|
|
882
862
|
return response;
|
|
883
863
|
})
|
|
884
864
|
.catch((err) => {
|
|
885
|
-
console.error(
|
|
886
|
-
throw new StandardError(500,
|
|
865
|
+
console.error('Failed to fetch months:', err);
|
|
866
|
+
throw new StandardError(500, 'Failed to fetch months');
|
|
887
867
|
});
|
|
888
868
|
}
|
|
889
869
|
fetchBills(body = {}, cancelToken, headers = {}) {
|
|
890
|
-
if (!this.companyId || this.companyId.trim() ===
|
|
891
|
-
throw new StandardError(400,
|
|
870
|
+
if (!this.companyId || this.companyId.trim() === '') {
|
|
871
|
+
throw new StandardError(400, 'Company ID is required');
|
|
892
872
|
}
|
|
893
|
-
return this._fetch(
|
|
873
|
+
return this._fetch('POST', `/company/${this.companyId}/bills`, JSON.stringify(body), cancelToken, {
|
|
894
874
|
...headers,
|
|
895
|
-
|
|
875
|
+
'Content-Type': 'application/json',
|
|
896
876
|
})
|
|
897
877
|
.then((response) => {
|
|
898
878
|
if (!response || !Array.isArray(response)) {
|
|
899
|
-
throw new StandardError(400,
|
|
879
|
+
throw new StandardError(400, 'Invalid bills response');
|
|
900
880
|
}
|
|
901
881
|
return response;
|
|
902
882
|
})
|
|
903
883
|
.catch((err) => {
|
|
904
|
-
console.error(
|
|
905
|
-
throw new StandardError(500,
|
|
884
|
+
console.error('Failed to fetch bills:', err);
|
|
885
|
+
throw new StandardError(500, 'Failed to fetch bills');
|
|
906
886
|
});
|
|
907
887
|
}
|
|
908
888
|
fetchRoutes(body = {}, cancelToken, headers = {}) {
|
|
909
|
-
if (!this.companyId || this.companyId.trim() ===
|
|
910
|
-
throw new StandardError(400,
|
|
889
|
+
if (!this.companyId || this.companyId.trim() === '') {
|
|
890
|
+
throw new StandardError(400, 'Company ID is required');
|
|
911
891
|
}
|
|
912
|
-
return this._fetch(
|
|
892
|
+
return this._fetch('POST', `/company/${this.companyId}/routes`, JSON.stringify(body), cancelToken, {
|
|
913
893
|
...headers,
|
|
914
|
-
|
|
894
|
+
'Content-Type': 'application/json',
|
|
915
895
|
})
|
|
916
896
|
.then((response) => {
|
|
917
897
|
if (!response || !Array.isArray(response)) {
|
|
918
|
-
throw new StandardError(400,
|
|
898
|
+
throw new StandardError(400, 'Invalid routes response');
|
|
919
899
|
}
|
|
920
900
|
return response;
|
|
921
901
|
})
|
|
922
902
|
.catch((err) => {
|
|
923
|
-
console.error(
|
|
924
|
-
throw new StandardError(500,
|
|
903
|
+
console.error('Failed to fetch routes:', err);
|
|
904
|
+
throw new StandardError(500, 'Failed to fetch routes');
|
|
925
905
|
});
|
|
926
906
|
}
|
|
927
907
|
fetchTeams(body = {}, cancelToken, headers = {}) {
|
|
928
|
-
if (!this.companyId || this.companyId.trim() ===
|
|
929
|
-
throw new StandardError(400,
|
|
908
|
+
if (!this.companyId || this.companyId.trim() === '') {
|
|
909
|
+
throw new StandardError(400, 'Company ID is required');
|
|
930
910
|
}
|
|
931
|
-
return this._fetch(
|
|
911
|
+
return this._fetch('POST', `/company/${this.companyId}/teams`, JSON.stringify(body), cancelToken, {
|
|
932
912
|
...headers,
|
|
933
|
-
|
|
913
|
+
'Content-Type': 'application/json',
|
|
934
914
|
})
|
|
935
915
|
.then((response) => {
|
|
936
916
|
if (!response || !Array.isArray(response)) {
|
|
937
|
-
throw new StandardError(400,
|
|
917
|
+
throw new StandardError(400, 'Invalid teams response');
|
|
938
918
|
}
|
|
939
919
|
return response;
|
|
940
920
|
})
|
|
941
921
|
.catch((err) => {
|
|
942
|
-
console.error(
|
|
943
|
-
throw new StandardError(500,
|
|
922
|
+
console.error('Failed to fetch teams:', err);
|
|
923
|
+
throw new StandardError(500, 'Failed to fetch teams');
|
|
944
924
|
});
|
|
945
925
|
}
|
|
946
926
|
fetchLabels(body = {}, cancelToken, headers = {}) {
|
|
947
|
-
if (!this.companyId || this.companyId.trim() ===
|
|
948
|
-
throw new StandardError(400,
|
|
927
|
+
if (!this.companyId || this.companyId.trim() === '') {
|
|
928
|
+
throw new StandardError(400, 'Company ID is required');
|
|
949
929
|
}
|
|
950
|
-
return this._fetch(
|
|
930
|
+
return this._fetch('POST', `/company/${this.companyId}/labels`, JSON.stringify(body), cancelToken, {
|
|
951
931
|
...headers,
|
|
952
|
-
|
|
932
|
+
'Content-Type': 'application/json',
|
|
953
933
|
})
|
|
954
934
|
.then((response) => {
|
|
955
935
|
if (!response || !Array.isArray(response)) {
|
|
956
|
-
throw new StandardError(400,
|
|
936
|
+
throw new StandardError(400, 'Invalid labels response');
|
|
957
937
|
}
|
|
958
938
|
return response;
|
|
959
939
|
})
|
|
960
940
|
.catch((err) => {
|
|
961
|
-
console.error(
|
|
962
|
-
throw new StandardError(500,
|
|
941
|
+
console.error('Failed to fetch labels:', err);
|
|
942
|
+
throw new StandardError(500, 'Failed to fetch labels');
|
|
963
943
|
});
|
|
964
944
|
}
|
|
965
945
|
fetchGroups(body = {}, cancelToken, headers = {}) {
|
|
966
|
-
if (!this.companyId || this.companyId.trim() ===
|
|
967
|
-
throw new StandardError(400,
|
|
946
|
+
if (!this.companyId || this.companyId.trim() === '') {
|
|
947
|
+
throw new StandardError(400, 'Company ID is required');
|
|
968
948
|
}
|
|
969
|
-
return this._fetch(
|
|
949
|
+
return this._fetch('POST', `/company/${this.companyId}/groups`, JSON.stringify(body), cancelToken, {
|
|
970
950
|
...headers,
|
|
971
|
-
|
|
951
|
+
'Content-Type': 'application/json',
|
|
972
952
|
})
|
|
973
953
|
.then((response) => {
|
|
974
954
|
if (!response || !Array.isArray(response)) {
|
|
975
|
-
throw new StandardError(400,
|
|
955
|
+
throw new StandardError(400, 'Invalid groups response');
|
|
976
956
|
}
|
|
977
957
|
return response;
|
|
978
958
|
})
|
|
979
959
|
.catch((err) => {
|
|
980
|
-
console.error(
|
|
981
|
-
throw new StandardError(500,
|
|
960
|
+
console.error('Failed to fetch groups:', err);
|
|
961
|
+
throw new StandardError(500, 'Failed to fetch groups');
|
|
982
962
|
});
|
|
983
963
|
}
|
|
984
964
|
fetchSkills(body = {}, cancelToken, headers = {}) {
|
|
985
|
-
if (!this.companyId || this.companyId.trim() ===
|
|
986
|
-
throw new StandardError(400,
|
|
965
|
+
if (!this.companyId || this.companyId.trim() === '') {
|
|
966
|
+
throw new StandardError(400, 'Company ID is required');
|
|
987
967
|
}
|
|
988
|
-
return this._fetch(
|
|
968
|
+
return this._fetch('POST', `/company/${this.companyId}/skills`, JSON.stringify(body), cancelToken, {
|
|
989
969
|
...headers,
|
|
990
|
-
|
|
970
|
+
'Content-Type': 'application/json',
|
|
991
971
|
})
|
|
992
972
|
.then((response) => {
|
|
993
973
|
if (!response || !Array.isArray(response)) {
|
|
994
|
-
throw new StandardError(400,
|
|
974
|
+
throw new StandardError(400, 'Invalid skills response');
|
|
995
975
|
}
|
|
996
976
|
return response;
|
|
997
977
|
})
|
|
998
978
|
.catch((err) => {
|
|
999
|
-
console.error(
|
|
1000
|
-
throw new StandardError(500,
|
|
979
|
+
console.error('Failed to fetch skills:', err);
|
|
980
|
+
throw new StandardError(500, 'Failed to fetch skills');
|
|
1001
981
|
});
|
|
1002
982
|
}
|
|
1003
983
|
fetchSessions(body = {}, cancelToken, headers = {}) {
|
|
1004
|
-
if (!this.companyId || this.companyId.trim() ===
|
|
1005
|
-
throw new StandardError(400,
|
|
984
|
+
if (!this.companyId || this.companyId.trim() === '') {
|
|
985
|
+
throw new StandardError(400, 'Company ID is required');
|
|
1006
986
|
}
|
|
1007
|
-
return this._fetch(
|
|
987
|
+
return this._fetch('POST', `/company/${this.companyId}/sessions`, JSON.stringify(body), cancelToken, {
|
|
1008
988
|
...headers,
|
|
1009
|
-
|
|
989
|
+
'Content-Type': 'application/json',
|
|
1010
990
|
})
|
|
1011
991
|
.then((response) => {
|
|
1012
992
|
if (!response || !Array.isArray(response)) {
|
|
1013
|
-
throw new StandardError(400,
|
|
993
|
+
throw new StandardError(400, 'Invalid sessions response');
|
|
1014
994
|
}
|
|
1015
995
|
return response;
|
|
1016
996
|
})
|
|
1017
997
|
.catch((err) => {
|
|
1018
|
-
console.error(
|
|
1019
|
-
throw new StandardError(500,
|
|
998
|
+
console.error('Failed to fetch sessions:', err);
|
|
999
|
+
throw new StandardError(500, 'Failed to fetch sessions');
|
|
1020
1000
|
});
|
|
1021
1001
|
}
|
|
1022
1002
|
/* ── Email delivery tracking ──────────────────────────────────────── */
|
|
@@ -1029,7 +1009,7 @@ export class AvroQueryClient {
|
|
|
1029
1009
|
if (this._emailListenersInit)
|
|
1030
1010
|
return;
|
|
1031
1011
|
this._emailListenersInit = true;
|
|
1032
|
-
this.socket.on(
|
|
1012
|
+
this.socket.on('email_succeeded', (data) => {
|
|
1033
1013
|
const entry = this._emailTracking.get(data.request_id);
|
|
1034
1014
|
if (!entry)
|
|
1035
1015
|
return;
|
|
@@ -1040,7 +1020,7 @@ export class AvroQueryClient {
|
|
|
1040
1020
|
}, 5000);
|
|
1041
1021
|
entry.onSuccess?.(data);
|
|
1042
1022
|
});
|
|
1043
|
-
this.socket.on(
|
|
1023
|
+
this.socket.on('email_failed', (data) => {
|
|
1044
1024
|
const entry = this._emailTracking.get(data.request_id);
|
|
1045
1025
|
if (!entry)
|
|
1046
1026
|
return;
|
|
@@ -1093,7 +1073,7 @@ export class AvroQueryClient {
|
|
|
1093
1073
|
return this.post({
|
|
1094
1074
|
path: `/bill/${billId}/email`,
|
|
1095
1075
|
data: JSON.stringify(body),
|
|
1096
|
-
headers: {
|
|
1076
|
+
headers: { 'Content-Type': 'application/json' },
|
|
1097
1077
|
});
|
|
1098
1078
|
}
|
|
1099
1079
|
catch (error) {
|