bdy 1.25.0-dev → 1.25.1-beta

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.
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "bdy",
3
3
  "preferGlobal": false,
4
- "version": "1.25.0-dev",
4
+ "version": "1.25.1-beta",
5
5
  "type": "commonjs",
6
6
  "license": "MIT",
7
7
  "homepage": "https://buddy.works/docs/cli",
@@ -69,7 +69,7 @@
69
69
  "cross-spawn": "7.0.6",
70
70
  "dotenv": "17.4.2",
71
71
  "eventsource": "4.1.0",
72
- "fastify": "5.8.5",
72
+ "fastify": "5.12.3",
73
73
  "fdir": "6.5.0",
74
74
  "fflate": "0.8.3",
75
75
  "human-id": "4.2.0",
@@ -136,6 +136,6 @@
136
136
  "rollup-plugin-natives": "0.7.8",
137
137
  "typescript": "6.0.3",
138
138
  "typescript-eslint": "8.61.0",
139
- "vitest": "4.1.8"
139
+ "vitest": "4.1.11"
140
140
  }
141
141
  }
@@ -30,10 +30,24 @@ class ServerHttp2 extends events_1.default {
30
30
  // throttle owns the sweep timer and unrefs it, and stop() below shuts it down so a tunnel
31
31
  // restart leaves nothing behind.
32
32
  this.shedLog = new logThrottle_1.default(utils_1.TUNNEL_HTTP2_SHED_LOG_INTERVAL, (_kind, suppressed) => logger_js_1.default.info((0, texts_1.LOG_HTTP2_SESSION_SHED_TAIL)(suppressed)));
33
- this.server = http2_1.default.createServer((req, res) => this.processRequest(req, res));
33
+ // settings.initialWindowSize is the per-STREAM half of the upload window - see
34
+ // TUNNEL_H2_WINDOW_SIZE. The per-CONNECTION half is set on each session below, and neither
35
+ // works without the other.
36
+ this.server = http2_1.default.createServer({ settings: { initialWindowSize: utils_1.TUNNEL_H2_WINDOW_SIZE } }, (req, res) => this.processRequest(req, res));
34
37
  this.server.on('session', (session) => {
35
38
  session.id = (0, uuid_1.v4)();
36
39
  this.sessions += 1;
40
+ // The per-connection half. Wrapped because a session can die between this event and the call
41
+ // - a channel the worker dropped, a GOAWAY - and setLocalWindowSize throws on a destroyed one.
42
+ // This is throughput tuning: it may not take down a request, let alone the agent.
43
+ try {
44
+ if (!session.destroyed && !session.closed) {
45
+ session.setLocalWindowSize(utils_1.TUNNEL_H2_WINDOW_SIZE);
46
+ }
47
+ }
48
+ catch {
49
+ // do nothing
50
+ }
37
51
  // Streams in flight on THIS session. Http2Session runs its own frame-activity timer, which
38
52
  // works even though the underlying "socket" is an ssh2 channel with no setTimeout of its own -
39
53
  // but frame activity is not the same as being busy. A SILENT in-flight stream (SSE with long
@@ -36,9 +36,9 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
36
36
  return (mod && mod.__esModule) ? mod : { "default": mod };
37
37
  };
38
38
  Object.defineProperty(exports, "__esModule", { value: true });
39
- exports.TARGET_HTTP_REGEX = exports.TARGET_TCP_TLS_REGEX = exports.ApiErrorTunnelsDisabled = exports.ApiErrorWorkspaceFlagged = exports.ApiErrorTunnelLimitReached = exports.ApiErrorAgentLimitReached = exports.ApiErrorDomainRestricted = exports.ApiErrorTargetInvalid = exports.ApiErrorWrongToken = exports.ApiErrorFailedToConnect = exports.ApiErrorAgentNotFound = exports.ARTIFACT_AUTH_TYPE = exports.TARGET_EXEC_STATUS = exports.TARGET_SCOPE = exports.ARTIFACT_TYPE = exports.SANDBOX_SNAPSHOT_STATUS = exports.SANDBOX_APP_STATUS = exports.SANDBOX_SETUP_STATUS = exports.SANDBOX_EXEC_STATUS = exports.SANDBOX_EXEC_RUNTIME = exports.SANDBOX_STATUS = exports.REST_API_ENDPOINT = exports.REST_API_REGION = exports.DEFAULT_SANDBOX_CP_USER = exports.ARTIFACT_DEFAULT_VERSION = exports.SUGGESTED_BROWSER_VERSION = exports.AGENT_UPDATE_STATUS_TTL_MS = exports.AGENT_UPDATE_PROBATION_MS = exports.AGENT_UPDATE_MAX_ATTEMPTS = exports.AGENT_FETCH_RETRY_MAX = exports.AGENT_FETCH_RETRY_MIN = exports.SSH_HANDSHAKE_TIMEOUT = exports.DEFAULT_TIMEOUT = exports.getSshIdent = exports.TUNNEL_SSH_IDENT_SHARED_H1 = exports.TUNNEL_SSH_IDENT_SHARED_H2 = exports.TUNNEL_CLIENT_IP_HEADER = exports.TUNNEL_HTTP2_SHED_LOG_INTERVAL = exports.TUNNEL_HTTP2_MAX_SESSIONS = exports.TUNNEL_HTTP1_CHANNEL_KEEPALIVE = exports.TUNNEL_HTTP2_SESSION_IDLE_TIMEOUT = exports.TUNNEL_HTTP_RETRY_AFTER = exports.TUNNEL_HTTP_MAX_INFLIGHT = exports.TUNNEL_HTTP_CB_MIN_REQUESTS = exports.TUNNEL_HTTP_CB_WINDOW = exports.TUNNEL_MAX_REQUEST_SIZE_TO_SYNC = exports.TUNNEL_HTTP_LOG_MAX_REQUESTS = exports.TUNNEL_HTTP_LOG_MAX_BODY = exports.TUNNEL_HTTP_RATE_WINDOW = exports.TUNNEL_HTTP_RATE_LIMIT = void 0;
40
- exports.ARTIFACT_README_SIZE_LIMIT = exports.filterIgnoredEntries = exports.parseIgnorePatterns = exports.ARTIFACT_IGNORE_DEFAULT = exports.createZip = exports.getGitName = exports.getGitEmail = exports.MCP_TOOL_CATEGORIES = exports.getBasicCommandTls = exports.getBasicCommandHttp = exports.getBasicCommandSandboxEndpoint = exports.getBasicCommandTcp = exports.getCurrentUser = exports.getServiceUser = exports.getRealTargetHost = exports.isWindows = exports.isLinux = exports.isOsx = exports.isDocker = exports.truncate = exports.sleep = exports.getLatestVersion = exports.getVersionEnv = exports.getCurrentVersionWithoutEnv = exports.isVersionNewer = exports.getVersionWithoutEnv = exports.parseVersion = exports.getVersion = exports.isInstalledByChoco = exports.isInstalledByApt = exports.isInstalledByBrew = exports.isInstalledByNpm = exports.isNpmGlobalWritable = exports.isPathWritable = exports.tryGetEmail = exports.execLocally = exports.getHomeDirectory = exports.HOME_DIR_NAME = exports.chownToHomeOwner = exports.isDomainAvailable = exports.sandboxScopeOptions = exports.newCommand = exports.formatBytes = exports.formatHelp = exports.getPlatform = exports.getHostname = exports.isStringRegExp = exports.getWorkingDir = exports.getRootDir = exports.TARGET_ONLY_PORT_REGEX = void 0;
41
- exports.findArtifactReadme = exports.isPathInside = exports.getComposerReadmePath = exports.parseComposerJson = exports.ARTIFACT_README_NAMES = void 0;
39
+ exports.TARGET_TCP_TLS_REGEX = exports.ApiErrorTunnelsDisabled = exports.ApiErrorWorkspaceFlagged = exports.ApiErrorTunnelLimitReached = exports.ApiErrorAgentLimitReached = exports.ApiErrorDomainRestricted = exports.ApiErrorTargetInvalid = exports.ApiErrorWrongToken = exports.ApiErrorFailedToConnect = exports.ApiErrorAgentNotFound = exports.ARTIFACT_AUTH_TYPE = exports.TARGET_EXEC_STATUS = exports.TARGET_SCOPE = exports.ARTIFACT_TYPE = exports.SANDBOX_SNAPSHOT_STATUS = exports.SANDBOX_APP_STATUS = exports.SANDBOX_SETUP_STATUS = exports.SANDBOX_EXEC_STATUS = exports.SANDBOX_EXEC_RUNTIME = exports.SANDBOX_STATUS = exports.REST_API_ENDPOINT = exports.REST_API_REGION = exports.DEFAULT_SANDBOX_CP_USER = exports.ARTIFACT_DEFAULT_VERSION = exports.SUGGESTED_BROWSER_VERSION = exports.AGENT_UPDATE_STATUS_TTL_MS = exports.AGENT_UPDATE_PROBATION_MS = exports.AGENT_UPDATE_MAX_ATTEMPTS = exports.AGENT_FETCH_RETRY_MAX = exports.AGENT_FETCH_RETRY_MIN = exports.SSH_HANDSHAKE_TIMEOUT = exports.DEFAULT_TIMEOUT = exports.getSshIdent = exports.TUNNEL_SSH_IDENT_SHARED_H1 = exports.TUNNEL_SSH_IDENT_SHARED_H2 = exports.TUNNEL_CLIENT_IP_HEADER = exports.TUNNEL_H2_WINDOW_SIZE = exports.TUNNEL_HTTP2_SHED_LOG_INTERVAL = exports.TUNNEL_HTTP2_MAX_SESSIONS = exports.TUNNEL_HTTP1_CHANNEL_KEEPALIVE = exports.TUNNEL_HTTP2_SESSION_IDLE_TIMEOUT = exports.TUNNEL_HTTP_RETRY_AFTER = exports.TUNNEL_HTTP_MAX_INFLIGHT = exports.TUNNEL_HTTP_CB_MIN_REQUESTS = exports.TUNNEL_HTTP_CB_WINDOW = exports.TUNNEL_MAX_REQUEST_SIZE_TO_SYNC = exports.TUNNEL_HTTP_LOG_MAX_REQUESTS = exports.TUNNEL_HTTP_LOG_MAX_BODY = exports.TUNNEL_HTTP_RATE_WINDOW = exports.TUNNEL_HTTP_RATE_LIMIT = void 0;
40
+ exports.filterIgnoredEntries = exports.parseIgnorePatterns = exports.ARTIFACT_IGNORE_DEFAULT = exports.createZip = exports.getGitName = exports.getGitEmail = exports.MCP_TOOL_CATEGORIES = exports.getBasicCommandTls = exports.getBasicCommandHttp = exports.getBasicCommandSandboxEndpoint = exports.getBasicCommandTcp = exports.getCurrentUser = exports.getServiceUser = exports.getRealTargetHost = exports.isWindows = exports.isLinux = exports.isOsx = exports.isDocker = exports.truncate = exports.sleep = exports.getLatestVersion = exports.getVersionEnv = exports.getCurrentVersionWithoutEnv = exports.isVersionNewer = exports.getVersionWithoutEnv = exports.parseVersion = exports.getVersion = exports.isInstalledByChoco = exports.isInstalledByApt = exports.isInstalledByBrew = exports.isInstalledByNpm = exports.isNpmGlobalWritable = exports.isPathWritable = exports.tryGetEmail = exports.execLocally = exports.getHomeDirectory = exports.HOME_DIR_NAME = exports.chownToHomeOwner = exports.isDomainAvailable = exports.sandboxScopeOptions = exports.newCommand = exports.formatBytes = exports.formatHelp = exports.getPlatform = exports.getHostname = exports.isStringRegExp = exports.getWorkingDir = exports.getRootDir = exports.TARGET_ONLY_PORT_REGEX = exports.TARGET_HTTP_REGEX = void 0;
41
+ exports.findArtifactReadme = exports.isPathInside = exports.getComposerReadmePath = exports.parseComposerJson = exports.ARTIFACT_README_NAMES = exports.ARTIFACT_README_SIZE_LIMIT = void 0;
42
42
  exports.apiErrorCodeToClass = apiErrorCodeToClass;
43
43
  exports.isFile = isFile;
44
44
  exports.getAppWorkspaceUrl = getAppWorkspaceUrl;
@@ -106,6 +106,23 @@ exports.TUNNEL_HTTP2_MAX_SESSIONS = 4000;
106
106
  // (logger.checkLogSize), so an unthrottled stream would discard the evidence of the flood it is
107
107
  // recording. Mirrors PIPE_HTTP2_ADMISSION_LOG_INTERVAL on the worker side.
108
108
  exports.TUNNEL_HTTP2_SHED_LOG_INTERVAL = 60000;
109
+ // The h2 flow-control window this agent announces, and the half of the upload path only the CLI can
110
+ // set. Throughput in one direction is window/RTT, and node leaves both windows at the RFC 7540
111
+ // default of 65535 forever: measured on the worker's side of the same arithmetic, 343kB/s at 180ms
112
+ // RTT against 3526kB/s at 1MB. The worker widened what IT receives (worker/src/h2window.js), which
113
+ // covers downloads; what the worker may SEND us runs on the window announced here, so without this
114
+ // an upload stayed at the default no matter what the edge did.
115
+ //
116
+ // It must be applied in TWO places and neither works alone - the worker measured exactly that:
117
+ // `settings.initialWindowSize` at createServer is the per-STREAM window, announced in SETTINGS, and
118
+ // `session.setLocalWindowSize` is the per-CONNECTION one, which SETTINGS cannot carry.
119
+ //
120
+ // What it costs on a laptop: a window is CREDIT, not a buffer. Bytes are resident only where the
121
+ // peer sends faster than we consume, and they are bounded by the CONNECTION window rather than the
122
+ // sum of the streams. The theoretical ceiling is this times TUNNEL_HTTP2_MAX_SESSIONS, but the
123
+ // binding cap is TUNNEL_HTTP_MAX_INFLIGHT (2000) - and an agent taking thousands of concurrent
124
+ // backpressured uploads is already past what a laptop survives, window or no window.
125
+ exports.TUNNEL_H2_WINDOW_SIZE = 1024 * 1024;
109
126
  // Per-request client IP on a shared h2 channel (handshake type HTTP2_SHARED). Trusted ONLY on a
110
127
  // channel the worker opened as shared: on any other channel the address still comes from the
111
128
  // handshake, so an old worker - which does not strip a client-sent copy of this header - cannot be
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "bdy",
3
3
  "preferGlobal": false,
4
- "version": "1.25.0-dev",
4
+ "version": "1.25.1-beta",
5
5
  "type": "commonjs",
6
6
  "license": "MIT",
7
7
  "homepage": "https://buddy.works/docs/cli",
@@ -69,7 +69,7 @@
69
69
  "cross-spawn": "7.0.6",
70
70
  "dotenv": "17.4.2",
71
71
  "eventsource": "4.1.0",
72
- "fastify": "5.8.5",
72
+ "fastify": "5.12.3",
73
73
  "fdir": "6.5.0",
74
74
  "fflate": "0.8.3",
75
75
  "human-id": "4.2.0",
@@ -136,6 +136,6 @@
136
136
  "rollup-plugin-natives": "0.7.8",
137
137
  "typescript": "6.0.3",
138
138
  "typescript-eslint": "8.61.0",
139
- "vitest": "4.1.8"
139
+ "vitest": "4.1.11"
140
140
  }
141
141
  }