@builder.io/ai-utils 0.20.1 → 0.21.1

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.20.1",
3
+ "version": "0.21.1",
4
4
  "description": "Builder.io AI utils",
5
5
  "type": "module",
6
6
  "main": "src/index.js",
@@ -9,6 +9,14 @@
9
9
  ".": {
10
10
  "import": "./src/index.js",
11
11
  "types": "./src/index.d.ts"
12
+ },
13
+ "./src/connectivity/node": {
14
+ "import": "./src/connectivity/node.js",
15
+ "types": "./src/connectivity/node.d.ts"
16
+ },
17
+ "./src/connectivity/browser": {
18
+ "import": "./src/connectivity/browser.js",
19
+ "types": "./src/connectivity/browser.d.ts"
12
20
  }
13
21
  },
14
22
  "files": [
@@ -0,0 +1,7 @@
1
+ export type { Source, TestId, Test, RunChecksInput, ProgressEvent, CheckResult, CheckReport, ConnectivityErrorCode, CheckType, Recommendation, LikelyCause, ConnectivityStatus, AnalysisResult, AnalyzeConnectivityInput, } from "./types.js";
2
+ export { runChecks } from "./run-checks.browser.js";
3
+ export { mapNodeErrorToConnectivityCode, mapHttpStatusToErrorCode, mapFetchErrorToConnectivityCode, SELF_SIGNED_CERT_ERRORS, CERT_EXPIRED_ERRORS, CERT_NOT_YET_VALID_ERRORS, CERT_INVALID_ERRORS, CERT_HOSTNAME_MISMATCH_ERRORS, SSL_PROTOCOL_ERRORS, SSL_HANDSHAKE_ERRORS, NETWORK_UNREACHABLE_ERRORS, TIMEOUT_ERRORS, PROXY_ERRORS, DNS_ERRORS, } from "./error-codes.js";
4
+ export { BUILDER_TARGETS, DEFAULT_PORTS, resolveTarget, extractHostname, extractPort, } from "./targets.js";
5
+ export { isBrowser, isNode, getCheckTypeForTestId, isCheckAvailable, getUnavailabilityReason, } from "./environment.js";
6
+ export { httpCheck } from "./checks/http-check.js";
7
+ export type { HttpCheckOptions } from "./checks/http-check.js";
@@ -0,0 +1,5 @@
1
+ export { runChecks } from "./run-checks.browser.js";
2
+ export { mapNodeErrorToConnectivityCode, mapHttpStatusToErrorCode, mapFetchErrorToConnectivityCode, SELF_SIGNED_CERT_ERRORS, CERT_EXPIRED_ERRORS, CERT_NOT_YET_VALID_ERRORS, CERT_INVALID_ERRORS, CERT_HOSTNAME_MISMATCH_ERRORS, SSL_PROTOCOL_ERRORS, SSL_HANDSHAKE_ERRORS, NETWORK_UNREACHABLE_ERRORS, TIMEOUT_ERRORS, PROXY_ERRORS, DNS_ERRORS, } from "./error-codes.js";
3
+ export { BUILDER_TARGETS, DEFAULT_PORTS, resolveTarget, extractHostname, extractPort, } from "./targets.js";
4
+ export { isBrowser, isNode, getCheckTypeForTestId, isCheckAvailable, getUnavailabilityReason, } from "./environment.js";
5
+ export { httpCheck } from "./checks/http-check.js";
@@ -0,0 +1,8 @@
1
+ import type { CheckResult, Source, TestId } from "../types.js";
2
+ export interface DnsCheckOptions {
3
+ hostname: string;
4
+ source: Source;
5
+ testId: TestId;
6
+ timeout?: number;
7
+ }
8
+ export declare function dnsCheck(options: DnsCheckOptions): Promise<CheckResult>;
@@ -0,0 +1,96 @@
1
+ import dns from "dns";
2
+ import { mapNodeErrorToConnectivityCode } from "../error-codes.js";
3
+ const { resolve4, resolve6 } = dns.promises;
4
+ const DEFAULT_TIMEOUT_MS = 10000;
5
+ export async function dnsCheck(options) {
6
+ const { hostname, source, testId, timeout = DEFAULT_TIMEOUT_MS } = options;
7
+ const startTime = Date.now();
8
+ let timeoutId;
9
+ const timeoutPromise = new Promise((_, reject) => {
10
+ timeoutId = setTimeout(() => {
11
+ reject(new Error("DNS resolution timed out"));
12
+ }, timeout);
13
+ });
14
+ try {
15
+ let addresses = [];
16
+ let ipVersion = "IPv4";
17
+ try {
18
+ addresses = await Promise.race([resolve4(hostname), timeoutPromise]);
19
+ }
20
+ catch (ipv4Error) {
21
+ // If IPv4 fails with ENODATA/ENOTFOUND, try IPv6 before giving up
22
+ const err = ipv4Error;
23
+ if (err.code === "ENODATA" || err.code === "ENOTFOUND") {
24
+ try {
25
+ addresses = await Promise.race([resolve6(hostname), timeoutPromise]);
26
+ ipVersion = "IPv6";
27
+ }
28
+ catch (_a) {
29
+ throw ipv4Error;
30
+ }
31
+ }
32
+ else {
33
+ throw ipv4Error;
34
+ }
35
+ }
36
+ clearTimeout(timeoutId);
37
+ const durationMs = Date.now() - startTime;
38
+ if (addresses.length === 0) {
39
+ return {
40
+ source,
41
+ testId,
42
+ target: hostname,
43
+ passed: false,
44
+ errorCode: "dns_resolution_failed",
45
+ durationMs,
46
+ metadata: {
47
+ error: "No addresses resolved",
48
+ },
49
+ };
50
+ }
51
+ return {
52
+ source,
53
+ testId,
54
+ target: hostname,
55
+ passed: true,
56
+ durationMs,
57
+ metadata: {
58
+ addresses,
59
+ ipVersion,
60
+ addressCount: addresses.length,
61
+ },
62
+ };
63
+ }
64
+ catch (error) {
65
+ clearTimeout(timeoutId);
66
+ const durationMs = Date.now() - startTime;
67
+ const err = error;
68
+ if (err.message === "DNS resolution timed out") {
69
+ return {
70
+ source,
71
+ testId,
72
+ target: hostname,
73
+ passed: false,
74
+ errorCode: "dns_timeout",
75
+ durationMs,
76
+ metadata: {
77
+ error: err.message,
78
+ timeoutMs: timeout,
79
+ },
80
+ };
81
+ }
82
+ const errorCode = mapNodeErrorToConnectivityCode(err);
83
+ return {
84
+ source,
85
+ testId,
86
+ target: hostname,
87
+ passed: false,
88
+ errorCode,
89
+ durationMs,
90
+ metadata: {
91
+ error: err.message,
92
+ nodeErrorCode: err.code,
93
+ },
94
+ };
95
+ }
96
+ }
@@ -0,0 +1,8 @@
1
+ import type { CheckResult, Source, TestId } from "../types.js";
2
+ export interface HttpCheckOptions {
3
+ target: string;
4
+ source: Source;
5
+ testId: TestId;
6
+ timeout?: number;
7
+ }
8
+ export declare function httpCheck(options: HttpCheckOptions): Promise<CheckResult>;
@@ -0,0 +1,81 @@
1
+ import { mapHttpStatusToErrorCode, mapFetchErrorToConnectivityCode, } from "../error-codes.js";
2
+ const DEFAULT_TIMEOUT_MS = 30000;
3
+ const LATENCY_THRESHOLD_MS = 5000;
4
+ export async function httpCheck(options) {
5
+ const { target, source, testId, timeout = DEFAULT_TIMEOUT_MS } = options;
6
+ const startTime = Date.now();
7
+ const controller = new AbortController();
8
+ const timeoutId = setTimeout(() => controller.abort(), timeout);
9
+ try {
10
+ const response = await fetch(target, {
11
+ method: "HEAD",
12
+ signal: controller.signal,
13
+ redirect: "follow",
14
+ });
15
+ clearTimeout(timeoutId);
16
+ const durationMs = Date.now() - startTime;
17
+ const errorCode = mapHttpStatusToErrorCode(response.status);
18
+ const hasHighLatency = durationMs > LATENCY_THRESHOLD_MS;
19
+ if (errorCode) {
20
+ return {
21
+ source,
22
+ testId,
23
+ target,
24
+ passed: false,
25
+ errorCode,
26
+ durationMs,
27
+ metadata: {
28
+ statusCode: response.status,
29
+ statusText: response.statusText,
30
+ },
31
+ };
32
+ }
33
+ return {
34
+ source,
35
+ testId,
36
+ target,
37
+ passed: true,
38
+ durationMs,
39
+ errorCode: hasHighLatency ? "latency_high" : undefined,
40
+ metadata: {
41
+ statusCode: response.status,
42
+ statusText: response.statusText,
43
+ latencyHigh: hasHighLatency,
44
+ },
45
+ };
46
+ }
47
+ catch (error) {
48
+ clearTimeout(timeoutId);
49
+ const durationMs = Date.now() - startTime;
50
+ const err = error;
51
+ if (err.name === "AbortError") {
52
+ return {
53
+ source,
54
+ testId,
55
+ target,
56
+ passed: false,
57
+ errorCode: "tcp_connection_timeout",
58
+ durationMs,
59
+ metadata: {
60
+ error: "Request timed out",
61
+ timeoutMs: timeout,
62
+ },
63
+ };
64
+ }
65
+ const errorCode = mapFetchErrorToConnectivityCode(err);
66
+ return {
67
+ source,
68
+ testId,
69
+ target,
70
+ passed: false,
71
+ errorCode,
72
+ durationMs,
73
+ metadata: {
74
+ error: err.message,
75
+ ...(err.cause && {
76
+ causeCode: err.cause.code,
77
+ }),
78
+ },
79
+ };
80
+ }
81
+ }
@@ -0,0 +1,9 @@
1
+ import type { CheckResult, Source, TestId } from "../types.js";
2
+ export interface SshCheckOptions {
3
+ hostname: string;
4
+ port?: number;
5
+ source: Source;
6
+ testId: TestId;
7
+ timeout?: number;
8
+ }
9
+ export declare function sshCheck(options: SshCheckOptions): Promise<CheckResult>;
@@ -0,0 +1,108 @@
1
+ import net from "net";
2
+ import { mapNodeErrorToConnectivityCode } from "../error-codes.js";
3
+ const DEFAULT_PORT = 22;
4
+ const DEFAULT_TIMEOUT_MS = 5000;
5
+ const SSH_BANNER_PREFIX = "SSH-";
6
+ export async function sshCheck(options) {
7
+ var _a, _b;
8
+ const { hostname, port = DEFAULT_PORT, source, testId, timeout = DEFAULT_TIMEOUT_MS, } = options;
9
+ const target = `${hostname}:${port}`;
10
+ const startTime = Date.now();
11
+ try {
12
+ const result = await new Promise((resolve) => {
13
+ const socket = new net.Socket();
14
+ let banner = "";
15
+ socket.setTimeout(timeout);
16
+ socket.on("connect", () => {
17
+ // Wait for SSH banner data before closing
18
+ });
19
+ socket.on("data", (data) => {
20
+ banner += data.toString();
21
+ if (banner.includes("\n") || banner.length > 256) {
22
+ socket.destroy();
23
+ banner = banner.split("\n")[0].trim();
24
+ if (banner.startsWith(SSH_BANNER_PREFIX)) {
25
+ resolve({ success: true, banner });
26
+ }
27
+ else {
28
+ resolve({
29
+ success: false,
30
+ error: new Error(`Unexpected response: not an SSH server`),
31
+ banner,
32
+ });
33
+ }
34
+ }
35
+ });
36
+ socket.on("timeout", () => {
37
+ socket.destroy();
38
+ const error = new Error("SSH connection timed out");
39
+ error.code = "ETIMEDOUT";
40
+ resolve({ success: false, error });
41
+ });
42
+ socket.on("error", (err) => {
43
+ socket.destroy();
44
+ resolve({ success: false, error: err });
45
+ });
46
+ socket.on("end", () => {
47
+ if (!banner) {
48
+ resolve({
49
+ success: false,
50
+ error: new Error("Connection closed without receiving SSH banner"),
51
+ });
52
+ }
53
+ });
54
+ socket.connect(port, hostname);
55
+ });
56
+ const durationMs = Date.now() - startTime;
57
+ if (result.success) {
58
+ return {
59
+ source,
60
+ testId,
61
+ target,
62
+ passed: true,
63
+ durationMs,
64
+ metadata: {
65
+ hostname,
66
+ port,
67
+ banner: result.banner,
68
+ },
69
+ };
70
+ }
71
+ const errorCode = result.error
72
+ ? mapNodeErrorToConnectivityCode(result.error)
73
+ : "tcp_connection_refused";
74
+ return {
75
+ source,
76
+ testId,
77
+ target,
78
+ passed: false,
79
+ errorCode,
80
+ durationMs,
81
+ metadata: {
82
+ hostname,
83
+ port,
84
+ error: (_a = result.error) === null || _a === void 0 ? void 0 : _a.message,
85
+ nodeErrorCode: (_b = result.error) === null || _b === void 0 ? void 0 : _b.code,
86
+ banner: result.banner,
87
+ },
88
+ };
89
+ }
90
+ catch (error) {
91
+ const durationMs = Date.now() - startTime;
92
+ const err = error;
93
+ return {
94
+ source,
95
+ testId,
96
+ target,
97
+ passed: false,
98
+ errorCode: mapNodeErrorToConnectivityCode(err),
99
+ durationMs,
100
+ metadata: {
101
+ hostname,
102
+ port,
103
+ error: err.message,
104
+ nodeErrorCode: err.code,
105
+ },
106
+ };
107
+ }
108
+ }
@@ -0,0 +1,9 @@
1
+ import type { CheckResult, Source, TestId } from "../types.js";
2
+ export interface TcpCheckOptions {
3
+ hostname: string;
4
+ port?: number;
5
+ source: Source;
6
+ testId: TestId;
7
+ timeout?: number;
8
+ }
9
+ export declare function tcpCheck(options: TcpCheckOptions): Promise<CheckResult>;
@@ -0,0 +1,80 @@
1
+ import net from "net";
2
+ import { mapNodeErrorToConnectivityCode } from "../error-codes.js";
3
+ const DEFAULT_TIMEOUT_MS = 5000;
4
+ const DEFAULT_PORT = 443;
5
+ export async function tcpCheck(options) {
6
+ var _a, _b;
7
+ const { hostname, port = DEFAULT_PORT, source, testId, timeout = DEFAULT_TIMEOUT_MS, } = options;
8
+ const target = `${hostname}:${port}`;
9
+ const startTime = Date.now();
10
+ try {
11
+ const result = await new Promise((resolve) => {
12
+ const socket = new net.Socket();
13
+ socket.setTimeout(timeout);
14
+ socket.on("connect", () => {
15
+ socket.destroy();
16
+ resolve({ success: true });
17
+ });
18
+ socket.on("timeout", () => {
19
+ socket.destroy();
20
+ const error = new Error("Connection timed out");
21
+ error.code = "ETIMEDOUT";
22
+ resolve({ success: false, error });
23
+ });
24
+ socket.on("error", (err) => {
25
+ socket.destroy();
26
+ resolve({ success: false, error: err });
27
+ });
28
+ socket.connect(port, hostname);
29
+ });
30
+ const durationMs = Date.now() - startTime;
31
+ if (result.success) {
32
+ return {
33
+ source,
34
+ testId,
35
+ target,
36
+ passed: true,
37
+ durationMs,
38
+ metadata: {
39
+ hostname,
40
+ port,
41
+ },
42
+ };
43
+ }
44
+ const errorCode = result.error
45
+ ? mapNodeErrorToConnectivityCode(result.error)
46
+ : "tcp_connection_timeout";
47
+ return {
48
+ source,
49
+ testId,
50
+ target,
51
+ passed: false,
52
+ errorCode,
53
+ durationMs,
54
+ metadata: {
55
+ hostname,
56
+ port,
57
+ error: (_a = result.error) === null || _a === void 0 ? void 0 : _a.message,
58
+ nodeErrorCode: (_b = result.error) === null || _b === void 0 ? void 0 : _b.code,
59
+ },
60
+ };
61
+ }
62
+ catch (error) {
63
+ const durationMs = Date.now() - startTime;
64
+ const err = error;
65
+ return {
66
+ source,
67
+ testId,
68
+ target,
69
+ passed: false,
70
+ errorCode: mapNodeErrorToConnectivityCode(err),
71
+ durationMs,
72
+ metadata: {
73
+ hostname,
74
+ port,
75
+ error: err.message,
76
+ nodeErrorCode: err.code,
77
+ },
78
+ };
79
+ }
80
+ }
@@ -0,0 +1,9 @@
1
+ import type { CheckResult, Source, TestId } from "../types.js";
2
+ export interface TlsCheckOptions {
3
+ hostname: string;
4
+ port?: number;
5
+ source: Source;
6
+ testId: TestId;
7
+ timeout?: number;
8
+ }
9
+ export declare function tlsCheck(options: TlsCheckOptions): Promise<CheckResult>;
@@ -0,0 +1,113 @@
1
+ import tls from "tls";
2
+ import { mapNodeErrorToConnectivityCode } from "../error-codes.js";
3
+ const DEFAULT_TIMEOUT_MS = 10000;
4
+ const DEFAULT_PORT = 443;
5
+ export async function tlsCheck(options) {
6
+ var _a, _b;
7
+ const { hostname, port = DEFAULT_PORT, source, testId, timeout = DEFAULT_TIMEOUT_MS, } = options;
8
+ const target = `${hostname}:${port}`;
9
+ const startTime = Date.now();
10
+ try {
11
+ const result = await new Promise((resolve) => {
12
+ const socket = tls.connect({
13
+ host: hostname,
14
+ port,
15
+ servername: hostname, // SNI required for virtual hosts
16
+ rejectUnauthorized: true,
17
+ timeout,
18
+ }, () => {
19
+ const cert = socket.getPeerCertificate();
20
+ let certInfo;
21
+ if (cert && Object.keys(cert).length > 0) {
22
+ certInfo = {
23
+ subject: formatCertName(cert.subject),
24
+ issuer: formatCertName(cert.issuer),
25
+ validFrom: cert.valid_from,
26
+ validTo: cert.valid_to,
27
+ fingerprint: cert.fingerprint,
28
+ serialNumber: cert.serialNumber,
29
+ subjectAltNames: cert.subjectaltname
30
+ ? cert.subjectaltname.split(", ")
31
+ : undefined,
32
+ };
33
+ }
34
+ socket.end();
35
+ resolve({ success: true, certInfo });
36
+ });
37
+ socket.on("timeout", () => {
38
+ socket.destroy();
39
+ const error = new Error("TLS connection timed out");
40
+ error.code = "ETIMEDOUT";
41
+ resolve({ success: false, error });
42
+ });
43
+ socket.on("error", (err) => {
44
+ socket.destroy();
45
+ resolve({ success: false, error: err });
46
+ });
47
+ });
48
+ const durationMs = Date.now() - startTime;
49
+ if (result.success) {
50
+ return {
51
+ source,
52
+ testId,
53
+ target,
54
+ passed: true,
55
+ durationMs,
56
+ metadata: {
57
+ hostname,
58
+ port,
59
+ certificate: result.certInfo,
60
+ },
61
+ };
62
+ }
63
+ const errorCode = result.error
64
+ ? mapNodeErrorToConnectivityCode(result.error)
65
+ : "tls_handshake_failed";
66
+ return {
67
+ source,
68
+ testId,
69
+ target,
70
+ passed: false,
71
+ errorCode,
72
+ durationMs,
73
+ metadata: {
74
+ hostname,
75
+ port,
76
+ error: (_a = result.error) === null || _a === void 0 ? void 0 : _a.message,
77
+ nodeErrorCode: (_b = result.error) === null || _b === void 0 ? void 0 : _b.code,
78
+ },
79
+ };
80
+ }
81
+ catch (error) {
82
+ const durationMs = Date.now() - startTime;
83
+ const err = error;
84
+ return {
85
+ source,
86
+ testId,
87
+ target,
88
+ passed: false,
89
+ errorCode: mapNodeErrorToConnectivityCode(err),
90
+ durationMs,
91
+ metadata: {
92
+ hostname,
93
+ port,
94
+ error: err.message,
95
+ nodeErrorCode: err.code,
96
+ },
97
+ };
98
+ }
99
+ }
100
+ function formatCertName(name) {
101
+ if (!name) {
102
+ return "";
103
+ }
104
+ const parts = [];
105
+ const fields = ["CN", "O", "OU", "L", "ST", "C"];
106
+ for (const field of fields) {
107
+ const value = name[field];
108
+ if (value) {
109
+ parts.push(`${field}=${value}`);
110
+ }
111
+ }
112
+ return parts.join(", ");
113
+ }
@@ -0,0 +1,6 @@
1
+ import type { TestId, CheckType } from "./types.js";
2
+ export declare function isBrowser(): boolean;
3
+ export declare function isNode(): boolean;
4
+ export declare function getCheckTypeForTestId(testId: TestId): CheckType;
5
+ export declare function isCheckAvailable(checkType: CheckType): boolean;
6
+ export declare function getUnavailabilityReason(checkType: CheckType): string;
@@ -0,0 +1,27 @@
1
+ export function isBrowser() {
2
+ return (typeof window !== "undefined" && typeof window.document !== "undefined");
3
+ }
4
+ export function isNode() {
5
+ return (typeof process !== "undefined" &&
6
+ process.versions != null &&
7
+ process.versions.node != null);
8
+ }
9
+ export function getCheckTypeForTestId(testId) {
10
+ if (testId.startsWith("git-host:")) {
11
+ return testId.replace("git-host:", "");
12
+ }
13
+ return "http";
14
+ }
15
+ export function isCheckAvailable(checkType) {
16
+ if (checkType === "http") {
17
+ return true;
18
+ }
19
+ // DNS, TCP, TLS, and SSH checks require Node.js modules
20
+ return isNode();
21
+ }
22
+ export function getUnavailabilityReason(checkType) {
23
+ if (isBrowser()) {
24
+ return `${checkType.toUpperCase()} checks are not available in browser environments. Only HTTP checks can be performed from the browser.`;
25
+ }
26
+ return `${checkType.toUpperCase()} checks are not available in this environment.`;
27
+ }
@@ -0,0 +1,21 @@
1
+ import type { ConnectivityErrorCode } from "./types.js";
2
+ export declare const SELF_SIGNED_CERT_ERRORS: Set<string>;
3
+ export declare const CERT_EXPIRED_ERRORS: Set<string>;
4
+ export declare const CERT_NOT_YET_VALID_ERRORS: Set<string>;
5
+ export declare const CERT_INVALID_ERRORS: Set<string>;
6
+ export declare const CERT_HOSTNAME_MISMATCH_ERRORS: Set<string>;
7
+ export declare const SSL_PROTOCOL_ERRORS: Set<string>;
8
+ export declare const SSL_HANDSHAKE_ERRORS: Set<string>;
9
+ export declare const NETWORK_UNREACHABLE_ERRORS: Set<string>;
10
+ export declare const TIMEOUT_ERRORS: Set<string>;
11
+ export declare const PROXY_ERRORS: Set<string>;
12
+ export declare const DNS_ERRORS: Set<string>;
13
+ export declare function mapNodeErrorToConnectivityCode(error: Error & {
14
+ code?: string;
15
+ }): ConnectivityErrorCode;
16
+ export declare function mapHttpStatusToErrorCode(status: number): ConnectivityErrorCode | undefined;
17
+ export declare function mapFetchErrorToConnectivityCode(error: Error & {
18
+ cause?: Error & {
19
+ code?: string;
20
+ };
21
+ }): ConnectivityErrorCode;
@@ -0,0 +1,167 @@
1
+ export const SELF_SIGNED_CERT_ERRORS = new Set([
2
+ "DEPTH_ZERO_SELF_SIGNED_CERT",
3
+ "SELF_SIGNED_CERT_IN_CHAIN",
4
+ ]);
5
+ export const CERT_EXPIRED_ERRORS = new Set([
6
+ "CERT_HAS_EXPIRED",
7
+ "ERROR_IN_CERT_NOT_AFTER_FIELD",
8
+ ]);
9
+ // Most commonly caused by incorrect system clock settings
10
+ export const CERT_NOT_YET_VALID_ERRORS = new Set([
11
+ "CERT_NOT_YET_VALID",
12
+ "ERROR_IN_CERT_NOT_BEFORE_FIELD",
13
+ ]);
14
+ export const CERT_INVALID_ERRORS = new Set([
15
+ "UNABLE_TO_GET_ISSUER_CERT",
16
+ "UNABLE_TO_GET_ISSUER_CERT_LOCALLY",
17
+ "UNABLE_TO_VERIFY_LEAF_SIGNATURE",
18
+ "INVALID_CA",
19
+ "CERT_SIGNATURE_FAILURE",
20
+ "CERT_REVOKED",
21
+ "CERT_REJECTED",
22
+ "CERT_UNTRUSTED",
23
+ "CERT_CHAIN_TOO_LONG",
24
+ "PATH_LENGTH_EXCEEDED",
25
+ "INVALID_PURPOSE",
26
+ "UNABLE_TO_DECODE_ISSUER_PUBLIC_KEY",
27
+ "UNABLE_TO_DECRYPT_CERT_SIGNATURE",
28
+ ]);
29
+ export const CERT_HOSTNAME_MISMATCH_ERRORS = new Set([
30
+ "HOSTNAME_MISMATCH",
31
+ "ERR_TLS_CERT_ALTNAME_INVALID",
32
+ ]);
33
+ export const SSL_PROTOCOL_ERRORS = new Set([
34
+ "ERR_TLS_INVALID_PROTOCOL_VERSION",
35
+ "ERR_TLS_INVALID_PROTOCOL_METHOD",
36
+ "ERR_TLS_PROTOCOL_VERSION_CONFLICT",
37
+ "ERR_TLS_INVALID_STATE",
38
+ "ERR_TLS_INVALID_CONTEXT",
39
+ "ERR_TLS_RENEGOTIATION_DISABLED",
40
+ "ERR_TLS_REQUIRED_SERVER_NAME",
41
+ "ERR_TLS_SESSION_ATTACK",
42
+ "ERR_TLS_SNI_FROM_SERVER",
43
+ "ERR_TLS_DH_PARAM_SIZE",
44
+ "ERR_SSL_WRONG_VERSION_NUMBER",
45
+ "EPROTO",
46
+ ]);
47
+ export const SSL_HANDSHAKE_ERRORS = new Set([
48
+ "ERR_TLS_HANDSHAKE_TIMEOUT",
49
+ "ERR_SSL_HANDSHAKE_FAILURE",
50
+ ]);
51
+ export const NETWORK_UNREACHABLE_ERRORS = new Set([
52
+ "ENETUNREACH",
53
+ "EHOSTUNREACH",
54
+ "ENETDOWN",
55
+ "ENONET",
56
+ ]);
57
+ export const TIMEOUT_ERRORS = new Set([
58
+ "ETIMEDOUT",
59
+ "ESOCKETTIMEDOUT",
60
+ "ERR_SOCKET_CONNECTION_TIMEOUT",
61
+ "ERR_HTTP_REQUEST_TIMEOUT",
62
+ ]);
63
+ export const PROXY_ERRORS = new Set([
64
+ "ERR_PROXY_INVALID_CONFIG",
65
+ "ERR_PROXY_TUNNEL",
66
+ "ERR_TUNNEL_CONNECTION_FAILED",
67
+ ]);
68
+ export const DNS_ERRORS = new Set(["ENOTFOUND", "EAI_AGAIN", "ENODATA"]);
69
+ export function mapNodeErrorToConnectivityCode(error) {
70
+ const errorCode = error.code;
71
+ if (!errorCode) {
72
+ return "unknown_error";
73
+ }
74
+ if (DNS_ERRORS.has(errorCode)) {
75
+ return "dns_resolution_failed";
76
+ }
77
+ if (errorCode === "ECONNREFUSED") {
78
+ return "tcp_connection_refused";
79
+ }
80
+ if (errorCode === "ECONNRESET" || errorCode === "EPIPE") {
81
+ return "tcp_connection_reset";
82
+ }
83
+ if (TIMEOUT_ERRORS.has(errorCode)) {
84
+ return "tcp_connection_timeout";
85
+ }
86
+ if (errorCode === "ENETUNREACH" || errorCode === "ENETDOWN") {
87
+ return "tcp_network_unreachable";
88
+ }
89
+ if (errorCode === "EHOSTUNREACH") {
90
+ return "tcp_host_unreachable";
91
+ }
92
+ if (SELF_SIGNED_CERT_ERRORS.has(errorCode)) {
93
+ return "tls_self_signed_cert";
94
+ }
95
+ if (CERT_EXPIRED_ERRORS.has(errorCode)) {
96
+ return "tls_cert_expired";
97
+ }
98
+ if (CERT_NOT_YET_VALID_ERRORS.has(errorCode)) {
99
+ return "tls_cert_not_yet_valid";
100
+ }
101
+ if (CERT_HOSTNAME_MISMATCH_ERRORS.has(errorCode)) {
102
+ return "tls_cert_hostname_mismatch";
103
+ }
104
+ if (CERT_INVALID_ERRORS.has(errorCode)) {
105
+ return "tls_cert_invalid";
106
+ }
107
+ if (SSL_HANDSHAKE_ERRORS.has(errorCode)) {
108
+ return "tls_handshake_failed";
109
+ }
110
+ if (SSL_PROTOCOL_ERRORS.has(errorCode)) {
111
+ return "tls_protocol_error";
112
+ }
113
+ if (PROXY_ERRORS.has(errorCode)) {
114
+ return "proxy_tunnel_failed";
115
+ }
116
+ return "unknown_error";
117
+ }
118
+ export function mapHttpStatusToErrorCode(status) {
119
+ if (status >= 200 && status < 400) {
120
+ return undefined;
121
+ }
122
+ if (status === 407) {
123
+ return "proxy_auth_required";
124
+ }
125
+ if (status === 401) {
126
+ return "http_unauthorized";
127
+ }
128
+ if (status === 403) {
129
+ return "http_forbidden";
130
+ }
131
+ if (status === 404) {
132
+ return "http_not_found";
133
+ }
134
+ if (status === 503) {
135
+ return "http_service_unavailable";
136
+ }
137
+ if (status >= 500) {
138
+ return "http_server_error";
139
+ }
140
+ return "unknown_error";
141
+ }
142
+ // Fetch errors don't have Node.js-style error codes, so we inspect the message
143
+ export function mapFetchErrorToConnectivityCode(error) {
144
+ if (error.cause && "code" in error.cause) {
145
+ return mapNodeErrorToConnectivityCode(error.cause);
146
+ }
147
+ const message = error.message.toLowerCase();
148
+ if (message.includes("failed to fetch") || message.includes("network")) {
149
+ return "tcp_connection_refused";
150
+ }
151
+ if (message.includes("timeout") || message.includes("timed out")) {
152
+ return "tcp_connection_timeout";
153
+ }
154
+ if (message.includes("dns") || message.includes("not found")) {
155
+ return "dns_resolution_failed";
156
+ }
157
+ if (message.includes("certificate") || message.includes("ssl")) {
158
+ if (message.includes("expired")) {
159
+ return "tls_cert_expired";
160
+ }
161
+ if (message.includes("self-signed") || message.includes("self signed")) {
162
+ return "tls_self_signed_cert";
163
+ }
164
+ return "tls_cert_invalid";
165
+ }
166
+ return "unknown_error";
167
+ }
@@ -0,0 +1,15 @@
1
+ export type { Source, TestId, Test, RunChecksInput, ProgressEvent, CheckResult, CheckReport, ConnectivityErrorCode, CheckType, Recommendation, LikelyCause, ConnectivityStatus, AnalysisResult, AnalyzeConnectivityInput, } from "./types.js";
2
+ export { runChecks } from "./run-checks.js";
3
+ export { mapNodeErrorToConnectivityCode, mapHttpStatusToErrorCode, mapFetchErrorToConnectivityCode, SELF_SIGNED_CERT_ERRORS, CERT_EXPIRED_ERRORS, CERT_NOT_YET_VALID_ERRORS, CERT_INVALID_ERRORS, CERT_HOSTNAME_MISMATCH_ERRORS, SSL_PROTOCOL_ERRORS, SSL_HANDSHAKE_ERRORS, NETWORK_UNREACHABLE_ERRORS, TIMEOUT_ERRORS, PROXY_ERRORS, DNS_ERRORS, } from "./error-codes.js";
4
+ export { BUILDER_TARGETS, DEFAULT_PORTS, resolveTarget, extractHostname, extractPort, } from "./targets.js";
5
+ export { isBrowser, isNode, getCheckTypeForTestId, isCheckAvailable, getUnavailabilityReason, } from "./environment.js";
6
+ export { httpCheck } from "./checks/http-check.js";
7
+ export type { HttpCheckOptions } from "./checks/http-check.js";
8
+ export { dnsCheck } from "./checks/dns-check.js";
9
+ export type { DnsCheckOptions } from "./checks/dns-check.js";
10
+ export { tcpCheck } from "./checks/tcp-check.js";
11
+ export type { TcpCheckOptions } from "./checks/tcp-check.js";
12
+ export { tlsCheck } from "./checks/tls-check.js";
13
+ export type { TlsCheckOptions } from "./checks/tls-check.js";
14
+ export { sshCheck } from "./checks/ssh-check.js";
15
+ export type { SshCheckOptions } from "./checks/ssh-check.js";
@@ -0,0 +1,9 @@
1
+ export { runChecks } from "./run-checks.js";
2
+ export { mapNodeErrorToConnectivityCode, mapHttpStatusToErrorCode, mapFetchErrorToConnectivityCode, SELF_SIGNED_CERT_ERRORS, CERT_EXPIRED_ERRORS, CERT_NOT_YET_VALID_ERRORS, CERT_INVALID_ERRORS, CERT_HOSTNAME_MISMATCH_ERRORS, SSL_PROTOCOL_ERRORS, SSL_HANDSHAKE_ERRORS, NETWORK_UNREACHABLE_ERRORS, TIMEOUT_ERRORS, PROXY_ERRORS, DNS_ERRORS, } from "./error-codes.js";
3
+ export { BUILDER_TARGETS, DEFAULT_PORTS, resolveTarget, extractHostname, extractPort, } from "./targets.js";
4
+ export { isBrowser, isNode, getCheckTypeForTestId, isCheckAvailable, getUnavailabilityReason, } from "./environment.js";
5
+ export { httpCheck } from "./checks/http-check.js";
6
+ export { dnsCheck } from "./checks/dns-check.js";
7
+ export { tcpCheck } from "./checks/tcp-check.js";
8
+ export { tlsCheck } from "./checks/tls-check.js";
9
+ export { sshCheck } from "./checks/ssh-check.js";
@@ -0,0 +1,2 @@
1
+ import type { RunChecksInput, CheckReport } from "./types.js";
2
+ export declare function runChecks(input: RunChecksInput): Promise<CheckReport>;
@@ -0,0 +1,103 @@
1
+ import { resolveTarget } from "./targets.js";
2
+ import { getCheckTypeForTestId, isCheckAvailable, getUnavailabilityReason, } from "./environment.js";
3
+ import { httpCheck } from "./checks/http-check.js";
4
+ export async function runChecks(input) {
5
+ const { tests, gitHost, onProgress } = input;
6
+ const results = [];
7
+ const total = tests.length;
8
+ for (let index = 0; index < tests.length; index++) {
9
+ const test = tests[index];
10
+ emitProgress(onProgress, {
11
+ type: "test:start",
12
+ test,
13
+ index,
14
+ total,
15
+ });
16
+ const result = await runSingleCheck(test, gitHost);
17
+ results.push(result);
18
+ emitProgress(onProgress, {
19
+ type: "test:complete",
20
+ result,
21
+ index,
22
+ total,
23
+ });
24
+ }
25
+ emitProgress(onProgress, {
26
+ type: "batch:complete",
27
+ results,
28
+ });
29
+ return {
30
+ timestamp: new Date().toISOString(),
31
+ gitHost,
32
+ results,
33
+ };
34
+ }
35
+ async function runSingleCheck(test, gitHost) {
36
+ const { source, testId } = test;
37
+ const checkType = getCheckTypeForTestId(testId);
38
+ if (!isCheckAvailable(checkType)) {
39
+ const startTime = Date.now();
40
+ let target;
41
+ try {
42
+ target = resolveTarget(testId, gitHost);
43
+ }
44
+ catch (_a) {
45
+ target = gitHost || testId;
46
+ }
47
+ return {
48
+ source,
49
+ testId,
50
+ target,
51
+ passed: false,
52
+ errorCode: "check_unavailable",
53
+ durationMs: Date.now() - startTime,
54
+ metadata: {
55
+ reason: getUnavailabilityReason(checkType),
56
+ checkType,
57
+ },
58
+ };
59
+ }
60
+ let target;
61
+ try {
62
+ target = resolveTarget(testId, gitHost);
63
+ }
64
+ catch (error) {
65
+ return {
66
+ source,
67
+ testId,
68
+ target: gitHost || testId,
69
+ passed: false,
70
+ errorCode: "unknown_error",
71
+ durationMs: 0,
72
+ metadata: {
73
+ error: error.message,
74
+ },
75
+ };
76
+ }
77
+ switch (checkType) {
78
+ case "http":
79
+ return httpCheck({ target, source, testId });
80
+ default:
81
+ return {
82
+ source,
83
+ testId,
84
+ target,
85
+ passed: false,
86
+ errorCode: "check_unavailable",
87
+ durationMs: 0,
88
+ metadata: {
89
+ reason: `Check type "${checkType}" is not available in browser environments`,
90
+ },
91
+ };
92
+ }
93
+ }
94
+ function emitProgress(onProgress, event) {
95
+ if (onProgress) {
96
+ try {
97
+ onProgress(event);
98
+ }
99
+ catch (_a) {
100
+ // Ignore errors in progress callback to prevent breaking the check flow
101
+ }
102
+ }
103
+ }
@@ -0,0 +1,2 @@
1
+ import type { RunChecksInput, CheckReport } from "./types.js";
2
+ export declare function runChecks(input: RunChecksInput): Promise<CheckReport>;
@@ -0,0 +1,134 @@
1
+ import { resolveTarget, extractHostname, extractPort } from "./targets.js";
2
+ import { getCheckTypeForTestId, isCheckAvailable, getUnavailabilityReason, } from "./environment.js";
3
+ import { httpCheck } from "./checks/http-check.js";
4
+ import { dnsCheck } from "./checks/dns-check.js";
5
+ import { tcpCheck } from "./checks/tcp-check.js";
6
+ import { tlsCheck } from "./checks/tls-check.js";
7
+ import { sshCheck } from "./checks/ssh-check.js";
8
+ export async function runChecks(input) {
9
+ const { tests, gitHost, onProgress } = input;
10
+ const results = [];
11
+ const total = tests.length;
12
+ for (let index = 0; index < tests.length; index++) {
13
+ const test = tests[index];
14
+ emitProgress(onProgress, {
15
+ type: "test:start",
16
+ test,
17
+ index,
18
+ total,
19
+ });
20
+ const result = await runSingleCheck(test, gitHost);
21
+ results.push(result);
22
+ emitProgress(onProgress, {
23
+ type: "test:complete",
24
+ result,
25
+ index,
26
+ total,
27
+ });
28
+ }
29
+ emitProgress(onProgress, {
30
+ type: "batch:complete",
31
+ results,
32
+ });
33
+ return {
34
+ timestamp: new Date().toISOString(),
35
+ gitHost,
36
+ results,
37
+ };
38
+ }
39
+ async function runSingleCheck(test, gitHost) {
40
+ const { source, testId } = test;
41
+ const checkType = getCheckTypeForTestId(testId);
42
+ if (!isCheckAvailable(checkType)) {
43
+ const startTime = Date.now();
44
+ let target;
45
+ try {
46
+ target = resolveTarget(testId, gitHost);
47
+ }
48
+ catch (_a) {
49
+ target = gitHost || testId;
50
+ }
51
+ return {
52
+ source,
53
+ testId,
54
+ target,
55
+ passed: false,
56
+ errorCode: "check_unavailable",
57
+ durationMs: Date.now() - startTime,
58
+ metadata: {
59
+ reason: getUnavailabilityReason(checkType),
60
+ checkType,
61
+ },
62
+ };
63
+ }
64
+ let target;
65
+ try {
66
+ target = resolveTarget(testId, gitHost);
67
+ }
68
+ catch (error) {
69
+ return {
70
+ source,
71
+ testId,
72
+ target: gitHost || testId,
73
+ passed: false,
74
+ errorCode: "unknown_error",
75
+ durationMs: 0,
76
+ metadata: {
77
+ error: error.message,
78
+ },
79
+ };
80
+ }
81
+ switch (checkType) {
82
+ case "http":
83
+ return httpCheck({ target, source, testId });
84
+ case "dns":
85
+ return dnsCheck({
86
+ hostname: extractHostname(target),
87
+ source,
88
+ testId,
89
+ });
90
+ case "tcp":
91
+ return tcpCheck({
92
+ hostname: extractHostname(target),
93
+ port: extractPort(target, 443),
94
+ source,
95
+ testId,
96
+ });
97
+ case "tls":
98
+ return tlsCheck({
99
+ hostname: extractHostname(target),
100
+ port: extractPort(target, 443),
101
+ source,
102
+ testId,
103
+ });
104
+ case "ssh":
105
+ return sshCheck({
106
+ hostname: extractHostname(target),
107
+ port: 22,
108
+ source,
109
+ testId,
110
+ });
111
+ default:
112
+ return {
113
+ source,
114
+ testId,
115
+ target,
116
+ passed: false,
117
+ errorCode: "unknown_error",
118
+ durationMs: 0,
119
+ metadata: {
120
+ error: `Unknown check type: ${checkType}`,
121
+ },
122
+ };
123
+ }
124
+ }
125
+ function emitProgress(onProgress, event) {
126
+ if (onProgress) {
127
+ try {
128
+ onProgress(event);
129
+ }
130
+ catch (_a) {
131
+ // Ignore errors in progress callback to prevent breaking the check flow
132
+ }
133
+ }
134
+ }
@@ -0,0 +1,6 @@
1
+ import type { TestId } from "./types.js";
2
+ export declare const BUILDER_TARGETS: Record<string, string>;
3
+ export declare const DEFAULT_PORTS: Record<string, number>;
4
+ export declare function resolveTarget(testId: TestId, gitHost?: string): string;
5
+ export declare function extractHostname(target: string): string;
6
+ export declare function extractPort(target: string, defaultPort?: number): number;
@@ -0,0 +1,52 @@
1
+ export const BUILDER_TARGETS = {
2
+ "builder.io": "https://www.builder.io",
3
+ "builder.codes": "https://test.projects.builder.codes/proxy-health",
4
+ "api.builder.io": "https://api.builder.io/codegen/health",
5
+ "cdn.builder.io": "https://cdn.builder.io/api/v1/image/assets/TEMP/75a212ab82b6175c9862b125e0e23db8d369a58a?width=100",
6
+ "builderio.xyz": "https://builderio.xyz/health",
7
+ "fly.dev": "https://fly.dev",
8
+ };
9
+ export const DEFAULT_PORTS = {
10
+ http: 443,
11
+ https: 443,
12
+ ssh: 22,
13
+ tcp: 443,
14
+ tls: 443,
15
+ };
16
+ export function resolveTarget(testId, gitHost) {
17
+ if (testId.startsWith("git-host:")) {
18
+ if (!gitHost) {
19
+ throw new Error(`gitHost parameter is required for test "${testId}"`);
20
+ }
21
+ return gitHost;
22
+ }
23
+ const target = BUILDER_TARGETS[testId];
24
+ if (!target) {
25
+ throw new Error(`Unknown testId: ${testId}`);
26
+ }
27
+ return target;
28
+ }
29
+ export function extractHostname(target) {
30
+ try {
31
+ const url = new URL(target);
32
+ return url.hostname;
33
+ }
34
+ catch (_a) {
35
+ return target;
36
+ }
37
+ }
38
+ export function extractPort(target, defaultPort = 443) {
39
+ try {
40
+ const url = new URL(target);
41
+ if (url.port) {
42
+ return parseInt(url.port, 10);
43
+ }
44
+ if (url.protocol === "http:") {
45
+ return 80;
46
+ }
47
+ return defaultPort;
48
+ }
49
+ catch (_a) {
50
+ return defaultPort;
51
+ }
52
+ }
@@ -0,0 +1,66 @@
1
+ export type Source = "local" | "cloud" | "static-ip";
2
+ export type TestId = "builder.io" | "builder.codes" | "api.builder.io" | "cdn.builder.io" | "builderio.xyz" | "fly.dev" | "git-host:http" | "git-host:dns" | "git-host:tcp" | "git-host:tls" | "git-host:ssh";
3
+ export interface Test {
4
+ source: Source;
5
+ testId: TestId;
6
+ }
7
+ export interface RunChecksInput {
8
+ tests: Test[];
9
+ gitHost?: string;
10
+ onProgress?: (event: ProgressEvent) => void;
11
+ }
12
+ export type ProgressEvent = {
13
+ type: "test:start";
14
+ test: Test;
15
+ index: number;
16
+ total: number;
17
+ } | {
18
+ type: "test:complete";
19
+ result: CheckResult;
20
+ index: number;
21
+ total: number;
22
+ } | {
23
+ type: "batch:complete";
24
+ results: CheckResult[];
25
+ };
26
+ export interface CheckResult {
27
+ source: Source;
28
+ testId: TestId;
29
+ target: string;
30
+ passed: boolean;
31
+ errorCode?: ConnectivityErrorCode;
32
+ durationMs: number;
33
+ metadata?: Record<string, unknown>;
34
+ }
35
+ export interface CheckReport {
36
+ timestamp: string;
37
+ gitHost?: string;
38
+ results: CheckResult[];
39
+ }
40
+ 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";
41
+ export type CheckType = "http" | "dns" | "tcp" | "tls" | "ssh";
42
+ 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";
43
+ export type LikelyCause = "ip_whitelisting_required" | "vpn_blocking" | "corporate_proxy_required" | "self_signed_certificate" | "dns_misconfiguration" | "firewall_blocking" | "server_unavailable";
44
+ export type ConnectivityStatus = "pass" | "fail" | "unknown";
45
+ export interface AnalysisResult {
46
+ recommendation: Recommendation;
47
+ reason: string;
48
+ steps: string[];
49
+ fallback?: Recommendation;
50
+ likelyCause?: LikelyCause;
51
+ summary: {
52
+ localToBuilder: ConnectivityStatus;
53
+ localToGitHost: ConnectivityStatus;
54
+ cloudToGitHost: ConnectivityStatus;
55
+ staticIpToGitHost: ConnectivityStatus;
56
+ };
57
+ allResults: CheckResult[];
58
+ }
59
+ export interface AnalyzeConnectivityInput {
60
+ localResults: CheckResult[];
61
+ serverResults: CheckResult[];
62
+ spaceSettings: {
63
+ staticProxyEnabled: boolean;
64
+ };
65
+ gitHost: string;
66
+ }
@@ -0,0 +1 @@
1
+ export {};
package/src/events.d.ts CHANGED
@@ -419,4 +419,58 @@ export interface AssistantFusionSuggestionEvent {
419
419
  message: string;
420
420
  };
421
421
  }
422
+ export interface BaseFusionEvent<ExtraData extends Record<string, unknown> = {}, ExtraAttrs extends Record<string, string> = {}, V extends number = number> {
423
+ data: {
424
+ eventId: string;
425
+ ownerId: string;
426
+ userId: string | undefined;
427
+ source: string;
428
+ tags: string[];
429
+ audience: string;
430
+ private: boolean;
431
+ timestamp: number;
432
+ } & ExtraData;
433
+ attributes: {
434
+ eventName: string;
435
+ namespace: string;
436
+ version: `${V}`;
437
+ ownerId: string;
438
+ } & ExtraAttrs;
439
+ orderingKey?: string;
440
+ }
441
+ export type FusionEventVariant<EventName extends string, ExtraData extends Record<string, unknown> = {}, ExtraAttrs extends Record<string, string> = {}, V extends number = 1> = BaseFusionEvent<ExtraData, ExtraAttrs, V> & {
442
+ attributes: {
443
+ eventName: EventName;
444
+ };
445
+ };
446
+ export type AiTaskCompletedEvent = FusionEventVariant<"ai.task.completed", {
447
+ durationMs?: number;
448
+ success: boolean;
449
+ }, {
450
+ taskId: string;
451
+ }, 1>;
452
+ export declare const AiTaskCompletedEvent: {
453
+ eventName: "ai.task.completed";
454
+ version: "1";
455
+ };
456
+ export type AiTaskFailedEvent = FusionEventVariant<"ai.task.failed", {
457
+ durationMs?: number;
458
+ error: string;
459
+ }, {
460
+ taskId: string;
461
+ }, 1>;
462
+ export declare const AiTaskFailedEvent: {
463
+ eventName: "ai.task.failed";
464
+ version: "1";
465
+ };
466
+ export type GitPrCreatedEvent = FusionEventVariant<"git.pr.created", {
467
+ prNumber: number;
468
+ repo: string;
469
+ branch: string;
470
+ }, {}, 1>;
471
+ export declare const GitPrCreatedEvent: {
472
+ eventName: "git.pr.created";
473
+ version: "1";
474
+ };
475
+ export type FusionEvent = AiTaskCompletedEvent | AiTaskFailedEvent | GitPrCreatedEvent;
422
476
  export {};
package/src/events.js CHANGED
@@ -1 +1,12 @@
1
- export {};
1
+ export const AiTaskCompletedEvent = {
2
+ eventName: "ai.task.completed",
3
+ version: "1",
4
+ };
5
+ export const AiTaskFailedEvent = {
6
+ eventName: "ai.task.failed",
7
+ version: "1",
8
+ };
9
+ export const GitPrCreatedEvent = {
10
+ eventName: "git.pr.created",
11
+ version: "1",
12
+ };
package/src/index.d.ts CHANGED
@@ -9,3 +9,4 @@ export * from "./repo-indexing.js";
9
9
  export * from "./organization.js";
10
10
  export * from "./features.js";
11
11
  export * from "./vscode-tunnel.js";
12
+ export * from "./connectivity/types.js";
package/src/index.js CHANGED
@@ -9,3 +9,4 @@ export * from "./repo-indexing.js";
9
9
  export * from "./organization.js";
10
10
  export * from "./features.js";
11
11
  export * from "./vscode-tunnel.js";
12
+ export * from "./connectivity/types.js";
package/src/projects.d.ts CHANGED
@@ -535,7 +535,10 @@ export interface Project {
535
535
  authUser?: string;
536
536
  authPassword?: string;
537
537
  };
538
- qaBot?: boolean;
538
+ prReviewer?: {
539
+ enabled: boolean;
540
+ instructions?: string;
541
+ };
539
542
  postMergeMemories?: boolean;
540
543
  httpsServerKeyPath?: string;
541
544
  httpsServerCertPath?: string;