@tensorlakeai/tensorlake 0.5.152 → 0.5.153

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.
Files changed (35) hide show
  1. package/dist/applications/index.cjs +3515 -3394
  2. package/dist/applications/index.cjs.map +1 -1
  3. package/dist/applications/index.d.cts +3 -3
  4. package/dist/applications/index.d.ts +3 -3
  5. package/dist/applications/index.js +3470 -3349
  6. package/dist/applications/index.js.map +1 -1
  7. package/dist/function-agent/main.cjs +1 -1
  8. package/dist/function-agent/main.js +1 -1
  9. package/dist/function-executor/main.cjs +2 -2
  10. package/dist/function-executor/main.js +2 -2
  11. package/dist/index.cjs +1270 -782
  12. package/dist/index.cjs.map +1 -1
  13. package/dist/index.d.cts +311 -21
  14. package/dist/index.d.ts +311 -21
  15. package/dist/index.js +1248 -773
  16. package/dist/index.js.map +1 -1
  17. package/dist/{remote-CC48cvYP.d.cts → remote-B3vn4tt1.d.cts} +1 -1
  18. package/dist/{remote-BbSrvgUn.d.ts → remote-DqBUuciu.d.ts} +1 -1
  19. package/dist/{sandbox-image-CAK_K7ND.d.cts → sandbox-image-BMiFlzAs.d.cts} +168 -13
  20. package/dist/{sandbox-image-CAK_K7ND.d.ts → sandbox-image-BMiFlzAs.d.ts} +168 -13
  21. package/dist/sandbox-image.cjs +339 -1300
  22. package/dist/sandbox-image.cjs.map +1 -1
  23. package/dist/sandbox-image.d.cts +1 -1
  24. package/dist/sandbox-image.d.ts +1 -1
  25. package/dist/sandbox-image.js +338 -1299
  26. package/dist/sandbox-image.js.map +1 -1
  27. package/package.json +7 -7
  28. package/runtime/function-executor/manifest.json +5 -5
  29. package/runtime/function-executor/package/dist/function-executor/main.js +2 -2
  30. package/runtime/function-executor/package/npm-shrinkwrap.json +2 -2
  31. package/runtime/function-executor/package/package.json +1 -1
  32. package/runtime/typescript-function-runner/manifest.json +5 -5
  33. package/runtime/typescript-function-runner/package/dist/function-agent/main.js +1 -1
  34. package/runtime/typescript-function-runner/package/npm-shrinkwrap.json +26 -26
  35. package/runtime/typescript-function-runner/package/package.json +7 -7
package/dist/index.cjs CHANGED
@@ -49,7 +49,7 @@ var init_defaults = __esm({
49
49
  "src/defaults.ts"() {
50
50
  "use strict";
51
51
  init_cjs_shims();
52
- SDK_VERSION = "0.5.152";
52
+ SDK_VERSION = "0.5.153";
53
53
  API_URL = process.env.TENSORLAKE_API_URL ?? "https://api.tensorlake.ai";
54
54
  API_KEY = process.env.TENSORLAKE_API_KEY ?? void 0;
55
55
  NAMESPACE = process.env.INDEXIFY_NAMESPACE ?? "default";
@@ -498,7 +498,7 @@ var init_native_worker_client = __esm({
498
498
  }
499
499
  };
500
500
  runtimeKey = /* @__PURE__ */ Symbol.for(
501
- `tensorlake.native.worker.${false ? "source" : "0.5.152"}.v1`
501
+ `tensorlake.native.worker.${false ? "source" : "0.5.153"}.v1`
502
502
  );
503
503
  runtimes = globalThis;
504
504
  }
@@ -598,6 +598,8 @@ var init_models = __esm({
598
598
  SnapshotStatus2["LOCAL_READY"] = "local_ready";
599
599
  SnapshotStatus2["COMPLETED"] = "completed";
600
600
  SnapshotStatus2["FAILED"] = "failed";
601
+ SnapshotStatus2["DELETING"] = "deleting";
602
+ SnapshotStatus2["REPLICATING"] = "replicating";
601
603
  return SnapshotStatus2;
602
604
  })(SnapshotStatus || {});
603
605
  ProcessStatus = /* @__PURE__ */ ((ProcessStatus2) => {
@@ -3886,9 +3888,8 @@ var init_sandbox = __esm({
3886
3888
  *
3887
3889
  * Resource targets use create's cpus, memoryMb, and diskMb names. Resize
3888
3890
  * waits by default; wait=false returns admission. Timeout does not cancel it.
3889
- * CPU-only CAS sandboxes support CPU, memory, and root-disk resize; GPU CAS sandboxes
3890
- * support only root-disk growth and reject CPU and memory changes.
3891
- * Non-CAS sandboxes do not support live resize.
3891
+ * Which runtimes and dimensions support a live resize is decided by the
3892
+ * server, whose policy error is thrown unchanged.
3892
3893
  * Wait, timeout, and pollInterval are ignored on non-resource updates.
3893
3894
  * A no-op returns current resources with absent or earlier resize metadata.
3894
3895
  *
@@ -4306,29 +4307,29 @@ var init_sandbox = __esm({
4306
4307
  }
4307
4308
  // --- File operations ---
4308
4309
  /** Read a file from the sandbox and return its raw bytes. */
4309
- async readFile(path3) {
4310
+ async readFile(path4) {
4310
4311
  const proxy = await this.proxy.client();
4311
- const { traceId, data } = await callNative(() => proxy.readFile(path3), {
4312
+ const { traceId, data } = await callNative(() => proxy.readFile(path4), {
4312
4313
  sandboxId: this.sandboxId
4313
4314
  });
4314
4315
  return Object.assign(Uint8Array.from(data), { traceId });
4315
4316
  }
4316
4317
  /** Write raw bytes to a file in the sandbox, creating it if it does not exist. */
4317
- async writeFile(path3, content) {
4318
+ async writeFile(path4, content) {
4318
4319
  const proxy = await this.proxy.client();
4319
- await callNative(() => proxy.writeFile(path3, Buffer.from(content)), {
4320
+ await callNative(() => proxy.writeFile(path4, Buffer.from(content)), {
4320
4321
  sandboxId: this.sandboxId
4321
4322
  });
4322
4323
  }
4323
4324
  /** Delete a file from the sandbox. */
4324
- async deleteFile(path3) {
4325
+ async deleteFile(path4) {
4325
4326
  const proxy = await this.proxy.client();
4326
- await callNative(() => proxy.deleteFile(path3), { sandboxId: this.sandboxId });
4327
+ await callNative(() => proxy.deleteFile(path4), { sandboxId: this.sandboxId });
4327
4328
  }
4328
4329
  /** List the contents of a directory in the sandbox. */
4329
- async listDirectory(path3) {
4330
+ async listDirectory(path4) {
4330
4331
  const proxy = await this.proxy.client();
4331
- const { traceId, json } = await callNative(() => proxy.listDirectory(path3), {
4332
+ const { traceId, json } = await callNative(() => proxy.listDirectory(path4), {
4332
4333
  sandboxId: this.sandboxId
4333
4334
  });
4334
4335
  return Object.assign(fromSnakeKeys(JSON.parse(json)), {
@@ -4994,9 +4995,9 @@ var init_client = __esm({
4994
4995
  });
4995
4996
  }
4996
4997
  /**
4997
- * Update properties or resize a running sandbox. CPU-only CAS sandboxes support
4998
- * CPU, memory, and root-disk resize; GPU CAS sandboxes support only root-disk
4999
- * growth. Non-CAS sandboxes do not support live resize.
4998
+ * Update properties or resize a running sandbox. Which runtimes and
4999
+ * dimensions support a live resize is decided by the server, whose policy
5000
+ * error is thrown unchanged.
5000
5001
  * Resource names match create. Resize waits by default; wait=false returns
5001
5002
  * admission. Timeout leaves the resize running and reports its generation.
5002
5003
  * Wait, timeout, and pollInterval are ignored on non-resource updates.
@@ -5315,6 +5316,11 @@ var init_client = __esm({
5315
5316
  `Snapshot ${result.snapshotId} failed: ${info.error}`
5316
5317
  );
5317
5318
  }
5319
+ if (info.status === "deleting" /* DELETING */) {
5320
+ throw new SandboxError(
5321
+ `Snapshot ${result.snapshotId} is being deleted`
5322
+ );
5323
+ }
5318
5324
  await sleep2(pollInterval * 1e3);
5319
5325
  }
5320
5326
  throw new SandboxError(
@@ -5572,585 +5578,6 @@ var init_client = __esm({
5572
5578
  }
5573
5579
  });
5574
5580
 
5575
- // src/native-cloud.ts
5576
- async function serializeRequest(method, path3, options) {
5577
- const headers = { ...options?.headers };
5578
- let body = options?.body;
5579
- if (options?.json !== void 0) {
5580
- body = JSON.stringify(options.json);
5581
- if (!Object.keys(headers).some((key) => key.toLowerCase() === "content-type")) {
5582
- headers["Content-Type"] = "application/json";
5583
- }
5584
- }
5585
- const request = {
5586
- method,
5587
- path: path3,
5588
- headersJson: JSON.stringify(headers),
5589
- statusOnlyCodes: [...options?.statusOnlyCodes ?? []]
5590
- };
5591
- if (body instanceof FormData) {
5592
- request.parts = [];
5593
- for (const [name, value] of body.entries()) {
5594
- request.parts.push(typeof value === "string" ? { name, data: Buffer.from(value) } : { name, data: Buffer.from(await value.arrayBuffer()), filename: value.name, contentType: value.type || "application/octet-stream" });
5595
- }
5596
- } else if (body !== void 0) {
5597
- if (body instanceof Blob) request.body = Buffer.from(await body.arrayBuffer());
5598
- else if (typeof body === "string") request.body = Buffer.from(body);
5599
- else if (body instanceof ArrayBuffer) request.body = Buffer.from(new Uint8Array(body));
5600
- else request.body = Buffer.from(body);
5601
- }
5602
- return request;
5603
- }
5604
- var NativeCloudTransport;
5605
- var init_native_cloud = __esm({
5606
- "src/native-cloud.ts"() {
5607
- "use strict";
5608
- init_cjs_shims();
5609
- init_native_sandbox();
5610
- init_native_worker_client();
5611
- NativeCloudTransport = class {
5612
- constructor(options) {
5613
- this.options = options;
5614
- if (!Number.isSafeInteger(options.maxRetries) || options.maxRetries < 0 || options.maxRetries > 4294967295) {
5615
- throw new RangeError("maxRetries must be a non-negative 32-bit integer");
5616
- }
5617
- if (!Number.isFinite(options.retryBackoffMs) || options.retryBackoffMs < 0) {
5618
- throw new RangeError("retryBackoffMs must be a non-negative finite number");
5619
- }
5620
- }
5621
- native;
5622
- closed = false;
5623
- client() {
5624
- if (this.closed) throw new Error("Tensorlake native client is closed");
5625
- if (this.native) return this.native;
5626
- const ctor = loadNativeSandboxBinding().NativeCloudClient;
5627
- if (!ctor) throw new Error("Native binding does not export NativeCloudClient; rebuild with 'npm run build:native'");
5628
- return this.native = new ctor(JSON.stringify(this.options));
5629
- }
5630
- close() {
5631
- this.closed = true;
5632
- releaseNativeHandle(this.native ?? null);
5633
- this.native = void 0;
5634
- }
5635
- async requestResponse(method, path3, options) {
5636
- const request = await serializeRequest(method, path3, options);
5637
- const raw = await callNative(() => this.client().request(request));
5638
- const response = new Response(
5639
- [204, 205, 304].includes(raw.status) ? null : Uint8Array.from(raw.data).buffer,
5640
- { status: raw.status, headers: JSON.parse(raw.headersJson) }
5641
- );
5642
- return Object.assign(response, { traceId: raw.traceId });
5643
- }
5644
- async requestJson(method, path3) {
5645
- const response = await this.requestResponse(method, path3);
5646
- const text = await response.text();
5647
- const value = text ? JSON.parse(text) : null;
5648
- return Object.assign(value ?? {}, { traceId: response.traceId });
5649
- }
5650
- async *stream(method, path3, signal) {
5651
- if (signal?.aborted) return;
5652
- const request = await serializeRequest(method, path3, { headers: { Accept: "text/event-stream" } });
5653
- yield* nativeEventStream((emit) => this.client().stream(request, emit), void 0, signal);
5654
- }
5655
- };
5656
- }
5657
- });
5658
-
5659
- // src/cloud-client.ts
5660
- function secretFromMetadata(metadata) {
5661
- return {
5662
- id: metadata.id,
5663
- name: metadata.name,
5664
- createdAt: new Date(metadata.created_at_ms)
5665
- };
5666
- }
5667
- function applicationAllowsUnauthenticatedRequests(manifest) {
5668
- return Array.isArray(manifest.allow) && manifest.allow.includes(UNAUTHENTICATED_REQUESTS);
5669
- }
5670
- function publicEndpointIdFromManifest(manifest) {
5671
- for (const key of ["public_endpoint_id", "publicEndpointId"]) {
5672
- const value = manifest[key];
5673
- if (typeof value === "string" && value.length > 0) {
5674
- return value;
5675
- }
5676
- }
5677
- return void 0;
5678
- }
5679
- function generatePublicEndpointId() {
5680
- return `endpoint_${(0, import_nanoid.nanoid)()}`;
5681
- }
5682
- function createApplicationBuildForm(request, imageContexts) {
5683
- const contextsByPartName = /* @__PURE__ */ new Map();
5684
- for (const context of imageContexts) {
5685
- if (contextsByPartName.has(context.contextTarPartName)) {
5686
- throw new Error(
5687
- `duplicate image context part name '${context.contextTarPartName}'`
5688
- );
5689
- }
5690
- contextsByPartName.set(context.contextTarPartName, context);
5691
- }
5692
- const form = new FormData();
5693
- form.append(
5694
- "app_version",
5695
- new Blob([JSON.stringify(request)], { type: "application/json" }),
5696
- "app_version"
5697
- );
5698
- for (const image of request.images) {
5699
- const context = contextsByPartName.get(image.contextTarPartName);
5700
- if (!context) {
5701
- throw new Error(
5702
- `missing image context for part '${image.contextTarPartName}'`
5703
- );
5704
- }
5705
- form.append(
5706
- image.contextTarPartName,
5707
- new Blob([toBlobPart(context.contextTarGz)]),
5708
- `${image.contextTarPartName}.tar.gz`
5709
- );
5710
- }
5711
- for (const context of imageContexts) {
5712
- if (!request.images.some((image) => image.contextTarPartName === context.contextTarPartName)) {
5713
- throw new Error(
5714
- `unexpected image context for part '${context.contextTarPartName}'`
5715
- );
5716
- }
5717
- }
5718
- return form;
5719
- }
5720
- function trimTrailingSlashes2(value) {
5721
- return value.endsWith("/") ? value.slice(0, -1) : value;
5722
- }
5723
- function nextRequestPath(next) {
5724
- const schemeIndex = next.indexOf("://");
5725
- if (schemeIndex !== -1) {
5726
- const afterScheme = next.slice(schemeIndex + 3);
5727
- const slashIndex = afterScheme.indexOf("/");
5728
- return slashIndex === -1 ? "/" : afterScheme.slice(slashIndex);
5729
- }
5730
- return next.startsWith("/") ? next : `/${next}`;
5731
- }
5732
- function toBlobPart(data) {
5733
- if (typeof data === "string" || data instanceof Blob) {
5734
- return data;
5735
- }
5736
- if (data instanceof Uint8Array) {
5737
- return Uint8Array.from(data).buffer;
5738
- }
5739
- return data;
5740
- }
5741
- function toRequestBody(data) {
5742
- return toBlobPart(data);
5743
- }
5744
- async function parseJsonResponse(response) {
5745
- const text = await response.text();
5746
- if (!text) {
5747
- return void 0;
5748
- }
5749
- return JSON.parse(text);
5750
- }
5751
- var import_nanoid, CloudClient, UNAUTHENTICATED_REQUESTS;
5752
- var init_cloud_client = __esm({
5753
- "src/cloud-client.ts"() {
5754
- "use strict";
5755
- init_cjs_shims();
5756
- import_nanoid = require("nanoid");
5757
- init_defaults();
5758
- init_native_cloud();
5759
- init_models();
5760
- CloudClient = class _CloudClient {
5761
- transport;
5762
- organizationId;
5763
- projectId;
5764
- namespace;
5765
- constructor(options) {
5766
- this.organizationId = options?.organizationId;
5767
- this.projectId = options?.projectId;
5768
- this.namespace = options?.namespace ?? NAMESPACE;
5769
- this.transport = new NativeCloudTransport({
5770
- baseUrl: options?.apiUrl ?? API_URL,
5771
- apiKey: options?.apiKey ?? API_KEY,
5772
- organizationId: this.organizationId,
5773
- projectId: this.projectId,
5774
- maxRetries: options?.maxRetries ?? MAX_RETRIES,
5775
- retryBackoffMs: options?.retryBackoffMs ?? RETRY_BACKOFF_MS,
5776
- timeoutMs: DEFAULT_HTTP_TIMEOUT_MS,
5777
- userAgent: `tensorlake-typescript-sdk/${SDK_VERSION}`
5778
- });
5779
- }
5780
- static forCloud(options) {
5781
- return new _CloudClient(options);
5782
- }
5783
- close() {
5784
- this.transport.close();
5785
- }
5786
- async upsertApplication(manifest, codeZip, upgradeRunningRequests = false) {
5787
- const applicationManifest = { ...manifest };
5788
- let publicEndpointId = publicEndpointIdFromManifest(applicationManifest);
5789
- if (applicationAllowsUnauthenticatedRequests(applicationManifest) && publicEndpointId === void 0) {
5790
- const applicationName = applicationManifest.name;
5791
- if (typeof applicationName === "string" && applicationName.length > 0) {
5792
- publicEndpointId = await this.existingApplicationPublicEndpointId(applicationName);
5793
- }
5794
- publicEndpointId ??= generatePublicEndpointId();
5795
- }
5796
- if (publicEndpointId !== void 0) {
5797
- applicationManifest.public_endpoint_id = publicEndpointId;
5798
- delete applicationManifest.publicEndpointId;
5799
- }
5800
- const form = new FormData();
5801
- form.append(
5802
- "code",
5803
- new Blob([toBlobPart(codeZip)], { type: "application/zip" }),
5804
- "code.zip"
5805
- );
5806
- form.append("code_content_type", "application/zip");
5807
- form.append("application", JSON.stringify(applicationManifest));
5808
- form.append(
5809
- "upgrade_requests_to_latest_code",
5810
- String(upgradeRunningRequests)
5811
- );
5812
- await this.transport.requestResponse("POST", this.namespacePath("applications"), {
5813
- body: form
5814
- });
5815
- }
5816
- async deleteApplication(applicationName) {
5817
- await this.transport.requestResponse(
5818
- "DELETE",
5819
- this.namespacePath(`applications/${encodeURIComponent(applicationName)}`)
5820
- );
5821
- }
5822
- async deleteSandboxImage(imageName) {
5823
- await this.transport.requestResponse(
5824
- "DELETE",
5825
- this.namespacePath(`sandbox-images/${encodeURIComponent(imageName)}`)
5826
- );
5827
- }
5828
- /**
5829
- * Look up a registered sandbox image (template) by its registered name.
5830
- *
5831
- * Returns the template, or `null` when no image with that name exists.
5832
- * API-key clients may omit organization/project IDs and use the
5833
- * token-scoped Platform API route directly. Explicit scope remains
5834
- * available for PAT callers.
5835
- */
5836
- async findSandboxImageByName(imageName, options) {
5837
- const base = this.platformProjectPath(
5838
- "sandbox-templates",
5839
- options?.organizationId,
5840
- options?.projectId
5841
- );
5842
- const response = await this.transport.requestResponse(
5843
- "GET",
5844
- `${base}/by-name/${encodeURIComponent(imageName)}`,
5845
- { statusOnlyCodes: /* @__PURE__ */ new Set([404]) }
5846
- );
5847
- if (response.status === 404) {
5848
- return null;
5849
- }
5850
- const raw = await parseJsonResponse(response);
5851
- return fromSnakeKeys(raw);
5852
- }
5853
- /**
5854
- * List all registered sandbox images (templates), following pagination to
5855
- * the end. API-key clients may omit organization/project IDs and use the
5856
- * token-scoped Platform API route directly.
5857
- */
5858
- async listSandboxImages(options) {
5859
- const base = this.platformProjectPath(
5860
- "sandbox-templates",
5861
- options?.organizationId,
5862
- options?.projectId
5863
- );
5864
- let path3 = `${base}?pageSize=100`;
5865
- const templates = [];
5866
- while (path3 !== null) {
5867
- const page = await this.transport.requestJson(
5868
- "GET",
5869
- path3
5870
- );
5871
- for (const item of page.items ?? []) {
5872
- templates.push(fromSnakeKeys(item));
5873
- }
5874
- const next = page.pagination?.next;
5875
- path3 = next ? nextRequestPath(next) : null;
5876
- }
5877
- return templates;
5878
- }
5879
- async applications() {
5880
- const raw = await this.transport.requestJson(
5881
- "GET",
5882
- this.namespacePath("applications")
5883
- );
5884
- return (raw.applications ?? []).map(
5885
- (application) => fromSnakeKeys(application)
5886
- );
5887
- }
5888
- async applicationManifest(applicationName) {
5889
- const raw = await this.transport.requestJson(
5890
- "GET",
5891
- this.namespacePath(`applications/${encodeURIComponent(applicationName)}`)
5892
- );
5893
- return fromSnakeKeys(raw);
5894
- }
5895
- async runRequest(applicationName, inputs = []) {
5896
- const path3 = this.namespacePath(
5897
- `applications/${encodeURIComponent(applicationName)}`
5898
- );
5899
- const response = inputs.length === 0 ? await this.transport.requestResponse("POST", path3, {
5900
- body: new Uint8Array(),
5901
- headers: { Accept: "application/json" }
5902
- }) : inputs.length === 1 && inputs[0].name === "0" ? await this.transport.requestResponse("POST", path3, {
5903
- body: toRequestBody(inputs[0].data),
5904
- headers: {
5905
- Accept: "application/json",
5906
- "Content-Type": inputs[0].contentType
5907
- }
5908
- }) : await this.runMultipartRequest(path3, inputs);
5909
- const body = await parseJsonResponse(response);
5910
- const requestId = body?.request_id;
5911
- if (!requestId) {
5912
- throw new Error("missing request_id in run request response body");
5913
- }
5914
- return requestId;
5915
- }
5916
- async waitOnRequestCompletion(applicationName, requestId) {
5917
- const stream = this.transport.stream(
5918
- "GET",
5919
- this.namespacePath(
5920
- `applications/${encodeURIComponent(applicationName)}/requests/${encodeURIComponent(requestId)}/progress`
5921
- )
5922
- );
5923
- for await (const event of stream) {
5924
- if (Object.prototype.hasOwnProperty.call(event, "RequestFinished")) {
5925
- return;
5926
- }
5927
- }
5928
- throw new Error("progress stream ended before request completion");
5929
- }
5930
- async requestMetadata(applicationName, requestId) {
5931
- const raw = await this.transport.requestJson(
5932
- "GET",
5933
- this.namespacePath(
5934
- `applications/${encodeURIComponent(applicationName)}/requests/${encodeURIComponent(requestId)}`
5935
- )
5936
- );
5937
- return fromSnakeKeys(raw);
5938
- }
5939
- async requestOutput(applicationName, requestId) {
5940
- const response = await this.transport.requestResponse(
5941
- "GET",
5942
- this.namespacePath(
5943
- `applications/${encodeURIComponent(applicationName)}/requests/${encodeURIComponent(requestId)}/output`
5944
- )
5945
- );
5946
- const serializedValue = new Uint8Array(await response.arrayBuffer());
5947
- const contentType = response.headers.get("content-type") ?? "";
5948
- return {
5949
- serializedValue,
5950
- contentType
5951
- };
5952
- }
5953
- async listSecrets(options) {
5954
- const base = this.secretCollectionPath(
5955
- options?.organizationId,
5956
- options?.projectId
5957
- );
5958
- const raw = await this.transport.requestJson("GET", base);
5959
- const pageSize = Math.max(0, options?.pageSize ?? 100);
5960
- return Object.assign(
5961
- {
5962
- items: raw.slice(0, pageSize).map(secretFromMetadata),
5963
- pagination: { total: raw.length }
5964
- },
5965
- { traceId: raw.traceId }
5966
- );
5967
- }
5968
- async getSecret(secretId, options) {
5969
- const base = this.secretCollectionPath(
5970
- options?.organizationId,
5971
- options?.projectId
5972
- );
5973
- const raw = await this.transport.requestJson(
5974
- "GET",
5975
- `${base}/${encodeURIComponent(secretId)}`
5976
- );
5977
- return Object.assign(secretFromMetadata(raw), { traceId: raw.traceId });
5978
- }
5979
- async upsertSecrets(secrets, options) {
5980
- const base = this.secretCollectionPath(
5981
- options?.organizationId,
5982
- options?.projectId
5983
- );
5984
- if (Array.isArray(secrets)) {
5985
- const results = [];
5986
- for (const secret of secrets) {
5987
- results.push(await this.upsertSecret(base, secret));
5988
- }
5989
- return results;
5990
- }
5991
- return this.upsertSecret(base, secrets);
5992
- }
5993
- async deleteSecret(secretId, options) {
5994
- const base = this.secretCollectionPath(
5995
- options?.organizationId,
5996
- options?.projectId
5997
- );
5998
- await this.transport.requestResponse(
5999
- "DELETE",
6000
- `${base}/${encodeURIComponent(secretId)}`
6001
- );
6002
- }
6003
- async upsertSecret(base, secret) {
6004
- let response = await this.transport.requestResponse("POST", base, {
6005
- json: secret,
6006
- headers: { "Idempotency-Key": (0, import_nanoid.nanoid)() },
6007
- statusOnlyCodes: /* @__PURE__ */ new Set([409])
6008
- });
6009
- if (response.status === 409) {
6010
- const prefix = base.slice(0, -"/secrets".length);
6011
- const existing = await this.transport.requestJson(
6012
- "GET",
6013
- `${prefix}/secret-names/${encodeURIComponent(secret.name)}`
6014
- );
6015
- response = await this.transport.requestResponse(
6016
- "POST",
6017
- `${base}/${encodeURIComponent(existing.id)}/versions`,
6018
- {
6019
- json: { value: secret.value },
6020
- headers: { "Idempotency-Key": (0, import_nanoid.nanoid)() }
6021
- }
6022
- );
6023
- }
6024
- const metadata = await parseJsonResponse(response);
6025
- return Object.assign(secretFromMetadata(metadata), {
6026
- traceId: response.traceId
6027
- });
6028
- }
6029
- async startImageBuild(buildServicePath, request) {
6030
- const form = new FormData();
6031
- form.append("graph_name", request.applicationName);
6032
- form.append("graph_version", request.applicationVersion);
6033
- form.append("graph_function_name", request.functionName);
6034
- form.append("image_name", request.imageName);
6035
- form.append("image_id", request.imageId);
6036
- form.append(
6037
- "context",
6038
- new Blob([toBlobPart(request.buildContext)]),
6039
- "context.tar.gz"
6040
- );
6041
- const response = await this.transport.requestResponse(
6042
- "PUT",
6043
- `${trimTrailingSlashes2(buildServicePath)}/builds`,
6044
- { body: form }
6045
- );
6046
- const raw = await parseJsonResponse(response);
6047
- return fromSnakeKeys(raw);
6048
- }
6049
- async createApplicationBuild(buildServicePath, request, imageContexts) {
6050
- const form = createApplicationBuildForm(request, imageContexts);
6051
- const response = await this.transport.requestResponse(
6052
- "POST",
6053
- trimTrailingSlashes2(buildServicePath),
6054
- { body: form }
6055
- );
6056
- const raw = await parseJsonResponse(response);
6057
- return fromSnakeKeys(raw);
6058
- }
6059
- async applicationBuildInfo(buildServicePath, applicationBuildId) {
6060
- const raw = await this.transport.requestJson(
6061
- "GET",
6062
- `${trimTrailingSlashes2(buildServicePath)}/${encodeURIComponent(applicationBuildId)}`
6063
- );
6064
- return fromSnakeKeys(raw);
6065
- }
6066
- async cancelApplicationBuild(buildServicePath, applicationBuildId) {
6067
- const raw = await this.transport.requestJson(
6068
- "POST",
6069
- `${trimTrailingSlashes2(buildServicePath)}/${encodeURIComponent(applicationBuildId)}/cancel`
6070
- );
6071
- return fromSnakeKeys(raw);
6072
- }
6073
- async buildInfo(buildServicePath, buildId) {
6074
- const raw = await this.transport.requestJson(
6075
- "GET",
6076
- `${trimTrailingSlashes2(buildServicePath)}/builds/${encodeURIComponent(buildId)}`
6077
- );
6078
- return fromSnakeKeys(raw);
6079
- }
6080
- async cancelBuild(buildServicePath, buildId) {
6081
- await this.transport.requestResponse(
6082
- "POST",
6083
- `${trimTrailingSlashes2(buildServicePath)}/builds/${encodeURIComponent(buildId)}/cancel`
6084
- );
6085
- }
6086
- async *streamBuildLogs(buildServicePath, buildId, signal) {
6087
- const stream = this.transport.stream(
6088
- "GET",
6089
- `${trimTrailingSlashes2(buildServicePath)}/builds/${encodeURIComponent(buildId)}/logs`,
6090
- signal
6091
- );
6092
- for await (const event of stream) {
6093
- yield fromSnakeKeys(event);
6094
- }
6095
- }
6096
- async runMultipartRequest(path3, inputs) {
6097
- const form = new FormData();
6098
- for (const input of inputs) {
6099
- form.append(
6100
- input.name,
6101
- new Blob([toBlobPart(input.data)], { type: input.contentType }),
6102
- input.name
6103
- );
6104
- }
6105
- return this.transport.requestResponse("POST", path3, {
6106
- body: form,
6107
- headers: { Accept: "application/json" }
6108
- });
6109
- }
6110
- namespacePath(subpath) {
6111
- return `/v1/namespaces/${encodeURIComponent(this.namespace)}/${subpath.replace(/^\/+/, "")}`;
6112
- }
6113
- async existingApplicationPublicEndpointId(applicationName) {
6114
- const response = await this.transport.requestResponse(
6115
- "GET",
6116
- this.namespacePath(`applications/${encodeURIComponent(applicationName)}`),
6117
- { statusOnlyCodes: /* @__PURE__ */ new Set([404]) }
6118
- );
6119
- if (response.status === 404) {
6120
- return void 0;
6121
- }
6122
- const application = await parseJsonResponse(response);
6123
- return publicEndpointIdFromManifest(application);
6124
- }
6125
- platformProjectPath(resource, organizationId, projectId) {
6126
- const resolvedOrganizationId = organizationId ?? this.organizationId;
6127
- const resolvedProjectId = projectId ?? this.projectId;
6128
- if (!resolvedOrganizationId && !resolvedProjectId) {
6129
- return `/platform/v1/${resource}`;
6130
- }
6131
- if (!resolvedOrganizationId || !resolvedProjectId) {
6132
- throw new Error(
6133
- "organizationId and projectId must be provided together"
6134
- );
6135
- }
6136
- return `/platform/v1/organizations/${encodeURIComponent(resolvedOrganizationId)}/projects/${encodeURIComponent(resolvedProjectId)}/${resource}`;
6137
- }
6138
- secretCollectionPath(organizationId, projectId) {
6139
- const resolvedOrganizationId = organizationId ?? this.organizationId;
6140
- const resolvedProjectId = projectId ?? this.projectId;
6141
- if (!resolvedOrganizationId && !resolvedProjectId) {
6142
- return this.namespacePath("secrets");
6143
- }
6144
- if (!resolvedOrganizationId || !resolvedProjectId) {
6145
- throw new Error("organizationId and projectId must be provided together");
6146
- }
6147
- return this.namespacePath("secrets");
6148
- }
6149
- };
6150
- UNAUTHENTICATED_REQUESTS = "unauthenticated_requests";
6151
- }
6152
- });
6153
-
6154
5581
  // src/image.ts
6155
5582
  function cloneOperation(op) {
6156
5583
  return {
@@ -6343,9 +5770,9 @@ var require_libc = __commonJS({
6343
5770
  // src/native-binding.ts
6344
5771
  function packageRoot() {
6345
5772
  const parent = (0, import_node_url.fileURLToPath)(new URL("../", importMetaUrl));
6346
- if (fs.existsSync(import_node_path2.default.join(parent, "package.json"))) return parent;
5773
+ if (fs.existsSync(import_node_path.default.join(parent, "package.json"))) return parent;
6347
5774
  const grandparent = (0, import_node_url.fileURLToPath)(new URL("../../", importMetaUrl));
6348
- if (fs.existsSync(import_node_path2.default.join(grandparent, "package.json"))) return grandparent;
5775
+ if (fs.existsSync(import_node_path.default.join(grandparent, "package.json"))) return grandparent;
6349
5776
  return parent;
6350
5777
  }
6351
5778
  function linuxLibcFamily(options) {
@@ -6368,7 +5795,7 @@ function nativeTargetId(platform = process.platform, arch = process.arch, option
6368
5795
  function nativeBindingPath(options = {}) {
6369
5796
  const platform = options.platform ?? process.platform;
6370
5797
  const arch = options.arch ?? process.arch;
6371
- return import_node_path2.default.join(
5798
+ return import_node_path.default.join(
6372
5799
  options.packageRoot ?? packageRoot(),
6373
5800
  "dist",
6374
5801
  "native",
@@ -6401,7 +5828,7 @@ function loadNative() {
6401
5828
  }
6402
5829
  return require2(packageEntry);
6403
5830
  }
6404
- var import_libc, fs, import_node_module2, import_node_path2, import_node_url, NATIVE_PACKAGES, cachedLinuxLibc;
5831
+ var import_libc, fs, import_node_module2, import_node_path, import_node_url, NATIVE_PACKAGES, cachedLinuxLibc;
6405
5832
  var init_native_binding = __esm({
6406
5833
  "src/native-binding.ts"() {
6407
5834
  "use strict";
@@ -6409,7 +5836,7 @@ var init_native_binding = __esm({
6409
5836
  import_libc = __toESM(require_libc(), 1);
6410
5837
  fs = __toESM(require("fs"), 1);
6411
5838
  import_node_module2 = require("module");
6412
- import_node_path2 = __toESM(require("path"), 1);
5839
+ import_node_path = __toESM(require("path"), 1);
6413
5840
  import_node_url = require("url");
6414
5841
  NATIVE_PACKAGES = {
6415
5842
  "darwin-arm64": "@tensorlakeai/native-darwin-arm64",
@@ -6422,16 +5849,471 @@ var init_native_binding = __esm({
6422
5849
  }
6423
5850
  });
6424
5851
 
5852
+ // src/image-builds.ts
5853
+ function camelize(key) {
5854
+ return key.replace(/_([a-z])/g, (_, c) => c.toUpperCase());
5855
+ }
5856
+ function toImageBuildError(error) {
5857
+ if (!(error instanceof Error)) return error;
5858
+ let payload;
5859
+ try {
5860
+ payload = JSON.parse(error.message);
5861
+ } catch {
5862
+ return error;
5863
+ }
5864
+ if (!payload || payload.category !== "image_build") return error;
5865
+ const details = {};
5866
+ for (const [key, value] of Object.entries(payload)) {
5867
+ if (key === "category") continue;
5868
+ details[camelize(key)] = value;
5869
+ }
5870
+ const typed = details;
5871
+ switch (typed.code) {
5872
+ case "not_found":
5873
+ return new ImageBuildNotFoundError(typed);
5874
+ case "image_build_in_progress":
5875
+ return new ImageBuildInProgressError(typed);
5876
+ case "failed":
5877
+ return new ImageBuildFailedError(typed);
5878
+ case "cancelled":
5879
+ return new ImageBuildCancelledError(typed);
5880
+ case "timeout":
5881
+ return new ImageBuildTimeoutError(typed);
5882
+ case "interrupted":
5883
+ return new ImageBuildInterruptedError(typed);
5884
+ default:
5885
+ return new ImageBuildError(typed);
5886
+ }
5887
+ }
5888
+ function camelizeRecord(value) {
5889
+ const out = {};
5890
+ for (const [key, inner] of Object.entries(value)) out[camelize(key)] = inner;
5891
+ return out;
5892
+ }
5893
+ function parseBuildInfo(raw) {
5894
+ const camel = camelizeRecord(raw);
5895
+ const result = raw.result && typeof raw.result === "object" ? camelizeRecord(raw.result) : null;
5896
+ return {
5897
+ buildId: String(raw.build_id ?? ""),
5898
+ clientRequestId: camel.clientRequestId ?? null,
5899
+ kind: String(raw.kind ?? ""),
5900
+ name: raw.name ?? null,
5901
+ status: String(raw.status ?? ""),
5902
+ phase: raw.phase ?? null,
5903
+ attemptNo: Number(raw.attempt_no ?? 0),
5904
+ builderSandboxId: camel.builderSandboxId ?? null,
5905
+ error: raw.error ?? null,
5906
+ result,
5907
+ operationDeadlineMs: camel.operationDeadlineMs ?? null,
5908
+ createdAtMs: camel.createdAtMs ?? null,
5909
+ updatedAtMs: camel.updatedAtMs ?? null,
5910
+ raw
5911
+ };
5912
+ }
5913
+ function parseResult(json) {
5914
+ return camelizeRecord(JSON.parse(json));
5915
+ }
5916
+ function credentialsFromEnv() {
5917
+ const context = __imageBuildInternals.buildContextFromEnv();
5918
+ if (!context.apiKey) {
5919
+ if (context.personalAccessToken) {
5920
+ throw new ImageBuildError({
5921
+ code: "auth",
5922
+ message: "Sandbox image SDKs require TENSORLAKE_API_KEY. Personal access tokens are CLI-only."
5923
+ });
5924
+ }
5925
+ throw new ImageBuildError({ code: "auth", message: "Missing TENSORLAKE_API_KEY credentials." });
5926
+ }
5927
+ return { apiUrl: context.apiUrl, bearerToken: context.apiKey, namespace: context.namespace };
5928
+ }
5929
+ function clientOptions(credentials) {
5930
+ return {
5931
+ apiUrl: credentials.apiUrl,
5932
+ bearerToken: credentials.bearerToken,
5933
+ namespace: credentials.namespace,
5934
+ useScopeHeaders: false
5935
+ };
5936
+ }
5937
+ function rejectLegacyReference(buildId) {
5938
+ if (typeof buildId !== "string" || buildId.trim().length === 0) {
5939
+ throw new ImageBuildError({ code: "usage", message: "buildId must be a non-empty string" });
5940
+ }
5941
+ if (buildId.startsWith("sandbox_template_")) {
5942
+ throw new ImageBuildError({
5943
+ code: "usage",
5944
+ message: `'${buildId}' is a legacy sandbox template id; legacy images have no build operation to get, wait for or cancel`,
5945
+ buildId
5946
+ });
5947
+ }
5948
+ if (buildId.startsWith("image_")) {
5949
+ throw new ImageBuildError({
5950
+ code: "usage",
5951
+ message: `'${buildId}' is an image id, not a build id; look the image up with findSandboxImageByName or use the build id admission returned`,
5952
+ buildId
5953
+ });
5954
+ }
5955
+ }
5956
+ async function __runWithInterrupt(signal, run) {
5957
+ const binding = __imageBuildInternals.loadNativeBinding();
5958
+ if (signal === void 0) {
5959
+ try {
5960
+ return await run(void 0);
5961
+ } catch (error) {
5962
+ throw toImageBuildError(error);
5963
+ }
5964
+ }
5965
+ const interruptId = binding.createImageBuildInterrupt();
5966
+ const onAbort = () => binding.triggerImageBuildInterrupt(interruptId);
5967
+ if (signal.aborted) onAbort();
5968
+ else signal.addEventListener("abort", onAbort, { once: true });
5969
+ try {
5970
+ return await run(interruptId);
5971
+ } catch (error) {
5972
+ throw toImageBuildError(error);
5973
+ } finally {
5974
+ signal.removeEventListener("abort", onAbort);
5975
+ binding.releaseImageBuildInterrupt(interruptId);
5976
+ }
5977
+ }
5978
+ function makeEmitter(options) {
5979
+ const emit = options.emit ?? (options.verbose ? __imageBuildInternals.stderrEmit : __imageBuildInternals.noopEmit);
5980
+ let emitError;
5981
+ const forward = (event) => {
5982
+ try {
5983
+ emit(__imageBuildInternals.eventToEmitDict(event));
5984
+ } catch (error) {
5985
+ emitError ??= error;
5986
+ }
5987
+ };
5988
+ return {
5989
+ forward,
5990
+ emit,
5991
+ rethrow() {
5992
+ if (emitError != null) throw emitError;
5993
+ }
5994
+ };
5995
+ }
5996
+ function decodeStarted(json, credentials) {
5997
+ const payload = JSON.parse(json);
5998
+ return new ImageBuildHandle(parseBuildInfo(payload.build ?? {}), credentials, payload.client_request_id);
5999
+ }
6000
+ async function startImageBuild(source, options = {}, deps = {}) {
6001
+ const emitter = makeEmitter({ emit: deps.emit ?? options.emit, verbose: options.verbose });
6002
+ let dockerfilePath;
6003
+ let dockerfileText;
6004
+ let contextDir;
6005
+ let name;
6006
+ let tempContextDir;
6007
+ if (source instanceof Image) {
6008
+ if (!source.baseImage) throw new Error("Image must have a baseImage to build");
6009
+ if (options.contextDir != null) {
6010
+ contextDir = import_node_path2.default.resolve(options.contextDir);
6011
+ } else if (__imageBuildInternals.imageRequiresContext(source)) {
6012
+ throw new Error(
6013
+ "This image reads files from the host (via COPY/ADD or a RUN bind mount), so it needs a build context. Pass `contextDir` pointing at the directory that contains those sources; they resolve relative to it, like `docker build <contextDir>`."
6014
+ );
6015
+ } else {
6016
+ tempContextDir = (0, import_node_fs.mkdtempSync)(import_node_path2.default.join(import_node_os.default.tmpdir(), "tl-build-context-"));
6017
+ contextDir = tempContextDir;
6018
+ }
6019
+ dockerfilePath = import_node_path2.default.join(contextDir, "Dockerfile");
6020
+ let text = dockerfileContent(source);
6021
+ if (!text.endsWith("\n")) text += "\n";
6022
+ dockerfileText = text;
6023
+ name = options.registeredName ?? source.name;
6024
+ } else if (typeof source === "string") {
6025
+ const resolved = import_node_path2.default.resolve(source);
6026
+ if (!(0, import_node_fs.existsSync)(resolved)) throw new Error(`Dockerfile not found: ${source}`);
6027
+ dockerfilePath = resolved;
6028
+ name = options.registeredName ?? __imageBuildInternals.defaultRegisteredName(resolved);
6029
+ } else {
6030
+ throw new TypeError(`source must be an Image or a Dockerfile path, got ${typeof source}`);
6031
+ }
6032
+ try {
6033
+ const credentials = credentialsFromEnv();
6034
+ const binding = __imageBuildInternals.loadNativeBinding();
6035
+ emitter.emit({ type: "status", message: `Building image '${name}'...` });
6036
+ const json = await __runWithInterrupt(
6037
+ options.signal,
6038
+ (interruptId) => binding.startImageBuild(
6039
+ {
6040
+ apiUrl: credentials.apiUrl,
6041
+ bearerToken: credentials.bearerToken,
6042
+ dockerfilePath,
6043
+ registeredName: name,
6044
+ diskMb: options.diskMb,
6045
+ cpus: options.cpus,
6046
+ memoryMb: options.memoryMb,
6047
+ isPublic: options.isPublic ?? false,
6048
+ namespace: credentials.namespace,
6049
+ useScopeHeaders: false,
6050
+ dockerConfigJson: options.dockerConfigJson,
6051
+ dockerfileText,
6052
+ contextDir,
6053
+ cas: true,
6054
+ buildArgs: options.buildArgs
6055
+ },
6056
+ emitter.forward,
6057
+ interruptId
6058
+ )
6059
+ );
6060
+ emitter.rethrow();
6061
+ return decodeStarted(json, credentials);
6062
+ } finally {
6063
+ if (tempContextDir != null) (0, import_node_fs.rmSync)(tempContextDir, { recursive: true, force: true });
6064
+ }
6065
+ }
6066
+ async function startImageImport(imageReference, options = {}, deps = {}) {
6067
+ if (typeof imageReference !== "string" || imageReference.trim().length === 0) {
6068
+ throw new Error("image reference to import must not be empty");
6069
+ }
6070
+ const reference = imageReference.trim();
6071
+ const name = options.registeredName ?? __imageBuildInternals.defaultRegisteredNameFromImage(reference);
6072
+ const emitter = makeEmitter({ emit: deps.emit ?? options.emit, verbose: options.verbose });
6073
+ const credentials = credentialsFromEnv();
6074
+ const binding = __imageBuildInternals.loadNativeBinding();
6075
+ emitter.emit({ type: "status", message: `Importing image '${reference}' as '${name}'...` });
6076
+ const json = await __runWithInterrupt(
6077
+ options.signal,
6078
+ (interruptId) => binding.startImageImport(
6079
+ {
6080
+ apiUrl: credentials.apiUrl,
6081
+ bearerToken: credentials.bearerToken,
6082
+ imageReference: reference,
6083
+ registeredName: name,
6084
+ diskMb: options.diskMb,
6085
+ cpus: options.cpus,
6086
+ memoryMb: options.memoryMb,
6087
+ isPublic: options.isPublic ?? false,
6088
+ namespace: credentials.namespace,
6089
+ useScopeHeaders: false,
6090
+ dockerConfigJson: options.dockerConfigJson,
6091
+ cas: true
6092
+ },
6093
+ emitter.forward,
6094
+ interruptId
6095
+ )
6096
+ );
6097
+ emitter.rethrow();
6098
+ return decodeStarted(json, credentials);
6099
+ }
6100
+ async function getImageBuild(buildId) {
6101
+ rejectLegacyReference(buildId);
6102
+ const credentials = credentialsFromEnv();
6103
+ const binding = __imageBuildInternals.loadNativeBinding();
6104
+ let json;
6105
+ try {
6106
+ json = await binding.getImageBuild(clientOptions(credentials), buildId);
6107
+ } catch (error) {
6108
+ throw toImageBuildError(error);
6109
+ }
6110
+ return new ImageBuildHandle(parseBuildInfo(JSON.parse(json)), credentials);
6111
+ }
6112
+ async function waitImageBuild(buildId, options = {}) {
6113
+ rejectLegacyReference(buildId);
6114
+ const credentials = credentialsFromEnv();
6115
+ const binding = __imageBuildInternals.loadNativeBinding();
6116
+ const emitter = makeEmitter(options);
6117
+ const json = await __runWithInterrupt(
6118
+ options.signal,
6119
+ (interruptId) => binding.waitImageBuild(
6120
+ clientOptions(credentials),
6121
+ buildId,
6122
+ { timeoutMs: options.timeoutMs, followLogs: options.followLogs ?? false },
6123
+ emitter.forward,
6124
+ interruptId
6125
+ )
6126
+ );
6127
+ emitter.rethrow();
6128
+ return parseResult(json);
6129
+ }
6130
+ async function cancelImageBuildWith(credentials, selector) {
6131
+ const binding = __imageBuildInternals.loadNativeBinding();
6132
+ let json;
6133
+ try {
6134
+ json = await binding.cancelImageBuild(clientOptions(credentials), {
6135
+ buildId: selector.buildId,
6136
+ clientRequestId: selector.clientRequestId
6137
+ });
6138
+ } catch (error) {
6139
+ throw toImageBuildError(error);
6140
+ }
6141
+ const payload = JSON.parse(json);
6142
+ const outcome = String(payload.outcome ?? "");
6143
+ return {
6144
+ outcome,
6145
+ build: payload.build ? parseBuildInfo(payload.build) : null,
6146
+ confirmed: ["cancelled", "already_cancelled", "already_failed"].includes(outcome)
6147
+ };
6148
+ }
6149
+ async function cancelImageBuild(selector) {
6150
+ const hasBuild = selector.buildId != null;
6151
+ const hasRequest = selector.clientRequestId != null;
6152
+ if (hasBuild === hasRequest) {
6153
+ throw new ImageBuildError({
6154
+ code: "usage",
6155
+ message: "pass exactly one of buildId or clientRequestId"
6156
+ });
6157
+ }
6158
+ if (selector.buildId != null) rejectLegacyReference(selector.buildId);
6159
+ return cancelImageBuildWith(credentialsFromEnv(), selector);
6160
+ }
6161
+ var import_node_path2, import_node_os, import_node_fs, ImageBuildError, ImageBuildNotFoundError, ImageBuildInProgressError, ImageBuildFailedError, ImageBuildCancelledError, ImageBuildTimeoutError, ImageBuildInterruptedError, ImageBuildHandle;
6162
+ var init_image_builds = __esm({
6163
+ "src/image-builds.ts"() {
6164
+ "use strict";
6165
+ init_cjs_shims();
6166
+ import_node_path2 = __toESM(require("path"), 1);
6167
+ import_node_os = __toESM(require("os"), 1);
6168
+ import_node_fs = require("fs");
6169
+ init_image();
6170
+ init_sandbox_image();
6171
+ ImageBuildError = class extends Error {
6172
+ code;
6173
+ buildId;
6174
+ clientRequestId;
6175
+ details;
6176
+ constructor(details) {
6177
+ super(details.message);
6178
+ this.name = "ImageBuildError";
6179
+ this.code = details.code;
6180
+ this.details = details;
6181
+ if (details.buildId) this.buildId = details.buildId;
6182
+ if (details.clientRequestId) this.clientRequestId = details.clientRequestId;
6183
+ }
6184
+ };
6185
+ ImageBuildNotFoundError = class extends ImageBuildError {
6186
+ constructor(details) {
6187
+ super(details);
6188
+ this.name = "ImageBuildNotFoundError";
6189
+ }
6190
+ };
6191
+ ImageBuildInProgressError = class extends ImageBuildError {
6192
+ imageName;
6193
+ activeBuildId;
6194
+ activeKind;
6195
+ activeStatus;
6196
+ constructor(details) {
6197
+ super(details);
6198
+ this.name = "ImageBuildInProgressError";
6199
+ if (details.imageName) this.imageName = details.imageName;
6200
+ if (details.activeBuildId) this.activeBuildId = details.activeBuildId;
6201
+ if (details.activeKind) this.activeKind = details.activeKind;
6202
+ if (details.activeStatus) this.activeStatus = details.activeStatus;
6203
+ }
6204
+ };
6205
+ ImageBuildFailedError = class extends ImageBuildError {
6206
+ error;
6207
+ info;
6208
+ constructor(details) {
6209
+ super(details);
6210
+ this.name = "ImageBuildFailedError";
6211
+ this.error = details.error ?? "no error recorded";
6212
+ if (details.info) this.info = parseBuildInfo(details.info);
6213
+ }
6214
+ };
6215
+ ImageBuildCancelledError = class extends ImageBuildError {
6216
+ info;
6217
+ constructor(details) {
6218
+ super(details);
6219
+ this.name = "ImageBuildCancelledError";
6220
+ if (details.info) this.info = parseBuildInfo(details.info);
6221
+ }
6222
+ };
6223
+ ImageBuildTimeoutError = class extends ImageBuildError {
6224
+ constructor(details) {
6225
+ super(details);
6226
+ this.name = "ImageBuildTimeoutError";
6227
+ }
6228
+ };
6229
+ ImageBuildInterruptedError = class extends ImageBuildError {
6230
+ outcome;
6231
+ confirmed;
6232
+ result;
6233
+ constructor(details) {
6234
+ super(details);
6235
+ this.name = "ImageBuildInterruptedError";
6236
+ this.outcome = details.outcome ?? "unconfirmed";
6237
+ this.confirmed = details.confirmed === true;
6238
+ if (details.result) this.result = details.result;
6239
+ }
6240
+ };
6241
+ ImageBuildHandle = class {
6242
+ buildId;
6243
+ /**
6244
+ * The admission's request id, when this handle started the build. Never
6245
+ * needed to cancel; a recovery aid for a lost admission answer.
6246
+ */
6247
+ clientRequestId;
6248
+ #info;
6249
+ #credentials;
6250
+ /** @internal */
6251
+ constructor(info, credentials, clientRequestId) {
6252
+ this.buildId = info.buildId;
6253
+ this.clientRequestId = clientRequestId ?? info.clientRequestId ?? null;
6254
+ this.#info = info;
6255
+ this.#credentials = credentials;
6256
+ }
6257
+ /** The last observed state. */
6258
+ get info() {
6259
+ return this.#info;
6260
+ }
6261
+ /** Re-read the current state. */
6262
+ async refresh() {
6263
+ const binding = __imageBuildInternals.loadNativeBinding();
6264
+ let json;
6265
+ try {
6266
+ json = await binding.getImageBuild(clientOptions(this.#credentials), this.buildId);
6267
+ } catch (error) {
6268
+ throw toImageBuildError(error);
6269
+ }
6270
+ this.#info = parseBuildInfo(JSON.parse(json));
6271
+ return this.#info;
6272
+ }
6273
+ /**
6274
+ * Wait for publication and return this build's immutable result. See
6275
+ * {@link ImageBuildWaitOptions} for the timeout/abort distinction.
6276
+ */
6277
+ async wait(options = {}) {
6278
+ const binding = __imageBuildInternals.loadNativeBinding();
6279
+ const emitter = makeEmitter(options);
6280
+ const json = await __runWithInterrupt(
6281
+ options.signal,
6282
+ (interruptId) => binding.waitImageBuild(
6283
+ clientOptions(this.#credentials),
6284
+ this.buildId,
6285
+ { timeoutMs: options.timeoutMs, followLogs: options.followLogs ?? false },
6286
+ emitter.forward,
6287
+ interruptId
6288
+ )
6289
+ );
6290
+ emitter.rethrow();
6291
+ const result = parseResult(json);
6292
+ this.#info = { ...this.#info, status: "succeeded", result };
6293
+ return result;
6294
+ }
6295
+ /** Cancel this build by its id (the sufficient selector). */
6296
+ async cancel() {
6297
+ return cancelImageBuildWith(this.#credentials, { buildId: this.buildId });
6298
+ }
6299
+ };
6300
+ }
6301
+ });
6302
+
6425
6303
  // src/sandbox-image.ts
6426
6304
  var sandbox_image_exports = {};
6427
6305
  __export(sandbox_image_exports, {
6306
+ __imageBuildInternals: () => __imageBuildInternals,
6428
6307
  __setNativeBindingForTest: () => __setNativeBindingForTest,
6429
6308
  buildContextFromEnv: () => buildContextFromEnv,
6430
6309
  createSandboxImage: () => createSandboxImage,
6431
6310
  deleteSandboxImage: () => deleteSandboxImage,
6311
+ deleteSandboxImageWithCredentials: () => deleteSandboxImageWithCredentials,
6432
6312
  findSandboxImageByName: () => findSandboxImageByName,
6313
+ findSandboxImageByNameWithCredentials: () => findSandboxImageByNameWithCredentials,
6433
6314
  importSandboxImage: () => importSandboxImage,
6434
6315
  listSandboxImages: () => listSandboxImages,
6316
+ listSandboxImagesWithCredentials: () => listSandboxImagesWithCredentials,
6435
6317
  runCreateSandboxImageCli: () => runCreateSandboxImageCli,
6436
6318
  runImportSandboxImageCli: () => runImportSandboxImageCli
6437
6319
  });
@@ -6505,6 +6387,15 @@ function eventToEmitDict(event) {
6505
6387
  message: event.message
6506
6388
  };
6507
6389
  if (event.stream != null) out.stream = event.stream;
6390
+ if (event.buildId != null) out.build_id = event.buildId;
6391
+ if (event.clientRequestId !== void 0 && event.eventType !== "status") {
6392
+ out.client_request_id = event.clientRequestId;
6393
+ }
6394
+ if (event.status != null) out.status = event.status;
6395
+ if (event.phase !== void 0 && event.eventType.startsWith("build_")) out.phase = event.phase;
6396
+ if (event.attempt != null) out.attempt = event.attempt;
6397
+ if (event.outcome != null) out.outcome = event.outcome;
6398
+ if (event.confirmed != null) out.confirmed = event.confirmed;
6508
6399
  return out;
6509
6400
  }
6510
6401
  function runOpMountsContext(op) {
@@ -6606,38 +6497,47 @@ async function createSandboxImage(source, options = {}, deps = {}) {
6606
6497
  deps._allowPat ? "Missing TENSORLAKE_API_KEY or TENSORLAKE_PAT credentials." : "Missing TENSORLAKE_API_KEY credentials."
6607
6498
  );
6608
6499
  }
6500
+ if (options.signal !== void 0 && !options.cas) {
6501
+ throw new Error(
6502
+ "signal is only supported for CAS image builds (cas: true); a legacy build has no Image Service build operation to cancel"
6503
+ );
6504
+ }
6609
6505
  emit({ type: "status", message: `Building image '${effectiveName}'...` });
6610
6506
  const binding = loadNativeBinding();
6611
6507
  let emitError;
6612
- const resultJson = await binding.buildSandboxImage(
6613
- {
6614
- apiUrl: context.apiUrl,
6615
- bearerToken,
6616
- dockerfilePath,
6617
- registeredName: effectiveName,
6618
- diskMb: options.diskMb,
6619
- builderDiskMb: options.builderDiskMb,
6620
- cpus: options.cpus,
6621
- memoryMb: options.memoryMb,
6622
- isPublic: options.isPublic ?? false,
6623
- organizationId: usePat ? context.organizationId : void 0,
6624
- projectId: usePat ? context.projectId : void 0,
6625
- namespace: context.namespace,
6626
- useScopeHeaders: usePat,
6627
- userAgent: void 0,
6628
- dockerCompat: options.dockerCompat ?? false,
6629
- dockerConfigJson: options.dockerConfigJson,
6630
- dockerfileText,
6631
- contextDir: nativeContextDir
6632
- },
6633
- (event) => {
6634
- try {
6635
- emit(eventToEmitDict(event));
6636
- } catch (error) {
6637
- emitError ??= error;
6638
- }
6508
+ const nativeOptions = {
6509
+ apiUrl: context.apiUrl,
6510
+ bearerToken,
6511
+ dockerfilePath,
6512
+ registeredName: effectiveName,
6513
+ diskMb: options.diskMb,
6514
+ builderDiskMb: options.builderDiskMb,
6515
+ cpus: options.cpus,
6516
+ memoryMb: options.memoryMb,
6517
+ isPublic: options.isPublic ?? false,
6518
+ organizationId: usePat ? context.organizationId : void 0,
6519
+ projectId: usePat ? context.projectId : void 0,
6520
+ namespace: context.namespace,
6521
+ useScopeHeaders: usePat,
6522
+ userAgent: void 0,
6523
+ dockerCompat: options.dockerCompat ?? false,
6524
+ dockerConfigJson: options.dockerConfigJson,
6525
+ dockerfileText,
6526
+ contextDir: nativeContextDir,
6527
+ cas: options.cas ?? false,
6528
+ buildArgs: options.buildArgs
6529
+ };
6530
+ const forward = (event) => {
6531
+ try {
6532
+ emit(eventToEmitDict(event));
6533
+ } catch (error) {
6534
+ emitError ??= error;
6639
6535
  }
6640
- );
6536
+ };
6537
+ const resultJson = options.cas ? await __runWithInterrupt(
6538
+ options.signal,
6539
+ (interruptId) => binding.buildSandboxImage(nativeOptions, forward, interruptId)
6540
+ ) : await binding.buildSandboxImage(nativeOptions, forward);
6641
6541
  if (emitError != null) {
6642
6542
  throw emitError;
6643
6543
  }
@@ -6683,39 +6583,47 @@ async function importSandboxImage(imageReference, options = {}, deps = {}) {
6683
6583
  deps._allowPat ? "Missing TENSORLAKE_API_KEY or TENSORLAKE_PAT credentials." : "Missing TENSORLAKE_API_KEY credentials."
6684
6584
  );
6685
6585
  }
6586
+ if (options.signal !== void 0 && !options.cas) {
6587
+ throw new Error(
6588
+ "signal is only supported for CAS image imports (cas: true); a legacy import has no Image Service build operation to cancel"
6589
+ );
6590
+ }
6686
6591
  emit({
6687
6592
  type: "status",
6688
6593
  message: `Importing image '${reference}' as '${effectiveName}'...`
6689
6594
  });
6690
6595
  const binding = loadNativeBinding();
6691
6596
  let emitError;
6692
- const resultJson = await binding.importSandboxImage(
6693
- {
6694
- apiUrl: context.apiUrl,
6695
- bearerToken,
6696
- imageReference: reference,
6697
- registeredName: effectiveName,
6698
- diskMb: options.diskMb,
6699
- builderDiskMb: options.builderDiskMb,
6700
- cpus: options.cpus,
6701
- memoryMb: options.memoryMb,
6702
- isPublic: options.isPublic ?? false,
6703
- organizationId: usePat ? context.organizationId : void 0,
6704
- projectId: usePat ? context.projectId : void 0,
6705
- namespace: context.namespace,
6706
- useScopeHeaders: usePat,
6707
- userAgent: void 0,
6708
- dockerCompat: options.dockerCompat ?? false,
6709
- dockerConfigJson: options.dockerConfigJson
6710
- },
6711
- (event) => {
6712
- try {
6713
- emit(eventToEmitDict(event));
6714
- } catch (error) {
6715
- emitError ??= error;
6716
- }
6597
+ const nativeOptions = {
6598
+ apiUrl: context.apiUrl,
6599
+ bearerToken,
6600
+ imageReference: reference,
6601
+ registeredName: effectiveName,
6602
+ diskMb: options.diskMb,
6603
+ builderDiskMb: options.builderDiskMb,
6604
+ cpus: options.cpus,
6605
+ memoryMb: options.memoryMb,
6606
+ isPublic: options.isPublic ?? false,
6607
+ organizationId: usePat ? context.organizationId : void 0,
6608
+ projectId: usePat ? context.projectId : void 0,
6609
+ namespace: context.namespace,
6610
+ useScopeHeaders: usePat,
6611
+ userAgent: void 0,
6612
+ dockerCompat: options.dockerCompat ?? false,
6613
+ dockerConfigJson: options.dockerConfigJson,
6614
+ cas: options.cas ?? false
6615
+ };
6616
+ const forward = (event) => {
6617
+ try {
6618
+ emit(eventToEmitDict(event));
6619
+ } catch (error) {
6620
+ emitError ??= error;
6717
6621
  }
6718
- );
6622
+ };
6623
+ const resultJson = options.cas ? await __runWithInterrupt(
6624
+ options.signal,
6625
+ (interruptId) => binding.importSandboxImage(nativeOptions, forward, interruptId)
6626
+ ) : await binding.importSandboxImage(nativeOptions, forward);
6719
6627
  if (emitError != null) {
6720
6628
  throw emitError;
6721
6629
  }
@@ -6731,10 +6639,7 @@ async function importSandboxImage(imageReference, options = {}, deps = {}) {
6731
6639
  emit({ type: "done" });
6732
6640
  return result;
6733
6641
  }
6734
- async function deleteSandboxImage(imageName) {
6735
- if (typeof imageName !== "string" || imageName.length === 0) {
6736
- throw new TypeError("imageName must be a non-empty string");
6737
- }
6642
+ function catalogOptionsFromEnv() {
6738
6643
  const context = buildContextFromEnv();
6739
6644
  const bearerToken = context.apiKey;
6740
6645
  if (!bearerToken) {
@@ -6745,66 +6650,76 @@ async function deleteSandboxImage(imageName) {
6745
6650
  }
6746
6651
  throw new Error("Missing TENSORLAKE_API_KEY credentials.");
6747
6652
  }
6748
- const client = new CloudClient({
6749
- apiUrl: context.apiUrl,
6750
- apiKey: bearerToken,
6751
- namespace: context.namespace
6752
- });
6753
- try {
6754
- await client.deleteSandboxImage(imageName);
6755
- } finally {
6756
- client.close();
6757
- }
6653
+ return { apiUrl: context.apiUrl, bearerToken, useScopeHeaders: false };
6758
6654
  }
6759
- async function findSandboxImageByName(imageName) {
6760
- if (typeof imageName !== "string" || imageName.length === 0) {
6761
- throw new TypeError("imageName must be a non-empty string");
6762
- }
6655
+ function catalogOptionsFromCredentials(credentials) {
6763
6656
  const context = buildContextFromEnv();
6764
- const bearerToken = context.apiKey;
6657
+ const bearerToken = credentials.apiKey ?? context.apiKey;
6765
6658
  if (!bearerToken) {
6766
- if (context.personalAccessToken) {
6767
- throw new Error(
6768
- "Sandbox image SDKs require TENSORLAKE_API_KEY. Personal access tokens are CLI-only."
6769
- );
6770
- }
6771
6659
  throw new Error("Missing TENSORLAKE_API_KEY credentials.");
6772
6660
  }
6773
- const client = new CloudClient({
6774
- apiUrl: context.apiUrl,
6775
- apiKey: bearerToken,
6776
- namespace: context.namespace
6777
- });
6778
- try {
6779
- return await client.findSandboxImageByName(imageName);
6780
- } finally {
6781
- client.close();
6661
+ const { organizationId, projectId } = credentials;
6662
+ if (organizationId === void 0 !== (projectId === void 0)) {
6663
+ throw new TypeError("organizationId and projectId must be given together");
6782
6664
  }
6665
+ return {
6666
+ apiUrl: credentials.apiUrl ?? context.apiUrl,
6667
+ bearerToken,
6668
+ organizationId,
6669
+ projectId,
6670
+ useScopeHeaders: organizationId !== void 0
6671
+ };
6783
6672
  }
6784
- async function listSandboxImages() {
6785
- const context = buildContextFromEnv();
6786
- const bearerToken = context.apiKey;
6787
- if (!bearerToken) {
6788
- if (context.personalAccessToken) {
6789
- throw new Error(
6790
- "Sandbox image SDKs require TENSORLAKE_API_KEY. Personal access tokens are CLI-only."
6791
- );
6792
- }
6793
- throw new Error("Missing TENSORLAKE_API_KEY credentials.");
6673
+ function parseTemplate(json) {
6674
+ return JSON.parse(json);
6675
+ }
6676
+ async function deleteSandboxImage(imageName) {
6677
+ if (typeof imageName !== "string" || imageName.length === 0) {
6678
+ throw new TypeError("imageName must be a non-empty string");
6794
6679
  }
6795
- const client = new CloudClient({
6796
- apiUrl: context.apiUrl,
6797
- apiKey: bearerToken,
6798
- namespace: context.namespace
6799
- });
6800
- try {
6801
- return await client.listSandboxImages();
6802
- } finally {
6803
- client.close();
6680
+ await loadNativeBinding().deleteSandboxImage(catalogOptionsFromEnv(), imageName);
6681
+ }
6682
+ async function deleteSandboxImageWithCredentials(credentials, imageName) {
6683
+ if (typeof imageName !== "string" || imageName.length === 0) {
6684
+ throw new TypeError("imageName must be a non-empty string");
6685
+ }
6686
+ await loadNativeBinding().deleteSandboxImage(
6687
+ catalogOptionsFromCredentials(credentials),
6688
+ imageName
6689
+ );
6690
+ }
6691
+ async function findSandboxImageByName(imageName) {
6692
+ if (typeof imageName !== "string" || imageName.length === 0) {
6693
+ throw new TypeError("imageName must be a non-empty string");
6694
+ }
6695
+ const json = await loadNativeBinding().findSandboxImage(
6696
+ catalogOptionsFromEnv(),
6697
+ imageName
6698
+ );
6699
+ return json == null ? null : parseTemplate(json);
6700
+ }
6701
+ async function findSandboxImageByNameWithCredentials(credentials, imageName) {
6702
+ if (typeof imageName !== "string" || imageName.length === 0) {
6703
+ throw new TypeError("imageName must be a non-empty string");
6804
6704
  }
6705
+ const json = await loadNativeBinding().findSandboxImage(
6706
+ catalogOptionsFromCredentials(credentials),
6707
+ imageName
6708
+ );
6709
+ return json == null ? null : parseTemplate(json);
6710
+ }
6711
+ async function listSandboxImages() {
6712
+ const json = await loadNativeBinding().listSandboxImages(catalogOptionsFromEnv());
6713
+ return JSON.parse(json);
6714
+ }
6715
+ async function listSandboxImagesWithCredentials(credentials) {
6716
+ const json = await loadNativeBinding().listSandboxImages(
6717
+ catalogOptionsFromCredentials(credentials)
6718
+ );
6719
+ return JSON.parse(json);
6805
6720
  }
6806
6721
  async function runCreateSandboxImageCli(argv = process.argv.slice(2)) {
6807
- const parsed = (0, import_node_util2.parseArgs)({
6722
+ const parsed = (0, import_node_util.parseArgs)({
6808
6723
  args: argv,
6809
6724
  allowPositionals: true,
6810
6725
  options: {
@@ -6858,7 +6773,7 @@ async function runCreateSandboxImageCli(argv = process.argv.slice(2)) {
6858
6773
  );
6859
6774
  }
6860
6775
  async function runImportSandboxImageCli(argv = process.argv.slice(2)) {
6861
- const parsed = (0, import_node_util2.parseArgs)({
6776
+ const parsed = (0, import_node_util.parseArgs)({
6862
6777
  args: argv,
6863
6778
  allowPositionals: true,
6864
6779
  options: {
@@ -6911,7 +6826,7 @@ async function runImportSandboxImageCli(argv = process.argv.slice(2)) {
6911
6826
  { emit: ndjsonStdoutEmit, _allowPat: true }
6912
6827
  );
6913
6828
  }
6914
- var import_node_path3, import_node_os2, import_node_fs2, import_node_util2, cachedNativeBinding, cachedNativeBindingError, DEFAULT_IMAGE_NAME2;
6829
+ var import_node_path3, import_node_os2, import_node_fs2, import_node_util, cachedNativeBinding, cachedNativeBindingError, DEFAULT_IMAGE_NAME2, __imageBuildInternals;
6915
6830
  var init_sandbox_image = __esm({
6916
6831
  "src/sandbox-image.ts"() {
6917
6832
  "use strict";
@@ -6919,11 +6834,21 @@ var init_sandbox_image = __esm({
6919
6834
  import_node_path3 = __toESM(require("path"), 1);
6920
6835
  import_node_os2 = __toESM(require("os"), 1);
6921
6836
  import_node_fs2 = require("fs");
6922
- import_node_util2 = require("util");
6923
- init_cloud_client();
6837
+ import_node_util = require("util");
6924
6838
  init_image();
6925
6839
  init_native_binding();
6840
+ init_image_builds();
6926
6841
  DEFAULT_IMAGE_NAME2 = "default";
6842
+ __imageBuildInternals = {
6843
+ loadNativeBinding: () => loadNativeBinding(),
6844
+ buildContextFromEnv: () => buildContextFromEnv(),
6845
+ stderrEmit: (event) => stderrEmit(event),
6846
+ noopEmit: (event) => noopEmit(event),
6847
+ eventToEmitDict: (event) => eventToEmitDict(event),
6848
+ imageRequiresContext: (image) => imageRequiresContext(image),
6849
+ defaultRegisteredName: (dockerfilePath) => defaultRegisteredName(dockerfilePath),
6850
+ defaultRegisteredNameFromImage: (reference) => defaultRegisteredNameFromImage(reference)
6851
+ };
6927
6852
  }
6928
6853
  });
6929
6854
 
@@ -6948,7 +6873,15 @@ __export(index_exports, {
6948
6873
  Headers: () => Headers,
6949
6874
  HttpBody: () => HttpBody,
6950
6875
  Image: () => Image,
6876
+ ImageBuildCancelledError: () => ImageBuildCancelledError,
6877
+ ImageBuildError: () => ImageBuildError,
6878
+ ImageBuildFailedError: () => ImageBuildFailedError,
6879
+ ImageBuildHandle: () => ImageBuildHandle,
6880
+ ImageBuildInProgressError: () => ImageBuildInProgressError,
6881
+ ImageBuildInterruptedError: () => ImageBuildInterruptedError,
6882
+ ImageBuildNotFoundError: () => ImageBuildNotFoundError,
6951
6883
  ImageBuildOperationType: () => ImageBuildOperationType,
6884
+ ImageBuildTimeoutError: () => ImageBuildTimeoutError,
6952
6885
  MountError: () => MountError,
6953
6886
  OutputMode: () => OutputMode,
6954
6887
  PendingSandbox: () => PendingSandbox,
@@ -6981,12 +6914,14 @@ __export(index_exports, {
6981
6914
  TERMINATION_REASON_CANCELLED: () => TERMINATION_REASON_CANCELLED,
6982
6915
  TERMINATION_REASON_NO_CAPACITY: () => TERMINATION_REASON_NO_CAPACITY,
6983
6916
  TcpTunnel: () => TcpTunnel,
6917
+ cancelImageBuild: () => cancelImageBuild,
6984
6918
  createFileSystem: () => createFileSystem,
6985
6919
  createSandboxImage: () => createSandboxImage,
6986
6920
  deleteFileSystem: () => deleteFileSystem,
6987
6921
  deleteSandboxImage: () => deleteSandboxImage,
6988
6922
  dockerfileContent: () => dockerfileContent,
6989
6923
  findSandboxImageByName: () => findSandboxImageByName,
6924
+ getImageBuild: () => getImageBuild,
6990
6925
  importSandboxImage: () => importSandboxImage,
6991
6926
  isSandboxPending: () => isSandboxPending,
6992
6927
  listFileSystems: () => listFileSystems,
@@ -6998,7 +6933,10 @@ __export(index_exports, {
6998
6933
  runLocal: () => runLocal,
6999
6934
  runRemote: () => runRemote,
7000
6935
  sandboxUrlFromIngressEndpoint: () => sandboxUrlFromIngressEndpoint,
7001
- schema: () => schema
6936
+ schema: () => schema,
6937
+ startImageBuild: () => startImageBuild,
6938
+ startImageImport: () => startImageImport,
6939
+ waitImageBuild: () => waitImageBuild
7002
6940
  });
7003
6941
  module.exports = __toCommonJS(index_exports);
7004
6942
  init_cjs_shims();
@@ -7008,11 +6946,546 @@ init_pending_sandbox();
7008
6946
  init_sandbox();
7009
6947
  init_desktop();
7010
6948
  init_tunnel();
7011
- init_cloud_client();
6949
+
6950
+ // src/cloud-client.ts
6951
+ init_cjs_shims();
6952
+ var import_nanoid = require("nanoid");
6953
+ init_defaults();
6954
+
6955
+ // src/native-cloud.ts
6956
+ init_cjs_shims();
6957
+ init_native_sandbox();
6958
+ init_native_worker_client();
6959
+ var NativeCloudTransport = class {
6960
+ constructor(options) {
6961
+ this.options = options;
6962
+ if (!Number.isSafeInteger(options.maxRetries) || options.maxRetries < 0 || options.maxRetries > 4294967295) {
6963
+ throw new RangeError("maxRetries must be a non-negative 32-bit integer");
6964
+ }
6965
+ if (!Number.isFinite(options.retryBackoffMs) || options.retryBackoffMs < 0) {
6966
+ throw new RangeError("retryBackoffMs must be a non-negative finite number");
6967
+ }
6968
+ }
6969
+ native;
6970
+ closed = false;
6971
+ client() {
6972
+ if (this.closed) throw new Error("Tensorlake native client is closed");
6973
+ if (this.native) return this.native;
6974
+ const ctor = loadNativeSandboxBinding().NativeCloudClient;
6975
+ if (!ctor) throw new Error("Native binding does not export NativeCloudClient; rebuild with 'npm run build:native'");
6976
+ return this.native = new ctor(JSON.stringify(this.options));
6977
+ }
6978
+ close() {
6979
+ this.closed = true;
6980
+ releaseNativeHandle(this.native ?? null);
6981
+ this.native = void 0;
6982
+ }
6983
+ async requestResponse(method, path4, options) {
6984
+ const request = await serializeRequest(method, path4, options);
6985
+ const raw = await callNative(() => this.client().request(request));
6986
+ const response = new Response(
6987
+ [204, 205, 304].includes(raw.status) ? null : Uint8Array.from(raw.data).buffer,
6988
+ { status: raw.status, headers: JSON.parse(raw.headersJson) }
6989
+ );
6990
+ return Object.assign(response, { traceId: raw.traceId });
6991
+ }
6992
+ async requestJson(method, path4) {
6993
+ const response = await this.requestResponse(method, path4);
6994
+ const text = await response.text();
6995
+ const value = text ? JSON.parse(text) : null;
6996
+ return Object.assign(value ?? {}, { traceId: response.traceId });
6997
+ }
6998
+ async *stream(method, path4, signal) {
6999
+ if (signal?.aborted) return;
7000
+ const request = await serializeRequest(method, path4, { headers: { Accept: "text/event-stream" } });
7001
+ yield* nativeEventStream((emit) => this.client().stream(request, emit), void 0, signal);
7002
+ }
7003
+ };
7004
+ async function serializeRequest(method, path4, options) {
7005
+ const headers = { ...options?.headers };
7006
+ let body = options?.body;
7007
+ if (options?.json !== void 0) {
7008
+ body = JSON.stringify(options.json);
7009
+ if (!Object.keys(headers).some((key) => key.toLowerCase() === "content-type")) {
7010
+ headers["Content-Type"] = "application/json";
7011
+ }
7012
+ }
7013
+ const request = {
7014
+ method,
7015
+ path: path4,
7016
+ headersJson: JSON.stringify(headers),
7017
+ statusOnlyCodes: [...options?.statusOnlyCodes ?? []]
7018
+ };
7019
+ if (body instanceof FormData) {
7020
+ request.parts = [];
7021
+ for (const [name, value] of body.entries()) {
7022
+ request.parts.push(typeof value === "string" ? { name, data: Buffer.from(value) } : { name, data: Buffer.from(await value.arrayBuffer()), filename: value.name, contentType: value.type || "application/octet-stream" });
7023
+ }
7024
+ } else if (body !== void 0) {
7025
+ if (body instanceof Blob) request.body = Buffer.from(await body.arrayBuffer());
7026
+ else if (typeof body === "string") request.body = Buffer.from(body);
7027
+ else if (body instanceof ArrayBuffer) request.body = Buffer.from(new Uint8Array(body));
7028
+ else request.body = Buffer.from(body);
7029
+ }
7030
+ return request;
7031
+ }
7032
+
7033
+ // src/cloud-client.ts
7034
+ init_models();
7035
+ init_sandbox_image();
7036
+ var CloudClient = class _CloudClient {
7037
+ transport;
7038
+ apiUrl;
7039
+ apiKey;
7040
+ organizationId;
7041
+ projectId;
7042
+ namespace;
7043
+ constructor(options) {
7044
+ this.apiUrl = options?.apiUrl ?? API_URL;
7045
+ this.apiKey = options?.apiKey ?? API_KEY;
7046
+ this.organizationId = options?.organizationId;
7047
+ this.projectId = options?.projectId;
7048
+ this.namespace = options?.namespace ?? NAMESPACE;
7049
+ this.transport = new NativeCloudTransport({
7050
+ baseUrl: options?.apiUrl ?? API_URL,
7051
+ apiKey: options?.apiKey ?? API_KEY,
7052
+ organizationId: this.organizationId,
7053
+ projectId: this.projectId,
7054
+ maxRetries: options?.maxRetries ?? MAX_RETRIES,
7055
+ retryBackoffMs: options?.retryBackoffMs ?? RETRY_BACKOFF_MS,
7056
+ timeoutMs: DEFAULT_HTTP_TIMEOUT_MS,
7057
+ userAgent: `tensorlake-typescript-sdk/${SDK_VERSION}`
7058
+ });
7059
+ }
7060
+ static forCloud(options) {
7061
+ return new _CloudClient(options);
7062
+ }
7063
+ close() {
7064
+ this.transport.close();
7065
+ }
7066
+ async upsertApplication(manifest, codeZip, upgradeRunningRequests = false) {
7067
+ const applicationManifest = { ...manifest };
7068
+ let publicEndpointId = publicEndpointIdFromManifest(applicationManifest);
7069
+ if (applicationAllowsUnauthenticatedRequests(applicationManifest) && publicEndpointId === void 0) {
7070
+ const applicationName = applicationManifest.name;
7071
+ if (typeof applicationName === "string" && applicationName.length > 0) {
7072
+ publicEndpointId = await this.existingApplicationPublicEndpointId(applicationName);
7073
+ }
7074
+ publicEndpointId ??= generatePublicEndpointId();
7075
+ }
7076
+ if (publicEndpointId !== void 0) {
7077
+ applicationManifest.public_endpoint_id = publicEndpointId;
7078
+ delete applicationManifest.publicEndpointId;
7079
+ }
7080
+ const form = new FormData();
7081
+ form.append(
7082
+ "code",
7083
+ new Blob([toBlobPart(codeZip)], { type: "application/zip" }),
7084
+ "code.zip"
7085
+ );
7086
+ form.append("code_content_type", "application/zip");
7087
+ form.append("application", JSON.stringify(applicationManifest));
7088
+ form.append(
7089
+ "upgrade_requests_to_latest_code",
7090
+ String(upgradeRunningRequests)
7091
+ );
7092
+ await this.transport.requestResponse("POST", this.namespacePath("applications"), {
7093
+ body: form
7094
+ });
7095
+ }
7096
+ async deleteApplication(applicationName) {
7097
+ await this.transport.requestResponse(
7098
+ "DELETE",
7099
+ this.namespacePath(`applications/${encodeURIComponent(applicationName)}`)
7100
+ );
7101
+ }
7102
+ /**
7103
+ * Delete a registered sandbox image by name or id through the merged
7104
+ * catalog, with this client's credentials: an `image_` id or a name the
7105
+ * Image Service knows deletes a CAS image, a `sandbox_template_` id or a
7106
+ * name registered only in the platform registry deletes a legacy image.
7107
+ * Rejects when neither catalog knows the reference. The same semantics
7108
+ * and accepted differences as the module-level `deleteSandboxImage`.
7109
+ */
7110
+ async deleteSandboxImage(imageName) {
7111
+ await deleteSandboxImageWithCredentials(this.catalogCredentials(), imageName);
7112
+ }
7113
+ /**
7114
+ * Look up a registered sandbox image by name or id through the merged
7115
+ * catalog, with this client's credentials. Returns the image in the
7116
+ * sandbox-template shape, or `null` when neither the Image Service nor the
7117
+ * platform registry knows the reference. An explicit organization/project
7118
+ * scope (the client's, or the call's override) addresses that project's
7119
+ * routes directly, as before; without one the key's own scope applies.
7120
+ */
7121
+ async findSandboxImageByName(imageName, options) {
7122
+ return findSandboxImageByNameWithCredentials(
7123
+ this.catalogCredentials(options),
7124
+ imageName
7125
+ );
7126
+ }
7127
+ /**
7128
+ * List every registered sandbox image of the project (CAS and legacy, in
7129
+ * the sandbox-template shape, newest first) through the merged catalog,
7130
+ * with this client's credentials. An explicit organization/project scope
7131
+ * (the client's, or the call's override) addresses that project's routes
7132
+ * directly, as before; without one the key's own scope applies.
7133
+ */
7134
+ async listSandboxImages(options) {
7135
+ return listSandboxImagesWithCredentials(this.catalogCredentials(options));
7136
+ }
7137
+ catalogCredentials(options) {
7138
+ return {
7139
+ apiUrl: this.apiUrl,
7140
+ apiKey: this.apiKey,
7141
+ organizationId: options?.organizationId ?? this.organizationId,
7142
+ projectId: options?.projectId ?? this.projectId
7143
+ };
7144
+ }
7145
+ async applications() {
7146
+ const raw = await this.transport.requestJson(
7147
+ "GET",
7148
+ this.namespacePath("applications")
7149
+ );
7150
+ return (raw.applications ?? []).map(
7151
+ (application) => fromSnakeKeys(application)
7152
+ );
7153
+ }
7154
+ async applicationManifest(applicationName) {
7155
+ const raw = await this.transport.requestJson(
7156
+ "GET",
7157
+ this.namespacePath(`applications/${encodeURIComponent(applicationName)}`)
7158
+ );
7159
+ return fromSnakeKeys(raw);
7160
+ }
7161
+ async runRequest(applicationName, inputs = []) {
7162
+ const path4 = this.namespacePath(
7163
+ `applications/${encodeURIComponent(applicationName)}`
7164
+ );
7165
+ const response = inputs.length === 0 ? await this.transport.requestResponse("POST", path4, {
7166
+ body: new Uint8Array(),
7167
+ headers: { Accept: "application/json" }
7168
+ }) : inputs.length === 1 && inputs[0].name === "0" ? await this.transport.requestResponse("POST", path4, {
7169
+ body: toRequestBody(inputs[0].data),
7170
+ headers: {
7171
+ Accept: "application/json",
7172
+ "Content-Type": inputs[0].contentType
7173
+ }
7174
+ }) : await this.runMultipartRequest(path4, inputs);
7175
+ const body = await parseJsonResponse(response);
7176
+ const requestId = body?.request_id;
7177
+ if (!requestId) {
7178
+ throw new Error("missing request_id in run request response body");
7179
+ }
7180
+ return requestId;
7181
+ }
7182
+ async waitOnRequestCompletion(applicationName, requestId) {
7183
+ const stream = this.transport.stream(
7184
+ "GET",
7185
+ this.namespacePath(
7186
+ `applications/${encodeURIComponent(applicationName)}/requests/${encodeURIComponent(requestId)}/progress`
7187
+ )
7188
+ );
7189
+ for await (const event of stream) {
7190
+ if (Object.prototype.hasOwnProperty.call(event, "RequestFinished")) {
7191
+ return;
7192
+ }
7193
+ }
7194
+ throw new Error("progress stream ended before request completion");
7195
+ }
7196
+ async requestMetadata(applicationName, requestId) {
7197
+ const raw = await this.transport.requestJson(
7198
+ "GET",
7199
+ this.namespacePath(
7200
+ `applications/${encodeURIComponent(applicationName)}/requests/${encodeURIComponent(requestId)}`
7201
+ )
7202
+ );
7203
+ return fromSnakeKeys(raw);
7204
+ }
7205
+ async requestOutput(applicationName, requestId) {
7206
+ const response = await this.transport.requestResponse(
7207
+ "GET",
7208
+ this.namespacePath(
7209
+ `applications/${encodeURIComponent(applicationName)}/requests/${encodeURIComponent(requestId)}/output`
7210
+ )
7211
+ );
7212
+ const serializedValue = new Uint8Array(await response.arrayBuffer());
7213
+ const contentType = response.headers.get("content-type") ?? "";
7214
+ return {
7215
+ serializedValue,
7216
+ contentType
7217
+ };
7218
+ }
7219
+ async listSecrets(options) {
7220
+ const base = this.secretCollectionPath(
7221
+ options?.organizationId,
7222
+ options?.projectId
7223
+ );
7224
+ const raw = await this.transport.requestJson("GET", base);
7225
+ const pageSize = Math.max(0, options?.pageSize ?? 100);
7226
+ return Object.assign(
7227
+ {
7228
+ items: raw.slice(0, pageSize).map(secretFromMetadata),
7229
+ pagination: { total: raw.length }
7230
+ },
7231
+ { traceId: raw.traceId }
7232
+ );
7233
+ }
7234
+ async getSecret(secretId, options) {
7235
+ const base = this.secretCollectionPath(
7236
+ options?.organizationId,
7237
+ options?.projectId
7238
+ );
7239
+ const raw = await this.transport.requestJson(
7240
+ "GET",
7241
+ `${base}/${encodeURIComponent(secretId)}`
7242
+ );
7243
+ return Object.assign(secretFromMetadata(raw), { traceId: raw.traceId });
7244
+ }
7245
+ async upsertSecrets(secrets, options) {
7246
+ const base = this.secretCollectionPath(
7247
+ options?.organizationId,
7248
+ options?.projectId
7249
+ );
7250
+ if (Array.isArray(secrets)) {
7251
+ const results = [];
7252
+ for (const secret of secrets) {
7253
+ results.push(await this.upsertSecret(base, secret));
7254
+ }
7255
+ return results;
7256
+ }
7257
+ return this.upsertSecret(base, secrets);
7258
+ }
7259
+ async deleteSecret(secretId, options) {
7260
+ const base = this.secretCollectionPath(
7261
+ options?.organizationId,
7262
+ options?.projectId
7263
+ );
7264
+ await this.transport.requestResponse(
7265
+ "DELETE",
7266
+ `${base}/${encodeURIComponent(secretId)}`
7267
+ );
7268
+ }
7269
+ async upsertSecret(base, secret) {
7270
+ let response = await this.transport.requestResponse("POST", base, {
7271
+ json: secret,
7272
+ headers: { "Idempotency-Key": (0, import_nanoid.nanoid)() },
7273
+ statusOnlyCodes: /* @__PURE__ */ new Set([409])
7274
+ });
7275
+ if (response.status === 409) {
7276
+ const prefix = base.slice(0, -"/secrets".length);
7277
+ const existing = await this.transport.requestJson(
7278
+ "GET",
7279
+ `${prefix}/secret-names/${encodeURIComponent(secret.name)}`
7280
+ );
7281
+ response = await this.transport.requestResponse(
7282
+ "POST",
7283
+ `${base}/${encodeURIComponent(existing.id)}/versions`,
7284
+ {
7285
+ json: { value: secret.value },
7286
+ headers: { "Idempotency-Key": (0, import_nanoid.nanoid)() }
7287
+ }
7288
+ );
7289
+ }
7290
+ const metadata = await parseJsonResponse(response);
7291
+ return Object.assign(secretFromMetadata(metadata), {
7292
+ traceId: response.traceId
7293
+ });
7294
+ }
7295
+ async startImageBuild(buildServicePath, request) {
7296
+ const form = new FormData();
7297
+ form.append("graph_name", request.applicationName);
7298
+ form.append("graph_version", request.applicationVersion);
7299
+ form.append("graph_function_name", request.functionName);
7300
+ form.append("image_name", request.imageName);
7301
+ form.append("image_id", request.imageId);
7302
+ form.append(
7303
+ "context",
7304
+ new Blob([toBlobPart(request.buildContext)]),
7305
+ "context.tar.gz"
7306
+ );
7307
+ const response = await this.transport.requestResponse(
7308
+ "PUT",
7309
+ `${trimTrailingSlashes2(buildServicePath)}/builds`,
7310
+ { body: form }
7311
+ );
7312
+ const raw = await parseJsonResponse(response);
7313
+ return fromSnakeKeys(raw);
7314
+ }
7315
+ async createApplicationBuild(buildServicePath, request, imageContexts) {
7316
+ const form = createApplicationBuildForm(request, imageContexts);
7317
+ const response = await this.transport.requestResponse(
7318
+ "POST",
7319
+ trimTrailingSlashes2(buildServicePath),
7320
+ { body: form }
7321
+ );
7322
+ const raw = await parseJsonResponse(response);
7323
+ return fromSnakeKeys(raw);
7324
+ }
7325
+ async applicationBuildInfo(buildServicePath, applicationBuildId) {
7326
+ const raw = await this.transport.requestJson(
7327
+ "GET",
7328
+ `${trimTrailingSlashes2(buildServicePath)}/${encodeURIComponent(applicationBuildId)}`
7329
+ );
7330
+ return fromSnakeKeys(raw);
7331
+ }
7332
+ async cancelApplicationBuild(buildServicePath, applicationBuildId) {
7333
+ const raw = await this.transport.requestJson(
7334
+ "POST",
7335
+ `${trimTrailingSlashes2(buildServicePath)}/${encodeURIComponent(applicationBuildId)}/cancel`
7336
+ );
7337
+ return fromSnakeKeys(raw);
7338
+ }
7339
+ async buildInfo(buildServicePath, buildId) {
7340
+ const raw = await this.transport.requestJson(
7341
+ "GET",
7342
+ `${trimTrailingSlashes2(buildServicePath)}/builds/${encodeURIComponent(buildId)}`
7343
+ );
7344
+ return fromSnakeKeys(raw);
7345
+ }
7346
+ async cancelBuild(buildServicePath, buildId) {
7347
+ await this.transport.requestResponse(
7348
+ "POST",
7349
+ `${trimTrailingSlashes2(buildServicePath)}/builds/${encodeURIComponent(buildId)}/cancel`
7350
+ );
7351
+ }
7352
+ async *streamBuildLogs(buildServicePath, buildId, signal) {
7353
+ const stream = this.transport.stream(
7354
+ "GET",
7355
+ `${trimTrailingSlashes2(buildServicePath)}/builds/${encodeURIComponent(buildId)}/logs`,
7356
+ signal
7357
+ );
7358
+ for await (const event of stream) {
7359
+ yield fromSnakeKeys(event);
7360
+ }
7361
+ }
7362
+ async runMultipartRequest(path4, inputs) {
7363
+ const form = new FormData();
7364
+ for (const input of inputs) {
7365
+ form.append(
7366
+ input.name,
7367
+ new Blob([toBlobPart(input.data)], { type: input.contentType }),
7368
+ input.name
7369
+ );
7370
+ }
7371
+ return this.transport.requestResponse("POST", path4, {
7372
+ body: form,
7373
+ headers: { Accept: "application/json" }
7374
+ });
7375
+ }
7376
+ namespacePath(subpath) {
7377
+ return `/v1/namespaces/${encodeURIComponent(this.namespace)}/${subpath.replace(/^\/+/, "")}`;
7378
+ }
7379
+ async existingApplicationPublicEndpointId(applicationName) {
7380
+ const response = await this.transport.requestResponse(
7381
+ "GET",
7382
+ this.namespacePath(`applications/${encodeURIComponent(applicationName)}`),
7383
+ { statusOnlyCodes: /* @__PURE__ */ new Set([404]) }
7384
+ );
7385
+ if (response.status === 404) {
7386
+ return void 0;
7387
+ }
7388
+ const application = await parseJsonResponse(response);
7389
+ return publicEndpointIdFromManifest(application);
7390
+ }
7391
+ secretCollectionPath(organizationId, projectId) {
7392
+ const resolvedOrganizationId = organizationId ?? this.organizationId;
7393
+ const resolvedProjectId = projectId ?? this.projectId;
7394
+ if (!resolvedOrganizationId && !resolvedProjectId) {
7395
+ return this.namespacePath("secrets");
7396
+ }
7397
+ if (!resolvedOrganizationId || !resolvedProjectId) {
7398
+ throw new Error("organizationId and projectId must be provided together");
7399
+ }
7400
+ return this.namespacePath("secrets");
7401
+ }
7402
+ };
7403
+ function secretFromMetadata(metadata) {
7404
+ return {
7405
+ id: metadata.id,
7406
+ name: metadata.name,
7407
+ createdAt: new Date(metadata.created_at_ms)
7408
+ };
7409
+ }
7410
+ var UNAUTHENTICATED_REQUESTS = "unauthenticated_requests";
7411
+ function applicationAllowsUnauthenticatedRequests(manifest) {
7412
+ return Array.isArray(manifest.allow) && manifest.allow.includes(UNAUTHENTICATED_REQUESTS);
7413
+ }
7414
+ function publicEndpointIdFromManifest(manifest) {
7415
+ for (const key of ["public_endpoint_id", "publicEndpointId"]) {
7416
+ const value = manifest[key];
7417
+ if (typeof value === "string" && value.length > 0) {
7418
+ return value;
7419
+ }
7420
+ }
7421
+ return void 0;
7422
+ }
7423
+ function generatePublicEndpointId() {
7424
+ return `endpoint_${(0, import_nanoid.nanoid)()}`;
7425
+ }
7426
+ function createApplicationBuildForm(request, imageContexts) {
7427
+ const contextsByPartName = /* @__PURE__ */ new Map();
7428
+ for (const context of imageContexts) {
7429
+ if (contextsByPartName.has(context.contextTarPartName)) {
7430
+ throw new Error(
7431
+ `duplicate image context part name '${context.contextTarPartName}'`
7432
+ );
7433
+ }
7434
+ contextsByPartName.set(context.contextTarPartName, context);
7435
+ }
7436
+ const form = new FormData();
7437
+ form.append(
7438
+ "app_version",
7439
+ new Blob([JSON.stringify(request)], { type: "application/json" }),
7440
+ "app_version"
7441
+ );
7442
+ for (const image of request.images) {
7443
+ const context = contextsByPartName.get(image.contextTarPartName);
7444
+ if (!context) {
7445
+ throw new Error(
7446
+ `missing image context for part '${image.contextTarPartName}'`
7447
+ );
7448
+ }
7449
+ form.append(
7450
+ image.contextTarPartName,
7451
+ new Blob([toBlobPart(context.contextTarGz)]),
7452
+ `${image.contextTarPartName}.tar.gz`
7453
+ );
7454
+ }
7455
+ for (const context of imageContexts) {
7456
+ if (!request.images.some((image) => image.contextTarPartName === context.contextTarPartName)) {
7457
+ throw new Error(
7458
+ `unexpected image context for part '${context.contextTarPartName}'`
7459
+ );
7460
+ }
7461
+ }
7462
+ return form;
7463
+ }
7464
+ function trimTrailingSlashes2(value) {
7465
+ return value.endsWith("/") ? value.slice(0, -1) : value;
7466
+ }
7467
+ function toBlobPart(data) {
7468
+ if (typeof data === "string" || data instanceof Blob) {
7469
+ return data;
7470
+ }
7471
+ if (data instanceof Uint8Array) {
7472
+ return Uint8Array.from(data).buffer;
7473
+ }
7474
+ return data;
7475
+ }
7476
+ function toRequestBody(data) {
7477
+ return toBlobPart(data);
7478
+ }
7479
+ async function parseJsonResponse(response) {
7480
+ const text = await response.text();
7481
+ if (!text) {
7482
+ return void 0;
7483
+ }
7484
+ return JSON.parse(text);
7485
+ }
7012
7486
 
7013
7487
  // src/api-client.ts
7014
7488
  init_cjs_shims();
7015
- init_cloud_client();
7016
7489
 
7017
7490
  // src/filesystem.ts
7018
7491
  init_cjs_shims();
@@ -7021,21 +7494,21 @@ var import_node_crypto2 = require("crypto");
7021
7494
  // src/mount-cli.ts
7022
7495
  init_cjs_shims();
7023
7496
  var import_node_child_process = require("child_process");
7024
- var import_node_fs = require("fs");
7025
- var import_node_os = require("os");
7026
- var import_node_path = require("path");
7027
- var import_node_util = require("util");
7497
+ var import_node_fs3 = require("fs");
7498
+ var import_node_os3 = require("os");
7499
+ var import_node_path4 = require("path");
7500
+ var import_node_util2 = require("util");
7028
7501
 
7029
7502
  // src/filesystem-models.ts
7030
7503
  init_cjs_shims();
7031
7504
  var GIT_MODE_DIR = 16384;
7032
7505
  var GIT_MODE_SYMLINK = 40960;
7033
- function trimSlashes(path3) {
7506
+ function trimSlashes(path4) {
7034
7507
  let start = 0;
7035
- let end = path3.length;
7036
- while (start < end && path3.charCodeAt(start) === 47) start += 1;
7037
- while (end > start && path3.charCodeAt(end - 1) === 47) end -= 1;
7038
- return path3.slice(start, end);
7508
+ let end = path4.length;
7509
+ while (start < end && path4.charCodeAt(start) === 47) start += 1;
7510
+ while (end > start && path4.charCodeAt(end - 1) === 47) end -= 1;
7511
+ return path4.slice(start, end);
7039
7512
  }
7040
7513
  function fileEntryFromWire(entry, dirPath) {
7041
7514
  const mode = entry.mode ?? 33188;
@@ -7053,9 +7526,9 @@ function fileEntryFromWire(entry, dirPath) {
7053
7526
  }
7054
7527
  function mountStatusFromRaw(raw, localPath) {
7055
7528
  const mounted = "mounted" in raw ? Boolean(raw.mounted) : "active" in raw ? Boolean(raw.active) : true;
7056
- const path3 = String(raw.path || raw.mount_path || localPath || "");
7529
+ const path4 = String(raw.path || raw.mount_path || localPath || "");
7057
7530
  const filesystem = raw.filesystem || raw.file_system || raw.repository || null;
7058
- return { path: path3, filesystem, mounted, raw };
7531
+ return { path: path4, filesystem, mounted, raw };
7059
7532
  }
7060
7533
  var FilesystemError = class extends Error {
7061
7534
  constructor(message) {
@@ -7074,11 +7547,11 @@ var FilesystemNotFoundError = class extends FilesystemError {
7074
7547
  var FileNotFoundInFilesystemError = class extends FilesystemError {
7075
7548
  filesystem;
7076
7549
  path;
7077
- constructor(filesystem, path3) {
7078
- super(`File not found in filesystem ${filesystem}: ${path3}`);
7550
+ constructor(filesystem, path4) {
7551
+ super(`File not found in filesystem ${filesystem}: ${path4}`);
7079
7552
  this.name = "FileNotFoundInFilesystemError";
7080
7553
  this.filesystem = filesystem;
7081
- this.path = path3;
7554
+ this.path = path4;
7082
7555
  }
7083
7556
  };
7084
7557
  var FilesystemAPIError = class extends FilesystemError {
@@ -7113,7 +7586,7 @@ var CliNotFoundError = class extends MountError {
7113
7586
  };
7114
7587
 
7115
7588
  // src/mount-cli.ts
7116
- var execFileAsync = (0, import_node_util.promisify)(import_node_child_process.execFile);
7589
+ var execFileAsync = (0, import_node_util2.promisify)(import_node_child_process.execFile);
7117
7590
  var MountCli = class {
7118
7591
  constructor(command, envOverrides) {
7119
7592
  this.command = command;
@@ -7124,9 +7597,9 @@ var MountCli = class {
7124
7597
  const candidates = [];
7125
7598
  if (process.env.TENSORLAKE_CLI) candidates.push(process.env.TENSORLAKE_CLI);
7126
7599
  candidates.push("tl");
7127
- const installed = (0, import_node_path.join)((0, import_node_os.homedir)(), ".tensorlake", "bin", "tl");
7600
+ const installed = (0, import_node_path4.join)((0, import_node_os3.homedir)(), ".tensorlake", "bin", "tl");
7128
7601
  try {
7129
- (0, import_node_fs.accessSync)(installed, import_node_fs.constants.F_OK);
7602
+ (0, import_node_fs3.accessSync)(installed, import_node_fs3.constants.F_OK);
7130
7603
  candidates.push(installed);
7131
7604
  } catch {
7132
7605
  }
@@ -7432,8 +7905,8 @@ var Filesystem = class {
7432
7905
  }
7433
7906
  // -- writes -------------------------------------------------------------------
7434
7907
  /** Write one file. Returns the snapshot (version) the write produced. */
7435
- async writeFile(path3, data, message) {
7436
- return await this.writeFiles(/* @__PURE__ */ new Map([[path3, data]]), message);
7908
+ async writeFile(path4, data, message) {
7909
+ return await this.writeFiles(/* @__PURE__ */ new Map([[path4, data]]), message);
7437
7910
  }
7438
7911
  /** Write several files (and/or delete paths) in one atomic snapshot. */
7439
7912
  async writeFiles(files, message, deletes = []) {
@@ -7441,8 +7914,8 @@ var Filesystem = class {
7441
7914
  if (entries.length === 0 && deletes.length === 0) {
7442
7915
  throw new FilesystemError("nothing to write: no files or deletions given");
7443
7916
  }
7444
- const writes = entries.map(([path3, data]) => ({
7445
- path: path3,
7917
+ const writes = entries.map(([path4, data]) => ({
7918
+ path: path4,
7446
7919
  content: toBuffer(data)
7447
7920
  }));
7448
7921
  const resolvedMessage = message || `write ${writes.length} file(s) via SDK`;
@@ -7458,9 +7931,9 @@ var Filesystem = class {
7458
7931
  * Stream one local file directly to object storage in bounded parts.
7459
7932
  * This is the memory-bounded API for multi-GiB files.
7460
7933
  */
7461
- async writeFileFromPath(path3, localPath, message) {
7934
+ async writeFileFromPath(path4, localPath, message) {
7462
7935
  return await this.writeFilesFromPaths(
7463
- /* @__PURE__ */ new Map([[path3, localPath]]),
7936
+ /* @__PURE__ */ new Map([[path4, localPath]]),
7464
7937
  message
7465
7938
  );
7466
7939
  }
@@ -7473,7 +7946,7 @@ var Filesystem = class {
7473
7946
  if (entries.length === 0) {
7474
7947
  throw new FilesystemError("nothing to write: no local files given");
7475
7948
  }
7476
- const writes = entries.map(([path3, localPath]) => ({ path: path3, localPath }));
7949
+ const writes = entries.map(([path4, localPath]) => ({ path: path4, localPath }));
7477
7950
  const resolvedMessage = message || `write ${writes.length} local file(s) via SDK`;
7478
7951
  const branch = await this.branch();
7479
7952
  const traced = await callNative2(
@@ -7550,11 +8023,11 @@ var Filesystem = class {
7550
8023
  };
7551
8024
  }
7552
8025
  /** Delete one file. Returns the durable version the deletion produced. */
7553
- async deleteFile(path3, message) {
8026
+ async deleteFile(path4, message) {
7554
8027
  return await this.writeFiles(
7555
8028
  /* @__PURE__ */ new Map(),
7556
- message || `delete ${path3} via SDK`,
7557
- [path3]
8029
+ message || `delete ${path4} via SDK`,
8030
+ [path4]
7558
8031
  );
7559
8032
  }
7560
8033
  /**
@@ -7605,15 +8078,15 @@ var Filesystem = class {
7605
8078
  * Read a file's bytes at `version` (the current `main` head or a retained
7606
8079
  * snapshot id; defaults to the filesystem's current head).
7607
8080
  */
7608
- async readFile(path3, version) {
7609
- return (await this.readFileWithMetadata(path3, { version })).data;
8081
+ async readFile(path4, version) {
8082
+ return (await this.readFileWithMetadata(path4, { version })).data;
7610
8083
  }
7611
8084
  /**
7612
8085
  * Read bytes and immutable metadata in one request. A range is executed by
7613
8086
  * Artifact Storage, so callers never download the unrequested remainder.
7614
8087
  */
7615
- async readFileWithMetadata(path3, options = {}) {
7616
- if (trimSlashes(path3) === "") {
8088
+ async readFileWithMetadata(path4, options = {}) {
8089
+ if (trimSlashes(path4) === "") {
7617
8090
  throw new FilesystemError("file path must not be empty");
7618
8091
  }
7619
8092
  const range = options.range;
@@ -7626,12 +8099,12 @@ var Filesystem = class {
7626
8099
  const traced = await callNative2(
7627
8100
  () => this.native.readFilesystemFile(
7628
8101
  this.name,
7629
- path3,
8102
+ path4,
7630
8103
  resolvedVersion,
7631
8104
  range?.offset,
7632
8105
  range?.length
7633
8106
  ),
7634
- new FileNotFoundInFilesystemError(this.name, path3)
8107
+ new FileNotFoundInFilesystemError(this.name, path4)
7635
8108
  );
7636
8109
  const fullSize = traced.fullSize;
7637
8110
  if (!traced.contentId || fullSize === void 0 || !Number.isSafeInteger(fullSize) || fullSize < 0 || traced.data.byteLength > fullSize) {
@@ -7646,9 +8119,9 @@ var Filesystem = class {
7646
8119
  };
7647
8120
  }
7648
8121
  /** Read a file as UTF-8 text at `version`. Throws on non-UTF-8 content. */
7649
- async readText(path3, version) {
8122
+ async readText(path4, version) {
7650
8123
  return new TextDecoder("utf-8", { fatal: true, ignoreBOM: true }).decode(
7651
- await this.readFile(path3, version)
8124
+ await this.readFile(path4, version)
7652
8125
  );
7653
8126
  }
7654
8127
  /** List one directory (non-recursive) at `version`. */
@@ -7711,11 +8184,11 @@ var FilesystemMount = class {
7711
8184
  path;
7712
8185
  readonly;
7713
8186
  /** @internal — obtain instances via `FilesystemClient.mount()`. */
7714
- constructor(client, cli, filesystem, path3, readonly) {
8187
+ constructor(client, cli, filesystem, path4, readonly) {
7715
8188
  this.client = client;
7716
8189
  this.cli = cli;
7717
8190
  this.filesystem = filesystem;
7718
- this.path = path3;
8191
+ this.path = path4;
7719
8192
  this.readonly = readonly;
7720
8193
  }
7721
8194
  /** Flush pending local changes into a durable snapshot. */
@@ -7733,6 +8206,7 @@ var FilesystemMount = class {
7733
8206
  };
7734
8207
 
7735
8208
  // src/api-client.ts
8209
+ init_sandbox_image();
7736
8210
  init_errors();
7737
8211
  var APIClient = class {
7738
8212
  cloudClient;
@@ -7760,7 +8234,7 @@ var APIClient = class {
7760
8234
  await this.cloudClient.deleteApplication(applicationName);
7761
8235
  }
7762
8236
  async deleteSandboxImage(imageName) {
7763
- await this.cloudClient.deleteSandboxImage(imageName);
8237
+ await deleteSandboxImageWithCredentials(this.filesystemOptions, imageName);
7764
8238
  }
7765
8239
  async createFileSystem(name, description, options) {
7766
8240
  const filesystem = await new FilesystemClient(this.filesystemOptions).create(
@@ -7830,7 +8304,7 @@ init_sandbox_image();
7830
8304
 
7831
8305
  // src/repository-mount.ts
7832
8306
  init_cjs_shims();
7833
- var import_node_path4 = require("path");
8307
+ var import_node_path5 = require("path");
7834
8308
  function requireNonEmpty(value, name) {
7835
8309
  if (typeof value !== "string" || value.length === 0) {
7836
8310
  throw new TypeError(`${name} must be a non-empty string`);
@@ -7847,28 +8321,28 @@ var GitCli = class extends MountCli {
7847
8321
  if (options.readOnly && (options.publish || options.workspace !== void 0) || options.publish && options.workspace !== void 0) {
7848
8322
  throw new TypeError("readOnly, publish, and workspace are mutually exclusive");
7849
8323
  }
7850
- const path3 = (0, import_node_path4.resolve)(localPath);
8324
+ const path4 = (0, import_node_path5.resolve)(localPath);
7851
8325
  const args = ["mount"];
7852
8326
  if (options.readOnly) args.push("--ro");
7853
8327
  if (options.publish) args.push("--publish");
7854
8328
  if (options.workspace !== void 0) args.push(`--workspace=${options.workspace}`);
7855
- args.push("--", target, path3);
8329
+ args.push("--", target, path4);
7856
8330
  await this.run(args);
7857
- return new RepositoryMount(this, target, path3, options.readOnly ?? false);
8331
+ return new RepositoryMount(this, target, path4, options.readOnly ?? false);
7858
8332
  }
7859
8333
  async unmount(localPath, options = {}) {
7860
8334
  requireNonEmpty(localPath, "localPath");
7861
8335
  const args = ["unmount"];
7862
8336
  if (options.deleteWorkspace) args.push("--delete");
7863
8337
  if (options.discard) args.push("--discard");
7864
- args.push("--", (0, import_node_path4.resolve)(localPath));
8338
+ args.push("--", (0, import_node_path5.resolve)(localPath));
7865
8339
  await this.run(args);
7866
8340
  }
7867
8341
  async status(localPath) {
7868
8342
  const args = ["status", "--json"];
7869
8343
  if (localPath !== void 0) {
7870
8344
  requireNonEmpty(localPath, "localPath");
7871
- args.push("--", (0, import_node_path4.resolve)(localPath));
8345
+ args.push("--", (0, import_node_path5.resolve)(localPath));
7872
8346
  }
7873
8347
  const output = await this.run(args, 6e4);
7874
8348
  let raw;
@@ -7883,7 +8357,7 @@ var GitCli = class extends MountCli {
7883
8357
  }
7884
8358
  const stringField = (key) => typeof raw[key] === "string" ? raw[key] : null;
7885
8359
  return {
7886
- path: stringField("mountpoint") ?? (localPath === void 0 ? "" : (0, import_node_path4.resolve)(localPath)),
8360
+ path: stringField("mountpoint") ?? (localPath === void 0 ? "" : (0, import_node_path5.resolve)(localPath)),
7887
8361
  repository: stringField("repository"),
7888
8362
  reference: stringField("reference"),
7889
8363
  workspaceId: stringField("workspace"),
@@ -7892,44 +8366,44 @@ var GitCli = class extends MountCli {
7892
8366
  raw
7893
8367
  };
7894
8368
  }
7895
- async snapshot(path3, message) {
8369
+ async snapshot(path4, message) {
7896
8370
  const args = ["snapshot"];
7897
8371
  if (message !== void 0) args.push(`--message=${message}`);
7898
- args.push("--", path3);
8372
+ args.push("--", path4);
7899
8373
  await this.run(args);
7900
8374
  }
7901
- async sync(path3, target) {
7902
- const args = ["sync", "--", path3];
8375
+ async sync(path4, target) {
8376
+ const args = ["sync", "--", path4];
7903
8377
  if (target !== void 0) {
7904
8378
  requireNonEmpty(target, "target");
7905
8379
  args.push(target);
7906
8380
  }
7907
8381
  await this.run(args);
7908
8382
  }
7909
- async rebase(path3, target, failOnConflict) {
8383
+ async rebase(path4, target, failOnConflict) {
7910
8384
  requireNonEmpty(target, "target");
7911
8385
  const args = ["rebase"];
7912
8386
  if (failOnConflict) args.push("--fail-on-conflict");
7913
- args.push("--", path3, target);
8387
+ args.push("--", path4, target);
7914
8388
  await this.run(args);
7915
8389
  }
7916
- async promote(path3, branch, merge) {
8390
+ async promote(path4, branch, merge) {
7917
8391
  requireNonEmpty(branch, "branch");
7918
8392
  const args = ["promote"];
7919
8393
  if (merge) args.push("--merge");
7920
- args.push("--", path3, branch);
8394
+ args.push("--", path4, branch);
7921
8395
  await this.run(args);
7922
8396
  }
7923
- async prefetch(path3) {
7924
- await this.run(["prefetch", "--", path3]);
8397
+ async prefetch(path4) {
8398
+ await this.run(["prefetch", "--", path4]);
7925
8399
  }
7926
8400
  };
7927
8401
  var RepositoryMount = class {
7928
8402
  /** @internal Obtain instances via RepositoryClient.mount(). */
7929
- constructor(cli, target, path3, readOnly) {
8403
+ constructor(cli, target, path4, readOnly) {
7930
8404
  this.cli = cli;
7931
8405
  this.target = target;
7932
- this.path = path3;
8406
+ this.path = path4;
7933
8407
  this.readOnly = readOnly;
7934
8408
  }
7935
8409
  /** Inspect workspace state, pending changes, and daemon diagnostics. */
@@ -8164,6 +8638,7 @@ function validateTimeoutMs2(timeoutMs) {
8164
8638
 
8165
8639
  // src/index.ts
8166
8640
  init_sandbox_image();
8641
+ init_image_builds();
8167
8642
 
8168
8643
  // src/file-system.ts
8169
8644
  init_cjs_shims();
@@ -9547,38 +10022,38 @@ init_cjs_shims();
9547
10022
  var import_node_crypto4 = require("crypto");
9548
10023
  var textEncoder = new TextEncoder();
9549
10024
  var textDecoder = new TextDecoder("utf-8", { fatal: true });
9550
- function assertJSONValue(value, path3, seen) {
10025
+ function assertJSONValue(value, path4, seen) {
9551
10026
  if (value === null || typeof value === "string" || typeof value === "boolean") return;
9552
10027
  if (typeof value === "number") {
9553
- if (!Number.isFinite(value)) throw new SerializationError(`${path3} contains a non-finite number`);
10028
+ if (!Number.isFinite(value)) throw new SerializationError(`${path4} contains a non-finite number`);
9554
10029
  return;
9555
10030
  }
9556
10031
  if (typeof value !== "object") {
9557
- throw new SerializationError(`${path3} contains unsupported ${typeof value}`);
10032
+ throw new SerializationError(`${path4} contains unsupported ${typeof value}`);
9558
10033
  }
9559
10034
  if (isFile(value)) {
9560
- throw new SerializationError(`${path3} contains a nested File; File is only supported as a direct value`);
10035
+ throw new SerializationError(`${path4} contains a nested File; File is only supported as a direct value`);
9561
10036
  }
9562
10037
  if (isHttpBody(value)) {
9563
10038
  throw new SerializationError(
9564
- `${path3} contains a nested HttpBody; HttpBody is only supported as a direct value`
10039
+ `${path4} contains a nested HttpBody; HttpBody is only supported as a direct value`
9565
10040
  );
9566
10041
  }
9567
- if (seen.has(value)) throw new SerializationError(`${path3} contains a cycle`);
10042
+ if (seen.has(value)) throw new SerializationError(`${path4} contains a cycle`);
9568
10043
  if (Object.getPrototypeOf(value) !== Object.prototype && !Array.isArray(value)) {
9569
- throw new SerializationError(`${path3} contains unsupported ${value.constructor?.name ?? "object"}`);
10044
+ throw new SerializationError(`${path4} contains unsupported ${value.constructor?.name ?? "object"}`);
9570
10045
  }
9571
10046
  seen.add(value);
9572
10047
  if (Array.isArray(value)) {
9573
10048
  for (let index = 0; index < value.length; index += 1) {
9574
10049
  if (!Object.prototype.hasOwnProperty.call(value, index)) {
9575
- throw new SerializationError(`${path3} contains a sparse array entry at index ${index}`);
10050
+ throw new SerializationError(`${path4} contains a sparse array entry at index ${index}`);
9576
10051
  }
9577
- assertJSONValue(value[index], `${path3}[${index}]`, seen);
10052
+ assertJSONValue(value[index], `${path4}[${index}]`, seen);
9578
10053
  }
9579
10054
  } else {
9580
10055
  for (const [key, item] of Object.entries(value)) {
9581
- assertJSONValue(item, `${path3}.${key}`, seen);
10056
+ assertJSONValue(item, `${path4}.${key}`, seen);
9582
10057
  }
9583
10058
  }
9584
10059
  seen.delete(value);
@@ -10028,7 +10503,15 @@ init_models();
10028
10503
  Headers,
10029
10504
  HttpBody,
10030
10505
  Image,
10506
+ ImageBuildCancelledError,
10507
+ ImageBuildError,
10508
+ ImageBuildFailedError,
10509
+ ImageBuildHandle,
10510
+ ImageBuildInProgressError,
10511
+ ImageBuildInterruptedError,
10512
+ ImageBuildNotFoundError,
10031
10513
  ImageBuildOperationType,
10514
+ ImageBuildTimeoutError,
10032
10515
  MountError,
10033
10516
  OutputMode,
10034
10517
  PendingSandbox,
@@ -10061,12 +10544,14 @@ init_models();
10061
10544
  TERMINATION_REASON_CANCELLED,
10062
10545
  TERMINATION_REASON_NO_CAPACITY,
10063
10546
  TcpTunnel,
10547
+ cancelImageBuild,
10064
10548
  createFileSystem,
10065
10549
  createSandboxImage,
10066
10550
  deleteFileSystem,
10067
10551
  deleteSandboxImage,
10068
10552
  dockerfileContent,
10069
10553
  findSandboxImageByName,
10554
+ getImageBuild,
10070
10555
  importSandboxImage,
10071
10556
  isSandboxPending,
10072
10557
  listFileSystems,
@@ -10078,6 +10563,9 @@ init_models();
10078
10563
  runLocal,
10079
10564
  runRemote,
10080
10565
  sandboxUrlFromIngressEndpoint,
10081
- schema
10566
+ schema,
10567
+ startImageBuild,
10568
+ startImageImport,
10569
+ waitImageBuild
10082
10570
  });
10083
10571
  //# sourceMappingURL=index.cjs.map