@buildautomaton/cli 0.1.9 → 0.1.11
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/dist/cli.js +233 -103
- package/dist/cli.js.map +4 -4
- package/dist/index.js +234 -104
- package/dist/index.js.map +4 -4
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -2236,7 +2236,7 @@ var require_websocket = __commonJS({
|
|
|
2236
2236
|
"../../node_modules/.pnpm/ws@8.19.0/node_modules/ws/lib/websocket.js"(exports, module) {
|
|
2237
2237
|
"use strict";
|
|
2238
2238
|
var EventEmitter2 = __require("events");
|
|
2239
|
-
var
|
|
2239
|
+
var https2 = __require("https");
|
|
2240
2240
|
var http = __require("http");
|
|
2241
2241
|
var net = __require("net");
|
|
2242
2242
|
var tls = __require("tls");
|
|
@@ -2771,7 +2771,7 @@ var require_websocket = __commonJS({
|
|
|
2771
2771
|
}
|
|
2772
2772
|
const defaultPort = isSecure ? 443 : 80;
|
|
2773
2773
|
const key = randomBytes(16).toString("base64");
|
|
2774
|
-
const request = isSecure ?
|
|
2774
|
+
const request = isSecure ? https2.request : http.request;
|
|
2775
2775
|
const protocolSet = /* @__PURE__ */ new Set();
|
|
2776
2776
|
let perMessageDeflate;
|
|
2777
2777
|
opts.createConnection = opts.createConnection || (isSecure ? tlsConnect : netConnect);
|
|
@@ -22050,9 +22050,6 @@ var require_dist2 = __commonJS({
|
|
|
22050
22050
|
}
|
|
22051
22051
|
});
|
|
22052
22052
|
|
|
22053
|
-
// src/bridge/connection/create-ws-bridge.ts
|
|
22054
|
-
import https from "node:https";
|
|
22055
|
-
|
|
22056
22053
|
// ../../node_modules/.pnpm/ws@8.19.0/node_modules/ws/wrapper.mjs
|
|
22057
22054
|
var import_stream = __toESM(require_stream(), 1);
|
|
22058
22055
|
var import_receiver = __toESM(require_receiver(), 1);
|
|
@@ -22073,26 +22070,77 @@ function applyCliOutboundNetworkPreferences() {
|
|
|
22073
22070
|
}
|
|
22074
22071
|
}
|
|
22075
22072
|
|
|
22073
|
+
// src/bridge/connection/cli-ws-client.ts
|
|
22074
|
+
import https from "node:https";
|
|
22075
|
+
var CLI_WEBSOCKET_CLIENT_PING_MS = 25e3;
|
|
22076
|
+
function attachWebSocketClientPing(ws, intervalMs) {
|
|
22077
|
+
let timer = null;
|
|
22078
|
+
function clear() {
|
|
22079
|
+
if (timer != null) {
|
|
22080
|
+
clearInterval(timer);
|
|
22081
|
+
timer = null;
|
|
22082
|
+
}
|
|
22083
|
+
}
|
|
22084
|
+
clear();
|
|
22085
|
+
timer = setInterval(() => {
|
|
22086
|
+
if (ws.readyState === wrapper_default.OPEN) {
|
|
22087
|
+
try {
|
|
22088
|
+
ws.ping();
|
|
22089
|
+
} catch {
|
|
22090
|
+
}
|
|
22091
|
+
}
|
|
22092
|
+
}, intervalMs);
|
|
22093
|
+
return clear;
|
|
22094
|
+
}
|
|
22095
|
+
function buildCliWebSocketClientOptions(wsUrl) {
|
|
22096
|
+
const wsOptions = { perMessageDeflate: false, family: 4 };
|
|
22097
|
+
if (wsUrl.startsWith("wss://")) {
|
|
22098
|
+
wsOptions.agent = new https.Agent({ rejectUnauthorized: false, family: 4 });
|
|
22099
|
+
}
|
|
22100
|
+
return wsOptions;
|
|
22101
|
+
}
|
|
22102
|
+
function logCliWebSocketError(log2, serviceLabel, err, detail) {
|
|
22103
|
+
const mid = detail ? ` ${detail}` : "";
|
|
22104
|
+
log2(`${serviceLabel} WebSocket error${mid}: ${err.message}`);
|
|
22105
|
+
}
|
|
22106
|
+
function safeCloseWebSocket(ws) {
|
|
22107
|
+
try {
|
|
22108
|
+
if (ws.readyState === wrapper_default.CLOSED) {
|
|
22109
|
+
ws.removeAllListeners();
|
|
22110
|
+
return;
|
|
22111
|
+
}
|
|
22112
|
+
ws.once("close", () => {
|
|
22113
|
+
ws.removeAllListeners();
|
|
22114
|
+
});
|
|
22115
|
+
ws.close();
|
|
22116
|
+
} catch {
|
|
22117
|
+
try {
|
|
22118
|
+
ws.removeAllListeners();
|
|
22119
|
+
} catch {
|
|
22120
|
+
}
|
|
22121
|
+
}
|
|
22122
|
+
}
|
|
22123
|
+
function safeSendWebSocketBinary(ws, data) {
|
|
22124
|
+
if (ws.readyState !== wrapper_default.OPEN) return false;
|
|
22125
|
+
try {
|
|
22126
|
+
ws.send(data, { binary: true });
|
|
22127
|
+
return true;
|
|
22128
|
+
} catch {
|
|
22129
|
+
return false;
|
|
22130
|
+
}
|
|
22131
|
+
}
|
|
22132
|
+
|
|
22076
22133
|
// src/bridge/connection/create-ws-bridge.ts
|
|
22077
22134
|
var BRIDGE_AUTH_ERROR_HEADER = "x-bridge-auth-error";
|
|
22078
22135
|
var BRIDGE_AUTH_ERROR_TOKEN_INVALID = "token_invalid";
|
|
22079
22136
|
function createWsBridge(options) {
|
|
22080
22137
|
const { url: url2, onMessage, onOpen, onClose, onError: onError2, onAuthInvalid, clientPingIntervalMs } = options;
|
|
22081
22138
|
applyCliOutboundNetworkPreferences();
|
|
22082
|
-
const
|
|
22083
|
-
|
|
22084
|
-
|
|
22085
|
-
|
|
22086
|
-
|
|
22087
|
-
wsOptions.agent = new https.Agent({ rejectUnauthorized: false, family: 4 });
|
|
22088
|
-
}
|
|
22089
|
-
const ws = new wrapper_default(url2, wsOptions);
|
|
22090
|
-
let clientPingTimer = null;
|
|
22091
|
-
function clearClientPing() {
|
|
22092
|
-
if (clientPingTimer != null) {
|
|
22093
|
-
clearInterval(clientPingTimer);
|
|
22094
|
-
clientPingTimer = null;
|
|
22095
|
-
}
|
|
22139
|
+
const ws = new wrapper_default(url2, buildCliWebSocketClientOptions(url2));
|
|
22140
|
+
let clearClientPing = null;
|
|
22141
|
+
function disposeClientPing() {
|
|
22142
|
+
clearClientPing?.();
|
|
22143
|
+
clearClientPing = null;
|
|
22096
22144
|
}
|
|
22097
22145
|
ws.on("unexpected-response", (request, response) => {
|
|
22098
22146
|
const status = response?.statusCode ?? 0;
|
|
@@ -22103,16 +22151,9 @@ function createWsBridge(options) {
|
|
|
22103
22151
|
}
|
|
22104
22152
|
});
|
|
22105
22153
|
ws.on("open", () => {
|
|
22106
|
-
|
|
22154
|
+
disposeClientPing();
|
|
22107
22155
|
if (clientPingIntervalMs != null && clientPingIntervalMs > 0) {
|
|
22108
|
-
|
|
22109
|
-
if (ws.readyState === wrapper_default.OPEN) {
|
|
22110
|
-
try {
|
|
22111
|
-
ws.ping();
|
|
22112
|
-
} catch {
|
|
22113
|
-
}
|
|
22114
|
-
}
|
|
22115
|
-
}, clientPingIntervalMs);
|
|
22156
|
+
clearClientPing = attachWebSocketClientPing(ws, clientPingIntervalMs);
|
|
22116
22157
|
}
|
|
22117
22158
|
onOpen?.();
|
|
22118
22159
|
});
|
|
@@ -22133,11 +22174,11 @@ function createWsBridge(options) {
|
|
|
22133
22174
|
}
|
|
22134
22175
|
});
|
|
22135
22176
|
ws.on("close", (code, reason) => {
|
|
22136
|
-
|
|
22177
|
+
disposeClientPing();
|
|
22137
22178
|
onClose?.(code, reason.toString());
|
|
22138
22179
|
});
|
|
22139
22180
|
ws.on("error", (err) => {
|
|
22140
|
-
|
|
22181
|
+
disposeClientPing();
|
|
22141
22182
|
onError2?.(err);
|
|
22142
22183
|
});
|
|
22143
22184
|
return ws;
|
|
@@ -22823,12 +22864,64 @@ async function createSdkStdioAcpClient(options) {
|
|
|
22823
22864
|
});
|
|
22824
22865
|
}
|
|
22825
22866
|
|
|
22867
|
+
// src/net/transient-local-fetch-retry.ts
|
|
22868
|
+
var LOCAL_PREVIEW_FETCH_RETRY_DELAYS_MS = [30, 100, 200, 400];
|
|
22869
|
+
function sleepMs(ms) {
|
|
22870
|
+
return new Promise((r) => setTimeout(r, ms));
|
|
22871
|
+
}
|
|
22872
|
+
function collectErrorText(err) {
|
|
22873
|
+
const parts = [];
|
|
22874
|
+
let e = err;
|
|
22875
|
+
for (let depth = 0; depth < 6 && e != null; depth += 1) {
|
|
22876
|
+
if (e instanceof Error) {
|
|
22877
|
+
parts.push(e.message);
|
|
22878
|
+
e = e.cause;
|
|
22879
|
+
} else {
|
|
22880
|
+
parts.push(String(e));
|
|
22881
|
+
break;
|
|
22882
|
+
}
|
|
22883
|
+
}
|
|
22884
|
+
return parts.join(" ").toLowerCase();
|
|
22885
|
+
}
|
|
22886
|
+
function isTransientLocalServiceError(err) {
|
|
22887
|
+
const text = collectErrorText(err);
|
|
22888
|
+
if (!text) return false;
|
|
22889
|
+
return text.includes("fetch failed") || text.includes("econnrefused") || text.includes("econnreset") || text.includes("epipe") || text.includes("etimedout") || text.includes("socket hang up") || text.includes("network connection lost") || text.includes("ecanceled") || text.includes("aborted") || text.includes("und_err_socket") || text.includes("other side closed") || text.includes("eai_again");
|
|
22890
|
+
}
|
|
22891
|
+
function isIdempotentHttpMethod(method) {
|
|
22892
|
+
const m = method.toUpperCase();
|
|
22893
|
+
return m === "GET" || m === "HEAD" || m === "OPTIONS";
|
|
22894
|
+
}
|
|
22895
|
+
async function fetchWithLocalTransientRetries(url2, init, options) {
|
|
22896
|
+
const method = (init?.method ?? "GET").toUpperCase();
|
|
22897
|
+
const allowRetry = isIdempotentHttpMethod(method);
|
|
22898
|
+
const delays = options?.delaysMs ?? LOCAL_PREVIEW_FETCH_RETRY_DELAYS_MS;
|
|
22899
|
+
const maxAttempts = options?.maxAttempts ?? (allowRetry ? Math.max(1, delays.length + 1) : 1);
|
|
22900
|
+
let lastErr;
|
|
22901
|
+
for (let attempt = 0; attempt < maxAttempts; attempt += 1) {
|
|
22902
|
+
try {
|
|
22903
|
+
return await fetch(url2, init);
|
|
22904
|
+
} catch (e) {
|
|
22905
|
+
lastErr = e;
|
|
22906
|
+
const canRetry = allowRetry && attempt < maxAttempts - 1 && isTransientLocalServiceError(e);
|
|
22907
|
+
if (!canRetry) throw e;
|
|
22908
|
+
const waitMs = delays[Math.min(attempt, delays.length - 1)] ?? 100;
|
|
22909
|
+
await sleepMs(waitMs);
|
|
22910
|
+
}
|
|
22911
|
+
}
|
|
22912
|
+
throw lastErr instanceof Error ? lastErr : new Error(String(lastErr));
|
|
22913
|
+
}
|
|
22914
|
+
|
|
22826
22915
|
// src/firehose/proxy/local-proxy.ts
|
|
22827
22916
|
var ALLOWED_HOSTS = ["localhost", "127.0.0.1", "::1"];
|
|
22828
22917
|
function isAllowedHost(host) {
|
|
22829
22918
|
const h = host.replace(/^\[|\]$/g, "");
|
|
22830
22919
|
return ALLOWED_HOSTS.includes(host) || ALLOWED_HOSTS.includes(h);
|
|
22831
22920
|
}
|
|
22921
|
+
function isIdempotentProxyMethod(method) {
|
|
22922
|
+
const m = method.toUpperCase();
|
|
22923
|
+
return m === "GET" || m === "HEAD" || m === "OPTIONS";
|
|
22924
|
+
}
|
|
22832
22925
|
function checkUrlAndHost(request) {
|
|
22833
22926
|
let url2;
|
|
22834
22927
|
try {
|
|
@@ -22856,38 +22949,47 @@ async function proxyToLocal(request) {
|
|
|
22856
22949
|
path: url2.pathname + url2.search,
|
|
22857
22950
|
headers: request.headers
|
|
22858
22951
|
};
|
|
22859
|
-
|
|
22860
|
-
|
|
22861
|
-
|
|
22862
|
-
|
|
22863
|
-
|
|
22864
|
-
|
|
22865
|
-
|
|
22866
|
-
|
|
22867
|
-
|
|
22868
|
-
|
|
22869
|
-
|
|
22952
|
+
const maxAttempts = isIdempotentProxyMethod(request.method) ? LOCAL_PREVIEW_FETCH_RETRY_DELAYS_MS.length + 1 : 1;
|
|
22953
|
+
for (let attempt = 0; attempt < maxAttempts; attempt += 1) {
|
|
22954
|
+
const once = await new Promise((resolve14) => {
|
|
22955
|
+
const req = mod.request(opts, (res) => {
|
|
22956
|
+
const chunks = [];
|
|
22957
|
+
res.on("data", (c) => chunks.push(c));
|
|
22958
|
+
res.on("end", () => {
|
|
22959
|
+
const body = Buffer.concat(chunks).toString("utf8");
|
|
22960
|
+
const headers = {};
|
|
22961
|
+
for (const [k, v] of Object.entries(res.headers)) {
|
|
22962
|
+
if (typeof v === "string") headers[k] = v;
|
|
22963
|
+
else if (Array.isArray(v) && v[0]) headers[k] = v[0];
|
|
22964
|
+
}
|
|
22965
|
+
resolve14({
|
|
22966
|
+
id: request.id,
|
|
22967
|
+
statusCode: res.statusCode ?? 0,
|
|
22968
|
+
headers,
|
|
22969
|
+
body
|
|
22970
|
+
});
|
|
22971
|
+
});
|
|
22972
|
+
});
|
|
22973
|
+
req.on("error", (err) => {
|
|
22870
22974
|
resolve14({
|
|
22871
22975
|
id: request.id,
|
|
22872
|
-
statusCode:
|
|
22873
|
-
headers,
|
|
22874
|
-
body
|
|
22976
|
+
statusCode: 0,
|
|
22977
|
+
headers: {},
|
|
22978
|
+
body: "",
|
|
22979
|
+
error: err.message
|
|
22875
22980
|
});
|
|
22876
22981
|
});
|
|
22982
|
+
const method = request.method.toUpperCase();
|
|
22983
|
+
if (request.body && method !== "GET" && method !== "HEAD") req.write(request.body);
|
|
22984
|
+
req.end();
|
|
22877
22985
|
});
|
|
22878
|
-
|
|
22879
|
-
|
|
22880
|
-
|
|
22881
|
-
|
|
22882
|
-
|
|
22883
|
-
|
|
22884
|
-
|
|
22885
|
-
});
|
|
22886
|
-
});
|
|
22887
|
-
const method = request.method.toUpperCase();
|
|
22888
|
-
if (request.body && method !== "GET" && method !== "HEAD") req.write(request.body);
|
|
22889
|
-
req.end();
|
|
22890
|
-
});
|
|
22986
|
+
const errMsg = once.error ?? "";
|
|
22987
|
+
const canRetry = attempt < maxAttempts - 1 && errMsg !== "" && isTransientLocalServiceError(new Error(errMsg));
|
|
22988
|
+
if (!canRetry) return once;
|
|
22989
|
+
const waitMs = LOCAL_PREVIEW_FETCH_RETRY_DELAYS_MS[Math.min(attempt, LOCAL_PREVIEW_FETCH_RETRY_DELAYS_MS.length - 1)] ?? 100;
|
|
22990
|
+
await sleepMs(waitMs);
|
|
22991
|
+
}
|
|
22992
|
+
throw new Error("Local proxy retry loop exited unexpectedly");
|
|
22891
22993
|
}
|
|
22892
22994
|
async function proxyToLocalStreaming(request, callbacks) {
|
|
22893
22995
|
const checked = checkUrlAndHost(request);
|
|
@@ -22904,7 +23006,7 @@ async function proxyToLocalStreaming(request, callbacks) {
|
|
|
22904
23006
|
if (request.body !== void 0 && request.body !== null && method !== "GET" && method !== "HEAD") {
|
|
22905
23007
|
init.body = request.body;
|
|
22906
23008
|
}
|
|
22907
|
-
const res = await
|
|
23009
|
+
const res = await fetchWithLocalTransientRetries(request.url, init);
|
|
22908
23010
|
const headers = {};
|
|
22909
23011
|
res.headers.forEach((value, key) => {
|
|
22910
23012
|
headers[key] = value;
|
|
@@ -23437,9 +23539,9 @@ function runPendingAuth(options) {
|
|
|
23437
23539
|
keepaliveInterval = null;
|
|
23438
23540
|
}
|
|
23439
23541
|
if (ws) {
|
|
23440
|
-
ws
|
|
23441
|
-
ws.close();
|
|
23542
|
+
const w = ws;
|
|
23442
23543
|
ws = null;
|
|
23544
|
+
safeCloseWebSocket(w);
|
|
23443
23545
|
}
|
|
23444
23546
|
}
|
|
23445
23547
|
function connect() {
|
|
@@ -23482,7 +23584,7 @@ function runPendingAuth(options) {
|
|
|
23482
23584
|
connect();
|
|
23483
23585
|
}, delay2);
|
|
23484
23586
|
},
|
|
23485
|
-
onError: (err) => logFn
|
|
23587
|
+
onError: (err) => logCliWebSocketError(logFn, "[Bridge service]", err, "while waiting for sign-in"),
|
|
23486
23588
|
onMessage: (data) => {
|
|
23487
23589
|
const msg = data;
|
|
23488
23590
|
if (msg.type === "auth_token" && typeof msg.token === "string") {
|
|
@@ -30037,14 +30139,50 @@ async function removeSessionWorktrees(paths, log2) {
|
|
|
30037
30139
|
}
|
|
30038
30140
|
|
|
30039
30141
|
// src/git/working-tree-status.ts
|
|
30040
|
-
async function
|
|
30041
|
-
|
|
30142
|
+
async function tryConfigGet(g, key) {
|
|
30143
|
+
try {
|
|
30144
|
+
const out = await g.raw(["config", "--get", key]);
|
|
30145
|
+
const v = String(out).trim();
|
|
30146
|
+
return v || null;
|
|
30147
|
+
} catch {
|
|
30148
|
+
return null;
|
|
30149
|
+
}
|
|
30150
|
+
}
|
|
30151
|
+
async function resolveRemoteTrackingRefForAhead(g) {
|
|
30042
30152
|
try {
|
|
30043
30153
|
await g.raw(["rev-parse", "--verify", "@{u}"]);
|
|
30154
|
+
return "@{u}";
|
|
30155
|
+
} catch {
|
|
30156
|
+
}
|
|
30157
|
+
const branch = (await g.raw(["rev-parse", "--abbrev-ref", "HEAD"])).trim();
|
|
30158
|
+
if (!branch || branch === "HEAD") return null;
|
|
30159
|
+
const remote = await tryConfigGet(g, `branch.${branch}.remote`) ?? "origin";
|
|
30160
|
+
const merge2 = await tryConfigGet(g, `branch.${branch}.merge`);
|
|
30161
|
+
if (merge2) {
|
|
30162
|
+
const upstreamBranch = merge2.replace(/^refs\/heads\//, "");
|
|
30163
|
+
const ref = `refs/remotes/${remote}/${upstreamBranch}`;
|
|
30164
|
+
try {
|
|
30165
|
+
await g.raw(["rev-parse", "--verify", ref]);
|
|
30166
|
+
return ref;
|
|
30167
|
+
} catch {
|
|
30168
|
+
}
|
|
30169
|
+
}
|
|
30170
|
+
const fallbackRef = `refs/remotes/${remote}/${branch}`;
|
|
30171
|
+
try {
|
|
30172
|
+
await g.raw(["rev-parse", "--verify", fallbackRef]);
|
|
30173
|
+
return fallbackRef;
|
|
30044
30174
|
} catch {
|
|
30045
|
-
return
|
|
30175
|
+
return null;
|
|
30046
30176
|
}
|
|
30047
|
-
|
|
30177
|
+
}
|
|
30178
|
+
async function commitsAheadOfRemoteTracking(repoDir) {
|
|
30179
|
+
const g = simpleGit(repoDir);
|
|
30180
|
+
const trackingRef = await resolveRemoteTrackingRefForAhead(g);
|
|
30181
|
+
if (!trackingRef) return 0;
|
|
30182
|
+
const localSha = (await g.raw(["rev-parse", "HEAD"])).trim();
|
|
30183
|
+
const remoteSha = (await g.raw(["rev-parse", trackingRef])).trim();
|
|
30184
|
+
if (localSha === remoteSha) return 0;
|
|
30185
|
+
const out = await g.raw(["rev-list", "--count", `${trackingRef}..HEAD`]);
|
|
30048
30186
|
const n = parseInt(String(out).trim(), 10);
|
|
30049
30187
|
return Number.isNaN(n) ? 0 : n;
|
|
30050
30188
|
}
|
|
@@ -30052,7 +30190,7 @@ async function getRepoWorkingTreeStatus(repoDir) {
|
|
|
30052
30190
|
const g = simpleGit(repoDir);
|
|
30053
30191
|
const st = await g.status();
|
|
30054
30192
|
const hasUncommittedChanges = (st.files?.length ?? 0) > 0;
|
|
30055
|
-
const ahead = await
|
|
30193
|
+
const ahead = await commitsAheadOfRemoteTracking(repoDir);
|
|
30056
30194
|
return { hasUncommittedChanges, hasUnpushedCommits: ahead > 0 };
|
|
30057
30195
|
}
|
|
30058
30196
|
async function aggregateSessionPathsWorkingTreeStatus(paths) {
|
|
@@ -30068,7 +30206,7 @@ async function aggregateSessionPathsWorkingTreeStatus(paths) {
|
|
|
30068
30206
|
async function pushAheadOfUpstreamForPaths(paths) {
|
|
30069
30207
|
for (const p of paths) {
|
|
30070
30208
|
const g = simpleGit(p);
|
|
30071
|
-
const ahead = await
|
|
30209
|
+
const ahead = await commitsAheadOfRemoteTracking(p);
|
|
30072
30210
|
if (ahead <= 0) continue;
|
|
30073
30211
|
await g.push();
|
|
30074
30212
|
}
|
|
@@ -31343,13 +31481,13 @@ var DevServerManager = class {
|
|
|
31343
31481
|
}
|
|
31344
31482
|
};
|
|
31345
31483
|
|
|
31346
|
-
// src/firehose/connect-firehose.ts
|
|
31347
|
-
import https2 from "node:https";
|
|
31348
|
-
|
|
31349
31484
|
// src/firehose/proxy/start-streaming-proxy.ts
|
|
31350
31485
|
function startStreamingProxy(ws, log2, pr) {
|
|
31351
31486
|
proxyToLocalStreaming(pr, {
|
|
31352
31487
|
onStart: (statusCode, headers) => {
|
|
31488
|
+
if (ws.readyState !== wrapper_default.OPEN) {
|
|
31489
|
+
throw new Error("Preview stream interrupted (firehose connection closed)");
|
|
31490
|
+
}
|
|
31353
31491
|
const forwardedHeaders = { ...headers };
|
|
31354
31492
|
const ce = "content-encoding";
|
|
31355
31493
|
const cl = "content-length";
|
|
@@ -31362,7 +31500,10 @@ function startStreamingProxy(ws, log2, pr) {
|
|
|
31362
31500
|
},
|
|
31363
31501
|
onChunk: (chunk) => {
|
|
31364
31502
|
const idBuf = Buffer.from(pr.id, "utf8");
|
|
31365
|
-
|
|
31503
|
+
const buf = Buffer.concat([idBuf, Buffer.from(chunk)]);
|
|
31504
|
+
if (!safeSendWebSocketBinary(ws, buf)) {
|
|
31505
|
+
throw new Error("Preview stream interrupted (firehose connection closed)");
|
|
31506
|
+
}
|
|
31366
31507
|
},
|
|
31367
31508
|
onEnd: () => sendWsMessage(ws, { type: "proxy_result_end", id: pr.id }),
|
|
31368
31509
|
onError: (error40) => {
|
|
@@ -31480,22 +31621,15 @@ function tryConsumeBinaryProxyBody(raw, deps) {
|
|
|
31480
31621
|
}
|
|
31481
31622
|
|
|
31482
31623
|
// src/firehose/connect-firehose.ts
|
|
31483
|
-
var FIREHOSE_CLIENT_PING_MS = 25e3;
|
|
31484
31624
|
function connectFirehose(options) {
|
|
31485
31625
|
const { firehoseServerUrl, workspaceId, bridgeName, proxyPorts, log: log2, devServerManager, onOpen, onClose } = options;
|
|
31486
31626
|
const wsUrl = buildFirehoseCliWsUrl(firehoseServerUrl);
|
|
31487
31627
|
applyCliOutboundNetworkPreferences();
|
|
31488
|
-
const
|
|
31489
|
-
|
|
31490
|
-
|
|
31491
|
-
|
|
31492
|
-
|
|
31493
|
-
let clientPingTimer = null;
|
|
31494
|
-
function clearClientPing() {
|
|
31495
|
-
if (clientPingTimer != null) {
|
|
31496
|
-
clearInterval(clientPingTimer);
|
|
31497
|
-
clientPingTimer = null;
|
|
31498
|
-
}
|
|
31628
|
+
const ws = new wrapper_default(wsUrl, buildCliWebSocketClientOptions(wsUrl));
|
|
31629
|
+
let clearClientPing = null;
|
|
31630
|
+
function disposeClientPing() {
|
|
31631
|
+
clearClientPing?.();
|
|
31632
|
+
clearClientPing = null;
|
|
31499
31633
|
}
|
|
31500
31634
|
const firehoseSend = (payload) => {
|
|
31501
31635
|
sendWsMessage(ws, payload);
|
|
@@ -31509,15 +31643,8 @@ function connectFirehose(options) {
|
|
|
31509
31643
|
startStreamingProxy: (pr) => startStreamingProxy(ws, log2, pr)
|
|
31510
31644
|
};
|
|
31511
31645
|
ws.on("open", () => {
|
|
31512
|
-
|
|
31513
|
-
|
|
31514
|
-
if (ws.readyState === wrapper_default.OPEN) {
|
|
31515
|
-
try {
|
|
31516
|
-
ws.ping();
|
|
31517
|
-
} catch {
|
|
31518
|
-
}
|
|
31519
|
-
}
|
|
31520
|
-
}, FIREHOSE_CLIENT_PING_MS);
|
|
31646
|
+
disposeClientPing();
|
|
31647
|
+
clearClientPing = attachWebSocketClientPing(ws, CLI_WEBSOCKET_CLIENT_PING_MS);
|
|
31521
31648
|
onOpen?.();
|
|
31522
31649
|
devServerManager.attachFirehose(firehoseSend);
|
|
31523
31650
|
sendWsMessage(ws, { type: "identify", workspaceId, bridgeName, proxyPorts });
|
|
@@ -31533,24 +31660,23 @@ function connectFirehose(options) {
|
|
|
31533
31660
|
}
|
|
31534
31661
|
});
|
|
31535
31662
|
ws.on("close", (code, reason) => {
|
|
31536
|
-
|
|
31663
|
+
disposeClientPing();
|
|
31537
31664
|
devServerManager.detachFirehose();
|
|
31538
31665
|
const reasonStr = typeof reason === "string" ? reason : reason.toString();
|
|
31539
31666
|
onClose?.(code, reasonStr);
|
|
31540
31667
|
});
|
|
31541
31668
|
ws.on("error", (err) => {
|
|
31542
|
-
|
|
31543
|
-
log2
|
|
31669
|
+
disposeClientPing();
|
|
31670
|
+
logCliWebSocketError(log2, "[Proxy and log service]", err);
|
|
31671
|
+
if (ws.readyState === wrapper_default.CONNECTING || ws.readyState === wrapper_default.OPEN) {
|
|
31672
|
+
safeCloseWebSocket(ws);
|
|
31673
|
+
}
|
|
31544
31674
|
});
|
|
31545
31675
|
return {
|
|
31546
31676
|
close() {
|
|
31547
|
-
|
|
31677
|
+
disposeClientPing();
|
|
31548
31678
|
devServerManager.detachFirehose();
|
|
31549
|
-
|
|
31550
|
-
ws.removeAllListeners();
|
|
31551
|
-
ws.close();
|
|
31552
|
-
} catch {
|
|
31553
|
-
}
|
|
31679
|
+
safeCloseWebSocket(ws);
|
|
31554
31680
|
},
|
|
31555
31681
|
isConnected: () => ws.readyState === wrapper_default.OPEN
|
|
31556
31682
|
};
|
|
@@ -32729,7 +32855,6 @@ async function refreshBridgeTokens(params) {
|
|
|
32729
32855
|
}
|
|
32730
32856
|
|
|
32731
32857
|
// src/bridge/connection/main-bridge-ws-lifecycle.ts
|
|
32732
|
-
var BRIDGE_CLIENT_PING_MS = 25e3;
|
|
32733
32858
|
function createMainBridgeWebSocketLifecycle(params) {
|
|
32734
32859
|
const {
|
|
32735
32860
|
state,
|
|
@@ -32787,6 +32912,11 @@ function createMainBridgeWebSocketLifecycle(params) {
|
|
|
32787
32912
|
const prev = state.currentWs;
|
|
32788
32913
|
if (prev) {
|
|
32789
32914
|
prev.removeAllListeners();
|
|
32915
|
+
prev.once("error", () => {
|
|
32916
|
+
});
|
|
32917
|
+
prev.once("close", () => {
|
|
32918
|
+
prev.removeAllListeners();
|
|
32919
|
+
});
|
|
32790
32920
|
try {
|
|
32791
32921
|
prev.close();
|
|
32792
32922
|
} catch {
|
|
@@ -32796,7 +32926,7 @@ function createMainBridgeWebSocketLifecycle(params) {
|
|
|
32796
32926
|
const url2 = buildBridgeUrl(apiUrl, workspaceId, tokens.accessToken);
|
|
32797
32927
|
state.currentWs = createWsBridge({
|
|
32798
32928
|
url: url2,
|
|
32799
|
-
clientPingIntervalMs:
|
|
32929
|
+
clientPingIntervalMs: CLI_WEBSOCKET_CLIENT_PING_MS,
|
|
32800
32930
|
onAuthInvalid: () => {
|
|
32801
32931
|
if (authRefreshInFlight) return;
|
|
32802
32932
|
void (async () => {
|
|
@@ -32832,7 +32962,7 @@ function createMainBridgeWebSocketLifecycle(params) {
|
|
|
32832
32962
|
},
|
|
32833
32963
|
onOpen: handleOpen,
|
|
32834
32964
|
onClose: handleClose,
|
|
32835
|
-
onError: (err) => logFn
|
|
32965
|
+
onError: (err) => logCliWebSocketError(logFn, "[Bridge service]", err),
|
|
32836
32966
|
onMessage: (data) => handleBridgeMessage(data, messageDeps)
|
|
32837
32967
|
});
|
|
32838
32968
|
}
|