@buildautomaton/cli 0.1.61 → 0.1.62
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 +480 -289
- package/dist/cli.js.map +4 -4
- package/dist/index.js +463 -272
- package/dist/index.js.map +4 -4
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -22625,18 +22625,6 @@ var import_websocket = __toESM(require_websocket(), 1);
|
|
|
22625
22625
|
var import_websocket_server = __toESM(require_websocket_server(), 1);
|
|
22626
22626
|
var wrapper_default = import_websocket.default;
|
|
22627
22627
|
|
|
22628
|
-
// src/net/apply-cli-outbound-network-prefs.ts
|
|
22629
|
-
import dns from "node:dns";
|
|
22630
|
-
var applied = false;
|
|
22631
|
-
function applyCliOutboundNetworkPreferences() {
|
|
22632
|
-
if (applied) return;
|
|
22633
|
-
applied = true;
|
|
22634
|
-
try {
|
|
22635
|
-
dns.setDefaultResultOrder("ipv4first");
|
|
22636
|
-
} catch {
|
|
22637
|
-
}
|
|
22638
|
-
}
|
|
22639
|
-
|
|
22640
22628
|
// src/connection/cli-ws-client.ts
|
|
22641
22629
|
import https from "node:https";
|
|
22642
22630
|
var CLI_WEBSOCKET_CLIENT_PING_MS = 25e3;
|
|
@@ -22738,7 +22726,6 @@ function createWsBridge(options) {
|
|
|
22738
22726
|
onCompactHeartbeatAck,
|
|
22739
22727
|
isActiveSocket
|
|
22740
22728
|
} = options;
|
|
22741
|
-
applyCliOutboundNetworkPreferences();
|
|
22742
22729
|
const ws = new wrapper_default(url2, buildCliWebSocketClientOptions(url2));
|
|
22743
22730
|
let clearClientPing = null;
|
|
22744
22731
|
function disposeClientPing() {
|
|
@@ -24855,6 +24842,71 @@ async function createSdkStdioAcpClient(options) {
|
|
|
24855
24842
|
});
|
|
24856
24843
|
}
|
|
24857
24844
|
|
|
24845
|
+
// src/firehose/proxy/constants.ts
|
|
24846
|
+
var LOCAL_PROXY_REQUEST_TIMEOUT_MS = 3e4;
|
|
24847
|
+
|
|
24848
|
+
// src/firehose/proxy/prepare-local-proxy-request-headers.ts
|
|
24849
|
+
var HOP_BY_HOP_HEADERS = /* @__PURE__ */ new Set([
|
|
24850
|
+
"connection",
|
|
24851
|
+
"keep-alive",
|
|
24852
|
+
"proxy-authenticate",
|
|
24853
|
+
"proxy-authorization",
|
|
24854
|
+
"te",
|
|
24855
|
+
"trailers",
|
|
24856
|
+
"transfer-encoding",
|
|
24857
|
+
"upgrade"
|
|
24858
|
+
]);
|
|
24859
|
+
var BODY_HEADERS = /* @__PURE__ */ new Set(["content-length", "content-type", "content-encoding"]);
|
|
24860
|
+
function methodAllowsRequestBody(method) {
|
|
24861
|
+
const normalized = method.toUpperCase();
|
|
24862
|
+
return normalized !== "GET" && normalized !== "HEAD";
|
|
24863
|
+
}
|
|
24864
|
+
function prepareLocalProxyRequestHeaders(method, headers, sendingBody) {
|
|
24865
|
+
const out = {};
|
|
24866
|
+
for (const [key, value] of Object.entries(headers ?? {})) {
|
|
24867
|
+
const lower = key.toLowerCase();
|
|
24868
|
+
if (lower === "host") continue;
|
|
24869
|
+
if (HOP_BY_HOP_HEADERS.has(lower)) continue;
|
|
24870
|
+
if (lower === "origin" || lower === "referer") continue;
|
|
24871
|
+
if (!sendingBody && BODY_HEADERS.has(lower)) continue;
|
|
24872
|
+
out[key] = value;
|
|
24873
|
+
}
|
|
24874
|
+
return out;
|
|
24875
|
+
}
|
|
24876
|
+
|
|
24877
|
+
// src/firehose/proxy/build-local-proxy-http-request.ts
|
|
24878
|
+
var ALLOWED_HOSTS = /* @__PURE__ */ new Set(["localhost", "127.0.0.1", "::1"]);
|
|
24879
|
+
function willSendLocalProxyBody(request) {
|
|
24880
|
+
if (!methodAllowsRequestBody(request.method)) return false;
|
|
24881
|
+
return request.body !== void 0 && request.body !== null;
|
|
24882
|
+
}
|
|
24883
|
+
function buildLocalProxyHttpRequest(request) {
|
|
24884
|
+
let url2;
|
|
24885
|
+
try {
|
|
24886
|
+
url2 = new URL(request.url);
|
|
24887
|
+
} catch {
|
|
24888
|
+
return { error: `Invalid URL: ${request.url}` };
|
|
24889
|
+
}
|
|
24890
|
+
const hostname2 = url2.hostname.replace(/^\[|\]$/g, "");
|
|
24891
|
+
if (!ALLOWED_HOSTS.has(url2.hostname) && !ALLOWED_HOSTS.has(hostname2)) {
|
|
24892
|
+
return { error: "Only localhost requests are allowed" };
|
|
24893
|
+
}
|
|
24894
|
+
const sendingBody = willSendLocalProxyBody(request);
|
|
24895
|
+
const headers = prepareLocalProxyRequestHeaders(request.method, request.headers, sendingBody);
|
|
24896
|
+
headers.host = url2.host;
|
|
24897
|
+
const isHttps = url2.protocol === "https:";
|
|
24898
|
+
const port = url2.port ? Number(url2.port) : isHttps ? 443 : 80;
|
|
24899
|
+
return {
|
|
24900
|
+
method: request.method,
|
|
24901
|
+
hostname: url2.hostname,
|
|
24902
|
+
port,
|
|
24903
|
+
path: `${url2.pathname}${url2.search}`,
|
|
24904
|
+
headers,
|
|
24905
|
+
sendingBody,
|
|
24906
|
+
body: sendingBody ? request.body : void 0
|
|
24907
|
+
};
|
|
24908
|
+
}
|
|
24909
|
+
|
|
24858
24910
|
// src/net/transient-local-fetch-retry.ts
|
|
24859
24911
|
var LOCAL_PREVIEW_FETCH_RETRY_DELAYS_MS = [30, 100, 200, 400];
|
|
24860
24912
|
function sleepMs(ms) {
|
|
@@ -24879,148 +24931,151 @@ function isTransientLocalServiceError(err) {
|
|
|
24879
24931
|
if (!text) return false;
|
|
24880
24932
|
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");
|
|
24881
24933
|
}
|
|
24882
|
-
|
|
24883
|
-
|
|
24884
|
-
|
|
24885
|
-
}
|
|
24886
|
-
|
|
24887
|
-
|
|
24888
|
-
|
|
24889
|
-
const delays = options?.delaysMs ?? LOCAL_PREVIEW_FETCH_RETRY_DELAYS_MS;
|
|
24890
|
-
const maxAttempts = options?.maxAttempts ?? (allowRetry ? Math.max(1, delays.length + 1) : 1);
|
|
24891
|
-
let lastErr;
|
|
24892
|
-
for (let attempt = 0; attempt < maxAttempts; attempt += 1) {
|
|
24893
|
-
try {
|
|
24894
|
-
return await fetch(url2, init);
|
|
24895
|
-
} catch (e) {
|
|
24896
|
-
lastErr = e;
|
|
24897
|
-
const canRetry = allowRetry && attempt < maxAttempts - 1 && isTransientLocalServiceError(e);
|
|
24898
|
-
if (!canRetry) throw e;
|
|
24899
|
-
const waitMs = delays[Math.min(attempt, delays.length - 1)] ?? 100;
|
|
24900
|
-
await sleepMs(waitMs);
|
|
24901
|
-
}
|
|
24934
|
+
|
|
24935
|
+
// src/firehose/proxy/incoming-message-headers.ts
|
|
24936
|
+
function incomingMessageHeaders(res) {
|
|
24937
|
+
const headers = {};
|
|
24938
|
+
for (const [k, v] of Object.entries(res.headers)) {
|
|
24939
|
+
if (typeof v === "string") headers[k] = v;
|
|
24940
|
+
else if (Array.isArray(v) && v[0]) headers[k] = v[0];
|
|
24902
24941
|
}
|
|
24903
|
-
|
|
24942
|
+
return headers;
|
|
24904
24943
|
}
|
|
24905
24944
|
|
|
24906
|
-
// src/firehose/proxy/local-
|
|
24907
|
-
|
|
24908
|
-
|
|
24909
|
-
const h = host.replace(/^\[|\]$/g, "");
|
|
24910
|
-
return ALLOWED_HOSTS.includes(host) || ALLOWED_HOSTS.includes(h);
|
|
24911
|
-
}
|
|
24912
|
-
function isIdempotentProxyMethod(method) {
|
|
24913
|
-
const m = method.toUpperCase();
|
|
24914
|
-
return m === "GET" || m === "HEAD" || m === "OPTIONS";
|
|
24915
|
-
}
|
|
24916
|
-
function checkUrlAndHost(request) {
|
|
24917
|
-
let url2;
|
|
24918
|
-
try {
|
|
24919
|
-
url2 = new URL(request.url);
|
|
24920
|
-
} catch {
|
|
24921
|
-
return { error: `Invalid URL: ${request.url}` };
|
|
24922
|
-
}
|
|
24923
|
-
if (!isAllowedHost(url2.hostname)) {
|
|
24924
|
-
return { error: "Only localhost requests are allowed" };
|
|
24925
|
-
}
|
|
24926
|
-
return { url: url2 };
|
|
24945
|
+
// src/firehose/proxy/run-local-http-request.ts
|
|
24946
|
+
async function loadHttpModule(isHttps) {
|
|
24947
|
+
return isHttps ? import("https") : import("http");
|
|
24927
24948
|
}
|
|
24928
|
-
|
|
24929
|
-
|
|
24930
|
-
|
|
24931
|
-
|
|
24932
|
-
|
|
24933
|
-
|
|
24934
|
-
|
|
24935
|
-
const mod = isHttps ? await import("https") : await import("http");
|
|
24936
|
-
const opts = {
|
|
24937
|
-
method: request.method,
|
|
24938
|
-
hostname: url2.hostname,
|
|
24939
|
-
port: url2.port || (isHttps ? 443 : 80),
|
|
24940
|
-
path: url2.pathname + url2.search,
|
|
24941
|
-
headers: request.headers
|
|
24949
|
+
function buildLocalHttpRequestOptions(built) {
|
|
24950
|
+
return {
|
|
24951
|
+
method: built.method,
|
|
24952
|
+
hostname: built.hostname,
|
|
24953
|
+
port: built.port,
|
|
24954
|
+
path: built.path,
|
|
24955
|
+
headers: built.headers
|
|
24942
24956
|
};
|
|
24943
|
-
|
|
24944
|
-
|
|
24945
|
-
|
|
24946
|
-
|
|
24947
|
-
|
|
24948
|
-
|
|
24949
|
-
|
|
24950
|
-
|
|
24951
|
-
|
|
24952
|
-
|
|
24953
|
-
|
|
24954
|
-
|
|
24955
|
-
}
|
|
24956
|
-
resolve35({
|
|
24957
|
-
id: request.id,
|
|
24958
|
-
statusCode: res.statusCode ?? 0,
|
|
24959
|
-
headers,
|
|
24960
|
-
body
|
|
24961
|
-
});
|
|
24957
|
+
}
|
|
24958
|
+
function runLocalHttpRequestOnce(mod, built) {
|
|
24959
|
+
const opts = buildLocalHttpRequestOptions(built);
|
|
24960
|
+
return new Promise((resolve35) => {
|
|
24961
|
+
const req = mod.request(opts, (res) => {
|
|
24962
|
+
const chunks = [];
|
|
24963
|
+
res.on("data", (chunk) => chunks.push(chunk));
|
|
24964
|
+
res.on("end", () => {
|
|
24965
|
+
resolve35({
|
|
24966
|
+
statusCode: res.statusCode ?? 0,
|
|
24967
|
+
headers: incomingMessageHeaders(res),
|
|
24968
|
+
body: Buffer.concat(chunks)
|
|
24962
24969
|
});
|
|
24963
24970
|
});
|
|
24964
|
-
|
|
24971
|
+
res.on("error", (err) => {
|
|
24965
24972
|
resolve35({
|
|
24966
|
-
id: request.id,
|
|
24967
24973
|
statusCode: 0,
|
|
24968
24974
|
headers: {},
|
|
24969
|
-
body:
|
|
24975
|
+
body: Buffer.alloc(0),
|
|
24970
24976
|
error: err.message
|
|
24971
24977
|
});
|
|
24972
24978
|
});
|
|
24973
|
-
const method = request.method.toUpperCase();
|
|
24974
|
-
if (request.body && method !== "GET" && method !== "HEAD") req.write(request.body);
|
|
24975
|
-
req.end();
|
|
24976
24979
|
});
|
|
24980
|
+
req.setTimeout(LOCAL_PROXY_REQUEST_TIMEOUT_MS, () => {
|
|
24981
|
+
req.destroy(new Error(`Local preview request timed out after ${LOCAL_PROXY_REQUEST_TIMEOUT_MS}ms`));
|
|
24982
|
+
});
|
|
24983
|
+
req.on("error", (err) => {
|
|
24984
|
+
resolve35({
|
|
24985
|
+
statusCode: 0,
|
|
24986
|
+
headers: {},
|
|
24987
|
+
body: Buffer.alloc(0),
|
|
24988
|
+
error: err.message
|
|
24989
|
+
});
|
|
24990
|
+
});
|
|
24991
|
+
if (built.sendingBody && built.body != null) {
|
|
24992
|
+
req.write(built.body);
|
|
24993
|
+
}
|
|
24994
|
+
req.end();
|
|
24995
|
+
});
|
|
24996
|
+
}
|
|
24997
|
+
|
|
24998
|
+
// src/firehose/proxy/proxy-to-local.ts
|
|
24999
|
+
function isIdempotentProxyMethod(method) {
|
|
25000
|
+
const m = method.toUpperCase();
|
|
25001
|
+
return m === "GET" || m === "HEAD" || m === "OPTIONS";
|
|
25002
|
+
}
|
|
25003
|
+
async function proxyToLocal(request) {
|
|
25004
|
+
const built = buildLocalProxyHttpRequest(request);
|
|
25005
|
+
if ("error" in built) {
|
|
25006
|
+
return { id: request.id, statusCode: 0, headers: {}, body: "", error: built.error };
|
|
25007
|
+
}
|
|
25008
|
+
const isHttps = request.url.startsWith("https:");
|
|
25009
|
+
const mod = await loadHttpModule(isHttps);
|
|
25010
|
+
const maxAttempts = isIdempotentProxyMethod(request.method) ? LOCAL_PREVIEW_FETCH_RETRY_DELAYS_MS.length + 1 : 1;
|
|
25011
|
+
for (let attempt = 0; attempt < maxAttempts; attempt += 1) {
|
|
25012
|
+
const once = await runLocalHttpRequestOnce(mod, built);
|
|
24977
25013
|
const errMsg = once.error ?? "";
|
|
24978
25014
|
const canRetry = attempt < maxAttempts - 1 && errMsg !== "" && isTransientLocalServiceError(new Error(errMsg));
|
|
24979
|
-
if (!canRetry)
|
|
25015
|
+
if (!canRetry) {
|
|
25016
|
+
return {
|
|
25017
|
+
id: request.id,
|
|
25018
|
+
statusCode: once.statusCode,
|
|
25019
|
+
headers: once.headers,
|
|
25020
|
+
body: once.body.toString("utf8"),
|
|
25021
|
+
error: once.error
|
|
25022
|
+
};
|
|
25023
|
+
}
|
|
24980
25024
|
const waitMs = LOCAL_PREVIEW_FETCH_RETRY_DELAYS_MS[Math.min(attempt, LOCAL_PREVIEW_FETCH_RETRY_DELAYS_MS.length - 1)] ?? 100;
|
|
24981
25025
|
await sleepMs(waitMs);
|
|
24982
25026
|
}
|
|
24983
25027
|
throw new Error("Local proxy retry loop exited unexpectedly");
|
|
24984
25028
|
}
|
|
25029
|
+
|
|
25030
|
+
// src/firehose/proxy/proxy-to-local-streaming.ts
|
|
24985
25031
|
async function proxyToLocalStreaming(request, callbacks) {
|
|
24986
|
-
const
|
|
24987
|
-
if ("error" in
|
|
24988
|
-
callbacks.onError(
|
|
25032
|
+
const built = buildLocalProxyHttpRequest(request);
|
|
25033
|
+
if ("error" in built) {
|
|
25034
|
+
callbacks.onError(built.error);
|
|
24989
25035
|
return;
|
|
24990
25036
|
}
|
|
24991
|
-
|
|
24992
|
-
|
|
24993
|
-
|
|
24994
|
-
|
|
24995
|
-
|
|
24996
|
-
|
|
24997
|
-
|
|
24998
|
-
|
|
24999
|
-
|
|
25000
|
-
|
|
25001
|
-
|
|
25002
|
-
|
|
25003
|
-
headers[key] = value;
|
|
25004
|
-
});
|
|
25005
|
-
callbacks.onStart(res.status, headers);
|
|
25006
|
-
const reader = res.body?.getReader();
|
|
25007
|
-
if (!reader) {
|
|
25008
|
-
callbacks.onEnd();
|
|
25009
|
-
return;
|
|
25010
|
-
}
|
|
25011
|
-
try {
|
|
25012
|
-
for (; ; ) {
|
|
25013
|
-
const { done, value } = await reader.read();
|
|
25014
|
-
if (done) break;
|
|
25015
|
-
callbacks.onChunk(value);
|
|
25037
|
+
const isHttps = request.url.startsWith("https:");
|
|
25038
|
+
const mod = await loadHttpModule(isHttps);
|
|
25039
|
+
const opts = buildLocalHttpRequestOptions(built);
|
|
25040
|
+
await new Promise((resolve35) => {
|
|
25041
|
+
const req = mod.request(opts, (res) => {
|
|
25042
|
+
try {
|
|
25043
|
+
callbacks.onStart(res.statusCode ?? 0, incomingMessageHeaders(res));
|
|
25044
|
+
} catch (err) {
|
|
25045
|
+
req.destroy();
|
|
25046
|
+
callbacks.onError(err instanceof Error ? err.message : String(err));
|
|
25047
|
+
resolve35();
|
|
25048
|
+
return;
|
|
25016
25049
|
}
|
|
25017
|
-
|
|
25018
|
-
|
|
25050
|
+
res.on("data", (chunk) => {
|
|
25051
|
+
try {
|
|
25052
|
+
callbacks.onChunk(new Uint8Array(chunk));
|
|
25053
|
+
} catch (err) {
|
|
25054
|
+
req.destroy();
|
|
25055
|
+
callbacks.onError(err instanceof Error ? err.message : String(err));
|
|
25056
|
+
}
|
|
25057
|
+
});
|
|
25058
|
+
res.on("end", () => {
|
|
25059
|
+
callbacks.onEnd();
|
|
25060
|
+
resolve35();
|
|
25061
|
+
});
|
|
25062
|
+
res.on("error", (err) => {
|
|
25063
|
+
callbacks.onError(err.message);
|
|
25064
|
+
resolve35();
|
|
25065
|
+
});
|
|
25066
|
+
});
|
|
25067
|
+
req.setTimeout(LOCAL_PROXY_REQUEST_TIMEOUT_MS, () => {
|
|
25068
|
+
req.destroy(new Error(`Local preview request timed out after ${LOCAL_PROXY_REQUEST_TIMEOUT_MS}ms`));
|
|
25069
|
+
});
|
|
25070
|
+
req.on("error", (err) => {
|
|
25071
|
+
callbacks.onError(err.message);
|
|
25072
|
+
resolve35();
|
|
25073
|
+
});
|
|
25074
|
+
if (built.sendingBody && built.body != null) {
|
|
25075
|
+
req.write(built.body);
|
|
25019
25076
|
}
|
|
25020
|
-
|
|
25021
|
-
}
|
|
25022
|
-
callbacks.onError(err instanceof Error ? err.message : String(err));
|
|
25023
|
-
}
|
|
25077
|
+
req.end();
|
|
25078
|
+
});
|
|
25024
25079
|
}
|
|
25025
25080
|
|
|
25026
25081
|
// src/skills/preview.ts
|
|
@@ -25272,7 +25327,7 @@ function installBridgeProcessResilience() {
|
|
|
25272
25327
|
}
|
|
25273
25328
|
|
|
25274
25329
|
// src/cli-version.ts
|
|
25275
|
-
var CLI_VERSION = "0.1.
|
|
25330
|
+
var CLI_VERSION = "0.1.62".length > 0 ? "0.1.62" : "0.0.0-dev";
|
|
25276
25331
|
|
|
25277
25332
|
// src/connection/heartbeat/constants.ts
|
|
25278
25333
|
var BRIDGE_APP_HEARTBEAT_INTERVAL_MS = 1e4;
|
|
@@ -26654,38 +26709,38 @@ function readCodeNavCacheMigrationSql(filename) {
|
|
|
26654
26709
|
}
|
|
26655
26710
|
|
|
26656
26711
|
// src/sqlite/run-sqlite-migrations.ts
|
|
26657
|
-
function checkpointSatisfiedByLegacyChain(
|
|
26658
|
-
return Array.isArray(replacesLegacyMigrations) && replacesLegacyMigrations.length > 0 && replacesLegacyMigrations.every((n) =>
|
|
26712
|
+
function checkpointSatisfiedByLegacyChain(applied, replacesLegacyMigrations) {
|
|
26713
|
+
return Array.isArray(replacesLegacyMigrations) && replacesLegacyMigrations.length > 0 && replacesLegacyMigrations.every((n) => applied.has(n));
|
|
26659
26714
|
}
|
|
26660
|
-
function recordMigrationAndPruneCheckpointLegacy(db, migration,
|
|
26715
|
+
function recordMigrationAndPruneCheckpointLegacy(db, migration, applied) {
|
|
26661
26716
|
db.run("INSERT INTO __migrations (name) VALUES (?)", [migration.name]);
|
|
26662
|
-
|
|
26717
|
+
applied.add(migration.name);
|
|
26663
26718
|
if (migration.checkpoint !== true) return;
|
|
26664
26719
|
const legacy = migration.replacesLegacyMigrations;
|
|
26665
26720
|
if (!legacy?.length) return;
|
|
26666
26721
|
for (const legacyName of legacy) {
|
|
26667
26722
|
if (legacyName === migration.name) continue;
|
|
26668
26723
|
db.run("DELETE FROM __migrations WHERE name = ?", [legacyName]);
|
|
26669
|
-
|
|
26724
|
+
applied.delete(legacyName);
|
|
26670
26725
|
}
|
|
26671
26726
|
}
|
|
26672
26727
|
function runSqliteMigrations(db, migrations, bootstrapSql, label) {
|
|
26673
26728
|
db.exec(bootstrapSql);
|
|
26674
26729
|
const appliedRows = db.all("SELECT name FROM __migrations");
|
|
26675
|
-
const
|
|
26730
|
+
const applied = new Set(appliedRows.map((r) => r.name));
|
|
26676
26731
|
for (const migration of migrations) {
|
|
26677
|
-
if (
|
|
26678
|
-
if (migration.checkpoint === true && checkpointSatisfiedByLegacyChain(
|
|
26679
|
-
recordMigrationAndPruneCheckpointLegacy(db, migration,
|
|
26732
|
+
if (applied.has(migration.name)) continue;
|
|
26733
|
+
if (migration.checkpoint === true && checkpointSatisfiedByLegacyChain(applied, migration.replacesLegacyMigrations)) {
|
|
26734
|
+
recordMigrationAndPruneCheckpointLegacy(db, migration, applied);
|
|
26680
26735
|
continue;
|
|
26681
26736
|
}
|
|
26682
26737
|
if (migration.alreadyApplied?.(db)) {
|
|
26683
|
-
recordMigrationAndPruneCheckpointLegacy(db, migration,
|
|
26738
|
+
recordMigrationAndPruneCheckpointLegacy(db, migration, applied);
|
|
26684
26739
|
continue;
|
|
26685
26740
|
}
|
|
26686
26741
|
try {
|
|
26687
26742
|
migration.migrate(db);
|
|
26688
|
-
recordMigrationAndPruneCheckpointLegacy(db, migration,
|
|
26743
|
+
recordMigrationAndPruneCheckpointLegacy(db, migration, applied);
|
|
26689
26744
|
} catch (e) {
|
|
26690
26745
|
console.error(`[${label}] Migration failed: ${migration.name}`, e);
|
|
26691
26746
|
throw e;
|
|
@@ -34832,6 +34887,9 @@ function envForSpawn(base, userEnv, ports) {
|
|
|
34832
34887
|
});
|
|
34833
34888
|
if (ports.length > 0) {
|
|
34834
34889
|
out.PORTS = ports.join(",");
|
|
34890
|
+
if (!userKeys.has("PORT")) {
|
|
34891
|
+
out.PORT = String(ports[0]);
|
|
34892
|
+
}
|
|
34835
34893
|
}
|
|
34836
34894
|
if (!userKeys.has("NO_COLOR")) {
|
|
34837
34895
|
delete out.NO_COLOR;
|
|
@@ -35734,6 +35792,12 @@ function createBridgePreviewStack(options) {
|
|
|
35734
35792
|
return { previewEnvironmentManager, scheduleInitialIndexBuildsOnce, identifyReportedPaths };
|
|
35735
35793
|
}
|
|
35736
35794
|
|
|
35795
|
+
// src/firehose/build-cli-ws-url.ts
|
|
35796
|
+
function buildFirehoseCliWsUrl(baseUrl) {
|
|
35797
|
+
const base = baseUrl.startsWith("https") ? baseUrl.replace(/^https/, "wss") : baseUrl.replace(/^http/, "ws");
|
|
35798
|
+
return `${base.replace(/\/$/, "")}/ws`;
|
|
35799
|
+
}
|
|
35800
|
+
|
|
35737
35801
|
// src/firehose/proxy/start-streaming-proxy.ts
|
|
35738
35802
|
function startStreamingProxy(ws, log2, pr) {
|
|
35739
35803
|
proxyToLocalStreaming(pr, {
|
|
@@ -35741,15 +35805,7 @@ function startStreamingProxy(ws, log2, pr) {
|
|
|
35741
35805
|
if (ws.readyState !== wrapper_default.OPEN) {
|
|
35742
35806
|
throw new Error("Preview stream interrupted (firehose connection closed)");
|
|
35743
35807
|
}
|
|
35744
|
-
|
|
35745
|
-
const ce = "content-encoding";
|
|
35746
|
-
const cl = "content-length";
|
|
35747
|
-
const keys = Object.keys(forwardedHeaders).filter(
|
|
35748
|
-
(k) => k.toLowerCase() !== ce && k.toLowerCase() !== cl
|
|
35749
|
-
);
|
|
35750
|
-
const filtered = {};
|
|
35751
|
-
for (const k of keys) if (forwardedHeaders[k] != null) filtered[k] = forwardedHeaders[k];
|
|
35752
|
-
sendWsMessage(ws, { type: "proxy_result_start", id: pr.id, statusCode, headers: filtered });
|
|
35808
|
+
sendWsMessage(ws, { type: "proxy_result_start", id: pr.id, statusCode, headers });
|
|
35753
35809
|
},
|
|
35754
35810
|
onChunk: (chunk) => {
|
|
35755
35811
|
const idBuf = Buffer.from(pr.id, "utf8");
|
|
@@ -35766,10 +35822,19 @@ function startStreamingProxy(ws, log2, pr) {
|
|
|
35766
35822
|
});
|
|
35767
35823
|
}
|
|
35768
35824
|
|
|
35769
|
-
// src/firehose/
|
|
35770
|
-
function
|
|
35771
|
-
const
|
|
35772
|
-
|
|
35825
|
+
// src/firehose/create-firehose-message-deps.ts
|
|
35826
|
+
function createFirehoseMessageDeps(ws, log2, previewEnvironmentManager) {
|
|
35827
|
+
const pendingProxyBody = /* @__PURE__ */ new Map();
|
|
35828
|
+
const earlyProxyBinaryBody = /* @__PURE__ */ new Map();
|
|
35829
|
+
const deps = {
|
|
35830
|
+
ws,
|
|
35831
|
+
log: log2,
|
|
35832
|
+
previewEnvironmentManager,
|
|
35833
|
+
pendingProxyBody,
|
|
35834
|
+
earlyProxyBinaryBody,
|
|
35835
|
+
startStreamingProxy: (pr) => startStreamingProxy(ws, log2, pr)
|
|
35836
|
+
};
|
|
35837
|
+
return deps;
|
|
35773
35838
|
}
|
|
35774
35839
|
|
|
35775
35840
|
// src/firehose/routing/firehose-message-router.ts
|
|
@@ -35810,25 +35875,27 @@ var handleProxyMessage = (msg, deps) => {
|
|
|
35810
35875
|
if (!proxy || typeof proxy !== "object") return;
|
|
35811
35876
|
const pr = proxy;
|
|
35812
35877
|
if (pr.streamResponse) {
|
|
35813
|
-
const bodyLength = pr.bodyLength ?? 0;
|
|
35878
|
+
const bodyLength = methodAllowsRequestBody(pr.method) ? pr.bodyLength ?? 0 : 0;
|
|
35879
|
+
const streamingRequest = {
|
|
35880
|
+
id: pr.id,
|
|
35881
|
+
method: pr.method,
|
|
35882
|
+
url: pr.url,
|
|
35883
|
+
headers: pr.headers,
|
|
35884
|
+
streamResponse: true
|
|
35885
|
+
};
|
|
35814
35886
|
if (bodyLength > 0) {
|
|
35815
|
-
deps.
|
|
35816
|
-
|
|
35817
|
-
|
|
35818
|
-
|
|
35819
|
-
|
|
35820
|
-
|
|
35821
|
-
|
|
35822
|
-
|
|
35823
|
-
|
|
35887
|
+
const earlyBody = deps.earlyProxyBinaryBody.get(pr.id);
|
|
35888
|
+
if (earlyBody !== void 0) {
|
|
35889
|
+
deps.earlyProxyBinaryBody.delete(pr.id);
|
|
35890
|
+
deps.startStreamingProxy({
|
|
35891
|
+
...streamingRequest,
|
|
35892
|
+
body: earlyBody.length > 0 ? earlyBody : void 0
|
|
35893
|
+
});
|
|
35894
|
+
} else {
|
|
35895
|
+
deps.pendingProxyBody.set(pr.id, { pr: streamingRequest });
|
|
35896
|
+
}
|
|
35824
35897
|
} else {
|
|
35825
|
-
deps.startStreamingProxy(
|
|
35826
|
-
id: pr.id,
|
|
35827
|
-
method: pr.method,
|
|
35828
|
-
url: pr.url,
|
|
35829
|
-
headers: pr.headers,
|
|
35830
|
-
streamResponse: true
|
|
35831
|
-
});
|
|
35898
|
+
deps.startStreamingProxy(streamingRequest);
|
|
35832
35899
|
}
|
|
35833
35900
|
return;
|
|
35834
35901
|
}
|
|
@@ -35859,37 +35926,63 @@ function dispatchFirehoseJsonMessage(msg, deps) {
|
|
|
35859
35926
|
|
|
35860
35927
|
// src/firehose/routing/try-consume-binary-proxy-body.ts
|
|
35861
35928
|
var PROXY_ID_BYTES = 36;
|
|
35929
|
+
var PROXY_ID_RE = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
|
|
35862
35930
|
function tryConsumeBinaryProxyBody(raw, deps) {
|
|
35863
35931
|
if (raw.length < PROXY_ID_BYTES) return false;
|
|
35864
35932
|
const id = raw.slice(0, PROXY_ID_BYTES).toString("utf8");
|
|
35865
|
-
|
|
35866
|
-
if (!pending2) return false;
|
|
35867
|
-
deps.pendingProxyBody.delete(id);
|
|
35933
|
+
if (!PROXY_ID_RE.test(id)) return false;
|
|
35868
35934
|
const body = raw.slice(PROXY_ID_BYTES);
|
|
35869
|
-
|
|
35870
|
-
|
|
35871
|
-
|
|
35872
|
-
|
|
35935
|
+
const bodyBytes = body.length > 0 ? new Uint8Array(body) : new Uint8Array(0);
|
|
35936
|
+
const pending2 = deps.pendingProxyBody.get(id);
|
|
35937
|
+
if (pending2) {
|
|
35938
|
+
deps.pendingProxyBody.delete(id);
|
|
35939
|
+
deps.startStreamingProxy({
|
|
35940
|
+
...pending2.pr,
|
|
35941
|
+
body: bodyBytes.length > 0 ? bodyBytes : void 0
|
|
35942
|
+
});
|
|
35943
|
+
return true;
|
|
35944
|
+
}
|
|
35945
|
+
deps.earlyProxyBinaryBody.set(id, bodyBytes);
|
|
35873
35946
|
return true;
|
|
35874
35947
|
}
|
|
35875
35948
|
|
|
35876
|
-
// src/firehose/
|
|
35877
|
-
function
|
|
35949
|
+
// src/firehose/handle-inbound-firehose-frame.ts
|
|
35950
|
+
function handleInboundFirehoseFrame(raw, deps) {
|
|
35951
|
+
if (Buffer.isBuffer(raw) && tryConsumeBinaryProxyBody(raw, deps)) {
|
|
35952
|
+
return;
|
|
35953
|
+
}
|
|
35954
|
+
let msg;
|
|
35955
|
+
try {
|
|
35956
|
+
const text = Buffer.isBuffer(raw) ? raw.toString("utf8") : String(raw);
|
|
35957
|
+
msg = JSON.parse(text);
|
|
35958
|
+
} catch {
|
|
35959
|
+
return;
|
|
35960
|
+
}
|
|
35961
|
+
if (msg.type === "proxy") {
|
|
35962
|
+
dispatchFirehoseJsonMessage(msg, deps);
|
|
35963
|
+
return;
|
|
35964
|
+
}
|
|
35965
|
+
setImmediate(() => {
|
|
35966
|
+
dispatchFirehoseJsonMessage(msg, deps);
|
|
35967
|
+
});
|
|
35968
|
+
}
|
|
35969
|
+
|
|
35970
|
+
// src/firehose/wire-firehose-websocket.ts
|
|
35971
|
+
function wireFirehoseWebSocket(options) {
|
|
35878
35972
|
const {
|
|
35879
|
-
|
|
35973
|
+
ws,
|
|
35974
|
+
deps,
|
|
35975
|
+
log: log2,
|
|
35976
|
+
previewEnvironmentManager,
|
|
35880
35977
|
workspaceId,
|
|
35881
35978
|
bridgeName,
|
|
35882
35979
|
proxyPorts,
|
|
35883
|
-
log: log2,
|
|
35884
|
-
previewEnvironmentManager,
|
|
35885
35980
|
onOpen,
|
|
35886
35981
|
onClose,
|
|
35887
35982
|
suppressWebSocketErrors
|
|
35888
35983
|
} = options;
|
|
35889
|
-
const wsUrl = buildFirehoseCliWsUrl(firehoseServerUrl);
|
|
35890
|
-
applyCliOutboundNetworkPreferences();
|
|
35891
|
-
const ws = new wrapper_default(wsUrl, buildCliWebSocketClientOptions(wsUrl));
|
|
35892
35984
|
let clearClientPing = null;
|
|
35985
|
+
let identifyParams = { workspaceId, bridgeName, proxyPorts };
|
|
35893
35986
|
function disposeClientPing() {
|
|
35894
35987
|
clearClientPing?.();
|
|
35895
35988
|
clearClientPing = null;
|
|
@@ -35897,36 +35990,32 @@ function connectFirehose(options) {
|
|
|
35897
35990
|
const firehoseSend = (payload) => {
|
|
35898
35991
|
sendWsMessage(ws, payload);
|
|
35899
35992
|
};
|
|
35900
|
-
|
|
35901
|
-
|
|
35902
|
-
ws
|
|
35903
|
-
|
|
35904
|
-
|
|
35905
|
-
|
|
35906
|
-
|
|
35907
|
-
|
|
35993
|
+
function sendIdentify(params) {
|
|
35994
|
+
identifyParams = params;
|
|
35995
|
+
if (ws.readyState !== wrapper_default.OPEN) return;
|
|
35996
|
+
sendWsMessage(ws, {
|
|
35997
|
+
type: "identify",
|
|
35998
|
+
workspaceId: params.workspaceId,
|
|
35999
|
+
bridgeName: params.bridgeName,
|
|
36000
|
+
proxyPorts: params.proxyPorts
|
|
36001
|
+
});
|
|
36002
|
+
}
|
|
36003
|
+
function detachPreviewEnvironmentManager() {
|
|
36004
|
+
previewEnvironmentManager.detachFirehose();
|
|
36005
|
+
}
|
|
35908
36006
|
ws.on("open", () => {
|
|
35909
36007
|
disposeClientPing();
|
|
35910
36008
|
clearClientPing = attachWebSocketClientPing(ws, CLI_WEBSOCKET_CLIENT_PING_MS);
|
|
35911
36009
|
onOpen?.();
|
|
35912
36010
|
previewEnvironmentManager.attachFirehose(firehoseSend);
|
|
35913
|
-
|
|
36011
|
+
sendIdentify(identifyParams);
|
|
35914
36012
|
});
|
|
35915
36013
|
ws.on("message", (raw) => {
|
|
35916
|
-
|
|
35917
|
-
return;
|
|
35918
|
-
}
|
|
35919
|
-
setImmediate(() => {
|
|
35920
|
-
try {
|
|
35921
|
-
const text = Buffer.isBuffer(raw) ? raw.toString("utf8") : String(raw);
|
|
35922
|
-
dispatchFirehoseJsonMessage(JSON.parse(text), deps);
|
|
35923
|
-
} catch {
|
|
35924
|
-
}
|
|
35925
|
-
});
|
|
36014
|
+
handleInboundFirehoseFrame(raw, deps);
|
|
35926
36015
|
});
|
|
35927
36016
|
ws.on("close", (code, reason) => {
|
|
35928
36017
|
disposeClientPing();
|
|
35929
|
-
|
|
36018
|
+
detachPreviewEnvironmentManager();
|
|
35930
36019
|
const reasonStr = typeof reason === "string" ? reason : reason.toString();
|
|
35931
36020
|
onClose?.(code, reasonStr);
|
|
35932
36021
|
});
|
|
@@ -35939,25 +36028,64 @@ function connectFirehose(options) {
|
|
|
35939
36028
|
safeCloseWebSocket(ws);
|
|
35940
36029
|
}
|
|
35941
36030
|
});
|
|
36031
|
+
return { disposeClientPing, sendIdentify, detachPreviewEnvironmentManager };
|
|
36032
|
+
}
|
|
36033
|
+
|
|
36034
|
+
// src/firehose/connect-firehose.ts
|
|
36035
|
+
function connectFirehose(options) {
|
|
36036
|
+
const {
|
|
36037
|
+
firehoseServerUrl,
|
|
36038
|
+
workspaceId,
|
|
36039
|
+
bridgeName,
|
|
36040
|
+
proxyPorts,
|
|
36041
|
+
log: log2,
|
|
36042
|
+
previewEnvironmentManager,
|
|
36043
|
+
onOpen,
|
|
36044
|
+
onClose,
|
|
36045
|
+
suppressWebSocketErrors
|
|
36046
|
+
} = options;
|
|
36047
|
+
const wsUrl = buildFirehoseCliWsUrl(firehoseServerUrl);
|
|
36048
|
+
const ws = new wrapper_default(wsUrl, buildCliWebSocketClientOptions(wsUrl));
|
|
36049
|
+
const deps = createFirehoseMessageDeps(ws, log2, previewEnvironmentManager);
|
|
36050
|
+
const wired = wireFirehoseWebSocket({
|
|
36051
|
+
ws,
|
|
36052
|
+
deps,
|
|
36053
|
+
log: log2,
|
|
36054
|
+
previewEnvironmentManager,
|
|
36055
|
+
workspaceId,
|
|
36056
|
+
bridgeName,
|
|
36057
|
+
proxyPorts,
|
|
36058
|
+
onOpen,
|
|
36059
|
+
onClose,
|
|
36060
|
+
suppressWebSocketErrors
|
|
36061
|
+
});
|
|
35942
36062
|
return {
|
|
35943
36063
|
close() {
|
|
35944
|
-
disposeClientPing();
|
|
35945
|
-
|
|
36064
|
+
wired.disposeClientPing();
|
|
36065
|
+
wired.detachPreviewEnvironmentManager();
|
|
35946
36066
|
safeCloseWebSocket(ws);
|
|
35947
36067
|
},
|
|
35948
|
-
isConnected: () => ws.readyState === wrapper_default.OPEN
|
|
36068
|
+
isConnected: () => ws.readyState === wrapper_default.OPEN,
|
|
36069
|
+
updateIdentify: wired.sendIdentify
|
|
35949
36070
|
};
|
|
35950
36071
|
}
|
|
35951
36072
|
|
|
35952
|
-
// src/connection/
|
|
35953
|
-
function
|
|
35954
|
-
|
|
35955
|
-
|
|
35956
|
-
|
|
35957
|
-
|
|
35958
|
-
|
|
35959
|
-
|
|
35960
|
-
|
|
36073
|
+
// src/connection/firehose/compare-firehose-params.ts
|
|
36074
|
+
function proxyPortsEqual(a, b) {
|
|
36075
|
+
if (a.length !== b.length) return false;
|
|
36076
|
+
const sa = [...a].sort((x, y) => x - y);
|
|
36077
|
+
const sb = [...b].sort((x, y) => x - y);
|
|
36078
|
+
return sa.every((v, i) => v === sb[i]);
|
|
36079
|
+
}
|
|
36080
|
+
function sameFirehoseBridge(a, b) {
|
|
36081
|
+
return a.firehoseServerUrl === b.firehoseServerUrl && a.workspaceId === b.workspaceId && a.bridgeName === b.bridgeName;
|
|
36082
|
+
}
|
|
36083
|
+
function shouldReuseOpenFirehoseConnection(prev, next, isConnected) {
|
|
36084
|
+
return Boolean(prev && sameFirehoseBridge(prev, next) && isConnected());
|
|
36085
|
+
}
|
|
36086
|
+
|
|
36087
|
+
// src/connection/firehose/create-firehose-connect-callbacks.ts
|
|
36088
|
+
function createFirehoseConnectCallbacks(state, myGen, logFn, scheduleFirehoseRetryAfterDrop) {
|
|
35961
36089
|
function firehoseCtx() {
|
|
35962
36090
|
return {
|
|
35963
36091
|
closedByUser: state.closedByUser,
|
|
@@ -35966,6 +36094,55 @@ function attachFirehoseAfterIdentified(ctx, params) {
|
|
|
35966
36094
|
firehoseQuiet: state.firehoseQuiet
|
|
35967
36095
|
};
|
|
35968
36096
|
}
|
|
36097
|
+
return {
|
|
36098
|
+
onOpen: () => {
|
|
36099
|
+
if (myGen !== state.firehoseGeneration) return;
|
|
36100
|
+
try {
|
|
36101
|
+
clearFirehoseReconnectQuietOnOpen(
|
|
36102
|
+
{
|
|
36103
|
+
firehoseQuiet: state.firehoseQuiet,
|
|
36104
|
+
firehoseOutage: state.firehoseOutage,
|
|
36105
|
+
lastFirehoseReconnectCloseMeta: state.lastFirehoseReconnectCloseMeta
|
|
36106
|
+
},
|
|
36107
|
+
logFn
|
|
36108
|
+
);
|
|
36109
|
+
} catch {
|
|
36110
|
+
}
|
|
36111
|
+
const logOpenAsFirehoseReconnect = state.firehoseReconnectAttempt > 0;
|
|
36112
|
+
state.firehoseReconnectAttempt = 0;
|
|
36113
|
+
if (!logOpenAsFirehoseReconnect) {
|
|
36114
|
+
try {
|
|
36115
|
+
logFn("Connected to preview tunnel (local HTTP proxy and dev logs).");
|
|
36116
|
+
} catch {
|
|
36117
|
+
}
|
|
36118
|
+
}
|
|
36119
|
+
},
|
|
36120
|
+
onClose: (code, reason) => {
|
|
36121
|
+
if (myGen !== state.firehoseGeneration) return;
|
|
36122
|
+
state.firehoseHandle = null;
|
|
36123
|
+
if (state.closedByUser) return;
|
|
36124
|
+
state.lastFirehoseReconnectCloseMeta = { code, reason };
|
|
36125
|
+
try {
|
|
36126
|
+
beginFirehoseDeferredDisconnect(firehoseCtx(), code, reason, logFn);
|
|
36127
|
+
} catch {
|
|
36128
|
+
}
|
|
36129
|
+
try {
|
|
36130
|
+
scheduleFirehoseRetryAfterDrop({ code, reason });
|
|
36131
|
+
} catch {
|
|
36132
|
+
}
|
|
36133
|
+
}
|
|
36134
|
+
};
|
|
36135
|
+
}
|
|
36136
|
+
|
|
36137
|
+
// src/connection/firehose/create-firehose-reconnect-scheduler.ts
|
|
36138
|
+
function createFirehoseReconnectScheduler(ctx, reconnect) {
|
|
36139
|
+
const { state, logFn } = ctx;
|
|
36140
|
+
function clearFirehoseReconnectTimer() {
|
|
36141
|
+
if (state.firehoseReconnectTimeout != null) {
|
|
36142
|
+
clearTimeout(state.firehoseReconnectTimeout);
|
|
36143
|
+
state.firehoseReconnectTimeout = null;
|
|
36144
|
+
}
|
|
36145
|
+
}
|
|
35969
36146
|
function scheduleFirehoseRetryAfterDrop(closeMeta) {
|
|
35970
36147
|
if (state.closedByUser) return;
|
|
35971
36148
|
const meta = closeMeta ?? state.lastFirehoseReconnectCloseMeta ?? void 0;
|
|
@@ -35987,30 +36164,60 @@ function attachFirehoseAfterIdentified(ctx, params) {
|
|
|
35987
36164
|
state.firehoseReconnectTimeout = id;
|
|
35988
36165
|
},
|
|
35989
36166
|
shouldAbortBeforeRun: () => state.closedByUser,
|
|
35990
|
-
run:
|
|
35991
|
-
const p = state.lastFirehoseParams;
|
|
35992
|
-
if (!p) return;
|
|
35993
|
-
attachFirehoseAfterIdentified(ctx, p);
|
|
35994
|
-
},
|
|
36167
|
+
run: reconnect,
|
|
35995
36168
|
reschedule: () => {
|
|
35996
36169
|
scheduleFirehoseRetryAfterDrop();
|
|
35997
36170
|
}
|
|
35998
36171
|
});
|
|
35999
36172
|
}
|
|
36000
|
-
|
|
36001
|
-
|
|
36002
|
-
|
|
36003
|
-
|
|
36004
|
-
|
|
36005
|
-
|
|
36006
|
-
|
|
36173
|
+
return { clearFirehoseReconnectTimer, scheduleFirehoseRetryAfterDrop };
|
|
36174
|
+
}
|
|
36175
|
+
function logInitialFirehoseConnect(state, logFn) {
|
|
36176
|
+
if (state.firehoseReconnectAttempt !== 0) return;
|
|
36177
|
+
try {
|
|
36178
|
+
logFn("Connecting to preview tunnel (local HTTP proxy and dev logs)\u2026");
|
|
36179
|
+
} catch {
|
|
36007
36180
|
}
|
|
36181
|
+
}
|
|
36182
|
+
function replaceFirehoseHandle(state) {
|
|
36008
36183
|
state.firehoseGeneration += 1;
|
|
36009
36184
|
const myGen = state.firehoseGeneration;
|
|
36010
36185
|
if (state.firehoseHandle) {
|
|
36011
36186
|
state.firehoseHandle.close();
|
|
36012
36187
|
state.firehoseHandle = null;
|
|
36013
36188
|
}
|
|
36189
|
+
return myGen;
|
|
36190
|
+
}
|
|
36191
|
+
|
|
36192
|
+
// src/connection/firehose/attach-firehose-after-identified.ts
|
|
36193
|
+
function attachFirehoseAfterIdentified(ctx, params) {
|
|
36194
|
+
const { state, previewEnvironmentManager, logFn } = ctx;
|
|
36195
|
+
const prev = state.lastFirehoseParams;
|
|
36196
|
+
if (shouldReuseOpenFirehoseConnection(prev, params, () => state.firehoseHandle?.isConnected() ?? false)) {
|
|
36197
|
+
state.lastFirehoseParams = params;
|
|
36198
|
+
if (prev && !proxyPortsEqual(prev.proxyPorts, params.proxyPorts)) {
|
|
36199
|
+
state.firehoseHandle?.updateIdentify(params);
|
|
36200
|
+
}
|
|
36201
|
+
return;
|
|
36202
|
+
}
|
|
36203
|
+
const { clearFirehoseReconnectTimer, scheduleFirehoseRetryAfterDrop } = createFirehoseReconnectScheduler(
|
|
36204
|
+
ctx,
|
|
36205
|
+
() => {
|
|
36206
|
+
const p = state.lastFirehoseParams;
|
|
36207
|
+
if (!p) return;
|
|
36208
|
+
attachFirehoseAfterIdentified(ctx, p);
|
|
36209
|
+
}
|
|
36210
|
+
);
|
|
36211
|
+
state.lastFirehoseParams = params;
|
|
36212
|
+
clearFirehoseReconnectTimer();
|
|
36213
|
+
logInitialFirehoseConnect(state, logFn);
|
|
36214
|
+
const myGen = replaceFirehoseHandle(state);
|
|
36215
|
+
const { onOpen, onClose } = createFirehoseConnectCallbacks(
|
|
36216
|
+
state,
|
|
36217
|
+
myGen,
|
|
36218
|
+
logFn,
|
|
36219
|
+
scheduleFirehoseRetryAfterDrop
|
|
36220
|
+
);
|
|
36014
36221
|
state.firehoseHandle = connectFirehose({
|
|
36015
36222
|
firehoseServerUrl: params.firehoseServerUrl,
|
|
36016
36223
|
workspaceId: params.workspaceId,
|
|
@@ -36019,45 +36226,17 @@ function attachFirehoseAfterIdentified(ctx, params) {
|
|
|
36019
36226
|
log: logFn,
|
|
36020
36227
|
previewEnvironmentManager,
|
|
36021
36228
|
suppressWebSocketErrors: () => !state.closedByUser && state.firehoseOutage.startedAt != null,
|
|
36022
|
-
onOpen
|
|
36023
|
-
|
|
36024
|
-
try {
|
|
36025
|
-
clearFirehoseReconnectQuietOnOpen(
|
|
36026
|
-
{
|
|
36027
|
-
firehoseQuiet: state.firehoseQuiet,
|
|
36028
|
-
firehoseOutage: state.firehoseOutage,
|
|
36029
|
-
lastFirehoseReconnectCloseMeta: state.lastFirehoseReconnectCloseMeta
|
|
36030
|
-
},
|
|
36031
|
-
logFn
|
|
36032
|
-
);
|
|
36033
|
-
} catch {
|
|
36034
|
-
}
|
|
36035
|
-
const logOpenAsFirehoseReconnect = state.firehoseReconnectAttempt > 0;
|
|
36036
|
-
state.firehoseReconnectAttempt = 0;
|
|
36037
|
-
if (!logOpenAsFirehoseReconnect) {
|
|
36038
|
-
try {
|
|
36039
|
-
logFn("Connected to preview tunnel (local HTTP proxy and dev logs).");
|
|
36040
|
-
} catch {
|
|
36041
|
-
}
|
|
36042
|
-
}
|
|
36043
|
-
},
|
|
36044
|
-
onClose: (code, reason) => {
|
|
36045
|
-
if (myGen !== state.firehoseGeneration) return;
|
|
36046
|
-
state.firehoseHandle = null;
|
|
36047
|
-
if (state.closedByUser) return;
|
|
36048
|
-
state.lastFirehoseReconnectCloseMeta = { code, reason };
|
|
36049
|
-
try {
|
|
36050
|
-
beginFirehoseDeferredDisconnect(firehoseCtx(), code, reason, logFn);
|
|
36051
|
-
} catch {
|
|
36052
|
-
}
|
|
36053
|
-
try {
|
|
36054
|
-
scheduleFirehoseRetryAfterDrop({ code, reason });
|
|
36055
|
-
} catch {
|
|
36056
|
-
}
|
|
36057
|
-
}
|
|
36229
|
+
onOpen,
|
|
36230
|
+
onClose
|
|
36058
36231
|
});
|
|
36059
36232
|
}
|
|
36060
36233
|
|
|
36234
|
+
// src/connection/firehose/update-firehose-identify-on-open-connection.ts
|
|
36235
|
+
function updateFirehoseIdentifyOnOpenConnection(state, params) {
|
|
36236
|
+
state.lastFirehoseParams = params;
|
|
36237
|
+
state.firehoseHandle?.updateIdentify(params);
|
|
36238
|
+
}
|
|
36239
|
+
|
|
36061
36240
|
// src/connection/create-bridge-identified-handler.ts
|
|
36062
36241
|
function createOnBridgeIdentified(opts) {
|
|
36063
36242
|
const { previewEnvironmentManager, firehoseServerUrl, workspaceId, state, logFn } = opts;
|
|
@@ -36094,6 +36273,7 @@ function createBridgeMessageDeps(params) {
|
|
|
36094
36273
|
reportAutoDetectedAgents,
|
|
36095
36274
|
warmupAgentCapabilitiesOnConnect: warmupAgentCapabilitiesOnConnect2,
|
|
36096
36275
|
previewEnvironmentManager,
|
|
36276
|
+
updateFirehoseProxyPorts,
|
|
36097
36277
|
e2ee,
|
|
36098
36278
|
cloudApiBaseUrl,
|
|
36099
36279
|
getCloudAccessToken
|
|
@@ -36112,6 +36292,7 @@ function createBridgeMessageDeps(params) {
|
|
|
36112
36292
|
reportAutoDetectedAgents,
|
|
36113
36293
|
warmupAgentCapabilitiesOnConnect: warmupAgentCapabilitiesOnConnect2,
|
|
36114
36294
|
previewEnvironmentManager,
|
|
36295
|
+
updateFirehoseProxyPorts,
|
|
36115
36296
|
e2ee,
|
|
36116
36297
|
cloudApiBaseUrl,
|
|
36117
36298
|
getCloudAccessToken
|
|
@@ -36372,6 +36553,11 @@ function createBridgeRuntimeMessageSetup(options) {
|
|
|
36372
36553
|
getWs
|
|
36373
36554
|
}),
|
|
36374
36555
|
previewEnvironmentManager,
|
|
36556
|
+
updateFirehoseProxyPorts: (proxyPorts) => {
|
|
36557
|
+
const p = state.lastFirehoseParams;
|
|
36558
|
+
if (!p) return;
|
|
36559
|
+
updateFirehoseIdentifyOnOpenConnection(state, { ...p, proxyPorts });
|
|
36560
|
+
},
|
|
36375
36561
|
e2ee,
|
|
36376
36562
|
cloudApiBaseUrl: apiUrl,
|
|
36377
36563
|
getCloudAccessToken: () => tokens.accessToken
|
|
@@ -43641,16 +43827,16 @@ async function applySessionWipToPreviewCheckouts(options) {
|
|
|
43641
43827
|
return;
|
|
43642
43828
|
}
|
|
43643
43829
|
await gitResetWorktreeToBranch(previewCheckout, deployBranch);
|
|
43644
|
-
const
|
|
43830
|
+
const applied = await applyWorkingTreeWip(
|
|
43645
43831
|
previewCheckout,
|
|
43646
43832
|
state.sessionCheckout,
|
|
43647
43833
|
state.wip,
|
|
43648
43834
|
log2
|
|
43649
43835
|
);
|
|
43650
|
-
if (!
|
|
43836
|
+
if (!applied.ok) {
|
|
43651
43837
|
failure = {
|
|
43652
43838
|
ok: false,
|
|
43653
|
-
error:
|
|
43839
|
+
error: applied.error ?? `Failed to apply session WIP to preview (${state.repoPathRelativeToWorkspaceRoot})`
|
|
43654
43840
|
};
|
|
43655
43841
|
}
|
|
43656
43842
|
});
|
|
@@ -43749,7 +43935,7 @@ async function deploySessionToPreviewEnvironment(options) {
|
|
|
43749
43935
|
return { ok: false, error: "Failed to create preview environment worktrees" };
|
|
43750
43936
|
}
|
|
43751
43937
|
await yieldToEventLoop2();
|
|
43752
|
-
const
|
|
43938
|
+
const applied = await applySessionWipToPreviewCheckouts({
|
|
43753
43939
|
previewWorktreeManager,
|
|
43754
43940
|
environmentId: eid,
|
|
43755
43941
|
deployBranch,
|
|
@@ -43757,8 +43943,8 @@ async function deploySessionToPreviewEnvironment(options) {
|
|
|
43757
43943
|
repoStates,
|
|
43758
43944
|
log: log2
|
|
43759
43945
|
});
|
|
43760
|
-
if (!
|
|
43761
|
-
return { ok: false, error:
|
|
43946
|
+
if (!applied.ok) {
|
|
43947
|
+
return { ok: false, error: applied.error };
|
|
43762
43948
|
}
|
|
43763
43949
|
log2(
|
|
43764
43950
|
`[worktrees] Deployed session ${sid.slice(0, 8)}\u2026 to preview ${eid.slice(0, 8)}\u2026 on branch ${deployBranch}.`
|
|
@@ -46179,12 +46365,17 @@ var handlePreviewEnvironmentControl = (msg, deps) => {
|
|
|
46179
46365
|
};
|
|
46180
46366
|
|
|
46181
46367
|
// src/routing/handlers/preview-environments-config.ts
|
|
46368
|
+
var VALID_PORT = (p) => typeof p === "number" && Number.isInteger(p) && p > 0 && p < 65536;
|
|
46182
46369
|
var handlePreviewEnvironmentsConfig = (msg, deps) => {
|
|
46183
46370
|
const previewEnvironments = msg.previewEnvironments;
|
|
46371
|
+
const proxyPorts = Array.isArray(msg.proxyPorts) ? msg.proxyPorts.filter(VALID_PORT) : void 0;
|
|
46184
46372
|
setImmediate(() => {
|
|
46185
46373
|
deps.previewEnvironmentManager?.applyConfig(previewEnvironments ?? []);
|
|
46186
46374
|
const environmentIds = parsePreviewEnvironmentDefs(previewEnvironments ?? []).map((d) => d.environmentId);
|
|
46187
46375
|
void deps.previewWorktreeManager?.syncConfiguredEnvironments(environmentIds);
|
|
46376
|
+
if (proxyPorts !== void 0) {
|
|
46377
|
+
deps.updateFirehoseProxyPorts?.(proxyPorts);
|
|
46378
|
+
}
|
|
46188
46379
|
});
|
|
46189
46380
|
};
|
|
46190
46381
|
|