tensorlake 0.5.89 → 0.5.91

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.d.cts CHANGED
@@ -422,8 +422,16 @@ interface CreatePoolOptions {
422
422
  entrypoint?: string[];
423
423
  maxContainers?: number;
424
424
  warmContainers?: number;
425
+ /** Network policy for each container. Can be replaced later via updatePool. */
426
+ network?: NetworkConfig;
425
427
  }
426
428
  interface UpdatePoolOptions {
429
+ /**
430
+ * Network policy for each container. Omit to keep the pool's current policy,
431
+ * set to replace it, or pass `null` to remove it (unclaimed warm containers
432
+ * are recycled onto the new policy).
433
+ */
434
+ network?: NetworkConfig | null;
427
435
  /** Sandbox image name, such as `tensorlake/ubuntu-minimal` or a registered Sandbox Image. */
428
436
  image: string;
429
437
  cpus?: number;
@@ -454,6 +462,8 @@ interface SandboxPoolInfo {
454
462
  entrypoint?: string[];
455
463
  maxContainers?: number;
456
464
  warmContainers?: number;
465
+ /** The network policy that applies to each container in the pool. */
466
+ networkPolicy?: NetworkConfig;
457
467
  containers?: PoolContainerInfo[];
458
468
  createdAt?: Date;
459
469
  updatedAt?: Date;
@@ -1152,7 +1162,13 @@ declare class SandboxClient {
1152
1162
  getPool(poolId: string): Promise<SandboxPoolInfo>;
1153
1163
  /** List all sandbox pools in the namespace. */
1154
1164
  listPools(): Promise<Traced<SandboxPoolInfo[]>>;
1155
- /** Replace the configuration of an existing sandbox pool. */
1165
+ /**
1166
+ * Replace a pool configuration. Omit `network` to keep the pool's current
1167
+ * network policy, set it to replace the policy, or pass `null` to remove the
1168
+ * policy entirely. On a change the service recycles the pool's unclaimed
1169
+ * warm containers onto the new policy, while containers already claimed by
1170
+ * sandboxes keep the policy they booted with.
1171
+ */
1156
1172
  updatePool(poolId: string, options: UpdatePoolOptions): Promise<SandboxPoolInfo>;
1157
1173
  /** Delete a sandbox pool. Fails if the pool has active containers. */
1158
1174
  deletePool(poolId: string): Promise<void>;
@@ -1262,6 +1278,7 @@ declare class CloudClient {
1262
1278
  streamBuildLogs(buildServicePath: string, buildId: string, signal?: AbortSignal): AsyncIterable<BuildLogEntry>;
1263
1279
  private runMultipartRequest;
1264
1280
  private namespacePath;
1281
+ private existingApplicationPublicEndpointId;
1265
1282
  private resolveScope;
1266
1283
  }
1267
1284
 
package/dist/index.d.ts CHANGED
@@ -422,8 +422,16 @@ interface CreatePoolOptions {
422
422
  entrypoint?: string[];
423
423
  maxContainers?: number;
424
424
  warmContainers?: number;
425
+ /** Network policy for each container. Can be replaced later via updatePool. */
426
+ network?: NetworkConfig;
425
427
  }
426
428
  interface UpdatePoolOptions {
429
+ /**
430
+ * Network policy for each container. Omit to keep the pool's current policy,
431
+ * set to replace it, or pass `null` to remove it (unclaimed warm containers
432
+ * are recycled onto the new policy).
433
+ */
434
+ network?: NetworkConfig | null;
427
435
  /** Sandbox image name, such as `tensorlake/ubuntu-minimal` or a registered Sandbox Image. */
428
436
  image: string;
429
437
  cpus?: number;
@@ -454,6 +462,8 @@ interface SandboxPoolInfo {
454
462
  entrypoint?: string[];
455
463
  maxContainers?: number;
456
464
  warmContainers?: number;
465
+ /** The network policy that applies to each container in the pool. */
466
+ networkPolicy?: NetworkConfig;
457
467
  containers?: PoolContainerInfo[];
458
468
  createdAt?: Date;
459
469
  updatedAt?: Date;
@@ -1152,7 +1162,13 @@ declare class SandboxClient {
1152
1162
  getPool(poolId: string): Promise<SandboxPoolInfo>;
1153
1163
  /** List all sandbox pools in the namespace. */
1154
1164
  listPools(): Promise<Traced<SandboxPoolInfo[]>>;
1155
- /** Replace the configuration of an existing sandbox pool. */
1165
+ /**
1166
+ * Replace a pool configuration. Omit `network` to keep the pool's current
1167
+ * network policy, set it to replace the policy, or pass `null` to remove the
1168
+ * policy entirely. On a change the service recycles the pool's unclaimed
1169
+ * warm containers onto the new policy, while containers already claimed by
1170
+ * sandboxes keep the policy they booted with.
1171
+ */
1156
1172
  updatePool(poolId: string, options: UpdatePoolOptions): Promise<SandboxPoolInfo>;
1157
1173
  /** Delete a sandbox pool. Fails if the pool has active containers. */
1158
1174
  deletePool(poolId: string): Promise<void>;
@@ -1262,6 +1278,7 @@ declare class CloudClient {
1262
1278
  streamBuildLogs(buildServicePath: string, buildId: string, signal?: AbortSignal): AsyncIterable<BuildLogEntry>;
1263
1279
  private runMultipartRequest;
1264
1280
  private namespacePath;
1281
+ private existingApplicationPublicEndpointId;
1265
1282
  private resolveScope;
1266
1283
  }
1267
1284
 
package/dist/index.js CHANGED
@@ -19,7 +19,7 @@ var SDK_VERSION, API_URL, API_KEY, NAMESPACE, SANDBOX_PROXY_URL, DEFAULT_HTTP_TI
19
19
  var init_defaults = __esm({
20
20
  "src/defaults.ts"() {
21
21
  "use strict";
22
- SDK_VERSION = "0.5.89";
22
+ SDK_VERSION = "0.5.91";
23
23
  API_URL = process.env.TENSORLAKE_API_URL ?? "https://api.tensorlake.ai";
24
24
  API_KEY = process.env.TENSORLAKE_API_KEY ?? void 0;
25
25
  NAMESPACE = process.env.INDEXIFY_NAMESPACE ?? "default";
@@ -322,7 +322,8 @@ function parseTimestamp(v) {
322
322
  return new Date(ts * 1e3);
323
323
  }
324
324
  function fromSnakeKeys(obj, idField) {
325
- if (Array.isArray(obj)) return obj.map((item) => fromSnakeKeys(item, idField));
325
+ if (Array.isArray(obj))
326
+ return obj.map((item) => fromSnakeKeys(item, idField));
326
327
  if (obj !== null && typeof obj === "object" && !(obj instanceof Date)) {
327
328
  const result = {};
328
329
  for (const [k, v] of Object.entries(obj)) {
@@ -4014,13 +4015,17 @@ function resolveRequestTimeoutMs(options) {
4014
4015
  }
4015
4016
  function secondsToMillis3(seconds) {
4016
4017
  if (!Number.isFinite(seconds) || seconds <= 0) {
4017
- throw new SandboxError("requestTimeout must be a positive number of seconds");
4018
+ throw new SandboxError(
4019
+ "requestTimeout must be a positive number of seconds"
4020
+ );
4018
4021
  }
4019
4022
  return Math.ceil(seconds * 1e3);
4020
4023
  }
4021
4024
  function validateTimeoutMs(timeoutMs) {
4022
4025
  if (!Number.isFinite(timeoutMs) || timeoutMs <= 0) {
4023
- throw new SandboxError("timeoutMs must be a positive number of milliseconds");
4026
+ throw new SandboxError(
4027
+ "timeoutMs must be a positive number of milliseconds"
4028
+ );
4024
4029
  }
4025
4030
  }
4026
4031
  function sleep2(ms) {
@@ -4223,7 +4228,9 @@ var init_client = __esm({
4223
4228
  }
4224
4229
  /** List all sandboxes in the namespace. */
4225
4230
  async list() {
4226
- const { traceId, json } = await callNative(() => this.native.listSandboxes());
4231
+ const { traceId, json } = await callNative(
4232
+ () => this.native.listSandboxes()
4233
+ );
4227
4234
  const parsed = JSON.parse(json);
4228
4235
  const sandboxes = (parsed.sandboxes ?? []).map(
4229
4236
  (s) => fromSnakeKeys(s, "sandboxId")
@@ -4301,7 +4308,9 @@ var init_client = __esm({
4301
4308
  body.exposed_ports = normalizeUserPorts(options.exposedPorts);
4302
4309
  }
4303
4310
  if (Object.keys(body).length === 0) {
4304
- throw new SandboxError("At least one sandbox update field must be provided.");
4311
+ throw new SandboxError(
4312
+ "At least one sandbox update field must be provided."
4313
+ );
4305
4314
  }
4306
4315
  return this.tracedJson(
4307
4316
  () => this.native.updateSandbox(sandboxId, JSON.stringify(body)),
@@ -4337,7 +4346,9 @@ var init_client = __esm({
4337
4346
  const requestedPorts = normalizeUserPorts(ports);
4338
4347
  const current = await this.getPortAccess(sandboxId);
4339
4348
  const toRemove = new Set(requestedPorts);
4340
- const desiredPorts = current.exposedPorts.filter((port) => !toRemove.has(port));
4349
+ const desiredPorts = current.exposedPorts.filter(
4350
+ (port) => !toRemove.has(port)
4351
+ );
4341
4352
  return this.update(sandboxId, {
4342
4353
  allowUnauthenticatedAccess: desiredPorts.length ? current.allowUnauthenticatedAccess : false,
4343
4354
  exposedPorts: desiredPorts
@@ -4345,7 +4356,10 @@ var init_client = __esm({
4345
4356
  }
4346
4357
  /** Terminate and delete a sandbox. */
4347
4358
  async delete(sandboxId) {
4348
- await callNative(() => this.native.deleteSandbox(sandboxId), { sandboxId, notFoundKind: "sandbox" });
4359
+ await callNative(() => this.native.deleteSandbox(sandboxId), {
4360
+ sandboxId,
4361
+ notFoundKind: "sandbox"
4362
+ });
4349
4363
  }
4350
4364
  /**
4351
4365
  * Suspend a named sandbox, preserving its state for later resume.
@@ -4356,7 +4370,10 @@ var init_client = __esm({
4356
4370
  * (fire-and-return); the server processes the suspend asynchronously.
4357
4371
  */
4358
4372
  async suspend(sandboxId, options) {
4359
- await callNative(() => this.native.suspendSandbox(sandboxId), { sandboxId, notFoundKind: "sandbox" });
4373
+ await callNative(() => this.native.suspendSandbox(sandboxId), {
4374
+ sandboxId,
4375
+ notFoundKind: "sandbox"
4376
+ });
4360
4377
  if (options?.wait === false) return;
4361
4378
  const timeout = options?.timeout ?? 300;
4362
4379
  const pollInterval = options?.pollInterval ?? 1;
@@ -4365,11 +4382,15 @@ var init_client = __esm({
4365
4382
  const info = await this.get(sandboxId);
4366
4383
  if (info.status === "suspended" /* SUSPENDED */) return;
4367
4384
  if (info.status === "terminated" /* TERMINATED */) {
4368
- throw new SandboxError(`Sandbox ${sandboxId} terminated while waiting for suspend`);
4385
+ throw new SandboxError(
4386
+ `Sandbox ${sandboxId} terminated while waiting for suspend`
4387
+ );
4369
4388
  }
4370
4389
  await sleep2(pollInterval * 1e3);
4371
4390
  }
4372
- throw new SandboxError(`Sandbox ${sandboxId} did not suspend within ${timeout}s`);
4391
+ throw new SandboxError(
4392
+ `Sandbox ${sandboxId} did not suspend within ${timeout}s`
4393
+ );
4373
4394
  }
4374
4395
  /**
4375
4396
  * Resume a suspended sandbox and bring it back to `Running`.
@@ -4379,7 +4400,10 @@ var init_client = __esm({
4379
4400
  * (fire-and-return); the server processes the resume asynchronously.
4380
4401
  */
4381
4402
  async resume(sandboxId, options) {
4382
- await callNative(() => this.native.resumeSandbox(sandboxId), { sandboxId, notFoundKind: "sandbox" });
4403
+ await callNative(() => this.native.resumeSandbox(sandboxId), {
4404
+ sandboxId,
4405
+ notFoundKind: "sandbox"
4406
+ });
4383
4407
  if (options?.wait === false) return;
4384
4408
  const timeout = options?.timeout ?? 300;
4385
4409
  const pollInterval = options?.pollInterval ?? 1;
@@ -4388,11 +4412,15 @@ var init_client = __esm({
4388
4412
  const info = await this.get(sandboxId);
4389
4413
  if (info.status === "running" /* RUNNING */) return;
4390
4414
  if (info.status === "terminated" /* TERMINATED */) {
4391
- throw new SandboxError(`Sandbox ${sandboxId} terminated while waiting for resume`);
4415
+ throw new SandboxError(
4416
+ `Sandbox ${sandboxId} terminated while waiting for resume`
4417
+ );
4392
4418
  }
4393
4419
  await sleep2(pollInterval * 1e3);
4394
4420
  }
4395
- throw new SandboxError(`Sandbox ${sandboxId} did not resume within ${timeout}s`);
4421
+ throw new SandboxError(
4422
+ `Sandbox ${sandboxId} did not resume within ${timeout}s`
4423
+ );
4396
4424
  }
4397
4425
  /**
4398
4426
  * Attach a registered file system to a running sandbox at `mountPath`.
@@ -4472,7 +4500,9 @@ var init_client = __esm({
4472
4500
  }
4473
4501
  /** List all snapshots in the namespace. */
4474
4502
  async listSnapshots() {
4475
- const { traceId, json } = await callNative(() => this.native.listSnapshots());
4503
+ const { traceId, json } = await callNative(
4504
+ () => this.native.listSnapshots()
4505
+ );
4476
4506
  const parsed = JSON.parse(json);
4477
4507
  const snapshots = (parsed.snapshots ?? []).map(
4478
4508
  (s) => fromSnakeKeys(s, "snapshotId")
@@ -4500,7 +4530,8 @@ var init_client = __esm({
4500
4530
  const deadline = Date.now() + timeout * 1e3;
4501
4531
  while (Date.now() < deadline) {
4502
4532
  const info = await this.getSnapshot(result.snapshotId);
4503
- if (snapshotStatusSatisfiesWaitCondition(info.status, waitUntil)) return info;
4533
+ if (snapshotStatusSatisfiesWaitCondition(info.status, waitUntil))
4534
+ return info;
4504
4535
  if (info.status === "failed" /* FAILED */) {
4505
4536
  throw new SandboxError(
4506
4537
  `Snapshot ${result.snapshotId} failed: ${info.error}`
@@ -4525,8 +4556,11 @@ var init_client = __esm({
4525
4556
  timeout_secs: options.timeoutSecs ?? 0
4526
4557
  };
4527
4558
  if (options.entrypoint != null) body.entrypoint = options.entrypoint;
4528
- if (options.maxContainers != null) body.max_containers = options.maxContainers;
4529
- if (options.warmContainers != null) body.warm_containers = options.warmContainers;
4559
+ if (options.maxContainers != null)
4560
+ body.max_containers = options.maxContainers;
4561
+ if (options.warmContainers != null)
4562
+ body.warm_containers = options.warmContainers;
4563
+ if (options.network != null) body.network = toSnakeKeys(options.network);
4530
4564
  return this.plainJson(
4531
4565
  () => this.native.createPool(JSON.stringify(body)),
4532
4566
  "poolId"
@@ -4549,7 +4583,13 @@ var init_client = __esm({
4549
4583
  );
4550
4584
  return Object.assign(pools, { traceId });
4551
4585
  }
4552
- /** Replace the configuration of an existing sandbox pool. */
4586
+ /**
4587
+ * Replace a pool configuration. Omit `network` to keep the pool's current
4588
+ * network policy, set it to replace the policy, or pass `null` to remove the
4589
+ * policy entirely. On a change the service recycles the pool's unclaimed
4590
+ * warm containers onto the new policy, while containers already claimed by
4591
+ * sandboxes keep the policy they booted with.
4592
+ */
4553
4593
  async updatePool(poolId, options) {
4554
4594
  const body = {
4555
4595
  image: options.image,
@@ -4561,8 +4601,13 @@ var init_client = __esm({
4561
4601
  timeout_secs: options.timeoutSecs ?? 0
4562
4602
  };
4563
4603
  if (options.entrypoint != null) body.entrypoint = options.entrypoint;
4564
- if (options.maxContainers != null) body.max_containers = options.maxContainers;
4565
- if (options.warmContainers != null) body.warm_containers = options.warmContainers;
4604
+ if (options.maxContainers != null)
4605
+ body.max_containers = options.maxContainers;
4606
+ if (options.warmContainers != null)
4607
+ body.warm_containers = options.warmContainers;
4608
+ if (options.network !== void 0) {
4609
+ body.network = options.network === null ? null : toSnakeKeys(options.network);
4610
+ }
4566
4611
  return this.plainJson(
4567
4612
  () => this.native.updatePool(poolId, JSON.stringify(body)),
4568
4613
  "poolId",
@@ -4571,7 +4616,10 @@ var init_client = __esm({
4571
4616
  }
4572
4617
  /** Delete a sandbox pool. Fails if the pool has active containers. */
4573
4618
  async deletePool(poolId) {
4574
- await callNative(() => this.native.deletePool(poolId), { poolId, notFoundKind: "pool" });
4619
+ await callNative(() => this.native.deletePool(poolId), {
4620
+ poolId,
4621
+ notFoundKind: "pool"
4622
+ });
4575
4623
  }
4576
4624
  // --- Connect ---
4577
4625
  /** Return a `Sandbox` handle for an existing running sandbox without verifying it exists. */
@@ -4608,11 +4656,16 @@ var init_client = __esm({
4608
4656
  });
4609
4657
  const createStart = nowMs();
4610
4658
  const result = options?.poolId != null ? await requestClient.claim(options.poolId) : await requestClient.create(options);
4611
- logSdkTiming("sandbox.create", options?.poolId != null ? "claim_response" : "create_response", createStart, {
4612
- sandbox_id: result.sandboxId,
4613
- status: result.status,
4614
- server_trace_id: result.traceId
4615
- });
4659
+ logSdkTiming(
4660
+ "sandbox.create",
4661
+ options?.poolId != null ? "claim_response" : "create_response",
4662
+ createStart,
4663
+ {
4664
+ sandbox_id: result.sandboxId,
4665
+ status: result.status,
4666
+ server_trace_id: result.traceId
4667
+ }
4668
+ );
4616
4669
  const requestedName = options?.poolId != null ? null : options?.name ?? null;
4617
4670
  const finishConnect = (sandboxId, routingHint, name, ingressEndpoint, sandboxUrl) => {
4618
4671
  const explicitProxyUrl = options?.proxyUrl ?? explicitProxyUrlOverride() ?? void 0;
@@ -5080,6 +5133,22 @@ var init_sse = __esm({
5080
5133
  });
5081
5134
 
5082
5135
  // src/cloud-client.ts
5136
+ import { nanoid } from "nanoid";
5137
+ function applicationAllowsUnauthenticatedRequests(manifest) {
5138
+ return Array.isArray(manifest.allow) && manifest.allow.includes(UNAUTHENTICATED_REQUESTS);
5139
+ }
5140
+ function publicEndpointIdFromManifest(manifest) {
5141
+ for (const key of ["public_endpoint_id", "publicEndpointId"]) {
5142
+ const value = manifest[key];
5143
+ if (typeof value === "string" && value.length > 0) {
5144
+ return value;
5145
+ }
5146
+ }
5147
+ return void 0;
5148
+ }
5149
+ function generatePublicEndpointId() {
5150
+ return `endpoint_${nanoid()}`;
5151
+ }
5083
5152
  function createApplicationBuildForm(request, imageContexts) {
5084
5153
  const contextsByPartName = /* @__PURE__ */ new Map();
5085
5154
  for (const context of imageContexts) {
@@ -5149,7 +5218,7 @@ async function parseJsonResponse(response) {
5149
5218
  }
5150
5219
  return JSON.parse(text);
5151
5220
  }
5152
- var CloudClient;
5221
+ var CloudClient, UNAUTHENTICATED_REQUESTS;
5153
5222
  var init_cloud_client = __esm({
5154
5223
  "src/cloud-client.ts"() {
5155
5224
  "use strict";
@@ -5182,6 +5251,19 @@ var init_cloud_client = __esm({
5182
5251
  this.http.close();
5183
5252
  }
5184
5253
  async upsertApplication(manifest, codeZip, upgradeRunningRequests = false) {
5254
+ const applicationManifest = { ...manifest };
5255
+ let publicEndpointId = publicEndpointIdFromManifest(applicationManifest);
5256
+ if (applicationAllowsUnauthenticatedRequests(applicationManifest) && publicEndpointId === void 0) {
5257
+ const applicationName = applicationManifest.name;
5258
+ if (typeof applicationName === "string" && applicationName.length > 0) {
5259
+ publicEndpointId = await this.existingApplicationPublicEndpointId(applicationName);
5260
+ }
5261
+ publicEndpointId ??= generatePublicEndpointId();
5262
+ }
5263
+ if (publicEndpointId !== void 0) {
5264
+ applicationManifest.public_endpoint_id = publicEndpointId;
5265
+ delete applicationManifest.publicEndpointId;
5266
+ }
5185
5267
  const form = new FormData();
5186
5268
  form.append(
5187
5269
  "code",
@@ -5189,7 +5271,7 @@ var init_cloud_client = __esm({
5189
5271
  "code.zip"
5190
5272
  );
5191
5273
  form.append("code_content_type", "application/zip");
5192
- form.append("application", JSON.stringify(manifest));
5274
+ form.append("application", JSON.stringify(applicationManifest));
5193
5275
  form.append(
5194
5276
  "upgrade_requests_to_latest_code",
5195
5277
  String(upgradeRunningRequests)
@@ -5502,6 +5584,18 @@ var init_cloud_client = __esm({
5502
5584
  namespacePath(subpath) {
5503
5585
  return `/v1/namespaces/${encodeURIComponent(this.namespace)}/${subpath.replace(/^\/+/, "")}`;
5504
5586
  }
5587
+ async existingApplicationPublicEndpointId(applicationName) {
5588
+ const response = await this.http.requestResponse(
5589
+ "GET",
5590
+ this.namespacePath(`applications/${encodeURIComponent(applicationName)}`),
5591
+ { allowedErrorStatusCodes: /* @__PURE__ */ new Set([404]) }
5592
+ );
5593
+ if (response.status === 404) {
5594
+ return void 0;
5595
+ }
5596
+ const application = await parseJsonResponse(response);
5597
+ return publicEndpointIdFromManifest(application);
5598
+ }
5505
5599
  resolveScope(organizationId, projectId) {
5506
5600
  const resolvedOrganizationId = organizationId ?? this.organizationId;
5507
5601
  const resolvedProjectId = projectId ?? this.projectId;
@@ -5516,6 +5610,7 @@ var init_cloud_client = __esm({
5516
5610
  };
5517
5611
  }
5518
5612
  };
5613
+ UNAUTHENTICATED_REQUESTS = "unauthenticated_requests";
5519
5614
  }
5520
5615
  });
5521
5616