@go-avro/avro-js 0.0.38 → 0.0.42
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.
|
@@ -17,7 +17,10 @@ export const AvroQueryClientProvider = ({ baseUrl, authManager, queryClient, con
|
|
|
17
17
|
return () => {
|
|
18
18
|
try {
|
|
19
19
|
client.teardownSocketInvalidation();
|
|
20
|
-
|
|
20
|
+
// Socket is NOT disconnected here. Its lifecycle is managed by the
|
|
21
|
+
// AvroQueryClient constructor and token refresh callbacks.
|
|
22
|
+
// Disconnecting here breaks React StrictMode — the constructor's
|
|
23
|
+
// async connect flow has already completed, so the socket stays dead.
|
|
21
24
|
}
|
|
22
25
|
catch (e) {
|
|
23
26
|
// ignore
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import io from "socket.io-client";
|
|
2
2
|
import { useMutation, useQueryClient, } from "@tanstack/react-query";
|
|
3
3
|
import { v4 as uuidv4 } from "uuid";
|
|
4
|
-
import { Job, LoginResponse, } from "../types/api";
|
|
4
|
+
import { _Event, Job, LoginResponse, Route, } from "../types/api";
|
|
5
5
|
import { AuthState } from "../types/auth";
|
|
6
6
|
import { StandardError } from "../types/error";
|
|
7
7
|
function isBulkEvent(c) {
|
|
@@ -53,11 +53,13 @@ const SOCKET_EVENT_CONFIG = {
|
|
|
53
53
|
entityKey: "routes",
|
|
54
54
|
action: "create",
|
|
55
55
|
fetchPath: (id) => `/route/${id}`,
|
|
56
|
+
construct: (d) => new Route(d),
|
|
56
57
|
},
|
|
57
58
|
update_route: {
|
|
58
59
|
entityKey: "routes",
|
|
59
60
|
action: "update",
|
|
60
61
|
fetchPath: (id) => `/route/${id}`,
|
|
62
|
+
construct: (d) => new Route(d),
|
|
61
63
|
},
|
|
62
64
|
delete_route: { entityKey: "routes", action: "delete", fetchPath: null },
|
|
63
65
|
// ── Events (also refetch parent job — overdueness, last_event, etc.) ──
|
|
@@ -65,6 +67,7 @@ const SOCKET_EVENT_CONFIG = {
|
|
|
65
67
|
entityKey: "events",
|
|
66
68
|
action: "create",
|
|
67
69
|
fetchPath: (id) => `/event/${id}`,
|
|
70
|
+
construct: (d) => new _Event(d),
|
|
68
71
|
relatedRefetch: [
|
|
69
72
|
{
|
|
70
73
|
entityKey: "jobs",
|
|
@@ -78,6 +81,7 @@ const SOCKET_EVENT_CONFIG = {
|
|
|
78
81
|
entityKey: "events",
|
|
79
82
|
action: "update",
|
|
80
83
|
fetchPath: (id) => `/event/${id}`,
|
|
84
|
+
construct: (d) => new _Event(d),
|
|
81
85
|
relatedRefetch: [
|
|
82
86
|
{
|
|
83
87
|
entityKey: "jobs",
|
|
@@ -229,13 +233,16 @@ export class AvroQueryClient {
|
|
|
229
233
|
});
|
|
230
234
|
config.authManager.isAuthenticated().then((isAuth) => {
|
|
231
235
|
this.setAuthState(isAuth);
|
|
232
|
-
this.getCompanyId().then((id) => {
|
|
233
|
-
this.companyId = id;
|
|
234
|
-
});
|
|
235
236
|
if (!this.socket.connected && isAuth === AuthState.AUTHENTICATED) {
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
237
|
+
// Resolve both companyId and access token before connecting so
|
|
238
|
+
// the 'connect' handler in setupSocketInvalidation can immediately
|
|
239
|
+
// join the company room.
|
|
240
|
+
Promise.all([
|
|
241
|
+
this.getCompanyId(),
|
|
242
|
+
this.config.authManager.accessToken(),
|
|
243
|
+
])
|
|
244
|
+
.then(([id, token]) => {
|
|
245
|
+
this.companyId = id;
|
|
239
246
|
console.log("Initializing socket connection with token:", token);
|
|
240
247
|
this.socket.auth = { token: token };
|
|
241
248
|
this.socket.connect();
|
|
@@ -244,6 +251,12 @@ export class AvroQueryClient {
|
|
|
244
251
|
console.error("Not logged in:", err);
|
|
245
252
|
});
|
|
246
253
|
}
|
|
254
|
+
else {
|
|
255
|
+
// Not authenticated – still cache the companyId for later.
|
|
256
|
+
this.getCompanyId().then((id) => {
|
|
257
|
+
this.companyId = id;
|
|
258
|
+
});
|
|
259
|
+
}
|
|
247
260
|
});
|
|
248
261
|
this.socket.on("connect", () => {
|
|
249
262
|
this.setAuthState(AuthState.AUTHENTICATED);
|
|
@@ -315,6 +328,7 @@ export class AvroQueryClient {
|
|
|
315
328
|
if (isBulkEvent(config)) {
|
|
316
329
|
// ── Bulk: invalidate all specified keys ──────────────
|
|
317
330
|
const handler = () => {
|
|
331
|
+
console.log(`[socket-debug] bulk event: ${event}`, config.invalidateKeys);
|
|
318
332
|
for (const key of config.invalidateKeys) {
|
|
319
333
|
queryClient.invalidateQueries({ queryKey: key });
|
|
320
334
|
}
|
|
@@ -326,9 +340,11 @@ export class AvroQueryClient {
|
|
|
326
340
|
// ── Targeted: surgical cache update ──────────────────
|
|
327
341
|
const { entityKey, action, fetchPath, idField, alsoInvalidate, relatedRefetch, } = config;
|
|
328
342
|
const handler = async (data) => {
|
|
343
|
+
console.log(`[socket-debug] targeted event: ${event}`, data);
|
|
329
344
|
const id = data?.[idField ?? "id"];
|
|
330
345
|
// No id → old backend or malformed payload → full invalidation
|
|
331
346
|
if (!id || typeof id !== "string") {
|
|
347
|
+
console.log(`[socket-debug] no id found, falling back to full invalidation for ${entityKey}`);
|
|
332
348
|
invalidateEntity(entityKey);
|
|
333
349
|
alsoInvalidate?.forEach((k) => queryClient.invalidateQueries({ queryKey: k }));
|
|
334
350
|
return;
|
|
@@ -366,8 +382,13 @@ export class AvroQueryClient {
|
|
|
366
382
|
}
|
|
367
383
|
// Auto join/leave company room
|
|
368
384
|
const joinCompanyRoom = () => {
|
|
385
|
+
console.log(`[socket-debug] joinCompanyRoom called, companyId=${this.companyId}, connected=${this.socket.connected}`);
|
|
369
386
|
if (this.companyId) {
|
|
370
387
|
this.socket.emit("join_company", { company_id: this.companyId });
|
|
388
|
+
console.log(`[socket-debug] emitted join_company for ${this.companyId}`);
|
|
389
|
+
}
|
|
390
|
+
else {
|
|
391
|
+
console.warn(`[socket-debug] joinCompanyRoom skipped — companyId is undefined`);
|
|
371
392
|
}
|
|
372
393
|
};
|
|
373
394
|
this.socket.on("connect", joinCompanyRoom);
|
|
@@ -376,6 +397,7 @@ export class AvroQueryClient {
|
|
|
376
397
|
if (this.socket.connected && this.companyId) {
|
|
377
398
|
joinCompanyRoom();
|
|
378
399
|
}
|
|
400
|
+
console.log(`[socket-debug] setupSocketInvalidation complete, socket.connected=${this.socket.connected}, companyId=${this.companyId}`);
|
|
379
401
|
this._socketInvalidationCleanup = () => {
|
|
380
402
|
for (const { event, handler } of handlers) {
|
|
381
403
|
this.socket.off(event, handler);
|
|
@@ -556,7 +578,20 @@ export class AvroQueryClient {
|
|
|
556
578
|
return this.config.authManager.getCache(key);
|
|
557
579
|
}
|
|
558
580
|
setCompanyId(companyId) {
|
|
581
|
+
const previousId = this.companyId;
|
|
559
582
|
this.companyId = companyId;
|
|
583
|
+
console.log(`[socket-debug] setCompanyId called: ${companyId}, socket.connected=${this.socket.connected}, prev=${previousId}`);
|
|
584
|
+
// If the socket is already connected, leave the old room and join the new one.
|
|
585
|
+
if (this.socket.connected) {
|
|
586
|
+
if (previousId && previousId !== companyId) {
|
|
587
|
+
this.socket.emit("leave_company", { company_id: previousId });
|
|
588
|
+
}
|
|
589
|
+
this.socket.emit("join_company", { company_id: companyId });
|
|
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`);
|
|
594
|
+
}
|
|
560
595
|
return this.config.authManager.setCompanyId(companyId);
|
|
561
596
|
}
|
|
562
597
|
getCompanyId() {
|
|
@@ -610,6 +645,7 @@ export class AvroQueryClient {
|
|
|
610
645
|
*/
|
|
611
646
|
async _syncEntity(queryClient, params) {
|
|
612
647
|
const { action, entityKey, id, fetchPath, construct } = params;
|
|
648
|
+
console.log(`[socket-debug] _syncEntity: action=${action}, entity=${entityKey}, id=${id}, fetchPath=${fetchPath}`);
|
|
613
649
|
const predicate = (q) => matchesEntityKey(q, entityKey);
|
|
614
650
|
const invalidate = () => queryClient.invalidateQueries({ predicate });
|
|
615
651
|
// ─── DELETE ─────────────────────────────────────────
|
|
@@ -643,6 +679,7 @@ export class AvroQueryClient {
|
|
|
643
679
|
staleTime: 0,
|
|
644
680
|
});
|
|
645
681
|
const item = construct ? construct(raw) : raw;
|
|
682
|
+
console.log(`[socket-debug] _syncEntity fetched ${entityKey}/${id}:`, item);
|
|
646
683
|
queryClient.setQueryData([entityKey, id], item);
|
|
647
684
|
if (action === "create") {
|
|
648
685
|
queryClient.setQueriesData({ predicate, type: "active" }, (old) => {
|
|
@@ -681,9 +718,11 @@ export class AvroQueryClient {
|
|
|
681
718
|
return old;
|
|
682
719
|
});
|
|
683
720
|
}
|
|
721
|
+
console.log(`[socket-debug] _syncEntity completed ${action} for ${entityKey}/${id}`);
|
|
684
722
|
return item;
|
|
685
723
|
}
|
|
686
|
-
catch {
|
|
724
|
+
catch (err) {
|
|
725
|
+
console.error(`[socket-debug] _syncEntity fetch FAILED for ${entityKey}/${id}:`, err);
|
|
687
726
|
invalidate();
|
|
688
727
|
return undefined;
|
|
689
728
|
}
|
|
@@ -32,14 +32,17 @@ AvroQueryClient.prototype.useGetCurrentCompany = function () {
|
|
|
32
32
|
queryKey: ["companies", "current"],
|
|
33
33
|
queryFn: async () => {
|
|
34
34
|
if (!this.companyId) {
|
|
35
|
-
|
|
35
|
+
const storedId = await this.config.authManager.getCompanyId();
|
|
36
|
+
if (storedId) {
|
|
37
|
+
await this.setCompanyId(storedId);
|
|
38
|
+
}
|
|
36
39
|
}
|
|
37
40
|
if (!this.companyId) {
|
|
38
41
|
const companyList = await this.get({
|
|
39
42
|
path: `/company/list`,
|
|
40
43
|
});
|
|
41
44
|
if (companyList.length > 0) {
|
|
42
|
-
this.
|
|
45
|
+
await this.setCompanyId(companyList[0].id);
|
|
43
46
|
}
|
|
44
47
|
else {
|
|
45
48
|
throw new Error("No company ID set and no companies available");
|