@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 CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@builder.io/ai-utils",
3
- "version": "0.48.1",
3
+ "version": "0.50.0",
4
4
  "description": "Builder.io AI utils",
5
5
  "files": [
6
6
  "src"
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
  }