@openclaw/gateway-client 2026.9.5 → 2026.9.7
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 +78 -3
- package/dist/browser.d.mts +24 -4
- package/dist/browser.mjs +51 -2
- package/dist/index.d.mts +22 -4
- package/dist/index.mjs +124 -77
- package/dist/{protocol-client-DZ7F1DIs.d.mts → protocol-client-DT451Msj.d.mts} +19 -2
- package/dist/{protocol-request-B5gBmLgq.d.mts → protocol-request-CtVhe3Bj.d.mts} +1 -1
- package/dist/{readiness-B99dV5nY.d.mts → readiness-Cj5C24o2.d.mts} +16 -24
- package/dist/readiness.d.mts +1 -1
- package/dist/scope-upgrade.d.mts +2 -1
- package/dist/scope-upgrade.mjs +12 -2
- package/dist/{session-subscriptions-yRMtCvZZ.d.mts → session-subscriptions-Bcq6_wtR.d.mts} +18 -4
- package/dist/{session-subscriptions-DrOaOXNR.mjs → session-subscriptions-LtlX9oRQ.mjs} +359 -123
- package/dist/timeouts.mjs +1 -1
- package/package.json +3 -3
package/README.md
CHANGED
|
@@ -163,9 +163,23 @@ transport timeouts return `false`. Both entries use the same implementation.
|
|
|
163
163
|
## Defaults and reconnect behavior
|
|
164
164
|
|
|
165
165
|
The Node client starts with a 30 second request timeout, a 15 second
|
|
166
|
-
connect-challenge timeout, and exponential reconnect
|
|
167
|
-
seconds with a multiplier of 2.
|
|
168
|
-
|
|
166
|
+
connect-challenge timeout, and exponential reconnect backoff from 1 second to 30
|
|
167
|
+
seconds with a multiplier of 2. Reconnects use randomized delays: the first waits
|
|
168
|
+
1–1.2 seconds, and sustained failures spread retries across 25–30 seconds.
|
|
169
|
+
Retryable server hints remain minimum waits and can extend beyond the normal cap,
|
|
170
|
+
with up to 20% additional spread. Adapter-owned startup retry hints retain their
|
|
171
|
+
exact next delay without advancing normal backoff.
|
|
172
|
+
|
|
173
|
+
Browser adapters can observe the shared client's `onReconnectScheduled(delayMs,
|
|
174
|
+
signal)` callback to display the actual retry wait, including jitter and timer
|
|
175
|
+
bounds. The signal aborts when the wait is canceled or superseded; adapters should
|
|
176
|
+
clear their countdown when creating the next socket.
|
|
177
|
+
|
|
178
|
+
A sequence gap calls `onGap` and retires the socket unless the callback already
|
|
179
|
+
replaced it. A gap-revealing `chat` final, aborted, or error event is delivered
|
|
180
|
+
first so its authoritative outcome can settle the run. Other gapped frames and
|
|
181
|
+
subsequent frames from that socket are not delivered. Reconnect restores a fresh live-text baseline; applications should
|
|
182
|
+
also refresh durable state and restore their session subscriptions.
|
|
169
183
|
|
|
170
184
|
The canonical defaults table and the server policy fields that can replace
|
|
171
185
|
pre-handshake values are documented in the
|
|
@@ -175,6 +189,67 @@ Use the `./timeouts` entry point when a host must align readiness or watchdog
|
|
|
175
189
|
budgets with these defaults. Use the `./readiness` entry point when startup must
|
|
176
190
|
wait for an event-loop probe before opening the socket.
|
|
177
191
|
|
|
192
|
+
## Streaming chat
|
|
193
|
+
|
|
194
|
+
Event callbacks receive the wire payload unchanged. A `chat` delta's optional
|
|
195
|
+
`message` is an authoritative snapshot that already includes `deltaText`.
|
|
196
|
+
Without `message`, append `deltaText` to the run's existing text. `replace: true`
|
|
197
|
+
replaces the text, including an empty replacement. The first frame received for
|
|
198
|
+
a run and frames that change canvas or media content supply a snapshot.
|
|
199
|
+
|
|
200
|
+
Both public entries export `mergeChatStreamMessage(previousMessage, payload)`
|
|
201
|
+
for clients that own their run state. The helper preserves nontext content and
|
|
202
|
+
message metadata and never appends a snapshot's delta twice. An append without
|
|
203
|
+
a baseline returns `undefined`; recover the connection instead of displaying
|
|
204
|
+
an incomplete answer. `reduceSessionProjectionRunEvent` uses the same merge
|
|
205
|
+
operation for clients using the shared session projection.
|
|
206
|
+
|
|
207
|
+
The high-level `@openclaw/sdk` retains reconstructed chat and assistant-item text
|
|
208
|
+
in its normalized run-event replay, so late readers can recover the text after the initial wire
|
|
209
|
+
snapshot is evicted. Its `rawEvents()` and each normalized event's `raw` field
|
|
210
|
+
still expose the original wire event, including omitted `message` fields.
|
|
211
|
+
Normalized assistant events retain cumulative `data.text` for their current item;
|
|
212
|
+
`data.delta` keeps its wire meaning, and the raw event can omit `data.text`.
|
|
213
|
+
Active chat baselines remain protected while their connection is current. The
|
|
214
|
+
SDK's concrete Gateway transport reconciles outstanding owned or observed runs
|
|
215
|
+
after reconnect through `agent.wait`. Active chat runs can recover display text
|
|
216
|
+
from an exact `chat.history.inFlightRun` match; newer live text always wins over
|
|
217
|
+
an older history response. Assistant-item text re-baselines on its next wire
|
|
218
|
+
snapshot because history contains display text, not raw assistant-item text.
|
|
219
|
+
|
|
220
|
+
SDK and ACP recovery share `recoverTerminalReply`: it collects all assistant
|
|
221
|
+
items for the run in transcript order, preserves live item boundaries, and reads
|
|
222
|
+
full messages when history truncated them. Recovered text preserves leading
|
|
223
|
+
indentation and trailing whitespace. It scans at most ten 200-record pages;
|
|
224
|
+
an incomplete scan reports unavailable instead of presenting a partial reply. The
|
|
225
|
+
bounded `terminalReply.text` summary is never used as complete output. Local
|
|
226
|
+
normalized recovery events have no `raw` field. Their `data.recovery.status`
|
|
227
|
+
reports `rebaselined`, `recovered`, or `unavailable`; unavailable full text omits
|
|
228
|
+
`outputText`. A bare wait timeout is not a run terminal. Terminal observations
|
|
229
|
+
have finite retention, and sessionless or unavailable transcript occurrences
|
|
230
|
+
cannot be reconstructed; unknown outcomes remain unsettled with a recovery
|
|
231
|
+
notice. Automatic recovery stops after four consecutive unavailable observations
|
|
232
|
+
(initial probe plus three waits), releases retention protection, and stays stopped
|
|
233
|
+
across reconnects. Confirmed activity resets that budget; late terminal frames can
|
|
234
|
+
still settle the run. Queued replies use exponential backoff with the Gateway
|
|
235
|
+
client's positive 20% jitter and a 25–30 second cap. ACP reports unavailable full
|
|
236
|
+
text explicitly instead of settling with a partial answer. Closing the client or
|
|
237
|
+
returning a run iterator cancels its recovery work.
|
|
238
|
+
|
|
239
|
+
Reconnect retires old text baselines. Ending the transport event stream also
|
|
240
|
+
releases outstanding-run protection, retaining only bounded replay. Custom
|
|
241
|
+
`OpenClawTransport` implementations must deliver terminal outcomes or end a
|
|
242
|
+
retired event stream; the generic transport interface does not expose reconnect
|
|
243
|
+
notifications and does not receive this automatic reconciliation.
|
|
244
|
+
Confirmed session unsubscribe also releases that session's baseline protection;
|
|
245
|
+
it also releases unobserved runs accepted before their first output. The
|
|
246
|
+
acknowledgment cannot retire a newer acceptance or subscription's snapshot. The concrete
|
|
247
|
+
Gateway transport preserves acknowledgment and event order. Custom transports
|
|
248
|
+
must preserve that ordering or end their retired event stream.
|
|
249
|
+
For raw `global` or `unknown` session keys, pass `agentId` when unsubscribing
|
|
250
|
+
to identify an agent-owned baseline. An unscoped acknowledgment cannot retire
|
|
251
|
+
a baseline with a known agent owner.
|
|
252
|
+
|
|
178
253
|
## Bundled internals
|
|
179
254
|
|
|
180
255
|
The retry supervisor and the small `@openclaw/net-policy/ip` implementation are
|
package/dist/browser.d.mts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import { A as
|
|
1
|
+
import { A as normalizeSessionProjectionRunId, C as reduceSessionProjectionRunEvent, D as SessionMessageIdentity, E as SessionMessageEnvelope, F as gatewayOriginScope, I as mergeChatStreamMessage, L as buildDeviceAuthPayload, M as readSessionMessageIdentity, N as readSessionMessageSequence, O as SessionProjectionEntry, P as gatewayCredentialScope, R as buildDeviceAuthPayloadV3, S as SessionProjectionRunTransition, T as readSessionProjectionFinalMessageIdentity, _ as reconcileSessionProjectionSnapshot, a as GatewaySessionMessageSubscriptionOptions, b as projectSessionTerminalReplyMessage, c as resetGatewaySessionMessageSubscriptionCoordinator, d as SessionProjectionRunStatus, f as SessionProjectionScope, g as projectLiveSessionMessage, h as createSessionProjection, i as GatewaySessionMessageSubscriptionCoordinatorOptions, j as readAssistantStreamSegmentIdentity, k as isLocallyOptimisticSessionMessage, l as SessionProjectionEvent, m as SessionProjectionState, n as GatewaySessionMessageSubscription, o as getGatewaySessionMessageSubscriptionCoordinator, p as SessionProjectionSnapshotOptions, r as GatewaySessionMessageSubscriptionCoordinator, s as releaseGatewaySessionMessageSubscription, t as GatewaySessionMessageRequestClient, u as SessionProjectionRun, v as reduceSessionProjection, w as hasSessionProjectionAcceptedFinal, x as SessionProjectionGatewayRunEvent, y as isSessionProjectionErrorMessage, z as normalizeDeviceMetadataForAuth } from "./session-subscriptions-Bcq6_wtR.mjs";
|
|
2
2
|
import { a as GatewayBrowserDeviceTokenStore, c as resolveGatewayConnectScopes, i as GatewayBrowserDeviceTokenRecord, l as selectGatewayConnectAuth, n as GatewayBrowserDeviceAuthPlan, o as GatewayConnectAuthSelection, r as GatewayBrowserDeviceIdentity, s as buildGatewayConnectAuth, t as GatewayBrowserDeviceAuthLifecycle, u as shouldRetryGatewayWithDeviceToken } from "./browser-device-auth-DoPo-sPB.mjs";
|
|
3
|
-
import { i as isGatewayProtocolResponseError, n as GatewayProtocolRequestOptions, r as GatewayProtocolRequestTimeoutError, t as GatewayProtocolRequestError } from "./protocol-request-
|
|
4
|
-
import { a as
|
|
3
|
+
import { i as isGatewayProtocolResponseError, n as GatewayProtocolRequestOptions, r as GatewayProtocolRequestTimeoutError, t as GatewayProtocolRequestError } from "./protocol-request-CtVhe3Bj.mjs";
|
|
4
|
+
import { a as GatewayProtocolConnectAuthority, c as GatewayProtocolTiming, i as GatewayProtocolCloseContext, l as GatewayProtocolRequestTiming, o as GatewayProtocolSocket, s as GatewayProtocolSocketHandlers, t as GatewayProtocolClient } from "./protocol-client-DT451Msj.mjs";
|
|
5
5
|
import { DEFAULT_GATEWAY_REQUEST_TIMEOUT_MS, DEFAULT_PREAUTH_HANDSHAKE_TIMEOUT_MS, resolveSafeTimeoutDelayMs } from "./timeouts.mjs";
|
|
6
6
|
import { ConnectParams as ConnectParams$1, GATEWAY_SERVER_CAPS } from "@openclaw/gateway-protocol/frame-guards";
|
|
7
7
|
import { ConnectParams, ErrorShape, EventFrame, HelloOk } from "@openclaw/gateway-protocol";
|
|
@@ -10,6 +10,26 @@ export * from "@openclaw/gateway-protocol/gateway-error-details";
|
|
|
10
10
|
export * from "@openclaw/gateway-protocol/client-info";
|
|
11
11
|
export * from "@openclaw/gateway-protocol/startup-unavailable";
|
|
12
12
|
export * from "@openclaw/gateway-protocol/version";
|
|
13
|
+
//#region packages/gateway-client/src/chat-stream-projection.d.ts
|
|
14
|
+
type ChatStreamScope = {
|
|
15
|
+
sessionKey: string;
|
|
16
|
+
agentId: unknown;
|
|
17
|
+
};
|
|
18
|
+
type ChatStreamEvent = {
|
|
19
|
+
event: string;
|
|
20
|
+
payload?: unknown;
|
|
21
|
+
};
|
|
22
|
+
/** Connection-owned chat baselines, independent of the selected local view. */
|
|
23
|
+
export declare class GatewayChatStreamProjection {
|
|
24
|
+
private readonly runs;
|
|
25
|
+
project<T extends ChatStreamEvent>(event: T): {
|
|
26
|
+
event: T;
|
|
27
|
+
missingBaseline: boolean;
|
|
28
|
+
};
|
|
29
|
+
retire(isRetired: (scope: ChatStreamScope) => boolean): void;
|
|
30
|
+
clear(): void;
|
|
31
|
+
}
|
|
32
|
+
//#endregion
|
|
13
33
|
//#region packages/gateway-client/src/model-catalog-connect.d.ts
|
|
14
34
|
/** A requested snapshot opts in only after the server advertises its connect field. */
|
|
15
35
|
export declare function resolveModelCatalogConnect(params: {
|
|
@@ -27,4 +47,4 @@ export declare function shouldPauseGatewayReconnect(params: {
|
|
|
27
47
|
clientVersionMismatchIsTerminal?: boolean;
|
|
28
48
|
}): boolean;
|
|
29
49
|
//#endregion
|
|
30
|
-
export { type ConnectParams, DEFAULT_GATEWAY_REQUEST_TIMEOUT_MS, DEFAULT_PREAUTH_HANDSHAKE_TIMEOUT_MS, type ErrorShape, type EventFrame, GATEWAY_SERVER_CAPS, GatewayBrowserDeviceAuthLifecycle, GatewayBrowserDeviceAuthPlan, GatewayBrowserDeviceIdentity, GatewayBrowserDeviceTokenRecord, GatewayBrowserDeviceTokenStore, GatewayConnectAuthSelection, GatewayProtocolClient, type GatewayProtocolCloseContext, type GatewayProtocolConnectAuthority, GatewayProtocolRequestError, type GatewayProtocolRequestOptions, GatewayProtocolRequestTimeoutError, type GatewayProtocolRequestTiming, type GatewayProtocolSocket, type GatewayProtocolSocketHandlers, type GatewayProtocolTiming, GatewaySessionMessageRequestClient, GatewaySessionMessageSubscription, GatewaySessionMessageSubscriptionCoordinator, GatewaySessionMessageSubscriptionCoordinatorOptions, GatewaySessionMessageSubscriptionOptions, type HelloOk, type SessionMessageEnvelope, type SessionMessageIdentity, type SessionProjectionEntry, SessionProjectionEvent, type SessionProjectionGatewayRunEvent, SessionProjectionRun, SessionProjectionRunStatus, type SessionProjectionRunTransition, SessionProjectionScope, SessionProjectionSnapshotOptions, SessionProjectionState, buildDeviceAuthPayload, buildDeviceAuthPayloadV3, buildGatewayConnectAuth, createSessionProjection, gatewayCredentialScope, gatewayOriginScope, getGatewaySessionMessageSubscriptionCoordinator, hasSessionProjectionAcceptedFinal, isGatewayProtocolResponseError, isLocallyOptimisticSessionMessage, isSessionProjectionErrorMessage, normalizeDeviceMetadataForAuth, normalizeSessionProjectionRunId, projectLiveSessionMessage, readAssistantStreamSegmentIdentity, readSessionMessageIdentity, readSessionMessageSequence, readSessionProjectionFinalMessageIdentity, reconcileSessionProjectionSnapshot, reduceSessionProjection, reduceSessionProjectionRunEvent, releaseGatewaySessionMessageSubscription, resetGatewaySessionMessageSubscriptionCoordinator, resolveGatewayConnectScopes, resolveSafeTimeoutDelayMs, selectGatewayConnectAuth, shouldRetryGatewayWithDeviceToken };
|
|
50
|
+
export { type ConnectParams, DEFAULT_GATEWAY_REQUEST_TIMEOUT_MS, DEFAULT_PREAUTH_HANDSHAKE_TIMEOUT_MS, type ErrorShape, type EventFrame, GATEWAY_SERVER_CAPS, GatewayBrowserDeviceAuthLifecycle, GatewayBrowserDeviceAuthPlan, GatewayBrowserDeviceIdentity, GatewayBrowserDeviceTokenRecord, GatewayBrowserDeviceTokenStore, GatewayConnectAuthSelection, GatewayProtocolClient, type GatewayProtocolCloseContext, type GatewayProtocolConnectAuthority, GatewayProtocolRequestError, type GatewayProtocolRequestOptions, GatewayProtocolRequestTimeoutError, type GatewayProtocolRequestTiming, type GatewayProtocolSocket, type GatewayProtocolSocketHandlers, type GatewayProtocolTiming, GatewaySessionMessageRequestClient, GatewaySessionMessageSubscription, GatewaySessionMessageSubscriptionCoordinator, GatewaySessionMessageSubscriptionCoordinatorOptions, GatewaySessionMessageSubscriptionOptions, type HelloOk, type SessionMessageEnvelope, type SessionMessageIdentity, type SessionProjectionEntry, SessionProjectionEvent, type SessionProjectionGatewayRunEvent, SessionProjectionRun, SessionProjectionRunStatus, type SessionProjectionRunTransition, SessionProjectionScope, SessionProjectionSnapshotOptions, SessionProjectionState, buildDeviceAuthPayload, buildDeviceAuthPayloadV3, buildGatewayConnectAuth, createSessionProjection, gatewayCredentialScope, gatewayOriginScope, getGatewaySessionMessageSubscriptionCoordinator, hasSessionProjectionAcceptedFinal, isGatewayProtocolResponseError, isLocallyOptimisticSessionMessage, isSessionProjectionErrorMessage, mergeChatStreamMessage, normalizeDeviceMetadataForAuth, normalizeSessionProjectionRunId, projectLiveSessionMessage, projectSessionTerminalReplyMessage, readAssistantStreamSegmentIdentity, readSessionMessageIdentity, readSessionMessageSequence, readSessionProjectionFinalMessageIdentity, reconcileSessionProjectionSnapshot, reduceSessionProjection, reduceSessionProjectionRunEvent, releaseGatewaySessionMessageSubscription, resetGatewaySessionMessageSubscriptionCoordinator, resolveGatewayConnectScopes, resolveSafeTimeoutDelayMs, selectGatewayConnectAuth, shouldRetryGatewayWithDeviceToken };
|
package/dist/browser.mjs
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { A as selectGatewayConnectAuth, C as isGatewayProtocolResponseError, D as GatewayBrowserDeviceAuthLifecycle, E as gatewayOriginScope,
|
|
1
|
+
import { A as selectGatewayConnectAuth, C as isGatewayProtocolResponseError, D as GatewayBrowserDeviceAuthLifecycle, E as gatewayOriginScope, I as buildDeviceAuthPayload, L as buildDeviceAuthPayloadV3, M as mergeChatStreamMessage, N as asNullableRecord, O as buildGatewayConnectAuth, R as normalizeDeviceMetadataForAuth, S as GatewayProtocolRequestTimeoutError, T as gatewayCredentialScope, _ as readSessionMessageIdentity, a as createSessionProjection, b as GatewayProtocolClient, c as reduceSessionProjection, d as readSessionProjectionFinalMessageIdentity, f as isSessionProjectionErrorMessage, g as readAssistantStreamSegmentIdentity, h as normalizeSessionProjectionRunId, i as resetGatewaySessionMessageSubscriptionCoordinator, j as shouldRetryGatewayWithDeviceToken, k as resolveGatewayConnectScopes, l as reduceSessionProjectionRunEvent, m as isLocallyOptimisticSessionMessage, n as getGatewaySessionMessageSubscriptionCoordinator, o as projectLiveSessionMessage, p as projectSessionTerminalReplyMessage, r as releaseGatewaySessionMessageSubscription, s as reconcileSessionProjectionSnapshot, t as GatewaySessionMessageSubscriptionCoordinator, u as hasSessionProjectionAcceptedFinal, v as readSessionMessageSequence, w as resolveModelCatalogConnect, x as GatewayProtocolRequestError, y as shouldPauseGatewayReconnect } from "./session-subscriptions-LtlX9oRQ.mjs";
|
|
2
2
|
import { DEFAULT_GATEWAY_REQUEST_TIMEOUT_MS, DEFAULT_PREAUTH_HANDSHAKE_TIMEOUT_MS, resolveSafeTimeoutDelayMs } from "./timeouts.mjs";
|
|
3
3
|
import { GATEWAY_SERVER_CAPS } from "@openclaw/gateway-protocol/frame-guards";
|
|
4
4
|
export * from "@openclaw/gateway-protocol/connect-error-details";
|
|
@@ -6,4 +6,53 @@ export * from "@openclaw/gateway-protocol/gateway-error-details";
|
|
|
6
6
|
export * from "@openclaw/gateway-protocol/client-info";
|
|
7
7
|
export * from "@openclaw/gateway-protocol/startup-unavailable";
|
|
8
8
|
export * from "@openclaw/gateway-protocol/version";
|
|
9
|
-
|
|
9
|
+
//#region packages/gateway-client/src/chat-stream-projection.ts
|
|
10
|
+
/** Connection-owned chat baselines, independent of the selected local view. */
|
|
11
|
+
var GatewayChatStreamProjection = class {
|
|
12
|
+
constructor() {
|
|
13
|
+
this.runs = /* @__PURE__ */ new Map();
|
|
14
|
+
}
|
|
15
|
+
project(event) {
|
|
16
|
+
if (event.event !== "chat") return {
|
|
17
|
+
event,
|
|
18
|
+
missingBaseline: false
|
|
19
|
+
};
|
|
20
|
+
const payload = asNullableRecord(event.payload);
|
|
21
|
+
if (!payload || typeof payload.runId !== "string" || typeof payload.sessionKey !== "string") return {
|
|
22
|
+
event,
|
|
23
|
+
missingBaseline: false
|
|
24
|
+
};
|
|
25
|
+
if (payload.state === "delta") {
|
|
26
|
+
const previous = this.runs.get(payload.runId);
|
|
27
|
+
const message = mergeChatStreamMessage(previous?.sessionKey === payload.sessionKey && previous.agentId === payload.agentId ? previous.message : void 0, payload);
|
|
28
|
+
if (message !== void 0) this.runs.set(payload.runId, {
|
|
29
|
+
sessionKey: payload.sessionKey,
|
|
30
|
+
agentId: payload.agentId,
|
|
31
|
+
message
|
|
32
|
+
});
|
|
33
|
+
return {
|
|
34
|
+
event: {
|
|
35
|
+
...event,
|
|
36
|
+
payload: {
|
|
37
|
+
...payload,
|
|
38
|
+
message
|
|
39
|
+
}
|
|
40
|
+
},
|
|
41
|
+
missingBaseline: message === void 0
|
|
42
|
+
};
|
|
43
|
+
}
|
|
44
|
+
if (payload.state === "final" || payload.state === "error" || payload.state === "aborted") this.runs.delete(payload.runId);
|
|
45
|
+
return {
|
|
46
|
+
event,
|
|
47
|
+
missingBaseline: false
|
|
48
|
+
};
|
|
49
|
+
}
|
|
50
|
+
retire(isRetired) {
|
|
51
|
+
for (const [runId, scope] of this.runs) if (isRetired(scope)) this.runs.delete(runId);
|
|
52
|
+
}
|
|
53
|
+
clear() {
|
|
54
|
+
this.runs.clear();
|
|
55
|
+
}
|
|
56
|
+
};
|
|
57
|
+
//#endregion
|
|
58
|
+
export { DEFAULT_GATEWAY_REQUEST_TIMEOUT_MS, DEFAULT_PREAUTH_HANDSHAKE_TIMEOUT_MS, GATEWAY_SERVER_CAPS, GatewayBrowserDeviceAuthLifecycle, GatewayChatStreamProjection, GatewayProtocolClient, GatewayProtocolRequestError, GatewayProtocolRequestTimeoutError, GatewaySessionMessageSubscriptionCoordinator, buildDeviceAuthPayload, buildDeviceAuthPayloadV3, buildGatewayConnectAuth, createSessionProjection, gatewayCredentialScope, gatewayOriginScope, getGatewaySessionMessageSubscriptionCoordinator, hasSessionProjectionAcceptedFinal, isGatewayProtocolResponseError, isLocallyOptimisticSessionMessage, isSessionProjectionErrorMessage, mergeChatStreamMessage, normalizeDeviceMetadataForAuth, normalizeSessionProjectionRunId, projectLiveSessionMessage, projectSessionTerminalReplyMessage, readAssistantStreamSegmentIdentity, readSessionMessageIdentity, readSessionMessageSequence, readSessionProjectionFinalMessageIdentity, reconcileSessionProjectionSnapshot, reduceSessionProjection, reduceSessionProjectionRunEvent, releaseGatewaySessionMessageSubscription, resetGatewaySessionMessageSubscriptionCoordinator, resolveGatewayConnectScopes, resolveModelCatalogConnect, resolveSafeTimeoutDelayMs, selectGatewayConnectAuth, shouldPauseGatewayReconnect, shouldRetryGatewayWithDeviceToken };
|
package/dist/index.d.mts
CHANGED
|
@@ -1,9 +1,27 @@
|
|
|
1
|
-
import { A as
|
|
1
|
+
import { A as normalizeSessionProjectionRunId, C as reduceSessionProjectionRunEvent, D as SessionMessageIdentity, E as SessionMessageEnvelope, F as gatewayOriginScope, I as mergeChatStreamMessage, L as buildDeviceAuthPayload, M as readSessionMessageIdentity, N as readSessionMessageSequence, O as SessionProjectionEntry, P as gatewayCredentialScope, R as buildDeviceAuthPayloadV3, S as SessionProjectionRunTransition, T as readSessionProjectionFinalMessageIdentity, _ as reconcileSessionProjectionSnapshot, a as GatewaySessionMessageSubscriptionOptions, b as projectSessionTerminalReplyMessage, c as resetGatewaySessionMessageSubscriptionCoordinator, d as SessionProjectionRunStatus, f as SessionProjectionScope, g as projectLiveSessionMessage, h as createSessionProjection, i as GatewaySessionMessageSubscriptionCoordinatorOptions, j as readAssistantStreamSegmentIdentity, k as isLocallyOptimisticSessionMessage, l as SessionProjectionEvent, m as SessionProjectionState, n as GatewaySessionMessageSubscription, o as getGatewaySessionMessageSubscriptionCoordinator, p as SessionProjectionSnapshotOptions, r as GatewaySessionMessageSubscriptionCoordinator, s as releaseGatewaySessionMessageSubscription, t as GatewaySessionMessageRequestClient, u as SessionProjectionRun, v as reduceSessionProjection, w as hasSessionProjectionAcceptedFinal, x as SessionProjectionGatewayRunEvent, y as isSessionProjectionErrorMessage, z as normalizeDeviceMetadataForAuth } from "./session-subscriptions-Bcq6_wtR.mjs";
|
|
2
2
|
import { a as GatewayBrowserDeviceTokenStore, c as resolveGatewayConnectScopes, i as GatewayBrowserDeviceTokenRecord, l as selectGatewayConnectAuth, n as GatewayBrowserDeviceAuthPlan, o as GatewayConnectAuthSelection, r as GatewayBrowserDeviceIdentity, s as buildGatewayConnectAuth, t as GatewayBrowserDeviceAuthLifecycle, u as shouldRetryGatewayWithDeviceToken } from "./browser-device-auth-DoPo-sPB.mjs";
|
|
3
|
-
import { i as isGatewayProtocolResponseError } from "./protocol-request-
|
|
3
|
+
import { i as isGatewayProtocolResponseError } from "./protocol-request-CtVhe3Bj.mjs";
|
|
4
|
+
import { n as GatewayClientCloseInfo, r as GatewayClientConnectionMetadata } from "./protocol-client-DT451Msj.mjs";
|
|
4
5
|
import { 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 } from "./timeouts.mjs";
|
|
5
|
-
import { _ as
|
|
6
|
+
import { _ as isGatewayConnectAssemblyError, a as startGatewayClientWithReadinessWait, c as waitForEventLoopReady, d as GatewayClientHostDeps, f as GatewayClientOptions, g as GatewayClientRequestError, h as GatewayReconnectPausedInfo, i as startGatewayClientWhenEventLoopReady, l as DeviceIdentity, m as GatewayClientRequestTimeoutError, n as GatewayClientStartReadinessOptions, o as EventLoopReadyOptions, p as GatewayClientRequestOptions, r as GatewayClientStartable, s as EventLoopReadyResult, t as EventLoopReadyWaiter, u as GatewayClient, v as DeviceAuthTokenRecord } from "./readiness-Cj5C24o2.mjs";
|
|
6
7
|
import { GatewayScopeUpgrade, ScopeUpgradeBinding, ScopeUpgradeOptions, ScopeUpgradeOutcome } from "./scope-upgrade.mjs";
|
|
8
|
+
//#region packages/gateway-client/src/run-recovery-text.d.ts
|
|
9
|
+
export type RecoveryRequest = (method: string, params: Record<string, unknown>, signal: AbortSignal) => Promise<unknown>;
|
|
10
|
+
export declare function recoverTerminalReply(params: {
|
|
11
|
+
runId: string;
|
|
12
|
+
scope: {
|
|
13
|
+
sessionKey?: string;
|
|
14
|
+
agentId?: string;
|
|
15
|
+
sessionId?: string;
|
|
16
|
+
};
|
|
17
|
+
result: unknown;
|
|
18
|
+
request: RecoveryRequest;
|
|
19
|
+
signal: AbortSignal;
|
|
20
|
+
}): Promise<{
|
|
21
|
+
outputText?: string;
|
|
22
|
+
unavailable?: string;
|
|
23
|
+
}>;
|
|
24
|
+
//#endregion
|
|
7
25
|
//#region packages/gateway-client/src/cloudflare-access.d.ts
|
|
8
26
|
export declare const CF_ACCESS_CLIENT_ID_HEADER = "CF-Access-Client-Id";
|
|
9
27
|
export declare const CF_ACCESS_CLIENT_SECRET_HEADER = "CF-Access-Client-Secret";
|
|
@@ -14,4 +32,4 @@ export type CloudflareAccessCredentials = Readonly<{
|
|
|
14
32
|
/** Build only the two headers Cloudflare Access defines for service-token auth. */
|
|
15
33
|
export declare function buildCloudflareAccessHeaders(credentials: CloudflareAccessCredentials): Record<string, string>;
|
|
16
34
|
//#endregion
|
|
17
|
-
export { DEFAULT_GATEWAY_REQUEST_TIMEOUT_MS, DEFAULT_PREAUTH_HANDSHAKE_TIMEOUT_MS, type DeviceAuthTokenRecord, DeviceIdentity, EventLoopReadyOptions, EventLoopReadyResult, EventLoopReadyWaiter, GatewayBrowserDeviceAuthLifecycle, GatewayBrowserDeviceAuthPlan, GatewayBrowserDeviceIdentity, GatewayBrowserDeviceTokenRecord, GatewayBrowserDeviceTokenStore, GatewayClient, GatewayClientCloseInfo, GatewayClientConnectionMetadata, GatewayClientHostDeps, GatewayClientOptions, GatewayClientRequestError, GatewayClientRequestOptions, GatewayClientRequestTimeoutError, GatewayClientStartReadinessOptions, GatewayClientStartable, GatewayConnectAuthSelection, GatewayReconnectPausedInfo, GatewayScopeUpgrade, GatewaySessionMessageRequestClient, GatewaySessionMessageSubscription, GatewaySessionMessageSubscriptionCoordinator, GatewaySessionMessageSubscriptionCoordinatorOptions, GatewaySessionMessageSubscriptionOptions, MAX_CONNECT_CHALLENGE_TIMEOUT_MS, MAX_SAFE_TIMEOUT_DELAY_MS, MIN_CONNECT_CHALLENGE_TIMEOUT_MS, ScopeUpgradeBinding, ScopeUpgradeOptions, ScopeUpgradeOutcome, type SessionMessageEnvelope, type SessionMessageIdentity, type SessionProjectionEntry, SessionProjectionEvent, type SessionProjectionGatewayRunEvent, SessionProjectionRun, SessionProjectionRunStatus, type SessionProjectionRunTransition, SessionProjectionScope, SessionProjectionSnapshotOptions, SessionProjectionState, addSafeTimeoutDelayGraceMs, buildDeviceAuthPayload, buildDeviceAuthPayloadV3, buildGatewayConnectAuth, clampConnectChallengeTimeoutMs, clearGatewayConnectTimeout, createSessionProjection, gatewayCredentialScope, gatewayOriginScope, getConnectChallengeTimeoutMsFromEnv, getGatewaySessionMessageSubscriptionCoordinator, hasSessionProjectionAcceptedFinal, isGatewayConnectAssemblyError, isGatewayProtocolResponseError, isLocallyOptimisticSessionMessage, isSessionProjectionErrorMessage, normalizeDeviceMetadataForAuth, normalizeSessionProjectionRunId, projectLiveSessionMessage, readAssistantStreamSegmentIdentity, readSessionMessageIdentity, readSessionMessageSequence, readSessionProjectionFinalMessageIdentity, reconcileSessionProjectionSnapshot, reduceSessionProjection, reduceSessionProjectionRunEvent, releaseGatewaySessionMessageSubscription, resetGatewaySessionMessageSubscriptionCoordinator, resolveConnectChallengeTimeoutMs, resolveFiniteTimeoutDelayMs, resolveGatewayConnectScopes, resolvePreauthHandshakeTimeoutMs, resolveSafeTimeoutDelayMs, selectGatewayConnectAuth, shouldRetryGatewayWithDeviceToken, startGatewayClientWhenEventLoopReady, startGatewayClientWithReadinessWait, startGatewayConnectTimeout, waitForEventLoopReady };
|
|
35
|
+
export { DEFAULT_GATEWAY_REQUEST_TIMEOUT_MS, DEFAULT_PREAUTH_HANDSHAKE_TIMEOUT_MS, type DeviceAuthTokenRecord, DeviceIdentity, EventLoopReadyOptions, EventLoopReadyResult, EventLoopReadyWaiter, GatewayBrowserDeviceAuthLifecycle, GatewayBrowserDeviceAuthPlan, GatewayBrowserDeviceIdentity, GatewayBrowserDeviceTokenRecord, GatewayBrowserDeviceTokenStore, GatewayClient, type GatewayClientCloseInfo, type GatewayClientConnectionMetadata, GatewayClientHostDeps, GatewayClientOptions, GatewayClientRequestError, GatewayClientRequestOptions, GatewayClientRequestTimeoutError, GatewayClientStartReadinessOptions, GatewayClientStartable, GatewayConnectAuthSelection, GatewayReconnectPausedInfo, GatewayScopeUpgrade, GatewaySessionMessageRequestClient, GatewaySessionMessageSubscription, GatewaySessionMessageSubscriptionCoordinator, GatewaySessionMessageSubscriptionCoordinatorOptions, GatewaySessionMessageSubscriptionOptions, MAX_CONNECT_CHALLENGE_TIMEOUT_MS, MAX_SAFE_TIMEOUT_DELAY_MS, MIN_CONNECT_CHALLENGE_TIMEOUT_MS, ScopeUpgradeBinding, ScopeUpgradeOptions, ScopeUpgradeOutcome, type SessionMessageEnvelope, type SessionMessageIdentity, type SessionProjectionEntry, SessionProjectionEvent, type SessionProjectionGatewayRunEvent, SessionProjectionRun, SessionProjectionRunStatus, type SessionProjectionRunTransition, SessionProjectionScope, SessionProjectionSnapshotOptions, SessionProjectionState, addSafeTimeoutDelayGraceMs, buildDeviceAuthPayload, buildDeviceAuthPayloadV3, buildGatewayConnectAuth, clampConnectChallengeTimeoutMs, clearGatewayConnectTimeout, createSessionProjection, gatewayCredentialScope, gatewayOriginScope, getConnectChallengeTimeoutMsFromEnv, getGatewaySessionMessageSubscriptionCoordinator, hasSessionProjectionAcceptedFinal, isGatewayConnectAssemblyError, isGatewayProtocolResponseError, isLocallyOptimisticSessionMessage, isSessionProjectionErrorMessage, mergeChatStreamMessage, normalizeDeviceMetadataForAuth, normalizeSessionProjectionRunId, projectLiveSessionMessage, projectSessionTerminalReplyMessage, readAssistantStreamSegmentIdentity, readSessionMessageIdentity, readSessionMessageSequence, readSessionProjectionFinalMessageIdentity, reconcileSessionProjectionSnapshot, reduceSessionProjection, reduceSessionProjectionRunEvent, releaseGatewaySessionMessageSubscription, resetGatewaySessionMessageSubscriptionCoordinator, resolveConnectChallengeTimeoutMs, resolveFiniteTimeoutDelayMs, resolveGatewayConnectScopes, resolvePreauthHandshakeTimeoutMs, resolveSafeTimeoutDelayMs, selectGatewayConnectAuth, shouldRetryGatewayWithDeviceToken, startGatewayClientWhenEventLoopReady, startGatewayClientWithReadinessWait, startGatewayConnectTimeout, waitForEventLoopReady };
|
package/dist/index.mjs
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { A as selectGatewayConnectAuth, C as isGatewayProtocolResponseError, D as GatewayBrowserDeviceAuthLifecycle, E as gatewayOriginScope,
|
|
1
|
+
import { A as selectGatewayConnectAuth, C as isGatewayProtocolResponseError, D as GatewayBrowserDeviceAuthLifecycle, E as gatewayOriginScope, F as isRecord, I as buildDeviceAuthPayload, L as buildDeviceAuthPayloadV3, M as mergeChatStreamMessage, O as buildGatewayConnectAuth, P as asRecord, R as normalizeDeviceMetadataForAuth, S as GatewayProtocolRequestTimeoutError, T as gatewayCredentialScope, _ as readSessionMessageIdentity, a as createSessionProjection, b as GatewayProtocolClient, c as reduceSessionProjection, d as readSessionProjectionFinalMessageIdentity, f as isSessionProjectionErrorMessage, g as readAssistantStreamSegmentIdentity, h as normalizeSessionProjectionRunId, i as resetGatewaySessionMessageSubscriptionCoordinator, j as shouldRetryGatewayWithDeviceToken, k as resolveGatewayConnectScopes, l as reduceSessionProjectionRunEvent, m as isLocallyOptimisticSessionMessage, n as getGatewaySessionMessageSubscriptionCoordinator, o as projectLiveSessionMessage, p as projectSessionTerminalReplyMessage, r as releaseGatewaySessionMessageSubscription, s as reconcileSessionProjectionSnapshot, t as GatewaySessionMessageSubscriptionCoordinator, u as hasSessionProjectionAcceptedFinal, v as readSessionMessageSequence, w as resolveModelCatalogConnect, x as GatewayProtocolRequestError, y as shouldPauseGatewayReconnect } from "./session-subscriptions-LtlX9oRQ.mjs";
|
|
2
2
|
import { 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 } from "./timeouts.mjs";
|
|
3
3
|
import { rawDataToString } from "./websocket-data.mjs";
|
|
4
4
|
import { n as startGatewayClientWithReadinessWait, r as waitForEventLoopReady, t as startGatewayClientWhenEventLoopReady } from "./readiness-CrWxd4TI.mjs";
|
|
@@ -10,7 +10,8 @@ import { resolveGatewayStartupRetryAfterMs } from "@openclaw/gateway-protocol/st
|
|
|
10
10
|
import { MIN_CLIENT_PROTOCOL_VERSION, MIN_NODE_PROTOCOL_VERSION, MIN_PROBE_PROTOCOL_VERSION, PROTOCOL_VERSION } from "@openclaw/gateway-protocol/version";
|
|
11
11
|
import { randomUUID } from "node:crypto";
|
|
12
12
|
import ipaddr from "ipaddr.js";
|
|
13
|
-
import {
|
|
13
|
+
import { isIP } from "node:net";
|
|
14
|
+
import { TLSSocket, checkServerIdentity } from "node:tls";
|
|
14
15
|
import path from "node:path";
|
|
15
16
|
//#region packages/normalization-core/src/string-coerce.ts
|
|
16
17
|
/** Trims string input and returns null for non-strings or empty strings. */
|
|
@@ -82,10 +83,7 @@ function normalizeUrlQueryParamName(name) {
|
|
|
82
83
|
try {
|
|
83
84
|
decoded = decodeURIComponent(current).replace(URL_QUERY_NAME_SEPARATOR_RE, "");
|
|
84
85
|
} catch {
|
|
85
|
-
|
|
86
|
-
value: normalizeLowercaseStringOrEmpty(current).replaceAll("-", "_"),
|
|
87
|
-
unresolvedEncoding: current.includes("%")
|
|
88
|
-
};
|
|
86
|
+
break;
|
|
89
87
|
}
|
|
90
88
|
if (decoded === current) return {
|
|
91
89
|
value: normalizeLowercaseStringOrEmpty(current).replaceAll("-", "_"),
|
|
@@ -159,9 +157,7 @@ function redactQueryString(value, depth) {
|
|
|
159
157
|
redactedEntries.push([redactedKey, redactedValue]);
|
|
160
158
|
}
|
|
161
159
|
if (!mutated) return value;
|
|
162
|
-
|
|
163
|
-
for (const [key, entryValue] of redactedEntries) redactedParams.append(key, entryValue);
|
|
164
|
-
return redactedParams.toString();
|
|
160
|
+
return new URLSearchParams(redactedEntries).toString();
|
|
165
161
|
}
|
|
166
162
|
function redactUrlLikeFallback(value) {
|
|
167
163
|
return redactSensitiveUrlPath(redactEmbeddedUrlUserInfo(value).replace(/([?&])([^=&]+)=([^&]*)/g, (match, prefix, key) => isSensitiveUrlQueryParamName$1(key) ? `${prefix}${key}=***` : match));
|
|
@@ -172,14 +168,14 @@ function redactAuthorityUserInfo(candidate, authorityStart) {
|
|
|
172
168
|
if (userInfoEnd < 0) return candidate;
|
|
173
169
|
return `${candidate.slice(0, authorityStart)}***:***@${authority.slice(userInfoEnd + 1)}`;
|
|
174
170
|
}
|
|
171
|
+
function skipAuthoritySeparators(candidate, start) {
|
|
172
|
+
let cursor = start;
|
|
173
|
+
while (candidate[cursor] === "/" || candidate[cursor] === "\\") cursor += 1;
|
|
174
|
+
return cursor;
|
|
175
|
+
}
|
|
175
176
|
function redactEmbeddedUrlUserInfo(value) {
|
|
176
|
-
return value.replace(SPECIAL_SCHEME_AUTHORITY_RE, (candidate) => {
|
|
177
|
-
|
|
178
|
-
while (authorityStart < candidate.length && (candidate[authorityStart] === "/" || candidate[authorityStart] === "\\")) authorityStart += 1;
|
|
179
|
-
return redactAuthorityUserInfo(candidate, authorityStart);
|
|
180
|
-
}).replace(SPECIAL_SCHEME_SPILLED_USERINFO_RE, (candidate) => {
|
|
181
|
-
let authorityStart = candidate.indexOf(":") + 1;
|
|
182
|
-
while (authorityStart < candidate.length && (candidate[authorityStart] === "/" || candidate[authorityStart] === "\\")) authorityStart += 1;
|
|
177
|
+
return value.replace(SPECIAL_SCHEME_AUTHORITY_RE, (candidate) => redactAuthorityUserInfo(candidate, skipAuthoritySeparators(candidate, candidate.indexOf(":") + 1))).replace(SPECIAL_SCHEME_SPILLED_USERINFO_RE, (candidate) => {
|
|
178
|
+
const authorityStart = skipAuthoritySeparators(candidate, candidate.indexOf(":") + 1);
|
|
183
179
|
const userInfoEnd = candidate.lastIndexOf("@");
|
|
184
180
|
const firstReservedDelimiter = candidate.slice(authorityStart).search(/[\\/?#]/u);
|
|
185
181
|
if (userInfoEnd < 0 || firstReservedDelimiter < 0) return candidate;
|
|
@@ -191,11 +187,7 @@ function redactEmbeddedUrlUserInfo(value) {
|
|
|
191
187
|
const possiblePort = candidate.slice(credentialSeparator + 1, absoluteReservedDelimiter);
|
|
192
188
|
if (/^\d+$/u.test(possiblePort) || /^\[[^\]]+\](?::\d+)?$/u.test(authorityPrefix)) return candidate;
|
|
193
189
|
return `${candidate.slice(0, authorityStart)}***:***@${candidate.slice(userInfoEnd + 1)}`;
|
|
194
|
-
}).replace(PROTOCOL_RELATIVE_AUTHORITY_RE, (candidate) =>
|
|
195
|
-
let authorityStart = 0;
|
|
196
|
-
while (authorityStart < candidate.length && (candidate[authorityStart] === "/" || candidate[authorityStart] === "\\")) authorityStart += 1;
|
|
197
|
-
return redactAuthorityUserInfo(candidate, authorityStart);
|
|
198
|
-
});
|
|
190
|
+
}).replace(PROTOCOL_RELATIVE_AUTHORITY_RE, (candidate) => redactAuthorityUserInfo(candidate, skipAuthoritySeparators(candidate, 0)));
|
|
199
191
|
}
|
|
200
192
|
function hasUnresolvedEmbeddedUrlUserInfo(value) {
|
|
201
193
|
for (const match of value.matchAll(/(?:\b(?:https?|wss?|ftp):[\\/]{0,2}|[\\/]{2,})/giu)) {
|
|
@@ -219,16 +211,15 @@ function redactFragment(value, depth) {
|
|
|
219
211
|
if (depth > MAX_NESTED_URL_REDACTION_DEPTH && looksLikeNestedUrlValue(value)) return "***";
|
|
220
212
|
const wholeUrl = redactSensitiveUrlAtDepth(value, depth);
|
|
221
213
|
if (wholeUrl.parsedWholeUrl) return redactUrlLikeFallback(wholeUrl.value);
|
|
222
|
-
const
|
|
223
|
-
const
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
const hashRouterQueryIndex = candidate.indexOf("?");
|
|
214
|
+
const firstQueryDelimiter = value.search(/[?&]/u);
|
|
215
|
+
const firstEquals = value.indexOf("=");
|
|
216
|
+
if (firstEquals >= 0 && (firstQueryDelimiter < 0 || firstEquals < firstQueryDelimiter)) return redactQueryString(value, depth);
|
|
217
|
+
const hashRouterQueryIndex = value.indexOf("?");
|
|
227
218
|
if (hashRouterQueryIndex >= 0) {
|
|
228
|
-
const redactedQuery = redactQueryString(
|
|
229
|
-
return `${redactEncodedUrlLikeString(redactUrlLikeFallback(
|
|
219
|
+
const redactedQuery = redactQueryString(value.slice(hashRouterQueryIndex + 1), depth);
|
|
220
|
+
return `${redactEncodedUrlLikeString(redactUrlLikeFallback(value.slice(0, hashRouterQueryIndex + 1)), depth + 1)}${redactedQuery}`;
|
|
230
221
|
}
|
|
231
|
-
const fallback = redactUrlLikeFallback(
|
|
222
|
+
const fallback = redactUrlLikeFallback(value);
|
|
232
223
|
if (!looksLikeNestedUrlValue(fallback)) return fallback;
|
|
233
224
|
let decoded;
|
|
234
225
|
try {
|
|
@@ -350,9 +341,7 @@ function isIpv6Address(address) {
|
|
|
350
341
|
return address.kind() === "ipv6";
|
|
351
342
|
}
|
|
352
343
|
function normalizeIpv4MappedAddress(address) {
|
|
353
|
-
|
|
354
|
-
if (!address.isIPv4MappedAddress()) return address;
|
|
355
|
-
return address.toIPv4Address();
|
|
344
|
+
return isIpv6Address(address) && address.isIPv4MappedAddress() ? address.toIPv4Address() : address;
|
|
356
345
|
}
|
|
357
346
|
function normalizeIpParseInput(raw) {
|
|
358
347
|
const trimmed = normalizeOptionalString(raw);
|
|
@@ -629,6 +618,11 @@ function resolveGatewayWebSocketTransport(params) {
|
|
|
629
618
|
const expectedFingerprint = params.tlsFingerprint ? normalizeTlsFingerprint(params.tlsFingerprint) : void 0;
|
|
630
619
|
if (params.tlsFingerprint && !expectedFingerprint) throw new GatewayWebSocketTransportConfigurationError("gateway tls fingerprint must be a SHA-256 fingerprint");
|
|
631
620
|
const options = { ...params.options };
|
|
621
|
+
if (usesTls && params.tlsServerName) {
|
|
622
|
+
const peerName = params.tlsServerName;
|
|
623
|
+
options.servername = isIP(peerName) ? "" : peerName;
|
|
624
|
+
options.checkServerIdentity = (_hostname, certificate) => checkServerIdentity(peerName, certificate);
|
|
625
|
+
}
|
|
632
626
|
if (usesTls && expectedFingerprint) applyGatewayWebSocketTlsPin(options, expectedFingerprint, normalize);
|
|
633
627
|
return { options };
|
|
634
628
|
}
|
|
@@ -812,6 +806,7 @@ var GatewayClient = class {
|
|
|
812
806
|
onParseError: (error) => this.logDebug(`gateway client parse error: ${formatGatewayClientErrorForLog(error)}`),
|
|
813
807
|
onEvent: (event) => this.opts.onEvent?.(event),
|
|
814
808
|
onGap: (info) => this.opts.onGap?.(info),
|
|
809
|
+
onRequestTiming: (timing) => this.opts.onRequestTiming?.(timing),
|
|
815
810
|
onActivity: () => {
|
|
816
811
|
this.lastTick = Date.now();
|
|
817
812
|
},
|
|
@@ -870,6 +865,7 @@ var GatewayClient = class {
|
|
|
870
865
|
const transport = resolveGatewayWebSocketTransport({
|
|
871
866
|
url,
|
|
872
867
|
tlsFingerprint: this.opts.tlsFingerprint,
|
|
868
|
+
tlsServerName: this.opts.tlsServerName,
|
|
873
869
|
env: this.opts.env,
|
|
874
870
|
normalizeTlsFingerprint: this.deps.normalizeTlsFingerprint,
|
|
875
871
|
options: {
|
|
@@ -1105,15 +1101,10 @@ var GatewayClient = class {
|
|
|
1105
1101
|
if (this.opts.role !== "node" || this.opts.mode !== GATEWAY_CLIENT_MODES.NODE || this.opts.clientName !== GATEWAY_CLIENT_NAMES.NODE_HOST) return false;
|
|
1106
1102
|
return (this.opts.minProtocol ?? MIN_NODE_PROTOCOL_VERSION) === MIN_NODE_PROTOCOL_VERSION && (this.opts.maxProtocol ?? PROTOCOL_VERSION) === PROTOCOL_VERSION;
|
|
1107
1103
|
}
|
|
1108
|
-
|
|
1109
|
-
if (
|
|
1110
|
-
const detailCode = readConnectErrorDetailCode(error.details);
|
|
1111
|
-
return error.details?.expectedProtocol === MIN_NODE_PROTOCOL_VERSION && (detailCode === ConnectErrorDetailCodes.PROTOCOL_MISMATCH || normalizeGatewayErrorText(error.message).includes("protocol mismatch"));
|
|
1112
|
-
}
|
|
1113
|
-
shouldRetryWithCurrentNodeProtocol(error) {
|
|
1114
|
-
if (!this.useLegacyNodeProtocolEnvelope || !this.shouldNegotiateLegacyNodeProtocol() || !(error instanceof GatewayClientRequestError)) return false;
|
|
1104
|
+
shouldRetryWithAlternateNodeProtocol(error) {
|
|
1105
|
+
if (!this.shouldNegotiateLegacyNodeProtocol() || !(error instanceof GatewayClientRequestError)) return false;
|
|
1115
1106
|
const detailCode = readConnectErrorDetailCode(error.details);
|
|
1116
|
-
return error.details?.expectedProtocol === PROTOCOL_VERSION && (detailCode === ConnectErrorDetailCodes.PROTOCOL_MISMATCH || normalizeGatewayErrorText(error.message).includes("protocol mismatch"));
|
|
1107
|
+
return error.details?.expectedProtocol === (this.useLegacyNodeProtocolEnvelope ? PROTOCOL_VERSION : MIN_NODE_PROTOCOL_VERSION) && (detailCode === ConnectErrorDetailCodes.PROTOCOL_MISMATCH || normalizeGatewayErrorText(error.message).includes("protocol mismatch"));
|
|
1117
1108
|
}
|
|
1118
1109
|
buildDeviceConnectParams(params) {
|
|
1119
1110
|
if (!this.opts.deviceIdentity) return;
|
|
@@ -1207,23 +1198,12 @@ var GatewayClient = class {
|
|
|
1207
1198
|
return cleared instanceof Promise ? cleared.then(() => decision) : decision;
|
|
1208
1199
|
}
|
|
1209
1200
|
resolveConnectRequestFailure(error, assembled) {
|
|
1210
|
-
if (this.
|
|
1211
|
-
const resetBackoff = !this.nodeProtocolTransitionPending;
|
|
1212
|
-
this.useLegacyNodeProtocolEnvelope = false;
|
|
1213
|
-
this.nodeProtocolTransitionPending = true;
|
|
1214
|
-
if (resetBackoff) this.protocol.resetReconnectBackoff(250);
|
|
1215
|
-
this.logDebug("gateway rejected protocol v3; retrying node host with protocol v4");
|
|
1216
|
-
return {
|
|
1217
|
-
closeCode: 1008,
|
|
1218
|
-
closeReason: "connect retry"
|
|
1219
|
-
};
|
|
1220
|
-
}
|
|
1221
|
-
if (this.shouldRetryWithLegacyNodeProtocol(error)) {
|
|
1201
|
+
if (this.shouldRetryWithAlternateNodeProtocol(error)) {
|
|
1222
1202
|
const resetBackoff = !this.nodeProtocolTransitionPending;
|
|
1223
|
-
this.useLegacyNodeProtocolEnvelope =
|
|
1203
|
+
this.useLegacyNodeProtocolEnvelope = !this.useLegacyNodeProtocolEnvelope;
|
|
1224
1204
|
this.nodeProtocolTransitionPending = true;
|
|
1225
1205
|
if (resetBackoff) this.protocol.resetReconnectBackoff(250);
|
|
1226
|
-
this.logDebug("gateway rejected protocol v4; retrying node host with protocol v3");
|
|
1206
|
+
this.logDebug(this.useLegacyNodeProtocolEnvelope ? "gateway rejected protocol v4; retrying node host with protocol v3" : "gateway rejected protocol v3; retrying node host with protocol v4");
|
|
1227
1207
|
return {
|
|
1228
1208
|
closeCode: 1008,
|
|
1229
1209
|
closeReason: "connect retry"
|
|
@@ -1252,10 +1232,7 @@ var GatewayClient = class {
|
|
|
1252
1232
|
reconnectDelayMs: startupRetryAfterMs
|
|
1253
1233
|
};
|
|
1254
1234
|
}
|
|
1255
|
-
if (this.
|
|
1256
|
-
error,
|
|
1257
|
-
authAgentRuntimeIdentityToken: assembled.authAgentRuntimeIdentityToken
|
|
1258
|
-
})) {
|
|
1235
|
+
if (assembled.authAgentRuntimeIdentityToken && this.isUnsupportedConnectAuthField(error, "agentruntimeidentitytoken")) {
|
|
1259
1236
|
const unsupportedIdentityError = /* @__PURE__ */ new Error("gateway rejected required agent runtime identity auth field; refusing to retry without it");
|
|
1260
1237
|
this.stopped = true;
|
|
1261
1238
|
this.notifyConnectError(unsupportedIdentityError);
|
|
@@ -1266,10 +1243,7 @@ var GatewayClient = class {
|
|
|
1266
1243
|
stop: true
|
|
1267
1244
|
};
|
|
1268
1245
|
}
|
|
1269
|
-
if (this.
|
|
1270
|
-
error,
|
|
1271
|
-
authApprovalRuntimeToken: assembled.authApprovalRuntimeToken
|
|
1272
|
-
})) {
|
|
1246
|
+
if (!this.approvalRuntimeTokenRetryBudgetUsed && assembled.authApprovalRuntimeToken && this.isUnsupportedConnectAuthField(error, "approvalruntimetoken")) {
|
|
1273
1247
|
this.approvalRuntimeTokenCompatibilityDisabled = true;
|
|
1274
1248
|
this.approvalRuntimeTokenRetryBudgetUsed = true;
|
|
1275
1249
|
this.protocol.resetReconnectBackoff(250);
|
|
@@ -1386,20 +1360,10 @@ var GatewayClient = class {
|
|
|
1386
1360
|
this.logDebug(`gateway client reconnect paused handler error: ${formatGatewayClientErrorForLog(err)}`);
|
|
1387
1361
|
}
|
|
1388
1362
|
}
|
|
1389
|
-
|
|
1390
|
-
if (
|
|
1391
|
-
|
|
1392
|
-
|
|
1393
|
-
if (params.error.gatewayCode !== "INVALID_REQUEST") return false;
|
|
1394
|
-
const message = normalizeGatewayErrorText(params.error.message);
|
|
1395
|
-
return message.includes("invalid connect params") && message.includes("approvalruntimetoken");
|
|
1396
|
-
}
|
|
1397
|
-
shouldFailClosedForUnsupportedAgentRuntimeIdentity(params) {
|
|
1398
|
-
if (!params.authAgentRuntimeIdentityToken) return false;
|
|
1399
|
-
if (!(params.error instanceof GatewayClientRequestError)) return false;
|
|
1400
|
-
if (params.error.gatewayCode !== "INVALID_REQUEST") return false;
|
|
1401
|
-
const message = normalizeGatewayErrorText(params.error.message);
|
|
1402
|
-
return message.includes("invalid connect params") && message.includes("agentruntimeidentitytoken");
|
|
1363
|
+
isUnsupportedConnectAuthField(error, field) {
|
|
1364
|
+
if (!(error instanceof GatewayClientRequestError) || error.gatewayCode !== "INVALID_REQUEST") return false;
|
|
1365
|
+
const message = normalizeGatewayErrorText(error.message);
|
|
1366
|
+
return message.includes("invalid connect params") && message.includes(field);
|
|
1403
1367
|
}
|
|
1404
1368
|
isTrustedDeviceRetryEndpoint() {
|
|
1405
1369
|
const rawUrl = this.opts.url ?? "ws://127.0.0.1:18789";
|
|
@@ -1459,6 +1423,89 @@ function createGatewayRequestAbortError(method) {
|
|
|
1459
1423
|
return err;
|
|
1460
1424
|
}
|
|
1461
1425
|
//#endregion
|
|
1426
|
+
//#region packages/gateway-client/src/run-recovery-text.ts
|
|
1427
|
+
async function recoverTerminalReply(params) {
|
|
1428
|
+
const { runId, scope, request, signal } = params;
|
|
1429
|
+
const result = asRecord(params.result);
|
|
1430
|
+
const disposition = asRecord(result.terminalReply).disposition;
|
|
1431
|
+
if (disposition === "silent" || disposition === "empty") return { outputText: "" };
|
|
1432
|
+
if (!scope.sessionKey) return { unavailable: "session-unavailable" };
|
|
1433
|
+
const receipt = asRecord(result.terminalReceipt);
|
|
1434
|
+
if (receipt.runId !== void 0 && receipt.runId !== runId) return { unavailable: "terminal-receipt-mismatch" };
|
|
1435
|
+
const expectedSessionId = typeof receipt.sessionId === "string" ? receipt.sessionId : scope.sessionId;
|
|
1436
|
+
const idempotencyKey = typeof receipt.assistantTranscriptIdempotencyKey === "string" ? receipt.assistantTranscriptIdempotencyKey : void 0;
|
|
1437
|
+
const matches = (message) => {
|
|
1438
|
+
const metadata = asRecord(message["__openclaw"]);
|
|
1439
|
+
return message.role === "assistant" && asRecord(message.openclawStreamFallback).source !== "segment" && (metadata.runId === runId || idempotencyKey !== void 0 && metadata.idempotencyKey === idempotencyKey);
|
|
1440
|
+
};
|
|
1441
|
+
const target = {
|
|
1442
|
+
sessionKey: scope.sessionKey,
|
|
1443
|
+
...scope.agentId ? { agentId: scope.agentId } : {}
|
|
1444
|
+
};
|
|
1445
|
+
let offset;
|
|
1446
|
+
let sessionId = expectedSessionId;
|
|
1447
|
+
const pages = [];
|
|
1448
|
+
let complete = false;
|
|
1449
|
+
try {
|
|
1450
|
+
for (let pageIndex = 0; pageIndex < 10; pageIndex += 1) {
|
|
1451
|
+
signal.throwIfAborted();
|
|
1452
|
+
const page = asRecord(await request("chat.history", {
|
|
1453
|
+
...target,
|
|
1454
|
+
limit: 200,
|
|
1455
|
+
...offset !== void 0 ? { offset } : {}
|
|
1456
|
+
}, signal));
|
|
1457
|
+
if (sessionId !== void 0 && page.sessionId !== sessionId) return { unavailable: "session-changed" };
|
|
1458
|
+
if (typeof page.sessionId === "string") sessionId = page.sessionId;
|
|
1459
|
+
const messages = Array.isArray(page.messages) ? page.messages.map(asRecord) : [];
|
|
1460
|
+
pages.unshift(messages.filter(matches));
|
|
1461
|
+
if (page.hasMore !== true) {
|
|
1462
|
+
complete = true;
|
|
1463
|
+
break;
|
|
1464
|
+
}
|
|
1465
|
+
if (typeof page.nextOffset !== "number" || !Number.isSafeInteger(page.nextOffset) || page.nextOffset <= (offset ?? 0)) break;
|
|
1466
|
+
offset = page.nextOffset;
|
|
1467
|
+
}
|
|
1468
|
+
if (!complete) return { unavailable: "history-limit-reached" };
|
|
1469
|
+
const messages = pages.flat();
|
|
1470
|
+
if (messages.length === 0 || idempotencyKey !== void 0 && !messages.some((message) => asRecord(message["__openclaw"]).idempotencyKey === idempotencyKey)) return { unavailable: "reply-not-found" };
|
|
1471
|
+
let outputText = "";
|
|
1472
|
+
const seen = /* @__PURE__ */ new Set();
|
|
1473
|
+
for (let message of messages) {
|
|
1474
|
+
signal.throwIfAborted();
|
|
1475
|
+
const metadata = asRecord(message["__openclaw"]);
|
|
1476
|
+
if (typeof metadata.id === "string") {
|
|
1477
|
+
if (seen.has(metadata.id)) continue;
|
|
1478
|
+
seen.add(metadata.id);
|
|
1479
|
+
}
|
|
1480
|
+
if (metadata.truncated === true) {
|
|
1481
|
+
if (typeof metadata.id !== "string") return { unavailable: "message-identity-unavailable" };
|
|
1482
|
+
const full = asRecord(await request("chat.message.get", {
|
|
1483
|
+
...target,
|
|
1484
|
+
messageId: metadata.id
|
|
1485
|
+
}, signal));
|
|
1486
|
+
message = asRecord(full.message);
|
|
1487
|
+
if (full.ok !== true || asRecord(message["__openclaw"]).id !== metadata.id || !matches(message) || asRecord(message["__openclaw"]).truncated === true) return { unavailable: "full-message-unavailable" };
|
|
1488
|
+
}
|
|
1489
|
+
const content = typeof message.text === "string" ? message.text : message.content;
|
|
1490
|
+
if (typeof content !== "string" && !Array.isArray(content)) return { unavailable: "reply-text-unavailable" };
|
|
1491
|
+
const text = typeof content === "string" ? content : content.flatMap((block) => {
|
|
1492
|
+
const part = asRecord(block);
|
|
1493
|
+
return (part.type === "text" || part.type === "input_text" || part.type === "output_text") && typeof part.text === "string" ? [part.text] : [];
|
|
1494
|
+
}).join("\n");
|
|
1495
|
+
if (outputText && text) {
|
|
1496
|
+
const trailing = outputText.endsWith("\n\n") ? 2 : outputText.endsWith("\n") ? 1 : 0;
|
|
1497
|
+
const leading = text.startsWith("\n\n") ? 2 : text.startsWith("\n") ? 1 : 0;
|
|
1498
|
+
outputText += "\n".repeat(Math.max(0, 2 - trailing - leading));
|
|
1499
|
+
}
|
|
1500
|
+
outputText += text;
|
|
1501
|
+
}
|
|
1502
|
+
return { outputText };
|
|
1503
|
+
} catch {
|
|
1504
|
+
signal.throwIfAborted();
|
|
1505
|
+
return { unavailable: "history-request-failed" };
|
|
1506
|
+
}
|
|
1507
|
+
}
|
|
1508
|
+
//#endregion
|
|
1462
1509
|
//#region packages/gateway-client/src/cloudflare-access.ts
|
|
1463
1510
|
const CF_ACCESS_CLIENT_ID_HEADER = "CF-Access-Client-Id";
|
|
1464
1511
|
const CF_ACCESS_CLIENT_SECRET_HEADER = "CF-Access-Client-Secret";
|
|
@@ -1470,4 +1517,4 @@ function buildCloudflareAccessHeaders(credentials) {
|
|
|
1470
1517
|
};
|
|
1471
1518
|
}
|
|
1472
1519
|
//#endregion
|
|
1473
|
-
export { CF_ACCESS_CLIENT_ID_HEADER, CF_ACCESS_CLIENT_SECRET_HEADER, DEFAULT_GATEWAY_REQUEST_TIMEOUT_MS, DEFAULT_PREAUTH_HANDSHAKE_TIMEOUT_MS, GatewayBrowserDeviceAuthLifecycle, GatewayClient, GatewayClientRequestError, GatewayClientRequestTimeoutError, GatewayScopeUpgrade, GatewaySessionMessageSubscriptionCoordinator, MAX_CONNECT_CHALLENGE_TIMEOUT_MS, MAX_SAFE_TIMEOUT_DELAY_MS, MIN_CONNECT_CHALLENGE_TIMEOUT_MS, addSafeTimeoutDelayGraceMs, buildCloudflareAccessHeaders, buildDeviceAuthPayload, buildDeviceAuthPayloadV3, buildGatewayConnectAuth, clampConnectChallengeTimeoutMs, clearGatewayConnectTimeout, createSessionProjection, gatewayCredentialScope, gatewayOriginScope, getConnectChallengeTimeoutMsFromEnv, getGatewaySessionMessageSubscriptionCoordinator, hasSessionProjectionAcceptedFinal, isGatewayConnectAssemblyError, isGatewayProtocolResponseError, isLocallyOptimisticSessionMessage, isSessionProjectionErrorMessage, normalizeDeviceMetadataForAuth, normalizeSessionProjectionRunId, projectLiveSessionMessage, readAssistantStreamSegmentIdentity, readSessionMessageIdentity, readSessionMessageSequence, readSessionProjectionFinalMessageIdentity, reconcileSessionProjectionSnapshot, reduceSessionProjection, reduceSessionProjectionRunEvent, releaseGatewaySessionMessageSubscription, resetGatewaySessionMessageSubscriptionCoordinator, resolveConnectChallengeTimeoutMs, resolveFiniteTimeoutDelayMs, resolveGatewayConnectScopes, resolvePreauthHandshakeTimeoutMs, resolveSafeTimeoutDelayMs, selectGatewayConnectAuth, shouldRetryGatewayWithDeviceToken, startGatewayClientWhenEventLoopReady, startGatewayClientWithReadinessWait, startGatewayConnectTimeout, waitForEventLoopReady };
|
|
1520
|
+
export { CF_ACCESS_CLIENT_ID_HEADER, CF_ACCESS_CLIENT_SECRET_HEADER, DEFAULT_GATEWAY_REQUEST_TIMEOUT_MS, DEFAULT_PREAUTH_HANDSHAKE_TIMEOUT_MS, GatewayBrowserDeviceAuthLifecycle, GatewayClient, GatewayClientRequestError, GatewayClientRequestTimeoutError, GatewayScopeUpgrade, GatewaySessionMessageSubscriptionCoordinator, MAX_CONNECT_CHALLENGE_TIMEOUT_MS, MAX_SAFE_TIMEOUT_DELAY_MS, MIN_CONNECT_CHALLENGE_TIMEOUT_MS, addSafeTimeoutDelayGraceMs, buildCloudflareAccessHeaders, buildDeviceAuthPayload, buildDeviceAuthPayloadV3, buildGatewayConnectAuth, clampConnectChallengeTimeoutMs, clearGatewayConnectTimeout, createSessionProjection, gatewayCredentialScope, gatewayOriginScope, getConnectChallengeTimeoutMsFromEnv, getGatewaySessionMessageSubscriptionCoordinator, hasSessionProjectionAcceptedFinal, isGatewayConnectAssemblyError, isGatewayProtocolResponseError, isLocallyOptimisticSessionMessage, isSessionProjectionErrorMessage, mergeChatStreamMessage, normalizeDeviceMetadataForAuth, normalizeSessionProjectionRunId, projectLiveSessionMessage, projectSessionTerminalReplyMessage, readAssistantStreamSegmentIdentity, readSessionMessageIdentity, readSessionMessageSequence, readSessionProjectionFinalMessageIdentity, reconcileSessionProjectionSnapshot, recoverTerminalReply, reduceSessionProjection, reduceSessionProjectionRunEvent, releaseGatewaySessionMessageSubscription, resetGatewaySessionMessageSubscriptionCoordinator, resolveConnectChallengeTimeoutMs, resolveFiniteTimeoutDelayMs, resolveGatewayConnectScopes, resolvePreauthHandshakeTimeoutMs, resolveSafeTimeoutDelayMs, selectGatewayConnectAuth, shouldRetryGatewayWithDeviceToken, startGatewayClientWhenEventLoopReady, startGatewayClientWithReadinessWait, startGatewayConnectTimeout, waitForEventLoopReady };
|