@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 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 canonical [installation guide](https://docs.openclaw.ai/gateway/clients#install-the-packages)
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 15 second
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
- The canonical defaults table and the server policy fields that can replace
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-DE0w2upu.mjs";
2
- import { n as DEFAULT_PREAUTH_HANDSHAKE_TIMEOUT_MS, p as resolveSafeTimeoutDelayMs, t as DEFAULT_GATEWAY_REQUEST_TIMEOUT_MS } from "./timeouts-CQTCye5U.mjs";
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-DE0w2upu.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-CQTCye5U.mjs";
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-rG6_5Ynk.mjs";
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-CQTCye5U.mjs";
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) {
@@ -1,2 +1,2 @@
1
- import { n as startGatewayClientWithReadinessWait, t as startGatewayClientWhenEventLoopReady } from "./readiness-rG6_5Ynk.mjs";
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-CQTCye5U.mjs";
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
- if (settled) return;
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 ? insertEntry(history, durable) : history;
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, insertEntry(state.entries, incoming, state.runs));
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, insertEntry(state.entries, incoming, state.runs));
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 ? insertEntry(state.entries.filter((_, index) => index !== existingIndex), incoming, state.runs) : state.entries.toSpliced(existingIndex, 1, incoming));
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 = insertEntry(entries, current, runs);
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 = insertEntry(entries, inferred.entry, runs);
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, insertEntry(state.entries, incoming, state.runs));
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).catch((error) => {
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 = 15e3;
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);
@@ -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 = 15000;
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 = 15000;
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-CQTCye5U.mjs";
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.5-beta.4",
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.5-beta.4",
65
+ "@openclaw/gateway-protocol": "2026.10.10-beta.1",
66
66
  "ipaddr.js": "2.5.0",
67
67
  "ws": "8.22.0"
68
68
  },