@bivy/bivy 0.18.11-staging.10 → 0.18.11-staging.12
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.
|
@@ -121,8 +121,13 @@ export async function fetchPendingWork(cfg) {
|
|
|
121
121
|
/** Consume the authoritative claim snapshot, not the earlier queue listing. */
|
|
122
122
|
export async function claimWork(cfg, id) {
|
|
123
123
|
const res = await cp(cfg, "POST", `/node/work/${encodeURIComponent(id)}/claim`, randomUUID());
|
|
124
|
-
if (!res.ok)
|
|
124
|
+
if (!res.ok) {
|
|
125
|
+
// 409 is the normal "another node won" race; anything else would otherwise
|
|
126
|
+
// leave an item silently pending forever.
|
|
127
|
+
if (res.status !== 409)
|
|
128
|
+
console.warn(`[control-plane-tasks] claim ${id} failed: HTTP ${res.status}`);
|
|
125
129
|
return undefined;
|
|
130
|
+
}
|
|
126
131
|
const data = await res.json();
|
|
127
132
|
return data.item ?? { id }; // compatibility with older control planes
|
|
128
133
|
}
|
package/dist/server.js
CHANGED
|
@@ -568,7 +568,8 @@ const runDelegation = new RunDelegationService({
|
|
|
568
568
|
if (!sessionId)
|
|
569
569
|
return undefined;
|
|
570
570
|
const routing = raw.routing && typeof raw.routing === "object" ? raw.routing : {};
|
|
571
|
-
|
|
571
|
+
// The queue routes by label `bivy/<machine>`.
|
|
572
|
+
const machine = typeof routing.nodeLabel === "string" && routing.nodeLabel ? routing.nodeLabel.replace(/^bivy\//, "") : identity.name;
|
|
572
573
|
if (machine === identity.name)
|
|
573
574
|
return delegationAnswer(sessionId);
|
|
574
575
|
const target = (await accountMachines()).find((m) => m.name === machine);
|
|
@@ -80,7 +80,23 @@ export class SiblingClient {
|
|
|
80
80
|
ws.on("message", (data) => this.onMessage(String(data), grant));
|
|
81
81
|
ws.on("close", () => this.handleClose());
|
|
82
82
|
ws.on("error", (err) => this.rejectPaired?.(err));
|
|
83
|
-
|
|
83
|
+
// A sibling that never answers pairing (offline behind a stale "online",
|
|
84
|
+
// or an incompatible build) must fail, not hang its caller forever.
|
|
85
|
+
const timeoutMs = this.opts.pairTimeoutMs ?? 20_000;
|
|
86
|
+
let timer;
|
|
87
|
+
try {
|
|
88
|
+
await Promise.race([
|
|
89
|
+
this.paired,
|
|
90
|
+
new Promise((_, reject) => { timer = setTimeout(() => reject(new Error("sibling did not answer pairing")), timeoutMs); }),
|
|
91
|
+
]);
|
|
92
|
+
}
|
|
93
|
+
catch (err) {
|
|
94
|
+
this.close();
|
|
95
|
+
throw err;
|
|
96
|
+
}
|
|
97
|
+
finally {
|
|
98
|
+
clearTimeout(timer);
|
|
99
|
+
}
|
|
84
100
|
}
|
|
85
101
|
async onMessage(raw, grant) {
|
|
86
102
|
let msg;
|
|
@@ -94,11 +110,23 @@ export class SiblingClient {
|
|
|
94
110
|
// Begin account pairing to obtain the sibling's room key.
|
|
95
111
|
// `ephemeral`: a sibling replica is a node↔node bridge, not a user device —
|
|
96
112
|
// authorized for the room key but never listed as a signed-in device.
|
|
97
|
-
|
|
113
|
+
// Pair payloads travel as a JSON string, as the node's relay client
|
|
114
|
+
// expects (it ignores any other shape) and as it replies.
|
|
115
|
+
this.sendControl({ t: "pair", p: JSON.stringify({ k: "pair.account", sessionToken: grant, devicePublicKeyB64: this.keypair.publicKeyB64, label: this.opts.label ?? "Bivy replica", ephemeral: true }) });
|
|
98
116
|
return;
|
|
99
117
|
}
|
|
100
118
|
if (msg.t === "pair") {
|
|
101
|
-
|
|
119
|
+
let pair = msg.p;
|
|
120
|
+
if (typeof pair === "string") {
|
|
121
|
+
try {
|
|
122
|
+
pair = JSON.parse(pair);
|
|
123
|
+
}
|
|
124
|
+
catch {
|
|
125
|
+
return;
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
if (pair && typeof pair === "object")
|
|
129
|
+
this.handlePair(pair);
|
|
102
130
|
return;
|
|
103
131
|
}
|
|
104
132
|
if (msg.t === "frame" && typeof msg.p === "string" && this.cipher) {
|
package/package.json
CHANGED