@builder.io/ai-utils 0.48.1 → 0.50.0
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/package.json +1 -1
- package/src/codegen.d.ts +8 -0
- package/src/connectivity/checks/websocket-check.d.ts +21 -0
- package/src/connectivity/checks/websocket-check.js +90 -0
- package/src/connectivity/environment.js +6 -2
- package/src/connectivity/run-checks.browser.js +3 -0
- package/src/connectivity/run-checks.js +3 -0
- package/src/connectivity/targets.js +3 -1
- package/src/connectivity/types.d.ts +2 -2
- package/src/projects.d.ts +21 -0
package/package.json
CHANGED
package/src/codegen.d.ts
CHANGED
|
@@ -68,6 +68,13 @@ export interface CustomAgentDefinition {
|
|
|
68
68
|
queueMode?: QueueMode;
|
|
69
69
|
softContextWindow?: number;
|
|
70
70
|
filePath?: string;
|
|
71
|
+
/** Maximum wall time (in milliseconds) before the agent watchdog aborts. */
|
|
72
|
+
maxTimeoutMs?: number;
|
|
73
|
+
/**
|
|
74
|
+
* Default max LLM completion turns when this agent is spawned via the Agent tool.
|
|
75
|
+
* Overrides generic sub-agent defaults in dev-tools when set.
|
|
76
|
+
*/
|
|
77
|
+
maxCompletions?: number;
|
|
71
78
|
/** Default reasoning effort level for this agent type. Overrides the session default. */
|
|
72
79
|
reasoning?: ReasoningEffort;
|
|
73
80
|
}
|
|
@@ -332,6 +339,7 @@ export interface TimelineRecording {
|
|
|
332
339
|
startEventId: number;
|
|
333
340
|
endEventId: number;
|
|
334
341
|
testCaseIds?: string[];
|
|
342
|
+
replayId?: string;
|
|
335
343
|
}>;
|
|
336
344
|
}
|
|
337
345
|
export interface TimelineSubmissionMetadata {
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import type { CheckResult, Source, TestId } from "../types.js";
|
|
2
|
+
export interface WebSocketCheckOptions {
|
|
3
|
+
target: string;
|
|
4
|
+
source: Source;
|
|
5
|
+
testId: TestId;
|
|
6
|
+
timeout?: number;
|
|
7
|
+
}
|
|
8
|
+
/**
|
|
9
|
+
* Tests WebSocket connectivity by attempting to open a WSS connection.
|
|
10
|
+
*
|
|
11
|
+
* Protocol notes:
|
|
12
|
+
* - Uses wss:// (WebSocket Secure) — ws:// is blocked by browsers on HTTPS pages
|
|
13
|
+
* due to mixed-content restrictions, and wss:// uses port 443 which is typically
|
|
14
|
+
* allowed by firewalls that permit HTTPS traffic.
|
|
15
|
+
* - Considers the check passed as soon as the WebSocket `open` event fires,
|
|
16
|
+
* meaning the TCP+TLS+HTTP-upgrade handshake completed successfully.
|
|
17
|
+
* - A firewall or proxy that blocks WebSocket upgrades (even on the same host/port
|
|
18
|
+
* that allows normal HTTPS) will cause the `error` event instead, and the check fails.
|
|
19
|
+
* - The timeout guards against silent connection drops that never emit an event.
|
|
20
|
+
*/
|
|
21
|
+
export declare function websocketCheck(options: WebSocketCheckOptions): Promise<CheckResult>;
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
const DEFAULT_TIMEOUT_MS = 10000;
|
|
2
|
+
/**
|
|
3
|
+
* Tests WebSocket connectivity by attempting to open a WSS connection.
|
|
4
|
+
*
|
|
5
|
+
* Protocol notes:
|
|
6
|
+
* - Uses wss:// (WebSocket Secure) — ws:// is blocked by browsers on HTTPS pages
|
|
7
|
+
* due to mixed-content restrictions, and wss:// uses port 443 which is typically
|
|
8
|
+
* allowed by firewalls that permit HTTPS traffic.
|
|
9
|
+
* - Considers the check passed as soon as the WebSocket `open` event fires,
|
|
10
|
+
* meaning the TCP+TLS+HTTP-upgrade handshake completed successfully.
|
|
11
|
+
* - A firewall or proxy that blocks WebSocket upgrades (even on the same host/port
|
|
12
|
+
* that allows normal HTTPS) will cause the `error` event instead, and the check fails.
|
|
13
|
+
* - The timeout guards against silent connection drops that never emit an event.
|
|
14
|
+
*/
|
|
15
|
+
export async function websocketCheck(options) {
|
|
16
|
+
const { target, source, testId, timeout = DEFAULT_TIMEOUT_MS } = options;
|
|
17
|
+
const startTime = Date.now();
|
|
18
|
+
return new Promise((resolve) => {
|
|
19
|
+
let settled = false;
|
|
20
|
+
let ws = null;
|
|
21
|
+
const timeoutId = setTimeout(() => {
|
|
22
|
+
if (settled)
|
|
23
|
+
return;
|
|
24
|
+
settled = true;
|
|
25
|
+
ws === null || ws === void 0 ? void 0 : ws.close();
|
|
26
|
+
resolve({
|
|
27
|
+
source,
|
|
28
|
+
testId,
|
|
29
|
+
target,
|
|
30
|
+
passed: false,
|
|
31
|
+
errorCode: "tcp_connection_timeout",
|
|
32
|
+
durationMs: Date.now() - startTime,
|
|
33
|
+
metadata: {
|
|
34
|
+
error: "WebSocket connection timed out",
|
|
35
|
+
timeoutMs: timeout,
|
|
36
|
+
},
|
|
37
|
+
});
|
|
38
|
+
}, timeout);
|
|
39
|
+
try {
|
|
40
|
+
ws = new WebSocket(target);
|
|
41
|
+
}
|
|
42
|
+
catch (err) {
|
|
43
|
+
clearTimeout(timeoutId);
|
|
44
|
+
settled = true;
|
|
45
|
+
resolve({
|
|
46
|
+
source,
|
|
47
|
+
testId,
|
|
48
|
+
target,
|
|
49
|
+
passed: false,
|
|
50
|
+
errorCode: "unknown_error",
|
|
51
|
+
durationMs: Date.now() - startTime,
|
|
52
|
+
metadata: {
|
|
53
|
+
error: err instanceof Error ? err.message : "Failed to create WebSocket",
|
|
54
|
+
},
|
|
55
|
+
});
|
|
56
|
+
return;
|
|
57
|
+
}
|
|
58
|
+
ws.onopen = () => {
|
|
59
|
+
if (settled)
|
|
60
|
+
return;
|
|
61
|
+
settled = true;
|
|
62
|
+
clearTimeout(timeoutId);
|
|
63
|
+
const durationMs = Date.now() - startTime;
|
|
64
|
+
ws === null || ws === void 0 ? void 0 : ws.close(1000);
|
|
65
|
+
resolve({
|
|
66
|
+
source,
|
|
67
|
+
testId,
|
|
68
|
+
target,
|
|
69
|
+
passed: true,
|
|
70
|
+
durationMs,
|
|
71
|
+
metadata: { protocol: (ws === null || ws === void 0 ? void 0 : ws.protocol) || undefined },
|
|
72
|
+
});
|
|
73
|
+
};
|
|
74
|
+
ws.onerror = () => {
|
|
75
|
+
if (settled)
|
|
76
|
+
return;
|
|
77
|
+
settled = true;
|
|
78
|
+
clearTimeout(timeoutId);
|
|
79
|
+
resolve({
|
|
80
|
+
source,
|
|
81
|
+
testId,
|
|
82
|
+
target,
|
|
83
|
+
passed: false,
|
|
84
|
+
errorCode: "tcp_connection_refused",
|
|
85
|
+
durationMs: Date.now() - startTime,
|
|
86
|
+
metadata: { error: "WebSocket connection failed" },
|
|
87
|
+
});
|
|
88
|
+
};
|
|
89
|
+
});
|
|
90
|
+
}
|
|
@@ -7,13 +7,17 @@ export function isNode() {
|
|
|
7
7
|
process.versions.node != null);
|
|
8
8
|
}
|
|
9
9
|
export function getCheckTypeForTestId(testId) {
|
|
10
|
+
if (testId === "health.builderio.xyz:ws" ||
|
|
11
|
+
testId === "health.builderio.dev:ws") {
|
|
12
|
+
return "websocket";
|
|
13
|
+
}
|
|
10
14
|
if (testId.startsWith("git-host:")) {
|
|
11
15
|
return testId.replace("git-host:", "");
|
|
12
16
|
}
|
|
13
17
|
return "http";
|
|
14
18
|
}
|
|
15
19
|
export function isCheckAvailable(checkType) {
|
|
16
|
-
if (checkType === "http") {
|
|
20
|
+
if (checkType === "http" || checkType === "websocket") {
|
|
17
21
|
return true;
|
|
18
22
|
}
|
|
19
23
|
// DNS, TCP, TLS, and SSH checks require Node.js modules
|
|
@@ -21,7 +25,7 @@ export function isCheckAvailable(checkType) {
|
|
|
21
25
|
}
|
|
22
26
|
export function getUnavailabilityReason(checkType) {
|
|
23
27
|
if (isBrowser()) {
|
|
24
|
-
return `${checkType.toUpperCase()} checks are not available in browser environments. Only HTTP checks can be performed from the browser.`;
|
|
28
|
+
return `${checkType.toUpperCase()} checks are not available in browser environments. Only HTTP and WebSocket checks can be performed from the browser.`;
|
|
25
29
|
}
|
|
26
30
|
return `${checkType.toUpperCase()} checks are not available in this environment.`;
|
|
27
31
|
}
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { resolveTarget } from "./targets.js";
|
|
2
2
|
import { getCheckTypeForTestId, isCheckAvailable, getUnavailabilityReason, } from "./environment.js";
|
|
3
3
|
import { httpCheck } from "./checks/http-check.js";
|
|
4
|
+
import { websocketCheck } from "./checks/websocket-check.js";
|
|
4
5
|
export async function runChecks(input) {
|
|
5
6
|
const { tests, gitHost, onProgress } = input;
|
|
6
7
|
const results = [];
|
|
@@ -77,6 +78,8 @@ async function runSingleCheck(test, gitHost) {
|
|
|
77
78
|
switch (checkType) {
|
|
78
79
|
case "http":
|
|
79
80
|
return httpCheck({ target, source, testId });
|
|
81
|
+
case "websocket":
|
|
82
|
+
return websocketCheck({ target, source, testId });
|
|
80
83
|
default:
|
|
81
84
|
return {
|
|
82
85
|
source,
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { resolveTarget, extractHostname, extractPort, extractExplicitPort, } from "./targets.js";
|
|
2
2
|
import { getCheckTypeForTestId, isCheckAvailable, getUnavailabilityReason, } from "./environment.js";
|
|
3
3
|
import { httpCheck } from "./checks/http-check.js";
|
|
4
|
+
import { websocketCheck } from "./checks/websocket-check.js";
|
|
4
5
|
import { dnsCheck } from "./checks/dns-check.js";
|
|
5
6
|
import { tcpCheck } from "./checks/tcp-check.js";
|
|
6
7
|
import { tlsCheck } from "./checks/tls-check.js";
|
|
@@ -81,6 +82,8 @@ async function runSingleCheck(test, gitHost, fetchFn, dispatcher, connectFn) {
|
|
|
81
82
|
switch (checkType) {
|
|
82
83
|
case "http":
|
|
83
84
|
return httpCheck({ target, source, testId, fetchFn, dispatcher });
|
|
85
|
+
case "websocket":
|
|
86
|
+
return websocketCheck({ target, source, testId });
|
|
84
87
|
case "dns":
|
|
85
88
|
return dnsCheck({
|
|
86
89
|
hostname: extractHostname(target),
|
|
@@ -3,8 +3,10 @@ export const BUILDER_TARGETS = {
|
|
|
3
3
|
"builder.codes": "https://test.projects.builder.codes/proxy-health",
|
|
4
4
|
"api.builder.io": "https://api.builder.io/codegen/health",
|
|
5
5
|
"cdn.builder.io": "https://cdn.builder.io/api/v1/image/assets/TEMP/75a212ab82b6175c9862b125e0e23db8d369a58a?width=100",
|
|
6
|
-
"builderio.xyz": "https://builderio.xyz/health",
|
|
7
6
|
"health.builderio.xyz": "https://health.builderio.xyz/health",
|
|
7
|
+
"health.builderio.xyz:ws": "wss://health.builderio.xyz/ws",
|
|
8
|
+
"health.builderio.dev": "https://health.builderio.dev/health",
|
|
9
|
+
"health.builderio.dev:ws": "wss://health.builderio.dev/ws",
|
|
8
10
|
"fly.dev": "https://fly.dev",
|
|
9
11
|
};
|
|
10
12
|
export const DEFAULT_PORTS = {
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
export type Source = "local" | "cloud" | "static-ip";
|
|
2
|
-
export type TestId = "builder.io" | "builder.codes" | "api.builder.io" | "cdn.builder.io" | "builderio.xyz" | "health.builderio.xyz" | "fly.dev" | "git-host:http" | "git-host:dns" | "git-host:tcp" | "git-host:tls" | "git-host:ssh";
|
|
2
|
+
export type TestId = "builder.io" | "builder.codes" | "api.builder.io" | "cdn.builder.io" | "health.builderio.xyz" | "health.builderio.xyz:ws" | "health.builderio.dev" | "health.builderio.dev:ws" | "fly.dev" | "git-host:http" | "git-host:dns" | "git-host:tcp" | "git-host:tls" | "git-host:ssh";
|
|
3
3
|
export interface Test {
|
|
4
4
|
source: Source;
|
|
5
5
|
testId: TestId;
|
|
@@ -61,7 +61,7 @@ export interface CheckReport {
|
|
|
61
61
|
results: CheckResult[];
|
|
62
62
|
}
|
|
63
63
|
export type ConnectivityErrorCode = "dns_resolution_failed" | "dns_timeout" | "dns_wrong_ip" | "tcp_connection_refused" | "tcp_connection_timeout" | "tcp_connection_reset" | "tcp_host_unreachable" | "tcp_network_unreachable" | "tls_self_signed_cert" | "tls_cert_expired" | "tls_cert_not_yet_valid" | "tls_cert_invalid" | "tls_cert_hostname_mismatch" | "tls_handshake_failed" | "tls_protocol_error" | "proxy_auth_required" | "proxy_connection_failed" | "proxy_tunnel_failed" | "http_unauthorized" | "http_forbidden" | "http_not_found" | "http_server_error" | "http_service_unavailable" | "latency_high" | "check_unavailable" | "unknown_error";
|
|
64
|
-
export type CheckType = "http" | "dns" | "tcp" | "tls" | "ssh";
|
|
64
|
+
export type CheckType = "http" | "websocket" | "dns" | "tcp" | "tls" | "ssh";
|
|
65
65
|
export type Recommendation = "ready_for_cloud_dev" | "enable_static_ip_proxy" | "whitelist_static_ip" | "fix_local_dns" | "fix_local_tls_certs" | "fix_local_firewall" | "use_local_development";
|
|
66
66
|
export type LikelyCause = "ip_whitelisting_required" | "vpn_blocking" | "corporate_proxy_required" | "self_signed_certificate" | "dns_misconfiguration" | "firewall_blocking" | "server_unavailable";
|
|
67
67
|
export type ConnectivityStatus = "pass" | "fail" | "unknown";
|
package/src/projects.d.ts
CHANGED
|
@@ -144,6 +144,8 @@ export interface ReadyMessage extends BaseMessage {
|
|
|
144
144
|
state: "ready";
|
|
145
145
|
message: string;
|
|
146
146
|
url: string;
|
|
147
|
+
/** Public kube hostnames (no scheme), e.g. `*.builderio.xyz` and `*.builderio.dev` when both are routed. */
|
|
148
|
+
hostnames?: string[];
|
|
147
149
|
status?: LaunchServerStatus;
|
|
148
150
|
}
|
|
149
151
|
export type MachineState = "unknown" | "created" | "starting" | "started" | "stopping" | "stopped" | "suspending" | "suspended" | "replacing" | "destroying" | "destroyed" | "not-found" | "running" | "failed";
|
|
@@ -480,6 +482,8 @@ export interface BranchSharedData {
|
|
|
480
482
|
kubeNamespace?: string | null;
|
|
481
483
|
kubePvcName?: string | null;
|
|
482
484
|
kubeHostname?: string | null;
|
|
485
|
+
/** Public kube hostnames for this branch (no scheme), when more than one domain is available. */
|
|
486
|
+
kubeHostnames?: string[] | null;
|
|
483
487
|
checkoutBranch?: string | null;
|
|
484
488
|
/** Whether this branch is for a fork PR - affects git operations (read-only, can't push) */
|
|
485
489
|
isFork?: boolean | null;
|
|
@@ -563,6 +567,10 @@ export interface ProjectAccessControl {
|
|
|
563
567
|
roles: Record<string, ProjectRolePermissions | null>;
|
|
564
568
|
users: Record<string, ProjectRolePermissions>;
|
|
565
569
|
}
|
|
570
|
+
export interface PreviewPasswordProtection {
|
|
571
|
+
enabled: boolean;
|
|
572
|
+
password?: string;
|
|
573
|
+
}
|
|
566
574
|
export interface Project {
|
|
567
575
|
id: string;
|
|
568
576
|
name: string;
|
|
@@ -686,6 +694,7 @@ export interface Project {
|
|
|
686
694
|
/** VPC peering ID for this project. Overrides the space-level defaultVpcPeering.
|
|
687
695
|
* References a document in the vpcPeerings collection. */
|
|
688
696
|
vpcPeering?: string;
|
|
697
|
+
previewPasswordProtection?: PreviewPasswordProtection;
|
|
689
698
|
};
|
|
690
699
|
screenshot: string | null;
|
|
691
700
|
isExample?: boolean;
|
|
@@ -823,6 +832,18 @@ export interface CreateBranchOptions {
|
|
|
823
832
|
gitAiBranch?: string | null;
|
|
824
833
|
/** Contextual information (e.g., a git diff) used by the backend to generate a friendly branch name via LLM */
|
|
825
834
|
branchContext?: string;
|
|
835
|
+
/**
|
|
836
|
+
* Lifecycle hook awaited by createBranch after the container is ready and
|
|
837
|
+
* before the initial message is dispatched to devtools/codegen. Use this to
|
|
838
|
+
* register webhook hooks so they're guaranteed to be in place before the
|
|
839
|
+
* first events stream out. Errors are caught + reported and do not block
|
|
840
|
+
* message dispatch.
|
|
841
|
+
*/
|
|
842
|
+
onContainerReady?: (info: {
|
|
843
|
+
projectId: string;
|
|
844
|
+
branchName: string;
|
|
845
|
+
url: string;
|
|
846
|
+
}) => Promise<void> | void;
|
|
826
847
|
}
|
|
827
848
|
interface BaseCreateBranchMessage {
|
|
828
849
|
}
|