tensorlake 0.5.33 → 0.5.35

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.
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
package/dist/index.cjs CHANGED
@@ -35,7 +35,7 @@ var SDK_VERSION, API_URL, API_KEY, NAMESPACE, SANDBOX_PROXY_URL, DEFAULT_HTTP_TI
35
35
  var init_defaults = __esm({
36
36
  "src/defaults.ts"() {
37
37
  "use strict";
38
- SDK_VERSION = "0.5.33";
38
+ SDK_VERSION = "0.5.35";
39
39
  API_URL = process.env.TENSORLAKE_API_URL ?? "https://api.tensorlake.ai";
40
40
  API_KEY = process.env.TENSORLAKE_API_KEY ?? void 0;
41
41
  NAMESPACE = process.env.INDEXIFY_NAMESPACE ?? "default";
@@ -411,9 +411,23 @@ var init_http = __esm({
411
411
  });
412
412
 
413
413
  // src/models.ts
414
+ function camelToSnake(str) {
415
+ return str.replace(CAMEL_TO_SNAKE_RE, (ch) => "_" + ch.toLowerCase());
416
+ }
414
417
  function snakeToCamel(str) {
415
418
  return str.replace(/_([a-z])/g, (_, ch) => ch.toUpperCase());
416
419
  }
420
+ function toSnakeKeys(obj) {
421
+ if (Array.isArray(obj)) return obj.map(toSnakeKeys);
422
+ if (obj !== null && typeof obj === "object" && !(obj instanceof Date)) {
423
+ const result = {};
424
+ for (const [k, v] of Object.entries(obj)) {
425
+ result[camelToSnake(k)] = toSnakeKeys(v);
426
+ }
427
+ return result;
428
+ }
429
+ return obj;
430
+ }
417
431
  function parseTimestamp(v) {
418
432
  if (v == null) return void 0;
419
433
  if (v instanceof Date) return v;
@@ -452,7 +466,7 @@ function fromSnakeKeys(obj, idField) {
452
466
  }
453
467
  return obj;
454
468
  }
455
- var SandboxStatus, SnapshotStatus, ProcessStatus, StdinMode, OutputMode, ContainerState;
469
+ var SandboxStatus, SnapshotStatus, ProcessStatus, StdinMode, OutputMode, ContainerState, CAMEL_TO_SNAKE_RE;
456
470
  var init_models = __esm({
457
471
  "src/models.ts"() {
458
472
  "use strict";
@@ -477,6 +491,7 @@ var init_models = __esm({
477
491
  ProcessStatus2["RUNNING"] = "running";
478
492
  ProcessStatus2["EXITED"] = "exited";
479
493
  ProcessStatus2["SIGNALED"] = "signaled";
494
+ ProcessStatus2["OOM_KILLED"] = "oom_killed";
480
495
  return ProcessStatus2;
481
496
  })(ProcessStatus || {});
482
497
  StdinMode = /* @__PURE__ */ ((StdinMode2) => {
@@ -494,6 +509,7 @@ var init_models = __esm({
494
509
  ContainerState2["RUNNING"] = "Running";
495
510
  return ContainerState2;
496
511
  })(ContainerState || {});
512
+ CAMEL_TO_SNAKE_RE = /[A-Z]/g;
497
513
  }
498
514
  });
499
515
 
@@ -3651,6 +3667,11 @@ var init_sandbox = __esm({
3651
3667
  if (options?.stderrMode != null && options.stderrMode !== "capture" /* CAPTURE */) {
3652
3668
  payload.stderr_mode = options.stderrMode;
3653
3669
  }
3670
+ if (options?.name != null) payload.name = options.name;
3671
+ if (options?.restart != null) payload.restart = toSnakeKeys(options.restart);
3672
+ if (options?.healthCheck != null) {
3673
+ payload.health_check = toSnakeKeys(options.healthCheck);
3674
+ }
3654
3675
  const raw = await this.http.requestJson(
3655
3676
  "POST",
3656
3677
  "/api/v1/processes",
@@ -3679,6 +3700,14 @@ var init_sandbox = __esm({
3679
3700
  async killProcess(pid) {
3680
3701
  await this.http.requestJson("DELETE", `/api/v1/processes/${pid}`);
3681
3702
  }
3703
+ /** Restart a managed process by PID. */
3704
+ async restartProcess(pid) {
3705
+ const raw = await this.http.requestJson(
3706
+ "POST",
3707
+ `/api/v1/processes/${pid}/restart`
3708
+ );
3709
+ return Object.assign(fromSnakeKeys(raw), { traceId: raw.traceId });
3710
+ }
3682
3711
  /** Send an arbitrary signal to a process (e.g. `15` for SIGTERM, `9` for SIGKILL). */
3683
3712
  async sendSignal(pid, signal) {
3684
3713
  const raw = await this.http.requestJson(
@@ -3955,6 +3984,49 @@ var client_exports = {};
3955
3984
  __export(client_exports, {
3956
3985
  SandboxClient: () => SandboxClient
3957
3986
  });
3987
+ function cloudInitIncludeData(source) {
3988
+ const isWindowsPath = /^[A-Za-z]:[\\/]/.test(source);
3989
+ try {
3990
+ const url = new URL(source);
3991
+ if ((url.protocol === "http:" || url.protocol === "https:") && url.hostname.length > 0) {
3992
+ return Buffer.from(`#include
3993
+ ${url.toString()}
3994
+ `, "utf8");
3995
+ }
3996
+ if (!isWindowsPath) {
3997
+ throw new SandboxError(
3998
+ "cloud-init URL must be an absolute HTTP(S) URL with a host"
3999
+ );
4000
+ }
4001
+ } catch (error) {
4002
+ if (error instanceof SandboxError) throw error;
4003
+ if (!isWindowsPath && /^[A-Za-z][A-Za-z0-9+.-]*:/.test(source)) {
4004
+ throw new SandboxError(
4005
+ "cloud-init URL must be an absolute HTTP(S) URL with a host"
4006
+ );
4007
+ }
4008
+ }
4009
+ return void 0;
4010
+ }
4011
+ async function readCloudInitBase64(cloudInit) {
4012
+ if (cloudInit == null) return void 0;
4013
+ const sourceText = cloudInit instanceof URL ? cloudInit.toString() : cloudInit;
4014
+ const includeData = cloudInitIncludeData(sourceText);
4015
+ const data = includeData ?? await (0, import_promises.readFile)(sourceText).catch((error) => {
4016
+ throw new SandboxError(
4017
+ `failed to read cloud-init file ${JSON.stringify(sourceText)}: ${error}`
4018
+ );
4019
+ });
4020
+ if (data.length === 0) {
4021
+ throw new SandboxError("cloud-init user data must not be empty");
4022
+ }
4023
+ if (data.length > MAX_CLOUD_INIT_USER_DATA_BYTES) {
4024
+ throw new SandboxError(
4025
+ `cloud-init user data exceeds ${MAX_CLOUD_INIT_USER_DATA_BYTES} byte limit`
4026
+ );
4027
+ }
4028
+ return data.toString("base64");
4029
+ }
3958
4030
  function resolveRequestTimeoutMs(options) {
3959
4031
  if (options?.requestTimeout != null) {
3960
4032
  return secondsToMillis4(options.requestTimeout);
@@ -4032,10 +4104,11 @@ function validateUserPort(port) {
4032
4104
  function dedupeAndSortPorts(ports) {
4033
4105
  return [...new Set(ports)].sort((a, b) => a - b);
4034
4106
  }
4035
- var CREATE_SANDBOX_RETRYABLE_STATUS_CODES, CREATE_SANDBOX_ALLOWED_ERROR_STATUS_CODES, COPY_SANDBOX_ALLOWED_ERROR_STATUS_CODES, SandboxClient, RESERVED_SANDBOX_MANAGEMENT_PORT;
4107
+ var import_promises, CREATE_SANDBOX_RETRYABLE_STATUS_CODES, CREATE_SANDBOX_ALLOWED_ERROR_STATUS_CODES, COPY_SANDBOX_ALLOWED_ERROR_STATUS_CODES, MAX_CLOUD_INIT_USER_DATA_BYTES, SandboxClient, RESERVED_SANDBOX_MANAGEMENT_PORT;
4036
4108
  var init_client = __esm({
4037
4109
  "src/client.ts"() {
4038
4110
  "use strict";
4111
+ import_promises = require("fs/promises");
4039
4112
  init_defaults();
4040
4113
  init_errors();
4041
4114
  init_http();
@@ -4045,6 +4118,7 @@ var init_client = __esm({
4045
4118
  CREATE_SANDBOX_RETRYABLE_STATUS_CODES = /* @__PURE__ */ new Set([502, 503]);
4046
4119
  CREATE_SANDBOX_ALLOWED_ERROR_STATUS_CODES = /* @__PURE__ */ new Set([504]);
4047
4120
  COPY_SANDBOX_ALLOWED_ERROR_STATUS_CODES = /* @__PURE__ */ new Set([422, 504]);
4121
+ MAX_CLOUD_INIT_USER_DATA_BYTES = 16 * 1024;
4048
4122
  SandboxClient = class _SandboxClient {
4049
4123
  http;
4050
4124
  apiUrl;
@@ -4135,6 +4209,7 @@ var init_client = __esm({
4135
4209
  // --- Sandbox CRUD ---
4136
4210
  /** Create a new sandbox. Returns immediately; the sandbox may still be starting. Use `createAndConnect()` for a blocking, ready-to-use handle. */
4137
4211
  async create(options) {
4212
+ const cloudInitBase64 = await readCloudInitBase64(options?.cloudInit);
4138
4213
  const body = {
4139
4214
  resources: {
4140
4215
  cpus: options?.cpus ?? 1,
@@ -4147,6 +4222,7 @@ var init_client = __esm({
4147
4222
  if (options?.entrypoint != null) body.entrypoint = options.entrypoint;
4148
4223
  if (options?.snapshotId != null) body.snapshot_id = options.snapshotId;
4149
4224
  if (options?.name != null) body.name = options.name;
4225
+ if (cloudInitBase64 != null) body.cloud_init_base64 = cloudInitBase64;
4150
4226
  if (options?.allowInternetAccess === false || options?.allowOut != null || options?.denyOut != null) {
4151
4227
  body.network = {
4152
4228
  allow_internet_access: options?.allowInternetAccess ?? true,
@@ -4379,7 +4455,7 @@ var init_client = __esm({
4379
4455
  const client = this.withRequestTimeout(options?.requestTimeout);
4380
4456
  const raw = await client.http.requestJson(
4381
4457
  "POST",
4382
- client.path(`sandbox/${sandboxId}/copy?times=${encodeURIComponent(String(times))}`),
4458
+ client.path(`sandboxes/${sandboxId}/copy?times=${encodeURIComponent(String(times))}`),
4383
4459
  { allowedErrorStatusCodes: COPY_SANDBOX_ALLOWED_ERROR_STATUS_CODES }
4384
4460
  );
4385
4461
  const result = fromSnakeKeys(raw, "sandboxId");
@@ -4564,6 +4640,9 @@ var init_client = __esm({
4564
4640
  * @throws {SandboxError} If the sandbox terminates during startup or the timeout elapses.
4565
4641
  */
4566
4642
  async createAndConnect(options) {
4643
+ if (options?.poolId != null && options?.cloudInit != null) {
4644
+ throw new SandboxError("cloud-init cannot be used with poolId");
4645
+ }
4567
4646
  const requestTimeout = options?.requestTimeout ?? options?.startupTimeout ?? this.requestTimeoutMs / 1e3;
4568
4647
  const requestClient = this.withRequestTimeout(requestTimeout);
4569
4648
  const result = options?.poolId != null ? await requestClient.claim(options.poolId) : await requestClient.create(options);