@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/cli.js
CHANGED
|
@@ -25631,7 +25631,7 @@ var {
|
|
|
25631
25631
|
} = import_index.default;
|
|
25632
25632
|
|
|
25633
25633
|
// src/cli-version.ts
|
|
25634
|
-
var CLI_VERSION = "0.1.
|
|
25634
|
+
var CLI_VERSION = "0.1.62".length > 0 ? "0.1.62" : "0.0.0-dev";
|
|
25635
25635
|
|
|
25636
25636
|
// src/cli/defaults.ts
|
|
25637
25637
|
var DEFAULT_API_URL = process.env.BUILDAUTOMATON_API_URL ?? "https://api.buildautomaton.com";
|
|
@@ -26151,18 +26151,6 @@ var import_websocket = __toESM(require_websocket(), 1);
|
|
|
26151
26151
|
var import_websocket_server = __toESM(require_websocket_server(), 1);
|
|
26152
26152
|
var wrapper_default = import_websocket.default;
|
|
26153
26153
|
|
|
26154
|
-
// src/net/apply-cli-outbound-network-prefs.ts
|
|
26155
|
-
import dns from "node:dns";
|
|
26156
|
-
var applied = false;
|
|
26157
|
-
function applyCliOutboundNetworkPreferences() {
|
|
26158
|
-
if (applied) return;
|
|
26159
|
-
applied = true;
|
|
26160
|
-
try {
|
|
26161
|
-
dns.setDefaultResultOrder("ipv4first");
|
|
26162
|
-
} catch {
|
|
26163
|
-
}
|
|
26164
|
-
}
|
|
26165
|
-
|
|
26166
26154
|
// src/connection/cli-ws-client.ts
|
|
26167
26155
|
import https from "node:https";
|
|
26168
26156
|
var CLI_WEBSOCKET_CLIENT_PING_MS = 25e3;
|
|
@@ -26264,7 +26252,6 @@ function createWsBridge(options) {
|
|
|
26264
26252
|
onCompactHeartbeatAck,
|
|
26265
26253
|
isActiveSocket
|
|
26266
26254
|
} = options;
|
|
26267
|
-
applyCliOutboundNetworkPreferences();
|
|
26268
26255
|
const ws = new wrapper_default(url2, buildCliWebSocketClientOptions(url2));
|
|
26269
26256
|
let clearClientPing = null;
|
|
26270
26257
|
function disposeClientPing() {
|
|
@@ -27706,38 +27693,38 @@ function readCodeNavCacheMigrationSql(filename) {
|
|
|
27706
27693
|
}
|
|
27707
27694
|
|
|
27708
27695
|
// src/sqlite/run-sqlite-migrations.ts
|
|
27709
|
-
function checkpointSatisfiedByLegacyChain(
|
|
27710
|
-
return Array.isArray(replacesLegacyMigrations) && replacesLegacyMigrations.length > 0 && replacesLegacyMigrations.every((n) =>
|
|
27696
|
+
function checkpointSatisfiedByLegacyChain(applied, replacesLegacyMigrations) {
|
|
27697
|
+
return Array.isArray(replacesLegacyMigrations) && replacesLegacyMigrations.length > 0 && replacesLegacyMigrations.every((n) => applied.has(n));
|
|
27711
27698
|
}
|
|
27712
|
-
function recordMigrationAndPruneCheckpointLegacy(db, migration,
|
|
27699
|
+
function recordMigrationAndPruneCheckpointLegacy(db, migration, applied) {
|
|
27713
27700
|
db.run("INSERT INTO __migrations (name) VALUES (?)", [migration.name]);
|
|
27714
|
-
|
|
27701
|
+
applied.add(migration.name);
|
|
27715
27702
|
if (migration.checkpoint !== true) return;
|
|
27716
27703
|
const legacy = migration.replacesLegacyMigrations;
|
|
27717
27704
|
if (!legacy?.length) return;
|
|
27718
27705
|
for (const legacyName of legacy) {
|
|
27719
27706
|
if (legacyName === migration.name) continue;
|
|
27720
27707
|
db.run("DELETE FROM __migrations WHERE name = ?", [legacyName]);
|
|
27721
|
-
|
|
27708
|
+
applied.delete(legacyName);
|
|
27722
27709
|
}
|
|
27723
27710
|
}
|
|
27724
27711
|
function runSqliteMigrations(db, migrations, bootstrapSql, label) {
|
|
27725
27712
|
db.exec(bootstrapSql);
|
|
27726
27713
|
const appliedRows = db.all("SELECT name FROM __migrations");
|
|
27727
|
-
const
|
|
27714
|
+
const applied = new Set(appliedRows.map((r) => r.name));
|
|
27728
27715
|
for (const migration of migrations) {
|
|
27729
|
-
if (
|
|
27730
|
-
if (migration.checkpoint === true && checkpointSatisfiedByLegacyChain(
|
|
27731
|
-
recordMigrationAndPruneCheckpointLegacy(db, migration,
|
|
27716
|
+
if (applied.has(migration.name)) continue;
|
|
27717
|
+
if (migration.checkpoint === true && checkpointSatisfiedByLegacyChain(applied, migration.replacesLegacyMigrations)) {
|
|
27718
|
+
recordMigrationAndPruneCheckpointLegacy(db, migration, applied);
|
|
27732
27719
|
continue;
|
|
27733
27720
|
}
|
|
27734
27721
|
if (migration.alreadyApplied?.(db)) {
|
|
27735
|
-
recordMigrationAndPruneCheckpointLegacy(db, migration,
|
|
27722
|
+
recordMigrationAndPruneCheckpointLegacy(db, migration, applied);
|
|
27736
27723
|
continue;
|
|
27737
27724
|
}
|
|
27738
27725
|
try {
|
|
27739
27726
|
migration.migrate(db);
|
|
27740
|
-
recordMigrationAndPruneCheckpointLegacy(db, migration,
|
|
27727
|
+
recordMigrationAndPruneCheckpointLegacy(db, migration, applied);
|
|
27741
27728
|
} catch (e) {
|
|
27742
27729
|
console.error(`[${label}] Migration failed: ${migration.name}`, e);
|
|
27743
27730
|
throw e;
|
|
@@ -37713,6 +37700,9 @@ function envForSpawn(base, userEnv, ports) {
|
|
|
37713
37700
|
});
|
|
37714
37701
|
if (ports.length > 0) {
|
|
37715
37702
|
out.PORTS = ports.join(",");
|
|
37703
|
+
if (!userKeys.has("PORT")) {
|
|
37704
|
+
out.PORT = String(ports[0]);
|
|
37705
|
+
}
|
|
37716
37706
|
}
|
|
37717
37707
|
if (!userKeys.has("NO_COLOR")) {
|
|
37718
37708
|
delete out.NO_COLOR;
|
|
@@ -38615,172 +38605,189 @@ function createBridgePreviewStack(options) {
|
|
|
38615
38605
|
return { previewEnvironmentManager, scheduleInitialIndexBuildsOnce, identifyReportedPaths };
|
|
38616
38606
|
}
|
|
38617
38607
|
|
|
38618
|
-
// src/
|
|
38619
|
-
|
|
38620
|
-
|
|
38621
|
-
return
|
|
38622
|
-
}
|
|
38623
|
-
function collectErrorText(err) {
|
|
38624
|
-
const parts = [];
|
|
38625
|
-
let e = err;
|
|
38626
|
-
for (let depth = 0; depth < 6 && e != null; depth += 1) {
|
|
38627
|
-
if (e instanceof Error) {
|
|
38628
|
-
parts.push(e.message);
|
|
38629
|
-
e = e.cause;
|
|
38630
|
-
} else {
|
|
38631
|
-
parts.push(String(e));
|
|
38632
|
-
break;
|
|
38633
|
-
}
|
|
38634
|
-
}
|
|
38635
|
-
return parts.join(" ").toLowerCase();
|
|
38636
|
-
}
|
|
38637
|
-
function isTransientLocalServiceError(err) {
|
|
38638
|
-
const text = collectErrorText(err);
|
|
38639
|
-
if (!text) return false;
|
|
38640
|
-
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");
|
|
38608
|
+
// src/firehose/build-cli-ws-url.ts
|
|
38609
|
+
function buildFirehoseCliWsUrl(baseUrl) {
|
|
38610
|
+
const base = baseUrl.startsWith("https") ? baseUrl.replace(/^https/, "wss") : baseUrl.replace(/^http/, "ws");
|
|
38611
|
+
return `${base.replace(/\/$/, "")}/ws`;
|
|
38641
38612
|
}
|
|
38642
|
-
|
|
38643
|
-
|
|
38644
|
-
|
|
38613
|
+
|
|
38614
|
+
// src/firehose/proxy/prepare-local-proxy-request-headers.ts
|
|
38615
|
+
var HOP_BY_HOP_HEADERS = /* @__PURE__ */ new Set([
|
|
38616
|
+
"connection",
|
|
38617
|
+
"keep-alive",
|
|
38618
|
+
"proxy-authenticate",
|
|
38619
|
+
"proxy-authorization",
|
|
38620
|
+
"te",
|
|
38621
|
+
"trailers",
|
|
38622
|
+
"transfer-encoding",
|
|
38623
|
+
"upgrade"
|
|
38624
|
+
]);
|
|
38625
|
+
var BODY_HEADERS = /* @__PURE__ */ new Set(["content-length", "content-type", "content-encoding"]);
|
|
38626
|
+
function methodAllowsRequestBody(method) {
|
|
38627
|
+
const normalized = method.toUpperCase();
|
|
38628
|
+
return normalized !== "GET" && normalized !== "HEAD";
|
|
38645
38629
|
}
|
|
38646
|
-
|
|
38647
|
-
const
|
|
38648
|
-
const
|
|
38649
|
-
|
|
38650
|
-
|
|
38651
|
-
|
|
38652
|
-
|
|
38653
|
-
|
|
38654
|
-
|
|
38655
|
-
} catch (e) {
|
|
38656
|
-
lastErr = e;
|
|
38657
|
-
const canRetry = allowRetry && attempt < maxAttempts - 1 && isTransientLocalServiceError(e);
|
|
38658
|
-
if (!canRetry) throw e;
|
|
38659
|
-
const waitMs = delays[Math.min(attempt, delays.length - 1)] ?? 100;
|
|
38660
|
-
await sleepMs(waitMs);
|
|
38661
|
-
}
|
|
38630
|
+
function prepareLocalProxyRequestHeaders(method, headers, sendingBody) {
|
|
38631
|
+
const out = {};
|
|
38632
|
+
for (const [key, value] of Object.entries(headers ?? {})) {
|
|
38633
|
+
const lower = key.toLowerCase();
|
|
38634
|
+
if (lower === "host") continue;
|
|
38635
|
+
if (HOP_BY_HOP_HEADERS.has(lower)) continue;
|
|
38636
|
+
if (lower === "origin" || lower === "referer") continue;
|
|
38637
|
+
if (!sendingBody && BODY_HEADERS.has(lower)) continue;
|
|
38638
|
+
out[key] = value;
|
|
38662
38639
|
}
|
|
38663
|
-
|
|
38640
|
+
return out;
|
|
38664
38641
|
}
|
|
38665
38642
|
|
|
38666
|
-
// src/firehose/proxy/local-proxy.ts
|
|
38667
|
-
var ALLOWED_HOSTS = ["localhost", "127.0.0.1", "::1"];
|
|
38668
|
-
function
|
|
38669
|
-
|
|
38670
|
-
return
|
|
38643
|
+
// src/firehose/proxy/build-local-proxy-http-request.ts
|
|
38644
|
+
var ALLOWED_HOSTS = /* @__PURE__ */ new Set(["localhost", "127.0.0.1", "::1"]);
|
|
38645
|
+
function willSendLocalProxyBody(request) {
|
|
38646
|
+
if (!methodAllowsRequestBody(request.method)) return false;
|
|
38647
|
+
return request.body !== void 0 && request.body !== null;
|
|
38671
38648
|
}
|
|
38672
|
-
function
|
|
38673
|
-
const m = method.toUpperCase();
|
|
38674
|
-
return m === "GET" || m === "HEAD" || m === "OPTIONS";
|
|
38675
|
-
}
|
|
38676
|
-
function checkUrlAndHost(request) {
|
|
38649
|
+
function buildLocalProxyHttpRequest(request) {
|
|
38677
38650
|
let url2;
|
|
38678
38651
|
try {
|
|
38679
38652
|
url2 = new URL(request.url);
|
|
38680
38653
|
} catch {
|
|
38681
38654
|
return { error: `Invalid URL: ${request.url}` };
|
|
38682
38655
|
}
|
|
38683
|
-
|
|
38656
|
+
const hostname2 = url2.hostname.replace(/^\[|\]$/g, "");
|
|
38657
|
+
if (!ALLOWED_HOSTS.has(url2.hostname) && !ALLOWED_HOSTS.has(hostname2)) {
|
|
38684
38658
|
return { error: "Only localhost requests are allowed" };
|
|
38685
38659
|
}
|
|
38686
|
-
|
|
38687
|
-
|
|
38688
|
-
|
|
38689
|
-
const checked = checkUrlAndHost(request);
|
|
38690
|
-
if ("error" in checked) {
|
|
38691
|
-
return { id: request.id, statusCode: 0, headers: {}, body: "", error: checked.error };
|
|
38692
|
-
}
|
|
38693
|
-
const { url: url2 } = checked;
|
|
38660
|
+
const sendingBody = willSendLocalProxyBody(request);
|
|
38661
|
+
const headers = prepareLocalProxyRequestHeaders(request.method, request.headers, sendingBody);
|
|
38662
|
+
headers.host = url2.host;
|
|
38694
38663
|
const isHttps = url2.protocol === "https:";
|
|
38695
|
-
const
|
|
38696
|
-
|
|
38664
|
+
const port = url2.port ? Number(url2.port) : isHttps ? 443 : 80;
|
|
38665
|
+
return {
|
|
38697
38666
|
method: request.method,
|
|
38698
38667
|
hostname: url2.hostname,
|
|
38699
|
-
port
|
|
38700
|
-
path: url2.pathname
|
|
38701
|
-
headers
|
|
38668
|
+
port,
|
|
38669
|
+
path: `${url2.pathname}${url2.search}`,
|
|
38670
|
+
headers,
|
|
38671
|
+
sendingBody,
|
|
38672
|
+
body: sendingBody ? request.body : void 0
|
|
38702
38673
|
};
|
|
38703
|
-
|
|
38704
|
-
|
|
38705
|
-
|
|
38706
|
-
|
|
38707
|
-
|
|
38708
|
-
|
|
38709
|
-
|
|
38710
|
-
|
|
38711
|
-
|
|
38712
|
-
|
|
38713
|
-
|
|
38714
|
-
|
|
38715
|
-
|
|
38716
|
-
|
|
38717
|
-
|
|
38718
|
-
|
|
38719
|
-
|
|
38720
|
-
|
|
38721
|
-
|
|
38674
|
+
}
|
|
38675
|
+
|
|
38676
|
+
// src/firehose/proxy/constants.ts
|
|
38677
|
+
var LOCAL_PROXY_REQUEST_TIMEOUT_MS = 3e4;
|
|
38678
|
+
|
|
38679
|
+
// src/firehose/proxy/incoming-message-headers.ts
|
|
38680
|
+
function incomingMessageHeaders(res) {
|
|
38681
|
+
const headers = {};
|
|
38682
|
+
for (const [k, v] of Object.entries(res.headers)) {
|
|
38683
|
+
if (typeof v === "string") headers[k] = v;
|
|
38684
|
+
else if (Array.isArray(v) && v[0]) headers[k] = v[0];
|
|
38685
|
+
}
|
|
38686
|
+
return headers;
|
|
38687
|
+
}
|
|
38688
|
+
|
|
38689
|
+
// src/firehose/proxy/run-local-http-request.ts
|
|
38690
|
+
async function loadHttpModule(isHttps) {
|
|
38691
|
+
return isHttps ? import("https") : import("http");
|
|
38692
|
+
}
|
|
38693
|
+
function buildLocalHttpRequestOptions(built) {
|
|
38694
|
+
return {
|
|
38695
|
+
method: built.method,
|
|
38696
|
+
hostname: built.hostname,
|
|
38697
|
+
port: built.port,
|
|
38698
|
+
path: built.path,
|
|
38699
|
+
headers: built.headers
|
|
38700
|
+
};
|
|
38701
|
+
}
|
|
38702
|
+
function runLocalHttpRequestOnce(mod, built) {
|
|
38703
|
+
const opts = buildLocalHttpRequestOptions(built);
|
|
38704
|
+
return new Promise((resolve37) => {
|
|
38705
|
+
const req = mod.request(opts, (res) => {
|
|
38706
|
+
const chunks = [];
|
|
38707
|
+
res.on("data", (chunk) => chunks.push(chunk));
|
|
38708
|
+
res.on("end", () => {
|
|
38709
|
+
resolve37({
|
|
38710
|
+
statusCode: res.statusCode ?? 0,
|
|
38711
|
+
headers: incomingMessageHeaders(res),
|
|
38712
|
+
body: Buffer.concat(chunks)
|
|
38722
38713
|
});
|
|
38723
38714
|
});
|
|
38724
|
-
|
|
38715
|
+
res.on("error", (err) => {
|
|
38725
38716
|
resolve37({
|
|
38726
|
-
id: request.id,
|
|
38727
38717
|
statusCode: 0,
|
|
38728
38718
|
headers: {},
|
|
38729
|
-
body:
|
|
38719
|
+
body: Buffer.alloc(0),
|
|
38730
38720
|
error: err.message
|
|
38731
38721
|
});
|
|
38732
38722
|
});
|
|
38733
|
-
const method = request.method.toUpperCase();
|
|
38734
|
-
if (request.body && method !== "GET" && method !== "HEAD") req.write(request.body);
|
|
38735
|
-
req.end();
|
|
38736
38723
|
});
|
|
38737
|
-
|
|
38738
|
-
|
|
38739
|
-
|
|
38740
|
-
|
|
38741
|
-
|
|
38742
|
-
|
|
38743
|
-
|
|
38724
|
+
req.setTimeout(LOCAL_PROXY_REQUEST_TIMEOUT_MS, () => {
|
|
38725
|
+
req.destroy(new Error(`Local preview request timed out after ${LOCAL_PROXY_REQUEST_TIMEOUT_MS}ms`));
|
|
38726
|
+
});
|
|
38727
|
+
req.on("error", (err) => {
|
|
38728
|
+
resolve37({
|
|
38729
|
+
statusCode: 0,
|
|
38730
|
+
headers: {},
|
|
38731
|
+
body: Buffer.alloc(0),
|
|
38732
|
+
error: err.message
|
|
38733
|
+
});
|
|
38734
|
+
});
|
|
38735
|
+
if (built.sendingBody && built.body != null) {
|
|
38736
|
+
req.write(built.body);
|
|
38737
|
+
}
|
|
38738
|
+
req.end();
|
|
38739
|
+
});
|
|
38744
38740
|
}
|
|
38741
|
+
|
|
38742
|
+
// src/firehose/proxy/proxy-to-local-streaming.ts
|
|
38745
38743
|
async function proxyToLocalStreaming(request, callbacks) {
|
|
38746
|
-
const
|
|
38747
|
-
if ("error" in
|
|
38748
|
-
callbacks.onError(
|
|
38744
|
+
const built = buildLocalProxyHttpRequest(request);
|
|
38745
|
+
if ("error" in built) {
|
|
38746
|
+
callbacks.onError(built.error);
|
|
38749
38747
|
return;
|
|
38750
38748
|
}
|
|
38751
|
-
|
|
38752
|
-
|
|
38753
|
-
|
|
38754
|
-
|
|
38755
|
-
|
|
38756
|
-
|
|
38757
|
-
|
|
38758
|
-
|
|
38759
|
-
|
|
38760
|
-
|
|
38761
|
-
|
|
38762
|
-
|
|
38763
|
-
headers[key] = value;
|
|
38764
|
-
});
|
|
38765
|
-
callbacks.onStart(res.status, headers);
|
|
38766
|
-
const reader = res.body?.getReader();
|
|
38767
|
-
if (!reader) {
|
|
38768
|
-
callbacks.onEnd();
|
|
38769
|
-
return;
|
|
38770
|
-
}
|
|
38771
|
-
try {
|
|
38772
|
-
for (; ; ) {
|
|
38773
|
-
const { done, value } = await reader.read();
|
|
38774
|
-
if (done) break;
|
|
38775
|
-
callbacks.onChunk(value);
|
|
38749
|
+
const isHttps = request.url.startsWith("https:");
|
|
38750
|
+
const mod = await loadHttpModule(isHttps);
|
|
38751
|
+
const opts = buildLocalHttpRequestOptions(built);
|
|
38752
|
+
await new Promise((resolve37) => {
|
|
38753
|
+
const req = mod.request(opts, (res) => {
|
|
38754
|
+
try {
|
|
38755
|
+
callbacks.onStart(res.statusCode ?? 0, incomingMessageHeaders(res));
|
|
38756
|
+
} catch (err) {
|
|
38757
|
+
req.destroy();
|
|
38758
|
+
callbacks.onError(err instanceof Error ? err.message : String(err));
|
|
38759
|
+
resolve37();
|
|
38760
|
+
return;
|
|
38776
38761
|
}
|
|
38777
|
-
|
|
38778
|
-
|
|
38762
|
+
res.on("data", (chunk) => {
|
|
38763
|
+
try {
|
|
38764
|
+
callbacks.onChunk(new Uint8Array(chunk));
|
|
38765
|
+
} catch (err) {
|
|
38766
|
+
req.destroy();
|
|
38767
|
+
callbacks.onError(err instanceof Error ? err.message : String(err));
|
|
38768
|
+
}
|
|
38769
|
+
});
|
|
38770
|
+
res.on("end", () => {
|
|
38771
|
+
callbacks.onEnd();
|
|
38772
|
+
resolve37();
|
|
38773
|
+
});
|
|
38774
|
+
res.on("error", (err) => {
|
|
38775
|
+
callbacks.onError(err.message);
|
|
38776
|
+
resolve37();
|
|
38777
|
+
});
|
|
38778
|
+
});
|
|
38779
|
+
req.setTimeout(LOCAL_PROXY_REQUEST_TIMEOUT_MS, () => {
|
|
38780
|
+
req.destroy(new Error(`Local preview request timed out after ${LOCAL_PROXY_REQUEST_TIMEOUT_MS}ms`));
|
|
38781
|
+
});
|
|
38782
|
+
req.on("error", (err) => {
|
|
38783
|
+
callbacks.onError(err.message);
|
|
38784
|
+
resolve37();
|
|
38785
|
+
});
|
|
38786
|
+
if (built.sendingBody && built.body != null) {
|
|
38787
|
+
req.write(built.body);
|
|
38779
38788
|
}
|
|
38780
|
-
|
|
38781
|
-
}
|
|
38782
|
-
callbacks.onError(err instanceof Error ? err.message : String(err));
|
|
38783
|
-
}
|
|
38789
|
+
req.end();
|
|
38790
|
+
});
|
|
38784
38791
|
}
|
|
38785
38792
|
|
|
38786
38793
|
// src/firehose/proxy/start-streaming-proxy.ts
|
|
@@ -38790,15 +38797,7 @@ function startStreamingProxy(ws, log2, pr) {
|
|
|
38790
38797
|
if (ws.readyState !== wrapper_default.OPEN) {
|
|
38791
38798
|
throw new Error("Preview stream interrupted (firehose connection closed)");
|
|
38792
38799
|
}
|
|
38793
|
-
|
|
38794
|
-
const ce = "content-encoding";
|
|
38795
|
-
const cl = "content-length";
|
|
38796
|
-
const keys = Object.keys(forwardedHeaders).filter(
|
|
38797
|
-
(k) => k.toLowerCase() !== ce && k.toLowerCase() !== cl
|
|
38798
|
-
);
|
|
38799
|
-
const filtered = {};
|
|
38800
|
-
for (const k of keys) if (forwardedHeaders[k] != null) filtered[k] = forwardedHeaders[k];
|
|
38801
|
-
sendWsMessage(ws, { type: "proxy_result_start", id: pr.id, statusCode, headers: filtered });
|
|
38800
|
+
sendWsMessage(ws, { type: "proxy_result_start", id: pr.id, statusCode, headers });
|
|
38802
38801
|
},
|
|
38803
38802
|
onChunk: (chunk) => {
|
|
38804
38803
|
const idBuf = Buffer.from(pr.id, "utf8");
|
|
@@ -38815,10 +38814,19 @@ function startStreamingProxy(ws, log2, pr) {
|
|
|
38815
38814
|
});
|
|
38816
38815
|
}
|
|
38817
38816
|
|
|
38818
|
-
// src/firehose/
|
|
38819
|
-
function
|
|
38820
|
-
const
|
|
38821
|
-
|
|
38817
|
+
// src/firehose/create-firehose-message-deps.ts
|
|
38818
|
+
function createFirehoseMessageDeps(ws, log2, previewEnvironmentManager) {
|
|
38819
|
+
const pendingProxyBody = /* @__PURE__ */ new Map();
|
|
38820
|
+
const earlyProxyBinaryBody = /* @__PURE__ */ new Map();
|
|
38821
|
+
const deps = {
|
|
38822
|
+
ws,
|
|
38823
|
+
log: log2,
|
|
38824
|
+
previewEnvironmentManager,
|
|
38825
|
+
pendingProxyBody,
|
|
38826
|
+
earlyProxyBinaryBody,
|
|
38827
|
+
startStreamingProxy: (pr) => startStreamingProxy(ws, log2, pr)
|
|
38828
|
+
};
|
|
38829
|
+
return deps;
|
|
38822
38830
|
}
|
|
38823
38831
|
|
|
38824
38832
|
// src/firehose/routing/firehose-message-router.ts
|
|
@@ -38853,31 +38861,90 @@ var handlePreviewEnvironmentLogsViewerClose = (msg, deps) => {
|
|
|
38853
38861
|
deps.previewEnvironmentManager.handleFirehoseLogViewerClose(environmentId, viewerId);
|
|
38854
38862
|
};
|
|
38855
38863
|
|
|
38864
|
+
// src/net/transient-local-fetch-retry.ts
|
|
38865
|
+
var LOCAL_PREVIEW_FETCH_RETRY_DELAYS_MS = [30, 100, 200, 400];
|
|
38866
|
+
function sleepMs(ms) {
|
|
38867
|
+
return new Promise((r) => setTimeout(r, ms));
|
|
38868
|
+
}
|
|
38869
|
+
function collectErrorText(err) {
|
|
38870
|
+
const parts = [];
|
|
38871
|
+
let e = err;
|
|
38872
|
+
for (let depth = 0; depth < 6 && e != null; depth += 1) {
|
|
38873
|
+
if (e instanceof Error) {
|
|
38874
|
+
parts.push(e.message);
|
|
38875
|
+
e = e.cause;
|
|
38876
|
+
} else {
|
|
38877
|
+
parts.push(String(e));
|
|
38878
|
+
break;
|
|
38879
|
+
}
|
|
38880
|
+
}
|
|
38881
|
+
return parts.join(" ").toLowerCase();
|
|
38882
|
+
}
|
|
38883
|
+
function isTransientLocalServiceError(err) {
|
|
38884
|
+
const text = collectErrorText(err);
|
|
38885
|
+
if (!text) return false;
|
|
38886
|
+
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");
|
|
38887
|
+
}
|
|
38888
|
+
|
|
38889
|
+
// src/firehose/proxy/proxy-to-local.ts
|
|
38890
|
+
function isIdempotentProxyMethod(method) {
|
|
38891
|
+
const m = method.toUpperCase();
|
|
38892
|
+
return m === "GET" || m === "HEAD" || m === "OPTIONS";
|
|
38893
|
+
}
|
|
38894
|
+
async function proxyToLocal(request) {
|
|
38895
|
+
const built = buildLocalProxyHttpRequest(request);
|
|
38896
|
+
if ("error" in built) {
|
|
38897
|
+
return { id: request.id, statusCode: 0, headers: {}, body: "", error: built.error };
|
|
38898
|
+
}
|
|
38899
|
+
const isHttps = request.url.startsWith("https:");
|
|
38900
|
+
const mod = await loadHttpModule(isHttps);
|
|
38901
|
+
const maxAttempts = isIdempotentProxyMethod(request.method) ? LOCAL_PREVIEW_FETCH_RETRY_DELAYS_MS.length + 1 : 1;
|
|
38902
|
+
for (let attempt = 0; attempt < maxAttempts; attempt += 1) {
|
|
38903
|
+
const once = await runLocalHttpRequestOnce(mod, built);
|
|
38904
|
+
const errMsg = once.error ?? "";
|
|
38905
|
+
const canRetry = attempt < maxAttempts - 1 && errMsg !== "" && isTransientLocalServiceError(new Error(errMsg));
|
|
38906
|
+
if (!canRetry) {
|
|
38907
|
+
return {
|
|
38908
|
+
id: request.id,
|
|
38909
|
+
statusCode: once.statusCode,
|
|
38910
|
+
headers: once.headers,
|
|
38911
|
+
body: once.body.toString("utf8"),
|
|
38912
|
+
error: once.error
|
|
38913
|
+
};
|
|
38914
|
+
}
|
|
38915
|
+
const waitMs = LOCAL_PREVIEW_FETCH_RETRY_DELAYS_MS[Math.min(attempt, LOCAL_PREVIEW_FETCH_RETRY_DELAYS_MS.length - 1)] ?? 100;
|
|
38916
|
+
await sleepMs(waitMs);
|
|
38917
|
+
}
|
|
38918
|
+
throw new Error("Local proxy retry loop exited unexpectedly");
|
|
38919
|
+
}
|
|
38920
|
+
|
|
38856
38921
|
// src/firehose/routing/handlers/proxy-message.ts
|
|
38857
38922
|
var handleProxyMessage = (msg, deps) => {
|
|
38858
38923
|
const proxy = msg.proxy;
|
|
38859
38924
|
if (!proxy || typeof proxy !== "object") return;
|
|
38860
38925
|
const pr = proxy;
|
|
38861
38926
|
if (pr.streamResponse) {
|
|
38862
|
-
const bodyLength = pr.bodyLength ?? 0;
|
|
38927
|
+
const bodyLength = methodAllowsRequestBody(pr.method) ? pr.bodyLength ?? 0 : 0;
|
|
38928
|
+
const streamingRequest = {
|
|
38929
|
+
id: pr.id,
|
|
38930
|
+
method: pr.method,
|
|
38931
|
+
url: pr.url,
|
|
38932
|
+
headers: pr.headers,
|
|
38933
|
+
streamResponse: true
|
|
38934
|
+
};
|
|
38863
38935
|
if (bodyLength > 0) {
|
|
38864
|
-
deps.
|
|
38865
|
-
|
|
38866
|
-
|
|
38867
|
-
|
|
38868
|
-
|
|
38869
|
-
|
|
38870
|
-
|
|
38871
|
-
|
|
38872
|
-
|
|
38936
|
+
const earlyBody = deps.earlyProxyBinaryBody.get(pr.id);
|
|
38937
|
+
if (earlyBody !== void 0) {
|
|
38938
|
+
deps.earlyProxyBinaryBody.delete(pr.id);
|
|
38939
|
+
deps.startStreamingProxy({
|
|
38940
|
+
...streamingRequest,
|
|
38941
|
+
body: earlyBody.length > 0 ? earlyBody : void 0
|
|
38942
|
+
});
|
|
38943
|
+
} else {
|
|
38944
|
+
deps.pendingProxyBody.set(pr.id, { pr: streamingRequest });
|
|
38945
|
+
}
|
|
38873
38946
|
} else {
|
|
38874
|
-
deps.startStreamingProxy(
|
|
38875
|
-
id: pr.id,
|
|
38876
|
-
method: pr.method,
|
|
38877
|
-
url: pr.url,
|
|
38878
|
-
headers: pr.headers,
|
|
38879
|
-
streamResponse: true
|
|
38880
|
-
});
|
|
38947
|
+
deps.startStreamingProxy(streamingRequest);
|
|
38881
38948
|
}
|
|
38882
38949
|
return;
|
|
38883
38950
|
}
|
|
@@ -38908,37 +38975,63 @@ function dispatchFirehoseJsonMessage(msg, deps) {
|
|
|
38908
38975
|
|
|
38909
38976
|
// src/firehose/routing/try-consume-binary-proxy-body.ts
|
|
38910
38977
|
var PROXY_ID_BYTES = 36;
|
|
38978
|
+
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;
|
|
38911
38979
|
function tryConsumeBinaryProxyBody(raw, deps) {
|
|
38912
38980
|
if (raw.length < PROXY_ID_BYTES) return false;
|
|
38913
38981
|
const id = raw.slice(0, PROXY_ID_BYTES).toString("utf8");
|
|
38914
|
-
|
|
38915
|
-
if (!pending2) return false;
|
|
38916
|
-
deps.pendingProxyBody.delete(id);
|
|
38982
|
+
if (!PROXY_ID_RE.test(id)) return false;
|
|
38917
38983
|
const body = raw.slice(PROXY_ID_BYTES);
|
|
38918
|
-
|
|
38919
|
-
|
|
38920
|
-
|
|
38921
|
-
|
|
38984
|
+
const bodyBytes = body.length > 0 ? new Uint8Array(body) : new Uint8Array(0);
|
|
38985
|
+
const pending2 = deps.pendingProxyBody.get(id);
|
|
38986
|
+
if (pending2) {
|
|
38987
|
+
deps.pendingProxyBody.delete(id);
|
|
38988
|
+
deps.startStreamingProxy({
|
|
38989
|
+
...pending2.pr,
|
|
38990
|
+
body: bodyBytes.length > 0 ? bodyBytes : void 0
|
|
38991
|
+
});
|
|
38992
|
+
return true;
|
|
38993
|
+
}
|
|
38994
|
+
deps.earlyProxyBinaryBody.set(id, bodyBytes);
|
|
38922
38995
|
return true;
|
|
38923
38996
|
}
|
|
38924
38997
|
|
|
38925
|
-
// src/firehose/
|
|
38926
|
-
function
|
|
38998
|
+
// src/firehose/handle-inbound-firehose-frame.ts
|
|
38999
|
+
function handleInboundFirehoseFrame(raw, deps) {
|
|
39000
|
+
if (Buffer.isBuffer(raw) && tryConsumeBinaryProxyBody(raw, deps)) {
|
|
39001
|
+
return;
|
|
39002
|
+
}
|
|
39003
|
+
let msg;
|
|
39004
|
+
try {
|
|
39005
|
+
const text = Buffer.isBuffer(raw) ? raw.toString("utf8") : String(raw);
|
|
39006
|
+
msg = JSON.parse(text);
|
|
39007
|
+
} catch {
|
|
39008
|
+
return;
|
|
39009
|
+
}
|
|
39010
|
+
if (msg.type === "proxy") {
|
|
39011
|
+
dispatchFirehoseJsonMessage(msg, deps);
|
|
39012
|
+
return;
|
|
39013
|
+
}
|
|
39014
|
+
setImmediate(() => {
|
|
39015
|
+
dispatchFirehoseJsonMessage(msg, deps);
|
|
39016
|
+
});
|
|
39017
|
+
}
|
|
39018
|
+
|
|
39019
|
+
// src/firehose/wire-firehose-websocket.ts
|
|
39020
|
+
function wireFirehoseWebSocket(options) {
|
|
38927
39021
|
const {
|
|
38928
|
-
|
|
39022
|
+
ws,
|
|
39023
|
+
deps,
|
|
39024
|
+
log: log2,
|
|
39025
|
+
previewEnvironmentManager,
|
|
38929
39026
|
workspaceId,
|
|
38930
39027
|
bridgeName,
|
|
38931
39028
|
proxyPorts,
|
|
38932
|
-
log: log2,
|
|
38933
|
-
previewEnvironmentManager,
|
|
38934
39029
|
onOpen,
|
|
38935
39030
|
onClose,
|
|
38936
39031
|
suppressWebSocketErrors
|
|
38937
39032
|
} = options;
|
|
38938
|
-
const wsUrl = buildFirehoseCliWsUrl(firehoseServerUrl);
|
|
38939
|
-
applyCliOutboundNetworkPreferences();
|
|
38940
|
-
const ws = new wrapper_default(wsUrl, buildCliWebSocketClientOptions(wsUrl));
|
|
38941
39033
|
let clearClientPing = null;
|
|
39034
|
+
let identifyParams = { workspaceId, bridgeName, proxyPorts };
|
|
38942
39035
|
function disposeClientPing() {
|
|
38943
39036
|
clearClientPing?.();
|
|
38944
39037
|
clearClientPing = null;
|
|
@@ -38946,36 +39039,32 @@ function connectFirehose(options) {
|
|
|
38946
39039
|
const firehoseSend = (payload) => {
|
|
38947
39040
|
sendWsMessage(ws, payload);
|
|
38948
39041
|
};
|
|
38949
|
-
|
|
38950
|
-
|
|
38951
|
-
ws
|
|
38952
|
-
|
|
38953
|
-
|
|
38954
|
-
|
|
38955
|
-
|
|
38956
|
-
|
|
39042
|
+
function sendIdentify(params) {
|
|
39043
|
+
identifyParams = params;
|
|
39044
|
+
if (ws.readyState !== wrapper_default.OPEN) return;
|
|
39045
|
+
sendWsMessage(ws, {
|
|
39046
|
+
type: "identify",
|
|
39047
|
+
workspaceId: params.workspaceId,
|
|
39048
|
+
bridgeName: params.bridgeName,
|
|
39049
|
+
proxyPorts: params.proxyPorts
|
|
39050
|
+
});
|
|
39051
|
+
}
|
|
39052
|
+
function detachPreviewEnvironmentManager() {
|
|
39053
|
+
previewEnvironmentManager.detachFirehose();
|
|
39054
|
+
}
|
|
38957
39055
|
ws.on("open", () => {
|
|
38958
39056
|
disposeClientPing();
|
|
38959
39057
|
clearClientPing = attachWebSocketClientPing(ws, CLI_WEBSOCKET_CLIENT_PING_MS);
|
|
38960
39058
|
onOpen?.();
|
|
38961
39059
|
previewEnvironmentManager.attachFirehose(firehoseSend);
|
|
38962
|
-
|
|
39060
|
+
sendIdentify(identifyParams);
|
|
38963
39061
|
});
|
|
38964
39062
|
ws.on("message", (raw) => {
|
|
38965
|
-
|
|
38966
|
-
return;
|
|
38967
|
-
}
|
|
38968
|
-
setImmediate(() => {
|
|
38969
|
-
try {
|
|
38970
|
-
const text = Buffer.isBuffer(raw) ? raw.toString("utf8") : String(raw);
|
|
38971
|
-
dispatchFirehoseJsonMessage(JSON.parse(text), deps);
|
|
38972
|
-
} catch {
|
|
38973
|
-
}
|
|
38974
|
-
});
|
|
39063
|
+
handleInboundFirehoseFrame(raw, deps);
|
|
38975
39064
|
});
|
|
38976
39065
|
ws.on("close", (code, reason) => {
|
|
38977
39066
|
disposeClientPing();
|
|
38978
|
-
|
|
39067
|
+
detachPreviewEnvironmentManager();
|
|
38979
39068
|
const reasonStr = typeof reason === "string" ? reason : reason.toString();
|
|
38980
39069
|
onClose?.(code, reasonStr);
|
|
38981
39070
|
});
|
|
@@ -38988,25 +39077,64 @@ function connectFirehose(options) {
|
|
|
38988
39077
|
safeCloseWebSocket(ws);
|
|
38989
39078
|
}
|
|
38990
39079
|
});
|
|
39080
|
+
return { disposeClientPing, sendIdentify, detachPreviewEnvironmentManager };
|
|
39081
|
+
}
|
|
39082
|
+
|
|
39083
|
+
// src/firehose/connect-firehose.ts
|
|
39084
|
+
function connectFirehose(options) {
|
|
39085
|
+
const {
|
|
39086
|
+
firehoseServerUrl,
|
|
39087
|
+
workspaceId,
|
|
39088
|
+
bridgeName,
|
|
39089
|
+
proxyPorts,
|
|
39090
|
+
log: log2,
|
|
39091
|
+
previewEnvironmentManager,
|
|
39092
|
+
onOpen,
|
|
39093
|
+
onClose,
|
|
39094
|
+
suppressWebSocketErrors
|
|
39095
|
+
} = options;
|
|
39096
|
+
const wsUrl = buildFirehoseCliWsUrl(firehoseServerUrl);
|
|
39097
|
+
const ws = new wrapper_default(wsUrl, buildCliWebSocketClientOptions(wsUrl));
|
|
39098
|
+
const deps = createFirehoseMessageDeps(ws, log2, previewEnvironmentManager);
|
|
39099
|
+
const wired = wireFirehoseWebSocket({
|
|
39100
|
+
ws,
|
|
39101
|
+
deps,
|
|
39102
|
+
log: log2,
|
|
39103
|
+
previewEnvironmentManager,
|
|
39104
|
+
workspaceId,
|
|
39105
|
+
bridgeName,
|
|
39106
|
+
proxyPorts,
|
|
39107
|
+
onOpen,
|
|
39108
|
+
onClose,
|
|
39109
|
+
suppressWebSocketErrors
|
|
39110
|
+
});
|
|
38991
39111
|
return {
|
|
38992
39112
|
close() {
|
|
38993
|
-
disposeClientPing();
|
|
38994
|
-
|
|
39113
|
+
wired.disposeClientPing();
|
|
39114
|
+
wired.detachPreviewEnvironmentManager();
|
|
38995
39115
|
safeCloseWebSocket(ws);
|
|
38996
39116
|
},
|
|
38997
|
-
isConnected: () => ws.readyState === wrapper_default.OPEN
|
|
39117
|
+
isConnected: () => ws.readyState === wrapper_default.OPEN,
|
|
39118
|
+
updateIdentify: wired.sendIdentify
|
|
38998
39119
|
};
|
|
38999
39120
|
}
|
|
39000
39121
|
|
|
39001
|
-
// src/connection/
|
|
39002
|
-
function
|
|
39003
|
-
|
|
39004
|
-
|
|
39005
|
-
|
|
39006
|
-
|
|
39007
|
-
|
|
39008
|
-
|
|
39009
|
-
|
|
39122
|
+
// src/connection/firehose/compare-firehose-params.ts
|
|
39123
|
+
function proxyPortsEqual(a, b) {
|
|
39124
|
+
if (a.length !== b.length) return false;
|
|
39125
|
+
const sa = [...a].sort((x, y) => x - y);
|
|
39126
|
+
const sb = [...b].sort((x, y) => x - y);
|
|
39127
|
+
return sa.every((v, i) => v === sb[i]);
|
|
39128
|
+
}
|
|
39129
|
+
function sameFirehoseBridge(a, b) {
|
|
39130
|
+
return a.firehoseServerUrl === b.firehoseServerUrl && a.workspaceId === b.workspaceId && a.bridgeName === b.bridgeName;
|
|
39131
|
+
}
|
|
39132
|
+
function shouldReuseOpenFirehoseConnection(prev, next, isConnected) {
|
|
39133
|
+
return Boolean(prev && sameFirehoseBridge(prev, next) && isConnected());
|
|
39134
|
+
}
|
|
39135
|
+
|
|
39136
|
+
// src/connection/firehose/create-firehose-connect-callbacks.ts
|
|
39137
|
+
function createFirehoseConnectCallbacks(state, myGen, logFn, scheduleFirehoseRetryAfterDrop) {
|
|
39010
39138
|
function firehoseCtx() {
|
|
39011
39139
|
return {
|
|
39012
39140
|
closedByUser: state.closedByUser,
|
|
@@ -39015,6 +39143,55 @@ function attachFirehoseAfterIdentified(ctx, params) {
|
|
|
39015
39143
|
firehoseQuiet: state.firehoseQuiet
|
|
39016
39144
|
};
|
|
39017
39145
|
}
|
|
39146
|
+
return {
|
|
39147
|
+
onOpen: () => {
|
|
39148
|
+
if (myGen !== state.firehoseGeneration) return;
|
|
39149
|
+
try {
|
|
39150
|
+
clearFirehoseReconnectQuietOnOpen(
|
|
39151
|
+
{
|
|
39152
|
+
firehoseQuiet: state.firehoseQuiet,
|
|
39153
|
+
firehoseOutage: state.firehoseOutage,
|
|
39154
|
+
lastFirehoseReconnectCloseMeta: state.lastFirehoseReconnectCloseMeta
|
|
39155
|
+
},
|
|
39156
|
+
logFn
|
|
39157
|
+
);
|
|
39158
|
+
} catch {
|
|
39159
|
+
}
|
|
39160
|
+
const logOpenAsFirehoseReconnect = state.firehoseReconnectAttempt > 0;
|
|
39161
|
+
state.firehoseReconnectAttempt = 0;
|
|
39162
|
+
if (!logOpenAsFirehoseReconnect) {
|
|
39163
|
+
try {
|
|
39164
|
+
logFn("Connected to preview tunnel (local HTTP proxy and dev logs).");
|
|
39165
|
+
} catch {
|
|
39166
|
+
}
|
|
39167
|
+
}
|
|
39168
|
+
},
|
|
39169
|
+
onClose: (code, reason) => {
|
|
39170
|
+
if (myGen !== state.firehoseGeneration) return;
|
|
39171
|
+
state.firehoseHandle = null;
|
|
39172
|
+
if (state.closedByUser) return;
|
|
39173
|
+
state.lastFirehoseReconnectCloseMeta = { code, reason };
|
|
39174
|
+
try {
|
|
39175
|
+
beginFirehoseDeferredDisconnect(firehoseCtx(), code, reason, logFn);
|
|
39176
|
+
} catch {
|
|
39177
|
+
}
|
|
39178
|
+
try {
|
|
39179
|
+
scheduleFirehoseRetryAfterDrop({ code, reason });
|
|
39180
|
+
} catch {
|
|
39181
|
+
}
|
|
39182
|
+
}
|
|
39183
|
+
};
|
|
39184
|
+
}
|
|
39185
|
+
|
|
39186
|
+
// src/connection/firehose/create-firehose-reconnect-scheduler.ts
|
|
39187
|
+
function createFirehoseReconnectScheduler(ctx, reconnect) {
|
|
39188
|
+
const { state, logFn } = ctx;
|
|
39189
|
+
function clearFirehoseReconnectTimer() {
|
|
39190
|
+
if (state.firehoseReconnectTimeout != null) {
|
|
39191
|
+
clearTimeout(state.firehoseReconnectTimeout);
|
|
39192
|
+
state.firehoseReconnectTimeout = null;
|
|
39193
|
+
}
|
|
39194
|
+
}
|
|
39018
39195
|
function scheduleFirehoseRetryAfterDrop(closeMeta) {
|
|
39019
39196
|
if (state.closedByUser) return;
|
|
39020
39197
|
const meta = closeMeta ?? state.lastFirehoseReconnectCloseMeta ?? void 0;
|
|
@@ -39036,30 +39213,60 @@ function attachFirehoseAfterIdentified(ctx, params) {
|
|
|
39036
39213
|
state.firehoseReconnectTimeout = id;
|
|
39037
39214
|
},
|
|
39038
39215
|
shouldAbortBeforeRun: () => state.closedByUser,
|
|
39039
|
-
run:
|
|
39040
|
-
const p = state.lastFirehoseParams;
|
|
39041
|
-
if (!p) return;
|
|
39042
|
-
attachFirehoseAfterIdentified(ctx, p);
|
|
39043
|
-
},
|
|
39216
|
+
run: reconnect,
|
|
39044
39217
|
reschedule: () => {
|
|
39045
39218
|
scheduleFirehoseRetryAfterDrop();
|
|
39046
39219
|
}
|
|
39047
39220
|
});
|
|
39048
39221
|
}
|
|
39049
|
-
|
|
39050
|
-
|
|
39051
|
-
|
|
39052
|
-
|
|
39053
|
-
|
|
39054
|
-
|
|
39055
|
-
|
|
39222
|
+
return { clearFirehoseReconnectTimer, scheduleFirehoseRetryAfterDrop };
|
|
39223
|
+
}
|
|
39224
|
+
function logInitialFirehoseConnect(state, logFn) {
|
|
39225
|
+
if (state.firehoseReconnectAttempt !== 0) return;
|
|
39226
|
+
try {
|
|
39227
|
+
logFn("Connecting to preview tunnel (local HTTP proxy and dev logs)\u2026");
|
|
39228
|
+
} catch {
|
|
39056
39229
|
}
|
|
39230
|
+
}
|
|
39231
|
+
function replaceFirehoseHandle(state) {
|
|
39057
39232
|
state.firehoseGeneration += 1;
|
|
39058
39233
|
const myGen = state.firehoseGeneration;
|
|
39059
39234
|
if (state.firehoseHandle) {
|
|
39060
39235
|
state.firehoseHandle.close();
|
|
39061
39236
|
state.firehoseHandle = null;
|
|
39062
39237
|
}
|
|
39238
|
+
return myGen;
|
|
39239
|
+
}
|
|
39240
|
+
|
|
39241
|
+
// src/connection/firehose/attach-firehose-after-identified.ts
|
|
39242
|
+
function attachFirehoseAfterIdentified(ctx, params) {
|
|
39243
|
+
const { state, previewEnvironmentManager, logFn } = ctx;
|
|
39244
|
+
const prev = state.lastFirehoseParams;
|
|
39245
|
+
if (shouldReuseOpenFirehoseConnection(prev, params, () => state.firehoseHandle?.isConnected() ?? false)) {
|
|
39246
|
+
state.lastFirehoseParams = params;
|
|
39247
|
+
if (prev && !proxyPortsEqual(prev.proxyPorts, params.proxyPorts)) {
|
|
39248
|
+
state.firehoseHandle?.updateIdentify(params);
|
|
39249
|
+
}
|
|
39250
|
+
return;
|
|
39251
|
+
}
|
|
39252
|
+
const { clearFirehoseReconnectTimer, scheduleFirehoseRetryAfterDrop } = createFirehoseReconnectScheduler(
|
|
39253
|
+
ctx,
|
|
39254
|
+
() => {
|
|
39255
|
+
const p = state.lastFirehoseParams;
|
|
39256
|
+
if (!p) return;
|
|
39257
|
+
attachFirehoseAfterIdentified(ctx, p);
|
|
39258
|
+
}
|
|
39259
|
+
);
|
|
39260
|
+
state.lastFirehoseParams = params;
|
|
39261
|
+
clearFirehoseReconnectTimer();
|
|
39262
|
+
logInitialFirehoseConnect(state, logFn);
|
|
39263
|
+
const myGen = replaceFirehoseHandle(state);
|
|
39264
|
+
const { onOpen, onClose } = createFirehoseConnectCallbacks(
|
|
39265
|
+
state,
|
|
39266
|
+
myGen,
|
|
39267
|
+
logFn,
|
|
39268
|
+
scheduleFirehoseRetryAfterDrop
|
|
39269
|
+
);
|
|
39063
39270
|
state.firehoseHandle = connectFirehose({
|
|
39064
39271
|
firehoseServerUrl: params.firehoseServerUrl,
|
|
39065
39272
|
workspaceId: params.workspaceId,
|
|
@@ -39068,45 +39275,17 @@ function attachFirehoseAfterIdentified(ctx, params) {
|
|
|
39068
39275
|
log: logFn,
|
|
39069
39276
|
previewEnvironmentManager,
|
|
39070
39277
|
suppressWebSocketErrors: () => !state.closedByUser && state.firehoseOutage.startedAt != null,
|
|
39071
|
-
onOpen
|
|
39072
|
-
|
|
39073
|
-
try {
|
|
39074
|
-
clearFirehoseReconnectQuietOnOpen(
|
|
39075
|
-
{
|
|
39076
|
-
firehoseQuiet: state.firehoseQuiet,
|
|
39077
|
-
firehoseOutage: state.firehoseOutage,
|
|
39078
|
-
lastFirehoseReconnectCloseMeta: state.lastFirehoseReconnectCloseMeta
|
|
39079
|
-
},
|
|
39080
|
-
logFn
|
|
39081
|
-
);
|
|
39082
|
-
} catch {
|
|
39083
|
-
}
|
|
39084
|
-
const logOpenAsFirehoseReconnect = state.firehoseReconnectAttempt > 0;
|
|
39085
|
-
state.firehoseReconnectAttempt = 0;
|
|
39086
|
-
if (!logOpenAsFirehoseReconnect) {
|
|
39087
|
-
try {
|
|
39088
|
-
logFn("Connected to preview tunnel (local HTTP proxy and dev logs).");
|
|
39089
|
-
} catch {
|
|
39090
|
-
}
|
|
39091
|
-
}
|
|
39092
|
-
},
|
|
39093
|
-
onClose: (code, reason) => {
|
|
39094
|
-
if (myGen !== state.firehoseGeneration) return;
|
|
39095
|
-
state.firehoseHandle = null;
|
|
39096
|
-
if (state.closedByUser) return;
|
|
39097
|
-
state.lastFirehoseReconnectCloseMeta = { code, reason };
|
|
39098
|
-
try {
|
|
39099
|
-
beginFirehoseDeferredDisconnect(firehoseCtx(), code, reason, logFn);
|
|
39100
|
-
} catch {
|
|
39101
|
-
}
|
|
39102
|
-
try {
|
|
39103
|
-
scheduleFirehoseRetryAfterDrop({ code, reason });
|
|
39104
|
-
} catch {
|
|
39105
|
-
}
|
|
39106
|
-
}
|
|
39278
|
+
onOpen,
|
|
39279
|
+
onClose
|
|
39107
39280
|
});
|
|
39108
39281
|
}
|
|
39109
39282
|
|
|
39283
|
+
// src/connection/firehose/update-firehose-identify-on-open-connection.ts
|
|
39284
|
+
function updateFirehoseIdentifyOnOpenConnection(state, params) {
|
|
39285
|
+
state.lastFirehoseParams = params;
|
|
39286
|
+
state.firehoseHandle?.updateIdentify(params);
|
|
39287
|
+
}
|
|
39288
|
+
|
|
39110
39289
|
// src/connection/create-bridge-identified-handler.ts
|
|
39111
39290
|
function createOnBridgeIdentified(opts) {
|
|
39112
39291
|
const { previewEnvironmentManager, firehoseServerUrl, workspaceId, state, logFn } = opts;
|
|
@@ -39143,6 +39322,7 @@ function createBridgeMessageDeps(params) {
|
|
|
39143
39322
|
reportAutoDetectedAgents,
|
|
39144
39323
|
warmupAgentCapabilitiesOnConnect: warmupAgentCapabilitiesOnConnect2,
|
|
39145
39324
|
previewEnvironmentManager,
|
|
39325
|
+
updateFirehoseProxyPorts,
|
|
39146
39326
|
e2ee,
|
|
39147
39327
|
cloudApiBaseUrl,
|
|
39148
39328
|
getCloudAccessToken
|
|
@@ -39161,6 +39341,7 @@ function createBridgeMessageDeps(params) {
|
|
|
39161
39341
|
reportAutoDetectedAgents,
|
|
39162
39342
|
warmupAgentCapabilitiesOnConnect: warmupAgentCapabilitiesOnConnect2,
|
|
39163
39343
|
previewEnvironmentManager,
|
|
39344
|
+
updateFirehoseProxyPorts,
|
|
39164
39345
|
e2ee,
|
|
39165
39346
|
cloudApiBaseUrl,
|
|
39166
39347
|
getCloudAccessToken
|
|
@@ -39421,6 +39602,11 @@ function createBridgeRuntimeMessageSetup(options) {
|
|
|
39421
39602
|
getWs
|
|
39422
39603
|
}),
|
|
39423
39604
|
previewEnvironmentManager,
|
|
39605
|
+
updateFirehoseProxyPorts: (proxyPorts) => {
|
|
39606
|
+
const p = state.lastFirehoseParams;
|
|
39607
|
+
if (!p) return;
|
|
39608
|
+
updateFirehoseIdentifyOnOpenConnection(state, { ...p, proxyPorts });
|
|
39609
|
+
},
|
|
39424
39610
|
e2ee,
|
|
39425
39611
|
cloudApiBaseUrl: apiUrl,
|
|
39426
39612
|
getCloudAccessToken: () => tokens.accessToken
|
|
@@ -46690,16 +46876,16 @@ async function applySessionWipToPreviewCheckouts(options) {
|
|
|
46690
46876
|
return;
|
|
46691
46877
|
}
|
|
46692
46878
|
await gitResetWorktreeToBranch(previewCheckout, deployBranch);
|
|
46693
|
-
const
|
|
46879
|
+
const applied = await applyWorkingTreeWip(
|
|
46694
46880
|
previewCheckout,
|
|
46695
46881
|
state.sessionCheckout,
|
|
46696
46882
|
state.wip,
|
|
46697
46883
|
log2
|
|
46698
46884
|
);
|
|
46699
|
-
if (!
|
|
46885
|
+
if (!applied.ok) {
|
|
46700
46886
|
failure = {
|
|
46701
46887
|
ok: false,
|
|
46702
|
-
error:
|
|
46888
|
+
error: applied.error ?? `Failed to apply session WIP to preview (${state.repoPathRelativeToWorkspaceRoot})`
|
|
46703
46889
|
};
|
|
46704
46890
|
}
|
|
46705
46891
|
});
|
|
@@ -46798,7 +46984,7 @@ async function deploySessionToPreviewEnvironment(options) {
|
|
|
46798
46984
|
return { ok: false, error: "Failed to create preview environment worktrees" };
|
|
46799
46985
|
}
|
|
46800
46986
|
await yieldToEventLoop2();
|
|
46801
|
-
const
|
|
46987
|
+
const applied = await applySessionWipToPreviewCheckouts({
|
|
46802
46988
|
previewWorktreeManager,
|
|
46803
46989
|
environmentId: eid,
|
|
46804
46990
|
deployBranch,
|
|
@@ -46806,8 +46992,8 @@ async function deploySessionToPreviewEnvironment(options) {
|
|
|
46806
46992
|
repoStates,
|
|
46807
46993
|
log: log2
|
|
46808
46994
|
});
|
|
46809
|
-
if (!
|
|
46810
|
-
return { ok: false, error:
|
|
46995
|
+
if (!applied.ok) {
|
|
46996
|
+
return { ok: false, error: applied.error };
|
|
46811
46997
|
}
|
|
46812
46998
|
log2(
|
|
46813
46999
|
`[worktrees] Deployed session ${sid.slice(0, 8)}\u2026 to preview ${eid.slice(0, 8)}\u2026 on branch ${deployBranch}.`
|
|
@@ -49402,12 +49588,17 @@ var handlePreviewEnvironmentControl = (msg, deps) => {
|
|
|
49402
49588
|
};
|
|
49403
49589
|
|
|
49404
49590
|
// src/routing/handlers/preview-environments-config.ts
|
|
49591
|
+
var VALID_PORT = (p) => typeof p === "number" && Number.isInteger(p) && p > 0 && p < 65536;
|
|
49405
49592
|
var handlePreviewEnvironmentsConfig = (msg, deps) => {
|
|
49406
49593
|
const previewEnvironments = msg.previewEnvironments;
|
|
49594
|
+
const proxyPorts = Array.isArray(msg.proxyPorts) ? msg.proxyPorts.filter(VALID_PORT) : void 0;
|
|
49407
49595
|
setImmediate(() => {
|
|
49408
49596
|
deps.previewEnvironmentManager?.applyConfig(previewEnvironments ?? []);
|
|
49409
49597
|
const environmentIds = parsePreviewEnvironmentDefs(previewEnvironments ?? []).map((d) => d.environmentId);
|
|
49410
49598
|
void deps.previewWorktreeManager?.syncConfiguredEnvironments(environmentIds);
|
|
49599
|
+
if (proxyPorts !== void 0) {
|
|
49600
|
+
deps.updateFirehoseProxyPorts?.(proxyPorts);
|
|
49601
|
+
}
|
|
49411
49602
|
});
|
|
49412
49603
|
};
|
|
49413
49604
|
|