@declaw/sdk 1.0.4 → 1.1.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/dist/index.js CHANGED
@@ -171,6 +171,12 @@ var ApiClient = class {
171
171
  }
172
172
  /**
173
173
  * Abort all in-flight requests and release resources.
174
+ *
175
+ * Since 1.1.1 the SDK maintains a process-wide shared ApiClient cache
176
+ * for hot class-method paths (Sandbox.create, Volumes.*, Template.*).
177
+ * Calling `close()` on a shared instance aborts its AbortController,
178
+ * which would cancel any concurrent in-flight call. Prefer
179
+ * `resetSharedClients()` if you want to tear down every cached client.
174
180
  */
175
181
  close() {
176
182
  this.abortController.abort();
@@ -290,6 +296,28 @@ var ApiClient = class {
290
296
  await new Promise((resolve) => setTimeout(resolve, ms));
291
297
  }
292
298
  };
299
+ var _sharedClients = /* @__PURE__ */ new Map();
300
+ function sharedKey(config) {
301
+ return [config.apiKey ?? "", config.apiUrl, config.requestTimeout ?? ""].join("|");
302
+ }
303
+ function getSharedClient(config) {
304
+ const key = sharedKey(config);
305
+ let client = _sharedClients.get(key);
306
+ if (!client) {
307
+ client = new ApiClient(config);
308
+ _sharedClients.set(key, client);
309
+ }
310
+ return client;
311
+ }
312
+ function resetSharedClients() {
313
+ for (const client of _sharedClients.values()) {
314
+ try {
315
+ client.close();
316
+ } catch {
317
+ }
318
+ }
319
+ _sharedClients.clear();
320
+ }
293
321
 
294
322
  // src/sandbox/network.ts
295
323
  var ALL_TRAFFIC = "0.0.0.0/0";
@@ -1693,6 +1721,23 @@ var Pty = class {
1693
1721
  }
1694
1722
  };
1695
1723
 
1724
+ // src/volumes/models.ts
1725
+ function parseVolumeInfo(data) {
1726
+ return {
1727
+ volumeId: String(data.volume_id ?? ""),
1728
+ ownerId: String(data.owner_id ?? ""),
1729
+ name: String(data.name ?? ""),
1730
+ blobKey: String(data.blob_key ?? ""),
1731
+ sizeBytes: Number(data.size_bytes ?? 0),
1732
+ contentType: String(data.content_type ?? ""),
1733
+ metadata: data.metadata ?? {},
1734
+ createdAt: String(data.created_at ?? "")
1735
+ };
1736
+ }
1737
+ function volumeAttachmentToJSON(att) {
1738
+ return { volume_id: att.volumeId, mount_path: att.mountPath };
1739
+ }
1740
+
1696
1741
  // src/sandbox/sandbox.ts
1697
1742
  var DEFAULT_TEMPLATE = "base";
1698
1743
  var DEFAULT_TIMEOUT = 300;
@@ -1822,51 +1867,49 @@ var Sandbox = class _Sandbox {
1822
1867
  apiUrl: opts?.apiUrl,
1823
1868
  requestTimeout: opts?.requestTimeout
1824
1869
  });
1825
- const client = new ApiClient(config);
1826
- try {
1827
- const body = {
1828
- template: opts?.template ?? DEFAULT_TEMPLATE,
1829
- timeout: opts?.timeout ?? DEFAULT_TIMEOUT,
1830
- secure: opts?.secure ?? true
1831
- };
1832
- if (opts?.metadata) {
1833
- body.metadata = opts.metadata;
1834
- }
1835
- if (opts?.envs) {
1836
- body.envs = opts.envs;
1837
- }
1838
- if (opts?.network) {
1839
- body.network = networkOptsToJSON(opts.network);
1840
- } else if (opts?.allowInternetAccess === false) {
1841
- body.network = { deny_out: [ALL_TRAFFIC] };
1842
- }
1843
- if (opts?.security) {
1844
- body.security = { policy_json: JSON.stringify(securityPolicyToJSON(opts.security)) };
1845
- if (opts.security.network && !body.network) {
1846
- body.network = typeof opts.security.network === "object" && "allowOut" in opts.security.network ? networkOptsToJSON(opts.security.network) : opts.security.network;
1847
- }
1848
- }
1849
- if (opts?.lifecycle) {
1850
- body.lifecycle = lifecycleToJSON(opts.lifecycle);
1870
+ const client = getSharedClient(config);
1871
+ const body = {
1872
+ template: opts?.template ?? DEFAULT_TEMPLATE,
1873
+ timeout: opts?.timeout ?? DEFAULT_TIMEOUT,
1874
+ secure: opts?.secure ?? true
1875
+ };
1876
+ if (opts?.metadata) {
1877
+ body.metadata = opts.metadata;
1878
+ }
1879
+ if (opts?.envs) {
1880
+ body.envs = opts.envs;
1881
+ }
1882
+ if (opts?.network) {
1883
+ body.network = networkOptsToJSON(opts.network);
1884
+ } else if (opts?.allowInternetAccess === false) {
1885
+ body.network = { deny_out: [ALL_TRAFFIC] };
1886
+ }
1887
+ if (opts?.security) {
1888
+ body.security = { policy_json: JSON.stringify(securityPolicyToJSON(opts.security)) };
1889
+ if (opts.security.network && !body.network) {
1890
+ body.network = typeof opts.security.network === "object" && "allowOut" in opts.security.network ? networkOptsToJSON(opts.security.network) : opts.security.network;
1851
1891
  }
1852
- const data = await client.post("/sandboxes", {
1853
- json: body,
1854
- timeout: opts?.requestTimeout
1855
- });
1856
- const sandboxId = data.sandbox_id;
1857
- assertValidId(sandboxId, "sandbox ID (from server)");
1858
- return new _Sandbox(
1859
- sandboxId,
1860
- config,
1861
- client,
1862
- data.envd_access_token,
1863
- data.sandbox_domain,
1864
- data.traffic_access_token
1865
- );
1866
- } catch (error) {
1867
- client.close();
1868
- throw error;
1869
1892
  }
1893
+ if (opts?.lifecycle) {
1894
+ body.lifecycle = lifecycleToJSON(opts.lifecycle);
1895
+ }
1896
+ if (opts?.volumes && opts.volumes.length > 0) {
1897
+ body.volumes = opts.volumes.map(volumeAttachmentToJSON);
1898
+ }
1899
+ const data = await client.post("/sandboxes", {
1900
+ json: body,
1901
+ timeout: opts?.requestTimeout
1902
+ });
1903
+ const sandboxId = data.sandbox_id;
1904
+ assertValidId(sandboxId, "sandbox ID (from server)");
1905
+ return new _Sandbox(
1906
+ sandboxId,
1907
+ config,
1908
+ client,
1909
+ data.envd_access_token,
1910
+ data.sandbox_domain,
1911
+ data.traffic_access_token
1912
+ );
1870
1913
  }
1871
1914
  /**
1872
1915
  * Connect to an existing sandbox.
@@ -1883,23 +1926,18 @@ var Sandbox = class _Sandbox {
1883
1926
  apiUrl: opts?.apiUrl,
1884
1927
  requestTimeout: opts?.requestTimeout
1885
1928
  });
1886
- const client = new ApiClient(config);
1887
- try {
1888
- const data = await client.get(`/sandboxes/${sandboxId}`, {
1889
- timeout: opts?.requestTimeout
1890
- });
1891
- return new _Sandbox(
1892
- data.sandbox_id,
1893
- config,
1894
- client,
1895
- data.envd_access_token,
1896
- data.sandbox_domain,
1897
- data.traffic_access_token
1898
- );
1899
- } catch (error) {
1900
- client.close();
1901
- throw error;
1902
- }
1929
+ const client = getSharedClient(config);
1930
+ const data = await client.get(`/sandboxes/${sandboxId}`, {
1931
+ timeout: opts?.requestTimeout
1932
+ });
1933
+ return new _Sandbox(
1934
+ data.sandbox_id,
1935
+ config,
1936
+ client,
1937
+ data.envd_access_token,
1938
+ data.sandbox_domain,
1939
+ data.traffic_access_token
1940
+ );
1903
1941
  }
1904
1942
  /**
1905
1943
  * List sandboxes.
@@ -1916,35 +1954,31 @@ var Sandbox = class _Sandbox {
1916
1954
  apiUrl: opts?.apiUrl,
1917
1955
  requestTimeout: opts?.requestTimeout
1918
1956
  });
1919
- const client = new ApiClient(config);
1920
- try {
1921
- const params = {};
1922
- if (opts?.query) {
1923
- for (const [key, value] of Object.entries(opts.query)) {
1924
- params[key] = value;
1925
- }
1926
- }
1927
- if (opts?.limit !== void 0) {
1928
- params.limit = String(opts.limit);
1929
- }
1930
- if (opts?.nextToken) {
1931
- params.next_token = opts.nextToken;
1957
+ const client = getSharedClient(config);
1958
+ const params = {};
1959
+ if (opts?.query) {
1960
+ for (const [key, value] of Object.entries(opts.query)) {
1961
+ params[key] = value;
1932
1962
  }
1933
- const data = await client.get("/sandboxes", {
1934
- params,
1935
- timeout: opts?.requestTimeout
1936
- });
1937
- const rawSandboxes = data.sandboxes ?? [];
1938
- const sandboxes = rawSandboxes.map(
1939
- (s) => parseSandboxInfo(s)
1940
- );
1941
- return {
1942
- sandboxes,
1943
- nextToken: data.next_token ?? void 0
1944
- };
1945
- } finally {
1946
- client.close();
1947
1963
  }
1964
+ if (opts?.limit !== void 0) {
1965
+ params.limit = String(opts.limit);
1966
+ }
1967
+ if (opts?.nextToken) {
1968
+ params.next_token = opts.nextToken;
1969
+ }
1970
+ const data = await client.get("/sandboxes", {
1971
+ params,
1972
+ timeout: opts?.requestTimeout
1973
+ });
1974
+ const rawSandboxes = data.sandboxes ?? [];
1975
+ const sandboxes = rawSandboxes.map(
1976
+ (s) => parseSandboxInfo(s)
1977
+ );
1978
+ return {
1979
+ sandboxes,
1980
+ nextToken: data.next_token ?? void 0
1981
+ };
1948
1982
  }
1949
1983
  /**
1950
1984
  * Kill this sandbox.
@@ -2096,33 +2130,31 @@ var Sandbox = class _Sandbox {
2096
2130
  apiUrl: options.apiUrl,
2097
2131
  requestTimeout: options.requestTimeout
2098
2132
  });
2099
- const client = new ApiClient(config);
2100
- try {
2101
- const query = options.snapshotId ? `?snapshot_id=${encodeURIComponent(options.snapshotId)}` : "";
2102
- await client.post(`/sandboxes/${sandboxId}/restore${query}`, {
2103
- timeout: options.requestTimeout
2104
- });
2105
- const data = await client.get(`/sandboxes/${sandboxId}`, {
2106
- timeout: options.requestTimeout
2107
- });
2108
- return new _Sandbox(
2109
- data.sandbox_id,
2110
- config,
2111
- client,
2112
- data.envd_access_token,
2113
- data.sandbox_domain,
2114
- data.traffic_access_token
2115
- );
2116
- } catch (error) {
2117
- client.close();
2118
- throw error;
2119
- }
2133
+ const client = getSharedClient(config);
2134
+ const query = options.snapshotId ? `?snapshot_id=${encodeURIComponent(options.snapshotId)}` : "";
2135
+ await client.post(`/sandboxes/${sandboxId}/restore${query}`, {
2136
+ timeout: options.requestTimeout
2137
+ });
2138
+ const data = await client.get(`/sandboxes/${sandboxId}`, {
2139
+ timeout: options.requestTimeout
2140
+ });
2141
+ return new _Sandbox(
2142
+ data.sandbox_id,
2143
+ config,
2144
+ client,
2145
+ data.envd_access_token,
2146
+ data.sandbox_domain,
2147
+ data.traffic_access_token
2148
+ );
2120
2149
  }
2121
2150
  /**
2122
- * Close the underlying HTTP client and release resources.
2151
+ * Historically closed the sandbox's HTTP client; since 1.1.1 the SDK
2152
+ * maintains a process-wide shared ApiClient (see `getSharedClient` in
2153
+ * api/client.ts) so per-sandbox close no longer tears the connection
2154
+ * pool down. Kept as a no-op for backwards compatibility — call
2155
+ * `resetSharedClients()` if you want to force a full teardown.
2123
2156
  */
2124
2157
  close() {
2125
- this._client.close();
2126
2158
  }
2127
2159
  /**
2128
2160
  * Support `await using sandbox = await Sandbox.create(...)` for automatic cleanup.
@@ -2352,36 +2384,32 @@ var Template = class {
2352
2384
  domain: opts?.domain,
2353
2385
  requestTimeout: opts?.requestTimeout
2354
2386
  });
2355
- const client = new ApiClient(config);
2356
- try {
2357
- const body = {
2358
- template: template.toJSON(),
2359
- alias
2360
- };
2361
- if (opts?.cpuCount !== void 0) {
2362
- body.cpu_count = opts.cpuCount;
2363
- }
2364
- if (opts?.memoryMb !== void 0) {
2365
- body.memory_mb = opts.memoryMb;
2366
- }
2367
- if (opts?.diskMb !== void 0) {
2368
- body.disk_mb = opts.diskMb;
2369
- }
2370
- const data = await client.post("/templates/build", {
2371
- json: body,
2372
- timeout: opts?.requestTimeout
2373
- });
2374
- const response = data;
2375
- const result = parseBuildInfo(response);
2376
- if (opts?.onBuildLogs && Array.isArray(response.logs)) {
2377
- for (const log of response.logs) {
2378
- opts.onBuildLogs(log);
2379
- }
2387
+ const client = getSharedClient(config);
2388
+ const body = {
2389
+ template: template.toJSON(),
2390
+ alias
2391
+ };
2392
+ if (opts?.cpuCount !== void 0) {
2393
+ body.cpu_count = opts.cpuCount;
2394
+ }
2395
+ if (opts?.memoryMb !== void 0) {
2396
+ body.memory_mb = opts.memoryMb;
2397
+ }
2398
+ if (opts?.diskMb !== void 0) {
2399
+ body.disk_mb = opts.diskMb;
2400
+ }
2401
+ const data = await client.post("/templates/build", {
2402
+ json: body,
2403
+ timeout: opts?.requestTimeout
2404
+ });
2405
+ const response = data;
2406
+ const result = parseBuildInfo(response);
2407
+ if (opts?.onBuildLogs && Array.isArray(response.logs)) {
2408
+ for (const log of response.logs) {
2409
+ opts.onBuildLogs(log);
2380
2410
  }
2381
- return result;
2382
- } finally {
2383
- client.close();
2384
2411
  }
2412
+ return result;
2385
2413
  }
2386
2414
  /**
2387
2415
  * Start a template build in the background.
@@ -2394,30 +2422,26 @@ var Template = class {
2394
2422
  domain: opts?.domain,
2395
2423
  requestTimeout: opts?.requestTimeout
2396
2424
  });
2397
- const client = new ApiClient(config);
2398
- try {
2399
- const body = {
2400
- template: template.toJSON(),
2401
- alias,
2402
- background: true
2403
- };
2404
- if (opts?.cpuCount !== void 0) {
2405
- body.cpu_count = opts.cpuCount;
2406
- }
2407
- if (opts?.memoryMb !== void 0) {
2408
- body.memory_mb = opts.memoryMb;
2409
- }
2410
- if (opts?.diskMb !== void 0) {
2411
- body.disk_mb = opts.diskMb;
2412
- }
2413
- const data = await client.post("/templates/build", {
2414
- json: body,
2415
- timeout: opts?.requestTimeout
2416
- });
2417
- return parseBuildInfo(data);
2418
- } finally {
2419
- client.close();
2425
+ const client = getSharedClient(config);
2426
+ const body = {
2427
+ template: template.toJSON(),
2428
+ alias,
2429
+ background: true
2430
+ };
2431
+ if (opts?.cpuCount !== void 0) {
2432
+ body.cpu_count = opts.cpuCount;
2433
+ }
2434
+ if (opts?.memoryMb !== void 0) {
2435
+ body.memory_mb = opts.memoryMb;
2420
2436
  }
2437
+ if (opts?.diskMb !== void 0) {
2438
+ body.disk_mb = opts.diskMb;
2439
+ }
2440
+ const data = await client.post("/templates/build", {
2441
+ json: body,
2442
+ timeout: opts?.requestTimeout
2443
+ });
2444
+ return parseBuildInfo(data);
2421
2445
  }
2422
2446
  /**
2423
2447
  * Get the status of a template build.
@@ -2431,15 +2455,86 @@ var Template = class {
2431
2455
  domain: opts?.domain,
2432
2456
  requestTimeout: opts?.requestTimeout
2433
2457
  });
2434
- const client = new ApiClient(config);
2435
- try {
2436
- const data = await client.get(`/templates/builds/${buildId}`, {
2437
- timeout: opts?.requestTimeout
2438
- });
2439
- return parseTemplateBuildStatus(data);
2440
- } finally {
2441
- client.close();
2458
+ const client = getSharedClient(config);
2459
+ const data = await client.get(`/templates/builds/${buildId}`, {
2460
+ timeout: opts?.requestTimeout
2461
+ });
2462
+ return parseTemplateBuildStatus(data);
2463
+ }
2464
+ };
2465
+
2466
+ // src/volumes/volumes.ts
2467
+ var VALID_VOLUME_ID_RE = /^[a-zA-Z0-9_-]+$/;
2468
+ function assertValidVolumeId(id) {
2469
+ if (!id || !VALID_VOLUME_ID_RE.test(id)) {
2470
+ throw new InvalidArgumentError(
2471
+ `Invalid volume ID: "${id}". Must be alphanumeric with hyphens/underscores only.`
2472
+ );
2473
+ }
2474
+ }
2475
+ var Volumes = class {
2476
+ /** Create a volume by streaming a tarball to the server. */
2477
+ static async create(name, data, opts) {
2478
+ if (!name) {
2479
+ throw new InvalidArgumentError("volume name is required");
2442
2480
  }
2481
+ const config = new ConnectionConfig({
2482
+ apiKey: opts?.apiKey,
2483
+ domain: opts?.domain,
2484
+ apiUrl: opts?.apiUrl,
2485
+ requestTimeout: opts?.requestTimeout
2486
+ });
2487
+ const client = getSharedClient(config);
2488
+ const body = data instanceof Uint8Array ? data : new Uint8Array(data);
2489
+ const resp = await client.post("/volumes", {
2490
+ params: { name },
2491
+ body,
2492
+ headers: { "Content-Type": opts?.contentType ?? "application/gzip" },
2493
+ timeout: opts?.requestTimeout
2494
+ });
2495
+ return parseVolumeInfo(resp);
2496
+ }
2497
+ /** Fetch metadata for a single volume. */
2498
+ static async get(volumeId, opts) {
2499
+ assertValidVolumeId(volumeId);
2500
+ const config = new ConnectionConfig({
2501
+ apiKey: opts?.apiKey,
2502
+ domain: opts?.domain,
2503
+ apiUrl: opts?.apiUrl,
2504
+ requestTimeout: opts?.requestTimeout
2505
+ });
2506
+ const client = getSharedClient(config);
2507
+ const resp = await client.get(`/volumes/${volumeId}`, {
2508
+ timeout: opts?.requestTimeout
2509
+ });
2510
+ return parseVolumeInfo(resp);
2511
+ }
2512
+ /** List all volumes owned by the caller, newest first. */
2513
+ static async list(opts) {
2514
+ const config = new ConnectionConfig({
2515
+ apiKey: opts?.apiKey,
2516
+ domain: opts?.domain,
2517
+ apiUrl: opts?.apiUrl,
2518
+ requestTimeout: opts?.requestTimeout
2519
+ });
2520
+ const client = getSharedClient(config);
2521
+ const resp = await client.get("/volumes", {
2522
+ timeout: opts?.requestTimeout
2523
+ });
2524
+ const rows = resp.volumes ?? [];
2525
+ return rows.map(parseVolumeInfo);
2526
+ }
2527
+ /** Delete a volume and its blob. Idempotent on the wire. */
2528
+ static async delete(volumeId, opts) {
2529
+ assertValidVolumeId(volumeId);
2530
+ const config = new ConnectionConfig({
2531
+ apiKey: opts?.apiKey,
2532
+ domain: opts?.domain,
2533
+ apiUrl: opts?.apiUrl,
2534
+ requestTimeout: opts?.requestTimeout
2535
+ });
2536
+ const client = getSharedClient(config);
2537
+ await client.delete(`/volumes/${volumeId}`, { timeout: opts?.requestTimeout });
2443
2538
  }
2444
2539
  };
2445
2540
  export {
@@ -2477,6 +2572,7 @@ export {
2477
2572
  TemplateError,
2478
2573
  TimeoutError,
2479
2574
  TransformDirection,
2575
+ Volumes,
2480
2576
  WatchHandle,
2481
2577
  applyTransformation,
2482
2578
  codeSecurityConfigToJSON,
@@ -2491,6 +2587,7 @@ export {
2491
2587
  createToxicityConfig,
2492
2588
  createTransformationRule,
2493
2589
  domainMatches,
2590
+ getSharedClient,
2494
2591
  invisibleTextConfigToJSON,
2495
2592
  isSensitive,
2496
2593
  networkPolicyToOpts,
@@ -2515,10 +2612,13 @@ export {
2515
2612
  parseSnapshotInfo,
2516
2613
  parseTemplateBuildStatus,
2517
2614
  parseToxicityConfig,
2615
+ parseVolumeInfo,
2518
2616
  parseWriteInfo,
2519
2617
  requiresTlsInterception,
2618
+ resetSharedClients,
2520
2619
  securityPolicyToJSON,
2521
2620
  toxicityConfigToJSON,
2522
- validateNetworkEntry
2621
+ validateNetworkEntry,
2622
+ volumeAttachmentToJSON
2523
2623
  };
2524
2624
  //# sourceMappingURL=index.js.map