@declaw/sdk 1.1.10 → 1.1.12

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/CHANGELOG.md CHANGED
@@ -5,6 +5,31 @@ All notable changes to the Declaw TypeScript / JavaScript SDK are documented in
5
5
  The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
6
6
  and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
7
7
 
8
+ ## [1.1.12]
9
+
10
+ ### Changed
11
+
12
+ - `DECLAW_SDK_CONNECTIONS` default lowered from 256 to **100**. Combined
13
+ with the existing `DECLAW_SDK_MAX_CONCURRENT_STREAMS=1000` default,
14
+ this gives an effective in-flight ceiling of **100,000 concurrent
15
+ requests** per Node process (vs 256,000 in 1.1.11). The lower default
16
+ reduces idle TCP socket count and keeps the per-connection stream
17
+ count well clear of the server's advertised
18
+ `SETTINGS_MAX_CONCURRENT_STREAMS=4096`. Both knobs remain
19
+ configurable via env vars for callers that need higher or lower caps.
20
+
21
+ ## [1.1.11]
22
+
23
+ ### Added
24
+
25
+ - `sandbox.stdio.start(cmd)` — native interactive stdio for sandboxed
26
+ processes. Returns a `StdioProcess` handle with `sendStdin()`,
27
+ `closeStdin()`, `stream()`, `kill()`, and `wait()`. Supports
28
+ callbacks (`onStdout`, `onStderr`) and async iteration.
29
+ - `sandbox.getHost(port)` — inbound HTTP port proxy URL for accessing
30
+ services running inside the sandbox.
31
+ - `sandbox.getMcpUrl()` — convenience URL for MCP servers on port 50005.
32
+
8
33
  ## [1.1.8]
9
34
 
10
35
  ### Documentation
package/dist/index.cjs CHANGED
@@ -59,6 +59,8 @@ __export(index_exports, {
59
59
  SandboxPaginator: () => SandboxPaginator,
60
60
  SandboxState: () => SandboxState,
61
61
  SnapshotPaginator: () => SnapshotPaginator,
62
+ Stdio: () => Stdio,
63
+ StdioProcess: () => StdioProcess,
62
64
  Template: () => Template,
63
65
  TemplateBase: () => TemplateBase,
64
66
  TemplateError: () => TemplateError,
@@ -246,9 +248,16 @@ function getDispatcher() {
246
248
  }
247
249
  const undici = await import("undici");
248
250
  const connOverride = parseInt(process.env.DECLAW_SDK_CONNECTIONS || "", 10);
249
- const connections = Number.isFinite(connOverride) && connOverride > 0 ? connOverride : 64;
251
+ const connections = Number.isFinite(connOverride) && connOverride > 0 ? connOverride : 100;
252
+ const streamsOverride = parseInt(process.env.DECLAW_SDK_MAX_CONCURRENT_STREAMS || "", 10);
253
+ const maxConcurrentStreams = Number.isFinite(streamsOverride) && streamsOverride > 0 ? streamsOverride : 1e3;
250
254
  return new undici.Agent({
251
255
  connections,
256
+ // maxConcurrentStreams only matters on H2 connections. undici negotiates
257
+ // down to whatever the server advertises in SETTINGS_MAX_CONCURRENT_STREAMS,
258
+ // so setting a high value here is safe — it caps the client-side intent,
259
+ // server still wins.
260
+ maxConcurrentStreams,
252
261
  keepAliveTimeout: 3e4,
253
262
  keepAliveMaxTimeout: 6e4,
254
263
  pipelining: 1,
@@ -1878,6 +1887,136 @@ var Pty = class {
1878
1887
  }
1879
1888
  };
1880
1889
 
1890
+ // src/sandbox/stdio/stdio.ts
1891
+ var import_stream2 = require("eventsource-parser/stream");
1892
+ var StdioProcess = class {
1893
+ cmdId;
1894
+ sandboxId;
1895
+ client;
1896
+ lastEntryId = 0;
1897
+ _exitCode = null;
1898
+ _bgStream = null;
1899
+ constructor(cmdId, sandboxId, client, opts) {
1900
+ this.cmdId = cmdId;
1901
+ this.sandboxId = sandboxId;
1902
+ this.client = client;
1903
+ if (opts?.onStdout || opts?.onStderr) {
1904
+ this._bgStream = this.stream({
1905
+ onStdout: opts.onStdout,
1906
+ onStderr: opts.onStderr
1907
+ });
1908
+ }
1909
+ }
1910
+ get exitCode() {
1911
+ return this._exitCode;
1912
+ }
1913
+ async sendStdin(data, requestTimeout) {
1914
+ const raw = typeof data === "string" ? new TextEncoder().encode(data) : data;
1915
+ let binary = "";
1916
+ for (let i = 0; i < raw.length; i++) {
1917
+ binary += String.fromCharCode(raw[i]);
1918
+ }
1919
+ const encoded = btoa(binary);
1920
+ await this.client.post(
1921
+ `/sandboxes/${this.sandboxId}/stdio/${this.cmdId}/stdin`,
1922
+ {
1923
+ json: { data: encoded },
1924
+ timeout: requestTimeout
1925
+ }
1926
+ );
1927
+ }
1928
+ async closeStdin(requestTimeout) {
1929
+ await this.client.post(
1930
+ `/sandboxes/${this.sandboxId}/stdio/${this.cmdId}/stdin/close`,
1931
+ { timeout: requestTimeout }
1932
+ );
1933
+ }
1934
+ async kill(requestTimeout) {
1935
+ const resp = await this.client.delete(
1936
+ `/sandboxes/${this.sandboxId}/stdio/${this.cmdId}`,
1937
+ { timeout: requestTimeout }
1938
+ );
1939
+ return Boolean(resp.killed);
1940
+ }
1941
+ async wait() {
1942
+ if (this._bgStream) {
1943
+ return this._bgStream;
1944
+ }
1945
+ return this.stream();
1946
+ }
1947
+ async stream(opts) {
1948
+ if (this._bgStream && !opts) {
1949
+ return this._bgStream;
1950
+ }
1951
+ let url = `/sandboxes/${this.sandboxId}/stdio/${this.cmdId}/stream`;
1952
+ if (this.lastEntryId > 0) {
1953
+ url += `?last_entry_id=${this.lastEntryId}`;
1954
+ }
1955
+ const response = await this.client.streamGet(url);
1956
+ const stream = response.body;
1957
+ if (!stream) {
1958
+ throw new SandboxError("No response body for stdio stream");
1959
+ }
1960
+ const eventStream = stream.pipeThrough(new TextDecoderStream()).pipeThrough(new import_stream2.EventSourceParserStream());
1961
+ for await (const event of eventStream) {
1962
+ if (event.event === "exit") {
1963
+ try {
1964
+ const parsed = JSON.parse(event.data);
1965
+ this._exitCode = parsed.exit_code ?? -1;
1966
+ } catch {
1967
+ this._exitCode = -1;
1968
+ }
1969
+ break;
1970
+ }
1971
+ if (event.event === "stdout" || event.event === "stderr") {
1972
+ try {
1973
+ const parsed = JSON.parse(event.data);
1974
+ const entryId = parsed.entry_id ?? 0;
1975
+ if (entryId > this.lastEntryId) {
1976
+ this.lastEntryId = entryId;
1977
+ }
1978
+ const raw = atob(parsed.data ?? "");
1979
+ const bytes = new Uint8Array(raw.length);
1980
+ for (let i = 0; i < raw.length; i++) {
1981
+ bytes[i] = raw.charCodeAt(i);
1982
+ }
1983
+ if (event.event === "stdout" && opts?.onStdout) {
1984
+ opts.onStdout(bytes);
1985
+ } else if (event.event === "stderr" && opts?.onStderr) {
1986
+ opts.onStderr(bytes);
1987
+ }
1988
+ } catch {
1989
+ continue;
1990
+ }
1991
+ }
1992
+ }
1993
+ return { exitCode: this._exitCode ?? -1 };
1994
+ }
1995
+ };
1996
+ var Stdio = class {
1997
+ sandboxId;
1998
+ client;
1999
+ constructor(sandboxId, client) {
2000
+ this.sandboxId = sandboxId;
2001
+ this.client = client;
2002
+ }
2003
+ async start(cmd, opts) {
2004
+ const user = opts?.user ?? "user";
2005
+ const body = { cmd, user };
2006
+ if (opts?.envs) body.envs = opts.envs;
2007
+ if (opts?.cwd) body.cwd = opts.cwd;
2008
+ const data = await this.client.post(
2009
+ `/sandboxes/${this.sandboxId}/stdio`,
2010
+ { json: body, timeout: opts?.requestTimeout }
2011
+ );
2012
+ const cmdId = data.cmd_id;
2013
+ return new StdioProcess(cmdId, this.sandboxId, this.client, {
2014
+ onStdout: opts?.onStdout,
2015
+ onStderr: opts?.onStderr
2016
+ });
2017
+ }
2018
+ };
2019
+
1881
2020
  // src/volumes/models.ts
1882
2021
  function parseVolumeInfo(data) {
1883
2022
  return {
@@ -1917,6 +2056,7 @@ var Sandbox = class _Sandbox {
1917
2056
  _commands;
1918
2057
  _files;
1919
2058
  _pty;
2059
+ _stdio;
1920
2060
  constructor(sandboxId, config, client, envdAccessToken, sandboxDomain, trafficAccessToken) {
1921
2061
  this._sandboxId = sandboxId;
1922
2062
  this._config = config;
@@ -1927,6 +2067,7 @@ var Sandbox = class _Sandbox {
1927
2067
  this._commands = new Commands(sandboxId, client);
1928
2068
  this._files = new Filesystem(sandboxId, client);
1929
2069
  this._pty = new Pty(sandboxId, client);
2070
+ this._stdio = new Stdio(sandboxId, client);
1930
2071
  }
1931
2072
  /** The unique sandbox identifier. */
1932
2073
  get sandboxId() {
@@ -1960,6 +2101,10 @@ var Sandbox = class _Sandbox {
1960
2101
  get pty() {
1961
2102
  return this._pty;
1962
2103
  }
2104
+ /** Stdio sub-module for interactive subprocess sessions with stdin pipe. */
2105
+ get stdio() {
2106
+ return this._stdio;
2107
+ }
1963
2108
  /**
1964
2109
  * Base URL for this sandbox's namespace on the Declaw API.
1965
2110
  *
@@ -1973,17 +2118,15 @@ var Sandbox = class _Sandbox {
1973
2118
  /**
1974
2119
  * Return the path-based URL that reverse-proxies to `port` inside the sandbox.
1975
2120
  *
1976
- * Note: the reverse-proxy backend is not yet deployed; calls to the returned
1977
- * URL will 404 until that feature ships. The URL shape is stable and safe to
1978
- * script against.
2121
+ * Requires `allowPublicTraffic` to be enabled on the sandbox's network
2122
+ * config (the default). The returned URL is authenticated via the same
2123
+ * API key as all other sandbox operations.
1979
2124
  */
1980
2125
  getHost(port) {
1981
2126
  return `${this.envdApiUrl}/ports/${port}`;
1982
2127
  }
1983
2128
  /**
1984
2129
  * Return the URL for an MCP server listening on port 50005 inside the sandbox.
1985
- *
1986
- * Same deployment caveat as {@link getHost}.
1987
2130
  */
1988
2131
  getMcpUrl() {
1989
2132
  return `${this.getHost(MCP_PORT)}/mcp`;
@@ -2819,6 +2962,8 @@ var Volumes = class {
2819
2962
  SandboxPaginator,
2820
2963
  SandboxState,
2821
2964
  SnapshotPaginator,
2965
+ Stdio,
2966
+ StdioProcess,
2822
2967
  Template,
2823
2968
  TemplateBase,
2824
2969
  TemplateError,