@cortexkit/subc-client 0.2.0 → 0.2.1
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/package.json +1 -1
- package/src/client.ts +20 -3
- package/src/socket.ts +9 -0
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@cortexkit/subc-client",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.1",
|
|
4
4
|
"description": "TypeScript client for the subc daemon. Wire-compatible (byte-for-byte) with the Rust subc-transport handshake and subc-protocol envelope.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"exports": {
|
package/src/client.ts
CHANGED
|
@@ -521,7 +521,7 @@ export class SubcClient {
|
|
|
521
521
|
timer: null,
|
|
522
522
|
};
|
|
523
523
|
pending.timer = setTimeout(() => {
|
|
524
|
-
this.rejectPending(key, pending, new SubcError(
|
|
524
|
+
this.rejectPending(key, pending, new SubcError(this.timeoutMessage(channel, corr, ms)));
|
|
525
525
|
}, ms);
|
|
526
526
|
this.pending.set(key, pending);
|
|
527
527
|
this.sock.write(encodeFrame(frame), Date.now() + ms).catch((err) => {
|
|
@@ -586,7 +586,7 @@ export class SubcClient {
|
|
|
586
586
|
classifyFailure,
|
|
587
587
|
};
|
|
588
588
|
pending.timer = setTimeout(() => {
|
|
589
|
-
this.rejectPending(key, pending, new SubcError(
|
|
589
|
+
this.rejectPending(key, pending, new SubcError(this.timeoutMessage(channel, corr, ms)));
|
|
590
590
|
}, ms);
|
|
591
591
|
this.pending.set(key, pending);
|
|
592
592
|
|
|
@@ -752,7 +752,14 @@ export class SubcClient {
|
|
|
752
752
|
}
|
|
753
753
|
for (const cached of this.routes.values()) {
|
|
754
754
|
if (cached.closed) continue; // closed concurrently with reconnect — don't reopen.
|
|
755
|
-
|
|
755
|
+
// Thread the route's consumer identity through the reopen, exactly as the
|
|
756
|
+
// lazy per-call path (openCachedRoute) does. Dropping it here would make a
|
|
757
|
+
// route reopened after a reconnect send route.open with no consumer_identity,
|
|
758
|
+
// so the daemon would re-stamp it with a different (weaker) principal than the
|
|
759
|
+
// one it was originally bound under — a silent post-reconnect trust downgrade.
|
|
760
|
+
const channel = await this.routeOpen(cached.target, cached.identity, {
|
|
761
|
+
consumerIdentity: cached.consumerIdentity ?? null,
|
|
762
|
+
});
|
|
756
763
|
// A closeRoute may have raced this reopen (flipping the tombstone during the
|
|
757
764
|
// route.open await). If so, GOODBYE the channel instead of installing it, so the
|
|
758
765
|
// closed route isn't silently re-established on the new connection.
|
|
@@ -765,6 +772,16 @@ export class SubcClient {
|
|
|
765
772
|
}
|
|
766
773
|
}
|
|
767
774
|
|
|
775
|
+
// A request timeout carries the local socket port and (channel, corr) so a
|
|
776
|
+
// packet capture can pinpoint the exact on-wire exchange — the decisive evidence
|
|
777
|
+
// for whether a "timed out" reply was actually delivered to this socket (a
|
|
778
|
+
// client-local demux problem) or never sent (a daemon/module problem).
|
|
779
|
+
private timeoutMessage(channel: number, corr: bigint, ms: number): string {
|
|
780
|
+
const port = this.sock.localPort();
|
|
781
|
+
const where = port === null ? "channel" : `local_port=${port} channel`;
|
|
782
|
+
return `request on ${where} ${channel} corr ${corr} timed out after ${ms}ms`;
|
|
783
|
+
}
|
|
784
|
+
|
|
768
785
|
private routeClosedDuringOpen(): SubcCallError {
|
|
769
786
|
return new SubcCallError("not_sent", "route was closed before route.open completed", "route_closed");
|
|
770
787
|
}
|
package/src/socket.ts
CHANGED
|
@@ -64,6 +64,15 @@ export class SubcSocket {
|
|
|
64
64
|
sock.on("close", () => fail(new SocketClosedError("subc connection closed")));
|
|
65
65
|
}
|
|
66
66
|
|
|
67
|
+
/**
|
|
68
|
+
* The OS-assigned local TCP port of this connection, or null if not yet
|
|
69
|
+
* connected/closed. Used to correlate a client-side timeout with a specific
|
|
70
|
+
* socket in a packet capture when diagnosing reply-delivery issues.
|
|
71
|
+
*/
|
|
72
|
+
localPort(): number | null {
|
|
73
|
+
return this.sock.localPort ?? null;
|
|
74
|
+
}
|
|
75
|
+
|
|
67
76
|
static connect(host: string, port: number, deadlineMs: number): Promise<SubcSocket> {
|
|
68
77
|
return new Promise((resolve, reject) => {
|
|
69
78
|
const sock = net.connect({ host, port });
|