@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.js CHANGED
@@ -46,7 +46,7 @@ var init_defaults = __esm({
46
46
  "src/defaults.ts"() {
47
47
  "use strict";
48
48
  init_esm_shims();
49
- SDK_VERSION = "0.5.152";
49
+ SDK_VERSION = "0.5.153";
50
50
  API_URL = process.env.TENSORLAKE_API_URL ?? "https://api.tensorlake.ai";
51
51
  API_KEY = process.env.TENSORLAKE_API_KEY ?? void 0;
52
52
  NAMESPACE = process.env.INDEXIFY_NAMESPACE ?? "default";
@@ -495,7 +495,7 @@ var init_native_worker_client = __esm({
495
495
  }
496
496
  };
497
497
  runtimeKey = /* @__PURE__ */ Symbol.for(
498
- `tensorlake.native.worker.${false ? "source" : "0.5.152"}.v1`
498
+ `tensorlake.native.worker.${false ? "source" : "0.5.153"}.v1`
499
499
  );
500
500
  runtimes = globalThis;
501
501
  }
@@ -595,6 +595,8 @@ var init_models = __esm({
595
595
  SnapshotStatus2["LOCAL_READY"] = "local_ready";
596
596
  SnapshotStatus2["COMPLETED"] = "completed";
597
597
  SnapshotStatus2["FAILED"] = "failed";
598
+ SnapshotStatus2["DELETING"] = "deleting";
599
+ SnapshotStatus2["REPLICATING"] = "replicating";
598
600
  return SnapshotStatus2;
599
601
  })(SnapshotStatus || {});
600
602
  ProcessStatus = /* @__PURE__ */ ((ProcessStatus2) => {
@@ -3883,9 +3885,8 @@ var init_sandbox = __esm({
3883
3885
  *
3884
3886
  * Resource targets use create's cpus, memoryMb, and diskMb names. Resize
3885
3887
  * waits by default; wait=false returns admission. Timeout does not cancel it.
3886
- * CPU-only CAS sandboxes support CPU, memory, and root-disk resize; GPU CAS sandboxes
3887
- * support only root-disk growth and reject CPU and memory changes.
3888
- * Non-CAS sandboxes do not support live resize.
3888
+ * Which runtimes and dimensions support a live resize is decided by the
3889
+ * server, whose policy error is thrown unchanged.
3889
3890
  * Wait, timeout, and pollInterval are ignored on non-resource updates.
3890
3891
  * A no-op returns current resources with absent or earlier resize metadata.
3891
3892
  *
@@ -4303,29 +4304,29 @@ var init_sandbox = __esm({
4303
4304
  }
4304
4305
  // --- File operations ---
4305
4306
  /** Read a file from the sandbox and return its raw bytes. */
4306
- async readFile(path4) {
4307
+ async readFile(path5) {
4307
4308
  const proxy = await this.proxy.client();
4308
- const { traceId, data } = await callNative(() => proxy.readFile(path4), {
4309
+ const { traceId, data } = await callNative(() => proxy.readFile(path5), {
4309
4310
  sandboxId: this.sandboxId
4310
4311
  });
4311
4312
  return Object.assign(Uint8Array.from(data), { traceId });
4312
4313
  }
4313
4314
  /** Write raw bytes to a file in the sandbox, creating it if it does not exist. */
4314
- async writeFile(path4, content) {
4315
+ async writeFile(path5, content) {
4315
4316
  const proxy = await this.proxy.client();
4316
- await callNative(() => proxy.writeFile(path4, Buffer.from(content)), {
4317
+ await callNative(() => proxy.writeFile(path5, Buffer.from(content)), {
4317
4318
  sandboxId: this.sandboxId
4318
4319
  });
4319
4320
  }
4320
4321
  /** Delete a file from the sandbox. */
4321
- async deleteFile(path4) {
4322
+ async deleteFile(path5) {
4322
4323
  const proxy = await this.proxy.client();
4323
- await callNative(() => proxy.deleteFile(path4), { sandboxId: this.sandboxId });
4324
+ await callNative(() => proxy.deleteFile(path5), { sandboxId: this.sandboxId });
4324
4325
  }
4325
4326
  /** List the contents of a directory in the sandbox. */
4326
- async listDirectory(path4) {
4327
+ async listDirectory(path5) {
4327
4328
  const proxy = await this.proxy.client();
4328
- const { traceId, json } = await callNative(() => proxy.listDirectory(path4), {
4329
+ const { traceId, json } = await callNative(() => proxy.listDirectory(path5), {
4329
4330
  sandboxId: this.sandboxId
4330
4331
  });
4331
4332
  return Object.assign(fromSnakeKeys(JSON.parse(json)), {
@@ -4991,9 +4992,9 @@ var init_client = __esm({
4991
4992
  });
4992
4993
  }
4993
4994
  /**
4994
- * Update properties or resize a running sandbox. CPU-only CAS sandboxes support
4995
- * CPU, memory, and root-disk resize; GPU CAS sandboxes support only root-disk
4996
- * growth. Non-CAS sandboxes do not support live resize.
4995
+ * Update properties or resize a running sandbox. Which runtimes and
4996
+ * dimensions support a live resize is decided by the server, whose policy
4997
+ * error is thrown unchanged.
4997
4998
  * Resource names match create. Resize waits by default; wait=false returns
4998
4999
  * admission. Timeout leaves the resize running and reports its generation.
4999
5000
  * Wait, timeout, and pollInterval are ignored on non-resource updates.
@@ -5312,6 +5313,11 @@ var init_client = __esm({
5312
5313
  `Snapshot ${result.snapshotId} failed: ${info.error}`
5313
5314
  );
5314
5315
  }
5316
+ if (info.status === "deleting" /* DELETING */) {
5317
+ throw new SandboxError(
5318
+ `Snapshot ${result.snapshotId} is being deleted`
5319
+ );
5320
+ }
5315
5321
  await sleep2(pollInterval * 1e3);
5316
5322
  }
5317
5323
  throw new SandboxError(
@@ -5569,585 +5575,6 @@ var init_client = __esm({
5569
5575
  }
5570
5576
  });
5571
5577
 
5572
- // src/native-cloud.ts
5573
- async function serializeRequest(method, path4, options) {
5574
- const headers = { ...options?.headers };
5575
- let body = options?.body;
5576
- if (options?.json !== void 0) {
5577
- body = JSON.stringify(options.json);
5578
- if (!Object.keys(headers).some((key) => key.toLowerCase() === "content-type")) {
5579
- headers["Content-Type"] = "application/json";
5580
- }
5581
- }
5582
- const request = {
5583
- method,
5584
- path: path4,
5585
- headersJson: JSON.stringify(headers),
5586
- statusOnlyCodes: [...options?.statusOnlyCodes ?? []]
5587
- };
5588
- if (body instanceof FormData) {
5589
- request.parts = [];
5590
- for (const [name, value] of body.entries()) {
5591
- 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" });
5592
- }
5593
- } else if (body !== void 0) {
5594
- if (body instanceof Blob) request.body = Buffer.from(await body.arrayBuffer());
5595
- else if (typeof body === "string") request.body = Buffer.from(body);
5596
- else if (body instanceof ArrayBuffer) request.body = Buffer.from(new Uint8Array(body));
5597
- else request.body = Buffer.from(body);
5598
- }
5599
- return request;
5600
- }
5601
- var NativeCloudTransport;
5602
- var init_native_cloud = __esm({
5603
- "src/native-cloud.ts"() {
5604
- "use strict";
5605
- init_esm_shims();
5606
- init_native_sandbox();
5607
- init_native_worker_client();
5608
- NativeCloudTransport = class {
5609
- constructor(options) {
5610
- this.options = options;
5611
- if (!Number.isSafeInteger(options.maxRetries) || options.maxRetries < 0 || options.maxRetries > 4294967295) {
5612
- throw new RangeError("maxRetries must be a non-negative 32-bit integer");
5613
- }
5614
- if (!Number.isFinite(options.retryBackoffMs) || options.retryBackoffMs < 0) {
5615
- throw new RangeError("retryBackoffMs must be a non-negative finite number");
5616
- }
5617
- }
5618
- native;
5619
- closed = false;
5620
- client() {
5621
- if (this.closed) throw new Error("Tensorlake native client is closed");
5622
- if (this.native) return this.native;
5623
- const ctor = loadNativeSandboxBinding().NativeCloudClient;
5624
- if (!ctor) throw new Error("Native binding does not export NativeCloudClient; rebuild with 'npm run build:native'");
5625
- return this.native = new ctor(JSON.stringify(this.options));
5626
- }
5627
- close() {
5628
- this.closed = true;
5629
- releaseNativeHandle(this.native ?? null);
5630
- this.native = void 0;
5631
- }
5632
- async requestResponse(method, path4, options) {
5633
- const request = await serializeRequest(method, path4, options);
5634
- const raw = await callNative(() => this.client().request(request));
5635
- const response = new Response(
5636
- [204, 205, 304].includes(raw.status) ? null : Uint8Array.from(raw.data).buffer,
5637
- { status: raw.status, headers: JSON.parse(raw.headersJson) }
5638
- );
5639
- return Object.assign(response, { traceId: raw.traceId });
5640
- }
5641
- async requestJson(method, path4) {
5642
- const response = await this.requestResponse(method, path4);
5643
- const text = await response.text();
5644
- const value = text ? JSON.parse(text) : null;
5645
- return Object.assign(value ?? {}, { traceId: response.traceId });
5646
- }
5647
- async *stream(method, path4, signal) {
5648
- if (signal?.aborted) return;
5649
- const request = await serializeRequest(method, path4, { headers: { Accept: "text/event-stream" } });
5650
- yield* nativeEventStream((emit) => this.client().stream(request, emit), void 0, signal);
5651
- }
5652
- };
5653
- }
5654
- });
5655
-
5656
- // src/cloud-client.ts
5657
- import { nanoid } from "nanoid";
5658
- function secretFromMetadata(metadata) {
5659
- return {
5660
- id: metadata.id,
5661
- name: metadata.name,
5662
- createdAt: new Date(metadata.created_at_ms)
5663
- };
5664
- }
5665
- function applicationAllowsUnauthenticatedRequests(manifest) {
5666
- return Array.isArray(manifest.allow) && manifest.allow.includes(UNAUTHENTICATED_REQUESTS);
5667
- }
5668
- function publicEndpointIdFromManifest(manifest) {
5669
- for (const key of ["public_endpoint_id", "publicEndpointId"]) {
5670
- const value = manifest[key];
5671
- if (typeof value === "string" && value.length > 0) {
5672
- return value;
5673
- }
5674
- }
5675
- return void 0;
5676
- }
5677
- function generatePublicEndpointId() {
5678
- return `endpoint_${nanoid()}`;
5679
- }
5680
- function createApplicationBuildForm(request, imageContexts) {
5681
- const contextsByPartName = /* @__PURE__ */ new Map();
5682
- for (const context of imageContexts) {
5683
- if (contextsByPartName.has(context.contextTarPartName)) {
5684
- throw new Error(
5685
- `duplicate image context part name '${context.contextTarPartName}'`
5686
- );
5687
- }
5688
- contextsByPartName.set(context.contextTarPartName, context);
5689
- }
5690
- const form = new FormData();
5691
- form.append(
5692
- "app_version",
5693
- new Blob([JSON.stringify(request)], { type: "application/json" }),
5694
- "app_version"
5695
- );
5696
- for (const image of request.images) {
5697
- const context = contextsByPartName.get(image.contextTarPartName);
5698
- if (!context) {
5699
- throw new Error(
5700
- `missing image context for part '${image.contextTarPartName}'`
5701
- );
5702
- }
5703
- form.append(
5704
- image.contextTarPartName,
5705
- new Blob([toBlobPart(context.contextTarGz)]),
5706
- `${image.contextTarPartName}.tar.gz`
5707
- );
5708
- }
5709
- for (const context of imageContexts) {
5710
- if (!request.images.some((image) => image.contextTarPartName === context.contextTarPartName)) {
5711
- throw new Error(
5712
- `unexpected image context for part '${context.contextTarPartName}'`
5713
- );
5714
- }
5715
- }
5716
- return form;
5717
- }
5718
- function trimTrailingSlashes2(value) {
5719
- return value.endsWith("/") ? value.slice(0, -1) : value;
5720
- }
5721
- function nextRequestPath(next) {
5722
- const schemeIndex = next.indexOf("://");
5723
- if (schemeIndex !== -1) {
5724
- const afterScheme = next.slice(schemeIndex + 3);
5725
- const slashIndex = afterScheme.indexOf("/");
5726
- return slashIndex === -1 ? "/" : afterScheme.slice(slashIndex);
5727
- }
5728
- return next.startsWith("/") ? next : `/${next}`;
5729
- }
5730
- function toBlobPart(data) {
5731
- if (typeof data === "string" || data instanceof Blob) {
5732
- return data;
5733
- }
5734
- if (data instanceof Uint8Array) {
5735
- return Uint8Array.from(data).buffer;
5736
- }
5737
- return data;
5738
- }
5739
- function toRequestBody(data) {
5740
- return toBlobPart(data);
5741
- }
5742
- async function parseJsonResponse(response) {
5743
- const text = await response.text();
5744
- if (!text) {
5745
- return void 0;
5746
- }
5747
- return JSON.parse(text);
5748
- }
5749
- var CloudClient, UNAUTHENTICATED_REQUESTS;
5750
- var init_cloud_client = __esm({
5751
- "src/cloud-client.ts"() {
5752
- "use strict";
5753
- init_esm_shims();
5754
- init_defaults();
5755
- init_native_cloud();
5756
- init_models();
5757
- CloudClient = class _CloudClient {
5758
- transport;
5759
- organizationId;
5760
- projectId;
5761
- namespace;
5762
- constructor(options) {
5763
- this.organizationId = options?.organizationId;
5764
- this.projectId = options?.projectId;
5765
- this.namespace = options?.namespace ?? NAMESPACE;
5766
- this.transport = new NativeCloudTransport({
5767
- baseUrl: options?.apiUrl ?? API_URL,
5768
- apiKey: options?.apiKey ?? API_KEY,
5769
- organizationId: this.organizationId,
5770
- projectId: this.projectId,
5771
- maxRetries: options?.maxRetries ?? MAX_RETRIES,
5772
- retryBackoffMs: options?.retryBackoffMs ?? RETRY_BACKOFF_MS,
5773
- timeoutMs: DEFAULT_HTTP_TIMEOUT_MS,
5774
- userAgent: `tensorlake-typescript-sdk/${SDK_VERSION}`
5775
- });
5776
- }
5777
- static forCloud(options) {
5778
- return new _CloudClient(options);
5779
- }
5780
- close() {
5781
- this.transport.close();
5782
- }
5783
- async upsertApplication(manifest, codeZip, upgradeRunningRequests = false) {
5784
- const applicationManifest = { ...manifest };
5785
- let publicEndpointId = publicEndpointIdFromManifest(applicationManifest);
5786
- if (applicationAllowsUnauthenticatedRequests(applicationManifest) && publicEndpointId === void 0) {
5787
- const applicationName = applicationManifest.name;
5788
- if (typeof applicationName === "string" && applicationName.length > 0) {
5789
- publicEndpointId = await this.existingApplicationPublicEndpointId(applicationName);
5790
- }
5791
- publicEndpointId ??= generatePublicEndpointId();
5792
- }
5793
- if (publicEndpointId !== void 0) {
5794
- applicationManifest.public_endpoint_id = publicEndpointId;
5795
- delete applicationManifest.publicEndpointId;
5796
- }
5797
- const form = new FormData();
5798
- form.append(
5799
- "code",
5800
- new Blob([toBlobPart(codeZip)], { type: "application/zip" }),
5801
- "code.zip"
5802
- );
5803
- form.append("code_content_type", "application/zip");
5804
- form.append("application", JSON.stringify(applicationManifest));
5805
- form.append(
5806
- "upgrade_requests_to_latest_code",
5807
- String(upgradeRunningRequests)
5808
- );
5809
- await this.transport.requestResponse("POST", this.namespacePath("applications"), {
5810
- body: form
5811
- });
5812
- }
5813
- async deleteApplication(applicationName) {
5814
- await this.transport.requestResponse(
5815
- "DELETE",
5816
- this.namespacePath(`applications/${encodeURIComponent(applicationName)}`)
5817
- );
5818
- }
5819
- async deleteSandboxImage(imageName) {
5820
- await this.transport.requestResponse(
5821
- "DELETE",
5822
- this.namespacePath(`sandbox-images/${encodeURIComponent(imageName)}`)
5823
- );
5824
- }
5825
- /**
5826
- * Look up a registered sandbox image (template) by its registered name.
5827
- *
5828
- * Returns the template, or `null` when no image with that name exists.
5829
- * API-key clients may omit organization/project IDs and use the
5830
- * token-scoped Platform API route directly. Explicit scope remains
5831
- * available for PAT callers.
5832
- */
5833
- async findSandboxImageByName(imageName, options) {
5834
- const base = this.platformProjectPath(
5835
- "sandbox-templates",
5836
- options?.organizationId,
5837
- options?.projectId
5838
- );
5839
- const response = await this.transport.requestResponse(
5840
- "GET",
5841
- `${base}/by-name/${encodeURIComponent(imageName)}`,
5842
- { statusOnlyCodes: /* @__PURE__ */ new Set([404]) }
5843
- );
5844
- if (response.status === 404) {
5845
- return null;
5846
- }
5847
- const raw = await parseJsonResponse(response);
5848
- return fromSnakeKeys(raw);
5849
- }
5850
- /**
5851
- * List all registered sandbox images (templates), following pagination to
5852
- * the end. API-key clients may omit organization/project IDs and use the
5853
- * token-scoped Platform API route directly.
5854
- */
5855
- async listSandboxImages(options) {
5856
- const base = this.platformProjectPath(
5857
- "sandbox-templates",
5858
- options?.organizationId,
5859
- options?.projectId
5860
- );
5861
- let path4 = `${base}?pageSize=100`;
5862
- const templates = [];
5863
- while (path4 !== null) {
5864
- const page = await this.transport.requestJson(
5865
- "GET",
5866
- path4
5867
- );
5868
- for (const item of page.items ?? []) {
5869
- templates.push(fromSnakeKeys(item));
5870
- }
5871
- const next = page.pagination?.next;
5872
- path4 = next ? nextRequestPath(next) : null;
5873
- }
5874
- return templates;
5875
- }
5876
- async applications() {
5877
- const raw = await this.transport.requestJson(
5878
- "GET",
5879
- this.namespacePath("applications")
5880
- );
5881
- return (raw.applications ?? []).map(
5882
- (application) => fromSnakeKeys(application)
5883
- );
5884
- }
5885
- async applicationManifest(applicationName) {
5886
- const raw = await this.transport.requestJson(
5887
- "GET",
5888
- this.namespacePath(`applications/${encodeURIComponent(applicationName)}`)
5889
- );
5890
- return fromSnakeKeys(raw);
5891
- }
5892
- async runRequest(applicationName, inputs = []) {
5893
- const path4 = this.namespacePath(
5894
- `applications/${encodeURIComponent(applicationName)}`
5895
- );
5896
- const response = inputs.length === 0 ? await this.transport.requestResponse("POST", path4, {
5897
- body: new Uint8Array(),
5898
- headers: { Accept: "application/json" }
5899
- }) : inputs.length === 1 && inputs[0].name === "0" ? await this.transport.requestResponse("POST", path4, {
5900
- body: toRequestBody(inputs[0].data),
5901
- headers: {
5902
- Accept: "application/json",
5903
- "Content-Type": inputs[0].contentType
5904
- }
5905
- }) : await this.runMultipartRequest(path4, inputs);
5906
- const body = await parseJsonResponse(response);
5907
- const requestId = body?.request_id;
5908
- if (!requestId) {
5909
- throw new Error("missing request_id in run request response body");
5910
- }
5911
- return requestId;
5912
- }
5913
- async waitOnRequestCompletion(applicationName, requestId) {
5914
- const stream = this.transport.stream(
5915
- "GET",
5916
- this.namespacePath(
5917
- `applications/${encodeURIComponent(applicationName)}/requests/${encodeURIComponent(requestId)}/progress`
5918
- )
5919
- );
5920
- for await (const event of stream) {
5921
- if (Object.prototype.hasOwnProperty.call(event, "RequestFinished")) {
5922
- return;
5923
- }
5924
- }
5925
- throw new Error("progress stream ended before request completion");
5926
- }
5927
- async requestMetadata(applicationName, requestId) {
5928
- const raw = await this.transport.requestJson(
5929
- "GET",
5930
- this.namespacePath(
5931
- `applications/${encodeURIComponent(applicationName)}/requests/${encodeURIComponent(requestId)}`
5932
- )
5933
- );
5934
- return fromSnakeKeys(raw);
5935
- }
5936
- async requestOutput(applicationName, requestId) {
5937
- const response = await this.transport.requestResponse(
5938
- "GET",
5939
- this.namespacePath(
5940
- `applications/${encodeURIComponent(applicationName)}/requests/${encodeURIComponent(requestId)}/output`
5941
- )
5942
- );
5943
- const serializedValue = new Uint8Array(await response.arrayBuffer());
5944
- const contentType = response.headers.get("content-type") ?? "";
5945
- return {
5946
- serializedValue,
5947
- contentType
5948
- };
5949
- }
5950
- async listSecrets(options) {
5951
- const base = this.secretCollectionPath(
5952
- options?.organizationId,
5953
- options?.projectId
5954
- );
5955
- const raw = await this.transport.requestJson("GET", base);
5956
- const pageSize = Math.max(0, options?.pageSize ?? 100);
5957
- return Object.assign(
5958
- {
5959
- items: raw.slice(0, pageSize).map(secretFromMetadata),
5960
- pagination: { total: raw.length }
5961
- },
5962
- { traceId: raw.traceId }
5963
- );
5964
- }
5965
- async getSecret(secretId, options) {
5966
- const base = this.secretCollectionPath(
5967
- options?.organizationId,
5968
- options?.projectId
5969
- );
5970
- const raw = await this.transport.requestJson(
5971
- "GET",
5972
- `${base}/${encodeURIComponent(secretId)}`
5973
- );
5974
- return Object.assign(secretFromMetadata(raw), { traceId: raw.traceId });
5975
- }
5976
- async upsertSecrets(secrets, options) {
5977
- const base = this.secretCollectionPath(
5978
- options?.organizationId,
5979
- options?.projectId
5980
- );
5981
- if (Array.isArray(secrets)) {
5982
- const results = [];
5983
- for (const secret of secrets) {
5984
- results.push(await this.upsertSecret(base, secret));
5985
- }
5986
- return results;
5987
- }
5988
- return this.upsertSecret(base, secrets);
5989
- }
5990
- async deleteSecret(secretId, options) {
5991
- const base = this.secretCollectionPath(
5992
- options?.organizationId,
5993
- options?.projectId
5994
- );
5995
- await this.transport.requestResponse(
5996
- "DELETE",
5997
- `${base}/${encodeURIComponent(secretId)}`
5998
- );
5999
- }
6000
- async upsertSecret(base, secret) {
6001
- let response = await this.transport.requestResponse("POST", base, {
6002
- json: secret,
6003
- headers: { "Idempotency-Key": nanoid() },
6004
- statusOnlyCodes: /* @__PURE__ */ new Set([409])
6005
- });
6006
- if (response.status === 409) {
6007
- const prefix = base.slice(0, -"/secrets".length);
6008
- const existing = await this.transport.requestJson(
6009
- "GET",
6010
- `${prefix}/secret-names/${encodeURIComponent(secret.name)}`
6011
- );
6012
- response = await this.transport.requestResponse(
6013
- "POST",
6014
- `${base}/${encodeURIComponent(existing.id)}/versions`,
6015
- {
6016
- json: { value: secret.value },
6017
- headers: { "Idempotency-Key": nanoid() }
6018
- }
6019
- );
6020
- }
6021
- const metadata = await parseJsonResponse(response);
6022
- return Object.assign(secretFromMetadata(metadata), {
6023
- traceId: response.traceId
6024
- });
6025
- }
6026
- async startImageBuild(buildServicePath, request) {
6027
- const form = new FormData();
6028
- form.append("graph_name", request.applicationName);
6029
- form.append("graph_version", request.applicationVersion);
6030
- form.append("graph_function_name", request.functionName);
6031
- form.append("image_name", request.imageName);
6032
- form.append("image_id", request.imageId);
6033
- form.append(
6034
- "context",
6035
- new Blob([toBlobPart(request.buildContext)]),
6036
- "context.tar.gz"
6037
- );
6038
- const response = await this.transport.requestResponse(
6039
- "PUT",
6040
- `${trimTrailingSlashes2(buildServicePath)}/builds`,
6041
- { body: form }
6042
- );
6043
- const raw = await parseJsonResponse(response);
6044
- return fromSnakeKeys(raw);
6045
- }
6046
- async createApplicationBuild(buildServicePath, request, imageContexts) {
6047
- const form = createApplicationBuildForm(request, imageContexts);
6048
- const response = await this.transport.requestResponse(
6049
- "POST",
6050
- trimTrailingSlashes2(buildServicePath),
6051
- { body: form }
6052
- );
6053
- const raw = await parseJsonResponse(response);
6054
- return fromSnakeKeys(raw);
6055
- }
6056
- async applicationBuildInfo(buildServicePath, applicationBuildId) {
6057
- const raw = await this.transport.requestJson(
6058
- "GET",
6059
- `${trimTrailingSlashes2(buildServicePath)}/${encodeURIComponent(applicationBuildId)}`
6060
- );
6061
- return fromSnakeKeys(raw);
6062
- }
6063
- async cancelApplicationBuild(buildServicePath, applicationBuildId) {
6064
- const raw = await this.transport.requestJson(
6065
- "POST",
6066
- `${trimTrailingSlashes2(buildServicePath)}/${encodeURIComponent(applicationBuildId)}/cancel`
6067
- );
6068
- return fromSnakeKeys(raw);
6069
- }
6070
- async buildInfo(buildServicePath, buildId) {
6071
- const raw = await this.transport.requestJson(
6072
- "GET",
6073
- `${trimTrailingSlashes2(buildServicePath)}/builds/${encodeURIComponent(buildId)}`
6074
- );
6075
- return fromSnakeKeys(raw);
6076
- }
6077
- async cancelBuild(buildServicePath, buildId) {
6078
- await this.transport.requestResponse(
6079
- "POST",
6080
- `${trimTrailingSlashes2(buildServicePath)}/builds/${encodeURIComponent(buildId)}/cancel`
6081
- );
6082
- }
6083
- async *streamBuildLogs(buildServicePath, buildId, signal) {
6084
- const stream = this.transport.stream(
6085
- "GET",
6086
- `${trimTrailingSlashes2(buildServicePath)}/builds/${encodeURIComponent(buildId)}/logs`,
6087
- signal
6088
- );
6089
- for await (const event of stream) {
6090
- yield fromSnakeKeys(event);
6091
- }
6092
- }
6093
- async runMultipartRequest(path4, inputs) {
6094
- const form = new FormData();
6095
- for (const input of inputs) {
6096
- form.append(
6097
- input.name,
6098
- new Blob([toBlobPart(input.data)], { type: input.contentType }),
6099
- input.name
6100
- );
6101
- }
6102
- return this.transport.requestResponse("POST", path4, {
6103
- body: form,
6104
- headers: { Accept: "application/json" }
6105
- });
6106
- }
6107
- namespacePath(subpath) {
6108
- return `/v1/namespaces/${encodeURIComponent(this.namespace)}/${subpath.replace(/^\/+/, "")}`;
6109
- }
6110
- async existingApplicationPublicEndpointId(applicationName) {
6111
- const response = await this.transport.requestResponse(
6112
- "GET",
6113
- this.namespacePath(`applications/${encodeURIComponent(applicationName)}`),
6114
- { statusOnlyCodes: /* @__PURE__ */ new Set([404]) }
6115
- );
6116
- if (response.status === 404) {
6117
- return void 0;
6118
- }
6119
- const application = await parseJsonResponse(response);
6120
- return publicEndpointIdFromManifest(application);
6121
- }
6122
- platformProjectPath(resource, organizationId, projectId) {
6123
- const resolvedOrganizationId = organizationId ?? this.organizationId;
6124
- const resolvedProjectId = projectId ?? this.projectId;
6125
- if (!resolvedOrganizationId && !resolvedProjectId) {
6126
- return `/platform/v1/${resource}`;
6127
- }
6128
- if (!resolvedOrganizationId || !resolvedProjectId) {
6129
- throw new Error(
6130
- "organizationId and projectId must be provided together"
6131
- );
6132
- }
6133
- return `/platform/v1/organizations/${encodeURIComponent(resolvedOrganizationId)}/projects/${encodeURIComponent(resolvedProjectId)}/${resource}`;
6134
- }
6135
- secretCollectionPath(organizationId, projectId) {
6136
- const resolvedOrganizationId = organizationId ?? this.organizationId;
6137
- const resolvedProjectId = projectId ?? this.projectId;
6138
- if (!resolvedOrganizationId && !resolvedProjectId) {
6139
- return this.namespacePath("secrets");
6140
- }
6141
- if (!resolvedOrganizationId || !resolvedProjectId) {
6142
- throw new Error("organizationId and projectId must be provided together");
6143
- }
6144
- return this.namespacePath("secrets");
6145
- }
6146
- };
6147
- UNAUTHENTICATED_REQUESTS = "unauthenticated_requests";
6148
- }
6149
- });
6150
-
6151
5578
  // src/image.ts
6152
5579
  import { randomUUID } from "crypto";
6153
5580
  function cloneOperation(op) {
@@ -6419,22 +5846,477 @@ var init_native_binding = __esm({
6419
5846
  }
6420
5847
  });
6421
5848
 
5849
+ // src/image-builds.ts
5850
+ import path3 from "path";
5851
+ import os from "os";
5852
+ import { existsSync as existsSync2, mkdtempSync, rmSync } from "fs";
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 = path3.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 = mkdtempSync(path3.join(os.tmpdir(), "tl-build-context-"));
6017
+ contextDir = tempContextDir;
6018
+ }
6019
+ dockerfilePath = path3.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 = path3.resolve(source);
6026
+ if (!existsSync2(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) 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 ImageBuildError, ImageBuildNotFoundError, ImageBuildInProgressError, ImageBuildFailedError, ImageBuildCancelledError, ImageBuildTimeoutError, ImageBuildInterruptedError, ImageBuildHandle;
6162
+ var init_image_builds = __esm({
6163
+ "src/image-builds.ts"() {
6164
+ "use strict";
6165
+ init_esm_shims();
6166
+ init_image();
6167
+ init_sandbox_image();
6168
+ ImageBuildError = class extends Error {
6169
+ code;
6170
+ buildId;
6171
+ clientRequestId;
6172
+ details;
6173
+ constructor(details) {
6174
+ super(details.message);
6175
+ this.name = "ImageBuildError";
6176
+ this.code = details.code;
6177
+ this.details = details;
6178
+ if (details.buildId) this.buildId = details.buildId;
6179
+ if (details.clientRequestId) this.clientRequestId = details.clientRequestId;
6180
+ }
6181
+ };
6182
+ ImageBuildNotFoundError = class extends ImageBuildError {
6183
+ constructor(details) {
6184
+ super(details);
6185
+ this.name = "ImageBuildNotFoundError";
6186
+ }
6187
+ };
6188
+ ImageBuildInProgressError = class extends ImageBuildError {
6189
+ imageName;
6190
+ activeBuildId;
6191
+ activeKind;
6192
+ activeStatus;
6193
+ constructor(details) {
6194
+ super(details);
6195
+ this.name = "ImageBuildInProgressError";
6196
+ if (details.imageName) this.imageName = details.imageName;
6197
+ if (details.activeBuildId) this.activeBuildId = details.activeBuildId;
6198
+ if (details.activeKind) this.activeKind = details.activeKind;
6199
+ if (details.activeStatus) this.activeStatus = details.activeStatus;
6200
+ }
6201
+ };
6202
+ ImageBuildFailedError = class extends ImageBuildError {
6203
+ error;
6204
+ info;
6205
+ constructor(details) {
6206
+ super(details);
6207
+ this.name = "ImageBuildFailedError";
6208
+ this.error = details.error ?? "no error recorded";
6209
+ if (details.info) this.info = parseBuildInfo(details.info);
6210
+ }
6211
+ };
6212
+ ImageBuildCancelledError = class extends ImageBuildError {
6213
+ info;
6214
+ constructor(details) {
6215
+ super(details);
6216
+ this.name = "ImageBuildCancelledError";
6217
+ if (details.info) this.info = parseBuildInfo(details.info);
6218
+ }
6219
+ };
6220
+ ImageBuildTimeoutError = class extends ImageBuildError {
6221
+ constructor(details) {
6222
+ super(details);
6223
+ this.name = "ImageBuildTimeoutError";
6224
+ }
6225
+ };
6226
+ ImageBuildInterruptedError = class extends ImageBuildError {
6227
+ outcome;
6228
+ confirmed;
6229
+ result;
6230
+ constructor(details) {
6231
+ super(details);
6232
+ this.name = "ImageBuildInterruptedError";
6233
+ this.outcome = details.outcome ?? "unconfirmed";
6234
+ this.confirmed = details.confirmed === true;
6235
+ if (details.result) this.result = details.result;
6236
+ }
6237
+ };
6238
+ ImageBuildHandle = class {
6239
+ buildId;
6240
+ /**
6241
+ * The admission's request id, when this handle started the build. Never
6242
+ * needed to cancel; a recovery aid for a lost admission answer.
6243
+ */
6244
+ clientRequestId;
6245
+ #info;
6246
+ #credentials;
6247
+ /** @internal */
6248
+ constructor(info, credentials, clientRequestId) {
6249
+ this.buildId = info.buildId;
6250
+ this.clientRequestId = clientRequestId ?? info.clientRequestId ?? null;
6251
+ this.#info = info;
6252
+ this.#credentials = credentials;
6253
+ }
6254
+ /** The last observed state. */
6255
+ get info() {
6256
+ return this.#info;
6257
+ }
6258
+ /** Re-read the current state. */
6259
+ async refresh() {
6260
+ const binding = __imageBuildInternals.loadNativeBinding();
6261
+ let json;
6262
+ try {
6263
+ json = await binding.getImageBuild(clientOptions(this.#credentials), this.buildId);
6264
+ } catch (error) {
6265
+ throw toImageBuildError(error);
6266
+ }
6267
+ this.#info = parseBuildInfo(JSON.parse(json));
6268
+ return this.#info;
6269
+ }
6270
+ /**
6271
+ * Wait for publication and return this build's immutable result. See
6272
+ * {@link ImageBuildWaitOptions} for the timeout/abort distinction.
6273
+ */
6274
+ async wait(options = {}) {
6275
+ const binding = __imageBuildInternals.loadNativeBinding();
6276
+ const emitter = makeEmitter(options);
6277
+ const json = await __runWithInterrupt(
6278
+ options.signal,
6279
+ (interruptId) => binding.waitImageBuild(
6280
+ clientOptions(this.#credentials),
6281
+ this.buildId,
6282
+ { timeoutMs: options.timeoutMs, followLogs: options.followLogs ?? false },
6283
+ emitter.forward,
6284
+ interruptId
6285
+ )
6286
+ );
6287
+ emitter.rethrow();
6288
+ const result = parseResult(json);
6289
+ this.#info = { ...this.#info, status: "succeeded", result };
6290
+ return result;
6291
+ }
6292
+ /** Cancel this build by its id (the sufficient selector). */
6293
+ async cancel() {
6294
+ return cancelImageBuildWith(this.#credentials, { buildId: this.buildId });
6295
+ }
6296
+ };
6297
+ }
6298
+ });
6299
+
6422
6300
  // src/sandbox-image.ts
6423
6301
  var sandbox_image_exports = {};
6424
6302
  __export(sandbox_image_exports, {
6303
+ __imageBuildInternals: () => __imageBuildInternals,
6425
6304
  __setNativeBindingForTest: () => __setNativeBindingForTest,
6426
6305
  buildContextFromEnv: () => buildContextFromEnv,
6427
6306
  createSandboxImage: () => createSandboxImage,
6428
6307
  deleteSandboxImage: () => deleteSandboxImage,
6308
+ deleteSandboxImageWithCredentials: () => deleteSandboxImageWithCredentials,
6429
6309
  findSandboxImageByName: () => findSandboxImageByName,
6310
+ findSandboxImageByNameWithCredentials: () => findSandboxImageByNameWithCredentials,
6430
6311
  importSandboxImage: () => importSandboxImage,
6431
6312
  listSandboxImages: () => listSandboxImages,
6313
+ listSandboxImagesWithCredentials: () => listSandboxImagesWithCredentials,
6432
6314
  runCreateSandboxImageCli: () => runCreateSandboxImageCli,
6433
6315
  runImportSandboxImageCli: () => runImportSandboxImageCli
6434
6316
  });
6435
- import path3 from "path";
6436
- import os from "os";
6437
- import { existsSync as existsSync2, mkdtempSync, rmSync } from "fs";
6317
+ import path4 from "path";
6318
+ import os2 from "os";
6319
+ import { existsSync as existsSync3, mkdtempSync as mkdtempSync2, rmSync as rmSync2 } from "fs";
6438
6320
  import { parseArgs } from "util";
6439
6321
  function loadNativeBinding() {
6440
6322
  if (cachedNativeBinding) return cachedNativeBinding;
@@ -6468,9 +6350,9 @@ function buildContextFromEnv() {
6468
6350
  };
6469
6351
  }
6470
6352
  function defaultRegisteredName(dockerfilePath) {
6471
- const parsed = path3.parse(dockerfilePath);
6353
+ const parsed = path4.parse(dockerfilePath);
6472
6354
  if (parsed.name.toLowerCase() === "dockerfile") {
6473
- const parentName = path3.basename(path3.dirname(dockerfilePath)).trim();
6355
+ const parentName = path4.basename(path4.dirname(dockerfilePath)).trim();
6474
6356
  return parentName || "sandbox-image";
6475
6357
  }
6476
6358
  return parsed.name || "sandbox-image";
@@ -6506,6 +6388,15 @@ function eventToEmitDict(event) {
6506
6388
  message: event.message
6507
6389
  };
6508
6390
  if (event.stream != null) out.stream = event.stream;
6391
+ if (event.buildId != null) out.build_id = event.buildId;
6392
+ if (event.clientRequestId !== void 0 && event.eventType !== "status") {
6393
+ out.client_request_id = event.clientRequestId;
6394
+ }
6395
+ if (event.status != null) out.status = event.status;
6396
+ if (event.phase !== void 0 && event.eventType.startsWith("build_")) out.phase = event.phase;
6397
+ if (event.attempt != null) out.attempt = event.attempt;
6398
+ if (event.outcome != null) out.outcome = event.outcome;
6399
+ if (event.confirmed != null) out.confirmed = event.confirmed;
6509
6400
  return out;
6510
6401
  }
6511
6402
  function runOpMountsContext(op) {
@@ -6560,24 +6451,24 @@ async function createSandboxImage(source, options = {}, deps = {}) {
6560
6451
  }
6561
6452
  let resolvedContext;
6562
6453
  if (options.contextDir != null) {
6563
- resolvedContext = path3.resolve(options.contextDir);
6454
+ resolvedContext = path4.resolve(options.contextDir);
6564
6455
  } else if (imageRequiresContext(source)) {
6565
6456
  throw new Error(
6566
6457
  "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>`."
6567
6458
  );
6568
6459
  } else {
6569
- tempContextDir = mkdtempSync(path3.join(os.tmpdir(), "tl-build-context-"));
6460
+ tempContextDir = mkdtempSync2(path4.join(os2.tmpdir(), "tl-build-context-"));
6570
6461
  resolvedContext = tempContextDir;
6571
6462
  }
6572
- dockerfilePath = path3.join(resolvedContext, "Dockerfile");
6463
+ dockerfilePath = path4.join(resolvedContext, "Dockerfile");
6573
6464
  let text = dockerfileContent(source);
6574
6465
  if (!text.endsWith("\n")) text += "\n";
6575
6466
  dockerfileText = text;
6576
6467
  nativeContextDir = resolvedContext;
6577
6468
  effectiveName = options.registeredName ?? source.name;
6578
6469
  } else if (typeof source === "string") {
6579
- const resolvedPath = path3.resolve(source);
6580
- if (!existsSync2(resolvedPath)) {
6470
+ const resolvedPath = path4.resolve(source);
6471
+ if (!existsSync3(resolvedPath)) {
6581
6472
  throw new Error(`Dockerfile not found: ${source}`);
6582
6473
  }
6583
6474
  dockerfilePath = resolvedPath;
@@ -6607,38 +6498,47 @@ async function createSandboxImage(source, options = {}, deps = {}) {
6607
6498
  deps._allowPat ? "Missing TENSORLAKE_API_KEY or TENSORLAKE_PAT credentials." : "Missing TENSORLAKE_API_KEY credentials."
6608
6499
  );
6609
6500
  }
6501
+ if (options.signal !== void 0 && !options.cas) {
6502
+ throw new Error(
6503
+ "signal is only supported for CAS image builds (cas: true); a legacy build has no Image Service build operation to cancel"
6504
+ );
6505
+ }
6610
6506
  emit({ type: "status", message: `Building image '${effectiveName}'...` });
6611
6507
  const binding = loadNativeBinding();
6612
6508
  let emitError;
6613
- const resultJson = await binding.buildSandboxImage(
6614
- {
6615
- apiUrl: context.apiUrl,
6616
- bearerToken,
6617
- dockerfilePath,
6618
- registeredName: effectiveName,
6619
- diskMb: options.diskMb,
6620
- builderDiskMb: options.builderDiskMb,
6621
- cpus: options.cpus,
6622
- memoryMb: options.memoryMb,
6623
- isPublic: options.isPublic ?? false,
6624
- organizationId: usePat ? context.organizationId : void 0,
6625
- projectId: usePat ? context.projectId : void 0,
6626
- namespace: context.namespace,
6627
- useScopeHeaders: usePat,
6628
- userAgent: void 0,
6629
- dockerCompat: options.dockerCompat ?? false,
6630
- dockerConfigJson: options.dockerConfigJson,
6631
- dockerfileText,
6632
- contextDir: nativeContextDir
6633
- },
6634
- (event) => {
6635
- try {
6636
- emit(eventToEmitDict(event));
6637
- } catch (error) {
6638
- emitError ??= error;
6639
- }
6509
+ const nativeOptions = {
6510
+ apiUrl: context.apiUrl,
6511
+ bearerToken,
6512
+ dockerfilePath,
6513
+ registeredName: effectiveName,
6514
+ diskMb: options.diskMb,
6515
+ builderDiskMb: options.builderDiskMb,
6516
+ cpus: options.cpus,
6517
+ memoryMb: options.memoryMb,
6518
+ isPublic: options.isPublic ?? false,
6519
+ organizationId: usePat ? context.organizationId : void 0,
6520
+ projectId: usePat ? context.projectId : void 0,
6521
+ namespace: context.namespace,
6522
+ useScopeHeaders: usePat,
6523
+ userAgent: void 0,
6524
+ dockerCompat: options.dockerCompat ?? false,
6525
+ dockerConfigJson: options.dockerConfigJson,
6526
+ dockerfileText,
6527
+ contextDir: nativeContextDir,
6528
+ cas: options.cas ?? false,
6529
+ buildArgs: options.buildArgs
6530
+ };
6531
+ const forward = (event) => {
6532
+ try {
6533
+ emit(eventToEmitDict(event));
6534
+ } catch (error) {
6535
+ emitError ??= error;
6640
6536
  }
6641
- );
6537
+ };
6538
+ const resultJson = options.cas ? await __runWithInterrupt(
6539
+ options.signal,
6540
+ (interruptId) => binding.buildSandboxImage(nativeOptions, forward, interruptId)
6541
+ ) : await binding.buildSandboxImage(nativeOptions, forward);
6642
6542
  if (emitError != null) {
6643
6543
  throw emitError;
6644
6544
  }
@@ -6655,7 +6555,7 @@ async function createSandboxImage(source, options = {}, deps = {}) {
6655
6555
  return result;
6656
6556
  } finally {
6657
6557
  if (tempContextDir != null) {
6658
- rmSync(tempContextDir, { recursive: true, force: true });
6558
+ rmSync2(tempContextDir, { recursive: true, force: true });
6659
6559
  }
6660
6560
  }
6661
6561
  }
@@ -6684,39 +6584,47 @@ async function importSandboxImage(imageReference, options = {}, deps = {}) {
6684
6584
  deps._allowPat ? "Missing TENSORLAKE_API_KEY or TENSORLAKE_PAT credentials." : "Missing TENSORLAKE_API_KEY credentials."
6685
6585
  );
6686
6586
  }
6587
+ if (options.signal !== void 0 && !options.cas) {
6588
+ throw new Error(
6589
+ "signal is only supported for CAS image imports (cas: true); a legacy import has no Image Service build operation to cancel"
6590
+ );
6591
+ }
6687
6592
  emit({
6688
6593
  type: "status",
6689
6594
  message: `Importing image '${reference}' as '${effectiveName}'...`
6690
6595
  });
6691
6596
  const binding = loadNativeBinding();
6692
6597
  let emitError;
6693
- const resultJson = await binding.importSandboxImage(
6694
- {
6695
- apiUrl: context.apiUrl,
6696
- bearerToken,
6697
- imageReference: reference,
6698
- registeredName: effectiveName,
6699
- diskMb: options.diskMb,
6700
- builderDiskMb: options.builderDiskMb,
6701
- cpus: options.cpus,
6702
- memoryMb: options.memoryMb,
6703
- isPublic: options.isPublic ?? false,
6704
- organizationId: usePat ? context.organizationId : void 0,
6705
- projectId: usePat ? context.projectId : void 0,
6706
- namespace: context.namespace,
6707
- useScopeHeaders: usePat,
6708
- userAgent: void 0,
6709
- dockerCompat: options.dockerCompat ?? false,
6710
- dockerConfigJson: options.dockerConfigJson
6711
- },
6712
- (event) => {
6713
- try {
6714
- emit(eventToEmitDict(event));
6715
- } catch (error) {
6716
- emitError ??= error;
6717
- }
6598
+ const nativeOptions = {
6599
+ apiUrl: context.apiUrl,
6600
+ bearerToken,
6601
+ imageReference: reference,
6602
+ registeredName: effectiveName,
6603
+ diskMb: options.diskMb,
6604
+ builderDiskMb: options.builderDiskMb,
6605
+ cpus: options.cpus,
6606
+ memoryMb: options.memoryMb,
6607
+ isPublic: options.isPublic ?? false,
6608
+ organizationId: usePat ? context.organizationId : void 0,
6609
+ projectId: usePat ? context.projectId : void 0,
6610
+ namespace: context.namespace,
6611
+ useScopeHeaders: usePat,
6612
+ userAgent: void 0,
6613
+ dockerCompat: options.dockerCompat ?? false,
6614
+ dockerConfigJson: options.dockerConfigJson,
6615
+ cas: options.cas ?? false
6616
+ };
6617
+ const forward = (event) => {
6618
+ try {
6619
+ emit(eventToEmitDict(event));
6620
+ } catch (error) {
6621
+ emitError ??= error;
6718
6622
  }
6719
- );
6623
+ };
6624
+ const resultJson = options.cas ? await __runWithInterrupt(
6625
+ options.signal,
6626
+ (interruptId) => binding.importSandboxImage(nativeOptions, forward, interruptId)
6627
+ ) : await binding.importSandboxImage(nativeOptions, forward);
6720
6628
  if (emitError != null) {
6721
6629
  throw emitError;
6722
6630
  }
@@ -6732,10 +6640,7 @@ async function importSandboxImage(imageReference, options = {}, deps = {}) {
6732
6640
  emit({ type: "done" });
6733
6641
  return result;
6734
6642
  }
6735
- async function deleteSandboxImage(imageName) {
6736
- if (typeof imageName !== "string" || imageName.length === 0) {
6737
- throw new TypeError("imageName must be a non-empty string");
6738
- }
6643
+ function catalogOptionsFromEnv() {
6739
6644
  const context = buildContextFromEnv();
6740
6645
  const bearerToken = context.apiKey;
6741
6646
  if (!bearerToken) {
@@ -6746,63 +6651,73 @@ async function deleteSandboxImage(imageName) {
6746
6651
  }
6747
6652
  throw new Error("Missing TENSORLAKE_API_KEY credentials.");
6748
6653
  }
6749
- const client = new CloudClient({
6750
- apiUrl: context.apiUrl,
6751
- apiKey: bearerToken,
6752
- namespace: context.namespace
6753
- });
6754
- try {
6755
- await client.deleteSandboxImage(imageName);
6756
- } finally {
6757
- client.close();
6758
- }
6654
+ return { apiUrl: context.apiUrl, bearerToken, useScopeHeaders: false };
6759
6655
  }
6760
- async function findSandboxImageByName(imageName) {
6761
- if (typeof imageName !== "string" || imageName.length === 0) {
6762
- throw new TypeError("imageName must be a non-empty string");
6763
- }
6656
+ function catalogOptionsFromCredentials(credentials) {
6764
6657
  const context = buildContextFromEnv();
6765
- const bearerToken = context.apiKey;
6658
+ const bearerToken = credentials.apiKey ?? context.apiKey;
6766
6659
  if (!bearerToken) {
6767
- if (context.personalAccessToken) {
6768
- throw new Error(
6769
- "Sandbox image SDKs require TENSORLAKE_API_KEY. Personal access tokens are CLI-only."
6770
- );
6771
- }
6772
6660
  throw new Error("Missing TENSORLAKE_API_KEY credentials.");
6773
6661
  }
6774
- const client = new CloudClient({
6775
- apiUrl: context.apiUrl,
6776
- apiKey: bearerToken,
6777
- namespace: context.namespace
6778
- });
6779
- try {
6780
- return await client.findSandboxImageByName(imageName);
6781
- } finally {
6782
- client.close();
6662
+ const { organizationId, projectId } = credentials;
6663
+ if (organizationId === void 0 !== (projectId === void 0)) {
6664
+ throw new TypeError("organizationId and projectId must be given together");
6783
6665
  }
6666
+ return {
6667
+ apiUrl: credentials.apiUrl ?? context.apiUrl,
6668
+ bearerToken,
6669
+ organizationId,
6670
+ projectId,
6671
+ useScopeHeaders: organizationId !== void 0
6672
+ };
6784
6673
  }
6785
- async function listSandboxImages() {
6786
- const context = buildContextFromEnv();
6787
- const bearerToken = context.apiKey;
6788
- if (!bearerToken) {
6789
- if (context.personalAccessToken) {
6790
- throw new Error(
6791
- "Sandbox image SDKs require TENSORLAKE_API_KEY. Personal access tokens are CLI-only."
6792
- );
6793
- }
6794
- throw new Error("Missing TENSORLAKE_API_KEY credentials.");
6674
+ function parseTemplate(json) {
6675
+ return JSON.parse(json);
6676
+ }
6677
+ async function deleteSandboxImage(imageName) {
6678
+ if (typeof imageName !== "string" || imageName.length === 0) {
6679
+ throw new TypeError("imageName must be a non-empty string");
6680
+ }
6681
+ await loadNativeBinding().deleteSandboxImage(catalogOptionsFromEnv(), imageName);
6682
+ }
6683
+ async function deleteSandboxImageWithCredentials(credentials, imageName) {
6684
+ if (typeof imageName !== "string" || imageName.length === 0) {
6685
+ throw new TypeError("imageName must be a non-empty string");
6686
+ }
6687
+ await loadNativeBinding().deleteSandboxImage(
6688
+ catalogOptionsFromCredentials(credentials),
6689
+ imageName
6690
+ );
6691
+ }
6692
+ async function findSandboxImageByName(imageName) {
6693
+ if (typeof imageName !== "string" || imageName.length === 0) {
6694
+ throw new TypeError("imageName must be a non-empty string");
6795
6695
  }
6796
- const client = new CloudClient({
6797
- apiUrl: context.apiUrl,
6798
- apiKey: bearerToken,
6799
- namespace: context.namespace
6800
- });
6801
- try {
6802
- return await client.listSandboxImages();
6803
- } finally {
6804
- client.close();
6696
+ const json = await loadNativeBinding().findSandboxImage(
6697
+ catalogOptionsFromEnv(),
6698
+ imageName
6699
+ );
6700
+ return json == null ? null : parseTemplate(json);
6701
+ }
6702
+ async function findSandboxImageByNameWithCredentials(credentials, imageName) {
6703
+ if (typeof imageName !== "string" || imageName.length === 0) {
6704
+ throw new TypeError("imageName must be a non-empty string");
6805
6705
  }
6706
+ const json = await loadNativeBinding().findSandboxImage(
6707
+ catalogOptionsFromCredentials(credentials),
6708
+ imageName
6709
+ );
6710
+ return json == null ? null : parseTemplate(json);
6711
+ }
6712
+ async function listSandboxImages() {
6713
+ const json = await loadNativeBinding().listSandboxImages(catalogOptionsFromEnv());
6714
+ return JSON.parse(json);
6715
+ }
6716
+ async function listSandboxImagesWithCredentials(credentials) {
6717
+ const json = await loadNativeBinding().listSandboxImages(
6718
+ catalogOptionsFromCredentials(credentials)
6719
+ );
6720
+ return JSON.parse(json);
6806
6721
  }
6807
6722
  async function runCreateSandboxImageCli(argv = process.argv.slice(2)) {
6808
6723
  const parsed = parseArgs({
@@ -6912,15 +6827,25 @@ async function runImportSandboxImageCli(argv = process.argv.slice(2)) {
6912
6827
  { emit: ndjsonStdoutEmit, _allowPat: true }
6913
6828
  );
6914
6829
  }
6915
- var cachedNativeBinding, cachedNativeBindingError, DEFAULT_IMAGE_NAME2;
6830
+ var cachedNativeBinding, cachedNativeBindingError, DEFAULT_IMAGE_NAME2, __imageBuildInternals;
6916
6831
  var init_sandbox_image = __esm({
6917
6832
  "src/sandbox-image.ts"() {
6918
6833
  "use strict";
6919
6834
  init_esm_shims();
6920
- init_cloud_client();
6921
6835
  init_image();
6922
6836
  init_native_binding();
6837
+ init_image_builds();
6923
6838
  DEFAULT_IMAGE_NAME2 = "default";
6839
+ __imageBuildInternals = {
6840
+ loadNativeBinding: () => loadNativeBinding(),
6841
+ buildContextFromEnv: () => buildContextFromEnv(),
6842
+ stderrEmit: (event) => stderrEmit(event),
6843
+ noopEmit: (event) => noopEmit(event),
6844
+ eventToEmitDict: (event) => eventToEmitDict(event),
6845
+ imageRequiresContext: (image) => imageRequiresContext(image),
6846
+ defaultRegisteredName: (dockerfilePath) => defaultRegisteredName(dockerfilePath),
6847
+ defaultRegisteredNameFromImage: (reference) => defaultRegisteredNameFromImage(reference)
6848
+ };
6924
6849
  }
6925
6850
  });
6926
6851
 
@@ -6932,11 +6857,546 @@ init_pending_sandbox();
6932
6857
  init_sandbox();
6933
6858
  init_desktop();
6934
6859
  init_tunnel();
6935
- init_cloud_client();
6860
+
6861
+ // src/cloud-client.ts
6862
+ init_esm_shims();
6863
+ init_defaults();
6864
+ import { nanoid } from "nanoid";
6865
+
6866
+ // src/native-cloud.ts
6867
+ init_esm_shims();
6868
+ init_native_sandbox();
6869
+ init_native_worker_client();
6870
+ var NativeCloudTransport = class {
6871
+ constructor(options) {
6872
+ this.options = options;
6873
+ if (!Number.isSafeInteger(options.maxRetries) || options.maxRetries < 0 || options.maxRetries > 4294967295) {
6874
+ throw new RangeError("maxRetries must be a non-negative 32-bit integer");
6875
+ }
6876
+ if (!Number.isFinite(options.retryBackoffMs) || options.retryBackoffMs < 0) {
6877
+ throw new RangeError("retryBackoffMs must be a non-negative finite number");
6878
+ }
6879
+ }
6880
+ native;
6881
+ closed = false;
6882
+ client() {
6883
+ if (this.closed) throw new Error("Tensorlake native client is closed");
6884
+ if (this.native) return this.native;
6885
+ const ctor = loadNativeSandboxBinding().NativeCloudClient;
6886
+ if (!ctor) throw new Error("Native binding does not export NativeCloudClient; rebuild with 'npm run build:native'");
6887
+ return this.native = new ctor(JSON.stringify(this.options));
6888
+ }
6889
+ close() {
6890
+ this.closed = true;
6891
+ releaseNativeHandle(this.native ?? null);
6892
+ this.native = void 0;
6893
+ }
6894
+ async requestResponse(method, path5, options) {
6895
+ const request = await serializeRequest(method, path5, options);
6896
+ const raw = await callNative(() => this.client().request(request));
6897
+ const response = new Response(
6898
+ [204, 205, 304].includes(raw.status) ? null : Uint8Array.from(raw.data).buffer,
6899
+ { status: raw.status, headers: JSON.parse(raw.headersJson) }
6900
+ );
6901
+ return Object.assign(response, { traceId: raw.traceId });
6902
+ }
6903
+ async requestJson(method, path5) {
6904
+ const response = await this.requestResponse(method, path5);
6905
+ const text = await response.text();
6906
+ const value = text ? JSON.parse(text) : null;
6907
+ return Object.assign(value ?? {}, { traceId: response.traceId });
6908
+ }
6909
+ async *stream(method, path5, signal) {
6910
+ if (signal?.aborted) return;
6911
+ const request = await serializeRequest(method, path5, { headers: { Accept: "text/event-stream" } });
6912
+ yield* nativeEventStream((emit) => this.client().stream(request, emit), void 0, signal);
6913
+ }
6914
+ };
6915
+ async function serializeRequest(method, path5, options) {
6916
+ const headers = { ...options?.headers };
6917
+ let body = options?.body;
6918
+ if (options?.json !== void 0) {
6919
+ body = JSON.stringify(options.json);
6920
+ if (!Object.keys(headers).some((key) => key.toLowerCase() === "content-type")) {
6921
+ headers["Content-Type"] = "application/json";
6922
+ }
6923
+ }
6924
+ const request = {
6925
+ method,
6926
+ path: path5,
6927
+ headersJson: JSON.stringify(headers),
6928
+ statusOnlyCodes: [...options?.statusOnlyCodes ?? []]
6929
+ };
6930
+ if (body instanceof FormData) {
6931
+ request.parts = [];
6932
+ for (const [name, value] of body.entries()) {
6933
+ 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" });
6934
+ }
6935
+ } else if (body !== void 0) {
6936
+ if (body instanceof Blob) request.body = Buffer.from(await body.arrayBuffer());
6937
+ else if (typeof body === "string") request.body = Buffer.from(body);
6938
+ else if (body instanceof ArrayBuffer) request.body = Buffer.from(new Uint8Array(body));
6939
+ else request.body = Buffer.from(body);
6940
+ }
6941
+ return request;
6942
+ }
6943
+
6944
+ // src/cloud-client.ts
6945
+ init_models();
6946
+ init_sandbox_image();
6947
+ var CloudClient = class _CloudClient {
6948
+ transport;
6949
+ apiUrl;
6950
+ apiKey;
6951
+ organizationId;
6952
+ projectId;
6953
+ namespace;
6954
+ constructor(options) {
6955
+ this.apiUrl = options?.apiUrl ?? API_URL;
6956
+ this.apiKey = options?.apiKey ?? API_KEY;
6957
+ this.organizationId = options?.organizationId;
6958
+ this.projectId = options?.projectId;
6959
+ this.namespace = options?.namespace ?? NAMESPACE;
6960
+ this.transport = new NativeCloudTransport({
6961
+ baseUrl: options?.apiUrl ?? API_URL,
6962
+ apiKey: options?.apiKey ?? API_KEY,
6963
+ organizationId: this.organizationId,
6964
+ projectId: this.projectId,
6965
+ maxRetries: options?.maxRetries ?? MAX_RETRIES,
6966
+ retryBackoffMs: options?.retryBackoffMs ?? RETRY_BACKOFF_MS,
6967
+ timeoutMs: DEFAULT_HTTP_TIMEOUT_MS,
6968
+ userAgent: `tensorlake-typescript-sdk/${SDK_VERSION}`
6969
+ });
6970
+ }
6971
+ static forCloud(options) {
6972
+ return new _CloudClient(options);
6973
+ }
6974
+ close() {
6975
+ this.transport.close();
6976
+ }
6977
+ async upsertApplication(manifest, codeZip, upgradeRunningRequests = false) {
6978
+ const applicationManifest = { ...manifest };
6979
+ let publicEndpointId = publicEndpointIdFromManifest(applicationManifest);
6980
+ if (applicationAllowsUnauthenticatedRequests(applicationManifest) && publicEndpointId === void 0) {
6981
+ const applicationName = applicationManifest.name;
6982
+ if (typeof applicationName === "string" && applicationName.length > 0) {
6983
+ publicEndpointId = await this.existingApplicationPublicEndpointId(applicationName);
6984
+ }
6985
+ publicEndpointId ??= generatePublicEndpointId();
6986
+ }
6987
+ if (publicEndpointId !== void 0) {
6988
+ applicationManifest.public_endpoint_id = publicEndpointId;
6989
+ delete applicationManifest.publicEndpointId;
6990
+ }
6991
+ const form = new FormData();
6992
+ form.append(
6993
+ "code",
6994
+ new Blob([toBlobPart(codeZip)], { type: "application/zip" }),
6995
+ "code.zip"
6996
+ );
6997
+ form.append("code_content_type", "application/zip");
6998
+ form.append("application", JSON.stringify(applicationManifest));
6999
+ form.append(
7000
+ "upgrade_requests_to_latest_code",
7001
+ String(upgradeRunningRequests)
7002
+ );
7003
+ await this.transport.requestResponse("POST", this.namespacePath("applications"), {
7004
+ body: form
7005
+ });
7006
+ }
7007
+ async deleteApplication(applicationName) {
7008
+ await this.transport.requestResponse(
7009
+ "DELETE",
7010
+ this.namespacePath(`applications/${encodeURIComponent(applicationName)}`)
7011
+ );
7012
+ }
7013
+ /**
7014
+ * Delete a registered sandbox image by name or id through the merged
7015
+ * catalog, with this client's credentials: an `image_` id or a name the
7016
+ * Image Service knows deletes a CAS image, a `sandbox_template_` id or a
7017
+ * name registered only in the platform registry deletes a legacy image.
7018
+ * Rejects when neither catalog knows the reference. The same semantics
7019
+ * and accepted differences as the module-level `deleteSandboxImage`.
7020
+ */
7021
+ async deleteSandboxImage(imageName) {
7022
+ await deleteSandboxImageWithCredentials(this.catalogCredentials(), imageName);
7023
+ }
7024
+ /**
7025
+ * Look up a registered sandbox image by name or id through the merged
7026
+ * catalog, with this client's credentials. Returns the image in the
7027
+ * sandbox-template shape, or `null` when neither the Image Service nor the
7028
+ * platform registry knows the reference. An explicit organization/project
7029
+ * scope (the client's, or the call's override) addresses that project's
7030
+ * routes directly, as before; without one the key's own scope applies.
7031
+ */
7032
+ async findSandboxImageByName(imageName, options) {
7033
+ return findSandboxImageByNameWithCredentials(
7034
+ this.catalogCredentials(options),
7035
+ imageName
7036
+ );
7037
+ }
7038
+ /**
7039
+ * List every registered sandbox image of the project (CAS and legacy, in
7040
+ * the sandbox-template shape, newest first) through the merged catalog,
7041
+ * with this client's credentials. An explicit organization/project scope
7042
+ * (the client's, or the call's override) addresses that project's routes
7043
+ * directly, as before; without one the key's own scope applies.
7044
+ */
7045
+ async listSandboxImages(options) {
7046
+ return listSandboxImagesWithCredentials(this.catalogCredentials(options));
7047
+ }
7048
+ catalogCredentials(options) {
7049
+ return {
7050
+ apiUrl: this.apiUrl,
7051
+ apiKey: this.apiKey,
7052
+ organizationId: options?.organizationId ?? this.organizationId,
7053
+ projectId: options?.projectId ?? this.projectId
7054
+ };
7055
+ }
7056
+ async applications() {
7057
+ const raw = await this.transport.requestJson(
7058
+ "GET",
7059
+ this.namespacePath("applications")
7060
+ );
7061
+ return (raw.applications ?? []).map(
7062
+ (application) => fromSnakeKeys(application)
7063
+ );
7064
+ }
7065
+ async applicationManifest(applicationName) {
7066
+ const raw = await this.transport.requestJson(
7067
+ "GET",
7068
+ this.namespacePath(`applications/${encodeURIComponent(applicationName)}`)
7069
+ );
7070
+ return fromSnakeKeys(raw);
7071
+ }
7072
+ async runRequest(applicationName, inputs = []) {
7073
+ const path5 = this.namespacePath(
7074
+ `applications/${encodeURIComponent(applicationName)}`
7075
+ );
7076
+ const response = inputs.length === 0 ? await this.transport.requestResponse("POST", path5, {
7077
+ body: new Uint8Array(),
7078
+ headers: { Accept: "application/json" }
7079
+ }) : inputs.length === 1 && inputs[0].name === "0" ? await this.transport.requestResponse("POST", path5, {
7080
+ body: toRequestBody(inputs[0].data),
7081
+ headers: {
7082
+ Accept: "application/json",
7083
+ "Content-Type": inputs[0].contentType
7084
+ }
7085
+ }) : await this.runMultipartRequest(path5, inputs);
7086
+ const body = await parseJsonResponse(response);
7087
+ const requestId = body?.request_id;
7088
+ if (!requestId) {
7089
+ throw new Error("missing request_id in run request response body");
7090
+ }
7091
+ return requestId;
7092
+ }
7093
+ async waitOnRequestCompletion(applicationName, requestId) {
7094
+ const stream = this.transport.stream(
7095
+ "GET",
7096
+ this.namespacePath(
7097
+ `applications/${encodeURIComponent(applicationName)}/requests/${encodeURIComponent(requestId)}/progress`
7098
+ )
7099
+ );
7100
+ for await (const event of stream) {
7101
+ if (Object.prototype.hasOwnProperty.call(event, "RequestFinished")) {
7102
+ return;
7103
+ }
7104
+ }
7105
+ throw new Error("progress stream ended before request completion");
7106
+ }
7107
+ async requestMetadata(applicationName, requestId) {
7108
+ const raw = await this.transport.requestJson(
7109
+ "GET",
7110
+ this.namespacePath(
7111
+ `applications/${encodeURIComponent(applicationName)}/requests/${encodeURIComponent(requestId)}`
7112
+ )
7113
+ );
7114
+ return fromSnakeKeys(raw);
7115
+ }
7116
+ async requestOutput(applicationName, requestId) {
7117
+ const response = await this.transport.requestResponse(
7118
+ "GET",
7119
+ this.namespacePath(
7120
+ `applications/${encodeURIComponent(applicationName)}/requests/${encodeURIComponent(requestId)}/output`
7121
+ )
7122
+ );
7123
+ const serializedValue = new Uint8Array(await response.arrayBuffer());
7124
+ const contentType = response.headers.get("content-type") ?? "";
7125
+ return {
7126
+ serializedValue,
7127
+ contentType
7128
+ };
7129
+ }
7130
+ async listSecrets(options) {
7131
+ const base = this.secretCollectionPath(
7132
+ options?.organizationId,
7133
+ options?.projectId
7134
+ );
7135
+ const raw = await this.transport.requestJson("GET", base);
7136
+ const pageSize = Math.max(0, options?.pageSize ?? 100);
7137
+ return Object.assign(
7138
+ {
7139
+ items: raw.slice(0, pageSize).map(secretFromMetadata),
7140
+ pagination: { total: raw.length }
7141
+ },
7142
+ { traceId: raw.traceId }
7143
+ );
7144
+ }
7145
+ async getSecret(secretId, options) {
7146
+ const base = this.secretCollectionPath(
7147
+ options?.organizationId,
7148
+ options?.projectId
7149
+ );
7150
+ const raw = await this.transport.requestJson(
7151
+ "GET",
7152
+ `${base}/${encodeURIComponent(secretId)}`
7153
+ );
7154
+ return Object.assign(secretFromMetadata(raw), { traceId: raw.traceId });
7155
+ }
7156
+ async upsertSecrets(secrets, options) {
7157
+ const base = this.secretCollectionPath(
7158
+ options?.organizationId,
7159
+ options?.projectId
7160
+ );
7161
+ if (Array.isArray(secrets)) {
7162
+ const results = [];
7163
+ for (const secret of secrets) {
7164
+ results.push(await this.upsertSecret(base, secret));
7165
+ }
7166
+ return results;
7167
+ }
7168
+ return this.upsertSecret(base, secrets);
7169
+ }
7170
+ async deleteSecret(secretId, options) {
7171
+ const base = this.secretCollectionPath(
7172
+ options?.organizationId,
7173
+ options?.projectId
7174
+ );
7175
+ await this.transport.requestResponse(
7176
+ "DELETE",
7177
+ `${base}/${encodeURIComponent(secretId)}`
7178
+ );
7179
+ }
7180
+ async upsertSecret(base, secret) {
7181
+ let response = await this.transport.requestResponse("POST", base, {
7182
+ json: secret,
7183
+ headers: { "Idempotency-Key": nanoid() },
7184
+ statusOnlyCodes: /* @__PURE__ */ new Set([409])
7185
+ });
7186
+ if (response.status === 409) {
7187
+ const prefix = base.slice(0, -"/secrets".length);
7188
+ const existing = await this.transport.requestJson(
7189
+ "GET",
7190
+ `${prefix}/secret-names/${encodeURIComponent(secret.name)}`
7191
+ );
7192
+ response = await this.transport.requestResponse(
7193
+ "POST",
7194
+ `${base}/${encodeURIComponent(existing.id)}/versions`,
7195
+ {
7196
+ json: { value: secret.value },
7197
+ headers: { "Idempotency-Key": nanoid() }
7198
+ }
7199
+ );
7200
+ }
7201
+ const metadata = await parseJsonResponse(response);
7202
+ return Object.assign(secretFromMetadata(metadata), {
7203
+ traceId: response.traceId
7204
+ });
7205
+ }
7206
+ async startImageBuild(buildServicePath, request) {
7207
+ const form = new FormData();
7208
+ form.append("graph_name", request.applicationName);
7209
+ form.append("graph_version", request.applicationVersion);
7210
+ form.append("graph_function_name", request.functionName);
7211
+ form.append("image_name", request.imageName);
7212
+ form.append("image_id", request.imageId);
7213
+ form.append(
7214
+ "context",
7215
+ new Blob([toBlobPart(request.buildContext)]),
7216
+ "context.tar.gz"
7217
+ );
7218
+ const response = await this.transport.requestResponse(
7219
+ "PUT",
7220
+ `${trimTrailingSlashes2(buildServicePath)}/builds`,
7221
+ { body: form }
7222
+ );
7223
+ const raw = await parseJsonResponse(response);
7224
+ return fromSnakeKeys(raw);
7225
+ }
7226
+ async createApplicationBuild(buildServicePath, request, imageContexts) {
7227
+ const form = createApplicationBuildForm(request, imageContexts);
7228
+ const response = await this.transport.requestResponse(
7229
+ "POST",
7230
+ trimTrailingSlashes2(buildServicePath),
7231
+ { body: form }
7232
+ );
7233
+ const raw = await parseJsonResponse(response);
7234
+ return fromSnakeKeys(raw);
7235
+ }
7236
+ async applicationBuildInfo(buildServicePath, applicationBuildId) {
7237
+ const raw = await this.transport.requestJson(
7238
+ "GET",
7239
+ `${trimTrailingSlashes2(buildServicePath)}/${encodeURIComponent(applicationBuildId)}`
7240
+ );
7241
+ return fromSnakeKeys(raw);
7242
+ }
7243
+ async cancelApplicationBuild(buildServicePath, applicationBuildId) {
7244
+ const raw = await this.transport.requestJson(
7245
+ "POST",
7246
+ `${trimTrailingSlashes2(buildServicePath)}/${encodeURIComponent(applicationBuildId)}/cancel`
7247
+ );
7248
+ return fromSnakeKeys(raw);
7249
+ }
7250
+ async buildInfo(buildServicePath, buildId) {
7251
+ const raw = await this.transport.requestJson(
7252
+ "GET",
7253
+ `${trimTrailingSlashes2(buildServicePath)}/builds/${encodeURIComponent(buildId)}`
7254
+ );
7255
+ return fromSnakeKeys(raw);
7256
+ }
7257
+ async cancelBuild(buildServicePath, buildId) {
7258
+ await this.transport.requestResponse(
7259
+ "POST",
7260
+ `${trimTrailingSlashes2(buildServicePath)}/builds/${encodeURIComponent(buildId)}/cancel`
7261
+ );
7262
+ }
7263
+ async *streamBuildLogs(buildServicePath, buildId, signal) {
7264
+ const stream = this.transport.stream(
7265
+ "GET",
7266
+ `${trimTrailingSlashes2(buildServicePath)}/builds/${encodeURIComponent(buildId)}/logs`,
7267
+ signal
7268
+ );
7269
+ for await (const event of stream) {
7270
+ yield fromSnakeKeys(event);
7271
+ }
7272
+ }
7273
+ async runMultipartRequest(path5, inputs) {
7274
+ const form = new FormData();
7275
+ for (const input of inputs) {
7276
+ form.append(
7277
+ input.name,
7278
+ new Blob([toBlobPart(input.data)], { type: input.contentType }),
7279
+ input.name
7280
+ );
7281
+ }
7282
+ return this.transport.requestResponse("POST", path5, {
7283
+ body: form,
7284
+ headers: { Accept: "application/json" }
7285
+ });
7286
+ }
7287
+ namespacePath(subpath) {
7288
+ return `/v1/namespaces/${encodeURIComponent(this.namespace)}/${subpath.replace(/^\/+/, "")}`;
7289
+ }
7290
+ async existingApplicationPublicEndpointId(applicationName) {
7291
+ const response = await this.transport.requestResponse(
7292
+ "GET",
7293
+ this.namespacePath(`applications/${encodeURIComponent(applicationName)}`),
7294
+ { statusOnlyCodes: /* @__PURE__ */ new Set([404]) }
7295
+ );
7296
+ if (response.status === 404) {
7297
+ return void 0;
7298
+ }
7299
+ const application = await parseJsonResponse(response);
7300
+ return publicEndpointIdFromManifest(application);
7301
+ }
7302
+ secretCollectionPath(organizationId, projectId) {
7303
+ const resolvedOrganizationId = organizationId ?? this.organizationId;
7304
+ const resolvedProjectId = projectId ?? this.projectId;
7305
+ if (!resolvedOrganizationId && !resolvedProjectId) {
7306
+ return this.namespacePath("secrets");
7307
+ }
7308
+ if (!resolvedOrganizationId || !resolvedProjectId) {
7309
+ throw new Error("organizationId and projectId must be provided together");
7310
+ }
7311
+ return this.namespacePath("secrets");
7312
+ }
7313
+ };
7314
+ function secretFromMetadata(metadata) {
7315
+ return {
7316
+ id: metadata.id,
7317
+ name: metadata.name,
7318
+ createdAt: new Date(metadata.created_at_ms)
7319
+ };
7320
+ }
7321
+ var UNAUTHENTICATED_REQUESTS = "unauthenticated_requests";
7322
+ function applicationAllowsUnauthenticatedRequests(manifest) {
7323
+ return Array.isArray(manifest.allow) && manifest.allow.includes(UNAUTHENTICATED_REQUESTS);
7324
+ }
7325
+ function publicEndpointIdFromManifest(manifest) {
7326
+ for (const key of ["public_endpoint_id", "publicEndpointId"]) {
7327
+ const value = manifest[key];
7328
+ if (typeof value === "string" && value.length > 0) {
7329
+ return value;
7330
+ }
7331
+ }
7332
+ return void 0;
7333
+ }
7334
+ function generatePublicEndpointId() {
7335
+ return `endpoint_${nanoid()}`;
7336
+ }
7337
+ function createApplicationBuildForm(request, imageContexts) {
7338
+ const contextsByPartName = /* @__PURE__ */ new Map();
7339
+ for (const context of imageContexts) {
7340
+ if (contextsByPartName.has(context.contextTarPartName)) {
7341
+ throw new Error(
7342
+ `duplicate image context part name '${context.contextTarPartName}'`
7343
+ );
7344
+ }
7345
+ contextsByPartName.set(context.contextTarPartName, context);
7346
+ }
7347
+ const form = new FormData();
7348
+ form.append(
7349
+ "app_version",
7350
+ new Blob([JSON.stringify(request)], { type: "application/json" }),
7351
+ "app_version"
7352
+ );
7353
+ for (const image of request.images) {
7354
+ const context = contextsByPartName.get(image.contextTarPartName);
7355
+ if (!context) {
7356
+ throw new Error(
7357
+ `missing image context for part '${image.contextTarPartName}'`
7358
+ );
7359
+ }
7360
+ form.append(
7361
+ image.contextTarPartName,
7362
+ new Blob([toBlobPart(context.contextTarGz)]),
7363
+ `${image.contextTarPartName}.tar.gz`
7364
+ );
7365
+ }
7366
+ for (const context of imageContexts) {
7367
+ if (!request.images.some((image) => image.contextTarPartName === context.contextTarPartName)) {
7368
+ throw new Error(
7369
+ `unexpected image context for part '${context.contextTarPartName}'`
7370
+ );
7371
+ }
7372
+ }
7373
+ return form;
7374
+ }
7375
+ function trimTrailingSlashes2(value) {
7376
+ return value.endsWith("/") ? value.slice(0, -1) : value;
7377
+ }
7378
+ function toBlobPart(data) {
7379
+ if (typeof data === "string" || data instanceof Blob) {
7380
+ return data;
7381
+ }
7382
+ if (data instanceof Uint8Array) {
7383
+ return Uint8Array.from(data).buffer;
7384
+ }
7385
+ return data;
7386
+ }
7387
+ function toRequestBody(data) {
7388
+ return toBlobPart(data);
7389
+ }
7390
+ async function parseJsonResponse(response) {
7391
+ const text = await response.text();
7392
+ if (!text) {
7393
+ return void 0;
7394
+ }
7395
+ return JSON.parse(text);
7396
+ }
6936
7397
 
6937
7398
  // src/api-client.ts
6938
7399
  init_esm_shims();
6939
- init_cloud_client();
6940
7400
 
6941
7401
  // src/filesystem.ts
6942
7402
  init_esm_shims();
@@ -6954,12 +7414,12 @@ import { promisify } from "util";
6954
7414
  init_esm_shims();
6955
7415
  var GIT_MODE_DIR = 16384;
6956
7416
  var GIT_MODE_SYMLINK = 40960;
6957
- function trimSlashes(path4) {
7417
+ function trimSlashes(path5) {
6958
7418
  let start = 0;
6959
- let end = path4.length;
6960
- while (start < end && path4.charCodeAt(start) === 47) start += 1;
6961
- while (end > start && path4.charCodeAt(end - 1) === 47) end -= 1;
6962
- return path4.slice(start, end);
7419
+ let end = path5.length;
7420
+ while (start < end && path5.charCodeAt(start) === 47) start += 1;
7421
+ while (end > start && path5.charCodeAt(end - 1) === 47) end -= 1;
7422
+ return path5.slice(start, end);
6963
7423
  }
6964
7424
  function fileEntryFromWire(entry, dirPath) {
6965
7425
  const mode = entry.mode ?? 33188;
@@ -6977,9 +7437,9 @@ function fileEntryFromWire(entry, dirPath) {
6977
7437
  }
6978
7438
  function mountStatusFromRaw(raw, localPath) {
6979
7439
  const mounted = "mounted" in raw ? Boolean(raw.mounted) : "active" in raw ? Boolean(raw.active) : true;
6980
- const path4 = String(raw.path || raw.mount_path || localPath || "");
7440
+ const path5 = String(raw.path || raw.mount_path || localPath || "");
6981
7441
  const filesystem = raw.filesystem || raw.file_system || raw.repository || null;
6982
- return { path: path4, filesystem, mounted, raw };
7442
+ return { path: path5, filesystem, mounted, raw };
6983
7443
  }
6984
7444
  var FilesystemError = class extends Error {
6985
7445
  constructor(message) {
@@ -6998,11 +7458,11 @@ var FilesystemNotFoundError = class extends FilesystemError {
6998
7458
  var FileNotFoundInFilesystemError = class extends FilesystemError {
6999
7459
  filesystem;
7000
7460
  path;
7001
- constructor(filesystem, path4) {
7002
- super(`File not found in filesystem ${filesystem}: ${path4}`);
7461
+ constructor(filesystem, path5) {
7462
+ super(`File not found in filesystem ${filesystem}: ${path5}`);
7003
7463
  this.name = "FileNotFoundInFilesystemError";
7004
7464
  this.filesystem = filesystem;
7005
- this.path = path4;
7465
+ this.path = path5;
7006
7466
  }
7007
7467
  };
7008
7468
  var FilesystemAPIError = class extends FilesystemError {
@@ -7356,8 +7816,8 @@ var Filesystem = class {
7356
7816
  }
7357
7817
  // -- writes -------------------------------------------------------------------
7358
7818
  /** Write one file. Returns the snapshot (version) the write produced. */
7359
- async writeFile(path4, data, message) {
7360
- return await this.writeFiles(/* @__PURE__ */ new Map([[path4, data]]), message);
7819
+ async writeFile(path5, data, message) {
7820
+ return await this.writeFiles(/* @__PURE__ */ new Map([[path5, data]]), message);
7361
7821
  }
7362
7822
  /** Write several files (and/or delete paths) in one atomic snapshot. */
7363
7823
  async writeFiles(files, message, deletes = []) {
@@ -7365,8 +7825,8 @@ var Filesystem = class {
7365
7825
  if (entries.length === 0 && deletes.length === 0) {
7366
7826
  throw new FilesystemError("nothing to write: no files or deletions given");
7367
7827
  }
7368
- const writes = entries.map(([path4, data]) => ({
7369
- path: path4,
7828
+ const writes = entries.map(([path5, data]) => ({
7829
+ path: path5,
7370
7830
  content: toBuffer(data)
7371
7831
  }));
7372
7832
  const resolvedMessage = message || `write ${writes.length} file(s) via SDK`;
@@ -7382,9 +7842,9 @@ var Filesystem = class {
7382
7842
  * Stream one local file directly to object storage in bounded parts.
7383
7843
  * This is the memory-bounded API for multi-GiB files.
7384
7844
  */
7385
- async writeFileFromPath(path4, localPath, message) {
7845
+ async writeFileFromPath(path5, localPath, message) {
7386
7846
  return await this.writeFilesFromPaths(
7387
- /* @__PURE__ */ new Map([[path4, localPath]]),
7847
+ /* @__PURE__ */ new Map([[path5, localPath]]),
7388
7848
  message
7389
7849
  );
7390
7850
  }
@@ -7397,7 +7857,7 @@ var Filesystem = class {
7397
7857
  if (entries.length === 0) {
7398
7858
  throw new FilesystemError("nothing to write: no local files given");
7399
7859
  }
7400
- const writes = entries.map(([path4, localPath]) => ({ path: path4, localPath }));
7860
+ const writes = entries.map(([path5, localPath]) => ({ path: path5, localPath }));
7401
7861
  const resolvedMessage = message || `write ${writes.length} local file(s) via SDK`;
7402
7862
  const branch = await this.branch();
7403
7863
  const traced = await callNative2(
@@ -7474,11 +7934,11 @@ var Filesystem = class {
7474
7934
  };
7475
7935
  }
7476
7936
  /** Delete one file. Returns the durable version the deletion produced. */
7477
- async deleteFile(path4, message) {
7937
+ async deleteFile(path5, message) {
7478
7938
  return await this.writeFiles(
7479
7939
  /* @__PURE__ */ new Map(),
7480
- message || `delete ${path4} via SDK`,
7481
- [path4]
7940
+ message || `delete ${path5} via SDK`,
7941
+ [path5]
7482
7942
  );
7483
7943
  }
7484
7944
  /**
@@ -7529,15 +7989,15 @@ var Filesystem = class {
7529
7989
  * Read a file's bytes at `version` (the current `main` head or a retained
7530
7990
  * snapshot id; defaults to the filesystem's current head).
7531
7991
  */
7532
- async readFile(path4, version) {
7533
- return (await this.readFileWithMetadata(path4, { version })).data;
7992
+ async readFile(path5, version) {
7993
+ return (await this.readFileWithMetadata(path5, { version })).data;
7534
7994
  }
7535
7995
  /**
7536
7996
  * Read bytes and immutable metadata in one request. A range is executed by
7537
7997
  * Artifact Storage, so callers never download the unrequested remainder.
7538
7998
  */
7539
- async readFileWithMetadata(path4, options = {}) {
7540
- if (trimSlashes(path4) === "") {
7999
+ async readFileWithMetadata(path5, options = {}) {
8000
+ if (trimSlashes(path5) === "") {
7541
8001
  throw new FilesystemError("file path must not be empty");
7542
8002
  }
7543
8003
  const range = options.range;
@@ -7550,12 +8010,12 @@ var Filesystem = class {
7550
8010
  const traced = await callNative2(
7551
8011
  () => this.native.readFilesystemFile(
7552
8012
  this.name,
7553
- path4,
8013
+ path5,
7554
8014
  resolvedVersion,
7555
8015
  range?.offset,
7556
8016
  range?.length
7557
8017
  ),
7558
- new FileNotFoundInFilesystemError(this.name, path4)
8018
+ new FileNotFoundInFilesystemError(this.name, path5)
7559
8019
  );
7560
8020
  const fullSize = traced.fullSize;
7561
8021
  if (!traced.contentId || fullSize === void 0 || !Number.isSafeInteger(fullSize) || fullSize < 0 || traced.data.byteLength > fullSize) {
@@ -7570,9 +8030,9 @@ var Filesystem = class {
7570
8030
  };
7571
8031
  }
7572
8032
  /** Read a file as UTF-8 text at `version`. Throws on non-UTF-8 content. */
7573
- async readText(path4, version) {
8033
+ async readText(path5, version) {
7574
8034
  return new TextDecoder("utf-8", { fatal: true, ignoreBOM: true }).decode(
7575
- await this.readFile(path4, version)
8035
+ await this.readFile(path5, version)
7576
8036
  );
7577
8037
  }
7578
8038
  /** List one directory (non-recursive) at `version`. */
@@ -7635,11 +8095,11 @@ var FilesystemMount = class {
7635
8095
  path;
7636
8096
  readonly;
7637
8097
  /** @internal — obtain instances via `FilesystemClient.mount()`. */
7638
- constructor(client, cli, filesystem, path4, readonly) {
8098
+ constructor(client, cli, filesystem, path5, readonly) {
7639
8099
  this.client = client;
7640
8100
  this.cli = cli;
7641
8101
  this.filesystem = filesystem;
7642
- this.path = path4;
8102
+ this.path = path5;
7643
8103
  this.readonly = readonly;
7644
8104
  }
7645
8105
  /** Flush pending local changes into a durable snapshot. */
@@ -7657,6 +8117,7 @@ var FilesystemMount = class {
7657
8117
  };
7658
8118
 
7659
8119
  // src/api-client.ts
8120
+ init_sandbox_image();
7660
8121
  init_errors();
7661
8122
  var APIClient = class {
7662
8123
  cloudClient;
@@ -7684,7 +8145,7 @@ var APIClient = class {
7684
8145
  await this.cloudClient.deleteApplication(applicationName);
7685
8146
  }
7686
8147
  async deleteSandboxImage(imageName) {
7687
- await this.cloudClient.deleteSandboxImage(imageName);
8148
+ await deleteSandboxImageWithCredentials(this.filesystemOptions, imageName);
7688
8149
  }
7689
8150
  async createFileSystem(name, description, options) {
7690
8151
  const filesystem = await new FilesystemClient(this.filesystemOptions).create(
@@ -7771,14 +8232,14 @@ var GitCli = class extends MountCli {
7771
8232
  if (options.readOnly && (options.publish || options.workspace !== void 0) || options.publish && options.workspace !== void 0) {
7772
8233
  throw new TypeError("readOnly, publish, and workspace are mutually exclusive");
7773
8234
  }
7774
- const path4 = resolve(localPath);
8235
+ const path5 = resolve(localPath);
7775
8236
  const args = ["mount"];
7776
8237
  if (options.readOnly) args.push("--ro");
7777
8238
  if (options.publish) args.push("--publish");
7778
8239
  if (options.workspace !== void 0) args.push(`--workspace=${options.workspace}`);
7779
- args.push("--", target, path4);
8240
+ args.push("--", target, path5);
7780
8241
  await this.run(args);
7781
- return new RepositoryMount(this, target, path4, options.readOnly ?? false);
8242
+ return new RepositoryMount(this, target, path5, options.readOnly ?? false);
7782
8243
  }
7783
8244
  async unmount(localPath, options = {}) {
7784
8245
  requireNonEmpty(localPath, "localPath");
@@ -7816,44 +8277,44 @@ var GitCli = class extends MountCli {
7816
8277
  raw
7817
8278
  };
7818
8279
  }
7819
- async snapshot(path4, message) {
8280
+ async snapshot(path5, message) {
7820
8281
  const args = ["snapshot"];
7821
8282
  if (message !== void 0) args.push(`--message=${message}`);
7822
- args.push("--", path4);
8283
+ args.push("--", path5);
7823
8284
  await this.run(args);
7824
8285
  }
7825
- async sync(path4, target) {
7826
- const args = ["sync", "--", path4];
8286
+ async sync(path5, target) {
8287
+ const args = ["sync", "--", path5];
7827
8288
  if (target !== void 0) {
7828
8289
  requireNonEmpty(target, "target");
7829
8290
  args.push(target);
7830
8291
  }
7831
8292
  await this.run(args);
7832
8293
  }
7833
- async rebase(path4, target, failOnConflict) {
8294
+ async rebase(path5, target, failOnConflict) {
7834
8295
  requireNonEmpty(target, "target");
7835
8296
  const args = ["rebase"];
7836
8297
  if (failOnConflict) args.push("--fail-on-conflict");
7837
- args.push("--", path4, target);
8298
+ args.push("--", path5, target);
7838
8299
  await this.run(args);
7839
8300
  }
7840
- async promote(path4, branch, merge) {
8301
+ async promote(path5, branch, merge) {
7841
8302
  requireNonEmpty(branch, "branch");
7842
8303
  const args = ["promote"];
7843
8304
  if (merge) args.push("--merge");
7844
- args.push("--", path4, branch);
8305
+ args.push("--", path5, branch);
7845
8306
  await this.run(args);
7846
8307
  }
7847
- async prefetch(path4) {
7848
- await this.run(["prefetch", "--", path4]);
8308
+ async prefetch(path5) {
8309
+ await this.run(["prefetch", "--", path5]);
7849
8310
  }
7850
8311
  };
7851
8312
  var RepositoryMount = class {
7852
8313
  /** @internal Obtain instances via RepositoryClient.mount(). */
7853
- constructor(cli, target, path4, readOnly) {
8314
+ constructor(cli, target, path5, readOnly) {
7854
8315
  this.cli = cli;
7855
8316
  this.target = target;
7856
- this.path = path4;
8317
+ this.path = path5;
7857
8318
  this.readOnly = readOnly;
7858
8319
  }
7859
8320
  /** Inspect workspace state, pending changes, and daemon diagnostics. */
@@ -8088,6 +8549,7 @@ function validateTimeoutMs2(timeoutMs) {
8088
8549
 
8089
8550
  // src/index.ts
8090
8551
  init_sandbox_image();
8552
+ init_image_builds();
8091
8553
 
8092
8554
  // src/file-system.ts
8093
8555
  init_esm_shims();
@@ -9471,38 +9933,38 @@ init_esm_shims();
9471
9933
  import { createHash } from "crypto";
9472
9934
  var textEncoder = new TextEncoder();
9473
9935
  var textDecoder = new TextDecoder("utf-8", { fatal: true });
9474
- function assertJSONValue(value, path4, seen) {
9936
+ function assertJSONValue(value, path5, seen) {
9475
9937
  if (value === null || typeof value === "string" || typeof value === "boolean") return;
9476
9938
  if (typeof value === "number") {
9477
- if (!Number.isFinite(value)) throw new SerializationError(`${path4} contains a non-finite number`);
9939
+ if (!Number.isFinite(value)) throw new SerializationError(`${path5} contains a non-finite number`);
9478
9940
  return;
9479
9941
  }
9480
9942
  if (typeof value !== "object") {
9481
- throw new SerializationError(`${path4} contains unsupported ${typeof value}`);
9943
+ throw new SerializationError(`${path5} contains unsupported ${typeof value}`);
9482
9944
  }
9483
9945
  if (isFile(value)) {
9484
- throw new SerializationError(`${path4} contains a nested File; File is only supported as a direct value`);
9946
+ throw new SerializationError(`${path5} contains a nested File; File is only supported as a direct value`);
9485
9947
  }
9486
9948
  if (isHttpBody(value)) {
9487
9949
  throw new SerializationError(
9488
- `${path4} contains a nested HttpBody; HttpBody is only supported as a direct value`
9950
+ `${path5} contains a nested HttpBody; HttpBody is only supported as a direct value`
9489
9951
  );
9490
9952
  }
9491
- if (seen.has(value)) throw new SerializationError(`${path4} contains a cycle`);
9953
+ if (seen.has(value)) throw new SerializationError(`${path5} contains a cycle`);
9492
9954
  if (Object.getPrototypeOf(value) !== Object.prototype && !Array.isArray(value)) {
9493
- throw new SerializationError(`${path4} contains unsupported ${value.constructor?.name ?? "object"}`);
9955
+ throw new SerializationError(`${path5} contains unsupported ${value.constructor?.name ?? "object"}`);
9494
9956
  }
9495
9957
  seen.add(value);
9496
9958
  if (Array.isArray(value)) {
9497
9959
  for (let index = 0; index < value.length; index += 1) {
9498
9960
  if (!Object.prototype.hasOwnProperty.call(value, index)) {
9499
- throw new SerializationError(`${path4} contains a sparse array entry at index ${index}`);
9961
+ throw new SerializationError(`${path5} contains a sparse array entry at index ${index}`);
9500
9962
  }
9501
- assertJSONValue(value[index], `${path4}[${index}]`, seen);
9963
+ assertJSONValue(value[index], `${path5}[${index}]`, seen);
9502
9964
  }
9503
9965
  } else {
9504
9966
  for (const [key, item] of Object.entries(value)) {
9505
- assertJSONValue(item, `${path4}.${key}`, seen);
9967
+ assertJSONValue(item, `${path5}.${key}`, seen);
9506
9968
  }
9507
9969
  }
9508
9970
  seen.delete(value);
@@ -9951,7 +10413,15 @@ export {
9951
10413
  Headers,
9952
10414
  HttpBody,
9953
10415
  Image,
10416
+ ImageBuildCancelledError,
10417
+ ImageBuildError,
10418
+ ImageBuildFailedError,
10419
+ ImageBuildHandle,
10420
+ ImageBuildInProgressError,
10421
+ ImageBuildInterruptedError,
10422
+ ImageBuildNotFoundError,
9954
10423
  ImageBuildOperationType,
10424
+ ImageBuildTimeoutError,
9955
10425
  MountError,
9956
10426
  OutputMode,
9957
10427
  PendingSandbox,
@@ -9984,12 +10454,14 @@ export {
9984
10454
  TERMINATION_REASON_CANCELLED,
9985
10455
  TERMINATION_REASON_NO_CAPACITY,
9986
10456
  TcpTunnel,
10457
+ cancelImageBuild,
9987
10458
  createFileSystem,
9988
10459
  createSandboxImage,
9989
10460
  deleteFileSystem,
9990
10461
  deleteSandboxImage,
9991
10462
  dockerfileContent,
9992
10463
  findSandboxImageByName,
10464
+ getImageBuild,
9993
10465
  importSandboxImage,
9994
10466
  isSandboxPending,
9995
10467
  listFileSystems,
@@ -10001,6 +10473,9 @@ export {
10001
10473
  runLocal,
10002
10474
  runRemote,
10003
10475
  sandboxUrlFromIngressEndpoint,
10004
- schema
10476
+ schema,
10477
+ startImageBuild,
10478
+ startImageImport,
10479
+ waitImageBuild
10005
10480
  };
10006
10481
  //# sourceMappingURL=index.js.map