@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/cli.js
CHANGED
|
@@ -5232,7 +5232,7 @@ var require_websocket = __commonJS({
|
|
|
5232
5232
|
"../../node_modules/.pnpm/ws@8.19.0/node_modules/ws/lib/websocket.js"(exports, module) {
|
|
5233
5233
|
"use strict";
|
|
5234
5234
|
var EventEmitter2 = __require("events");
|
|
5235
|
-
var
|
|
5235
|
+
var https2 = __require("https");
|
|
5236
5236
|
var http = __require("http");
|
|
5237
5237
|
var net = __require("net");
|
|
5238
5238
|
var tls = __require("tls");
|
|
@@ -5767,7 +5767,7 @@ var require_websocket = __commonJS({
|
|
|
5767
5767
|
}
|
|
5768
5768
|
const defaultPort = isSecure ? 443 : 80;
|
|
5769
5769
|
const key = randomBytes(16).toString("base64");
|
|
5770
|
-
const request = isSecure ?
|
|
5770
|
+
const request = isSecure ? https2.request : http.request;
|
|
5771
5771
|
const protocolSet = /* @__PURE__ */ new Set();
|
|
5772
5772
|
let perMessageDeflate;
|
|
5773
5773
|
opts.createConnection = opts.createConnection || (isSecure ? tlsConnect : netConnect);
|
|
@@ -25177,9 +25177,6 @@ var import_websocket = __toESM(require_websocket(), 1);
|
|
|
25177
25177
|
var import_websocket_server = __toESM(require_websocket_server(), 1);
|
|
25178
25178
|
var wrapper_default = import_websocket.default;
|
|
25179
25179
|
|
|
25180
|
-
// src/bridge/connection/create-ws-bridge.ts
|
|
25181
|
-
import https from "node:https";
|
|
25182
|
-
|
|
25183
25180
|
// src/net/apply-cli-outbound-network-prefs.ts
|
|
25184
25181
|
import dns from "node:dns";
|
|
25185
25182
|
var applied = false;
|
|
@@ -25192,26 +25189,77 @@ function applyCliOutboundNetworkPreferences() {
|
|
|
25192
25189
|
}
|
|
25193
25190
|
}
|
|
25194
25191
|
|
|
25192
|
+
// src/bridge/connection/cli-ws-client.ts
|
|
25193
|
+
import https from "node:https";
|
|
25194
|
+
var CLI_WEBSOCKET_CLIENT_PING_MS = 25e3;
|
|
25195
|
+
function attachWebSocketClientPing(ws, intervalMs) {
|
|
25196
|
+
let timer = null;
|
|
25197
|
+
function clear() {
|
|
25198
|
+
if (timer != null) {
|
|
25199
|
+
clearInterval(timer);
|
|
25200
|
+
timer = null;
|
|
25201
|
+
}
|
|
25202
|
+
}
|
|
25203
|
+
clear();
|
|
25204
|
+
timer = setInterval(() => {
|
|
25205
|
+
if (ws.readyState === wrapper_default.OPEN) {
|
|
25206
|
+
try {
|
|
25207
|
+
ws.ping();
|
|
25208
|
+
} catch {
|
|
25209
|
+
}
|
|
25210
|
+
}
|
|
25211
|
+
}, intervalMs);
|
|
25212
|
+
return clear;
|
|
25213
|
+
}
|
|
25214
|
+
function buildCliWebSocketClientOptions(wsUrl) {
|
|
25215
|
+
const wsOptions = { perMessageDeflate: false, family: 4 };
|
|
25216
|
+
if (wsUrl.startsWith("wss://")) {
|
|
25217
|
+
wsOptions.agent = new https.Agent({ rejectUnauthorized: false, family: 4 });
|
|
25218
|
+
}
|
|
25219
|
+
return wsOptions;
|
|
25220
|
+
}
|
|
25221
|
+
function logCliWebSocketError(log2, serviceLabel, err, detail) {
|
|
25222
|
+
const mid = detail ? ` ${detail}` : "";
|
|
25223
|
+
log2(`${serviceLabel} WebSocket error${mid}: ${err.message}`);
|
|
25224
|
+
}
|
|
25225
|
+
function safeCloseWebSocket(ws) {
|
|
25226
|
+
try {
|
|
25227
|
+
if (ws.readyState === wrapper_default.CLOSED) {
|
|
25228
|
+
ws.removeAllListeners();
|
|
25229
|
+
return;
|
|
25230
|
+
}
|
|
25231
|
+
ws.once("close", () => {
|
|
25232
|
+
ws.removeAllListeners();
|
|
25233
|
+
});
|
|
25234
|
+
ws.close();
|
|
25235
|
+
} catch {
|
|
25236
|
+
try {
|
|
25237
|
+
ws.removeAllListeners();
|
|
25238
|
+
} catch {
|
|
25239
|
+
}
|
|
25240
|
+
}
|
|
25241
|
+
}
|
|
25242
|
+
function safeSendWebSocketBinary(ws, data) {
|
|
25243
|
+
if (ws.readyState !== wrapper_default.OPEN) return false;
|
|
25244
|
+
try {
|
|
25245
|
+
ws.send(data, { binary: true });
|
|
25246
|
+
return true;
|
|
25247
|
+
} catch {
|
|
25248
|
+
return false;
|
|
25249
|
+
}
|
|
25250
|
+
}
|
|
25251
|
+
|
|
25195
25252
|
// src/bridge/connection/create-ws-bridge.ts
|
|
25196
25253
|
var BRIDGE_AUTH_ERROR_HEADER = "x-bridge-auth-error";
|
|
25197
25254
|
var BRIDGE_AUTH_ERROR_TOKEN_INVALID = "token_invalid";
|
|
25198
25255
|
function createWsBridge(options) {
|
|
25199
25256
|
const { url: url2, onMessage, onOpen, onClose, onError: onError2, onAuthInvalid, clientPingIntervalMs } = options;
|
|
25200
25257
|
applyCliOutboundNetworkPreferences();
|
|
25201
|
-
const
|
|
25202
|
-
|
|
25203
|
-
|
|
25204
|
-
|
|
25205
|
-
|
|
25206
|
-
wsOptions.agent = new https.Agent({ rejectUnauthorized: false, family: 4 });
|
|
25207
|
-
}
|
|
25208
|
-
const ws = new wrapper_default(url2, wsOptions);
|
|
25209
|
-
let clientPingTimer = null;
|
|
25210
|
-
function clearClientPing() {
|
|
25211
|
-
if (clientPingTimer != null) {
|
|
25212
|
-
clearInterval(clientPingTimer);
|
|
25213
|
-
clientPingTimer = null;
|
|
25214
|
-
}
|
|
25258
|
+
const ws = new wrapper_default(url2, buildCliWebSocketClientOptions(url2));
|
|
25259
|
+
let clearClientPing = null;
|
|
25260
|
+
function disposeClientPing() {
|
|
25261
|
+
clearClientPing?.();
|
|
25262
|
+
clearClientPing = null;
|
|
25215
25263
|
}
|
|
25216
25264
|
ws.on("unexpected-response", (request, response) => {
|
|
25217
25265
|
const status = response?.statusCode ?? 0;
|
|
@@ -25222,16 +25270,9 @@ function createWsBridge(options) {
|
|
|
25222
25270
|
}
|
|
25223
25271
|
});
|
|
25224
25272
|
ws.on("open", () => {
|
|
25225
|
-
|
|
25273
|
+
disposeClientPing();
|
|
25226
25274
|
if (clientPingIntervalMs != null && clientPingIntervalMs > 0) {
|
|
25227
|
-
|
|
25228
|
-
if (ws.readyState === wrapper_default.OPEN) {
|
|
25229
|
-
try {
|
|
25230
|
-
ws.ping();
|
|
25231
|
-
} catch {
|
|
25232
|
-
}
|
|
25233
|
-
}
|
|
25234
|
-
}, clientPingIntervalMs);
|
|
25275
|
+
clearClientPing = attachWebSocketClientPing(ws, clientPingIntervalMs);
|
|
25235
25276
|
}
|
|
25236
25277
|
onOpen?.();
|
|
25237
25278
|
});
|
|
@@ -25252,11 +25293,11 @@ function createWsBridge(options) {
|
|
|
25252
25293
|
}
|
|
25253
25294
|
});
|
|
25254
25295
|
ws.on("close", (code, reason) => {
|
|
25255
|
-
|
|
25296
|
+
disposeClientPing();
|
|
25256
25297
|
onClose?.(code, reason.toString());
|
|
25257
25298
|
});
|
|
25258
25299
|
ws.on("error", (err) => {
|
|
25259
|
-
|
|
25300
|
+
disposeClientPing();
|
|
25260
25301
|
onError2?.(err);
|
|
25261
25302
|
});
|
|
25262
25303
|
return ws;
|
|
@@ -25528,9 +25569,9 @@ function runPendingAuth(options) {
|
|
|
25528
25569
|
keepaliveInterval = null;
|
|
25529
25570
|
}
|
|
25530
25571
|
if (ws) {
|
|
25531
|
-
ws
|
|
25532
|
-
ws.close();
|
|
25572
|
+
const w = ws;
|
|
25533
25573
|
ws = null;
|
|
25574
|
+
safeCloseWebSocket(w);
|
|
25534
25575
|
}
|
|
25535
25576
|
}
|
|
25536
25577
|
function connect() {
|
|
@@ -25573,7 +25614,7 @@ function runPendingAuth(options) {
|
|
|
25573
25614
|
connect();
|
|
25574
25615
|
}, delay2);
|
|
25575
25616
|
},
|
|
25576
|
-
onError: (err) => logFn
|
|
25617
|
+
onError: (err) => logCliWebSocketError(logFn, "[Bridge service]", err, "while waiting for sign-in"),
|
|
25577
25618
|
onMessage: (data) => {
|
|
25578
25619
|
const msg = data;
|
|
25579
25620
|
if (msg.type === "auth_token" && typeof msg.token === "string") {
|
|
@@ -32793,14 +32834,50 @@ async function removeSessionWorktrees(paths, log2) {
|
|
|
32793
32834
|
}
|
|
32794
32835
|
|
|
32795
32836
|
// src/git/working-tree-status.ts
|
|
32796
|
-
async function
|
|
32797
|
-
|
|
32837
|
+
async function tryConfigGet(g, key) {
|
|
32838
|
+
try {
|
|
32839
|
+
const out = await g.raw(["config", "--get", key]);
|
|
32840
|
+
const v = String(out).trim();
|
|
32841
|
+
return v || null;
|
|
32842
|
+
} catch {
|
|
32843
|
+
return null;
|
|
32844
|
+
}
|
|
32845
|
+
}
|
|
32846
|
+
async function resolveRemoteTrackingRefForAhead(g) {
|
|
32798
32847
|
try {
|
|
32799
32848
|
await g.raw(["rev-parse", "--verify", "@{u}"]);
|
|
32849
|
+
return "@{u}";
|
|
32850
|
+
} catch {
|
|
32851
|
+
}
|
|
32852
|
+
const branch = (await g.raw(["rev-parse", "--abbrev-ref", "HEAD"])).trim();
|
|
32853
|
+
if (!branch || branch === "HEAD") return null;
|
|
32854
|
+
const remote = await tryConfigGet(g, `branch.${branch}.remote`) ?? "origin";
|
|
32855
|
+
const merge2 = await tryConfigGet(g, `branch.${branch}.merge`);
|
|
32856
|
+
if (merge2) {
|
|
32857
|
+
const upstreamBranch = merge2.replace(/^refs\/heads\//, "");
|
|
32858
|
+
const ref = `refs/remotes/${remote}/${upstreamBranch}`;
|
|
32859
|
+
try {
|
|
32860
|
+
await g.raw(["rev-parse", "--verify", ref]);
|
|
32861
|
+
return ref;
|
|
32862
|
+
} catch {
|
|
32863
|
+
}
|
|
32864
|
+
}
|
|
32865
|
+
const fallbackRef = `refs/remotes/${remote}/${branch}`;
|
|
32866
|
+
try {
|
|
32867
|
+
await g.raw(["rev-parse", "--verify", fallbackRef]);
|
|
32868
|
+
return fallbackRef;
|
|
32800
32869
|
} catch {
|
|
32801
|
-
return
|
|
32870
|
+
return null;
|
|
32802
32871
|
}
|
|
32803
|
-
|
|
32872
|
+
}
|
|
32873
|
+
async function commitsAheadOfRemoteTracking(repoDir) {
|
|
32874
|
+
const g = simpleGit(repoDir);
|
|
32875
|
+
const trackingRef = await resolveRemoteTrackingRefForAhead(g);
|
|
32876
|
+
if (!trackingRef) return 0;
|
|
32877
|
+
const localSha = (await g.raw(["rev-parse", "HEAD"])).trim();
|
|
32878
|
+
const remoteSha = (await g.raw(["rev-parse", trackingRef])).trim();
|
|
32879
|
+
if (localSha === remoteSha) return 0;
|
|
32880
|
+
const out = await g.raw(["rev-list", "--count", `${trackingRef}..HEAD`]);
|
|
32804
32881
|
const n = parseInt(String(out).trim(), 10);
|
|
32805
32882
|
return Number.isNaN(n) ? 0 : n;
|
|
32806
32883
|
}
|
|
@@ -32808,7 +32885,7 @@ async function getRepoWorkingTreeStatus(repoDir) {
|
|
|
32808
32885
|
const g = simpleGit(repoDir);
|
|
32809
32886
|
const st = await g.status();
|
|
32810
32887
|
const hasUncommittedChanges = (st.files?.length ?? 0) > 0;
|
|
32811
|
-
const ahead = await
|
|
32888
|
+
const ahead = await commitsAheadOfRemoteTracking(repoDir);
|
|
32812
32889
|
return { hasUncommittedChanges, hasUnpushedCommits: ahead > 0 };
|
|
32813
32890
|
}
|
|
32814
32891
|
async function aggregateSessionPathsWorkingTreeStatus(paths) {
|
|
@@ -32824,7 +32901,7 @@ async function aggregateSessionPathsWorkingTreeStatus(paths) {
|
|
|
32824
32901
|
async function pushAheadOfUpstreamForPaths(paths) {
|
|
32825
32902
|
for (const p of paths) {
|
|
32826
32903
|
const g = simpleGit(p);
|
|
32827
|
-
const ahead = await
|
|
32904
|
+
const ahead = await commitsAheadOfRemoteTracking(p);
|
|
32828
32905
|
if (ahead <= 0) continue;
|
|
32829
32906
|
await g.push();
|
|
32830
32907
|
}
|
|
@@ -34099,8 +34176,53 @@ var DevServerManager = class {
|
|
|
34099
34176
|
}
|
|
34100
34177
|
};
|
|
34101
34178
|
|
|
34102
|
-
// src/
|
|
34103
|
-
|
|
34179
|
+
// src/net/transient-local-fetch-retry.ts
|
|
34180
|
+
var LOCAL_PREVIEW_FETCH_RETRY_DELAYS_MS = [30, 100, 200, 400];
|
|
34181
|
+
function sleepMs(ms) {
|
|
34182
|
+
return new Promise((r) => setTimeout(r, ms));
|
|
34183
|
+
}
|
|
34184
|
+
function collectErrorText(err) {
|
|
34185
|
+
const parts = [];
|
|
34186
|
+
let e = err;
|
|
34187
|
+
for (let depth = 0; depth < 6 && e != null; depth += 1) {
|
|
34188
|
+
if (e instanceof Error) {
|
|
34189
|
+
parts.push(e.message);
|
|
34190
|
+
e = e.cause;
|
|
34191
|
+
} else {
|
|
34192
|
+
parts.push(String(e));
|
|
34193
|
+
break;
|
|
34194
|
+
}
|
|
34195
|
+
}
|
|
34196
|
+
return parts.join(" ").toLowerCase();
|
|
34197
|
+
}
|
|
34198
|
+
function isTransientLocalServiceError(err) {
|
|
34199
|
+
const text = collectErrorText(err);
|
|
34200
|
+
if (!text) return false;
|
|
34201
|
+
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");
|
|
34202
|
+
}
|
|
34203
|
+
function isIdempotentHttpMethod(method) {
|
|
34204
|
+
const m = method.toUpperCase();
|
|
34205
|
+
return m === "GET" || m === "HEAD" || m === "OPTIONS";
|
|
34206
|
+
}
|
|
34207
|
+
async function fetchWithLocalTransientRetries(url2, init, options) {
|
|
34208
|
+
const method = (init?.method ?? "GET").toUpperCase();
|
|
34209
|
+
const allowRetry = isIdempotentHttpMethod(method);
|
|
34210
|
+
const delays = options?.delaysMs ?? LOCAL_PREVIEW_FETCH_RETRY_DELAYS_MS;
|
|
34211
|
+
const maxAttempts = options?.maxAttempts ?? (allowRetry ? Math.max(1, delays.length + 1) : 1);
|
|
34212
|
+
let lastErr;
|
|
34213
|
+
for (let attempt = 0; attempt < maxAttempts; attempt += 1) {
|
|
34214
|
+
try {
|
|
34215
|
+
return await fetch(url2, init);
|
|
34216
|
+
} catch (e) {
|
|
34217
|
+
lastErr = e;
|
|
34218
|
+
const canRetry = allowRetry && attempt < maxAttempts - 1 && isTransientLocalServiceError(e);
|
|
34219
|
+
if (!canRetry) throw e;
|
|
34220
|
+
const waitMs = delays[Math.min(attempt, delays.length - 1)] ?? 100;
|
|
34221
|
+
await sleepMs(waitMs);
|
|
34222
|
+
}
|
|
34223
|
+
}
|
|
34224
|
+
throw lastErr instanceof Error ? lastErr : new Error(String(lastErr));
|
|
34225
|
+
}
|
|
34104
34226
|
|
|
34105
34227
|
// src/firehose/proxy/local-proxy.ts
|
|
34106
34228
|
var ALLOWED_HOSTS = ["localhost", "127.0.0.1", "::1"];
|
|
@@ -34108,6 +34230,10 @@ function isAllowedHost(host) {
|
|
|
34108
34230
|
const h = host.replace(/^\[|\]$/g, "");
|
|
34109
34231
|
return ALLOWED_HOSTS.includes(host) || ALLOWED_HOSTS.includes(h);
|
|
34110
34232
|
}
|
|
34233
|
+
function isIdempotentProxyMethod(method) {
|
|
34234
|
+
const m = method.toUpperCase();
|
|
34235
|
+
return m === "GET" || m === "HEAD" || m === "OPTIONS";
|
|
34236
|
+
}
|
|
34111
34237
|
function checkUrlAndHost(request) {
|
|
34112
34238
|
let url2;
|
|
34113
34239
|
try {
|
|
@@ -34135,38 +34261,47 @@ async function proxyToLocal(request) {
|
|
|
34135
34261
|
path: url2.pathname + url2.search,
|
|
34136
34262
|
headers: request.headers
|
|
34137
34263
|
};
|
|
34138
|
-
|
|
34139
|
-
|
|
34140
|
-
|
|
34141
|
-
|
|
34142
|
-
|
|
34143
|
-
|
|
34144
|
-
|
|
34145
|
-
|
|
34146
|
-
|
|
34147
|
-
|
|
34148
|
-
|
|
34264
|
+
const maxAttempts = isIdempotentProxyMethod(request.method) ? LOCAL_PREVIEW_FETCH_RETRY_DELAYS_MS.length + 1 : 1;
|
|
34265
|
+
for (let attempt = 0; attempt < maxAttempts; attempt += 1) {
|
|
34266
|
+
const once = await new Promise((resolve15) => {
|
|
34267
|
+
const req = mod.request(opts, (res) => {
|
|
34268
|
+
const chunks = [];
|
|
34269
|
+
res.on("data", (c) => chunks.push(c));
|
|
34270
|
+
res.on("end", () => {
|
|
34271
|
+
const body = Buffer.concat(chunks).toString("utf8");
|
|
34272
|
+
const headers = {};
|
|
34273
|
+
for (const [k, v] of Object.entries(res.headers)) {
|
|
34274
|
+
if (typeof v === "string") headers[k] = v;
|
|
34275
|
+
else if (Array.isArray(v) && v[0]) headers[k] = v[0];
|
|
34276
|
+
}
|
|
34277
|
+
resolve15({
|
|
34278
|
+
id: request.id,
|
|
34279
|
+
statusCode: res.statusCode ?? 0,
|
|
34280
|
+
headers,
|
|
34281
|
+
body
|
|
34282
|
+
});
|
|
34283
|
+
});
|
|
34284
|
+
});
|
|
34285
|
+
req.on("error", (err) => {
|
|
34149
34286
|
resolve15({
|
|
34150
34287
|
id: request.id,
|
|
34151
|
-
statusCode:
|
|
34152
|
-
headers,
|
|
34153
|
-
body
|
|
34288
|
+
statusCode: 0,
|
|
34289
|
+
headers: {},
|
|
34290
|
+
body: "",
|
|
34291
|
+
error: err.message
|
|
34154
34292
|
});
|
|
34155
34293
|
});
|
|
34294
|
+
const method = request.method.toUpperCase();
|
|
34295
|
+
if (request.body && method !== "GET" && method !== "HEAD") req.write(request.body);
|
|
34296
|
+
req.end();
|
|
34156
34297
|
});
|
|
34157
|
-
|
|
34158
|
-
|
|
34159
|
-
|
|
34160
|
-
|
|
34161
|
-
|
|
34162
|
-
|
|
34163
|
-
|
|
34164
|
-
});
|
|
34165
|
-
});
|
|
34166
|
-
const method = request.method.toUpperCase();
|
|
34167
|
-
if (request.body && method !== "GET" && method !== "HEAD") req.write(request.body);
|
|
34168
|
-
req.end();
|
|
34169
|
-
});
|
|
34298
|
+
const errMsg = once.error ?? "";
|
|
34299
|
+
const canRetry = attempt < maxAttempts - 1 && errMsg !== "" && isTransientLocalServiceError(new Error(errMsg));
|
|
34300
|
+
if (!canRetry) return once;
|
|
34301
|
+
const waitMs = LOCAL_PREVIEW_FETCH_RETRY_DELAYS_MS[Math.min(attempt, LOCAL_PREVIEW_FETCH_RETRY_DELAYS_MS.length - 1)] ?? 100;
|
|
34302
|
+
await sleepMs(waitMs);
|
|
34303
|
+
}
|
|
34304
|
+
throw new Error("Local proxy retry loop exited unexpectedly");
|
|
34170
34305
|
}
|
|
34171
34306
|
async function proxyToLocalStreaming(request, callbacks) {
|
|
34172
34307
|
const checked = checkUrlAndHost(request);
|
|
@@ -34183,7 +34318,7 @@ async function proxyToLocalStreaming(request, callbacks) {
|
|
|
34183
34318
|
if (request.body !== void 0 && request.body !== null && method !== "GET" && method !== "HEAD") {
|
|
34184
34319
|
init.body = request.body;
|
|
34185
34320
|
}
|
|
34186
|
-
const res = await
|
|
34321
|
+
const res = await fetchWithLocalTransientRetries(request.url, init);
|
|
34187
34322
|
const headers = {};
|
|
34188
34323
|
res.headers.forEach((value, key) => {
|
|
34189
34324
|
headers[key] = value;
|
|
@@ -34213,6 +34348,9 @@ async function proxyToLocalStreaming(request, callbacks) {
|
|
|
34213
34348
|
function startStreamingProxy(ws, log2, pr) {
|
|
34214
34349
|
proxyToLocalStreaming(pr, {
|
|
34215
34350
|
onStart: (statusCode, headers) => {
|
|
34351
|
+
if (ws.readyState !== wrapper_default.OPEN) {
|
|
34352
|
+
throw new Error("Preview stream interrupted (firehose connection closed)");
|
|
34353
|
+
}
|
|
34216
34354
|
const forwardedHeaders = { ...headers };
|
|
34217
34355
|
const ce = "content-encoding";
|
|
34218
34356
|
const cl = "content-length";
|
|
@@ -34225,7 +34363,10 @@ function startStreamingProxy(ws, log2, pr) {
|
|
|
34225
34363
|
},
|
|
34226
34364
|
onChunk: (chunk) => {
|
|
34227
34365
|
const idBuf = Buffer.from(pr.id, "utf8");
|
|
34228
|
-
|
|
34366
|
+
const buf = Buffer.concat([idBuf, Buffer.from(chunk)]);
|
|
34367
|
+
if (!safeSendWebSocketBinary(ws, buf)) {
|
|
34368
|
+
throw new Error("Preview stream interrupted (firehose connection closed)");
|
|
34369
|
+
}
|
|
34229
34370
|
},
|
|
34230
34371
|
onEnd: () => sendWsMessage(ws, { type: "proxy_result_end", id: pr.id }),
|
|
34231
34372
|
onError: (error40) => {
|
|
@@ -34343,22 +34484,15 @@ function tryConsumeBinaryProxyBody(raw, deps) {
|
|
|
34343
34484
|
}
|
|
34344
34485
|
|
|
34345
34486
|
// src/firehose/connect-firehose.ts
|
|
34346
|
-
var FIREHOSE_CLIENT_PING_MS = 25e3;
|
|
34347
34487
|
function connectFirehose(options) {
|
|
34348
34488
|
const { firehoseServerUrl, workspaceId, bridgeName, proxyPorts, log: log2, devServerManager, onOpen, onClose } = options;
|
|
34349
34489
|
const wsUrl = buildFirehoseCliWsUrl(firehoseServerUrl);
|
|
34350
34490
|
applyCliOutboundNetworkPreferences();
|
|
34351
|
-
const
|
|
34352
|
-
|
|
34353
|
-
|
|
34354
|
-
|
|
34355
|
-
|
|
34356
|
-
let clientPingTimer = null;
|
|
34357
|
-
function clearClientPing() {
|
|
34358
|
-
if (clientPingTimer != null) {
|
|
34359
|
-
clearInterval(clientPingTimer);
|
|
34360
|
-
clientPingTimer = null;
|
|
34361
|
-
}
|
|
34491
|
+
const ws = new wrapper_default(wsUrl, buildCliWebSocketClientOptions(wsUrl));
|
|
34492
|
+
let clearClientPing = null;
|
|
34493
|
+
function disposeClientPing() {
|
|
34494
|
+
clearClientPing?.();
|
|
34495
|
+
clearClientPing = null;
|
|
34362
34496
|
}
|
|
34363
34497
|
const firehoseSend = (payload) => {
|
|
34364
34498
|
sendWsMessage(ws, payload);
|
|
@@ -34372,15 +34506,8 @@ function connectFirehose(options) {
|
|
|
34372
34506
|
startStreamingProxy: (pr) => startStreamingProxy(ws, log2, pr)
|
|
34373
34507
|
};
|
|
34374
34508
|
ws.on("open", () => {
|
|
34375
|
-
|
|
34376
|
-
|
|
34377
|
-
if (ws.readyState === wrapper_default.OPEN) {
|
|
34378
|
-
try {
|
|
34379
|
-
ws.ping();
|
|
34380
|
-
} catch {
|
|
34381
|
-
}
|
|
34382
|
-
}
|
|
34383
|
-
}, FIREHOSE_CLIENT_PING_MS);
|
|
34509
|
+
disposeClientPing();
|
|
34510
|
+
clearClientPing = attachWebSocketClientPing(ws, CLI_WEBSOCKET_CLIENT_PING_MS);
|
|
34384
34511
|
onOpen?.();
|
|
34385
34512
|
devServerManager.attachFirehose(firehoseSend);
|
|
34386
34513
|
sendWsMessage(ws, { type: "identify", workspaceId, bridgeName, proxyPorts });
|
|
@@ -34396,24 +34523,23 @@ function connectFirehose(options) {
|
|
|
34396
34523
|
}
|
|
34397
34524
|
});
|
|
34398
34525
|
ws.on("close", (code, reason) => {
|
|
34399
|
-
|
|
34526
|
+
disposeClientPing();
|
|
34400
34527
|
devServerManager.detachFirehose();
|
|
34401
34528
|
const reasonStr = typeof reason === "string" ? reason : reason.toString();
|
|
34402
34529
|
onClose?.(code, reasonStr);
|
|
34403
34530
|
});
|
|
34404
34531
|
ws.on("error", (err) => {
|
|
34405
|
-
|
|
34406
|
-
log2
|
|
34532
|
+
disposeClientPing();
|
|
34533
|
+
logCliWebSocketError(log2, "[Proxy and log service]", err);
|
|
34534
|
+
if (ws.readyState === wrapper_default.CONNECTING || ws.readyState === wrapper_default.OPEN) {
|
|
34535
|
+
safeCloseWebSocket(ws);
|
|
34536
|
+
}
|
|
34407
34537
|
});
|
|
34408
34538
|
return {
|
|
34409
34539
|
close() {
|
|
34410
|
-
|
|
34540
|
+
disposeClientPing();
|
|
34411
34541
|
devServerManager.detachFirehose();
|
|
34412
|
-
|
|
34413
|
-
ws.removeAllListeners();
|
|
34414
|
-
ws.close();
|
|
34415
|
-
} catch {
|
|
34416
|
-
}
|
|
34542
|
+
safeCloseWebSocket(ws);
|
|
34417
34543
|
},
|
|
34418
34544
|
isConnected: () => ws.readyState === wrapper_default.OPEN
|
|
34419
34545
|
};
|
|
@@ -35766,7 +35892,6 @@ async function refreshBridgeTokens(params) {
|
|
|
35766
35892
|
}
|
|
35767
35893
|
|
|
35768
35894
|
// src/bridge/connection/main-bridge-ws-lifecycle.ts
|
|
35769
|
-
var BRIDGE_CLIENT_PING_MS = 25e3;
|
|
35770
35895
|
function createMainBridgeWebSocketLifecycle(params) {
|
|
35771
35896
|
const {
|
|
35772
35897
|
state,
|
|
@@ -35824,6 +35949,11 @@ function createMainBridgeWebSocketLifecycle(params) {
|
|
|
35824
35949
|
const prev = state.currentWs;
|
|
35825
35950
|
if (prev) {
|
|
35826
35951
|
prev.removeAllListeners();
|
|
35952
|
+
prev.once("error", () => {
|
|
35953
|
+
});
|
|
35954
|
+
prev.once("close", () => {
|
|
35955
|
+
prev.removeAllListeners();
|
|
35956
|
+
});
|
|
35827
35957
|
try {
|
|
35828
35958
|
prev.close();
|
|
35829
35959
|
} catch {
|
|
@@ -35833,7 +35963,7 @@ function createMainBridgeWebSocketLifecycle(params) {
|
|
|
35833
35963
|
const url2 = buildBridgeUrl(apiUrl, workspaceId, tokens.accessToken);
|
|
35834
35964
|
state.currentWs = createWsBridge({
|
|
35835
35965
|
url: url2,
|
|
35836
|
-
clientPingIntervalMs:
|
|
35966
|
+
clientPingIntervalMs: CLI_WEBSOCKET_CLIENT_PING_MS,
|
|
35837
35967
|
onAuthInvalid: () => {
|
|
35838
35968
|
if (authRefreshInFlight) return;
|
|
35839
35969
|
void (async () => {
|
|
@@ -35869,7 +35999,7 @@ function createMainBridgeWebSocketLifecycle(params) {
|
|
|
35869
35999
|
},
|
|
35870
36000
|
onOpen: handleOpen,
|
|
35871
36001
|
onClose: handleClose,
|
|
35872
|
-
onError: (err) => logFn
|
|
36002
|
+
onError: (err) => logCliWebSocketError(logFn, "[Bridge service]", err),
|
|
35873
36003
|
onMessage: (data) => handleBridgeMessage(data, messageDeps)
|
|
35874
36004
|
});
|
|
35875
36005
|
}
|