@openclaw/gateway-client 2026.10.5-beta.4 → 2026.10.10-beta.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/README.md +10 -3
- package/dist/browser.mjs +2 -2
- package/dist/index.mjs +3 -3
- package/dist/{readiness-rG6_5Ynk.mjs → readiness-CwRz4ZX8.mjs} +1 -8
- package/dist/readiness.mjs +1 -1
- package/dist/{session-subscriptions-DE0w2upu.mjs → session-subscriptions-hOI4k496.mjs} +47 -82
- package/dist/{timeouts-CQTCye5U.mjs → timeouts-F2UKsnjG.mjs} +1 -1
- package/dist/timeouts.d.mts +2 -2
- package/dist/timeouts.mjs +1 -1
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -31,7 +31,7 @@ Use the verified stable release with exact pins:
|
|
|
31
31
|
npm install --save-exact @openclaw/gateway-client@2026.8.1 @openclaw/gateway-protocol@2026.8.1
|
|
32
32
|
```
|
|
33
33
|
|
|
34
|
-
See the
|
|
34
|
+
See the [installation guide](https://docs.openclaw.ai/gateway/clients#install-the-packages)
|
|
35
35
|
for package/wire-version rules and recovery from reserved `0.0.0` artifacts.
|
|
36
36
|
Test it with the Gateway version you deploy; the root `openclaw` CLI has its own
|
|
37
37
|
package versions and dist-tags.
|
|
@@ -162,7 +162,7 @@ transport timeouts return `false`. Both entries use the same implementation.
|
|
|
162
162
|
|
|
163
163
|
## Defaults and reconnect behavior
|
|
164
164
|
|
|
165
|
-
The Node client starts with a 30 second request timeout, a
|
|
165
|
+
The Node client starts with a 30 second request timeout, a 30 second
|
|
166
166
|
connect-challenge timeout, and exponential reconnect backoff from 1 second to 30
|
|
167
167
|
seconds with a multiplier of 2. Reconnects use randomized delays: the first waits
|
|
168
168
|
1–1.2 seconds, and sustained failures spread retries across 25–30 seconds.
|
|
@@ -181,7 +181,14 @@ first so its authoritative outcome can settle the run. Other gapped frames and
|
|
|
181
181
|
subsequent frames from that socket are not delivered. Reconnect restores a fresh live-text baseline; applications should
|
|
182
182
|
also refresh durable state and restore their session subscriptions.
|
|
183
183
|
|
|
184
|
-
|
|
184
|
+
Session subscription requests time out without compensating RPCs. If the Gateway
|
|
185
|
+
applied a subscribe or unsubscribe but its acknowledgment was lost, observation
|
|
186
|
+
may remain stale until a fresh subscription or reconnect. In particular, a
|
|
187
|
+
retained handle may miss updates after an unacknowledged unsubscribe. The caller
|
|
188
|
+
still receives the timeout; ordinary acknowledged leases and release retries
|
|
189
|
+
retain their ownership and ordering.
|
|
190
|
+
|
|
191
|
+
The defaults table and the server policy fields that can replace
|
|
185
192
|
pre-handshake values are documented in the
|
|
186
193
|
[Gateway protocol specification](https://docs.openclaw.ai/gateway/protocol#client-constants).
|
|
187
194
|
|
package/dist/browser.mjs
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { A as buildGatewayConnectAuth, B as normalizeDeviceMetadataForAuth, C as isGatewayProtocolResponseError, D as gatewayCredentialScope, E as resolveModelCatalogConnect, F as asNullableRecord, M as selectGatewayConnectAuth, N as shouldRetryGatewayWithDeviceToken, O as gatewayOriginScope, P as mergeChatStreamMessage, R as buildDeviceAuthPayload, S as GatewayProtocolRequestTimeoutError, _ as isSessionProjectionErrorMessage, a as createSessionProjection, b as GatewayProtocolClient, c as reduceSessionProjection, d as readSessionProjectionFinalMessageIdentity, f as isLocallyOptimisticSessionMessage, g as readSessionMessageSequence, h as readSessionMessageIdentity, i as resetGatewaySessionMessageSubscriptionCoordinator, j as resolveGatewayConnectScopes, k as GatewayBrowserDeviceAuthLifecycle, l as reduceSessionProjectionRunEvent, m as readAssistantStreamSegmentIdentity, n as getGatewaySessionMessageSubscriptionCoordinator, o as projectLiveSessionMessage, p as normalizeSessionProjectionRunId, r as releaseGatewaySessionMessageSubscription, s as reconcileSessionProjectionSnapshot, t as GatewaySessionMessageSubscriptionCoordinator, u as hasSessionProjectionAcceptedFinal, v as projectSessionTerminalReplyMessage, x as GatewayProtocolRequestError, y as shouldPauseGatewayReconnect, z as buildDeviceAuthPayloadV3 } from "./session-subscriptions-
|
|
2
|
-
import { n as DEFAULT_PREAUTH_HANDSHAKE_TIMEOUT_MS, p as resolveSafeTimeoutDelayMs, t as DEFAULT_GATEWAY_REQUEST_TIMEOUT_MS } from "./timeouts-
|
|
1
|
+
import { A as buildGatewayConnectAuth, B as normalizeDeviceMetadataForAuth, C as isGatewayProtocolResponseError, D as gatewayCredentialScope, E as resolveModelCatalogConnect, F as asNullableRecord, M as selectGatewayConnectAuth, N as shouldRetryGatewayWithDeviceToken, O as gatewayOriginScope, P as mergeChatStreamMessage, R as buildDeviceAuthPayload, S as GatewayProtocolRequestTimeoutError, _ as isSessionProjectionErrorMessage, a as createSessionProjection, b as GatewayProtocolClient, c as reduceSessionProjection, d as readSessionProjectionFinalMessageIdentity, f as isLocallyOptimisticSessionMessage, g as readSessionMessageSequence, h as readSessionMessageIdentity, i as resetGatewaySessionMessageSubscriptionCoordinator, j as resolveGatewayConnectScopes, k as GatewayBrowserDeviceAuthLifecycle, l as reduceSessionProjectionRunEvent, m as readAssistantStreamSegmentIdentity, n as getGatewaySessionMessageSubscriptionCoordinator, o as projectLiveSessionMessage, p as normalizeSessionProjectionRunId, r as releaseGatewaySessionMessageSubscription, s as reconcileSessionProjectionSnapshot, t as GatewaySessionMessageSubscriptionCoordinator, u as hasSessionProjectionAcceptedFinal, v as projectSessionTerminalReplyMessage, x as GatewayProtocolRequestError, y as shouldPauseGatewayReconnect, z as buildDeviceAuthPayloadV3 } from "./session-subscriptions-hOI4k496.mjs";
|
|
2
|
+
import { n as DEFAULT_PREAUTH_HANDSHAKE_TIMEOUT_MS, p as resolveSafeTimeoutDelayMs, t as DEFAULT_GATEWAY_REQUEST_TIMEOUT_MS } from "./timeouts-F2UKsnjG.mjs";
|
|
3
3
|
import { GATEWAY_SERVER_CAPS } from "@openclaw/gateway-protocol/frame-guards";
|
|
4
4
|
export * from "@openclaw/gateway-protocol/connect-error-details";
|
|
5
5
|
export * from "@openclaw/gateway-protocol/gateway-error-details";
|
package/dist/index.mjs
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import { A as buildGatewayConnectAuth, B as normalizeDeviceMetadataForAuth, C as isGatewayProtocolResponseError, D as gatewayCredentialScope, E as resolveModelCatalogConnect, I as asRecord, L as isRecord, M as selectGatewayConnectAuth, N as shouldRetryGatewayWithDeviceToken, O as gatewayOriginScope, P as mergeChatStreamMessage, R as buildDeviceAuthPayload, S as GatewayProtocolRequestTimeoutError, T as raceWithTimeout, _ as isSessionProjectionErrorMessage, a as createSessionProjection, b as GatewayProtocolClient, c as reduceSessionProjection, d as readSessionProjectionFinalMessageIdentity, f as isLocallyOptimisticSessionMessage, g as readSessionMessageSequence, h as readSessionMessageIdentity, i as resetGatewaySessionMessageSubscriptionCoordinator, j as resolveGatewayConnectScopes, k as GatewayBrowserDeviceAuthLifecycle, l as reduceSessionProjectionRunEvent, m as readAssistantStreamSegmentIdentity, n as getGatewaySessionMessageSubscriptionCoordinator, o as projectLiveSessionMessage, p as normalizeSessionProjectionRunId, r as releaseGatewaySessionMessageSubscription, s as reconcileSessionProjectionSnapshot, t as GatewaySessionMessageSubscriptionCoordinator, u as hasSessionProjectionAcceptedFinal, v as projectSessionTerminalReplyMessage, w as createAbortError, x as GatewayProtocolRequestError, y as shouldPauseGatewayReconnect, z as buildDeviceAuthPayloadV3 } from "./session-subscriptions-
|
|
2
|
-
import { _ as normalizeOptionalString, a as MIN_CONNECT_CHALLENGE_TIMEOUT_MS, c as clearGatewayConnectTimeout, d as resolveFiniteTimeoutDelayMs, f as resolvePreauthHandshakeTimeoutMs, h as normalizeLowercaseStringOrEmpty, i as MAX_SAFE_TIMEOUT_DELAY_MS, l as getConnectChallengeTimeoutMsFromEnv, m as startGatewayConnectTimeout, n as DEFAULT_PREAUTH_HANDSHAKE_TIMEOUT_MS, o as addSafeTimeoutDelayGraceMs, p as resolveSafeTimeoutDelayMs, r as MAX_CONNECT_CHALLENGE_TIMEOUT_MS, s as clampConnectChallengeTimeoutMs, t as DEFAULT_GATEWAY_REQUEST_TIMEOUT_MS, u as resolveConnectChallengeTimeoutMs } from "./timeouts-
|
|
1
|
+
import { A as buildGatewayConnectAuth, B as normalizeDeviceMetadataForAuth, C as isGatewayProtocolResponseError, D as gatewayCredentialScope, E as resolveModelCatalogConnect, I as asRecord, L as isRecord, M as selectGatewayConnectAuth, N as shouldRetryGatewayWithDeviceToken, O as gatewayOriginScope, P as mergeChatStreamMessage, R as buildDeviceAuthPayload, S as GatewayProtocolRequestTimeoutError, T as raceWithTimeout, _ as isSessionProjectionErrorMessage, a as createSessionProjection, b as GatewayProtocolClient, c as reduceSessionProjection, d as readSessionProjectionFinalMessageIdentity, f as isLocallyOptimisticSessionMessage, g as readSessionMessageSequence, h as readSessionMessageIdentity, i as resetGatewaySessionMessageSubscriptionCoordinator, j as resolveGatewayConnectScopes, k as GatewayBrowserDeviceAuthLifecycle, l as reduceSessionProjectionRunEvent, m as readAssistantStreamSegmentIdentity, n as getGatewaySessionMessageSubscriptionCoordinator, o as projectLiveSessionMessage, p as normalizeSessionProjectionRunId, r as releaseGatewaySessionMessageSubscription, s as reconcileSessionProjectionSnapshot, t as GatewaySessionMessageSubscriptionCoordinator, u as hasSessionProjectionAcceptedFinal, v as projectSessionTerminalReplyMessage, w as createAbortError, x as GatewayProtocolRequestError, y as shouldPauseGatewayReconnect, z as buildDeviceAuthPayloadV3 } from "./session-subscriptions-hOI4k496.mjs";
|
|
2
|
+
import { _ as normalizeOptionalString, a as MIN_CONNECT_CHALLENGE_TIMEOUT_MS, c as clearGatewayConnectTimeout, d as resolveFiniteTimeoutDelayMs, f as resolvePreauthHandshakeTimeoutMs, h as normalizeLowercaseStringOrEmpty, i as MAX_SAFE_TIMEOUT_DELAY_MS, l as getConnectChallengeTimeoutMsFromEnv, m as startGatewayConnectTimeout, n as DEFAULT_PREAUTH_HANDSHAKE_TIMEOUT_MS, o as addSafeTimeoutDelayGraceMs, p as resolveSafeTimeoutDelayMs, r as MAX_CONNECT_CHALLENGE_TIMEOUT_MS, s as clampConnectChallengeTimeoutMs, t as DEFAULT_GATEWAY_REQUEST_TIMEOUT_MS, u as resolveConnectChallengeTimeoutMs } from "./timeouts-F2UKsnjG.mjs";
|
|
3
3
|
import { rawDataToString } from "./websocket-data.mjs";
|
|
4
|
-
import { n as startGatewayClientWithReadinessWait, r as waitForEventLoopReady, t as startGatewayClientWhenEventLoopReady } from "./readiness-
|
|
4
|
+
import { n as startGatewayClientWithReadinessWait, r as waitForEventLoopReady, t as startGatewayClientWhenEventLoopReady } from "./readiness-CwRz4ZX8.mjs";
|
|
5
5
|
import { GatewayScopeUpgrade } from "./scope-upgrade.mjs";
|
|
6
6
|
import { createRequire } from "node:module";
|
|
7
7
|
import { ConnectErrorDetailCodes, formatConnectErrorMessage, readConnectErrorDetailCode } from "@openclaw/gateway-protocol/connect-error-details";
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { d as resolveFiniteTimeoutDelayMs, u as resolveConnectChallengeTimeoutMs } from "./timeouts-
|
|
1
|
+
import { d as resolveFiniteTimeoutDelayMs, u as resolveConnectChallengeTimeoutMs } from "./timeouts-F2UKsnjG.mjs";
|
|
2
2
|
//#region packages/gateway-client/src/event-loop-ready.ts
|
|
3
3
|
const DEFAULT_MAX_WAIT_MS = 1e4;
|
|
4
4
|
const DEFAULT_INTERVAL_MS = 1;
|
|
@@ -19,11 +19,8 @@ async function waitForEventLoopReady(options = {}) {
|
|
|
19
19
|
let checks = 0;
|
|
20
20
|
let maxDriftMs = 0;
|
|
21
21
|
return await new Promise((resolve) => {
|
|
22
|
-
let settled = false;
|
|
23
22
|
let timer = null;
|
|
24
23
|
const finish = (ready, aborted = false) => {
|
|
25
|
-
if (settled) return;
|
|
26
|
-
settled = true;
|
|
27
24
|
if (timer) {
|
|
28
25
|
clearTimeout(timer);
|
|
29
26
|
timer = null;
|
|
@@ -46,10 +43,6 @@ async function waitForEventLoopReady(options = {}) {
|
|
|
46
43
|
}
|
|
47
44
|
signal?.addEventListener("abort", onAbort, { once: true });
|
|
48
45
|
const scheduleNext = () => {
|
|
49
|
-
if (signal?.aborted) {
|
|
50
|
-
finish(false, true);
|
|
51
|
-
return;
|
|
52
|
-
}
|
|
53
46
|
const elapsedMs = Math.max(0, Date.now() - startedAt);
|
|
54
47
|
const remainingMs = maxWaitMs - elapsedMs;
|
|
55
48
|
if (remainingMs <= 0) {
|
package/dist/readiness.mjs
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { n as startGatewayClientWithReadinessWait, t as startGatewayClientWhenEventLoopReady } from "./readiness-
|
|
1
|
+
import { n as startGatewayClientWithReadinessWait, t as startGatewayClientWhenEventLoopReady } from "./readiness-CwRz4ZX8.mjs";
|
|
2
2
|
export { startGatewayClientWhenEventLoopReady, startGatewayClientWithReadinessWait };
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { _ as normalizeOptionalString, c as clearGatewayConnectTimeout, g as normalizeNullableString, m as startGatewayConnectTimeout, p as resolveSafeTimeoutDelayMs, t as DEFAULT_GATEWAY_REQUEST_TIMEOUT_MS } from "./timeouts-
|
|
1
|
+
import { _ as normalizeOptionalString, c as clearGatewayConnectTimeout, g as normalizeNullableString, m as startGatewayConnectTimeout, p as resolveSafeTimeoutDelayMs, t as DEFAULT_GATEWAY_REQUEST_TIMEOUT_MS } from "./timeouts-F2UKsnjG.mjs";
|
|
2
2
|
import { ConnectErrorDetailCodes, readConnectErrorDetailCode, readConnectErrorRecoveryAdvice, readPairingConnectErrorDetails } from "@openclaw/gateway-protocol/connect-error-details";
|
|
3
3
|
import { isGatewayEventFrame, isGatewayResponseFrame } from "@openclaw/gateway-protocol/frame-guards";
|
|
4
4
|
import { GATEWAY_SUSPEND_IDENTITY_RETRY_AFTER_MS, isGatewayRestartUnavailableError, isGatewaySuspendUnavailableError } from "@openclaw/gateway-protocol/restart-unavailable";
|
|
@@ -333,14 +333,13 @@ async function sleepWithAbort(ms, abortSignal, options = {}) {
|
|
|
333
333
|
const delayMs = resolveSleepDelayMs(ms);
|
|
334
334
|
if (delayMs === 0) return;
|
|
335
335
|
await new Promise((resolve, reject) => {
|
|
336
|
-
let settled = false;
|
|
337
|
-
let timer = null;
|
|
338
336
|
const cleanup = () => abortSignal?.removeEventListener("abort", onAbort);
|
|
337
|
+
const timer = setTimeout(() => {
|
|
338
|
+
cleanup();
|
|
339
|
+
resolve();
|
|
340
|
+
}, delayMs);
|
|
339
341
|
const onAbort = () => {
|
|
340
|
-
|
|
341
|
-
settled = true;
|
|
342
|
-
if (timer) clearTimeout(timer);
|
|
343
|
-
timer = null;
|
|
342
|
+
clearTimeout(timer);
|
|
344
343
|
cleanup();
|
|
345
344
|
reject(createAbortError("aborted", { cause: abortSignal?.reason ?? /* @__PURE__ */ new Error("aborted") }));
|
|
346
345
|
};
|
|
@@ -349,14 +348,7 @@ async function sleepWithAbort(ms, abortSignal, options = {}) {
|
|
|
349
348
|
onAbort();
|
|
350
349
|
return;
|
|
351
350
|
}
|
|
352
|
-
timer = setTimeout(() => {
|
|
353
|
-
settled = true;
|
|
354
|
-
cleanup();
|
|
355
|
-
timer = null;
|
|
356
|
-
resolve();
|
|
357
|
-
}, delayMs);
|
|
358
351
|
if (options.ref === false) timer.unref?.();
|
|
359
|
-
if (abortSignal?.aborted) onAbort();
|
|
360
352
|
});
|
|
361
353
|
}
|
|
362
354
|
var RetrySupervisor = class {
|
|
@@ -1597,6 +1589,39 @@ function isUnsequencedLiveTerminal(current, run) {
|
|
|
1597
1589
|
return Boolean(current.live && current.identity?.role === "assistant" && !current.identity.id && current.identity.sequence === null && run && run.status !== "streaming" && readFinalContentIdentity(current.message) === readFinalContentIdentity(run.message));
|
|
1598
1590
|
}
|
|
1599
1591
|
//#endregion
|
|
1592
|
+
//#region packages/gateway-client/src/session-projection-order.ts
|
|
1593
|
+
function insertSessionProjectionEntry(entries, incoming, runs) {
|
|
1594
|
+
const sequence = incoming.identity?.sequence;
|
|
1595
|
+
let nextIndex = sequence === void 0 || sequence === null ? -1 : entries.findIndex((entry) => {
|
|
1596
|
+
const candidate = entry.identity?.sequence;
|
|
1597
|
+
return candidate !== void 0 && candidate !== null && candidate > sequence;
|
|
1598
|
+
});
|
|
1599
|
+
if (sequence !== void 0 && sequence !== null && nextIndex < 0) nextIndex = entries.length;
|
|
1600
|
+
if (incoming.identity?.role === "user" && incoming.identity.runId) {
|
|
1601
|
+
const runId = incoming.identity.runId;
|
|
1602
|
+
const terminalMessage = runs?.[runId]?.message;
|
|
1603
|
+
const belongsToRun = (entry) => entry.identity?.role === "assistant" && (entry.identity.runId === runId || entry.message === terminalMessage) || entry.pending && entry.identity?.role === "user" && !entry.identity.isImported && asNullableRecord(asNullableRecord(entry.message)?.["__openclaw"])?.steerTargetRunId === runId;
|
|
1604
|
+
if (sequence !== void 0 && sequence !== null) {
|
|
1605
|
+
const before = [];
|
|
1606
|
+
const dependents = [];
|
|
1607
|
+
for (const entry of entries.slice(0, nextIndex)) (entry.identity?.sequence === null && belongsToRun(entry) ? dependents : before).push(entry);
|
|
1608
|
+
return [
|
|
1609
|
+
...before,
|
|
1610
|
+
incoming,
|
|
1611
|
+
...dependents,
|
|
1612
|
+
...entries.slice(nextIndex)
|
|
1613
|
+
];
|
|
1614
|
+
}
|
|
1615
|
+
const terminalIndex = entries.findIndex(belongsToRun);
|
|
1616
|
+
if (terminalIndex >= 0 && (nextIndex < 0 || terminalIndex < nextIndex)) nextIndex = terminalIndex;
|
|
1617
|
+
}
|
|
1618
|
+
return nextIndex < 0 ? [...entries, incoming] : [
|
|
1619
|
+
...entries.slice(0, nextIndex),
|
|
1620
|
+
incoming,
|
|
1621
|
+
...entries.slice(nextIndex)
|
|
1622
|
+
];
|
|
1623
|
+
}
|
|
1624
|
+
//#endregion
|
|
1600
1625
|
//#region packages/gateway-client/src/session-projection-run-retention.ts
|
|
1601
1626
|
/** Bounded retention for completed and active session projection runs. */
|
|
1602
1627
|
const MAX_TRACKED_SESSION_RUNS = 200;
|
|
@@ -1721,37 +1746,6 @@ function withEntries(state, entries) {
|
|
|
1721
1746
|
messages: entries.map((entry) => entry.message)
|
|
1722
1747
|
};
|
|
1723
1748
|
}
|
|
1724
|
-
function insertEntry(entries, incoming, runs) {
|
|
1725
|
-
const sequence = incoming.identity?.sequence;
|
|
1726
|
-
let nextIndex = sequence === void 0 || sequence === null ? -1 : entries.findIndex((entry) => {
|
|
1727
|
-
const candidate = entry.identity?.sequence;
|
|
1728
|
-
return candidate !== void 0 && candidate !== null && candidate > sequence;
|
|
1729
|
-
});
|
|
1730
|
-
if (sequence !== void 0 && sequence !== null && nextIndex < 0) nextIndex = entries.length;
|
|
1731
|
-
if (incoming.identity?.role === "user" && incoming.identity.runId) {
|
|
1732
|
-
const runId = incoming.identity.runId;
|
|
1733
|
-
const terminalMessage = runs?.[runId]?.message;
|
|
1734
|
-
const belongsToRun = (entry) => entry.identity?.role === "assistant" && (entry.identity.runId === runId || entry.message === terminalMessage);
|
|
1735
|
-
if (sequence !== void 0 && sequence !== null) {
|
|
1736
|
-
const before = [];
|
|
1737
|
-
const replies = [];
|
|
1738
|
-
for (const entry of entries.slice(0, nextIndex)) (entry.identity?.sequence === null && belongsToRun(entry) ? replies : before).push(entry);
|
|
1739
|
-
return [
|
|
1740
|
-
...before,
|
|
1741
|
-
incoming,
|
|
1742
|
-
...replies,
|
|
1743
|
-
...entries.slice(nextIndex)
|
|
1744
|
-
];
|
|
1745
|
-
}
|
|
1746
|
-
const terminalIndex = entries.findIndex(belongsToRun);
|
|
1747
|
-
if (terminalIndex >= 0 && (nextIndex < 0 || terminalIndex < nextIndex)) nextIndex = terminalIndex;
|
|
1748
|
-
}
|
|
1749
|
-
return nextIndex < 0 ? [...entries, incoming] : [
|
|
1750
|
-
...entries.slice(0, nextIndex),
|
|
1751
|
-
incoming,
|
|
1752
|
-
...entries.slice(nextIndex)
|
|
1753
|
-
];
|
|
1754
|
-
}
|
|
1755
1749
|
function projectLiveSessionMessage(initialState, message, envelope, scope = {}) {
|
|
1756
1750
|
let state = initialState;
|
|
1757
1751
|
if (!scopesMatch(state.scope, scope)) return state;
|
|
@@ -1767,11 +1761,11 @@ function projectLiveSessionMessage(initialState, message, envelope, scope = {})
|
|
|
1767
1761
|
const provisional = durable === existing ? incoming : existing;
|
|
1768
1762
|
if (durable && isToolUsePersistedFinalRow(durable.message)) {
|
|
1769
1763
|
const history = state.entries.filter((entry) => entry !== provisional);
|
|
1770
|
-
const snapshot = durable === incoming ?
|
|
1764
|
+
const snapshot = durable === incoming ? insertSessionProjectionEntry(history, durable) : history;
|
|
1771
1765
|
const runId = provisional.identity?.runId;
|
|
1772
1766
|
const run = runId ? state.runs[runId] : void 0;
|
|
1773
1767
|
const terminalMatch = findUniqueSnapshotTerminalMatch(provisional, [durable], run, snapshot);
|
|
1774
|
-
if (!terminalMatch) return withEntries(state,
|
|
1768
|
+
if (!terminalMatch) return withEntries(state, insertSessionProjectionEntry(state.entries, incoming, state.runs));
|
|
1775
1769
|
if (terminalMatch.inferred && durable.identity && runId && run) {
|
|
1776
1770
|
const inferredSnapshotTerminal = {
|
|
1777
1771
|
entry: provisional,
|
|
@@ -1790,14 +1784,14 @@ function projectLiveSessionMessage(initialState, message, envelope, scope = {})
|
|
|
1790
1784
|
}
|
|
1791
1785
|
}
|
|
1792
1786
|
}
|
|
1793
|
-
if (!existing) return withEntries(state,
|
|
1787
|
+
if (!existing) return withEntries(state, insertSessionProjectionEntry(state.entries, incoming, state.runs));
|
|
1794
1788
|
const existingIndex = state.entries.indexOf(existing);
|
|
1795
1789
|
if (existing.message === message && existing.live && !existing.pending) return state;
|
|
1796
1790
|
if (!existing.pending && existing.identity?.id && !incoming.identity.id) return state;
|
|
1797
1791
|
if (incoming.identity.sequence !== null && (existing.pending || existing.identity?.sequence === null)) {
|
|
1798
1792
|
const sequence = incoming.identity.sequence;
|
|
1799
1793
|
const violatesOrder = state.entries.some(({ identity }, index) => identity?.sequence != null && (index < existingIndex ? identity.sequence > sequence : identity.sequence < sequence));
|
|
1800
|
-
return withEntries(state, violatesOrder ?
|
|
1794
|
+
return withEntries(state, violatesOrder ? insertSessionProjectionEntry(state.entries.filter((_, index) => index !== existingIndex), incoming, state.runs) : state.entries.toSpliced(existingIndex, 1, incoming));
|
|
1801
1795
|
}
|
|
1802
1796
|
return withEntries(state, state.entries.toSpliced(existingIndex, 1, incoming));
|
|
1803
1797
|
}
|
|
@@ -1823,7 +1817,7 @@ function reconcileSessionProjectionSnapshot(state, messages, scope = {}, options
|
|
|
1823
1817
|
};
|
|
1824
1818
|
continue;
|
|
1825
1819
|
}
|
|
1826
|
-
entries =
|
|
1820
|
+
entries = insertSessionProjectionEntry(entries, current, runs);
|
|
1827
1821
|
}
|
|
1828
1822
|
for (const [runId, run] of Object.entries(runs)) {
|
|
1829
1823
|
const inferred = run.inferredSnapshotTerminal;
|
|
@@ -1833,7 +1827,7 @@ function reconcileSessionProjectionSnapshot(state, messages, scope = {}, options
|
|
|
1833
1827
|
const matches = entries.filter((entry) => entryMatches(entry, inferred.entry, true));
|
|
1834
1828
|
const terminalMatch = findUniqueSnapshotTerminalMatch(inferred.entry, matches, run, entries);
|
|
1835
1829
|
if (candidateRemains && visible && terminalMatch?.inferred) continue;
|
|
1836
|
-
if (candidateRemains && visible && !terminalMatch) entries =
|
|
1830
|
+
if (candidateRemains && visible && !terminalMatch) entries = insertSessionProjectionEntry(entries, inferred.entry, runs);
|
|
1837
1831
|
const { inferredSnapshotTerminal: _inferred, ...settledRun } = run;
|
|
1838
1832
|
runs[runId] = settledRun;
|
|
1839
1833
|
}
|
|
@@ -1931,7 +1925,7 @@ function reduceSessionProjection(state, event) {
|
|
|
1931
1925
|
pending: true,
|
|
1932
1926
|
pendingRunId
|
|
1933
1927
|
} : entry));
|
|
1934
|
-
return seed || state.entries.some((entry) => entryMatches(entry, incoming)) ? state : withEntries(state,
|
|
1928
|
+
return seed || state.entries.some((entry) => entryMatches(entry, incoming)) ? state : withEntries(state, insertSessionProjectionEntry(state.entries, incoming, state.runs));
|
|
1935
1929
|
}
|
|
1936
1930
|
case "sendAcknowledged": {
|
|
1937
1931
|
const runId = normalizeSessionProjectionRunId(event.idempotencyKey ?? event.runId);
|
|
@@ -2095,16 +2089,6 @@ var GatewaySessionMessageSubscriptionCoordinator = class {
|
|
|
2095
2089
|
if (includeApprovals) entry.ready = this.#trackApprovalRequest(entry, entry.ready);
|
|
2096
2090
|
entry.ready.catch(() => void 0);
|
|
2097
2091
|
}
|
|
2098
|
-
if (entry.refreshRequired) {
|
|
2099
|
-
entry.refreshRequired = false;
|
|
2100
|
-
entry.plainFallback = null;
|
|
2101
|
-
entry.approvalRequest = null;
|
|
2102
|
-
const retainedApprovals = [...entry.handles].some((handle) => handle.includeApprovals);
|
|
2103
|
-
entry.ready = this.#requestSubscribe(entry, retainedApprovals).catch((error) => {
|
|
2104
|
-
entry.refreshRequired = true;
|
|
2105
|
-
throw error;
|
|
2106
|
-
});
|
|
2107
|
-
}
|
|
2108
2092
|
const result = await this.#acquireCapability(entry, includeApprovals);
|
|
2109
2093
|
if (!narration && entry.mode === "narration") await this.#requestSubscribe(entry, false, "full");
|
|
2110
2094
|
if (this.#retired) throw new Error("Session message subscription completed on a replaced Gateway connection");
|
|
@@ -2153,10 +2137,7 @@ var GatewaySessionMessageSubscriptionCoordinator = class {
|
|
|
2153
2137
|
return tracked;
|
|
2154
2138
|
}
|
|
2155
2139
|
const removeEntry = entry.handles.size === 1;
|
|
2156
|
-
const tracked = (removeEntry ? this.#requestMessages(entry).
|
|
2157
|
-
if (error instanceof GatewayProtocolRequestTimeoutError && error.requestSent) entry.refreshRequired = true;
|
|
2158
|
-
throw error;
|
|
2159
|
-
}) : this.#requestSubscribe(entry, false, "narration")).then(() => this.#finishRelease(subscription, owner, removeEntry)).finally(() => {
|
|
2140
|
+
const tracked = (removeEntry ? this.#requestMessages(entry) : this.#requestSubscribe(entry, false, "narration")).then(() => this.#finishRelease(subscription, owner, removeEntry)).finally(() => {
|
|
2160
2141
|
if (entry.release === tracked) entry.release = null;
|
|
2161
2142
|
});
|
|
2162
2143
|
entry.release = tracked;
|
|
@@ -2186,7 +2167,6 @@ var GatewaySessionMessageSubscriptionCoordinator = class {
|
|
|
2186
2167
|
wireRequest: null,
|
|
2187
2168
|
includeApprovals: false,
|
|
2188
2169
|
canonicalSettled: false,
|
|
2189
|
-
refreshRequired: false,
|
|
2190
2170
|
handles: /* @__PURE__ */ new Set(),
|
|
2191
2171
|
pendingOwners: 0,
|
|
2192
2172
|
pendingFullOwners: 0,
|
|
@@ -2248,21 +2228,6 @@ var GatewaySessionMessageSubscriptionCoordinator = class {
|
|
|
2248
2228
|
const result = await this.#requestMessages(entry, {
|
|
2249
2229
|
mode,
|
|
2250
2230
|
includeApprovals
|
|
2251
|
-
}).catch(async (error) => {
|
|
2252
|
-
if (!(error instanceof GatewayProtocolRequestTimeoutError) || !error.requestSent || this.#retired) throw error;
|
|
2253
|
-
try {
|
|
2254
|
-
const retainedApprovals = [...entry.handles].some((handle) => handle.includeApprovals);
|
|
2255
|
-
const retainedMode = entry.handles.size > 0 && [...entry.handles].every((handle) => handle.mode === "narration") ? "narration" : void 0;
|
|
2256
|
-
await this.#requestMessages(entry, entry.handles.size > 0 ? {
|
|
2257
|
-
mode: retainedMode,
|
|
2258
|
-
includeApprovals: retainedApprovals
|
|
2259
|
-
} : void 0);
|
|
2260
|
-
entry.mode = retainedMode;
|
|
2261
|
-
entry.includeApprovals = retainedApprovals;
|
|
2262
|
-
} catch (recoveryError) {
|
|
2263
|
-
if (!this.#retired) throw new AggregateError([error, recoveryError], "session message subscription recovery failed", { cause: recoveryError });
|
|
2264
|
-
}
|
|
2265
|
-
throw error;
|
|
2266
2231
|
});
|
|
2267
2232
|
const response = result && typeof result === "object" ? result : null;
|
|
2268
2233
|
const responseKey = response && "key" in response ? response.key : void 0;
|
|
@@ -39,7 +39,7 @@ function isTestRuntimeEnv(env) {
|
|
|
39
39
|
/** Maximum delay Node timers can represent without overflow warnings. */
|
|
40
40
|
const MAX_SAFE_TIMEOUT_DELAY_MS = 2147483647;
|
|
41
41
|
/** Default server-side window for gateway preauth handshakes. */
|
|
42
|
-
const DEFAULT_PREAUTH_HANDSHAKE_TIMEOUT_MS =
|
|
42
|
+
const DEFAULT_PREAUTH_HANDSHAKE_TIMEOUT_MS = 3e4;
|
|
43
43
|
/** Starts the browser-safe deadline that covers Gateway connect preparation and hello. */
|
|
44
44
|
function startGatewayConnectTimeout(onTimeout) {
|
|
45
45
|
const timer = setTimeout(onTimeout, DEFAULT_PREAUTH_HANDSHAKE_TIMEOUT_MS);
|
package/dist/timeouts.d.mts
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
/** Maximum delay Node timers can represent without overflow warnings. */
|
|
3
3
|
export declare const MAX_SAFE_TIMEOUT_DELAY_MS = 2147483647;
|
|
4
4
|
/** Default server-side window for gateway preauth handshakes. */
|
|
5
|
-
export declare const DEFAULT_PREAUTH_HANDSHAKE_TIMEOUT_MS =
|
|
5
|
+
export declare const DEFAULT_PREAUTH_HANDSHAKE_TIMEOUT_MS = 30000;
|
|
6
6
|
/** Starts the browser-safe deadline that covers Gateway connect preparation and hello. */
|
|
7
7
|
export declare function startGatewayConnectTimeout(onTimeout: () => void): ReturnType<typeof setTimeout>;
|
|
8
8
|
/** Clears either pending Gateway handshake phase without retaining its timer. */
|
|
@@ -12,7 +12,7 @@ export declare const DEFAULT_GATEWAY_REQUEST_TIMEOUT_MS = 30000;
|
|
|
12
12
|
/** Minimum client watchdog delay for connect challenge setup. */
|
|
13
13
|
export declare const MIN_CONNECT_CHALLENGE_TIMEOUT_MS = 250;
|
|
14
14
|
/** Default maximum client watchdog delay, aligned with the preauth server timeout. */
|
|
15
|
-
export declare const MAX_CONNECT_CHALLENGE_TIMEOUT_MS =
|
|
15
|
+
export declare const MAX_CONNECT_CHALLENGE_TIMEOUT_MS = 30000;
|
|
16
16
|
/** Clamps arbitrary timer delays to Node's safe range and an optional floor. */
|
|
17
17
|
export declare function resolveSafeTimeoutDelayMs(delayMs: number, opts?: {
|
|
18
18
|
minMs?: number;
|
package/dist/timeouts.mjs
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { a as MIN_CONNECT_CHALLENGE_TIMEOUT_MS, c as clearGatewayConnectTimeout, d as resolveFiniteTimeoutDelayMs, f as resolvePreauthHandshakeTimeoutMs, i as MAX_SAFE_TIMEOUT_DELAY_MS, l as getConnectChallengeTimeoutMsFromEnv, m as startGatewayConnectTimeout, n as DEFAULT_PREAUTH_HANDSHAKE_TIMEOUT_MS, o as addSafeTimeoutDelayGraceMs, p as resolveSafeTimeoutDelayMs, r as MAX_CONNECT_CHALLENGE_TIMEOUT_MS, s as clampConnectChallengeTimeoutMs, t as DEFAULT_GATEWAY_REQUEST_TIMEOUT_MS, u as resolveConnectChallengeTimeoutMs } from "./timeouts-
|
|
1
|
+
import { a as MIN_CONNECT_CHALLENGE_TIMEOUT_MS, c as clearGatewayConnectTimeout, d as resolveFiniteTimeoutDelayMs, f as resolvePreauthHandshakeTimeoutMs, i as MAX_SAFE_TIMEOUT_DELAY_MS, l as getConnectChallengeTimeoutMsFromEnv, m as startGatewayConnectTimeout, n as DEFAULT_PREAUTH_HANDSHAKE_TIMEOUT_MS, o as addSafeTimeoutDelayGraceMs, p as resolveSafeTimeoutDelayMs, r as MAX_CONNECT_CHALLENGE_TIMEOUT_MS, s as clampConnectChallengeTimeoutMs, t as DEFAULT_GATEWAY_REQUEST_TIMEOUT_MS, u as resolveConnectChallengeTimeoutMs } from "./timeouts-F2UKsnjG.mjs";
|
|
2
2
|
export { DEFAULT_GATEWAY_REQUEST_TIMEOUT_MS, DEFAULT_PREAUTH_HANDSHAKE_TIMEOUT_MS, MAX_CONNECT_CHALLENGE_TIMEOUT_MS, MAX_SAFE_TIMEOUT_DELAY_MS, MIN_CONNECT_CHALLENGE_TIMEOUT_MS, addSafeTimeoutDelayGraceMs, clampConnectChallengeTimeoutMs, clearGatewayConnectTimeout, getConnectChallengeTimeoutMsFromEnv, resolveConnectChallengeTimeoutMs, resolveFiniteTimeoutDelayMs, resolvePreauthHandshakeTimeoutMs, resolveSafeTimeoutDelayMs, startGatewayConnectTimeout };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@openclaw/gateway-client",
|
|
3
|
-
"version": "2026.10.
|
|
3
|
+
"version": "2026.10.10-beta.1",
|
|
4
4
|
"description": "Reference WebSocket client for the OpenClaw Gateway protocol",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"client",
|
|
@@ -62,7 +62,7 @@
|
|
|
62
62
|
}
|
|
63
63
|
},
|
|
64
64
|
"dependencies": {
|
|
65
|
-
"@openclaw/gateway-protocol": "2026.10.
|
|
65
|
+
"@openclaw/gateway-protocol": "2026.10.10-beta.1",
|
|
66
66
|
"ipaddr.js": "2.5.0",
|
|
67
67
|
"ws": "8.22.0"
|
|
68
68
|
},
|